Browse Source

* synchronized with trunk

git-svn-id: branches/unicodekvm@49412 -
nickysn 4 years ago
parent
commit
3c2c578386
83 changed files with 5677 additions and 1401 deletions
  1. 17 0
      .gitattributes
  2. 21 11
      compiler/aggas.pas
  3. 19 0
      compiler/aoptutils.pas
  4. 1 0
      compiler/arm/aasmcpu.pas
  5. 11 0
      compiler/arm/agarmgas.pas
  6. 150 0
      compiler/arm/agarmvasm.pas
  7. 3 0
      compiler/arm/cpuinfo.pas
  8. 4 0
      compiler/arm/cputarg.pas
  9. 2 2
      compiler/arm/narmmat.pas
  10. 1 0
      compiler/arm/narmutil.pas
  11. 12 3
      compiler/assemble.pas
  12. 989 830
      compiler/avr/aoptcpu.pas
  13. 2 1
      compiler/avr/ccpuinnr.inc
  14. 3 1
      compiler/avr/cgcpu.pas
  15. 2 1
      compiler/avr/cpubase.pas
  16. 2 1
      compiler/avr/itcpugas.pas
  17. 75 1
      compiler/avr/navrinl.pas
  18. 3 1
      compiler/avr/raavr.pas
  19. 9 6
      compiler/cclasses.pas
  20. 0 4
      compiler/cgbase.pas
  21. 2 2
      compiler/cgutils.pas
  22. 4 0
      compiler/fpcdefs.inc
  23. 6 2
      compiler/i386/aoptcpu.pas
  24. 1 0
      compiler/systems.inc
  25. 2 1
      compiler/systems.pas
  26. 1 0
      compiler/systems/t_sinclairql.pas
  27. 939 235
      compiler/x86/aoptx86.pas
  28. 15 0
      compiler/x86/cpubase.pas
  29. 6 2
      compiler/x86_64/aoptcpu.pas
  30. 24 11
      compiler/xtensa/cgcpu.pas
  31. 1 1
      packages/fcl-image/src/clipping.pp
  32. 10 11
      packages/fcl-js/src/jswriter.pp
  33. 9 3
      packages/fcl-passrc/examples/test_parser.pp
  34. 55 40
      packages/fcl-passrc/src/pasresolveeval.pas
  35. 18 21
      packages/fcl-passrc/src/pasresolver.pp
  36. 2 2
      packages/fcl-passrc/src/pasuseanalyzer.pas
  37. 7 7
      packages/fcl-passrc/src/pparser.pp
  38. 15 16
      packages/fcl-passrc/src/pscanner.pp
  39. 30 6
      packages/fcl-web/src/base/custfcgi.pp
  40. 665 22
      packages/fcl-web/src/base/httpdefs.pp
  41. 21 0
      packages/fcl-web/tests/integrationtests/README.md
  42. 1 0
      packages/fcl-web/tests/integrationtests/UploadFile1.txt
  43. 3 0
      packages/fcl-web/tests/integrationtests/UploadFile2.txt
  44. 199 0
      packages/fcl-web/tests/integrationtests/UploadFile3.txt
  45. 184 0
      packages/fcl-web/tests/integrationtests/fcgi_dump_request.pp
  46. 1034 0
      packages/fcl-web/tests/integrationtests/fcl-web_integrationtests.jmx
  47. 32 7
      packages/pastojs/src/fppas2js.pp
  48. 3 3
      packages/pastojs/src/pas2jscompiler.pp
  49. 12 12
      packages/pastojs/src/pas2jslogger.pp
  50. 2 2
      packages/pastojs/src/pas2jspparser.pp
  51. 29 2
      packages/pastojs/tests/tcmodules.pas
  52. 2 0
      packages/qlunits/README.txt
  53. 11 16
      packages/qlunits/examples/mtinf.pas
  54. 49 0
      packages/qlunits/examples/sms_info.pas
  55. 5 0
      packages/qlunits/fpmake.pp
  56. 181 0
      packages/qlunits/src/qdos.pas
  57. 146 0
      packages/qlunits/src/qdos_sysvars.inc
  58. 4 0
      packages/qlunits/src/sms.pas
  59. 226 0
      packages/qlunits/src/sms_sysvars.inc
  60. 2 0
      packages/qlunits/src/smsfuncs.inc
  61. 59 0
      packages/qlunits/tests/trecsize.pas
  62. 62 0
      packages/qlunits/tests/tsysvars.pas
  63. 2 2
      packages/rtl-objpas/src/inc/strutils.pp
  64. 6 6
      rtl/aarch64/aarch64.inc
  65. 1 0
      rtl/avr/cpuinnr.inc
  66. 2 0
      rtl/avr/intrinsics.pp
  67. 2 2
      rtl/inc/rttih.inc
  68. 2 2
      rtl/linux/system.pp
  69. 3 2
      rtl/objpas/classes/writer.inc
  70. 3 2
      rtl/objpas/types.pp
  71. 89 0
      rtl/riscv/riscv.inc
  72. 3 5
      rtl/riscv32/riscv32.inc
  73. 3 73
      rtl/riscv64/riscv64.inc
  74. 2 0
      rtl/sinclairql/smsfuncs.inc
  75. 10 1
      rtl/sinclairql/sysfile.inc
  76. 82 16
      rtl/sinclairql/system.pp
  77. 2 1
      rtl/win32/sysinit.inc
  78. 2 1
      rtl/win64/sysinit.pp
  79. 11 0
      tests/test/tdes1.pp
  80. 12 0
      tests/test/tdes2.pp
  81. 11 0
      tests/webtbf/tw26016.pp
  82. 22 0
      tests/webtbs/tw38940.pp
  83. 2 2
      utils/pas2js/docs/translation.html

+ 17 - 0
.gitattributes

@@ -64,6 +64,7 @@ compiler/aoptobj.pas svneol=native#text/plain
 compiler/aoptutils.pas svneol=native#text/pascal
 compiler/arm/aasmcpu.pas svneol=native#text/plain
 compiler/arm/agarmgas.pas svneol=native#text/plain
+compiler/arm/agarmvasm.pas svneol=native#text/pascal
 compiler/arm/aoptcpu.pas svneol=native#text/plain
 compiler/arm/aoptcpub.pas svneol=native#text/plain
 compiler/arm/aoptcpud.pas svneol=native#text/plain
@@ -4874,6 +4875,12 @@ packages/fcl-web/tests/cgigateway.lpi svneol=native#text/plain
 packages/fcl-web/tests/cgigateway.pp svneol=native#text/plain
 packages/fcl-web/tests/fpcunithpack.lpi svneol=native#text/plain
 packages/fcl-web/tests/fpcunithpack.lpr svneol=native#text/plain
+packages/fcl-web/tests/integrationtests/README.md svneol=native#text/markdown
+packages/fcl-web/tests/integrationtests/UploadFile1.txt svneol=native#text/plain
+packages/fcl-web/tests/integrationtests/UploadFile2.txt svneol=native#text/plain
+packages/fcl-web/tests/integrationtests/UploadFile3.txt svneol=native#text/plain
+packages/fcl-web/tests/integrationtests/fcgi_dump_request.pp svneol=native#text/pascal
+packages/fcl-web/tests/integrationtests/fcl-web_integrationtests.jmx svneol=native#text/xml
 packages/fcl-web/tests/tchttproute.pp svneol=native#text/plain
 packages/fcl-web/tests/testcgiapp.lpi svneol=native#text/plain
 packages/fcl-web/tests/testcgiapp.pp svneol=native#text/plain
@@ -8845,13 +8852,18 @@ packages/qlunits/Makefile.fpc svneol=native#text/plain
 packages/qlunits/README.txt svneol=native#text/plain
 packages/qlunits/examples/mtinf.pas svneol=native#text/plain
 packages/qlunits/examples/qlcube.pas svneol=native#text/plain
+packages/qlunits/examples/sms_info.pas svneol=native#text/plain
 packages/qlunits/fpmake.pp svneol=native#text/plain
 packages/qlunits/src/qdos.pas svneol=native#text/plain
+packages/qlunits/src/qdos_sysvars.inc svneol=native#text/plain
 packages/qlunits/src/qdosfuncs.inc svneol=native#text/plain
 packages/qlunits/src/qlfloat.pas svneol=native#text/plain
 packages/qlunits/src/qlutil.pas svneol=native#text/plain
 packages/qlunits/src/sms.pas svneol=native#text/plain
+packages/qlunits/src/sms_sysvars.inc svneol=native#text/plain
 packages/qlunits/src/smsfuncs.inc svneol=native#text/plain
+packages/qlunits/tests/trecsize.pas svneol=native#text/plain
+packages/qlunits/tests/tsysvars.pas svneol=native#text/plain
 packages/regexpr/Makefile svneol=native#text/plain
 packages/regexpr/Makefile.fpc svneol=native#text/plain
 packages/regexpr/Makefile.fpc.fpcmake svneol=native#text/plain
@@ -12100,6 +12112,7 @@ rtl/qnx/qnx.inc svneol=native#text/plain
 rtl/qnx/rtldefs.inc svneol=native#text/plain
 rtl/qnx/signal.inc svneol=native#text/plain
 rtl/qnx/system.pp svneol=native#text/plain
+rtl/riscv/riscv.inc svneol=native#text/plain
 rtl/riscv32/cpuh.inc svneol=native#text/plain
 rtl/riscv32/int64p.inc svneol=native#text/plain
 rtl/riscv32/makefile.cpu svneol=native#text/plain
@@ -15078,6 +15091,8 @@ tests/test/tdefault8.pp svneol=native#text/pascal
 tests/test/tdefault9.pp svneol=native#text/pascal
 tests/test/tdel1.pp svneol=native#text/plain
 tests/test/tdel2.pp svneol=native#text/plain
+tests/test/tdes1.pp svneol=native#text/pascal
+tests/test/tdes2.pp svneol=native#text/pascal
 tests/test/tdispinterface1a.pp svneol=native#text/pascal
 tests/test/tdispinterface1b.pp svneol=native#text/pascal
 tests/test/tdispinterface2.pp svneol=native#text/plain
@@ -16797,6 +16812,7 @@ tests/webtbf/tw25861.pp svneol=native#text/plain
 tests/webtbf/tw25862.pp svneol=native#text/plain
 tests/webtbf/tw25915.pp svneol=native#text/pascal
 tests/webtbf/tw25951.pp svneol=native#text/pascal
+tests/webtbf/tw26016.pp svneol=native#text/pascal
 tests/webtbf/tw26176.pp svneol=native#text/pascal
 tests/webtbf/tw26193.pp svneol=native#text/pascal
 tests/webtbf/tw26363.pp svneol=native#text/plain
@@ -18915,6 +18931,7 @@ tests/webtbs/tw38802.pp svneol=native#text/pascal
 tests/webtbs/tw38832.pp svneol=native#text/pascal
 tests/webtbs/tw38833.pp svneol=native#text/plain
 tests/webtbs/tw3893.pp svneol=native#text/plain
+tests/webtbs/tw38940.pp svneol=native#text/pascal
 tests/webtbs/tw3898.pp svneol=native#text/plain
 tests/webtbs/tw3899.pp svneol=native#text/plain
 tests/webtbs/tw3900.pp svneol=native#text/plain

+ 21 - 11
compiler/aggas.pas

@@ -1,4 +1,4 @@
-  {
+  {                  f
     Copyright (c) 1998-2006 by the Free Pascal team
 
     This unit implements the generic part of the GNU assembler
@@ -1408,7 +1408,8 @@ implementation
                  end
                else
                  begin
-                   if ((target_info.system <> system_arm_linux) and (target_info.system <> system_arm_android)) then
+                   if ((target_info.system <> system_arm_linux) and (target_info.system <> system_arm_android)) or
+                     (target_asm.id=as_arm_vasm) then
                      sepChar := '@'
                    else
                      sepChar := '#';
@@ -1617,15 +1618,24 @@ implementation
              end;
            ait_eabi_attribute:
              begin
-               case tai_eabi_attribute(hp).eattr_typ of
-                 eattrtype_dword:
-                   writer.AsmWrite(#9'.eabi_attribute '+tostr(tai_eabi_attribute(hp).tag)+','+tostr(tai_eabi_attribute(hp).value));
-                 eattrtype_ntbs:
-                   writer.AsmWrite(#9'.eabi_attribute '+tostr(tai_eabi_attribute(hp).tag)+',"'+tai_eabi_attribute(hp).valuestr^+'"');
-                 else
-                   Internalerror(2019100601);
-               end;
-               writer.AsmLn;
+               { as of today, vasm does not support the eabi directives }
+               if target_asm.id<>as_arm_vasm then
+                 begin
+                   case tai_eabi_attribute(hp).eattr_typ of
+                     eattrtype_dword:
+                       writer.AsmWrite(#9'.eabi_attribute '+tostr(tai_eabi_attribute(hp).tag)+','+tostr(tai_eabi_attribute(hp).value));
+                     eattrtype_ntbs:
+                       begin
+                         if assigned(tai_eabi_attribute(hp).valuestr) then
+                           writer.AsmWrite(#9'.eabi_attribute '+tostr(tai_eabi_attribute(hp).tag)+',"'+tai_eabi_attribute(hp).valuestr^+'"')
+                         else
+                           writer.AsmWrite(#9'.eabi_attribute '+tostr(tai_eabi_attribute(hp).tag)+',""');
+                       end
+                     else
+                       Internalerror(2019100601);
+                   end;
+                   writer.AsmLn;
+                 end;
              end;
 
 {$ifdef WASM}

+ 19 - 0
compiler/aoptutils.pas

@@ -35,6 +35,10 @@ unit aoptutils;
     function MatchOpType(const p : taicpu; type0,type1,type2 : toptype) : Boolean;
 {$endif max_operands>2}
 
+    { skips all alignment fields and returns the next label (or non-align).
+      returns immediately with true if hp is a label }
+    function SkipAligns(hp: tai; out hp2: tai): boolean;
+
     { skips all labels and returns the next "real" instruction }
     function SkipLabels(hp: tai; out hp2: tai): boolean;
 
@@ -67,6 +71,21 @@ unit aoptutils;
 {$endif max_operands>2}
 
 
+    { skips all alignment fields and returns the next label (or non-align).
+      Returns immediately with True if hp is a label }
+    function SkipAligns(hp: tai; out hp2: tai): boolean;
+      begin
+        while assigned(hp) and
+              (hp.typ in SkipInstr + [ait_label,ait_align]) Do
+          begin
+            { Check that the label is actually live }
+            if (hp.typ = ait_label) and tai_label(hp).labsym.is_used then
+              Break;
+            hp := tai(hp.next);
+          end;
+        SkipAligns := SetAndTest(hp, hp2);
+      end;
+
     { skips all labels and returns the next "real" instruction }
     function SkipLabels(hp: tai; out hp2: tai): boolean;
       begin

+ 1 - 0
compiler/arm/aasmcpu.pas

@@ -2213,6 +2213,7 @@ implementation
             IF_NONE,
             IF_ARMv4,
             IF_ARMv4,
+            IF_ARMv4,
             IF_ARMv4T or IF_ARMv4,
             IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T,
             IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE,

+ 11 - 0
compiler/arm/agarmgas.pas

@@ -61,6 +61,7 @@ unit agarmgas;
     const 
       cputype_to_gas_march : array[tcputype] of string = (
         '', // cpu_none
+        'armv2',
         'armv3',
         'armv4',
         'armv4t',
@@ -435,6 +436,16 @@ unit agarmgas;
                        internalerror(2003112903);
                    end;
                  end
+               { syscall number for vasm does not need a # }
+               else if (target_asm.id=as_arm_vasm) and (i=0) and ((op=A_SWI) or (op=A_SVC)) then
+                 begin
+                   case taicpu(hp).oper[0]^.typ of
+                     top_const:
+                       s:=s+sep+tostr(taicpu(hp).oper[0]^.val);
+                     else
+                       internalerror(2021052301);
+                   end;
+                 end
                else
                  s:=s+sep+getopstr(taicpu(hp).oper[i]^);
 

+ 150 - 0
compiler/arm/agarmvasm.pas

@@ -0,0 +1,150 @@
+{
+    Copyright (c) 2016 by the Free Pascal development team
+
+    This unit is the VASM assembler writer for ARM
+
+    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 agarmvasm;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       aasmbase,systems,
+       aasmtai,aasmdata,
+       assemble,aggas,agarmgas,
+       cpubase,cgutils,
+       globtype;
+
+  type
+    TARMVASM = class(TARMGNUAssembler)
+    protected
+      function sectionattrs(atype:TAsmSectiontype):string; override;
+    public
+      constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override;
+      function MakeCmdLine: TCmdStr; override;
+    end;
+
+  implementation
+
+    uses
+       cutils,cfileutl,globals,verbose,
+       cgbase,
+       cscript,
+       itcpugas,cpuinfo,
+       aasmcpu;
+
+{****************************************************************************}
+{                         VASM m68k Assembler writer                         }
+{****************************************************************************}
+
+
+    constructor TARMVASM.CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean);
+      begin
+        inherited;
+        InstrWriter := TARMInstrWriter.create(self);
+      end;
+
+
+    function TARMVASM.sectionattrs(atype:TAsmSectiontype):string;
+      begin
+        case atype of
+          sec_code, sec_fpc, sec_init, sec_fini:
+            result:='acrx';
+          { map sec_rodata as read-write, otherwise the linker (vlink) complains if it
+            has to write into the relocations in a rodata section. (KB) }
+          sec_data, sec_rodata:
+            result:='adrw';
+          sec_rodata_norel:
+            result:='adr';
+          sec_bss, sec_threadvar:
+            result:='aurw';
+          sec_stab, sec_stabstr:
+            result:='dr';
+          else
+            result:='';
+        end;
+      end;
+
+
+    const
+      cputype_to_vasm_march : array[tcputype] of string = (
+        '', // cpu_none
+        'a2',
+        'a3',
+        'a4',
+        'a4t',
+        '',
+        '',
+        '',
+        '',
+        '',
+        '',
+        '',
+        '',
+        '',
+        '',
+        '',
+        '',
+        '');
+
+    function TARMVASM.MakeCmdLine: TCmdStr;
+      var
+        objtype: string;
+      begin
+        result:=asminfo^.asmcmd;
+
+        case target_info.system of
+          { a.out doesn't support named sections, lets use ELF for interoperability }
+          system_arm_linux: objtype:='-Felf';
+        else
+          internalerror(2016052601);
+        end;
+
+        Replace(result,'$ASM',maybequoted(ScriptFixFileName(AsmFileName)));
+        Replace(result,'$OBJ',maybequoted(ScriptFixFileName(ObjFileName)));
+        Replace(result,'$ARCH','-'+cputype_to_vasm_march[current_settings.cputype]);
+        Replace(result,'$OTYPE',objtype);
+        Replace(result,'$EXTRAOPT',asmextraopt);
+      end;
+
+{*****************************************************************************
+                                  Initialize
+*****************************************************************************}
+
+  const
+    as_arm_vasm_info : tasminfo =
+       (
+         id     : as_arm_vasm;
+
+         idtxt  : 'VASM';
+         asmbin : 'vasmarm_std';
+         asmcmd:  '-quiet -elfregs -gas $OTYPE $ARCH -o $OBJ $EXTRAOPT $ASM';
+         supported_targets : [system_arm_linux];
+         flags : [af_needar,af_smartlink_sections];
+         labelprefix : '.L';
+         labelmaxlen : -1;
+         comment : '# ';
+         dollarsign: '$';
+       );
+
+begin
+  RegisterAssembler(as_arm_vasm_info,TARMVASM);
+end.

+ 3 - 0
compiler/arm/cpuinfo.pas

@@ -37,6 +37,7 @@ Type
    { possible supported processors for this target }
    tcputype =
       (cpu_none,
+       cpu_armv2,
        cpu_armv3,
        cpu_armv4,
        cpu_armv4t,
@@ -554,6 +555,7 @@ Const
    ];
 
    cputypestr : array[tcputype] of string[8] = ('',
+     'ARMV2',
      'ARMV3',
      'ARMV4',
      'ARMV4T',
@@ -1095,6 +1097,7 @@ Const
  const
    cpu_capabilities : array[tcputype] of set of tcpuflags =
      ( { cpu_none     } [],
+       { cpu_armv2    } [],
        { cpu_armv3    } [],
        { cpu_armv4    } [CPUARM_HAS_ALL_MEM,CPUARM_HAS_UMULL],
        { cpu_armv4t   } [CPUARM_HAS_THUMB,CPUARM_HAS_ALL_MEM,CPUARM_HAS_BX,CPUARM_HAS_UMULL],

+ 4 - 0
compiler/arm/cputarg.pas

@@ -81,6 +81,10 @@ implementation
       ,agarmgas
     {$endif}
 
+    {$ifndef Noagrmvasm}
+      ,agarmvasm
+    {$endif Noagarmvasm}
+
       ,ogcoff
       ,ogelf
       ,cpuelf

+ 2 - 2
compiler/arm/narmmat.pas

@@ -77,8 +77,8 @@ implementation
            (nodetype=divn) and
            not(is_64bit(resultdef)) and
            {Only the ARM and thumb2-isa support umull and smull, which are required for arbitary division by const optimization}
-           (GenerateArmCode or
-            GenerateThumb2Code or
+           (((GenerateArmCode or
+             GenerateThumb2Code) and (CPUARM_HAS_UMULL in cpu_capabilities[current_settings.cputype])) or
             (ispowerof2(tordconstnode(right).value,power) or
             (tordconstnode(right).value=1) or
             (tordconstnode(right).value=int64(-1))

+ 1 - 0
compiler/arm/narmutil.pas

@@ -97,6 +97,7 @@ interface
         if (target_info.system in [system_arm_linux]) and (target_info.abi in [abi_eabihf,abi_eabi]) then
           begin
             case current_settings.cputype of
+              cpu_armv2,
               cpu_armv3:
                 begin
                   current_asmdata.asmlists[al_start].Concat(tai_eabi_attribute.create(Tag_CPU_arch,0));

+ 12 - 3
compiler/assemble.pas

@@ -1791,7 +1791,10 @@ Implementation
                    eattrtype_dword:
                      eabi_section.alloc(LengthUleb128(tai_eabi_attribute(hp).value));
                    eattrtype_ntbs:
-                     eabi_section.alloc(Length(tai_eabi_attribute(hp).valuestr^)+1);
+                     if assigned(tai_eabi_attribute(hp).valuestr) then
+                       eabi_section.alloc(Length(tai_eabi_attribute(hp).valuestr^)+1)
+                     else
+                       eabi_section.alloc(1);
                    else
                      Internalerror(2019100701);
                  end;
@@ -1969,7 +1972,10 @@ Implementation
                    eattrtype_dword:
                      eabi_section.alloc(LengthUleb128(tai_eabi_attribute(hp).value));
                    eattrtype_ntbs:
-                     eabi_section.alloc(Length(tai_eabi_attribute(hp).valuestr^)+1);
+                     if assigned(tai_eabi_attribute(hp).valuestr) then
+                       eabi_section.alloc(Length(tai_eabi_attribute(hp).valuestr^)+1)
+                     else
+                       eabi_section.alloc(1);
                    else
                      Internalerror(2019100703);
                  end;
@@ -2336,7 +2342,10 @@ Implementation
                      end;
                    eattrtype_ntbs:
                      begin
-                       s:=tai_eabi_attribute(hp).valuestr^+#0;
+                       if assigned(tai_eabi_attribute(hp).valuestr) then
+                         s:=tai_eabi_attribute(hp).valuestr^+#0
+                       else
+                         s:=#0;
                        eabi_section.write(s[1],Length(s));
                      end
                    else

+ 989 - 830
compiler/avr/aoptcpu.pas

@@ -47,6 +47,21 @@ Type
     { uses the same constructor as TAopObj }
     function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
     procedure PeepHoleOptPass2;override;
+  private
+    function OptPass1ADD(var p : tai) : boolean;
+    function OptPass1ANDI(var p : tai) : boolean;
+    function OptPass1CALL(var p : tai) : boolean;
+    function OptPass1CLR(var p : tai) : boolean;
+    function OptPass1IN(var p : tai) : boolean;
+    function OptPass1LDI(var p : tai) : boolean;
+    function OptPass1LDS(var p : tai) : boolean;
+    function OptPass1MOV(var p : tai) : boolean;
+    function OptPass1PUSH(var p : tai) : boolean;
+    function OptPass1RCALL(var p : tai) : boolean;
+    function OptPass1SBI(var p : tai) : boolean;
+    function OptPass1SBR(var p : tai) : boolean;
+    function OptPass1STS(var p : tai) : boolean;
+    function OptPass1SUB(var p : tai) : boolean;
   End;
 
 Implementation
@@ -291,12 +306,968 @@ Implementation
     end;
 
 
-  function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
+  function TCpuAsmOptimizer.OptPass1LDI(var p : tai) : boolean;
+    var
+      hp1 : tai;
+      alloc ,dealloc: tai_regalloc;
+    begin
+      Result:=false;
+      { turn
+        ldi reg0, imm
+        <op> reg1, reg0
+        dealloc reg0
+        into
+        <op>i reg1, imm
+      }
+      if MatchOpType(taicpu(p),top_reg,top_const) and
+         GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
+         MatchInstruction(hp1,[A_CP,A_MOV,A_AND,A_SUB],2) and
+         (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
+         MatchOpType(taicpu(hp1),top_reg,top_reg) and
+         (getsupreg(taicpu(hp1).oper[0]^.reg) in [16..31]) and
+         (taicpu(hp1).oper[1]^.reg=taicpu(p).oper[0]^.reg) and
+         not(MatchOperand(taicpu(hp1).oper[0]^,taicpu(hp1).oper[1]^)) then
+        begin
+          TransferUsedRegs(TmpUsedRegs);
+          UpdateUsedRegs(TmpUsedRegs,tai(p.next));
+          UpdateUsedRegs(TmpUsedRegs,tai(hp1.next));
+          if not(RegUsedAfterInstruction(taicpu(hp1).oper[1]^.reg, hp1, TmpUsedRegs)) then
+            begin
+              case taicpu(hp1).opcode of
+                A_CP:
+                  taicpu(hp1).opcode:=A_CPI;
+                A_MOV:
+                  taicpu(hp1).opcode:=A_LDI;
+                A_AND:
+                  taicpu(hp1).opcode:=A_ANDI;
+                A_SUB:
+                  taicpu(hp1).opcode:=A_SUBI;
+                else
+                  internalerror(2016111901);
+              end;
+              taicpu(hp1).loadconst(1, taicpu(p).oper[1]^.val);
+
+              alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
+              dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
+
+              if assigned(alloc) and assigned(dealloc) then
+                begin
+                  asml.Remove(alloc);
+                  alloc.Free;
+                  asml.Remove(dealloc);
+                  dealloc.Free;
+                end;
+
+              DebugMsg('Peephole LdiOp2Opi performed', p);
+
+              result:=RemoveCurrentP(p);
+            end;
+        end;
+    end;
+
+
+  function TCpuAsmOptimizer.OptPass1STS(var p : tai) : boolean;
+    begin
+      Result:=false;
+      if (taicpu(p).oper[0]^.ref^.symbol=nil) and
+        (taicpu(p).oper[0]^.ref^.relsymbol=nil) and
+        (getsupreg(taicpu(p).oper[0]^.ref^.base)=RS_NO) and
+        (getsupreg(taicpu(p).oper[0]^.ref^.index)=RS_NO) and
+        (taicpu(p).oper[0]^.ref^.addressmode=AM_UNCHANGED) and
+        (((CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype]) and
+          (taicpu(p).oper[0]^.ref^.offset>=0) and
+          (taicpu(p).oper[0]^.ref^.offset<=63)) or
+         (not(CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype]) and
+          (taicpu(p).oper[0]^.ref^.offset>=32) and
+          (taicpu(p).oper[0]^.ref^.offset<=95))) then
+        begin
+          DebugMsg('Peephole Sts2Out performed', p);
+
+          taicpu(p).opcode:=A_OUT;
+          if CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype] then
+            taicpu(p).loadconst(0,taicpu(p).oper[0]^.ref^.offset)
+          else
+            taicpu(p).loadconst(0,taicpu(p).oper[0]^.ref^.offset-32);
+          result:=true;
+        end;
+    end;
+
+
+  function TCpuAsmOptimizer.OptPass1LDS(var p : tai) : boolean;
+    begin
+      Result:=false;
+      if (taicpu(p).oper[1]^.ref^.symbol=nil) and
+      (taicpu(p).oper[1]^.ref^.relsymbol=nil) and
+      (getsupreg(taicpu(p).oper[1]^.ref^.base)=RS_NO) and
+      (getsupreg(taicpu(p).oper[1]^.ref^.index)=RS_NO) and
+      (taicpu(p).oper[1]^.ref^.addressmode=AM_UNCHANGED) and
+      (((CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype]) and
+        (taicpu(p).oper[1]^.ref^.offset>=0) and
+        (taicpu(p).oper[1]^.ref^.offset<=63)) or
+       (not(CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype]) and
+        (taicpu(p).oper[1]^.ref^.offset>=32) and
+        (taicpu(p).oper[1]^.ref^.offset<=95))) then
+      begin
+        DebugMsg('Peephole Lds2In performed', p);
+
+        taicpu(p).opcode:=A_IN;
+        if CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype] then
+          taicpu(p).loadconst(1,taicpu(p).oper[1]^.ref^.offset)
+        else
+          taicpu(p).loadconst(1,taicpu(p).oper[1]^.ref^.offset-32);
+
+        result:=true;
+      end;
+    end;
+
+
+  function TCpuAsmOptimizer.OptPass1IN(var p : tai) : boolean;
+    var
+      hp1, hp2: tai;
+      l : TAsmLabel;
+    begin
+      Result:=false;
+      if GetNextInstruction(p,hp1) then
+        begin
+          {
+            in rX,Y
+            ori rX,n
+            out Y,rX
+
+            into
+            sbi rX,lg(n)
+          }
+          if (taicpu(p).oper[1]^.val<=31) and
+            MatchInstruction(hp1,A_ORI) and
+            (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
+            (PopCnt(byte(taicpu(hp1).oper[1]^.val))=1) and
+            GetNextInstruction(hp1,hp2) and
+            MatchInstruction(hp2,A_OUT) and
+            MatchOperand(taicpu(hp2).oper[1]^,taicpu(p).oper[0]^) and
+            MatchOperand(taicpu(hp2).oper[0]^,taicpu(p).oper[1]^) then
+            begin
+              DebugMsg('Peephole InOriOut2Sbi performed', p);
+
+              taicpu(p).opcode:=A_SBI;
+              taicpu(p).loadconst(0,taicpu(p).oper[1]^.val);
+              taicpu(p).loadconst(1,BsrByte(taicpu(hp1).oper[1]^.val));
+              asml.Remove(hp1);
+              hp1.Free;
+              asml.Remove(hp2);
+              hp2.Free;
+              result:=true;
+            end
+           {
+            in rX,Y
+            andi rX,not(n)
+            out Y,rX
+
+            into
+            cbi rX,lg(n)
+          }
+          else if (taicpu(p).oper[1]^.val<=31) and
+             MatchInstruction(hp1,A_ANDI) and
+             (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
+             (PopCnt(byte(not(taicpu(hp1).oper[1]^.val)))=1) and
+             GetNextInstruction(hp1,hp2) and
+             MatchInstruction(hp2,A_OUT) and
+             MatchOperand(taicpu(hp2).oper[1]^,taicpu(p).oper[0]^) and
+             MatchOperand(taicpu(hp2).oper[0]^,taicpu(p).oper[1]^) then
+            begin
+              DebugMsg('Peephole InAndiOut2Cbi performed', p);
+
+              taicpu(p).opcode:=A_CBI;
+              taicpu(p).loadconst(0,taicpu(p).oper[1]^.val);
+              taicpu(p).loadconst(1,BsrByte(not(taicpu(hp1).oper[1]^.val)));
+              asml.Remove(hp1);
+              hp1.Free;
+              asml.Remove(hp2);
+              hp2.Free;
+              result:=true;
+            end
+           {
+                in rX,Y
+                andi rX,n
+                breq/brne L1
+
+            into
+                sbis/sbic Y,lg(n)
+                jmp L1
+              .Ltemp:
+          }
+          else if (taicpu(p).oper[1]^.val<=31) and
+             MatchInstruction(hp1,A_ANDI) and
+             (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
+             (PopCnt(byte(taicpu(hp1).oper[1]^.val))=1) and
+             GetNextInstruction(hp1,hp2) and
+             MatchInstruction(hp2,A_BRxx) and
+             (taicpu(hp2).condition in [C_EQ,C_NE]) then
+            begin
+              if taicpu(hp2).condition=C_EQ then
+                taicpu(p).opcode:=A_SBIS
+              else
+                taicpu(p).opcode:=A_SBIC;
+
+              DebugMsg('Peephole InAndiBrx2SbixJmp performed', p);
+
+              taicpu(p).loadconst(0,taicpu(p).oper[1]^.val);
+              taicpu(p).loadconst(1,BsrByte(taicpu(hp1).oper[1]^.val));
+              asml.Remove(hp1);
+              hp1.Free;
+
+              taicpu(hp2).condition:=C_None;
+              if CPUAVR_HAS_JMP_CALL in cpu_capabilities[current_settings.cputype] then
+                taicpu(hp2).opcode:=A_JMP
+              else
+                taicpu(hp2).opcode:=A_RJMP;
+
+              current_asmdata.getjumplabel(l);
+              l.increfs;
+              asml.InsertAfter(tai_label.create(l), hp2);
+
+              result:=true;
+            end;
+        end;
+    end;
+
+
+  function TCpuAsmOptimizer.OptPass1SBR(var p : tai) : boolean;
+    var
+      hp1 : tai;
+    begin
+      Result:=false;
+      {
+        Turn
+          in rx, y
+          sbr* rx, z
+        Into
+          sbi* y, z
+      }
+      if (taicpu(p).ops=2) and
+         (taicpu(p).oper[0]^.typ=top_reg) and
+         assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and
+         GetLastInstruction(p,hp1) and
+         (hp1.typ=ait_instruction) and
+         (taicpu(hp1).opcode=A_IN) and
+         (taicpu(hp1).ops=2) and
+         (taicpu(hp1).oper[1]^.typ=top_const) and
+         (taicpu(hp1).oper[1]^.val in [0..31]) and
+         MatchOperand(taicpu(hp1).oper[0]^,taicpu(p).oper[0]^.reg) and
+         (not RegModifiedBetween(taicpu(p).oper[0]^.reg, hp1, p)) then
+        begin
+          if taicpu(p).opcode=A_SBRS then
+            taicpu(p).opcode:=A_SBIS
+          else
+            taicpu(p).opcode:=A_SBIC;
+
+          taicpu(p).loadconst(0, taicpu(hp1).oper[1]^.val);
+
+          DebugMsg('Peephole InSbrx2Sbix performed', p);
+
+          asml.Remove(hp1);
+          hp1.free;
+
+          result:=true;
+        end;
+
+      if InvertSkipInstruction(p) then
+        result:=true;
+    end;
+
+
+  function TCpuAsmOptimizer.OptPass1SBI(var p : tai) : boolean;
+    var
+      hp1, hp2, hp3, hp4, hp5: tai;
+    begin
+      Result:=false;
+      {
+        Turn
+            sbic/sbis X, y
+            jmp .L1
+            op
+          .L1:
+
+        into
+            sbis/sbic X,y
+            op
+          .L1:
+      }
+      if InvertSkipInstruction(p) then
+        result:=true
+      {
+        Turn
+            sbiX X, y
+            jmp .L1
+            jmp .L2
+          .L1:
+            op
+          .L2:
+
+        into
+            sbiX X,y
+          .L1:
+            op
+          .L2:
+      }
+      else if GetNextInstruction(p, hp1) and
+         (hp1.typ=ait_instruction) and
+         (taicpu(hp1).opcode in [A_JMP,A_RJMP]) and
+         (taicpu(hp1).ops>0) and
+         (taicpu(hp1).oper[0]^.typ = top_ref) and
+         (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and
+
+         GetNextInstruction(hp1, hp2) and
+         (hp2.typ=ait_instruction) and
+         (taicpu(hp2).opcode in [A_JMP,A_RJMP]) and
+         (taicpu(hp2).ops>0) and
+         (taicpu(hp2).oper[0]^.typ = top_ref) and
+         (taicpu(hp2).oper[0]^.ref^.symbol is TAsmLabel) and
+
+         GetNextInstruction(hp2, hp3) and
+         (hp3.typ=ait_label) and
+         (taicpu(hp1).oper[0]^.ref^.symbol=tai_label(hp3).labsym) and
+
+         GetNextInstruction(hp3, hp4) and
+         (hp4.typ=ait_instruction) and
+
+         GetNextInstruction(hp4, hp5) and
+         (hp3.typ=ait_label) and
+         (taicpu(hp2).oper[0]^.ref^.symbol=tai_label(hp5).labsym) then
+        begin
+          DebugMsg('Peephole SbiJmpJmp2Sbi performed',p);
+
+          tai_label(hp3).labsym.decrefs;
+          tai_label(hp5).labsym.decrefs;
+
+          AsmL.remove(hp1);
+          taicpu(hp1).Free;
+
+          AsmL.remove(hp2);
+          taicpu(hp2).Free;
+
+          result:=true;
+        end;
+    end;
+
+
+  function TCpuAsmOptimizer.OptPass1ANDI(var p : tai) : boolean;
+    var
+      hp1, hp2, hp3: tai;
+      i : longint;
+    begin
+      Result:=false;
+      {
+        Turn
+            andi rx, #pow2
+            brne l
+            <op>
+          l:
+        Into
+            sbrs rx, #(1 shl imm)
+            <op>
+          l:
+      }
+      if (taicpu(p).ops=2) and
+         (taicpu(p).oper[1]^.typ=top_const) and
+         ispowerof2(taicpu(p).oper[1]^.val,i) and
+         assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and
+         GetNextInstruction(p,hp1) and
+         (hp1.typ=ait_instruction) and
+         (taicpu(hp1).opcode=A_BRxx) and
+         (taicpu(hp1).condition in [C_EQ,C_NE]) and
+         (taicpu(hp1).ops>0) and
+         (taicpu(hp1).oper[0]^.typ = top_ref) and
+         (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and
+         GetNextInstruction(hp1,hp2) and
+         (hp2.typ=ait_instruction) and
+         GetNextInstruction(hp2,hp3) and
+         (hp3.typ=ait_label) and
+         (taicpu(hp1).oper[0]^.ref^.symbol=tai_label(hp3).labsym) then
+        begin
+          DebugMsg('Peephole AndiBr2Sbr performed', p);
+
+          taicpu(p).oper[1]^.val:=i;
+
+          if taicpu(hp1).condition=C_NE then
+            taicpu(p).opcode:=A_SBRS
+          else
+            taicpu(p).opcode:=A_SBRC;
+
+          asml.Remove(hp1);
+          hp1.free;
+
+          result:=true;
+        end
+      {
+        Remove
+          andi rx, #y
+          dealloc rx
+      }
+      else if (taicpu(p).ops=2) and
+         (taicpu(p).oper[0]^.typ=top_reg) and
+         assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and
+         (assigned(FindRegDeAlloc(NR_DEFAULTFLAGS,tai(p.Next))) or
+          (not RegInUsedRegs(NR_DEFAULTFLAGS,UsedRegs))) then
+        begin
+          DebugMsg('Redundant Andi removed', p);
+
+          result:=RemoveCurrentP(p);
+        end;
+    end;
+
+
+  function TCpuAsmOptimizer.OptPass1ADD(var p : tai) : boolean;
+    var
+      hp1: tai;
+    begin
+      Result:=false;
+      if (taicpu(p).oper[1]^.reg=GetDefaultZeroReg) and
+      GetNextInstruction(p, hp1) and
+      MatchInstruction(hp1,A_ADC) then
+      begin
+        DebugMsg('Peephole AddAdc2Add performed', p);
+
+        RemoveCurrentP(p, hp1);
+        Result := True;
+      end;
+    end;
+
+
+  function TCpuAsmOptimizer.OptPass1SUB(var p : tai) : boolean;
+    var
+      hp1: tai;
+    begin
+      Result:=false;
+      if (taicpu(p).oper[1]^.reg=GetDefaultZeroReg) and
+      GetNextInstruction(p, hp1) and
+      MatchInstruction(hp1,A_SBC) then
+      begin
+        DebugMsg('Peephole SubSbc2Sub performed', p);
+
+        taicpu(hp1).opcode:=A_SUB;
+
+        RemoveCurrentP(p, hp1);
+        Result := True;
+      end;
+    end;
+
+
+  function TCpuAsmOptimizer.OptPass1CLR(var p : tai) : boolean;
     var
-      hp1,hp2,hp3,hp4,hp5: tai;
+      hp1: tai;
       alloc, dealloc: tai_regalloc;
-      i: integer;
-      l: TAsmLabel;
+    begin
+      Result:=false;
+      { turn the common
+        clr rX
+        mov/ld rX, rY
+        into
+        mov/ld rX, rY
+      }
+      if (taicpu(p).ops=1) and
+         (taicpu(p).oper[0]^.typ=top_reg) and
+         GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
+         (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
+         (hp1.typ=ait_instruction) and
+         (taicpu(hp1).opcode in [A_MOV,A_LD]) and
+         (taicpu(hp1).ops>0) and
+         (taicpu(hp1).oper[0]^.typ=top_reg) and
+         (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) then
+        begin
+          DebugMsg('Peephole ClrMov2Mov performed', p);
+
+          result:=RemoveCurrentP(p);
+        end
+      { turn
+        clr rX
+        ...
+        adc rY, rX
+        into
+        ...
+        adc rY, r1
+      }
+      else if (taicpu(p).ops=1) and
+         (taicpu(p).oper[0]^.typ=top_reg) and
+         GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
+         (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
+         (hp1.typ=ait_instruction) and
+         (taicpu(hp1).opcode in [A_ADC,A_SBC]) and
+         (taicpu(hp1).ops=2) and
+         (taicpu(hp1).oper[1]^.typ=top_reg) and
+         (taicpu(hp1).oper[1]^.reg=taicpu(p).oper[0]^.reg) and
+         (taicpu(hp1).oper[0]^.reg<>taicpu(p).oper[0]^.reg) and
+         assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then
+        begin
+          DebugMsg('Peephole ClrAdc2Adc performed', p);
+
+          taicpu(hp1).oper[1]^.reg:=GetDefaultZeroReg;
+
+          alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
+          dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
+
+          if assigned(alloc) and assigned(dealloc) then
+            begin
+              asml.Remove(alloc);
+              alloc.Free;
+              asml.Remove(dealloc);
+              dealloc.Free;
+            end;
+
+          result:=RemoveCurrentP(p);
+        end;
+    end;
+
+
+  function TCpuAsmOptimizer.OptPass1PUSH(var p : tai) : boolean;
+    var
+      hp1, hp2, hp3: tai;
+    begin
+      Result:=false;
+      { turn
+        push reg0
+        push reg1
+        pop reg3
+        pop reg2
+
+        into
+
+        movw reg2,reg0
+
+        or
+
+        mov  reg3,reg1
+        mov  reg2,reg0
+
+      }
+      if GetNextInstruction(p,hp1) and
+         MatchInstruction(hp1,A_PUSH) and
+
+         GetNextInstruction(hp1,hp2) and
+         MatchInstruction(hp2,A_POP) and
+
+         GetNextInstruction(hp2,hp3) and
+         MatchInstruction(hp3,A_POP) then
+        begin
+         if (CPUAVR_HAS_MOVW in cpu_capabilities[current_settings.cputype]) and
+           (getsupreg(taicpu(hp1).oper[0]^.reg)=getsupreg(taicpu(p).oper[0]^.reg)+1) and
+           ((getsupreg(taicpu(p).oper[0]^.reg) mod 2)=0) and
+           (getsupreg(taicpu(hp2).oper[0]^.reg)=getsupreg(taicpu(hp3).oper[0]^.reg)+1) and
+           ((getsupreg(taicpu(hp3).oper[0]^.reg) mod 2)=0) then
+           begin
+             DebugMsg('Peephole PushPushPopPop2Movw performed', p);
+
+             taicpu(hp3).ops:=2;
+             taicpu(hp3).opcode:=A_MOVW;
+
+             taicpu(hp3).loadreg(1, taicpu(p).oper[0]^.reg);
+
+             { We're removing 3 concurrent instructions.  Remove hp1
+               and hp2 manually instead of calling RemoveCurrentP
+               as this means we won't be calling UpdateUsedRegs 3 times }
+             asml.Remove(hp1);
+             hp1.Free;
+
+             asml.Remove(hp2);
+             hp2.Free;
+
+             { By removing p last, we've guaranteed that p.Next is
+               valid (storing it prior to removing the instructions
+               may result in a dangling pointer if hp1 immediately
+               follows p), and because hp1, hp2 and hp3 came from
+               sequential calls to GetNextInstruction, it is
+               guaranteed that UpdateUsedRegs will stop at hp3. [Kit] }
+             RemoveCurrentP(p, hp3);
+             Result := True;
+           end
+         else
+           begin
+             DebugMsg('Peephole PushPushPopPop2MovMov performed', p);
+
+             taicpu(p).ops:=2;
+             taicpu(p).opcode:=A_MOV;
+
+             taicpu(hp1).ops:=2;
+             taicpu(hp1).opcode:=A_MOV;
+
+             taicpu(p).loadreg(1, taicpu(p).oper[0]^.reg);
+             taicpu(p).loadreg(0, taicpu(hp3).oper[0]^.reg);
+
+             taicpu(hp1).loadreg(1, taicpu(hp1).oper[0]^.reg);
+             taicpu(hp1).loadreg(0, taicpu(hp2).oper[0]^.reg);
+
+             { life range of reg2 and reg3 is increased, fix register allocation entries }
+             TransferUsedRegs(TmpUsedRegs);
+             UpdateUsedRegs(TmpUsedRegs,tai(p.Next));
+             AllocRegBetween(taicpu(hp2).oper[0]^.reg,hp1,hp2,TmpUsedRegs);
+
+             TransferUsedRegs(TmpUsedRegs);
+             AllocRegBetween(taicpu(hp3).oper[0]^.reg,p,hp3,TmpUsedRegs);
+
+             IncludeRegInUsedRegs(taicpu(hp3).oper[0]^.reg,UsedRegs);
+             UpdateUsedRegs(tai(p.Next));
+
+             asml.Remove(hp2);
+             hp2.Free;
+             asml.Remove(hp3);
+             hp3.Free;
+
+             result:=true;
+           end
+
+        end;
+    end;
+
+
+  function TCpuAsmOptimizer.OptPass1CALL(var p : tai) : boolean;
+    var
+      hp1: tai;
+    begin
+      Result:=false;
+      if (cs_opt_level4 in current_settings.optimizerswitches) and
+        GetNextInstruction(p,hp1) and
+        MatchInstruction(hp1,A_RET) then
+        begin
+           DebugMsg('Peephole CallReg2Jmp performed', p);
+
+           taicpu(p).opcode:=A_JMP;
+
+           asml.Remove(hp1);
+           hp1.Free;
+
+           result:=true;
+        end;
+    end;
+
+
+  function TCpuAsmOptimizer.OptPass1RCALL(var p : tai) : boolean;
+    var
+      hp1: tai;
+    begin
+      Result:=false;
+      if (cs_opt_level4 in current_settings.optimizerswitches) and
+        GetNextInstruction(p,hp1) and
+        MatchInstruction(hp1,A_RET) then
+        begin
+           DebugMsg('Peephole RCallReg2RJmp performed', p);
+
+           taicpu(p).opcode:=A_RJMP;
+
+           asml.Remove(hp1);
+           hp1.Free;
+
+           result:=true;
+        end;
+    end;
+
+
+  function TCpuAsmOptimizer.OptPass1MOV(var p : tai) : boolean;
+    var
+      hp1, hp2: tai;
+      i : Integer;
+      alloc, dealloc: tai_regalloc;
+    begin
+      Result:=false;
+      { change
+        mov reg0, reg1
+        dealloc reg0
+        into
+        dealloc reg0
+      }
+      if MatchOpType(taicpu(p),top_reg,top_reg) then
+        begin
+          TransferUsedRegs(TmpUsedRegs);
+          UpdateUsedRegs(TmpUsedRegs,tai(p.Next));
+          if not(RegInUsedRegs(taicpu(p).oper[0]^.reg,TmpUsedRegs)) and
+            { reg. allocation information before calls is not perfect, so don't do this before
+              calls/icalls }
+            GetNextInstruction(p,hp1) and
+            not(MatchInstruction(hp1,[A_CALL,A_RCALL])) then
+            begin
+              DebugMsg('Peephole Mov2Nop performed', p);
+              RemoveCurrentP(p, hp1);
+              Result := True;
+              exit;
+            end;
+        end;
+
+      { turn
+        mov reg0, reg1
+        <op> reg2,reg0
+        dealloc reg0
+        into
+        <op> reg2,reg1
+      }
+      if MatchOpType(taicpu(p),top_reg,top_reg) and
+         GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
+         (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p, hp1)) and
+         (MatchInstruction(hp1,[A_PUSH,A_MOV,A_CP,A_CPC,A_ADD,A_SUB,A_ADC,A_SBC,A_EOR,A_AND,A_OR,
+                                 A_OUT,A_IN]) or
+         { the reference register of ST/STD cannot be replaced }
+         (MatchInstruction(hp1,[A_STD,A_ST,A_STS]) and (MatchOperand(taicpu(p).oper[0]^,taicpu(hp1).oper[1]^)))) and
+         (not RegModifiedByInstruction(taicpu(p).oper[0]^.reg, hp1)) and
+         {(taicpu(hp1).ops=1) and
+         (taicpu(hp1).oper[0]^.typ = top_reg) and
+         (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and  }
+         assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then
+        begin
+          DebugMsg('Peephole MovOp2Op 1 performed', p);
+
+          for i := 0 to taicpu(hp1).ops-1 do
+            if taicpu(hp1).oper[i]^.typ=top_reg then
+              if taicpu(hp1).oper[i]^.reg=taicpu(p).oper[0]^.reg then
+                taicpu(hp1).oper[i]^.reg:=taicpu(p).oper[1]^.reg;
+
+          alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
+          dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
+
+          if assigned(alloc) and assigned(dealloc) then
+            begin
+              asml.Remove(alloc);
+              alloc.Free;
+              asml.Remove(dealloc);
+              dealloc.Free;
+            end;
+
+          { life range of reg1 is increased }
+          AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,usedregs);
+          { p will be removed, update used register as we continue
+            with the next instruction after p }
+
+          result:=RemoveCurrentP(p);
+        end
+      { turn
+        mov reg1, reg0
+        <op> reg1,xxxx
+        dealloc reg1
+        into
+        <op> reg1,xxx
+      }
+      else if MatchOpType(taicpu(p),top_reg,top_reg) and
+         GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
+         not(RegModifiedBetween(taicpu(p).oper[1]^.reg, p, hp1)) and
+         MatchInstruction(hp1,[A_CP,A_CPC,A_CPI,A_SBRS,A_SBRC]) and
+         assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then
+        begin
+          DebugMsg('Peephole MovOp2Op 2 performed', p);
+
+          for i := 0 to taicpu(hp1).ops-1 do
+            if taicpu(hp1).oper[i]^.typ=top_reg then
+              if taicpu(hp1).oper[i]^.reg=taicpu(p).oper[0]^.reg then
+                taicpu(hp1).oper[i]^.reg:=taicpu(p).oper[1]^.reg;
+
+          alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
+          dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
+
+          if assigned(alloc) and assigned(dealloc) then
+            begin
+              asml.Remove(alloc);
+              alloc.Free;
+              asml.Remove(dealloc);
+              dealloc.Free;
+            end;
+
+          { life range of reg1 is increased }
+          AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,usedregs);
+          { p will be removed, update used register as we continue
+            with the next instruction after p }
+
+          result:=RemoveCurrentP(p);
+        end
+      { remove
+        mov reg0,reg0
+      }
+      else if (taicpu(p).ops=2) and
+         (taicpu(p).oper[0]^.typ = top_reg) and
+         (taicpu(p).oper[1]^.typ = top_reg) and
+         (taicpu(p).oper[0]^.reg = taicpu(p).oper[1]^.reg) then
+        begin
+          DebugMsg('Peephole RedundantMov performed', p);
+
+          result:=RemoveCurrentP(p);
+        end
+      {
+        Turn
+          mov rx,ry
+          op rx,rz
+          mov ry, rx
+        Into
+          op ry,rz
+      }
+      else if (taicpu(p).ops=2) and
+         MatchOpType(taicpu(p),top_reg,top_reg) and
+         GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
+         (hp1.typ=ait_instruction) and
+         (taicpu(hp1).ops >= 1) and
+         (taicpu(hp1).oper[0]^.typ = top_reg) and
+         GetNextInstructionUsingReg(hp1,hp2,taicpu(hp1).oper[0]^.reg) and
+         MatchInstruction(hp2,A_MOV) and
+         MatchOpType(taicpu(hp2),top_reg,top_reg) and
+         (taicpu(hp2).oper[0]^.reg = taicpu(p).oper[1]^.reg) and
+         (taicpu(hp2).oper[1]^.reg = taicpu(hp1).oper[0]^.reg) and
+         (taicpu(hp2).oper[1]^.reg = taicpu(p).oper[0]^.reg) and
+         (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp2)) and
+         (taicpu(hp1).opcode in [A_ADD,A_ADC,A_SUB,A_SBC,A_AND,A_OR,A_EOR,
+                                 A_INC,A_DEC,
+                                 A_LSL,A_LSR,A_ASR,A_ROR,A_ROL]) and
+         assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg, tai(hp2.Next))) then
+        begin
+          DebugMsg('Peephole MovOpMov2Op performed', p);
+
+          if (taicpu(hp1).ops=2) and
+             (taicpu(hp1).oper[1]^.typ=top_reg) and
+             (taicpu(hp1).oper[1]^.reg = taicpu(p).oper[1]^.reg) then
+            taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg;
+
+          taicpu(hp1).oper[0]^.reg:=taicpu(p).oper[1]^.reg;
+
+          alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
+          dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp2.Next));
+
+          if assigned(alloc) and assigned(dealloc) then
+            begin
+              asml.Remove(alloc);
+              alloc.Free;
+              asml.Remove(dealloc);
+              dealloc.Free;
+            end;
+
+          asml.remove(hp2);
+          hp2.free;
+
+          result:=RemoveCurrentP(p);
+        end
+      {
+        Turn
+          mov rx,ry
+          op  rx,rw
+          mov rw,rx
+        Into
+          op rw,ry
+      }
+      else if (taicpu(p).ops=2) and
+         MatchOpType(taicpu(p),top_reg,top_reg) and
+         GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
+         (hp1.typ=ait_instruction) and
+         (taicpu(hp1).ops = 2) and
+         MatchOpType(taicpu(hp1),top_reg,top_reg) and
+         GetNextInstructionUsingReg(hp1,hp2,taicpu(hp1).oper[0]^.reg) and
+         (hp2.typ=ait_instruction) and
+         (taicpu(hp2).opcode=A_MOV) and
+         MatchOpType(taicpu(hp2),top_reg,top_reg) and
+         (taicpu(hp2).oper[0]^.reg = taicpu(hp1).oper[1]^.reg) and
+         (taicpu(hp2).oper[1]^.reg = taicpu(hp1).oper[0]^.reg) and
+         (taicpu(hp2).oper[1]^.reg = taicpu(p).oper[0]^.reg) and
+         (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) and
+         (taicpu(hp1).opcode in [A_ADD,A_ADC,A_AND,A_OR,A_EOR]) and
+         assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg, tai(hp2.Next))) then
+        begin
+          DebugMsg('Peephole MovOpMov2Op2 performed', p);
+
+          taicpu(hp1).oper[0]^.reg:=taicpu(hp2).oper[0]^.reg;
+          taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg;
+
+          alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
+          dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp2.Next));
+
+          if assigned(alloc) and assigned(dealloc) then
+            begin
+              asml.Remove(alloc);
+              alloc.Free;
+              asml.Remove(dealloc);
+              dealloc.Free;
+            end;
+
+          result:=RemoveCurrentP(p);
+
+          asml.remove(hp2);
+          hp2.free;
+        end
+      { fold
+        mov reg2,reg0
+        mov reg3,reg1
+        to
+        movw reg2,reg0
+      }
+      else if (CPUAVR_HAS_MOVW in cpu_capabilities[current_settings.cputype]) and
+         (taicpu(p).ops=2) and
+         (taicpu(p).oper[0]^.typ = top_reg) and
+         (taicpu(p).oper[1]^.typ = top_reg) and
+         getnextinstruction(p,hp1) and
+         (hp1.typ = ait_instruction) and
+         (taicpu(hp1).opcode = A_MOV) and
+         (taicpu(hp1).ops=2) and
+         (taicpu(hp1).oper[0]^.typ = top_reg) and
+         (taicpu(hp1).oper[1]^.typ = top_reg) and
+         (getsupreg(taicpu(hp1).oper[0]^.reg)=getsupreg(taicpu(p).oper[0]^.reg)+1) and
+         ((getsupreg(taicpu(p).oper[0]^.reg) mod 2)=0) and
+         ((getsupreg(taicpu(p).oper[1]^.reg) mod 2)=0) and
+         (getsupreg(taicpu(hp1).oper[1]^.reg)=getsupreg(taicpu(p).oper[1]^.reg)+1) then
+        begin
+          DebugMsg('Peephole MovMov2Movw performed', p);
+
+          alloc:=FindRegAllocBackward(taicpu(hp1).oper[0]^.reg,tai(hp1.Previous));
+          if assigned(alloc) then
+            begin
+              asml.Remove(alloc);
+              asml.InsertBefore(alloc,p);
+              { proper book keeping of currently used registers }
+              IncludeRegInUsedRegs(taicpu(hp1).oper[0]^.reg,UsedRegs);
+            end;
+
+          taicpu(p).opcode:=A_MOVW;
+          asml.remove(hp1);
+          hp1.free;
+          result:=true;
+        end
+      {
+        This removes the first mov from
+        mov rX,...
+        mov rX,...
+      }
+      else if GetNextInstruction(p,hp1) and MatchInstruction(hp1,A_MOV) and
+        { test condition here already instead in the while loop only, else MovMov2Mov 2 might be oversight }
+        MatchInstruction(hp1,A_MOV) and
+        MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) then
+        while MatchInstruction(hp1,A_MOV) and
+              MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and
+              { don't remove the first mov if the second is a mov rX,rX }
+              not(MatchOperand(taicpu(hp1).oper[0]^,taicpu(hp1).oper[1]^)) do
+          begin
+            DebugMsg('Peephole MovMov2Mov 1 performed', p);
+
+            RemoveCurrentP(p,hp1);
+            Result := True;
+
+            GetNextInstruction(hp1,hp1);
+            if not assigned(hp1) then
+              break;
+          end
+      {
+        This removes the second mov from
+        mov rX,rY
+
+        ...
+
+        mov rX,rY
+
+        if rX and rY are not modified in-between
+      }
+      else if GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[1]^.reg) and
+        MatchInstruction(hp1,A_MOV) and
+        MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and
+        MatchOperand(taicpu(p).oper[1]^, taicpu(hp1).oper[1]^) and
+        not(RegModifiedBetween(taicpu(p).oper[0]^.reg,p,hp1)) then
+        begin
+          DebugMsg('Peephole MovMov2Mov 2 performed', p);
+          AllocRegBetween(taicpu(p).oper[0]^.reg,p,hp1,UsedRegs);
+          RemoveInstruction(hp1);
+          Result := True;
+        end;
+    end;
+
+  function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
+    var
+      hp1,hp2: tai;
     begin
       result := false;
       case p.typ of
@@ -373,847 +1344,35 @@ Implementation
             else
               case taicpu(p).opcode of
                 A_LDI:
-                  begin
-                    { turn
-                      ldi reg0, imm
-                      <op> reg1, reg0
-                      dealloc reg0
-                      into
-                      <op>i reg1, imm
-                    }
-                    if MatchOpType(taicpu(p),top_reg,top_const) and
-                       GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
-                       MatchInstruction(hp1,[A_CP,A_MOV,A_AND,A_SUB],2) and
-                       (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
-                       MatchOpType(taicpu(hp1),top_reg,top_reg) and
-                       (getsupreg(taicpu(hp1).oper[0]^.reg) in [16..31]) and
-                       (taicpu(hp1).oper[1]^.reg=taicpu(p).oper[0]^.reg) and
-                       not(MatchOperand(taicpu(hp1).oper[0]^,taicpu(hp1).oper[1]^)) then
-                      begin
-                        TransferUsedRegs(TmpUsedRegs);
-                        UpdateUsedRegs(TmpUsedRegs,tai(p.next));
-                        UpdateUsedRegs(TmpUsedRegs,tai(hp1.next));
-                        if not(RegUsedAfterInstruction(taicpu(hp1).oper[1]^.reg, hp1, TmpUsedRegs)) then
-                          begin
-                            case taicpu(hp1).opcode of
-                              A_CP:
-                                taicpu(hp1).opcode:=A_CPI;
-                              A_MOV:
-                                taicpu(hp1).opcode:=A_LDI;
-                              A_AND:
-                                taicpu(hp1).opcode:=A_ANDI;
-                              A_SUB:
-                                taicpu(hp1).opcode:=A_SUBI;
-                              else
-                                internalerror(2016111901);
-                            end;
-                            taicpu(hp1).loadconst(1, taicpu(p).oper[1]^.val);
-
-                            alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
-                            dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
-
-                            if assigned(alloc) and assigned(dealloc) then
-                              begin
-                                asml.Remove(alloc);
-                                alloc.Free;
-                                asml.Remove(dealloc);
-                                dealloc.Free;
-                              end;
-
-                            DebugMsg('Peephole LdiOp2Opi performed', p);
-
-                            result:=RemoveCurrentP(p);
-                          end;
-                      end;
-                  end;
+                 Result:=OptPass1LDI(p);
                 A_STS:
-                  if (taicpu(p).oper[0]^.ref^.symbol=nil) and
-                    (taicpu(p).oper[0]^.ref^.relsymbol=nil) and
-                    (getsupreg(taicpu(p).oper[0]^.ref^.base)=RS_NO) and
-                    (getsupreg(taicpu(p).oper[0]^.ref^.index)=RS_NO) and
-                    (taicpu(p).oper[0]^.ref^.addressmode=AM_UNCHANGED) and
-                    (((CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype]) and
-                      (taicpu(p).oper[0]^.ref^.offset>=0) and
-                      (taicpu(p).oper[0]^.ref^.offset<=63)) or
-                     (not(CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype]) and
-                      (taicpu(p).oper[0]^.ref^.offset>=32) and
-                      (taicpu(p).oper[0]^.ref^.offset<=95))) then
-                    begin
-                      DebugMsg('Peephole Sts2Out performed', p);
-
-                      taicpu(p).opcode:=A_OUT;
-                      if CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype] then
-                        taicpu(p).loadconst(0,taicpu(p).oper[0]^.ref^.offset)
-                      else
-                        taicpu(p).loadconst(0,taicpu(p).oper[0]^.ref^.offset-32);
-                      result:=true;
-                    end;
+                  Result:=OptPass1STS(p);
                 A_LDS:
-                  if (taicpu(p).oper[1]^.ref^.symbol=nil) and
-                    (taicpu(p).oper[1]^.ref^.relsymbol=nil) and
-                    (getsupreg(taicpu(p).oper[1]^.ref^.base)=RS_NO) and
-                    (getsupreg(taicpu(p).oper[1]^.ref^.index)=RS_NO) and
-                    (taicpu(p).oper[1]^.ref^.addressmode=AM_UNCHANGED) and
-                    (((CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype]) and
-                      (taicpu(p).oper[1]^.ref^.offset>=0) and
-                      (taicpu(p).oper[1]^.ref^.offset<=63)) or
-                     (not(CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype]) and
-                      (taicpu(p).oper[1]^.ref^.offset>=32) and
-                      (taicpu(p).oper[1]^.ref^.offset<=95))) then
-                    begin
-                      DebugMsg('Peephole Lds2In performed', p);
-
-                      taicpu(p).opcode:=A_IN;
-                      if CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype] then
-                        taicpu(p).loadconst(1,taicpu(p).oper[1]^.ref^.offset)
-                      else
-                        taicpu(p).loadconst(1,taicpu(p).oper[1]^.ref^.offset-32);
-
-                      result:=true;
-                    end;
+                  Result:=OptPass1LDS(p);
                 A_IN:
-                    if GetNextInstruction(p,hp1) then
-                      begin
-                        {
-                          in rX,Y
-                          ori rX,n
-                          out Y,rX
-
-                          into
-                          sbi rX,lg(n)
-                        }
-                        if (taicpu(p).oper[1]^.val<=31) and
-                          MatchInstruction(hp1,A_ORI) and
-                          (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
-                          (PopCnt(byte(taicpu(hp1).oper[1]^.val))=1) and
-                          GetNextInstruction(hp1,hp2) and
-                          MatchInstruction(hp2,A_OUT) and
-                          MatchOperand(taicpu(hp2).oper[1]^,taicpu(p).oper[0]^) and
-                          MatchOperand(taicpu(hp2).oper[0]^,taicpu(p).oper[1]^) then
-                          begin
-                            DebugMsg('Peephole InOriOut2Sbi performed', p);
-
-                            taicpu(p).opcode:=A_SBI;
-                            taicpu(p).loadconst(0,taicpu(p).oper[1]^.val);
-                            taicpu(p).loadconst(1,BsrByte(taicpu(hp1).oper[1]^.val));
-                            asml.Remove(hp1);
-                            hp1.Free;
-                            asml.Remove(hp2);
-                            hp2.Free;
-                            result:=true;
-                          end
-                         {
-                          in rX,Y
-                          andi rX,not(n)
-                          out Y,rX
-
-                          into
-                          cbi rX,lg(n)
-                        }
-                        else if (taicpu(p).oper[1]^.val<=31) and
-                           MatchInstruction(hp1,A_ANDI) and
-                           (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
-                           (PopCnt(byte(not(taicpu(hp1).oper[1]^.val)))=1) and
-                           GetNextInstruction(hp1,hp2) and
-                           MatchInstruction(hp2,A_OUT) and
-                           MatchOperand(taicpu(hp2).oper[1]^,taicpu(p).oper[0]^) and
-                           MatchOperand(taicpu(hp2).oper[0]^,taicpu(p).oper[1]^) then
-                          begin
-                            DebugMsg('Peephole InAndiOut2Cbi performed', p);
-
-                            taicpu(p).opcode:=A_CBI;
-                            taicpu(p).loadconst(0,taicpu(p).oper[1]^.val);
-                            taicpu(p).loadconst(1,BsrByte(not(taicpu(hp1).oper[1]^.val)));
-                            asml.Remove(hp1);
-                            hp1.Free;
-                            asml.Remove(hp2);
-                            hp2.Free;
-                            result:=true;
-                          end
-                         {
-                              in rX,Y
-                              andi rX,n
-                              breq/brne L1
-
-                          into
-                              sbis/sbic Y,lg(n)
-                              jmp L1
-                            .Ltemp:
-                        }
-                        else if (taicpu(p).oper[1]^.val<=31) and
-                           MatchInstruction(hp1,A_ANDI) and
-                           (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
-                           (PopCnt(byte(taicpu(hp1).oper[1]^.val))=1) and
-                           GetNextInstruction(hp1,hp2) and
-                           MatchInstruction(hp2,A_BRxx) and
-                           (taicpu(hp2).condition in [C_EQ,C_NE]) then
-                          begin
-                            if taicpu(hp2).condition=C_EQ then
-                              taicpu(p).opcode:=A_SBIS
-                            else
-                              taicpu(p).opcode:=A_SBIC;
-
-                            DebugMsg('Peephole InAndiBrx2SbixJmp performed', p);
-
-                            taicpu(p).loadconst(0,taicpu(p).oper[1]^.val);
-                            taicpu(p).loadconst(1,BsrByte(taicpu(hp1).oper[1]^.val));
-                            asml.Remove(hp1);
-                            hp1.Free;
-
-                            taicpu(hp2).condition:=C_None;
-                            if CPUAVR_HAS_JMP_CALL in cpu_capabilities[current_settings.cputype] then
-                              taicpu(hp2).opcode:=A_JMP
-                            else
-                              taicpu(hp2).opcode:=A_RJMP;
-
-                            current_asmdata.getjumplabel(l);
-                            l.increfs;
-                            asml.InsertAfter(tai_label.create(l), hp2);
-
-                            result:=true;
-                          end;
-                      end;
+                  Result:=OptPass1IN(p);
                 A_SBRS,
                 A_SBRC:
-                  begin
-                    {
-                      Turn
-                        in rx, y
-                        sbr* rx, z
-                      Into
-                        sbi* y, z
-                    }
-                    if (taicpu(p).ops=2) and
-                       (taicpu(p).oper[0]^.typ=top_reg) and
-                       assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and
-                       GetLastInstruction(p,hp1) and
-                       (hp1.typ=ait_instruction) and
-                       (taicpu(hp1).opcode=A_IN) and
-                       (taicpu(hp1).ops=2) and
-                       (taicpu(hp1).oper[1]^.typ=top_const) and
-                       (taicpu(hp1).oper[1]^.val in [0..31]) and
-                       MatchOperand(taicpu(hp1).oper[0]^,taicpu(p).oper[0]^.reg) and
-                       (not RegModifiedBetween(taicpu(p).oper[0]^.reg, hp1, p)) then
-                      begin
-                        if taicpu(p).opcode=A_SBRS then
-                          taicpu(p).opcode:=A_SBIS
-                        else
-                          taicpu(p).opcode:=A_SBIC;
-
-                        taicpu(p).loadconst(0, taicpu(hp1).oper[1]^.val);
-
-                        DebugMsg('Peephole InSbrx2Sbix performed', p);
-
-                        asml.Remove(hp1);
-                        hp1.free;
-
-                        result:=true;
-                      end;
-
-                    if InvertSkipInstruction(p) then
-                      result:=true;
-                  end;
+                  Result:=OptPass1SBR(p);
                 A_ANDI:
-                  begin
-                    {
-                      Turn
-                          andi rx, #pow2
-                          brne l
-                          <op>
-                        l:
-                      Into
-                          sbrs rx, #(1 shl imm)
-                          <op>
-                        l:
-                    }
-                    if (taicpu(p).ops=2) and
-                       (taicpu(p).oper[1]^.typ=top_const) and
-                       ispowerof2(taicpu(p).oper[1]^.val,i) and
-                       assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and
-                       GetNextInstruction(p,hp1) and
-                       (hp1.typ=ait_instruction) and
-                       (taicpu(hp1).opcode=A_BRxx) and
-                       (taicpu(hp1).condition in [C_EQ,C_NE]) and
-                       (taicpu(hp1).ops>0) and
-                       (taicpu(hp1).oper[0]^.typ = top_ref) and
-                       (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and
-                       GetNextInstruction(hp1,hp2) and
-                       (hp2.typ=ait_instruction) and
-                       GetNextInstruction(hp2,hp3) and
-                       (hp3.typ=ait_label) and
-                       (taicpu(hp1).oper[0]^.ref^.symbol=tai_label(hp3).labsym) then
-                      begin
-                        DebugMsg('Peephole AndiBr2Sbr performed', p);
-
-                        taicpu(p).oper[1]^.val:=i;
-
-                        if taicpu(hp1).condition=C_NE then
-                          taicpu(p).opcode:=A_SBRS
-                        else
-                          taicpu(p).opcode:=A_SBRC;
-
-                        asml.Remove(hp1);
-                        hp1.free;
-
-                        result:=true;
-                      end
-                    {
-                      Remove
-                        andi rx, #y
-                        dealloc rx
-                    }
-                    else if (taicpu(p).ops=2) and
-                       (taicpu(p).oper[0]^.typ=top_reg) and
-                       assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and
-                       (assigned(FindRegDeAlloc(NR_DEFAULTFLAGS,tai(p.Next))) or
-                        (not RegInUsedRegs(NR_DEFAULTFLAGS,UsedRegs))) then
-                      begin
-                        DebugMsg('Redundant Andi removed', p);
-
-                        result:=RemoveCurrentP(p);
-                      end;
-                  end;
+                  Result:=OptPass1ANDI(p);
                 A_ADD:
-                  begin
-                    if (taicpu(p).oper[1]^.reg=GetDefaultZeroReg) and
-                    GetNextInstruction(p, hp1) and
-                    MatchInstruction(hp1,A_ADC) then
-                    begin
-                      DebugMsg('Peephole AddAdc2Add performed', p);
-
-                      RemoveCurrentP(p, hp1);
-                      Result := True;
-                    end;
-                  end;
+                  Result:=OptPass1ADD(p);
                 A_SUB:
-                  begin
-                    if (taicpu(p).oper[1]^.reg=GetDefaultZeroReg) and
-                    GetNextInstruction(p, hp1) and
-                    MatchInstruction(hp1,A_SBC) then
-                    begin
-                      DebugMsg('Peephole SubSbc2Sub performed', p);
-
-                      taicpu(hp1).opcode:=A_SUB;
-
-                      RemoveCurrentP(p, hp1);
-                      Result := True;
-                    end;
-                  end;
+                  Result:=OptPass1SUB(p);
                 A_CLR:
-                  begin
-                    { turn the common
-                      clr rX
-                      mov/ld rX, rY
-                      into
-                      mov/ld rX, rY
-                    }
-                    if (taicpu(p).ops=1) and
-                       (taicpu(p).oper[0]^.typ=top_reg) and
-                       GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
-                       (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
-                       (hp1.typ=ait_instruction) and
-                       (taicpu(hp1).opcode in [A_MOV,A_LD]) and
-                       (taicpu(hp1).ops>0) and
-                       (taicpu(hp1).oper[0]^.typ=top_reg) and
-                       (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) then
-                      begin
-                        DebugMsg('Peephole ClrMov2Mov performed', p);
-
-                        result:=RemoveCurrentP(p);
-                      end
-                    { turn
-                      clr rX
-                      ...
-                      adc rY, rX
-                      into
-                      ...
-                      adc rY, r1
-                    }
-                    else if (taicpu(p).ops=1) and
-                       (taicpu(p).oper[0]^.typ=top_reg) and
-                       GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
-                       (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
-                       (hp1.typ=ait_instruction) and
-                       (taicpu(hp1).opcode in [A_ADC,A_SBC]) and
-                       (taicpu(hp1).ops=2) and
-                       (taicpu(hp1).oper[1]^.typ=top_reg) and
-                       (taicpu(hp1).oper[1]^.reg=taicpu(p).oper[0]^.reg) and
-                       (taicpu(hp1).oper[0]^.reg<>taicpu(p).oper[0]^.reg) and
-                       assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then
-                      begin
-                        DebugMsg('Peephole ClrAdc2Adc performed', p);
-
-                        taicpu(hp1).oper[1]^.reg:=GetDefaultZeroReg;
-
-                        alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
-                        dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
-
-                        if assigned(alloc) and assigned(dealloc) then
-                          begin
-                            asml.Remove(alloc);
-                            alloc.Free;
-                            asml.Remove(dealloc);
-                            dealloc.Free;
-                          end;
-
-                        result:=RemoveCurrentP(p);
-                      end;
-                  end;
+                  Result:=OptPass1CLR(p);
                 A_PUSH:
-                  begin
-                    { turn
-                      push reg0
-                      push reg1
-                      pop reg3
-                      pop reg2
-
-                      into
-
-                      movw reg2,reg0
-
-                      or
-
-                      mov  reg3,reg1
-                      mov  reg2,reg0
-
-                    }
-                    if GetNextInstruction(p,hp1) and
-                       MatchInstruction(hp1,A_PUSH) and
-
-                       GetNextInstruction(hp1,hp2) and
-                       MatchInstruction(hp2,A_POP) and
-
-                       GetNextInstruction(hp2,hp3) and
-                       MatchInstruction(hp3,A_POP) then
-                      begin
-                       if (CPUAVR_HAS_MOVW in cpu_capabilities[current_settings.cputype]) and
-                         (getsupreg(taicpu(hp1).oper[0]^.reg)=getsupreg(taicpu(p).oper[0]^.reg)+1) and
-                         ((getsupreg(taicpu(p).oper[0]^.reg) mod 2)=0) and
-                         (getsupreg(taicpu(hp2).oper[0]^.reg)=getsupreg(taicpu(hp3).oper[0]^.reg)+1) and
-                         ((getsupreg(taicpu(hp3).oper[0]^.reg) mod 2)=0) then
-                         begin
-                           DebugMsg('Peephole PushPushPopPop2Movw performed', p);
-
-                           taicpu(hp3).ops:=2;
-                           taicpu(hp3).opcode:=A_MOVW;
-
-                           taicpu(hp3).loadreg(1, taicpu(p).oper[0]^.reg);
-
-                           { We're removing 3 concurrent instructions.  Remove hp1
-                             and hp2 manually instead of calling RemoveCurrentP
-                             as this means we won't be calling UpdateUsedRegs 3 times }
-                           asml.Remove(hp1);
-                           hp1.Free;
-
-                           asml.Remove(hp2);
-                           hp2.Free;
-
-                           { By removing p last, we've guaranteed that p.Next is
-                             valid (storing it prior to removing the instructions
-                             may result in a dangling pointer if hp1 immediately
-                             follows p), and because hp1, hp2 and hp3 came from
-                             sequential calls to GetNextInstruction, it is
-                             guaranteed that UpdateUsedRegs will stop at hp3. [Kit] }
-                           RemoveCurrentP(p, hp3);
-                           Result := True;
-                         end
-                       else
-                         begin
-                           DebugMsg('Peephole PushPushPopPop2MovMov performed', p);
-
-                           taicpu(p).ops:=2;
-                           taicpu(p).opcode:=A_MOV;
-
-                           taicpu(hp1).ops:=2;
-                           taicpu(hp1).opcode:=A_MOV;
-
-                           taicpu(p).loadreg(1, taicpu(p).oper[0]^.reg);
-                           taicpu(p).loadreg(0, taicpu(hp3).oper[0]^.reg);
-
-                           taicpu(hp1).loadreg(1, taicpu(hp1).oper[0]^.reg);
-                           taicpu(hp1).loadreg(0, taicpu(hp2).oper[0]^.reg);
-
-                           { life range of reg2 and reg3 is increased, fix register allocation entries }
-                           TransferUsedRegs(TmpUsedRegs);
-                           UpdateUsedRegs(TmpUsedRegs,tai(p.Next));
-                           AllocRegBetween(taicpu(hp2).oper[0]^.reg,hp1,hp2,TmpUsedRegs);
-
-                           TransferUsedRegs(TmpUsedRegs);
-                           AllocRegBetween(taicpu(hp3).oper[0]^.reg,p,hp3,TmpUsedRegs);
-
-                           IncludeRegInUsedRegs(taicpu(hp3).oper[0]^.reg,UsedRegs);
-                           UpdateUsedRegs(tai(p.Next));
-
-                           asml.Remove(hp2);
-                           hp2.Free;
-                           asml.Remove(hp3);
-                           hp3.Free;
-
-                           result:=true;
-                         end
-
-                      end;
-                  end;
+                  Result:=OptPass1PUSH(p);
                 A_CALL:
-                  if (cs_opt_level4 in current_settings.optimizerswitches) and
-                    GetNextInstruction(p,hp1) and
-                    MatchInstruction(hp1,A_RET) then
-                    begin
-                       DebugMsg('Peephole CallReg2Jmp performed', p);
-
-                       taicpu(p).opcode:=A_JMP;
-
-                       asml.Remove(hp1);
-                       hp1.Free;
-
-                       result:=true;
-                    end;
+                  Result:=OptPass1CALL(p);
                 A_RCALL:
-                  if (cs_opt_level4 in current_settings.optimizerswitches) and
-                    GetNextInstruction(p,hp1) and
-                    MatchInstruction(hp1,A_RET) then
-                    begin
-                       DebugMsg('Peephole RCallReg2RJmp performed', p);
-
-                       taicpu(p).opcode:=A_RJMP;
-
-                       asml.Remove(hp1);
-                       hp1.Free;
-
-                       result:=true;
-                    end;
+                  Result:=OptPass1RCALL(p);
                 A_MOV:
-                  begin
-                    { change
-                      mov reg0, reg1
-                      dealloc reg0
-                      into
-                      dealloc reg0
-                    }
-                    if MatchOpType(taicpu(p),top_reg,top_reg) then
-                      begin
-                        TransferUsedRegs(TmpUsedRegs);
-                        UpdateUsedRegs(TmpUsedRegs,tai(p.Next));
-                        if not(RegInUsedRegs(taicpu(p).oper[0]^.reg,TmpUsedRegs)) and
-                          { reg. allocation information before calls is not perfect, so don't do this before
-                            calls/icalls }
-                          GetNextInstruction(p,hp1) and
-                          not(MatchInstruction(hp1,[A_CALL,A_RCALL])) then
-                          begin
-                            DebugMsg('Peephole Mov2Nop performed', p);
-                            RemoveCurrentP(p, hp1);
-                            Result := True;
-                            exit;
-                          end;
-                      end;
-
-                    { turn
-                      mov reg0, reg1
-                      <op> reg2,reg0
-                      dealloc reg0
-                      into
-                      <op> reg2,reg1
-                    }
-                    if MatchOpType(taicpu(p),top_reg,top_reg) and
-                       GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
-                       (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p, hp1)) and
-                       (MatchInstruction(hp1,[A_PUSH,A_MOV,A_CP,A_CPC,A_ADD,A_SUB,A_ADC,A_SBC,A_EOR,A_AND,A_OR,
-                                               A_OUT,A_IN]) or
-                       { the reference register of ST/STD cannot be replaced }
-                       (MatchInstruction(hp1,[A_STD,A_ST,A_STS]) and (MatchOperand(taicpu(p).oper[0]^,taicpu(hp1).oper[1]^)))) and
-                       (not RegModifiedByInstruction(taicpu(p).oper[0]^.reg, hp1)) and
-                       {(taicpu(hp1).ops=1) and
-                       (taicpu(hp1).oper[0]^.typ = top_reg) and
-                       (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and  }
-                       assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then
-                      begin
-                        DebugMsg('Peephole MovOp2Op performed', p);
-
-                        for i := 0 to taicpu(hp1).ops-1 do
-                          if taicpu(hp1).oper[i]^.typ=top_reg then
-                            if taicpu(hp1).oper[i]^.reg=taicpu(p).oper[0]^.reg then
-                              taicpu(hp1).oper[i]^.reg:=taicpu(p).oper[1]^.reg;
-
-                        alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
-                        dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
-
-                        if assigned(alloc) and assigned(dealloc) then
-                          begin
-                            asml.Remove(alloc);
-                            alloc.Free;
-                            asml.Remove(dealloc);
-                            dealloc.Free;
-                          end;
-
-                        { life range of reg1 is increased }
-                        AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,usedregs);
-                        { p will be removed, update used register as we continue
-                          with the next instruction after p }
-
-                        result:=RemoveCurrentP(p);
-                      end
-                    { remove
-                      mov reg0,reg0
-                    }
-                    else if (taicpu(p).ops=2) and
-                       (taicpu(p).oper[0]^.typ = top_reg) and
-                       (taicpu(p).oper[1]^.typ = top_reg) and
-                       (taicpu(p).oper[0]^.reg = taicpu(p).oper[1]^.reg) then
-                      begin
-                        DebugMsg('Peephole RedundantMov performed', p);
-
-                        result:=RemoveCurrentP(p);
-                      end
-                    {
-                      Turn
-                        mov rx,ry
-                        op rx,rz
-                        mov ry, rx
-                      Into
-                        op ry,rz
-                    }
-                    else if (taicpu(p).ops=2) and
-                       MatchOpType(taicpu(p),top_reg,top_reg) and
-                       GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
-                       (hp1.typ=ait_instruction) and
-                       (taicpu(hp1).ops >= 1) and
-                       (taicpu(hp1).oper[0]^.typ = top_reg) and
-                       GetNextInstructionUsingReg(hp1,hp2,taicpu(hp1).oper[0]^.reg) and
-                       MatchInstruction(hp2,A_MOV) and
-                       MatchOpType(taicpu(hp2),top_reg,top_reg) and
-                       (taicpu(hp2).oper[0]^.reg = taicpu(p).oper[1]^.reg) and
-                       (taicpu(hp2).oper[1]^.reg = taicpu(hp1).oper[0]^.reg) and
-                       (taicpu(hp2).oper[1]^.reg = taicpu(p).oper[0]^.reg) and
-                       (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp2)) and
-                       (taicpu(hp1).opcode in [A_ADD,A_ADC,A_SUB,A_SBC,A_AND,A_OR,A_EOR,
-                                               A_INC,A_DEC,
-                                               A_LSL,A_LSR,A_ASR,A_ROR,A_ROL]) and
-                       assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg, tai(hp2.Next))) then
-                      begin
-                        DebugMsg('Peephole MovOpMov2Op performed', p);
-
-                        if (taicpu(hp1).ops=2) and
-                           (taicpu(hp1).oper[1]^.typ=top_reg) and
-                           (taicpu(hp1).oper[1]^.reg = taicpu(p).oper[1]^.reg) then
-                          taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg;
-
-                        taicpu(hp1).oper[0]^.reg:=taicpu(p).oper[1]^.reg;
-
-                        alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
-                        dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp2.Next));
-
-                        if assigned(alloc) and assigned(dealloc) then
-                          begin
-                            asml.Remove(alloc);
-                            alloc.Free;
-                            asml.Remove(dealloc);
-                            dealloc.Free;
-                          end;
-
-                        asml.remove(hp2);
-                        hp2.free;
-
-                        result:=RemoveCurrentP(p);
-                      end
-                    {
-                      Turn
-                        mov rx,ry
-                        op  rx,rw
-                        mov rw,rx
-                      Into
-                        op rw,ry
-                    }
-                    else if (taicpu(p).ops=2) and
-                       MatchOpType(taicpu(p),top_reg,top_reg) and
-                       GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
-                       (hp1.typ=ait_instruction) and
-                       (taicpu(hp1).ops = 2) and
-                       MatchOpType(taicpu(hp1),top_reg,top_reg) and
-                       GetNextInstructionUsingReg(hp1,hp2,taicpu(hp1).oper[0]^.reg) and
-                       (hp2.typ=ait_instruction) and
-                       (taicpu(hp2).opcode=A_MOV) and
-                       MatchOpType(taicpu(hp2),top_reg,top_reg) and
-                       (taicpu(hp2).oper[0]^.reg = taicpu(hp1).oper[1]^.reg) and
-                       (taicpu(hp2).oper[1]^.reg = taicpu(hp1).oper[0]^.reg) and
-                       (taicpu(hp2).oper[1]^.reg = taicpu(p).oper[0]^.reg) and
-                       (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) and
-                       (taicpu(hp1).opcode in [A_ADD,A_ADC,A_AND,A_OR,A_EOR]) and
-                       assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg, tai(hp2.Next))) then
-                      begin
-                        DebugMsg('Peephole MovOpMov2Op2 performed', p);
-
-                        taicpu(hp1).oper[0]^.reg:=taicpu(hp2).oper[0]^.reg;
-                        taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg;
-
-                        alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
-                        dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp2.Next));
-
-                        if assigned(alloc) and assigned(dealloc) then
-                          begin
-                            asml.Remove(alloc);
-                            alloc.Free;
-                            asml.Remove(dealloc);
-                            dealloc.Free;
-                          end;
-
-                        result:=RemoveCurrentP(p);
-
-                        asml.remove(hp2);
-                        hp2.free;
-                      end
-                    { fold
-                      mov reg2,reg0
-                      mov reg3,reg1
-                      to
-                      movw reg2,reg0
-                    }
-                    else if (CPUAVR_HAS_MOVW in cpu_capabilities[current_settings.cputype]) and
-                       (taicpu(p).ops=2) and
-                       (taicpu(p).oper[0]^.typ = top_reg) and
-                       (taicpu(p).oper[1]^.typ = top_reg) and
-                       getnextinstruction(p,hp1) and
-                       (hp1.typ = ait_instruction) and
-                       (taicpu(hp1).opcode = A_MOV) and
-                       (taicpu(hp1).ops=2) and
-                       (taicpu(hp1).oper[0]^.typ = top_reg) and
-                       (taicpu(hp1).oper[1]^.typ = top_reg) and
-                       (getsupreg(taicpu(hp1).oper[0]^.reg)=getsupreg(taicpu(p).oper[0]^.reg)+1) and
-                       ((getsupreg(taicpu(p).oper[0]^.reg) mod 2)=0) and
-                       ((getsupreg(taicpu(p).oper[1]^.reg) mod 2)=0) and
-                       (getsupreg(taicpu(hp1).oper[1]^.reg)=getsupreg(taicpu(p).oper[1]^.reg)+1) then
-                      begin
-                        DebugMsg('Peephole MovMov2Movw performed', p);
-
-                        alloc:=FindRegAllocBackward(taicpu(hp1).oper[0]^.reg,tai(hp1.Previous));
-                        if assigned(alloc) then
-                          begin
-                            asml.Remove(alloc);
-                            asml.InsertBefore(alloc,p);
-                            { proper book keeping of currently used registers }
-                            IncludeRegInUsedRegs(taicpu(hp1).oper[0]^.reg,UsedRegs);
-                          end;
-
-                        taicpu(p).opcode:=A_MOVW;
-                        asml.remove(hp1);
-                        hp1.free;
-                        result:=true;
-                      end
-                    {
-                      This removes the first mov from
-                      mov rX,...
-                      mov rX,...
-                    }
-                    else if GetNextInstruction(p,hp1) and MatchInstruction(hp1,A_MOV) and
-                      { test condition here already instead in the while loop only, else MovMov2Mov 2 might be oversight }
-                      MatchInstruction(hp1,A_MOV) and
-                      MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) then
-                      while MatchInstruction(hp1,A_MOV) and
-                            MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and
-                            { don't remove the first mov if the second is a mov rX,rX }
-                            not(MatchOperand(taicpu(hp1).oper[0]^,taicpu(hp1).oper[1]^)) do
-                        begin
-                          DebugMsg('Peephole MovMov2Mov 1 performed', p);
-
-                          RemoveCurrentP(p,hp1);
-                          Result := True;
-
-                          GetNextInstruction(hp1,hp1);
-                          if not assigned(hp1) then
-                            break;
-                        end
-                    {
-                      This removes the second mov from
-                      mov rX,rY
-
-                      ...
-
-                      mov rX,rY
-
-                      if rX and rY are not modified in-between
-                    }
-                    else if GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[1]^.reg) and
-                      MatchInstruction(hp1,A_MOV) and
-                      MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and
-                      MatchOperand(taicpu(p).oper[1]^, taicpu(hp1).oper[1]^) and
-                      not(RegModifiedBetween(taicpu(p).oper[0]^.reg,p,hp1)) then
-                      begin
-                        DebugMsg('Peephole MovMov2Mov 2 performed', p);
-                        AllocRegBetween(taicpu(p).oper[0]^.reg,p,hp1,UsedRegs);
-                        RemoveInstruction(hp1);
-                        Result := True;
-                      end;
-                  end;
+                  Result:=OptPass1MOV(p);
                 A_SBIC,
                 A_SBIS:
-                  begin
-                    {
-                      Turn
-                          sbic/sbis X, y
-                          jmp .L1
-                          op
-                        .L1:
-
-                      into
-                          sbis/sbic X,y
-                          op
-                        .L1:
-                    }
-                    if InvertSkipInstruction(p) then
-                      result:=true
-                    {
-                      Turn
-                          sbiX X, y
-                          jmp .L1
-                          jmp .L2
-                        .L1:
-                          op
-                        .L2:
-
-                      into
-                          sbiX X,y
-                        .L1:
-                          op
-                        .L2:
-                    }
-                    else if GetNextInstruction(p, hp1) and
-                       (hp1.typ=ait_instruction) and
-                       (taicpu(hp1).opcode in [A_JMP,A_RJMP]) and
-                       (taicpu(hp1).ops>0) and
-                       (taicpu(hp1).oper[0]^.typ = top_ref) and
-                       (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and
-
-                       GetNextInstruction(hp1, hp2) and
-                       (hp2.typ=ait_instruction) and
-                       (taicpu(hp2).opcode in [A_JMP,A_RJMP]) and
-                       (taicpu(hp2).ops>0) and
-                       (taicpu(hp2).oper[0]^.typ = top_ref) and
-                       (taicpu(hp2).oper[0]^.ref^.symbol is TAsmLabel) and
-
-                       GetNextInstruction(hp2, hp3) and
-                       (hp3.typ=ait_label) and
-                       (taicpu(hp1).oper[0]^.ref^.symbol=tai_label(hp3).labsym) and
-
-                       GetNextInstruction(hp3, hp4) and
-                       (hp4.typ=ait_instruction) and
-
-                       GetNextInstruction(hp4, hp5) and
-                       (hp3.typ=ait_label) and
-                       (taicpu(hp2).oper[0]^.ref^.symbol=tai_label(hp5).labsym) then
-                      begin
-                        DebugMsg('Peephole SbiJmpJmp2Sbi performed',p);
-
-                        tai_label(hp3).labsym.decrefs;
-                        tai_label(hp5).labsym.decrefs;
-
-                        AsmL.remove(hp1);
-                        taicpu(hp1).Free;
-
-                        AsmL.remove(hp2);
-                        taicpu(hp2).Free;
-
-                        result:=true;
-                      end;
-                  end;
+                  Result:=OptPass1SBI(p);
               end;
           end;
       end;

+ 2 - 1
compiler/avr/ccpuinnr.inc

@@ -18,5 +18,6 @@
   in_avr_sleep = in_cpu_first+3,
   in_avr_nop = in_cpu_first+4,
   in_avr_save = in_cpu_first+5,
-  in_avr_restore = in_cpu_first+6
+  in_avr_restore = in_cpu_first+6,
+  in_avr_des = in_cpu_first+7
 

+ 3 - 1
compiler/avr/cgcpu.pas

@@ -2357,7 +2357,9 @@ unit cgcpu;
          if ref.addressmode<>AM_UNCHANGED then
            internalerror(2011021706);
 
-        if assigned(ref.symbol) or (ref.offset<>0) then
+         if assigned(ref.symbol) or (ref.offset<>0) or
+           { If no other reference information it must imply an absolute reference to address 0 }
+           ((ref.index=NR_NO) and (ref.base=NR_NO)) then
           begin
             reference_reset(tmpref,0,[]);
             tmpref.symbol:=ref.symbol;

+ 2 - 1
compiler/avr/cpubase.pas

@@ -53,7 +53,8 @@ unit cpubase;
         A_LSL,A_LSR,A_ROL,A_ROR,A_ASR,A_SWAP,A_BSET,A_BCLR,A_SBI,A_CBI,
         A_SEC,A_SEH,A_SEI,A_SEN,A_SER,A_SES,A_SET,A_SEV,A_SEZ,
         A_CLC,A_CLH,A_CLI,A_CLN,A_CLR,A_CLS,A_CLT,A_CLV,A_CLZ,
-        A_BST,A_BLD,A_BREAK,A_NOP,A_SLEEP,A_WDR,A_XCH);
+        A_BST,A_BLD,A_BREAK,A_NOP,A_SLEEP,A_WDR,A_XCH,
+        A_DES);
 
 
       { This should define the array of instructions as string }

+ 2 - 1
compiler/avr/itcpugas.pas

@@ -44,7 +44,8 @@ interface
         'lsl','lsr','rol','ror','asr','swap','bset','bclr','sbi','cbi',
         'sec','seh','sei','sen','ser','ses','set','sev','sez',
         'clc','clh','cli','cln','clr','cls','clt','clv','clz',
-        'bst','bld','break','nop','sleep','wdr','xch');
+        'bst','bld','break','nop','sleep','wdr','xch',
+        'des');
 
     function gas_regnum_search(const s:string):Tregister;
     function gas_regname(r:Tregister):string;

+ 75 - 1
compiler/avr/navrinl.pas

@@ -40,6 +40,8 @@ unit navrinl;
   implementation
 
     uses
+      verbose,
+      constexp,
       compinnr,
       aasmdata,
       aasmcpu,
@@ -48,6 +50,7 @@ unit navrinl;
       hlcgobj,
       pass_2,
       cgbase, cgobj, cgutils,
+      ncon,ncal,
       cpubase;
 
     procedure tavrinlinenode.second_abs_long;
@@ -72,6 +75,8 @@ unit navrinl;
 
 
     function tavrinlinenode.pass_typecheck_cpu : tnode;
+      var
+        para1,para2,para3,para4: tcallparanode;
       begin
         Result:=nil;
         case inlinenumber of
@@ -94,6 +99,22 @@ unit navrinl;
               CheckParameters(1);
               resultdef:=voidtype;
             end;
+          in_avr_des:
+            begin
+              CheckParameters(4);
+              resultdef:=voidtype;
+              para4:=tcallparanode(left);
+              para3:=tcallparanode(tcallparanode(para4).nextpara);
+              para2:=tcallparanode(tcallparanode(para3).nextpara);
+              para1:=tcallparanode(tcallparanode(para2).nextpara);
+              if not(is_constintnode(para4.paravalue)) then
+                MessagePos(para4.paravalue.fileinfo,type_e_constant_expr_expected);
+              if not(is_constboolnode(para3.paravalue)) then
+                MessagePos(para3.paravalue.fileinfo,type_e_constant_expr_expected);
+              if (tordconstnode(para4.paravalue).value<0) or
+                (tordconstnode(para4.paravalue).value>15) then
+                MessagePos(para4.paravalue.fileinfo,parser_e_range_check_error);
+            end;
           else
             Result:=inherited pass_typecheck_cpu;
         end;
@@ -109,7 +130,8 @@ unit navrinl;
           in_avr_sei,
           in_avr_wdr,
           in_avr_cli,
-          in_avr_restore:
+          in_avr_restore,
+          in_avr_des:
             begin
               expectloc:=LOC_VOID;
               resultdef:=voidtype;
@@ -126,6 +148,10 @@ unit navrinl;
 
 
     procedure tavrinlinenode.pass_generate_code_cpu;
+      var
+        para1,para2,para3,para4: tcallparanode;
+        ref: treference;
+        r: TRegister;
       begin
         case inlinenumber of
           in_avr_nop:
@@ -152,6 +178,54 @@ unit navrinl;
               hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
               current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_OUT, NIO_SREG, left.location.register));
             end;
+          in_avr_des:
+            begin
+              para4:=tcallparanode(left);
+              para3:=tcallparanode(tcallparanode(para4).nextpara);
+              para2:=tcallparanode(tcallparanode(para3).nextpara);
+              para1:=tcallparanode(tcallparanode(para2).nextpara);
+              secondpass(tcallparanode(para1).paravalue);
+              secondpass(tcallparanode(para2).paravalue);
+
+              cg.getcpuregister(current_asmdata.CurrAsmList,NR_R30);
+              cg.getcpuregister(current_asmdata.CurrAsmList,NR_R31);
+
+              cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,tcallparanode(para2).paravalue.location.reference,NR_R30);
+              reference_reset(ref,0,[]);
+              ref.base:=NR_R30;
+              for r:=NR_R8 to NR_R15 do
+                begin
+                  cg.getcpuregister(current_asmdata.CurrAsmList,r);
+                  cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_8,OS_8,ref,r);
+                  inc(ref.offset);
+                end;
+              cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,tcallparanode(para1).paravalue.location.reference,NR_R30);
+              reference_reset(ref,0,[]);
+              ref.base:=NR_R30;
+              for r:=NR_R0 to NR_R7 do
+                begin
+                  cg.getcpuregister(current_asmdata.CurrAsmList,r);
+                  cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_8,OS_8,ref,r);
+                  inc(ref.offset);
+                end;
+              if tordconstnode(para3.paravalue).value=0 then
+                current_asmdata.CurrAsmList.concat(taicpu.op_none(A_CLH))
+              else
+                current_asmdata.CurrAsmList.concat(taicpu.op_none(A_SEH));
+              current_asmdata.CurrAsmList.concat(taicpu.op_const(A_DES,int64(tordconstnode(para4.paravalue).value)));
+
+              for r:=NR_R8 to NR_R15 do
+                cg.ungetcpuregister(current_asmdata.CurrAsmList,r);
+
+              { save data }
+              ref.offset:=0;
+              for r:=NR_R0 to NR_R7 do
+                begin
+                  cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_8,OS_8,r,ref);
+                  cg.ungetcpuregister(current_asmdata.CurrAsmList,r);
+                  inc(ref.offset);
+                end;
+            end
           else
             inherited pass_generate_code_cpu;
         end;

+ 3 - 1
compiler/avr/raavr.pas

@@ -256,7 +256,9 @@ unit raavr;
        // A_WDR
        (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none))),
        // A_XCH
-       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_Z), (typ: top_reg; rt: rt_all)))
+       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_Z), (typ: top_reg; rt: rt_all))),
+       // A_DES
+       (numOperands: (1 shl 1); Operands: ((typ: top_const; max: 15; min: 0), (typ: top_none)))
        );
 {$POP}
 

+ 9 - 6
compiler/cclasses.pas

@@ -883,15 +883,18 @@ begin
   else
     begin
       Result:=-1;
-      psrc:=@FList^[FCount-1];
-      For Index:=FCount-1 downto 0 Do
+      if FCount>0 then
         begin
-          if psrc^=Item then
+          psrc:=@FList^[FCount-1];
+          For Index:=FCount-1 downto 0 Do
             begin
-              Result:=Index;
-              exit;
+              if psrc^=Item then
+                begin
+                  Result:=Index;
+                  exit;
+                end;
+              dec(psrc);
             end;
-          dec(psrc);
         end;
     end;
 end;

+ 0 - 4
compiler/cgbase.pas

@@ -322,10 +322,6 @@ interface
       end;
 {$endif cpu64bitalu}
 
-      Tregistermmxset = record
-        reg0,reg1,reg2,reg3:Tregister
-      end;
-
       { Set type definition for registers }
       tsuperregisterset = array[byte] of set of byte;
 

+ 2 - 2
compiler/cgutils.pas

@@ -197,7 +197,7 @@ unit cgutils;
     { This routine verifies if two references are the same, and
        if so, returns TRUE, otherwise returns false.
     }
-    function references_equal(const sref,dref : treference) : boolean;
+    function references_equal(const sref,dref : treference) : boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
 
     { tlocation handling }
 
@@ -262,7 +262,7 @@ uses
       end;
 
 
-    function references_equal(const sref,dref : treference):boolean;
+    function references_equal(const sref,dref : treference):boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
       begin
         references_equal:=CompareByte(sref,dref,sizeof(treference))=0;
       end;

+ 4 - 0
compiler/fpcdefs.inc

@@ -224,6 +224,10 @@
   {$if defined(CPUARMHF) and not(defined(FPC_OARM)) and not(defined(FPC_ARMEL)) and not(defined(FPC_ARMEB))}
     {$define FPC_ARMHF}
   {$endif}
+  { inherit FPC_OARM? }
+  {$if defined(CPUARM) and not(defined(FPC_ARMHF)) and not(defined(FPC_ARMEL)) and not(defined(FPC_ARMEB))}
+    {$define FPC_ARMHF}
+  {$endif}
 {$endif arm}
 
 {$ifdef m68k}

+ 6 - 2
compiler/i386/aoptcpu.pas

@@ -166,6 +166,8 @@ unit aoptcpu;
                 A_MOVSX,
                 A_MOVZX :
                   Result:=OptPass1Movx(p);
+                A_TEST:
+                  Result:=OptPass1Test(p);
                 A_PUSH:
                   begin
                     if (taicpu(p).opsize = S_W) and
@@ -187,6 +189,8 @@ unit aoptcpu;
                   Result:=OptPass1SHLSAL(p);
                 A_SUB:
                   Result:=OptPass1Sub(p);
+                A_Jcc:
+                  Result:=OptPass1Jcc(p);
                 A_MOVAPD,
                 A_MOVAPS,
                 A_MOVUPD,
@@ -219,8 +223,6 @@ unit aoptcpu;
                 A_MOVSD,
                 A_MOVSS:
                   Result:=OptPass1MOVXX(p);
-                A_SETcc:
-                  Result:=OptPass1SETcc(p);
                 else
                   ;
               end;
@@ -258,6 +260,8 @@ unit aoptcpu;
                   Result:=OptPass2Movx(p);
                 A_SUB:
                   Result:=OptPass2SUB(p);
+                A_SETcc:
+                  Result:=OptPass2SETcc(p);
                 else
                   ;
               end;

+ 1 - 0
compiler/systems.inc

@@ -266,6 +266,7 @@
              ,as_z80_rel
              ,as_wasm32_wabt
              ,as_wasm32_llvm_mc        { WebAssembly code assembled by llvm-mc (llvm machine code playground) }
+             ,as_arm_vasm
        );
 
        tlink = (ld_none,

+ 2 - 1
compiler/systems.pas

@@ -385,7 +385,8 @@ interface
                                             system_aarch64_win64];
 
        { all systems for which weak linking has been tested/is supported }
-       systems_weak_linking = systems_darwin + systems_solaris + systems_linux + systems_android + systems_openbsd + systems_freebsd;
+       systems_weak_linking = systems_darwin + systems_solaris + systems_linux + systems_android + systems_openbsd + systems_freebsd +
+                              [system_m68k_sinclairql];
 
        systems_internal_sysinit = [system_i386_win32,system_x86_64_win64,
                                    system_i386_linux,system_powerpc64_linux,system_sparc64_linux,system_x86_64_linux,

+ 1 - 0
compiler/systems/t_sinclairql.pas

@@ -224,6 +224,7 @@ begin
       Add('  .bss (NOLOAD): {');
       Add('      _sbss = .;');
       Add('      *(.bss .bss.*)');
+      Add('      . = ALIGN(2); SHORT(0x0000);');
       Add('      _ebss = .;');
       Add('  } :'+ProgramHeaderName);
       Add('}');

File diff suppressed because it is too large
+ 939 - 235
compiler/x86/aoptx86.pas


+ 15 - 0
compiler/x86/cpubase.pas

@@ -340,6 +340,7 @@ topsize2memsize: array[topsize] of integer =
     function reg2opsize(r:Tregister):topsize;
     function reg_cgsize(const reg: tregister): tcgsize;
     function is_calljmp(o:tasmop):boolean;
+    function is_calljmpuncond(o:tasmop):boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
     procedure inverse_flags(var f: TResFlags);
     function flags_to_cond(const f: TResFlags) : TAsmCond;
     function is_segment_reg(r:tregister):boolean;
@@ -577,6 +578,20 @@ implementation
       end;
 
 
+    function is_calljmpuncond(o:tasmop):boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
+      begin
+        case o of
+          A_CALL,
+          A_JMP,
+          A_LCALL,
+          A_LJMP:
+            is_calljmpuncond:=true;
+          else
+            is_calljmpuncond:=false;
+        end;
+      end;
+
+
     procedure inverse_flags(var f: TResFlags);
       const
         inv_flags: array[TResFlags] of TResFlags =

+ 6 - 2
compiler/x86_64/aoptcpu.pas

@@ -127,8 +127,6 @@ uses
                   result:=OptPass1Sub(p);
                 A_SHL,A_SAL:
                   result:=OptPass1SHLSAL(p);
-                A_SETcc:
-                  result:=OptPass1SETcc(p);
                 A_FSTP,A_FISTP:
                   result:=OptPass1FSTP(p);
                 A_FLD:
@@ -145,6 +143,10 @@ uses
                 A_XORPD,
                 A_PXOR:
                   Result:=OptPass1PXor(p);
+                A_TEST:
+                  Result:=OptPass1Test(p);
+                A_Jcc:
+                  Result:=OptPass1Jcc(p);
                 else
                   ;
               end;
@@ -179,6 +181,8 @@ uses
                   Result:=OptPass2SUB(p);
                 A_ADD:
                   Result:=OptPass2ADD(p);
+                A_SETcc:
+                  result:=OptPass2SETcc(p);
                 else
                   ;
               end;

+ 24 - 11
compiler/xtensa/cgcpu.pas

@@ -655,6 +655,7 @@ implementation
             case target_info.abi of
               abi_xtensa_call0:
                 begin
+                  list.concat(tai_comment.Create(strpnew('  Start of abi_call0 entry localsize='+tostr(localsize))));
                   if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
                     Include(regs,RS_A15);
                   if pi_do_call in current_procinfo.flags then
@@ -693,23 +694,29 @@ implementation
                         begin
                           reference_reset(ref,4,[]);
                           ref.symbol:=create_data_entry(nil,-localsize);
+                          list.concat(tai_comment.Create(strpnew(' Decreasing stack pointer by localsize='+tostr(localsize)+' using A8 register')));
                           list.concat(taicpu.op_reg_ref(A_L32R,NR_A8,ref));
                           list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_A8));
                         end
                       else
-                        list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-localsize));
+                        begin
+                          list.concat(tai_comment.Create(strpnew(' Decreasing stack pointer by localsize='+tostr(localsize)+' using A8 register')));
+                          list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-localsize));
+                        end;
                     end;
 
                   reference_reset(ref,4,[]);
                   ref.base:=NR_STACK_POINTER_REG;
                   ref.offset:=localsize;
-                  if ref.offset>1024 then
+                  if localsize>1024 then
                     begin
-                      if ref.offset<=1024+32512 then
+                      list.concat(tai_comment.Create(strpnew('  Special entry code of abi_xtensa_call0 entry localsize='+tostr(localsize))));
+                      if localsize<=1024+32512 then
                         begin
-                          list.concat(taicpu.op_reg_reg_const(A_ADDMI,NR_A8,NR_STACK_POINTER_REG,ref.offset and $fffffc00));
-                          ref.offset:=ref.offset and $3ff;
+                          list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_A8,NR_STACK_POINTER_REG,localsize-registerarea));
+                          reference_reset(ref,4,[]);
                           ref.base:=NR_A8;
+                          ref.offset:=registerarea;
                         end
                       else
                         begin
@@ -726,6 +733,7 @@ implementation
                   if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
                     begin
                       dec(ref.offset,4);
+                      list.concat(tai_comment.Create(strpnew(' Storing reg A15 at offset='+tostr(ref.offset))));
                       list.concat(taicpu.op_reg_ref(A_S32I,NR_A15,ref));
                       a_reg_alloc(list,NR_FRAME_POINTER_REG);
                       list.concat(taicpu.op_reg_reg(A_MOV,NR_A15,NR_STACK_POINTER_REG));
@@ -737,12 +745,14 @@ implementation
                         if r in regs then
                           begin
                             dec(ref.offset,4);
+                            list.concat(tai_comment.Create(strpnew(' Storing reg '+std_regname(newreg(R_INTREGISTER,r,R_SUBWHOLE))+' at offset='+tostr(ref.offset))));
                             list.concat(taicpu.op_reg_ref(A_S32I,newreg(R_INTREGISTER,r,R_SUBWHOLE),ref));
                           end;
                     end;
                 end;
               abi_xtensa_windowed:
                 begin
+                  list.concat(tai_comment.Create(strpnew('  Start of abi_windowed entry localsize='+tostr(localsize))));
                   if stack_parameters and (pi_estimatestacksize in current_procinfo.flags) then
                     begin
                       list.concat(tai_comment.Create(strpnew('Stackframe size was estimated before code generation due to stack parameters')));
@@ -838,23 +848,23 @@ implementation
                       reference_reset(ref,4,[]);
                       ref.base:=NR_STACK_POINTER_REG;
                       ref.offset:=localsize;
-                      if ref.offset>1024 then
+                      if localsize>1024 then
                         begin
-                          if ref.offset<=1024+32512 then
+                          if localsize<=1024+32512 then
                             begin
-                              list.concat(taicpu.op_reg_reg_const(A_ADDMI,NR_A8,NR_STACK_POINTER_REG,ref.offset and $fffffc00));
-                              ref.offset:=ref.offset and $3ff;
+                              list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_A8,NR_STACK_POINTER_REG,ref.offset-registerarea));
+                              ref.offset:=registerarea;
                               ref.base:=NR_A8;
                             end
                           else
                             begin
                               reference_reset(ref,4,[]);
-                              ref.symbol:=create_data_entry(nil,ref.offset);
+                              ref.symbol:=create_data_entry(nil,ref.offset-registerarea);
                               list.concat(taicpu.op_reg_ref(A_L32R,NR_A8,ref));
                               list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_A8,NR_A8,NR_STACK_POINTER_REG));
                               reference_reset(ref,4,[]);
                               ref.base:=NR_A8;
-                              ref.offset:=0;
+                              ref.offset:=registerarea;
                             end;
                         end;
 
@@ -862,6 +872,7 @@ implementation
                       if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
                         begin
                           dec(ref.offset,4);
+                          list.concat(tai_comment.Create(strpnew(' Restoring reg A15 from offset='+tostr(ref.offset))));
                           list.concat(taicpu.op_reg_ref(A_L32I,NR_A15,ref));
                           a_reg_dealloc(list,NR_FRAME_POINTER_REG);
                         end;
@@ -873,12 +884,14 @@ implementation
                             if r in regs then
                               begin
                                 dec(ref.offset,4);
+                                list.concat(tai_comment.Create(strpnew(' Restoring reg '+std_regname(newreg(R_INTREGISTER,r,R_SUBWHOLE))+' from offset='+tostr(ref.offset))));
                                 list.concat(taicpu.op_reg_ref(A_L32I,newreg(R_INTREGISTER,r,R_SUBWHOLE),ref));
                               end;
                         end;
 
                       // restore stack pointer
                       { not sure if 32512 is the correct value or if it can be larger }
+                      list.concat(tai_comment.Create(strpnew(' Restoring stack pointer')));
                       if Localsize>32512 then
                         begin
                           reference_reset(ref,4,[]);

+ 1 - 1
packages/fcl-image/src/clipping.pp

@@ -57,7 +57,7 @@ begin
   SortRect (bounds);
   with Bounds do
     result := (x >= left) and (x <= right) and
-              (y >= bottom) and (y <= top);
+              (y >= top) and (y <= bottom);
 end;
 
 Function CheckRectClipping (ClipRect:TRect; var Rect:Trect) : Boolean;

+ 10 - 11
packages/fcl-js/src/jswriter.pp

@@ -63,10 +63,10 @@ Type
     {$endif}
     Function Write(Const S : TJSWriterString) : Integer;
     Function WriteLn(Const S : TJSWriterString) : Integer;
-    Function Write(Const Fmt : TJSWriterString; Args : Array of {$ifdef pas2js}jsvalue{$else}const{$endif}) : Integer;
-    Function WriteLn(Const Fmt : TJSWriterString; Args : Array of {$ifdef pas2js}jsvalue{$else}const{$endif}) : Integer;
-    Function Write(Const Args : Array of {$ifdef pas2js}jsvalue{$else}const{$endif}) : Integer;
-    Function WriteLn(Const Args : Array of {$ifdef pas2js}jsvalue{$else}const{$endif}) : Integer;
+    Function Write(Const Fmt : TJSWriterString; Args : Array of const) : Integer;
+    Function WriteLn(Const Fmt : TJSWriterString; Args : Array of const) : Integer;
+    Function Write(Const Args : Array of const) : Integer;
+    Function WriteLn(Const Args : Array of const) : Integer;
     Property CurLine: integer read FCurLine write FCurLine;
     Property CurColumn: integer read FCurColumn write FCurColumn;// char index, not codepoint
     Property CurElement: TJSElement read FCurElement write SetCurElement;
@@ -179,7 +179,7 @@ Type
   Protected
     // Helper routines
     Procedure Error(Const Msg : TJSWriterString);
-    Procedure Error(Const Fmt : TJSWriterString; Args : Array of {$ifdef pas2js}jsvalue{$else}const{$endif});
+    Procedure Error(Const Fmt : TJSWriterString; Args : Array of const);
     Procedure WriteIndent; // inline;
     {$ifdef FPC_HAS_CPSTRING}
     Procedure Write(Const U : UnicodeString);
@@ -466,7 +466,7 @@ begin
 end;
 
 procedure TJSWriter.Error(const Fmt: TJSWriterString;
-  Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
+  Args: array of const);
 begin
   Raise EJSWriter.CreateFmt(Fmt,Args);
 end;
@@ -2137,19 +2137,19 @@ begin
 end;
 
 function TTextWriter.Write(const Fmt: TJSWriterString;
-  Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif}): Integer;
+  Args: array of const): Integer;
 
 begin
   Result:=Write(Format(Fmt,Args));
 end;
 
 function TTextWriter.WriteLn(const Fmt: TJSWriterString;
-  Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif}): Integer;
+  Args: array of const): Integer;
 begin
   Result:=WriteLn(Format(Fmt,Args));
 end;
 
-function TTextWriter.Write(const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif}): Integer;
+function TTextWriter.Write(const Args: array of const): Integer;
 
 Var
   I : Integer;
@@ -2209,8 +2209,7 @@ begin
     end;
 end;
 
-function TTextWriter.WriteLn(
-  const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif}): Integer;
+function TTextWriter.WriteLn(const Args: array of const): Integer;
 begin
   Result:=Write(Args)+Writeln('');
 end;

+ 9 - 3
packages/fcl-passrc/examples/test_parser.pp

@@ -1297,12 +1297,17 @@ procedure GetTypes(pe:TPasElement; lindent:integer);
      ccSafeCall:WriteFmt(true,'SaveCall;',false);
    end;
   end;
-  
+
+  procedure GetHiddenModifiers(Mfs:TProcTypeModifiers);
+
+  begin
+   if ptmVarargs in Mfs then WriteFmt(true,'varargs;',false);
+  end;
+
  procedure GetHiddenModifiers(Mfs:TProcedureModifiers);
   begin
    if pmInline in Mfs then WriteFmt(true,'inline;',false);
    if pmAssembler in Mfs then WriteFmt(true,'assembler;',false);
-   if pmVarargs in Mfs then WriteFmt(true,'varargs;',false);
    if pmCompilerProc in Mfs then WriteFmt(true,'compilerproc;',false);
   end; 
 
@@ -1349,6 +1354,7 @@ procedure GetTypes(pe:TPasElement; lindent:integer);
    if lpp.IsStatic then WriteFmt(true,'static;',false);
    if lpp.IsForward then WriteFmt(true,'forward;',false);
    GetHiddenModifiers(lpp.Modifiers);
+   GetHiddenModifiers(lpp.ProcType.Modifiers);
    GetTCallingConvention(lpp.CallingConvention);
    if GetTPasMemberHints(TPasElement(lpp).Hints) then WriteFmt(false,'',true); //BUG ? missing hints
    if not Unformated then writeln;
@@ -1443,7 +1449,7 @@ procedure GetTypes(pe:TPasElement; lindent:integer);
    if assigned(pc) then
     begin
      s:=GetIndent(indent);
-     if (pc.ObjKind=okGeneric) then
+     if (pc.GenericTemplateTypes<>Nil) then
        begin
        write(s,'generic ',pc.Name);
        for l:=0 to pc.GenericTemplateTypes.Count-1 do

+ 55 - 40
packages/fcl-passrc/src/pasresolveeval.pas

@@ -695,7 +695,7 @@ type
 
   TPasResEvalLogHandler = procedure(Sender: TResExprEvaluator; const id: TMaxPrecInt;
     MsgType: TMessageType; MsgNumber: integer;
-    const Fmt: String; Args: Array of {$ifdef pas2js}jsvalue{$else}const{$endif}; PosEl: TPasElement) of object;
+    const Fmt: String; Args: Array of const; PosEl: TPasElement) of object;
   TPasResEvalIdentHandler = function(Sender: TResExprEvaluator;
     Expr: TPrimitiveExpr; Flags: TResEvalFlags): TResEvalValue of object;
   TPasResEvalParamsHandler = function(Sender: TResExprEvaluator;
@@ -718,9 +718,9 @@ type
     FOnRangeCheckEl: TPasResEvalRangeCheckElHandler;
   protected
     procedure LogMsg(const id: TMaxPrecInt; MsgType: TMessageType; MsgNumber: integer;
-      const Fmt: String; Args: Array of {$ifdef pas2js}jsvalue{$else}const{$endif}; PosEl: TPasElement); overload;
+      const Fmt: String; Args: Array of const; PosEl: TPasElement); overload;
     procedure RaiseMsg(const Id: TMaxPrecInt; MsgNumber: integer; const Fmt: String;
-      Args: Array of {$ifdef pas2js}jsvalue{$else}const{$endif}; ErrorPosEl: TPasElement);
+      Args: Array of const; ErrorPosEl: TPasElement);
     procedure RaiseNotYetImplemented(id: TMaxPrecInt; El: TPasElement; Msg: string = ''); virtual;
     procedure RaiseInternalError(id: TMaxPrecInt; const Msg: string = '');
     procedure RaiseConstantExprExp(id: TMaxPrecInt; ErrorEl: TPasElement);
@@ -763,6 +763,7 @@ type
     procedure SuccUnicodeString(Value: TResEvalUTF16; ErrorEl: TPasElement);
     procedure PredEnum(Value: TResEvalEnum; ErrorEl: TPasElement);
     procedure SuccEnum(Value: TResEvalEnum; ErrorEl: TPasElement);
+    function DivideByZero(LeftSign, RightSign: TValueSign): TMaxPrecFloat;
     function CreateResEvalInt(UInt: TMaxPrecUInt): TResEvalValue; virtual;
   public
     constructor Create;
@@ -814,6 +815,7 @@ type
 
 procedure ReleaseEvalValue(var Value: TResEvalValue);
 function NumberIsFloat(const Value: string): boolean;
+function Sign(const Value: TMaxPrecUInt): TValueSign; overload;
 
 {$ifdef FPC_HAS_CPSTRING}
 function RawStrToCaption(const r: RawByteString; MaxLength: integer): string;
@@ -852,6 +854,14 @@ begin
   Result:=false;
 end;
 
+function Sign(const Value: TMaxPrecUInt): TValueSign;
+begin
+  if Value>0 then
+    Result:=1
+  else
+    Result:=0;
+end;
+
 {$ifdef FPC_HAS_CPSTRING}
 function RawStrToCaption(const r: RawByteString; MaxLength: integer): string;
 var
@@ -1327,14 +1337,14 @@ end;
 
 procedure TResExprEvaluator.LogMsg(const id: TMaxPrecInt; MsgType: TMessageType;
   MsgNumber: integer; const Fmt: String;
-  Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+  Args: array of const;
   PosEl: TPasElement);
 begin
   OnLog(Self,id,MsgType,MsgNumber,Fmt,Args,PosEl);
 end;
 
 procedure TResExprEvaluator.RaiseMsg(const Id: TMaxPrecInt; MsgNumber: integer;
-  const Fmt: String; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+  const Fmt: String; Args: array of const;
   ErrorPosEl: TPasElement);
 begin
   LogMsg(id,mtError,MsgNumber,Fmt,Args,ErrorPosEl);
@@ -2537,32 +2547,32 @@ var
   aCurrency: TMaxPrecCurrency;
 begin
   Result:=nil;
+  Flo:=0.0;
   case LeftValue.Kind of
   revkInt:
     begin
     Int:=TResEvalInt(LeftValue).Int;
     case RightValue.Kind of
     revkInt:
+      begin
       // int / int
       if TResEvalInt(RightValue).Int=0 then
-        RaiseDivByZero(20170711143925,Expr)
+        Flo:=DivideByZero(Sign(Int),Sign(TResEvalInt(RightValue).Int))
       else
-        Result:=TResEvalFloat.CreateValue(Int / TResEvalInt(RightValue).Int);
+        Flo:=Int / TResEvalInt(RightValue).Int;
+      end;
     revkUInt:
       // int / uint
       if TResEvalUInt(RightValue).UInt=0 then
-        RaiseDivByZero(20170711144013,Expr)
+        Flo:=DivideByZero(Math.Sign(Int),Sign(TResEvalUInt(RightValue).UInt))
       else
-        Result:=TResEvalFloat.CreateValue(Int / TResEvalUInt(RightValue).UInt);
+        Flo:=Int / TResEvalUInt(RightValue).UInt;
     revkFloat:
-      begin
       // int / float
       try
         Flo:=Int / TResEvalFloat(RightValue).FloatValue;
       except
-        RaiseMsg(20170711144525,nDivByZero,sDivByZero,[],Expr);
-      end;
-      Result:=TResEvalFloat.CreateValue(Flo);
+        Flo:=DivideByZero(Sign(Int),Sign(TResEvalFloat(RightValue).FloatValue))
       end;
     revkCurrency:
       begin
@@ -2573,6 +2583,7 @@ begin
         RaiseMsg(20180421164915,nDivByZero,sDivByZero,[],Expr);
       end;
       Result:=TResEvalCurrency.CreateValue(aCurrency);
+      exit;
       end;
     else
       {$IFDEF VerbosePasResolver}
@@ -2588,24 +2599,21 @@ begin
     revkInt:
       // uint / int
       if TResEvalInt(RightValue).Int=0 then
-        RaiseDivByZero(20170711144103,Expr)
+        Flo:=DivideByZero(Sign(UInt),Sign(TResEvalInt(RightValue).Int))
       else
-        Result:=TResEvalFloat.CreateValue(UInt / TResEvalInt(RightValue).Int);
+        Flo:=UInt / TResEvalInt(RightValue).Int;
     revkUInt:
       // uint / uint
       if TResEvalUInt(RightValue).UInt=0 then
-        RaiseDivByZero(20170711144203,Expr)
+        Flo:=DivideByZero(Sign(UInt),Sign(TResEvalUInt(RightValue).UInt))
       else
-        Result:=TResEvalFloat.CreateValue(UInt / TResEvalUInt(RightValue).UInt);
+        Flo:=UInt / TResEvalUInt(RightValue).UInt;
     revkFloat:
-      begin
       // uint / float
       try
         Flo:=UInt / TResEvalFloat(RightValue).FloatValue;
       except
-        RaiseMsg(20170711144912,nDivByZero,sDivByZero,[],Expr);
-      end;
-      Result:=TResEvalFloat.CreateValue(Flo);
+        Flo:=DivideByZero(Sign(UInt),Sign(TResEvalFloat(RightValue).FloatValue))
       end;
     revkCurrency:
       begin
@@ -2616,6 +2624,7 @@ begin
         RaiseMsg(20180421164959,nDivByZero,sDivByZero,[],Expr);
       end;
       Result:=TResEvalCurrency.CreateValue(aCurrency);
+      exit;
       end;
     else
       {$IFDEF VerbosePasResolver}
@@ -2631,24 +2640,21 @@ begin
     revkInt:
       // float / int
       if TResEvalInt(RightValue).Int=0 then
-        RaiseDivByZero(20170711144954,Expr)
+        Flo:=DivideByZero(Sign(Flo),Sign(TResEvalInt(RightValue).Int))
       else
-        Result:=TResEvalFloat.CreateValue(Flo / TResEvalInt(RightValue).Int);
+        Flo:=Flo / TResEvalInt(RightValue).Int;
     revkUInt:
       // float / uint
       if TResEvalUInt(RightValue).UInt=0 then
-        RaiseDivByZero(20170711145023,Expr)
+        Flo:=DivideByZero(Sign(Flo),Sign(TResEvalUInt(RightValue).UInt))
       else
-        Result:=TResEvalFloat.CreateValue(Flo / TResEvalUInt(RightValue).UInt);
+        Flo:=Flo / TResEvalUInt(RightValue).UInt;
     revkFloat:
-      begin
       // float / float
       try
         Flo:=Flo / TResEvalFloat(RightValue).FloatValue;
       except
-        RaiseMsg(20170711145040,nDivByZero,sDivByZero,[],Expr);
-      end;
-      Result:=TResEvalFloat.CreateValue(Flo);
+        Flo:=DivideByZero(Sign(Flo),Sign(TResEvalFloat(RightValue).FloatValue))
       end;
     revkCurrency:
       begin
@@ -2674,48 +2680,45 @@ begin
     revkInt:
       // currency / int
       if TResEvalInt(RightValue).Int=0 then
-        RaiseDivByZero(20180421165154,Expr)
+        RaiseMsg(20210515133307,nDivByZero,sDivByZero,[],Expr)
       else
-        Result:=TResEvalCurrency.CreateValue(aCurrency / TResEvalInt(RightValue).Int);
+        aCurrency:=aCurrency / TResEvalInt(RightValue).Int;
     revkUInt:
       // currency / uint
       if TResEvalUInt(RightValue).UInt=0 then
-        RaiseDivByZero(20180421165205,Expr)
+        RaiseMsg(20210515133318,nDivByZero,sDivByZero,[],Expr)
       else
-        Result:=TResEvalCurrency.CreateValue(aCurrency / TResEvalUInt(RightValue).UInt);
+        aCurrency:=aCurrency / TResEvalUInt(RightValue).UInt;
     revkFloat:
-      begin
       // currency / float
       try
         aCurrency:=aCurrency / TResEvalFloat(RightValue).FloatValue;
       except
         RaiseMsg(20180421165237,nDivByZero,sDivByZero,[],Expr);
       end;
-      Result:=TResEvalCurrency.CreateValue(aCurrency);
-      end;
     revkCurrency:
-      begin
       // currency / currency
       try
         aCurrency:=aCurrency / TResEvalCurrency(RightValue).Value;
       except
         RaiseMsg(20180421165252,nDivByZero,sDivByZero,[],Expr);
       end;
-      Result:=TResEvalCurrency.CreateValue(aCurrency);
-      end;
     else
       {$IFDEF VerbosePasResolver}
       writeln('TResExprEvaluator.EvalBinaryDivideExpr currency / ? Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
       {$ENDIF}
       RaiseNotYetImplemented(20180421165301,Expr);
     end;
+    Result:=TResEvalCurrency.CreateValue(aCurrency);
+    exit;
     end;
   else
     {$IFDEF VerbosePasResolver}
-    writeln('TResExprEvaluator.EvalBinaryDivExpr div ?- Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
+    writeln('TResExprEvaluator.EvalBinaryDivExpr ? / - Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
     {$ENDIF}
     RaiseNotYetImplemented(20170530102352,Expr);
   end;
+  Result:=TResEvalFloat.CreateValue(Flo);
 end;
 
 function TResExprEvaluator.EvalBinaryDivExpr(Expr: TBinaryExpr; LeftValue,
@@ -5637,6 +5640,18 @@ begin
   Value.IdentEl:=TPasEnumValue(EnumType.Values[Value.Index]);
 end;
 
+function TResExprEvaluator.DivideByZero(LeftSign, RightSign: TValueSign
+  ): TMaxPrecFloat;
+// FPC/Delphi compatibility: exception at runtime, no exception at compile time
+begin
+  if LeftSign=0 then
+    Result:=0.0
+  else if (LeftSign<0)<>(RightSign<0) then
+    Result:=Math.NegInfinity
+  else
+    Result:=Math.Infinity;
+end;
+
 { TResolveData }
 
 procedure TResolveData.SetElement(AValue: TPasElement);

+ 18 - 21
packages/fcl-passrc/src/pasresolver.pp

@@ -1801,7 +1801,7 @@ type
     fExprEvaluator: TResExprEvaluator;
     procedure OnExprEvalLog(Sender: TResExprEvaluator; const id: TMaxPrecInt;
       MsgType: TMessageType; MsgNumber: integer; const Fmt: String;
-      Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif}; PosEl: TPasElement); virtual;
+      Args: array of const; PosEl: TPasElement); virtual;
     function OnExprEvalIdentifier(Sender: TResExprEvaluator;
       Expr: TPrimitiveExpr; Flags: TResEvalFlags): TResEvalValue; virtual;
     function OnExprEvalParams(Sender: TResExprEvaluator;
@@ -2174,10 +2174,10 @@ type
     class function GetDbgSourcePosStr(El: TPasElement): string;
     function GetElementSourcePosStr(El: TPasElement): string;
     procedure SetLastMsg(const id: TMaxPrecInt; MsgType: TMessageType; MsgNumber: integer;
-      Const Fmt : String; Args : Array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+      Const Fmt : String; Args : Array of const;
       PosEl: TPasElement);
     procedure LogMsg(const id: TMaxPrecInt; MsgType: TMessageType; MsgNumber: integer;
-      const Fmt: String; Args: Array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+      const Fmt: String; Args: Array of const;
       PosEl: TPasElement); overload;
     class function GetWarnIdentifierNumbers(Identifier: string;
       out MsgNumbers: TIntegerDynArray): boolean; virtual;
@@ -2188,7 +2188,7 @@ type
     procedure GetIncompatibleProcParamsDesc(GotType, ExpType: TPasProcedureType;
       out GotDesc, ExpDesc: string);
     procedure RaiseMsg(const Id: TMaxPrecInt; MsgNumber: integer; const Fmt: String;
-      Args: Array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+      Args: Array of const;
       ErrorPosEl: TPasElement); virtual;
     procedure RaiseNotYetImplemented(id: TMaxPrecInt; El: TPasElement; Msg: string = ''); virtual;
     procedure RaiseInternalError(id: TMaxPrecInt; const Msg: string = '');
@@ -2202,13 +2202,13 @@ type
     procedure RaiseVarExpected(id: TMaxPrecInt; ErrorEl: TPasElement; IdentEl: TPasElement);
     procedure RaiseRangeCheck(id: TMaxPrecInt; ErrorEl: TPasElement);
     procedure RaiseIncompatibleTypeDesc(id: TMaxPrecInt; MsgNumber: integer;
-      const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+      const Args: array of const;
       const GotDesc, ExpDesc: String; ErrorEl: TPasElement);
     procedure RaiseIncompatibleType(id: TMaxPrecInt; MsgNumber: integer;
-      const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+      const Args: array of const;
       GotType, ExpType: TPasType; ErrorEl: TPasElement);
     procedure RaiseIncompatibleTypeRes(id: TMaxPrecInt; MsgNumber: integer;
-      const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+      const Args: array of const;
       const GotType, ExpType: TPasResolverResult;
       ErrorEl: TPasElement);
     procedure RaiseHelpersCannotBeUsedAsType(id: TMaxPrecInt; ErrorEl: TPasElement);
@@ -15459,7 +15459,7 @@ end;
 
 procedure TPasResolver.OnExprEvalLog(Sender: TResExprEvaluator;
   const id: TMaxPrecInt; MsgType: TMessageType; MsgNumber: integer;
-  const Fmt: String; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+  const Fmt: String; Args: array of const;
   PosEl: TPasElement);
 begin
   if MsgType<=mtError then
@@ -23070,7 +23070,7 @@ end;
 
 procedure TPasResolver.SetLastMsg(const id: TMaxPrecInt; MsgType: TMessageType;
   MsgNumber: integer; const Fmt: String;
-  Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+  Args: array of const;
   PosEl: TPasElement);
 var
 {$IFDEF VerbosePasResolver}
@@ -23112,7 +23112,7 @@ begin
 end;
 
 procedure TPasResolver.RaiseMsg(const Id: TMaxPrecInt; MsgNumber: integer;
-  const Fmt: String; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+  const Fmt: String; Args: array of const;
   ErrorPosEl: TPasElement);
 var
   E: EPasResolve;
@@ -23224,25 +23224,22 @@ begin
 end;
 
 procedure TPasResolver.RaiseIncompatibleTypeDesc(id: TMaxPrecInt; MsgNumber: integer;
-  const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+  const Args: array of const;
   const GotDesc, ExpDesc: String; ErrorEl: TPasElement);
 
   function GetString(ArgNo: integer): string;
   begin
     if ArgNo>High(Args) then
       exit('invalid param '+IntToStr(ArgNo));
-    {$ifdef pas2js}
-    if isString(Args[ArgNo]) then
-      Result:=String(Args[ArgNo])
-    else
-      Result:='invalid param '+jsTypeOf(Args[ArgNo]);
-    {$else}
     case Args[ArgNo].VType of
+{$IFDEF PAS2JS}    
+    vtUnicodeString: Result:=Args[ArgNo].VUnicodeString;
+{$ELSE}    
     vtAnsiString: Result:=AnsiString(Args[ArgNo].VAnsiString);
+{$ENDIF}    
     else
       Result:='invalid param '+IntToStr(Ord(Args[ArgNo].VType));
     end;
-    {$endif}
   end;
 
 begin
@@ -23270,7 +23267,7 @@ begin
 end;
 
 procedure TPasResolver.RaiseIncompatibleType(id: TMaxPrecInt; MsgNumber: integer;
-  const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+  const Args: array of const;
   GotType, ExpType: TPasType; ErrorEl: TPasElement);
 var
   GotDesc, ExpDesc: String;
@@ -23280,7 +23277,7 @@ begin
 end;
 
 procedure TPasResolver.RaiseIncompatibleTypeRes(id: TMaxPrecInt; MsgNumber: integer;
-  const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+  const Args: array of const;
   const GotType, ExpType: TPasResolverResult;
   ErrorEl: TPasElement);
 var
@@ -23315,7 +23312,7 @@ end;
 
 procedure TPasResolver.LogMsg(const id: TMaxPrecInt; MsgType: TMessageType;
   MsgNumber: integer; const Fmt: String;
-  Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+  Args: array of const;
   PosEl: TPasElement);
 var
   Scanner: TPascalScanner;

+ 2 - 2
packages/fcl-passrc/src/pasuseanalyzer.pas

@@ -311,7 +311,7 @@ type
     function IsSpecializedGenericType(El: TPasElement): boolean;
     procedure EmitMessage(Id: TMaxPrecInt; MsgType: TMessageType;
       MsgNumber: integer; Fmt: String;
-      const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+      const Args: array of const;
       PosEl: TPasElement);
     procedure EmitMessage(Msg: TPAMessage);
     class function GetWarnIdentifierNumbers(Identifier: string;
@@ -3229,7 +3229,7 @@ end;
 
 procedure TPasAnalyzer.EmitMessage(Id: TMaxPrecInt; MsgType: TMessageType;
   MsgNumber: integer; Fmt: String;
-  const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+  const Args: array of const;
   PosEl: TPasElement);
 var
   Msg: TPAMessage;

+ 7 - 7
packages/fcl-passrc/src/pparser.pp

@@ -297,7 +297,7 @@ type
     Function SaveComments(Const AValue : String) : String;
     function LogEvent(E : TPParserLogEvent) : Boolean; inline;
     Procedure DoLog(MsgType: TMessageType; MsgNumber: integer; Const Msg : String; SkipSourceInfo : Boolean = False);overload;
-    Procedure DoLog(MsgType: TMessageType; MsgNumber: integer; Const Fmt : String; Args : Array of {$ifdef pas2js}jsvalue{$else}const{$endif};SkipSourceInfo : Boolean = False);overload;
+    Procedure DoLog(MsgType: TMessageType; MsgNumber: integer; Const Fmt : String; Args : Array of const;SkipSourceInfo : Boolean = False);overload;
     function GetProcTypeFromToken(tk: TToken; IsClass: Boolean=False ): TProcType;
     procedure ParseAsmBlock(AsmBlock: TPasImplAsmStatement); virtual;
     procedure ParseRecordMembers(ARec: TPasRecordType; AEndToken: TToken; AllowMethods : Boolean);
@@ -314,7 +314,7 @@ type
       ProcType: TProcType): boolean;
     function CheckVisibility(S: String; var AVisibility: TPasMemberVisibility; IsObjCProtocol : Boolean = False): Boolean;
     procedure ParseExc(MsgNumber: integer; const Msg: String);
-    procedure ParseExc(MsgNumber: integer; const Fmt: String; Args : Array of {$ifdef pas2js}jsvalue{$else}const{$endif});
+    procedure ParseExc(MsgNumber: integer; const Fmt: String; Args : Array of const);
     procedure ParseExcExpectedIdentifier;
     procedure ParseExcSyntaxError;
     procedure ParseExcTokenError(const Arg: string);
@@ -372,7 +372,7 @@ type
   public
     constructor Create(AScanner: TPascalScanner; AFileResolver: TBaseFileResolver;  AEngine: TPasTreeContainer);
     Destructor Destroy; override;
-    procedure SetLastMsg(MsgType: TMessageType; MsgNumber: integer; Const Fmt : String; Args : Array of {$ifdef pas2js}jsvalue{$else}const{$endif});
+    procedure SetLastMsg(MsgType: TMessageType; MsgNumber: integer; Const Fmt : String; Args : Array of const);
     // General parsing routines
     function CurTokenName: String;
     function CurTokenText: String;
@@ -988,7 +988,7 @@ begin
 end;
 
 procedure TPasParser.ParseExc(MsgNumber: integer; const Fmt: String;
-  Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
+  Args: array of const);
 var
   p: TPasSourcePos;
 begin
@@ -2326,7 +2326,7 @@ begin
     tkCaret                 : Result:=eopDeref;
   else
     result:=eopAdd; // Fool compiler
-    ParseExc(nParserNotAnOperand,SParserNotAnOperand,[AToken,TokenInfos[AToken]]);
+    ParseExc(nParserNotAnOperand,SParserNotAnOperand,[ord(AToken),TokenInfos[AToken]]);
   end;
 end;
 
@@ -4890,7 +4890,7 @@ begin
 end;
 
 procedure TPasParser.SetLastMsg(MsgType: TMessageType; MsgNumber: integer;
-  const Fmt: String; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
+  const Fmt: String; Args: array of const);
 begin
   FLastMsgType := MsgType;
   FLastMsgNumber := MsgNumber;
@@ -4906,7 +4906,7 @@ begin
 end;
 
 procedure TPasParser.DoLog(MsgType: TMessageType; MsgNumber: integer;
-  const Fmt: String; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+  const Fmt: String; Args: array of const;
   SkipSourceInfo: Boolean);
 
 Var

+ 15 - 16
packages/fcl-passrc/src/pscanner.pp

@@ -591,7 +591,7 @@ type
 
   TCEEvalVarEvent = function(Sender: TCondDirectiveEvaluator; Name: String; out Value: string): boolean of object;
   TCEEvalFunctionEvent = function(Sender: TCondDirectiveEvaluator; Name, Param: String; out Value: string): boolean of object;
-  TCELogEvent = procedure(Sender: TCondDirectiveEvaluator; Args : Array of {$ifdef pas2js}jsvalue{$else}const{$endif}) of object;
+  TCELogEvent = procedure(Sender: TCondDirectiveEvaluator; Args : Array of const) of object;
 
   { TCondDirectiveEvaluator - evaluate $IF expression }
 
@@ -631,7 +631,7 @@ type
     function IsExtended(const Value: String; out e: TMaxFloat): boolean;
     procedure NextToken;
     procedure Log(aMsgType: TMessageType; aMsgNumber: integer;
-      const aMsgFmt: String; const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif}; MsgPos: integer = 0);
+      const aMsgFmt: String; const Args: array of const; MsgPos: integer = 0);
     procedure LogXExpectedButTokenFound(const X: String; ErrorPos: integer = 0);
     procedure ReadOperand(Skip: boolean = false); // unary operators plus one operand
     procedure ReadExpression; // binary operators
@@ -786,8 +786,7 @@ type
     function IndexOfWarnMsgState(Number: integer; InsertPos: boolean): integer;
     function OnCondEvalFunction(Sender: TCondDirectiveEvaluator; Name,
       Param: String; out Value: string): boolean;
-    procedure OnCondEvalLog(Sender: TCondDirectiveEvaluator;
-      Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
+    procedure OnCondEvalLog(Sender: TCondDirectiveEvaluator; Args: array of const);
     function OnCondEvalVar(Sender: TCondDirectiveEvaluator; Name: String; out
       Value: string): boolean;
     procedure SetAllowedBoolSwitches(const AValue: TBoolSwitches);
@@ -806,11 +805,11 @@ type
     function FetchLine: boolean;
     procedure AddFile(aFilename: string); virtual;
     function GetMacroName(const Param: String): String;
-    procedure SetCurMsg(MsgType: TMessageType; MsgNumber: integer; Const Fmt : String; Args : Array of {$ifdef pas2js}jsvalue{$else}const{$endif});
+    procedure SetCurMsg(MsgType: TMessageType; MsgNumber: integer; Const Fmt : String; Args : Array of const);
     Procedure DoLog(MsgType: TMessageType; MsgNumber: integer; Const Msg : String; SkipSourceInfo : Boolean = False);overload;
-    Procedure DoLog(MsgType: TMessageType; MsgNumber: integer; Const Fmt : String; Args : Array of {$ifdef pas2js}jsvalue{$else}const{$endif};SkipSourceInfo : Boolean = False);overload;
+    Procedure DoLog(MsgType: TMessageType; MsgNumber: integer; Const Fmt : String; Args : Array of const;SkipSourceInfo : Boolean = False);overload;
     procedure Error(MsgNumber: integer; const Msg: string);overload;
-    procedure Error(MsgNumber: integer; const Fmt: string; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});overload;
+    procedure Error(MsgNumber: integer; const Fmt: string; Args: array of const);overload;
     procedure PushSkipMode;
     function GetMultiLineStringLineEnd(aReader: TLineReader): string;
 
@@ -1246,8 +1245,8 @@ function FilenameIsUnixAbsolute(const TheFilename: string): boolean;
 function IsNamedToken(Const AToken : String; Out T : TToken) : Boolean;
 Function ExtractFilenameOnly(Const AFileName : String) : String;
 
-procedure CreateMsgArgs(var MsgArgs: TMessageArgs; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
-function SafeFormat(const Fmt: string; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif}): string;
+procedure CreateMsgArgs(var MsgArgs: TMessageArgs; Args: array of const);
+function SafeFormat(const Fmt: string; Args: array of const): string;
 
 implementation
 
@@ -1341,7 +1340,7 @@ begin
     T:=SortedTokens[I];
 end;
 
-procedure CreateMsgArgs(var MsgArgs: TMessageArgs; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
+procedure CreateMsgArgs(var MsgArgs: TMessageArgs; Args: array of const);
 var
   i: Integer;
   {$ifdef pas2js}
@@ -1394,7 +1393,7 @@ begin
     {$endif}
 end;
 
-function SafeFormat(const Fmt: string; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif}): string;
+function SafeFormat(const Fmt: string; Args: array of const): string;
 var
   MsgArgs: TMessageArgs;
   i: Integer;
@@ -1804,7 +1803,7 @@ end;
 
 procedure TCondDirectiveEvaluator.Log(aMsgType: TMessageType;
   aMsgNumber: integer; const aMsgFmt: String;
-  const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+  const Args: array of const;
   MsgPos: integer);
 begin
   if MsgPos<1 then
@@ -3331,7 +3330,7 @@ begin
 end;
 
 procedure TPascalScanner.Error(MsgNumber: integer; const Fmt: string;
-  Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
+  Args: array of const);
 begin
   SetCurMsg(mtError,MsgNumber,Fmt,Args);
   raise EScannerError.CreateFmt('%s(%d,%d) Error: %s',
@@ -5281,7 +5280,7 @@ begin
 end;
 
 procedure TPascalScanner.OnCondEvalLog(Sender: TCondDirectiveEvaluator;
-  Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
+  Args: array of const);
 
 Var
   Msg : String;
@@ -5505,7 +5504,7 @@ begin
 end;
 
 procedure TPascalScanner.DoLog(MsgType: TMessageType; MsgNumber: integer;
-  const Fmt: String; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+  const Fmt: String; Args: array of const;
   SkipSourceInfo: Boolean);
 
 Var
@@ -5656,7 +5655,7 @@ begin
 end;
 
 procedure TPascalScanner.SetCurMsg(MsgType: TMessageType; MsgNumber: integer;
-  const Fmt: String; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
+  const Fmt: String; Args: array of const);
 begin
   FLastMsgType := MsgType;
   FLastMsgNumber := MsgNumber;

+ 30 - 6
packages/fcl-web/src/base/custfcgi.pp

@@ -62,6 +62,10 @@ Type
     FUR: TUnknownRecordEvent;
     FLog : TLogEvent;
     FSTDin : String;
+    FSTDinRead: Integer;
+
+    FRequestHeadersInitialized: Boolean;
+    FStreamingContentReceived: Boolean;
   Protected
     function DoGetCGIVar(AVarName: String): String; override;
     procedure GetNameValuePairsFromContentRecord(const ARecord : PFCGI_ContentRecord; NameValueList : TStrings); virtual;
@@ -247,6 +251,7 @@ end;
 
 function TFCGIRequest.ProcessFCGIRecord(AFCGIRecord: PFCGI_Header): boolean;
 var cl,rcl : Integer;
+  State: TContentStreamingState;
 begin
   Result := False;
   case AFCGIRecord^.reqtype of
@@ -257,6 +262,7 @@ begin
 //           log(etDebug,Format('Begin request body role & flags: %d %d',[Beton(Role),Flags]));
          end;
     FCGI_PARAMS :       begin
+                        FRequestHeadersInitialized := False;
                         if AFCGIRecord^.contentLength=0 then
                           Result := False
                         else
@@ -267,14 +273,34 @@ begin
                           end;
                         end;
     FCGI_STDIN :        begin
+                        if not FRequestHeadersInitialized then
+                          begin
+                          InitHeaderRequestVars;
+                          FRequestHeadersInitialized := True;
+                          end;
                         Result:=AFCGIRecord^.contentLength=0;
                         if not Result then
                           begin
-                          cl := length(FSTDin);
                           rcl := BetoN(PFCGI_ContentRecord(AFCGIRecord)^.header.contentLength);
-                          SetLength(FSTDin, rcl+cl);
-                          move(PFCGI_ContentRecord(AFCGIRecord)^.ContentData[0],FSTDin[cl+1],rcl);
-                          InitContent(FSTDin);
+                          if FStreamingContentReceived then
+                            State := cssData
+                          else
+                            State := cssStart;
+                          FStreamingContentReceived := True;
+
+                          ProcessStreamingContent(State, PFCGI_ContentRecord(AFCGIRecord)^.ContentData[0], rcl);
+                          end
+                        else
+                          begin
+                          if not FStreamingContentReceived then
+                            begin
+                            ProcessStreamingContent(cssStart, PFCGI_ContentRecord(AFCGIRecord)^.ContentData[0], 0);
+                            ProcessStreamingContent(cssEnd, PFCGI_ContentRecord(AFCGIRecord)^.ContentData[0], 0);
+                            end
+                          else
+                            begin
+                            ProcessStreamingContent(cssEnd, PFCGI_ContentRecord(AFCGIRecord)^.ContentData[0], 0);
+                            end;
                           end;
                         end;
   else
@@ -284,8 +310,6 @@ begin
       if poFailonUnknownRecord in FPO then
         TFCgiHandler.DoError('Unknown FASTCGI record type: %s',[AFCGIRecord^.reqtype]);
   end;
-  if Result then
-    InitRequestVars;
 end;
 
 function TFCGIRequest.DoGetCGIVar(AVarName: String): String;

+ 665 - 22
packages/fcl-web/src/base/httpdefs.pp

@@ -143,6 +143,8 @@ Const
                        22,23,24,
                        34,0,36,26) deprecated;
 
+type
+  TContentStreamingState = (cssStart, cssData, cssEnd);
 
 
 type
@@ -249,7 +251,11 @@ type
   TMimeItem = Class(TCollectionItem)
   private
   protected
+    FLocalFilename: string;
+
+    Function CreateUploadedFileStreaming(Files : TUploadedFiles) : TUploadedFile; virtual;
     Function CreateUploadedFile(Files : TUploadedFiles) : TUploadedFile; virtual;
+    function CreateFile(Files: TUploadedFiles): TUploadedFile; virtual;
     Function ProcessHeader(Const AHeader,AValue : String) : Boolean; virtual;
     procedure SaveToFile(const AFileName: String); virtual;
     function GetIsFile: Boolean; virtual;
@@ -258,6 +264,7 @@ type
     function GetHeader(AIndex: Integer): String; virtual; abstract;
     Procedure SetHeader(AIndex: Integer; Const AValue: String); virtual; abstract;
   Public
+    Procedure ProcessStreaming(const State: TContentStreamingState; const Buf; const Size: Integer); virtual; abstract;
     Procedure Process(Stream : TStream); virtual; abstract;
     Property Data : String index 0 Read GetHeader Write SetHeader;
     Property Name : String index 1 Read GetHeader Write SetHeader;
@@ -273,17 +280,44 @@ type
 
   TMimeItems = Class(TCollection)
   private
+    FBoundary: string;
+    FFiles: TUploadedFiles;
+    FPreamble: string;
     function GetP(AIndex : Integer): TMimeItem;
   Protected
     Procedure CreateUploadFiles(Files : TUploadedFiles; Vars : TStrings); virtual;
     procedure FormSplit(var Cnt: String; boundary: String); virtual;
+    procedure ProcessStreamingMultiPart(const State: TContentStreamingState; const Buf; const Size: Integer); virtual;
+    // With streaming is meant that the incoming data is processed in smaller
+    // chunks. To support streaming descendents have to implement
+    // ProcessStreamingMultiPart
+    class function SupportsStreamingProcessing: Boolean; virtual;
+    procedure SetBoundary(AValue: string); virtual;
   Public
     Function First : TMimeItem;
     Function Last : TMimeItem;
     Property Parts[AIndex : Integer] : TMimeItem Read GetP; default;
+    property Preamble: string read FPreamble;
+    Property Boundary: string read FBoundary write SetBoundary;
+    Property Files: TUploadedFiles read FFiles write FFiles;
   end;
   TMimeItemsClass = Class of TMimeItems;
 
+  { TStreamingMimeItems }
+
+  TStreamingMimeItems = class(TMimeItems)
+  private
+    FBuffer: string;
+    FBufferCount: SizeInt;
+    FCurrentItem: TMimeItem;
+    FMimeEndFound: Boolean;
+    FAtStart: Boolean;
+  protected
+    procedure SetBoundary(AValue: string); override;
+    procedure ProcessStreamingMultiPart(const State: TContentStreamingState; const Buf; const Size: Integer); override;
+    class function SupportsStreamingProcessing: Boolean; override;
+  end;
+
   { THTTPHeader }
 
   THTTPHeader = class(TObject)
@@ -333,6 +367,7 @@ type
     // Variables
     Class Function GetVariableHeaderName(AVariable : THTTPVariableType) : String;
     Function  GetHTTPVariable(AVariable : THTTPVariableType) : String;
+    Class Function ParseContentType(const AContentType: String; Parameters: TStrings) : String;
     // Get/Set custom headers.
     Function GetCustomHeader(const Name: String) : String; virtual;
     Procedure SetCustomHeader(const Name, Value: String); virtual;
@@ -403,6 +438,8 @@ type
     Property CustomHeaders: TStringList read GetCustomHeaders;
   end;
 
+  TStreamingContentType = (sctUnknown, sctMultipart, sctFormUrlEncoded);
+  TOnStreamEncodingEvent = Procedure (Sender : TRequest; const State: TContentStreamingState; const Buf; const Size: Integer) of object;
   TOnUnknownEncodingEvent = Procedure (Sender : TRequest; Const ContentType : String;Stream : TStream) of object;
   { TRequest }
 
@@ -417,6 +454,13 @@ type
     FLocalPathPrefix : string;
     FContentRead : Boolean;
     FRouteParams : TStrings;
+
+    FStreamingContentType: TStreamingContentType;
+    FMimeItems: TMimeItems;
+    FKeepFullContents: Boolean;
+    FStreamingContent: string;
+    FStreamingContentRead: Integer;
+    FOnStreamEncodingEvent: TOnStreamEncodingEvent;
     function GetLocalPathPrefix: string;
     function GetFirstHeaderLine: String;
     function GetRP(AParam : String): String;
@@ -426,6 +470,7 @@ type
     Function CreateUploadedFiles : TUploadedFiles; virtual;
     Function CreateMimeItems : TMimeItems; virtual;
     procedure HandleUnknownEncoding(Const AContentType : String;Stream : TStream); virtual;
+    procedure HandleStreamEncoding(const State: TContentStreamingState; const Buf; const Size: Integer); virtual;
     procedure ParseFirstHeaderLine(const line: String);override;
     procedure ReadContent; virtual;
     Procedure ProcessMultiPart(Stream : TStream; Const Boundary : String;SL:TStrings); virtual;
@@ -435,10 +480,22 @@ type
     Function GetTempUploadFileName(Const AName, AFileName : String; ASize : Int64) : String; virtual;
     // This will free any TUPloadedFile.Streams that may exist, as they may lock the files and thus prevent them
     Procedure DeleteTempUploadedFiles; virtual;
+
     Procedure InitRequestVars; virtual;
+    procedure InitContentRequestVars; virtual;
+    procedure InitHeaderRequestVars; virtual;
+
     Procedure InitPostVars; virtual;
     Procedure InitGetVars; virtual;
-    Procedure InitContent(Var AContent : String);
+    Procedure InitContent(const AContent : String);
+
+    procedure ProcessStreamingContent(const State: TContentStreamingState; const Buf; const Size: Integer); virtual;
+    function DerriveStreamingContentType(): TStreamingContentType;
+    procedure ProcessStreamingURLEncoded(const State: TContentStreamingState; const Buf; const Size: Integer); virtual;
+    procedure ProcessStreamingMultiPart(const State: TContentStreamingState; const Buf; const Size: Integer); virtual;
+    // ProcessStreamingSetContent collects all data and stores it into Content
+    procedure ProcessStreamingSetContent(const State: TContentStreamingState; const Buf; const Size: Integer); virtual;
+    procedure HandleStreamingUnknownEncoding(const State: TContentStreamingState; const Buf; const Size: Integer);
     Property ContentRead : Boolean Read FContentRead Write FContentRead;
   public
     Class Var DefaultRequestUploadDir : String;
@@ -456,6 +513,7 @@ type
     Property Files : TUploadedFiles Read FFiles;
     Property HandleGetOnPost : Boolean Read FHandleGetOnPost Write FHandleGetOnPost;
     Property OnUnknownEncoding : TOnUnknownEncodingEvent Read FOnUnknownEncoding Write FOnUnknownEncoding;
+    Property OnStreamEncodingEvent: TOnStreamEncodingEvent read FOnStreamEncodingEvent write FOnStreamEncodingEvent;
     Property IfMatch : String Index ord(hhIfMatch) Read GetHeaderValue Write SetHeaderValue;
     Property IfNoneMatch : String  Index ord(hhIfNoneMatch) Read GetHeaderValue Write SetHeaderValue;
     Property IfRange : String  Index ord(hhIfRange) Read GetHeaderValue Write SetHeaderValue;
@@ -463,6 +521,7 @@ type
     Property ContentRange : String Index ord(hhContentRange) Read GetHeaderValue Write SetHeaderValue;
     Property TE : String Index ord(hhTE) Read GetHeaderValue Write SetHeaderValue;
     Property Upgrade : String Index ord(hhUpgrade) Read GetHeaderValue Write SetHeaderValue;
+    property KeepFullContents: Boolean read FKeepFullContents write FKeepFullContents;
   end;
 
 
@@ -647,7 +706,7 @@ Var
   // Default classes used when instantiating the collections.
   UploadedFilesClass : TUploadedFilesClass = TUploadedFiles;
   UploadedFileClass : TUploadedFileClass = TUploadedFile;
-  MimeItemsClass : TMimeItemsClass = TMimeItems;
+  MimeItemsClass : TMimeItemsClass = TStreamingMimeItems;
   MimeItemClass : TMimeItemClass = nil;
 
 Const
@@ -726,15 +785,141 @@ Type
   THTTPMimeItem = Class(TMimeItem)
   private
     FData : Array[0..5] of string;
+    FHeadersProcessed: Boolean;
+    FBuffer: string;
+    FStream: TStream;
+    FDataSize: Int64;
   protected
     Procedure SetHeader(AIndex: Integer; Const AValue: String); override;
     function GetDataSize: Int64; override;
     function GetHeader(AIndex: Integer): String; override;
     function GetIsFile: Boolean; override;
   public
+    destructor Destroy; override;
     Procedure Process(Stream : TStream); override;
+    Procedure ProcessStreaming(const State: TContentStreamingState; const Buf; const Size: Integer); override;
   end;
 
+  { THTTPStreamingMimeItem }
+  THTTPStreamingMimeItem = Class(THTTPMimeItem)
+  protected
+    function GetDataSize: Int64; override;
+  end;
+
+function THTTPStreamingMimeItem.GetDataSize: Int64;
+begin
+  if GetIsFile then
+    Result:=FDataSize
+  else
+    Result:=Length(Data);
+end;
+
+
+{ TStreamingMimeItems }
+
+procedure TStreamingMimeItems.ProcessStreamingMultiPart(const State: TContentStreamingState; const Buf; const Size: Integer);
+var
+  bl: SizeInt;
+  p: SizeInt;
+  BufEnd: SizeInt;
+  LeadingLineEndMissing: Boolean;
+begin
+  // The length of the boundary, including the leading CR/LF, '--' and trailing '--' or
+  // CR/LF.
+  bl := Length(FBoundary)+6;
+  LeadingLineEndMissing:=False;
+  if State=cssStart then
+    begin
+    FMimeEndFound := False;
+    FAtStart := True;
+    end;
+
+  // Allocate enough memory to hold the buffer-size, and the lenght of the
+  // boundary (bl). To be able to find a boundary-string at which is divided between
+  // two calls to this function, the last bl-amount of characters at the end of
+  // the buffer, are stored to be handled in the next call to this function.
+  SetLength(FBuffer, Size+bl);
+  if Size > 0 then
+    System.Move(Buf, FBuffer[FBufferCount+1], Size);
+
+  BufEnd := FBufferCount+1+Size;
+
+  FBufferCount := 1;
+  repeat
+  if FAtStart and CompareMem(@FBuffer[1], PChar('--'+FBoundary), Length(FBoundary)+2) then
+    begin
+    // Sometimes a mime-message (mistakenly) does not start with CR/LF.
+    p := 1;
+    LeadingLineEndMissing := True;
+    end
+  else
+    p := Pos(#13#10'--'+FBoundary, FBuffer, FBufferCount);
+  if (P > 0) and (P < Size) then
+    begin
+    if Assigned(FCurrentItem) then
+      begin
+      FCurrentItem.ProcessStreaming(cssEnd, FBuffer[FBufferCount], P-FBufferCount);
+      FCurrentItem := Nil;
+      end
+    else
+      begin
+      if FAtStart and (P > 1) then
+        // Add the preamble to the content
+        FPreamble := Copy(FBuffer, FBufferCount, P-1);
+      end;
+    FAtStart := False;
+    Inc(P, bl);
+    if LeadingLineEndMissing then
+      begin
+      Dec(P, 2);
+      LeadingLineEndMissing := False;
+      end;
+    FBufferCount := P;
+    if (Copy(FBuffer,p-2,2)='--') then
+      FMimeEndFound := True;
+    end;
+  if not Assigned(FCurrentItem) and not FMimeEndFound then
+    begin
+    FCurrentItem := Add as TMimeItem;
+    FCurrentItem.ProcessStreaming(cssStart, FBuffer[p], 0)
+    end
+  until (P < 1) or FMimeEndFound;
+
+  if Assigned(FCurrentItem) then
+    begin
+    if state<>cssEnd then
+      begin
+      // Call FCurrentItem.ProcessStreaming with the current buffer, excluding
+      // the last bl bytes. Keep those at the start of FBuffer, to be handled
+      // in the next call to this function.
+      FCurrentItem.ProcessStreaming(cssData, FBuffer[FBufferCount], BufEnd-FBufferCount-bl);
+      System.Move(FBuffer[BufEnd-bl], FBuffer[1], bl);
+      FBufferCount := bl;
+      end
+    else
+      begin
+      // This function won't be called again. Call FCurrentItem.ProcessStreaming
+      // with the complete remaining buffer.
+      FCurrentItem.ProcessStreaming(cssEnd, FBuffer[FBufferCount], BufEnd-FBufferCount+bl);
+      FBufferCount := 0;
+      end;
+    end
+  else
+    FBufferCount := 0;
+end;
+
+class function TStreamingMimeItems.SupportsStreamingProcessing: Boolean;
+begin
+  Result := True;
+end;
+
+procedure TStreamingMimeItems.SetBoundary(AValue: string);
+begin
+  if Length(FBuffer) > 0 then
+    Raise Exception.Create('It is not possible to adapt the binary when the evaluation of streaming data has already been started.');
+  inherited SetBoundary(AValue);
+end;
+
 { TCORSSupport }
 
 procedure TCORSSupport.SetAllowedMethods(AValue: String);
@@ -935,15 +1120,152 @@ begin
       end;
     Line:=GetLine(D);
     end;
-  // Now Data contains the rest of the data, plus a CR/LF. Strip the CR/LF
+  // Now D contains the rest of the data, plus a CR/LF. Strip the CR/LF
   Len:=Length(D);
   If (len>2) then
-    Data:=Copy(D,1,Len-2)
+    begin
+    FDataSize := Len-2;
+    Data:=Copy(D,1,FDataSize)
+    end
   else
     Data:='';
   {$ifdef CGIDEBUG}SendMethodExit('THTTPMimeItem.Process');{$ENDIF}
 end;
 
+procedure THTTPMimeItem.ProcessStreaming(const State: TContentStreamingState; const Buf; const Size: Integer);
+
+  Function GetLine(Var S : String) : String;
+
+  Var
+    P : Integer;
+
+  begin
+    P:=Pos(#13#10,S);
+    If (P<>0) then
+      begin
+      Result:=Copy(S,1,P-1);
+      Delete(S,1,P+1);
+      end;
+  end;
+
+  Function GetWord(Var S : String) : String;
+
+  Var
+    I,len : Integer;
+    Quoted : Boolean;
+    C : Char;
+
+  begin
+    len:=length(S);
+    quoted:=false;
+    Result:='';
+    for i:=1 to len do
+      Begin
+      c:=S[i];
+      if (c='"') then
+        Quoted:=Not Quoted
+      else
+        begin
+        if not (c in [' ','=',';',':']) or Quoted then
+          Result:=Result+C;
+        if (c in [';',':','=']) and (not quoted) then
+          begin
+          Delete(S,1,I);
+          Exit;
+          end;
+        end;
+      end;
+     S:='';
+  end;
+
+  procedure AddData(const Buf; Size: SizeInt);
+  var
+    S: string;
+    i: SizeInt;
+    Files: TUploadedFiles;
+  begin
+    if Size > 0 then
+      begin
+      if GetIsFile then
+        begin
+        // Stream directly to file
+        if not Assigned(FStream) then
+          begin
+          Files := (Collection as TMimeItems).Files;
+          if Assigned(Files) then
+            FLocalFilename := Files.GetTempUploadFileName(Name, FileName, -1)
+          else
+            FLocalFilename := GetTempFileName('', '');
+          FStream := TFileStream.Create(FLocalFilename, fmCreate);
+          FDataSize := 0;
+          end;
+
+        FStream.Write(Buf, Size);
+        Inc(FDataSize, Size);
+        end
+      else
+        begin
+        S := Data;
+        i := Length(S);
+        SetLength(S, i+Size);
+        Move(Buf, S[i+1], Size);
+        Data := S;
+        end;
+      end;
+  end;
+
+var
+  i: SizeInt;
+  Line, S: string;
+begin
+  if not FHeadersProcessed then
+    begin
+    if Size>0 then
+      begin
+      i := Length(FBuffer);
+      SetLength(FBuffer, i + Size);
+      Move(Buf, FBuffer[i+1], Size);
+      if Copy(FBuffer, 1, 2) = #13#10 then
+        i := 3
+      else
+        i := Pos(#13#10#13#10, FBuffer)+4;
+      if i <> 4 then
+        begin
+        // The full headers are in the buffer now.
+        Line:=GetLine(FBuffer);
+        While (Line<>'') do
+          begin
+          {$ifdef CGIDEBUG}SendDebug('Process data line: '+line);{$ENDIF}
+          S:=GetWord(Line);
+          While (S<>'') do
+            begin
+            ProcessHeader(lowercase(S),GetWord(Line));
+            S:=GetWord(Line);
+            end;
+          Line:=GetLine(FBuffer);
+          end;
+        FHeadersProcessed := True;
+
+        AddData(FBuffer[1], Length(FBuffer));
+        end;
+      end;
+    end
+  else
+    AddData(Buf, Size);
+
+  if State=cssEnd then
+    begin
+    if GetIsFile then
+      FreeAndNil(FStream);
+    end;
+end;
+
+destructor THTTPMimeItem.Destroy;
+begin
+  FStream.Free;
+  inherited Destroy;
+end;
+
 { ---------------------------------------------------------------------
   THTTPHeader
   ---------------------------------------------------------------------}
@@ -1081,6 +1403,125 @@ begin
   Result:=FVariables[AVariable];
 end;
 
+type
+  TParseState =
+    (psStart, psContentType, psSearchParam, psParam, psSearchParamEqual, psSearchParamValue, psParamValueQuoted, psParamValue);
+
+Class Function THTTPHeader.ParseContentType(const AContentType: String; Parameters: TStrings): String;
+var
+  len: Integer;
+  ind: Integer;
+  state: TParseState;
+  start: Integer;
+  paramname: string;
+  paramvalue: string;
+begin
+  // See rfc1341, Content-Type
+  Result := '';
+  len := Length(AContentType);
+  if len=0 then
+    Exit;
+
+  ind := 1;
+  state := psStart;
+  while ind <= len do
+    begin
+    case state of
+      psStart:
+        begin
+        if not (AContentType[ind] in [' ']) then
+          begin
+          state := psContentType;
+          start := ind;
+          end;
+        end;
+      psContentType:
+        begin
+        if (AContentType[ind] in [' ', ';']) then
+          begin
+            Result := Copy(AContentType, start, ind-start);
+          if not Assigned(Parameters) then
+            Exit;
+          state := psSearchParam;
+          end;
+        if (ind = len) then
+          begin
+          Result := Copy(AContentType, start, ind-start+1);
+          end;
+        end;
+      psSearchParam:
+        begin
+        if not (AContentType[ind] in [' ', ';']) then
+          begin
+          state := psParam;
+          start := ind;
+          end;
+        end;
+      psParam:
+        begin
+        if (AContentType[ind] in [' ', '=']) then
+          begin
+            paramname := Copy(AContentType, start, ind-start);
+          if AContentType[ind] = '=' then
+            state := psSearchParamValue
+          else
+            state := psSearchParamEqual
+          end;
+        end;
+      psSearchParamEqual:
+        begin
+        if (AContentType[ind] = '=') then
+          state := psSearchParamValue;
+        end;
+      psSearchParamValue:
+        begin
+        if (AContentType[ind] = '"') then
+          begin
+          state := psParamValueQuoted;
+          start := ind +1;
+          end
+        else if (AContentType[ind] <> ' ') then
+          begin
+          state := psParamValue;
+          start := ind;
+          end;
+        end;
+      psParamValue:
+        begin
+        if (AContentType[ind] in [' ', ';']) then
+          begin
+          paramvalue := Copy(AContentType, start, ind-start);
+          Parameters.Values[paramname] := paramvalue;
+
+          state := psSearchParam;
+          end
+        else if (ind = len) then
+          begin
+          paramvalue := Copy(AContentType, start, ind-start+1);
+          Parameters.Values[paramname] := paramvalue;
+          end
+        end;
+      psParamValueQuoted:
+        begin
+        if AContentType[ind] = '"' then
+          begin
+          paramvalue := Copy(AContentType, start, ind-start);
+          Parameters.Values[paramname] := paramvalue;
+
+          state := psSearchParam;
+          end
+        else if (ind = len) then
+          begin
+          paramvalue := Copy(AContentType, start, ind-start+1);
+          Parameters.Values[paramname] := paramvalue;
+          end
+        end;
+    end;
+
+    inc(ind);
+    end;
+end;
+
 function THTTPHeader.GetHTTPVariable(AIndex: Integer): String;
 begin
   if (AIndex>=0) and (AIndex<=Ord(High(THTTPVariableType))) then
@@ -1432,7 +1873,10 @@ begin
     else
       begin
       Value:=P.FileName;
-      P.CreateUploadedFile(Files);
+      if SupportsStreamingProcessing then
+        P.CreateUploadedFileStreaming(Files)
+      else
+        P.CreateUploadedFile(Files);
       end;
     Vars.Add(Name+'='+Value)
     end;
@@ -1481,7 +1925,6 @@ Var
   D,LFN : String;
 
 begin
-  Result:=Nil;
   D:=Data;
   J:=DataSize;
   if (J=0){zero lenght file} or
@@ -1491,8 +1934,15 @@ begin
     begin
     LFN:=Files.GetTempUploadFileName(Name,FileName,J);
     SaveToFile(LFN);
+    FLocalFilename := LFN;
     end;
-  if (LFN<>'') then
+  Result := CreateFile(Files);
+end;
+
+function TMimeItem.CreateFile(Files: TUploadedFiles): TUploadedFile;
+begin
+  Result:=Nil;
+  if (FLocalFileName<>'') then
    begin
    Result:=Files.Add as TUploadedFile;
    with Result do
@@ -1502,12 +1952,24 @@ begin
      ContentType:=Self.ContentType;
      Disposition:=Self.Disposition;
      Size:=Self.Datasize;
-     LocalFileName:=LFN;
+     LocalFileName:=self.FLocalFileName;
      Description:=Self.Description;
      end;
    end;
 end;
 
+function TMimeItem.CreateUploadedFileStreaming(Files: TUploadedFiles): TUploadedFile;
+begin
+  if FLocalFilename='' then
+    // Even though this class supports streaming procesing of data, does not
+    // mean it is being used that way. In those cases the non-streaming file-
+    // creation has to take place: (For example, CGI does not use the
+    // streaming capabilities (may 2021))
+    CreateUploadedFile(Files)
+  else
+    CreateFile(Files);
+end;
+
 
 {
   This needs MASSIVE improvements for large files.
@@ -1527,6 +1989,8 @@ var
 
 begin
   {$ifdef CGIDEBUG}SendMethodEnter('TMimeItems.FormSplit');{$ENDIF}
+  FBoundary := boundary;
+
   Sep:='--'+boundary+#13+#10;
   Slen:=length(Sep);
   CLen:=Pos('--'+Boundary+'--',Cnt);
@@ -1569,6 +2033,21 @@ begin
     Result := Parts[Count - 1];
 end;
 
+class function TMimeItems.SupportsStreamingProcessing: Boolean;
+begin
+  Result := False;
+end;
+
+procedure TMimeItems.SetBoundary(AValue: string);
+begin
+  FBoundary := AValue;
+end;
+
+procedure TMimeItems.ProcessStreamingMultiPart(const State: TContentStreamingState; const Buf; const Size: Integer);
+begin
+  raise Exception.Create('Streaming processing of data not supported');
+end;
+
 { -------------------------------------------------------------------
   TRequest
   -------------------------------------------------------------------}
@@ -1612,12 +2091,14 @@ begin
   if (CI=Nil) then
     CI:=TMimeItem;
   Result:=CC.Create(CI);
+  Result.Files := Files;
 end;
 
 destructor TRequest.destroy;
 begin
   FreeAndNil(FRouteParams);
   FreeAndNil(FFiles);
+  FreeAndNil(FMimeItems);
   inherited destroy;
 end;
 
@@ -1864,29 +2345,52 @@ begin
   FFiles.DeleteTempUploadedFiles;
 end;
 
-procedure TRequest.InitRequestVars;
+procedure TRequest.InitHeaderRequestVars;
 
 var
   R : String;
 
 begin
 {$ifdef CGIDEBUG}
-  SendMethodEnter('TRequest.InitRequestVars');
+  SendMethodEnter('TRequest.InitHeaderRequestVars');
 {$endif}
   R:=Method;
   if (R='') then
     Raise EHTTP.CreateHelp(SErrNoRequestMethod,400);
   // Always process QUERYSTRING.
   InitGetVars;
+{$ifdef CGIDEBUG}
+  SendMethodExit('TRequest.InitHeaderRequestVars');
+{$endif}
+end;
+
+procedure TRequest.InitContentRequestVars;
+
+var
+  R : String;
+
+begin
+{$ifdef CGIDEBUG}
+  SendMethodEnter('TRequest.InitContentRequestVars');
+{$endif}
+  R:=Method;
   // POST and PUT, force post var treatment.
   // To catch other methods we do not treat specially, we'll do the same if contentlength>0
   if (CompareText(R,'POST')=0) or (CompareText(R,'PUT')=0) or (ContentLength>0) then
     InitPostVars;
 {$ifdef CGIDEBUG}
-  SendMethodExit('TRequest.InitRequestVars');
+  SendMethodExit('TRequest.InitContentRequestVars');
 {$endif}
 end;
 
+
+procedure TRequest.InitRequestVars;
+
+begin
+  InitHeaderRequestVars;
+  InitContentRequestVars;
+end;
+
 Type
   TCapacityStream = Class(TMemoryStream)
   Public
@@ -1913,12 +2417,13 @@ begin
       M.WriteBuffer(Content[1], Cl);
       M.Position:=0;
       CT:=ContentType;
-      if Pos('MULTIPART/FORM-DATA',Uppercase(CT))<>0 then
-        ProcessMultiPart(M,CT, ContentFields)
-      else if Pos('APPLICATION/X-WWW-FORM-URLENCODED',Uppercase(CT))<>0 then
-        ProcessUrlEncoded(M, ContentFields)
+      FStreamingContentType := DerriveStreamingContentType;
+      case FStreamingContentType of
+        sctMultipart:       ProcessMultiPart(M, CT, ContentFields);
+        sctFormUrlEncoded:  ProcessUrlEncoded(M, ContentFields);
       else
         HandleUnknownEncoding(CT,M)
+      end;
     finally
       M.Free;
     end;
@@ -1944,7 +2449,7 @@ begin
 {$endif}
 end;
 
-procedure TRequest.InitContent(var AContent: String);
+procedure TRequest.InitContent(const AContent: String);
 begin
   FVariables[hvContent]:=AContent;
   FContentRead:=True;
@@ -1959,14 +2464,18 @@ Var
   B : String;
   I : Integer;
   S : String;
+  ST: TStringList;
 
 begin
 {$ifdef CGIDEBUG} SendMethodEnter('ProcessMultiPart');{$endif CGIDEBUG}
-  i:=Pos('=',Boundary);
-  B:=Copy(Boundary,I+1,Length(Boundary)-I);
-  I:=Length(B);
-  If (I>0) and (B[1]='"') then
-    B:=Copy(B,2,I-2);
+  ST := TStringList.Create;
+  try
+    ParseContentType(Boundary, ST);
+    B := ST.Values['boundary'];
+  finally
+    ST.Free;
+  end;
+
   L:=CreateMimeItems;
   Try
     if Stream is TStringStream then
@@ -2007,6 +2516,140 @@ begin
 {$ifdef CGIDEBUG} SendMethodEnter('ProcessURLEncoded');{$endif CGIDEBUG}
 end;
 
+procedure TRequest.ProcessStreamingContent(const State: TContentStreamingState; const Buf; const Size: Integer);
+begin
+  if state = cssStart then
+    FStreamingContentType := DerriveStreamingContentType;
+  case FStreamingContentType of
+    sctMultipart:       ProcessStreamingMultiPart(State, Buf, Size);
+    sctFormUrlEncoded:  ProcessStreamingUrlEncoded(State, Buf, Size);
+  else
+    HandleStreamingUnknownEncoding(State, Buf, Size)
+  end;
+  HandleStreamEncoding(State, Buf, Size);
+end;
+
+function TRequest.DerriveStreamingContentType(): TStreamingContentType;
+var
+  CT: string;
+begin
+  CT:=Uppercase(ParseContentType(ContentType, nil));
+  if CT='MULTIPART/FORM-DATA' then
+    Result := sctMultipart
+  else if CT='APPLICATION/X-WWW-FORM-URLENCODED' then
+    Result := sctFormUrlEncoded
+  else
+    Result := sctUnknown
+end;
+
+procedure TRequest.ProcessStreamingMultiPart(const State: TContentStreamingState; const Buf; const Size: Integer);
+Var
+  ST: TStrings;
+  S: String;
+begin
+{$ifdef CGIDEBUG} SendMethodEnter('ProcessStreamingMultiPart');{$endif CGIDEBUG}
+  if State=cssStart then
+    begin
+    ST := TStringList.Create;
+    try
+      ParseContentType(ContentType, ST);
+      FMimeItems := CreateMimeItems;
+      FMimeItems.Boundary := ST.Values['boundary'];
+    finally
+      ST.Free;
+    end;
+    end;
+
+  if FKeepFullContents or not FMimeItems.SupportsStreamingProcessing then
+    ProcessStreamingSetContent(State, Buf, Size);
+
+  if FMimeItems.SupportsStreamingProcessing then
+    FMimeItems.ProcessStreamingMultiPart(State, Buf, Size);
+
+  if State=cssEnd then
+    begin
+    FMimeItems.CreateUploadFiles(Files, ContentFields);
+    if not FMimeItems.SupportsStreamingProcessing then
+      begin
+      S := Content;
+      FMimeItems.FormSplit(S, FMimeItems.Boundary);
+      FMimeItems.CreateUploadFiles(Files, ContentFields);
+      end
+    else if not FKeepFullContents then
+      Content := FMimeItems.Preamble;
+    FreeAndNil(FMimeItems);
+    FContentRead := True;
+    end;
+end;
+
+procedure TRequest.ProcessStreamingURLEncoded(const State: TContentStreamingState; const Buf; const Size: Integer);
+begin
+  // This implementation simply collects the contents, and then parses this
+  // content.
+  // ToDo: replace this with some code that really parses the content
+  // block-by-block.
+  ProcessStreamingSetContent(State, Buf, Size);
+  if state=cssEnd then
+    begin
+    ProcessQueryString(Content, ContentFields);
+    if not KeepFullContents then
+      Content := '';
+    end;
+end;
+
+procedure TRequest.HandleStreamingUnknownEncoding(const State: TContentStreamingState; const Buf; const Size: Integer);
+var
+  S: TStream;
+begin
+  ProcessStreamingSetContent(State, Buf, Size);
+  if Assigned(FOnUnknownEncoding) then
+    begin
+    if state=cssEnd then
+      begin
+      try
+        S := TStringStream.Create(Content);
+        FOnUnknownEncoding(Self,ContentType,nil);
+      finally
+        S.Free;
+      end;
+      end;
+    end;
+end;
+
+procedure TRequest.ProcessStreamingSetContent(const State: TContentStreamingState; const Buf; const Size: Integer);
+var
+  CL: LongInt;
+begin
+  {$ifdef CGIDEBUG} SendMethodEnter('ProcessStreamingSetContent');{$endif CGIDEBUG}
+  if State=cssStart then
+    begin
+    // First time this code is called. Search for a content-length
+    // header and use it as hint for the content-length.
+    if HeaderIsSet(hhContentLength) and TryStrToInt(GetHeader(hhContentLength), CL) and (CL>0) then
+      SetLength(FStreamingContent, CL);
+    end;
+
+  CL := FStreamingContentRead;
+  FStreamingContentRead := CL+Size;
+  if Length(FStreamingContent) < FStreamingContentRead then
+    SetLength(FStreamingContent, FStreamingContentRead);
+  if Size > 0 then
+    Move(Buf, FStreamingContent[CL+1], Size);
+
+  if State=cssEnd then
+    begin
+    SetLength(FStreamingContent, FStreamingContentRead);
+    Content := FStreamingContent;
+    FStreamingContent := '';
+    end;
+end;
+
+procedure TRequest.HandleStreamEncoding(const State: TContentStreamingState; const Buf; const Size: Integer);
+begin
+  if Assigned(FOnStreamEncodingEvent) then
+    FOnStreamEncodingEvent(Self, State, Buf, Size);
+end;
+
 { ---------------------------------------------------------------------
   TUploadedFiles
   ---------------------------------------------------------------------}
@@ -2507,5 +3150,5 @@ begin
 end;
 
 initialization
-  MimeItemClass:=THTTPMimeItem;
+  MimeItemClass:=THTTPStreamingMimeItem;
 end.

+ 21 - 0
packages/fcl-web/tests/integrationtests/README.md

@@ -0,0 +1,21 @@
+# Fcl-web integration tests
+
+This is an attempt to test the data-processing inside fcl-web.
+
+There are two parts: A fpc-application (fcgi_dump_request) that returns the
+received http-data in a Json-format. And an Apache jMeter test-script.
+
+The open-source tool jMeter form Apache is used to send http-requests to the
+fpc-application, and to do several assertions on the results.
+
+To run, you have to create a setup that supports the fcgi_dump_request
+application. For example using a Apache or NGINX setup.
+
+Then check the local-settings within the jMeter test script, and run it.
+
+In principle it is also possible to test plain CGI or the embeddes web-server
+with small changes to fcgi_dump_request.pp.
+
+Note that at the end of the jMeter script a call is made that makes the
+fcgi_dump_request terminate. When compiled with heap-trace information
+this can help locating memory leaks

+ 1 - 0
packages/fcl-web/tests/integrationtests/UploadFile1.txt

@@ -0,0 +1 @@
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Magna eget est lorem ipsum dolor. Enim sit amet venenatis urna cursus eget nunc scelerisque viverra. Non blandit massa enim nec. Nunc eget lorem dolor sed. Fringilla est ullamcorper eget nulla facilisi etiam dignissim. Donec ultrices tincidunt arcu non sodales neque sodales. Elementum facilisis leo vel fringilla est. Amet commodo nulla facilisi nullam. Fusce ut placerat orci nulla pellentesque dignissim enim. Convallis a cras semper auctor neque vitae tempus. Justo eget magna fermentum iaculis eu. Dapibus ultrices in iaculis nunc sed augue lacus viverra vitae. Pellentesque diam volutpat commodo sed egestas egestas fringilla phasellus faucibus. Viverra aliquet eget sit amet. Platea dictumst vestibulum rhoncus est pellentesque.

+ 3 - 0
packages/fcl-web/tests/integrationtests/UploadFile2.txt

@@ -0,0 +1,3 @@
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Laoreet suspendisse interdum consectetur libero id faucibus. Felis eget nunc lobortis mattis. Id interdum velit laoreet id. Eget mi proin sed libero enim sed faucibus turpis. Sed risus pretium quam vulputate dignissim suspendisse in est. Integer malesuada nunc vel risus commodo viverra maecenas. Sit amet justo donec enim diam vulputate. Laoreet non curabitur gravida arcu ac tortor dignissim convallis aenean. Rhoncus mattis rhoncus urna neque. Aliquet sagittis id consectetur purus ut faucibus.
+
+Sit amet consectetur adipiscing elit duis tristique sollicitudin. Integer quis auctor elit sed vulputate. Dui accumsan sit amet nulla facilisi morbi tempus iaculis. A scelerisque purus semper eget duis at tellus. Purus sit amet volutpat consequat. Non diam phasellus vestibulum lorem sed risus. Adipiscing elit pellentesque habitant morbi tristique. Interdum posuere lorem ipsum dolor sit amet consectetur adipiscing. Nunc aliquet bibendum enim facilisis gravida neque. Fringilla urna porttitor rhoncus dolor purus. Felis donec et odio pellentesque diam volutpat. Mauris in aliquam sem fringilla ut morbi tincidunt. Turpis massa sed elementum tempus. Quisque id diam vel quam elementum pulvinar etiam. Nisl pretium fusce id velit ut. Lacus sed turpis tincidunt id aliquet risus feugiat in ante.

+ 199 - 0
packages/fcl-web/tests/integrationtests/UploadFile3.txt

@@ -0,0 +1,199 @@
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Tellus id interdum velit laoreet id donec ultrices. In ornare quam viverra orci sagittis eu volutpat odio facilisis. Ullamcorper morbi tincidunt ornare massa eget egestas purus. Volutpat lacus laoreet non curabitur gravida arcu ac tortor. Mi bibendum neque egestas congue. A condimentum vitae sapien pellentesque. Mattis aliquam faucibus purus in massa tempor nec feugiat. Ullamcorper malesuada proin libero nunc consequat interdum varius. A cras semper auctor neque vitae tempus quam. Magnis dis parturient montes nascetur ridiculus mus. Habitant morbi tristique senectus et netus et malesuada fames. Condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi.
+
+Dolor sit amet consectetur adipiscing elit ut aliquam purus sit. Nam libero justo laoreet sit amet cursus sit. Nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum. Nulla aliquet enim tortor at auctor urna. Quis lectus nulla at volutpat diam ut. Neque viverra justo nec ultrices dui sapien eget mi proin. Tortor consequat id porta nibh. Aliquam vestibulum morbi blandit cursus risus at. Tellus cras adipiscing enim eu turpis egestas. Magna fermentum iaculis eu non diam phasellus vestibulum. Aenean vel elit scelerisque mauris pellentesque pulvinar pellentesque. Eget egestas purus viverra accumsan in nisl nisi. Placerat in egestas erat imperdiet. Sed enim ut sem viverra aliquet eget. Diam vulputate ut pharetra sit amet aliquam id diam maecenas.
+
+Tempor commodo ullamcorper a lacus vestibulum sed arcu non. Pellentesque nec nam aliquam sem et tortor consequat. Sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus. Pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices. Nisl nunc mi ipsum faucibus. Aliquam ultrices sagittis orci a scelerisque purus semper eget duis. Turpis massa tincidunt dui ut ornare lectus sit. Mus mauris vitae ultricies leo integer malesuada nunc. Non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus. Massa sed elementum tempus egestas sed sed risus pretium. Tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat. Sed viverra ipsum nunc aliquet bibendum enim facilisis. Odio pellentesque diam volutpat commodo sed egestas egestas. Eget dolor morbi non arcu. Quam adipiscing vitae proin sagittis nisl rhoncus mattis. Vitae elementum curabitur vitae nunc sed. Dolor magna eget est lorem ipsum dolor sit amet consectetur.
+
+Sit amet risus nullam eget. Mi quis hendrerit dolor magna. Mauris a diam maecenas sed enim. Libero volutpat sed cras ornare arcu dui vivamus arcu felis. Integer vitae justo eget magna. Senectus et netus et malesuada fames ac. Tellus integer feugiat scelerisque varius morbi enim. Suspendisse ultrices gravida dictum fusce ut placerat orci nulla. Pulvinar mattis nunc sed blandit libero volutpat sed cras. Sed ullamcorper morbi tincidunt ornare massa. Convallis tellus id interdum velit laoreet id donec ultrices. Porttitor eget dolor morbi non arcu risus quis varius.
+
+Venenatis tellus in metus vulputate eu scelerisque felis. Sed elementum tempus egestas sed sed risus pretium quam. Tortor pretium viverra suspendisse potenti nullam ac tortor vitae. Eget duis at tellus at urna condimentum. Ultricies tristique nulla aliquet enim tortor at auctor urna nunc. In egestas erat imperdiet sed euismod nisi porta lorem mollis. Vel risus commodo viverra maecenas accumsan lacus vel. Purus non enim praesent elementum. Hac habitasse platea dictumst vestibulum rhoncus est. Feugiat sed lectus vestibulum mattis ullamcorper. Sagittis eu volutpat odio facilisis mauris sit amet massa vitae. Aliquet risus feugiat in ante metus dictum at tempor commodo. Quis commodo odio aenean sed adipiscing diam donec adipiscing tristique. Dignissim enim sit amet venenatis urna cursus.
+
+Fames ac turpis egestas maecenas pharetra. Viverra nibh cras pulvinar mattis nunc sed. Et netus et malesuada fames ac turpis egestas maecenas. Sed nisi lacus sed viverra tellus in hac habitasse platea. Ac felis donec et odio. Ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget. Libero justo laoreet sit amet cursus. Amet consectetur adipiscing elit duis tristique sollicitudin nibh sit amet. Aliquet sagittis id consectetur purus ut faucibus pulvinar elementum. Morbi non arcu risus quis varius quam quisque. Sit amet purus gravida quis blandit turpis cursus in. Pharetra diam sit amet nisl suscipit. Maecenas ultricies mi eget mauris pharetra et ultrices neque.
+
+Dui id ornare arcu odio ut. Ac placerat vestibulum lectus mauris ultrices eros in cursus turpis. Blandit aliquam etiam erat velit scelerisque in dictum non. Feugiat in fermentum posuere urna nec tincidunt. In fermentum et sollicitudin ac orci. A pellentesque sit amet porttitor eget dolor morbi non. Adipiscing elit pellentesque habitant morbi. Viverra orci sagittis eu volutpat odio facilisis mauris sit amet. Id velit ut tortor pretium viverra suspendisse potenti nullam ac. Hac habitasse platea dictumst quisque sagittis. Metus dictum at tempor commodo ullamcorper a. Ut venenatis tellus in metus vulputate eu scelerisque. Vitae auctor eu augue ut lectus. Pulvinar elementum integer enim neque volutpat ac. Nunc mattis enim ut tellus elementum sagittis vitae et. Sem viverra aliquet eget sit amet tellus cras. Porttitor eget dolor morbi non arcu.
+
+Netus et malesuada fames ac turpis egestas integer eget aliquet. Sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum. Tristique et egestas quis ipsum. Vitae nunc sed velit dignissim sodales ut eu sem integer. Arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc. Sed blandit libero volutpat sed. Porttitor eget dolor morbi non. Venenatis tellus in metus vulputate eu. Nisi scelerisque eu ultrices vitae auctor eu augue. Lectus quam id leo in vitae turpis massa sed. Et ligula ullamcorper malesuada proin libero nunc consequat interdum varius. Ac placerat vestibulum lectus mauris ultrices eros in cursus turpis.
+
+Egestas sed tempus urna et. Nisl nisi scelerisque eu ultrices vitae auctor. Scelerisque purus semper eget duis at. Risus quis varius quam quisque id diam vel quam elementum. Ut consequat semper viverra nam libero justo laoreet. Duis ut diam quam nulla. Mattis molestie a iaculis at erat pellentesque. Ac tortor vitae purus faucibus ornare suspendisse sed. Etiam erat velit scelerisque in dictum non consectetur a erat. Elit at imperdiet dui accumsan sit amet. Sociis natoque penatibus et magnis dis parturient. Ut ornare lectus sit amet est placerat in egestas erat. Nullam non nisi est sit amet facilisis magna.
+
+A condimentum vitae sapien pellentesque habitant morbi. Enim tortor at auctor urna nunc id cursus metus. Ullamcorper morbi tincidunt ornare massa. Quis auctor elit sed vulputate mi sit amet. Dolor morbi non arcu risus quis. Semper eget duis at tellus at urna condimentum. Mi proin sed libero enim sed faucibus turpis. Sed risus ultricies tristique nulla aliquet enim tortor at auctor. Ridiculus mus mauris vitae ultricies leo integer malesuada nunc. Sit amet justo donec enim diam vulputate ut pharetra sit.
+
+Fames ac turpis egestas sed tempus urna et. In massa tempor nec feugiat. Pharetra pharetra massa massa ultricies mi quis hendrerit dolor. Lacinia quis vel eros donec. Curabitur vitae nunc sed velit dignissim sodales ut eu sem. Gravida dictum fusce ut placerat orci nulla. Tincidunt augue interdum velit euismod in. Vitae congue eu consequat ac felis donec et. Ac auctor augue mauris augue neque gravida in fermentum. Sed viverra tellus in hac habitasse platea dictumst vestibulum. Massa tempor nec feugiat nisl pretium fusce id velit. Est placerat in egestas erat imperdiet sed euismod nisi porta. Convallis posuere morbi leo urna. Enim neque volutpat ac tincidunt vitae semper. Turpis in eu mi bibendum neque. Diam donec adipiscing tristique risus nec feugiat in fermentum. Congue nisi vitae suscipit tellus mauris a diam maecenas.
+
+Lorem ipsum dolor sit amet consectetur. Risus commodo viverra maecenas accumsan lacus vel facilisis. Suspendisse faucibus interdum posuere lorem ipsum dolor sit. In nibh mauris cursus mattis. Ut morbi tincidunt augue interdum velit. Amet venenatis urna cursus eget nunc scelerisque viverra mauris in. Ullamcorper eget nulla facilisi etiam dignissim diam. Pellentesque eu tincidunt tortor aliquam nulla. Mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan. Sit amet luctus venenatis lectus magna fringilla urna porttitor. Faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae. Felis bibendum ut tristique et egestas.
+
+Suspendisse sed nisi lacus sed viverra tellus in hac habitasse. Aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod. Mattis aliquam faucibus purus in massa tempor nec. Feugiat vivamus at augue eget arcu dictum varius duis. In hendrerit gravida rutrum quisque non tellus. Dui ut ornare lectus sit. Egestas erat imperdiet sed euismod nisi porta lorem. Faucibus vitae aliquet nec ullamcorper sit amet risus nullam. Massa sed elementum tempus egestas sed sed risus. Ornare lectus sit amet est placerat in egestas erat. Arcu bibendum at varius vel. Ullamcorper sit amet risus nullam eget felis. Lorem donec massa sapien faucibus et molestie ac feugiat sed.
+
+Aliquet risus feugiat in ante metus dictum at. Platea dictumst quisque sagittis purus sit amet volutpat consequat. Dui faucibus in ornare quam viverra orci sagittis eu. Et ligula ullamcorper malesuada proin. Amet consectetur adipiscing elit duis tristique. Fermentum dui faucibus in ornare quam viverra orci. Feugiat vivamus at augue eget arcu. Diam sit amet nisl suscipit adipiscing bibendum. Dolor morbi non arcu risus. Morbi tristique senectus et netus et. Accumsan sit amet nulla facilisi morbi tempus iaculis urna id. Volutpat ac tincidunt vitae semper quis lectus nulla at. Natoque penatibus et magnis dis parturient montes nascetur ridiculus mus. Scelerisque felis imperdiet proin fermentum leo vel orci porta. Diam maecenas ultricies mi eget mauris pharetra et ultrices.
+
+Facilisis magna etiam tempor orci eu lobortis elementum nibh tellus. Consequat ac felis donec et. Cras pulvinar mattis nunc sed blandit libero volutpat sed cras. Sed viverra ipsum nunc aliquet bibendum enim facilisis. Molestie a iaculis at erat pellentesque adipiscing commodo elit at. Habitasse platea dictumst quisque sagittis purus. Tincidunt id aliquet risus feugiat. Facilisis magna etiam tempor orci eu lobortis. Vel eros donec ac odio tempor orci dapibus ultrices in. Mauris rhoncus aenean vel elit scelerisque mauris. Egestas dui id ornare arcu odio ut sem. Tortor aliquam nulla facilisi cras fermentum odio eu. Pharetra et ultrices neque ornare. Id velit ut tortor pretium viverra suspendisse potenti nullam ac. Dictum sit amet justo donec enim diam vulputate. Diam vel quam elementum pulvinar etiam non quam lacus suspendisse. Nibh tortor id aliquet lectus proin nibh nisl. Mattis vulputate enim nulla aliquet porttitor lacus. At auctor urna nunc id cursus metus aliquam eleifend mi. Viverra aliquet eget sit amet tellus cras.
+
+Neque volutpat ac tincidunt vitae semper. Magna fringilla urna porttitor rhoncus dolor purus non enim. Natoque penatibus et magnis dis parturient montes. Elementum facilisis leo vel fringilla est ullamcorper eget. Sit amet justo donec enim diam vulputate ut. Diam quis enim lobortis scelerisque fermentum. Sit amet risus nullam eget felis eget nunc lobortis. Quis hendrerit dolor magna eget est. Blandit massa enim nec dui nunc mattis enim. Sed faucibus turpis in eu mi bibendum neque egestas congue. Imperdiet proin fermentum leo vel orci porta. Egestas sed tempus urna et pharetra pharetra. Lacinia quis vel eros donec ac. Id venenatis a condimentum vitae sapien pellentesque habitant morbi. Nisl rhoncus mattis rhoncus urna neque viverra justo. Facilisis mauris sit amet massa vitae tortor. Dignissim suspendisse in est ante in nibh. Nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc. Congue mauris rhoncus aenean vel elit scelerisque mauris pellentesque pulvinar.
+
+Quis eleifend quam adipiscing vitae proin sagittis. Mi eget mauris pharetra et ultrices neque ornare aenean. Ipsum dolor sit amet consectetur. Mauris in aliquam sem fringilla ut morbi. Nulla malesuada pellentesque elit eget gravida cum sociis natoque. A condimentum vitae sapien pellentesque habitant morbi tristique senectus et. Pulvinar proin gravida hendrerit lectus a. Metus vulputate eu scelerisque felis. Vivamus arcu felis bibendum ut tristique et egestas. Duis convallis convallis tellus id. Neque ornare aenean euismod elementum nisi quis. Ultricies lacus sed turpis tincidunt id.
+
+Vel fringilla est ullamcorper eget nulla facilisi etiam. Pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id. Enim ut tellus elementum sagittis vitae et. Mattis vulputate enim nulla aliquet porttitor lacus luctus. Eget lorem dolor sed viverra. Pellentesque habitant morbi tristique senectus et netus et. Dolor sit amet consectetur adipiscing elit pellentesque habitant. Nisl vel pretium lectus quam id leo. Id faucibus nisl tincidunt eget nullam non. Gravida arcu ac tortor dignissim convallis aenean. Pellentesque diam volutpat commodo sed egestas egestas fringilla phasellus. Sed arcu non odio euismod lacinia at quis risus. Quis lectus nulla at volutpat. Augue interdum velit euismod in pellentesque massa placerat duis. Commodo quis imperdiet massa tincidunt nunc. Ullamcorper malesuada proin libero nunc consequat interdum varius sit amet. Libero id faucibus nisl tincidunt eget nullam. Blandit cursus risus at ultrices. Faucibus nisl tincidunt eget nullam non nisi. Aenean et tortor at risus viverra adipiscing.
+
+Egestas congue quisque egestas diam. Odio tempor orci dapibus ultrices in iaculis nunc sed. Volutpat blandit aliquam etiam erat velit scelerisque. Bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida. Viverra adipiscing at in tellus. At augue eget arcu dictum varius duis at. Sagittis aliquam malesuada bibendum arcu vitae. Nam at lectus urna duis convallis convallis tellus id interdum. Neque aliquam vestibulum morbi blandit cursus. Sagittis id consectetur purus ut faucibus pulvinar elementum integer enim. Dictum non consectetur a erat nam at lectus. Maecenas sed enim ut sem viverra. Nisi porta lorem mollis aliquam ut porttitor leo. Malesuada nunc vel risus commodo viverra maecenas. Sed vulputate mi sit amet mauris commodo quis imperdiet massa. Neque volutpat ac tincidunt vitae semper quis lectus nulla at. Vehicula ipsum a arcu cursus vitae congue mauris rhoncus. Volutpat diam ut venenatis tellus in metus vulputate eu scelerisque.
+
+Et malesuada fames ac turpis egestas maecenas. Ultrices mi tempus imperdiet nulla malesuada. Id eu nisl nunc mi ipsum faucibus vitae aliquet. Amet volutpat consequat mauris nunc congue nisi. Nisi quis eleifend quam adipiscing vitae proin sagittis nisl. Dictum non consectetur a erat nam. Eget dolor morbi non arcu risus quis varius. Nisi scelerisque eu ultrices vitae auctor eu augue. Lorem ipsum dolor sit amet consectetur adipiscing elit. Eu feugiat pretium nibh ipsum consequat nisl vel. Eget aliquet nibh praesent tristique magna sit amet purus. Sed arcu non odio euismod lacinia at. Nisi vitae suscipit tellus mauris. Accumsan lacus vel facilisis volutpat est velit egestas. Faucibus in ornare quam viverra orci sagittis. Odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam.
+
+Cursus vitae congue mauris rhoncus aenean vel elit. Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem. Mi in nulla posuere sollicitudin aliquam ultrices sagittis orci a. Dui nunc mattis enim ut. Velit euismod in pellentesque massa placerat duis ultricies lacus. Massa vitae tortor condimentum lacinia quis vel. Rhoncus mattis rhoncus urna neque viverra justo. Pellentesque habitant morbi tristique senectus et netus et malesuada fames. Vitae aliquet nec ullamcorper sit amet risus nullam eget. Pellentesque pulvinar pellentesque habitant morbi tristique senectus. Eget duis at tellus at urna. Faucibus a pellentesque sit amet porttitor eget.
+
+Iaculis urna id volutpat lacus laoreet. Lacinia quis vel eros donec ac odio tempor. Etiam dignissim diam quis enim lobortis scelerisque fermentum. Feugiat nisl pretium fusce id velit. Velit ut tortor pretium viverra suspendisse potenti nullam. Neque ornare aenean euismod elementum. Semper auctor neque vitae tempus. Nisl pretium fusce id velit ut. Neque egestas congue quisque egestas diam in. Nunc sed augue lacus viverra vitae congue eu. Diam vel quam elementum pulvinar etiam non quam lacus suspendisse. Gravida rutrum quisque non tellus orci. Senectus et netus et malesuada fames. Nisl purus in mollis nunc sed id semper risus.
+
+Interdum velit euismod in pellentesque massa placerat duis ultricies lacus. Arcu risus quis varius quam quisque id diam vel. Nec ullamcorper sit amet risus nullam eget. Tristique senectus et netus et malesuada. Eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim. Aliquet eget sit amet tellus cras adipiscing enim eu. Cursus in hac habitasse platea dictumst quisque sagittis. Augue lacus viverra vitae congue eu. Duis convallis convallis tellus id interdum velit laoreet id donec. Rhoncus aenean vel elit scelerisque mauris pellentesque pulvinar pellentesque habitant. Auctor neque vitae tempus quam pellentesque nec nam. At risus viverra adipiscing at in. Libero volutpat sed cras ornare arcu. Leo integer malesuada nunc vel risus. Ut tellus elementum sagittis vitae et.
+
+Id venenatis a condimentum vitae sapien. Lorem dolor sed viverra ipsum nunc aliquet. At in tellus integer feugiat. Quam id leo in vitae turpis massa sed. Donec ultrices tincidunt arcu non sodales neque. Nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus. Pharetra pharetra massa massa ultricies mi quis hendrerit. Habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper. Arcu odio ut sem nulla pharetra diam. Nullam vehicula ipsum a arcu cursus vitae congue mauris. Consectetur adipiscing elit pellentesque habitant morbi. Morbi tristique senectus et netus et malesuada fames. Mauris ultrices eros in cursus turpis massa. Hendrerit dolor magna eget est lorem. Facilisi morbi tempus iaculis urna id. Nascetur ridiculus mus mauris vitae ultricies leo integer. Blandit cursus risus at ultrices mi. Aenean vel elit scelerisque mauris pellentesque pulvinar pellentesque habitant. Est lorem ipsum dolor sit amet consectetur adipiscing.
+
+Leo vel orci porta non pulvinar neque laoreet suspendisse interdum. Cursus vitae congue mauris rhoncus aenean vel elit scelerisque mauris. Urna id volutpat lacus laoreet non curabitur gravida. Aliquet porttitor lacus luctus accumsan tortor. Lectus sit amet est placerat in egestas erat. Lacus sed viverra tellus in. Leo in vitae turpis massa sed. Interdum varius sit amet mattis vulputate enim. Tincidunt vitae semper quis lectus nulla. Turpis egestas maecenas pharetra convallis posuere morbi. Mauris pellentesque pulvinar pellentesque habitant morbi tristique senectus et. Enim blandit volutpat maecenas volutpat blandit. Duis ut diam quam nulla porttitor. Enim nulla aliquet porttitor lacus luctus accumsan. In vitae turpis massa sed. Malesuada proin libero nunc consequat interdum varius sit.
+
+Elit ullamcorper dignissim cras tincidunt lobortis. Duis ut diam quam nulla porttitor. Tellus rutrum tellus pellentesque eu tincidunt tortor. In fermentum posuere urna nec tincidunt praesent semper feugiat nibh. Nunc mattis enim ut tellus elementum sagittis. Amet tellus cras adipiscing enim eu turpis egestas pretium. Nunc pulvinar sapien et ligula ullamcorper malesuada proin. Sed libero enim sed faucibus turpis in eu mi. In massa tempor nec feugiat nisl pretium fusce id. Sit amet porttitor eget dolor. Molestie a iaculis at erat pellentesque adipiscing commodo elit at. Eleifend quam adipiscing vitae proin sagittis nisl rhoncus. Amet est placerat in egestas. Consequat nisl vel pretium lectus. Vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae. Massa tincidunt dui ut ornare.
+
+Cras semper auctor neque vitae. Enim sed faucibus turpis in eu mi. Posuere morbi leo urna molestie. Sed cras ornare arcu dui vivamus arcu felis bibendum. Amet est placerat in egestas erat imperdiet sed. Odio facilisis mauris sit amet. Amet facilisis magna etiam tempor orci eu lobortis. Sagittis id consectetur purus ut faucibus pulvinar elementum. Eu tincidunt tortor aliquam nulla facilisi cras fermentum. Amet mauris commodo quis imperdiet. Vitae tortor condimentum lacinia quis vel eros. Facilisis leo vel fringilla est ullamcorper eget nulla facilisi. Ut diam quam nulla porttitor. Nam libero justo laoreet sit. Porttitor rhoncus dolor purus non enim praesent elementum facilisis. Ut placerat orci nulla pellentesque dignissim.
+
+Velit dignissim sodales ut eu. Tincidunt id aliquet risus feugiat in ante. Eu nisl nunc mi ipsum faucibus. Interdum velit euismod in pellentesque massa. Sollicitudin aliquam ultrices sagittis orci a scelerisque purus semper. Sit amet justo donec enim diam vulputate ut pharetra. Accumsan lacus vel facilisis volutpat est velit. Fringilla est ullamcorper eget nulla facilisi etiam. Sed euismod nisi porta lorem mollis aliquam ut porttitor. Nec sagittis aliquam malesuada bibendum arcu vitae elementum curabitur vitae. Viverra maecenas accumsan lacus vel facilisis volutpat est. Et netus et malesuada fames ac turpis. Dolor morbi non arcu risus quis varius. Velit scelerisque in dictum non consectetur a erat. Ac ut consequat semper viverra nam libero justo. Odio tempor orci dapibus ultrices.
+
+Aliquam etiam erat velit scelerisque in dictum non consectetur a. Suspendisse faucibus interdum posuere lorem. Ultrices eros in cursus turpis massa tincidunt dui ut. Euismod nisi porta lorem mollis. Vel fringilla est ullamcorper eget. Bibendum est ultricies integer quis auctor. Lacus vestibulum sed arcu non odio. Eget sit amet tellus cras adipiscing enim eu turpis. Accumsan lacus vel facilisis volutpat est velit egestas dui. Vitae et leo duis ut diam quam nulla porttitor massa. Justo donec enim diam vulputate ut pharetra sit amet aliquam. Ac odio tempor orci dapibus ultrices in. Dis parturient montes nascetur ridiculus. Sit amet volutpat consequat mauris nunc congue nisi. Vitae sapien pellentesque habitant morbi tristique senectus. Metus dictum at tempor commodo ullamcorper a lacus. Sed viverra tellus in hac habitasse platea dictumst. Rhoncus est pellentesque elit ullamcorper. Nunc sed velit dignissim sodales ut. Vitae turpis massa sed elementum tempus egestas.
+
+Egestas quis ipsum suspendisse ultrices gravida dictum fusce ut. Aliquet nec ullamcorper sit amet. Eget sit amet tellus cras adipiscing enim eu turpis egestas. Orci phasellus egestas tellus rutrum. Vel facilisis volutpat est velit egestas dui id ornare arcu. Sit amet porttitor eget dolor morbi non arcu. Viverra mauris in aliquam sem fringilla ut morbi. Semper eget duis at tellus at. Lectus magna fringilla urna porttitor rhoncus dolor purus non. Urna duis convallis convallis tellus id interdum velit laoreet. Mi eget mauris pharetra et ultrices neque ornare aenean. Erat velit scelerisque in dictum non consectetur a erat. Quis ipsum suspendisse ultrices gravida. Tortor dignissim convallis aenean et. Sit amet nisl purus in mollis nunc. In massa tempor nec feugiat nisl pretium fusce id.
+
+Massa tincidunt dui ut ornare lectus. Molestie at elementum eu facilisis sed odio morbi. Lacus sed turpis tincidunt id aliquet risus feugiat. Viverra tellus in hac habitasse platea dictumst. Risus pretium quam vulputate dignissim suspendisse in. Risus quis varius quam quisque id diam vel quam elementum. Ultricies leo integer malesuada nunc vel risus commodo viverra. Justo donec enim diam vulputate. Diam vel quam elementum pulvinar etiam non quam lacus suspendisse. Dictum fusce ut placerat orci nulla pellentesque dignissim enim sit. Lacus vestibulum sed arcu non. In hac habitasse platea dictumst vestibulum rhoncus est. Scelerisque fermentum dui faucibus in. Scelerisque eu ultrices vitae auctor eu. Viverra nibh cras pulvinar mattis.
+
+Pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus. Tristique sollicitudin nibh sit amet commodo nulla. Nulla porttitor massa id neque aliquam. Rutrum quisque non tellus orci. Sit amet luctus venenatis lectus magna fringilla urna porttitor. Amet venenatis urna cursus eget nunc scelerisque viverra mauris. Sed euismod nisi porta lorem mollis aliquam ut. Dictum non consectetur a erat nam at. Morbi tincidunt augue interdum velit euismod in pellentesque massa. Lorem donec massa sapien faucibus. At augue eget arcu dictum varius duis at. Arcu cursus vitae congue mauris. Magna eget est lorem ipsum dolor sit amet consectetur. Amet commodo nulla facilisi nullam vehicula ipsum a arcu. Dui ut ornare lectus sit amet est placerat in egestas. Suspendisse potenti nullam ac tortor vitae purus faucibus. Ut eu sem integer vitae justo eget magna. Bibendum est ultricies integer quis auctor.
+
+Odio euismod lacinia at quis risus sed vulputate odio ut. Morbi quis commodo odio aenean sed adipiscing diam. Neque sodales ut etiam sit amet nisl purus. Mi sit amet mauris commodo quis imperdiet. In hendrerit gravida rutrum quisque non tellus orci ac. Ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim. Nibh mauris cursus mattis molestie a iaculis at erat. Nibh venenatis cras sed felis. Tincidunt vitae semper quis lectus nulla at volutpat diam ut. Quis commodo odio aenean sed adipiscing. Risus in hendrerit gravida rutrum quisque non tellus orci ac. Et netus et malesuada fames ac turpis egestas. Pulvinar pellentesque habitant morbi tristique senectus et netus. Turpis tincidunt id aliquet risus feugiat in ante.
+
+Nisl purus in mollis nunc sed id. Elit ut aliquam purus sit amet luctus venenatis. Ut eu sem integer vitae justo eget magna. Ac placerat vestibulum lectus mauris ultrices eros. Ultrices mi tempus imperdiet nulla malesuada. Consequat id porta nibh venenatis cras. Nisl pretium fusce id velit ut tortor pretium. Et netus et malesuada fames ac. Enim nulla aliquet porttitor lacus luctus accumsan tortor posuere. Bibendum at varius vel pharetra. Nec ullamcorper sit amet risus nullam. Amet risus nullam eget felis eget. Eros in cursus turpis massa tincidunt dui ut. Enim nec dui nunc mattis enim ut tellus. Quam pellentesque nec nam aliquam sem et tortor consequat. Nulla facilisi morbi tempus iaculis urna id. Magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies.
+
+Ac turpis egestas maecenas pharetra convallis posuere morbi leo. Eget duis at tellus at. Netus et malesuada fames ac turpis. Sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec. Erat nam at lectus urna duis convallis convallis tellus id. Quis blandit turpis cursus in hac habitasse platea dictumst. Sed euismod nisi porta lorem mollis. Ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel. Tristique senectus et netus et malesuada. Est ullamcorper eget nulla facilisi etiam dignissim. Egestas quis ipsum suspendisse ultrices gravida dictum fusce ut. Metus aliquam eleifend mi in nulla posuere. Dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc. Lectus sit amet est placerat in egestas erat. At erat pellentesque adipiscing commodo elit at. Pretium viverra suspendisse potenti nullam ac. Volutpat sed cras ornare arcu dui vivamus arcu felis.
+
+Malesuada fames ac turpis egestas integer eget. Tellus orci ac auctor augue mauris augue. Faucibus in ornare quam viverra orci. Sagittis aliquam malesuada bibendum arcu vitae elementum curabitur. Vel turpis nunc eget lorem. Mus mauris vitae ultricies leo integer malesuada nunc vel. Nisl suscipit adipiscing bibendum est ultricies integer quis. Ultrices vitae auctor eu augue ut lectus arcu bibendum at. Nulla pellentesque dignissim enim sit amet venenatis urna cursus eget. Potenti nullam ac tortor vitae purus faucibus. Morbi tempus iaculis urna id. Phasellus faucibus scelerisque eleifend donec pretium. Ultrices sagittis orci a scelerisque purus. Sit amet nulla facilisi morbi. Massa sapien faucibus et molestie ac feugiat. Vitae purus faucibus ornare suspendisse sed nisi. Ut ornare lectus sit amet est placerat in egestas erat. Lobortis mattis aliquam faucibus purus.
+
+Eu facilisis sed odio morbi quis commodo odio aenean. Faucibus a pellentesque sit amet porttitor eget dolor. Arcu bibendum at varius vel pharetra vel. Etiam dignissim diam quis enim lobortis scelerisque fermentum. Porttitor rhoncus dolor purus non. Vel elit scelerisque mauris pellentesque pulvinar. Porttitor eget dolor morbi non. Aliquam ultrices sagittis orci a scelerisque purus semper eget duis. In vitae turpis massa sed elementum tempus egestas sed. Elit eget gravida cum sociis natoque penatibus. Pulvinar sapien et ligula ullamcorper malesuada proin libero nunc. Elit pellentesque habitant morbi tristique senectus et netus. Ut etiam sit amet nisl purus in mollis nunc. Platea dictumst quisque sagittis purus sit amet volutpat consequat. Facilisis gravida neque convallis a. Ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper. Non arcu risus quis varius quam quisque id.
+
+Diam phasellus vestibulum lorem sed risus ultricies tristique nulla aliquet. Nec sagittis aliquam malesuada bibendum arcu vitae elementum. Id aliquet lectus proin nibh. Consectetur purus ut faucibus pulvinar elementum. Id aliquet risus feugiat in ante metus dictum at. Nulla porttitor massa id neque aliquam vestibulum morbi blandit. Eget aliquet nibh praesent tristique magna sit amet purus. Enim nunc faucibus a pellentesque. Tellus in hac habitasse platea. Adipiscing diam donec adipiscing tristique risus nec. Id consectetur purus ut faucibus pulvinar elementum. Sodales ut eu sem integer vitae. Eu nisl nunc mi ipsum faucibus.
+
+Consequat id porta nibh venenatis. Convallis aenean et tortor at risus viverra adipiscing at. Etiam sit amet nisl purus in mollis nunc. Ornare quam viverra orci sagittis eu volutpat odio facilisis. Egestas egestas fringilla phasellus faucibus scelerisque. Proin libero nunc consequat interdum varius sit amet mattis vulputate. Non blandit massa enim nec. Vestibulum morbi blandit cursus risus at ultrices. Et malesuada fames ac turpis egestas integer. Commodo viverra maecenas accumsan lacus vel facilisis. Morbi tristique senectus et netus et malesuada. Dui vivamus arcu felis bibendum ut tristique et. Neque laoreet suspendisse interdum consectetur libero. Donec massa sapien faucibus et molestie ac feugiat sed. Lectus nulla at volutpat diam ut venenatis. Mi eget mauris pharetra et ultrices neque ornare aenean. Ullamcorper a lacus vestibulum sed arcu. Vel facilisis volutpat est velit. Porttitor eget dolor morbi non arcu risus quis. Sodales ut etiam sit amet nisl purus.
+
+Consectetur libero id faucibus nisl tincidunt eget nullam non nisi. Sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis. Lectus nulla at volutpat diam ut. Suspendisse in est ante in nibh mauris cursus mattis molestie. Ornare suspendisse sed nisi lacus sed. Feugiat nibh sed pulvinar proin gravida hendrerit. Nec feugiat nisl pretium fusce id velit. Eget mauris pharetra et ultrices neque ornare aenean euismod elementum. Quam vulputate dignissim suspendisse in. Sed nisi lacus sed viverra tellus in. Hendrerit gravida rutrum quisque non tellus orci. Ac turpis egestas maecenas pharetra convallis. Lectus sit amet est placerat in. Id eu nisl nunc mi ipsum faucibus vitae aliquet.
+
+A arcu cursus vitae congue mauris rhoncus. Vitae nunc sed velit dignissim sodales ut eu sem. Amet nulla facilisi morbi tempus iaculis urna id volutpat lacus. Vitae aliquet nec ullamcorper sit amet risus nullam. Pulvinar mattis nunc sed blandit. Ac feugiat sed lectus vestibulum mattis ullamcorper. Lorem ipsum dolor sit amet consectetur adipiscing elit. Magna fermentum iaculis eu non diam phasellus vestibulum. Elementum sagittis vitae et leo duis ut. Sociis natoque penatibus et magnis dis. Eu scelerisque felis imperdiet proin fermentum leo vel orci. Ultricies integer quis auctor elit sed vulputate mi sit. Id consectetur purus ut faucibus pulvinar elementum integer enim. Risus sed vulputate odio ut. Vivamus arcu felis bibendum ut tristique. Fermentum posuere urna nec tincidunt praesent. Leo vel orci porta non. Turpis egestas sed tempus urna et. Sed velit dignissim sodales ut eu sem. Rhoncus dolor purus non enim praesent elementum facilisis leo vel.
+
+Tempus quam pellentesque nec nam aliquam sem. Pellentesque massa placerat duis ultricies lacus. In est ante in nibh mauris cursus mattis molestie a. Id leo in vitae turpis. Ac turpis egestas integer eget aliquet nibh praesent. Sit amet justo donec enim diam vulputate ut pharetra. Sapien et ligula ullamcorper malesuada proin libero nunc. Mauris vitae ultricies leo integer malesuada nunc. Sem viverra aliquet eget sit amet tellus cras adipiscing. Aliquam sem fringilla ut morbi tincidunt augue interdum. Tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat.
+
+Nunc consequat interdum varius sit amet mattis vulputate enim nulla. Et odio pellentesque diam volutpat. Faucibus interdum posuere lorem ipsum dolor. Urna duis convallis convallis tellus id interdum velit laoreet. Hac habitasse platea dictumst quisque sagittis. Cras fermentum odio eu feugiat pretium nibh ipsum consequat. Nisl suscipit adipiscing bibendum est ultricies. Tempor commodo ullamcorper a lacus. Rutrum quisque non tellus orci ac auctor augue. In arcu cursus euismod quis viverra. Aenean vel elit scelerisque mauris pellentesque pulvinar pellentesque habitant. Massa tincidunt dui ut ornare lectus sit amet. Vitae aliquet nec ullamcorper sit amet. Faucibus in ornare quam viverra orci sagittis eu volutpat. Porta nibh venenatis cras sed felis eget velit aliquet. Tincidunt augue interdum velit euismod. In mollis nunc sed id semper risus in hendrerit gravida. Eget dolor morbi non arcu risus.
+
+Nunc vel risus commodo viverra maecenas accumsan. Ornare suspendisse sed nisi lacus sed viverra tellus in. Magna sit amet purus gravida. Scelerisque viverra mauris in aliquam sem fringilla ut. Fermentum leo vel orci porta non pulvinar neque laoreet. Sed blandit libero volutpat sed cras. Congue quisque egestas diam in arcu cursus euismod quis viverra. Donec et odio pellentesque diam volutpat. Faucibus scelerisque eleifend donec pretium vulputate sapien. Mattis enim ut tellus elementum sagittis. Ipsum faucibus vitae aliquet nec ullamcorper.
+
+Quis hendrerit dolor magna eget. Magna eget est lorem ipsum dolor sit amet consectetur. Aliquet lectus proin nibh nisl. Vel pharetra vel turpis nunc eget lorem dolor sed. Fringilla phasellus faucibus scelerisque eleifend. Eget nunc lobortis mattis aliquam faucibus. Libero enim sed faucibus turpis in eu mi. Dui faucibus in ornare quam. Mollis aliquam ut porttitor leo. At risus viverra adipiscing at. Mattis aliquam faucibus purus in massa tempor. In egestas erat imperdiet sed.
+
+Ipsum nunc aliquet bibendum enim facilisis. Rhoncus dolor purus non enim praesent elementum facilisis leo. Nibh venenatis cras sed felis eget velit aliquet sagittis. Feugiat in fermentum posuere urna nec tincidunt. Risus pretium quam vulputate dignissim suspendisse. Suspendisse in est ante in nibh. Amet est placerat in egestas erat imperdiet sed euismod. Eleifend mi in nulla posuere sollicitudin aliquam. Est pellentesque elit ullamcorper dignissim. Volutpat est velit egestas dui id ornare arcu odio ut. Gravida cum sociis natoque penatibus et magnis dis. Aliquet porttitor lacus luctus accumsan. Arcu non sodales neque sodales ut etiam sit. Tincidunt dui ut ornare lectus sit amet est. Sem et tortor consequat id porta nibh venenatis cras. Eu turpis egestas pretium aenean pharetra magna ac placerat. Eu ultrices vitae auctor eu augue. Egestas diam in arcu cursus euismod quis viverra nibh.
+
+Sed id semper risus in hendrerit. Quam adipiscing vitae proin sagittis nisl rhoncus mattis. Sed velit dignissim sodales ut eu. Volutpat sed cras ornare arcu dui. Nisl pretium fusce id velit ut tortor pretium. Interdum velit laoreet id donec ultrices. Commodo odio aenean sed adipiscing diam donec adipiscing tristique risus. Iaculis nunc sed augue lacus. Turpis nunc eget lorem dolor sed viverra ipsum nunc. Enim nec dui nunc mattis enim ut. Mollis nunc sed id semper risus. Cum sociis natoque penatibus et magnis dis parturient montes nascetur. Volutpat consequat mauris nunc congue nisi vitae suscipit tellus. In arcu cursus euismod quis viverra.
+
+Aliquet eget sit amet tellus cras adipiscing. Sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque. A condimentum vitae sapien pellentesque habitant morbi. In est ante in nibh mauris cursus. Sagittis nisl rhoncus mattis rhoncus urna. Semper eget duis at tellus at urna. Sit amet consectetur adipiscing elit. Amet dictum sit amet justo. Tortor id aliquet lectus proin. Volutpat sed cras ornare arcu.
+
+Quam id leo in vitae turpis. Cursus turpis massa tincidunt dui ut. Feugiat scelerisque varius morbi enim nunc. Amet justo donec enim diam. Montes nascetur ridiculus mus mauris vitae ultricies leo. Lorem mollis aliquam ut porttitor leo a. At auctor urna nunc id cursus metus aliquam eleifend. Nisl nisi scelerisque eu ultrices vitae auctor eu augue. Tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce. Egestas tellus rutrum tellus pellentesque eu. Nibh tellus molestie nunc non blandit.
+
+Morbi tempus iaculis urna id volutpat lacus. Posuere ac ut consequat semper viverra nam. Ac auctor augue mauris augue neque gravida in fermentum. Sit amet aliquam id diam maecenas ultricies mi eget mauris. Purus in massa tempor nec feugiat nisl. Non nisi est sit amet facilisis. Tincidunt augue interdum velit euismod in pellentesque massa placerat duis. Sit amet purus gravida quis. Proin nibh nisl condimentum id venenatis a condimentum vitae. Cras adipiscing enim eu turpis egestas pretium. Risus commodo viverra maecenas accumsan. Elementum curabitur vitae nunc sed velit dignissim sodales ut eu. Condimentum vitae sapien pellentesque habitant morbi tristique senectus. Mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan. Elementum eu facilisis sed odio morbi.
+
+Nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit. Cursus risus at ultrices mi tempus. Eu non diam phasellus vestibulum. Nisl vel pretium lectus quam id. Sodales ut etiam sit amet nisl purus in mollis. Vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor. Ut placerat orci nulla pellentesque dignissim enim sit amet. Nec nam aliquam sem et tortor consequat id porta nibh. At tempor commodo ullamcorper a lacus vestibulum. Ac tortor dignissim convallis aenean et tortor at risus. Praesent semper feugiat nibh sed pulvinar. Est ullamcorper eget nulla facilisi etiam dignissim diam. Lorem donec massa sapien faucibus. Lectus proin nibh nisl condimentum id venenatis a condimentum. Aliquam eleifend mi in nulla posuere sollicitudin. Ultricies leo integer malesuada nunc vel risus commodo viverra. Aliquet lectus proin nibh nisl condimentum id venenatis a. Cursus mattis molestie a iaculis at erat pellentesque adipiscing commodo. Tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra. Sit amet luctus venenatis lectus magna.
+
+Vel pretium lectus quam id leo in vitae turpis massa. Sit amet nulla facilisi morbi. Eu ultrices vitae auctor eu augue ut lectus arcu. Dictum non consectetur a erat. Id velit ut tortor pretium viverra suspendisse potenti. Ut faucibus pulvinar elementum integer enim neque. Lorem mollis aliquam ut porttitor leo. Etiam non quam lacus suspendisse faucibus. Faucibus a pellentesque sit amet porttitor eget. Fermentum leo vel orci porta non pulvinar neque laoreet suspendisse.
+
+Purus non enim praesent elementum facilisis leo vel fringilla. Mi sit amet mauris commodo quis imperdiet massa. Ultrices sagittis orci a scelerisque purus semper eget duis at. Vulputate dignissim suspendisse in est ante in nibh mauris. Fames ac turpis egestas sed tempus urna et pharetra. Diam vulputate ut pharetra sit amet. Quisque non tellus orci ac auctor augue. Sed viverra ipsum nunc aliquet bibendum enim facilisis. Habitant morbi tristique senectus et. Risus in hendrerit gravida rutrum quisque non tellus orci ac. Senectus et netus et malesuada fames. Semper eget duis at tellus at urna condimentum. At elementum eu facilisis sed odio morbi quis commodo odio. Eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum. Tellus cras adipiscing enim eu turpis egestas pretium aenean. Sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec. Eu non diam phasellus vestibulum lorem sed risus ultricies tristique.
+
+Pulvinar pellentesque habitant morbi tristique senectus. Eget magna fermentum iaculis eu non diam phasellus vestibulum. Quis risus sed vulputate odio ut. A pellentesque sit amet porttitor eget dolor morbi. Sed turpis tincidunt id aliquet. Mattis enim ut tellus elementum. Eleifend donec pretium vulputate sapien. Convallis posuere morbi leo urna molestie at. Quam elementum pulvinar etiam non quam. Aliquam etiam erat velit scelerisque. Tincidunt arcu non sodales neque sodales. In iaculis nunc sed augue lacus viverra. Vel facilisis volutpat est velit egestas dui. Faucibus a pellentesque sit amet porttitor eget dolor morbi. In ante metus dictum at tempor commodo ullamcorper a lacus.
+
+Malesuada fames ac turpis egestas integer eget. Consectetur adipiscing elit duis tristique sollicitudin nibh. Tristique risus nec feugiat in fermentum posuere. Mauris vitae ultricies leo integer malesuada nunc vel risus. Pellentesque adipiscing commodo elit at imperdiet. Nulla facilisi etiam dignissim diam quis. Nulla porttitor massa id neque aliquam. At elementum eu facilisis sed odio morbi. A pellentesque sit amet porttitor eget dolor morbi non arcu. Nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum. Sapien faucibus et molestie ac feugiat sed lectus vestibulum. Et sollicitudin ac orci phasellus. Ultrices gravida dictum fusce ut placerat.
+
+At risus viverra adipiscing at in. In fermentum posuere urna nec tincidunt praesent semper feugiat nibh. Vitae turpis massa sed elementum tempus egestas sed sed risus. Leo urna molestie at elementum eu facilisis. Molestie at elementum eu facilisis sed odio morbi. Ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a. Sit amet luctus venenatis lectus. Enim eu turpis egestas pretium aenean pharetra magna ac. Sed euismod nisi porta lorem mollis aliquam ut porttitor. In fermentum posuere urna nec tincidunt. Mollis aliquam ut porttitor leo a diam sollicitudin tempor. Elementum nibh tellus molestie nunc. Id donec ultrices tincidunt arcu. Dui ut ornare lectus sit amet est placerat in. Pellentesque pulvinar pellentesque habitant morbi tristique senectus et netus et.
+
+Curabitur vitae nunc sed velit dignissim sodales ut eu sem. Ultricies tristique nulla aliquet enim tortor. Feugiat in ante metus dictum at tempor. Lacinia at quis risus sed vulputate odio ut. Donec massa sapien faucibus et molestie ac feugiat sed lectus. Erat nam at lectus urna duis convallis convallis. Laoreet sit amet cursus sit amet dictum sit amet. Feugiat vivamus at augue eget arcu dictum varius. Velit dignissim sodales ut eu sem integer vitae justo. Phasellus vestibulum lorem sed risus. Enim sit amet venenatis urna cursus eget nunc scelerisque. Euismod lacinia at quis risus. Nulla pharetra diam sit amet nisl suscipit adipiscing. Eget velit aliquet sagittis id consectetur purus ut faucibus. Odio eu feugiat pretium nibh ipsum consequat nisl vel pretium. Euismod nisi porta lorem mollis. Ut enim blandit volutpat maecenas volutpat. Sit amet consectetur adipiscing elit pellentesque habitant morbi. Est lorem ipsum dolor sit amet consectetur adipiscing. At imperdiet dui accumsan sit amet nulla facilisi morbi.
+
+Nec nam aliquam sem et tortor consequat. A lacus vestibulum sed arcu non odio euismod. Dictum fusce ut placerat orci nulla pellentesque dignissim. Cursus metus aliquam eleifend mi in nulla posuere sollicitudin. Id ornare arcu odio ut. Eu facilisis sed odio morbi quis commodo odio aenean sed. Risus commodo viverra maecenas accumsan lacus vel facilisis volutpat. Auctor urna nunc id cursus metus aliquam. Hendrerit gravida rutrum quisque non. Id velit ut tortor pretium. Dignissim suspendisse in est ante in nibh mauris cursus mattis. Vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras. Ultricies lacus sed turpis tincidunt id aliquet risus feugiat in. Duis at tellus at urna condimentum mattis pellentesque id. Sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum. Mattis nunc sed blandit libero volutpat sed cras ornare. Sit amet cursus sit amet dictum sit amet. Faucibus ornare suspendisse sed nisi lacus. Rutrum quisque non tellus orci.
+
+Mattis rhoncus urna neque viverra justo nec. Tristique senectus et netus et malesuada fames. Vitae tortor condimentum lacinia quis vel eros donec ac odio. Adipiscing commodo elit at imperdiet dui accumsan sit. Facilisis sed odio morbi quis commodo. Purus in massa tempor nec. Arcu felis bibendum ut tristique et. Netus et malesuada fames ac turpis egestas sed tempus. Bibendum neque egestas congue quisque. Non curabitur gravida arcu ac tortor dignissim convallis aenean. Sed felis eget velit aliquet sagittis id consectetur purus. Condimentum lacinia quis vel eros donec. Enim tortor at auctor urna. Ac turpis egestas integer eget aliquet nibh praesent. Ac turpis egestas sed tempus urna et pharetra. Imperdiet massa tincidunt nunc pulvinar sapien. Velit scelerisque in dictum non consectetur a erat. Velit scelerisque in dictum non consectetur a erat nam at. In eu mi bibendum neque egestas congue quisque.
+
+Non quam lacus suspendisse faucibus interdum posuere lorem ipsum dolor. Commodo quis imperdiet massa tincidunt nunc pulvinar sapien. Facilisi morbi tempus iaculis urna id volutpat lacus laoreet. Sit amet tellus cras adipiscing enim eu turpis egestas pretium. Ut morbi tincidunt augue interdum velit euismod in pellentesque. Eu non diam phasellus vestibulum. In nibh mauris cursus mattis. Convallis a cras semper auctor neque vitae. Eros in cursus turpis massa tincidunt. Sit amet consectetur adipiscing elit duis tristique sollicitudin nibh sit. Risus commodo viverra maecenas accumsan lacus vel.
+
+In hac habitasse platea dictumst quisque sagittis purus sit amet. Ipsum faucibus vitae aliquet nec ullamcorper sit amet risus. Ac turpis egestas maecenas pharetra convallis posuere. Dui vivamus arcu felis bibendum ut tristique et egestas quis. Ipsum dolor sit amet consectetur adipiscing elit duis tristique. Et magnis dis parturient montes nascetur ridiculus mus mauris vitae. Nunc vel risus commodo viverra maecenas accumsan lacus. Condimentum lacinia quis vel eros donec ac odio. Sit amet mattis vulputate enim nulla aliquet porttitor. Ultricies mi eget mauris pharetra et ultrices neque ornare. Porta non pulvinar neque laoreet suspendisse interdum consectetur libero.
+
+Erat imperdiet sed euismod nisi porta lorem mollis aliquam. Tincidunt arcu non sodales neque sodales ut etiam sit amet. Posuere urna nec tincidunt praesent semper. Posuere sollicitudin aliquam ultrices sagittis orci a scelerisque purus semper. In dictum non consectetur a erat nam at. Faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae. Euismod lacinia at quis risus sed vulputate odio ut enim. Tempor commodo ullamcorper a lacus vestibulum sed arcu non. Amet tellus cras adipiscing enim eu turpis egestas. Suspendisse potenti nullam ac tortor. Sit amet commodo nulla facilisi nullam vehicula ipsum a arcu. Mattis molestie a iaculis at erat. Non tellus orci ac auctor augue mauris augue.
+
+Suspendisse faucibus interdum posuere lorem ipsum dolor. Quam id leo in vitae turpis massa sed elementum. Malesuada proin libero nunc consequat interdum varius sit. Amet venenatis urna cursus eget. Egestas congue quisque egestas diam in. Sed elementum tempus egestas sed sed risus pretium quam. Commodo odio aenean sed adipiscing diam donec adipiscing. Mauris rhoncus aenean vel elit scelerisque mauris pellentesque pulvinar pellentesque. Sit amet nulla facilisi morbi tempus. Ut aliquam purus sit amet luctus. Id velit ut tortor pretium viverra. In hac habitasse platea dictumst quisque sagittis purus sit amet. Diam in arcu cursus euismod quis viverra. A arcu cursus vitae congue mauris rhoncus aenean vel elit. Nunc sed blandit libero volutpat sed cras ornare. Commodo quis imperdiet massa tincidunt nunc pulvinar sapien et. Aliquam vestibulum morbi blandit cursus risus at ultrices. Tellus elementum sagittis vitae et. Eleifend quam adipiscing vitae proin.
+
+Nullam non nisi est sit amet facilisis magna. Parturient montes nascetur ridiculus mus mauris. Augue ut lectus arcu bibendum at varius vel pharetra vel. Placerat orci nulla pellentesque dignissim enim sit amet venenatis. Sed lectus vestibulum mattis ullamcorper. Sit amet nulla facilisi morbi tempus iaculis urna. Amet massa vitae tortor condimentum lacinia. Volutpat maecenas volutpat blandit aliquam etiam. At urna condimentum mattis pellentesque id. Enim sit amet venenatis urna cursus eget nunc scelerisque. Sed nisi lacus sed viverra tellus in. Proin libero nunc consequat interdum varius sit amet mattis. Vulputate ut pharetra sit amet. Scelerisque eleifend donec pretium vulputate sapien nec. Quam pellentesque nec nam aliquam sem et tortor consequat. Massa massa ultricies mi quis hendrerit. A pellentesque sit amet porttitor eget dolor. Malesuada bibendum arcu vitae elementum.
+
+Sit amet volutpat consequat mauris. Eu feugiat pretium nibh ipsum consequat nisl. Pharetra et ultrices neque ornare aenean euismod elementum nisi. Vel risus commodo viverra maecenas accumsan lacus vel. Amet nulla facilisi morbi tempus iaculis urna id volutpat. Malesuada proin libero nunc consequat interdum varius sit. Laoreet id donec ultrices tincidunt arcu non. Non pulvinar neque laoreet suspendisse. Et netus et malesuada fames ac. Vel elit scelerisque mauris pellentesque pulvinar. Congue nisi vitae suscipit tellus mauris a diam maecenas. Duis tristique sollicitudin nibh sit. Cursus vitae congue mauris rhoncus aenean vel elit. Viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas.
+
+Mauris augue neque gravida in fermentum et. Cras pulvinar mattis nunc sed. Suspendisse ultrices gravida dictum fusce ut placerat orci. Urna et pharetra pharetra massa massa ultricies mi quis. Pulvinar sapien et ligula ullamcorper malesuada proin libero. Nec feugiat nisl pretium fusce id. Semper risus in hendrerit gravida. Cursus metus aliquam eleifend mi in nulla. Consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat. Id cursus metus aliquam eleifend mi in nulla posuere sollicitudin. Adipiscing commodo elit at imperdiet dui accumsan. Eget nunc scelerisque viverra mauris in aliquam sem fringilla. Volutpat diam ut venenatis tellus in metus vulputate eu. Accumsan tortor posuere ac ut. Augue mauris augue neque gravida in fermentum et sollicitudin.
+
+Fringilla est ullamcorper eget nulla facilisi etiam dignissim diam quis. Ut tortor pretium viverra suspendisse potenti nullam. Ut porttitor leo a diam sollicitudin tempor id eu nisl. Proin libero nunc consequat interdum varius sit amet. Praesent tristique magna sit amet purus gravida. Magna fringilla urna porttitor rhoncus dolor purus. Elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue. Sit amet est placerat in egestas erat imperdiet sed euismod. Tellus cras adipiscing enim eu turpis egestas pretium. Pretium viverra suspendisse potenti nullam ac tortor vitae. Arcu ac tortor dignissim convallis aenean et tortor. Fermentum leo vel orci porta. Eu sem integer vitae justo eget. Ut diam quam nulla porttitor massa id neque. Ultrices gravida dictum fusce ut placerat orci nulla pellentesque. Sed adipiscing diam donec adipiscing tristique risus. Faucibus ornare suspendisse sed nisi lacus sed viverra tellus in. Rutrum quisque non tellus orci. Malesuada fames ac turpis egestas integer eget. Viverra tellus in hac habitasse platea dictumst vestibulum.
+
+Faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper. Fames ac turpis egestas maecenas pharetra convallis posuere morbi. Risus quis varius quam quisque id diam vel quam elementum. Sagittis id consectetur purus ut faucibus. Blandit volutpat maecenas volutpat blandit aliquam etiam. Ut ornare lectus sit amet. Id venenatis a condimentum vitae sapien pellentesque. Consequat interdum varius sit amet mattis vulputate enim. Ut pharetra sit amet aliquam. Ac felis donec et odio pellentesque diam volutpat commodo sed. Vivamus at augue eget arcu dictum. Dictum sit amet justo donec. Nisi vitae suscipit tellus mauris.
+
+Elementum nibh tellus molestie nunc non. Mollis nunc sed id semper risus in. Pharetra magna ac placerat vestibulum lectus mauris ultrices eros in. Volutpat maecenas volutpat blandit aliquam etiam. Donec ultrices tincidunt arcu non sodales neque sodales ut etiam. Tortor id aliquet lectus proin. Vitae et leo duis ut diam quam nulla porttitor massa. Quis ipsum suspendisse ultrices gravida dictum fusce ut. Proin libero nunc consequat interdum varius sit. Nunc faucibus a pellentesque sit amet porttitor eget dolor morbi. Eu volutpat odio facilisis mauris sit. Mi sit amet mauris commodo quis imperdiet massa.
+
+Sem integer vitae justo eget magna fermentum iaculis. Dui id ornare arcu odio ut sem nulla pharetra. Risus in hendrerit gravida rutrum quisque. Volutpat diam ut venenatis tellus in. Enim facilisis gravida neque convallis a. Enim eu turpis egestas pretium aenean. At risus viverra adipiscing at in tellus integer feugiat scelerisque. Consequat nisl vel pretium lectus quam id leo in vitae. Felis imperdiet proin fermentum leo vel orci. Quis commodo odio aenean sed adipiscing diam. Adipiscing elit duis tristique sollicitudin. Vel pharetra vel turpis nunc. A pellentesque sit amet porttitor eget dolor. Arcu bibendum at varius vel pharetra vel turpis nunc eget. Ac orci phasellus egestas tellus rutrum tellus. Vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat.
+
+Vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat. Tincidunt nunc pulvinar sapien et ligula. Amet nisl purus in mollis nunc sed id. Sit amet nulla facilisi morbi tempus. Fermentum iaculis eu non diam. Purus sit amet luctus venenatis lectus magna fringilla urna porttitor. Molestie at elementum eu facilisis. Ut venenatis tellus in metus vulputate. Eu augue ut lectus arcu bibendum at varius vel. Orci sagittis eu volutpat odio facilisis mauris. Id leo in vitae turpis massa sed elementum. Quisque id diam vel quam elementum pulvinar etiam non quam. Mattis molestie a iaculis at erat pellentesque adipiscing commodo elit. Sed elementum tempus egestas sed sed risus pretium. Donec pretium vulputate sapien nec sagittis aliquam malesuada bibendum arcu. Tortor condimentum lacinia quis vel eros donec. In massa tempor nec feugiat nisl pretium fusce. Ut porttitor leo a diam sollicitudin tempor. Morbi blandit cursus risus at ultrices mi tempus. Eget mauris pharetra et ultrices neque ornare.
+
+Pellentesque habitant morbi tristique senectus et netus et. Diam phasellus vestibulum lorem sed risus ultricies tristique nulla aliquet. Tempor orci eu lobortis elementum nibh tellus molestie nunc. Interdum consectetur libero id faucibus nisl tincidunt eget nullam. Posuere morbi leo urna molestie at elementum. Amet aliquam id diam maecenas ultricies mi eget mauris pharetra. Commodo quis imperdiet massa tincidunt. Dignissim diam quis enim lobortis scelerisque. Placerat orci nulla pellentesque dignissim enim sit. Posuere ac ut consequat semper viverra nam. Tristique sollicitudin nibh sit amet commodo.
+
+Ac feugiat sed lectus vestibulum mattis ullamcorper velit. Adipiscing enim eu turpis egestas pretium aenean pharetra magna ac. Egestas sed sed risus pretium quam vulputate dignissim. Pellentesque massa placerat duis ultricies lacus sed turpis. Semper viverra nam libero justo laoreet. Sed egestas egestas fringilla phasellus faucibus scelerisque eleifend. Nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus. Ac tortor vitae purus faucibus ornare. Ac placerat vestibulum lectus mauris. Volutpat est velit egestas dui id ornare. Etiam tempor orci eu lobortis elementum. Massa sed elementum tempus egestas sed sed risus pretium. Commodo quis imperdiet massa tincidunt.
+
+Dolor sit amet consectetur adipiscing elit. Nulla at volutpat diam ut. Id velit ut tortor pretium viverra suspendisse. Ipsum dolor sit amet consectetur adipiscing elit. Varius morbi enim nunc faucibus a pellentesque. Dolor sit amet consectetur adipiscing elit ut aliquam purus sit. Orci a scelerisque purus semper eget duis at tellus. Egestas purus viverra accumsan in nisl. Purus sit amet luctus venenatis lectus magna fringilla. Pretium vulputate sapien nec sagittis aliquam malesuada bibendum. Mattis rhoncus urna neque viverra justo. Vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum. Tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat. Leo urna molestie at elementum eu. Mattis aliquam faucibus purus in. Id porta nibh venenatis cras sed felis eget. Nisl purus in mollis nunc sed id. Velit egestas dui id ornare arcu odio. Tincidunt eget nullam non nisi est. Augue ut lectus arcu bibendum at.
+
+Et ultrices neque ornare aenean euismod elementum nisi. Nibh ipsum consequat nisl vel pretium. Diam maecenas sed enim ut sem viverra aliquet eget sit. Vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra. Nisl rhoncus mattis rhoncus urna. Nec nam aliquam sem et tortor. Nisi est sit amet facilisis magna etiam tempor orci eu. Imperdiet proin fermentum leo vel orci. Dui sapien eget mi proin sed. Volutpat odio facilisis mauris sit amet massa vitae. A lacus vestibulum sed arcu non odio euismod. At lectus urna duis convallis convallis. Lectus sit amet est placerat in egestas. Egestas dui id ornare arcu odio ut sem nulla pharetra. Purus in mollis nunc sed id semper risus. Laoreet sit amet cursus sit. Mi proin sed libero enim sed faucibus turpis in. Ipsum dolor sit amet consectetur adipiscing elit ut aliquam. Sed risus ultricies tristique nulla aliquet enim tortor at. Congue eu consequat ac felis donec et odio pellentesque diam.
+
+Pellentesque habitant morbi tristique senectus. Sit amet luctus venenatis lectus magna fringilla. Sed risus ultricies tristique nulla aliquet enim tortor. Posuere sollicitudin aliquam ultrices sagittis orci a scelerisque purus. Sit amet venenatis urna cursus eget nunc. Eget felis eget nunc lobortis mattis aliquam faucibus purus in. Pretium aenean pharetra magna ac placerat vestibulum lectus mauris. Diam vel quam elementum pulvinar etiam non quam lacus. Rhoncus urna neque viverra justo nec ultrices dui sapien. Tellus id interdum velit laoreet id donec ultrices tincidunt arcu. Turpis massa sed elementum tempus egestas sed sed risus. Sit amet mattis vulputate enim nulla aliquet porttitor lacus. At quis risus sed vulputate. Pellentesque nec nam aliquam sem et tortor consequat id porta. Sed velit dignissim sodales ut eu. Rhoncus urna neque viverra justo. Ac turpis egestas sed tempus urna et.
+
+Risus sed vulputate odio ut. Diam in arcu cursus euismod. Ac turpis egestas maecenas pharetra convallis posuere morbi. Ac turpis egestas maecenas pharetra convallis. Risus feugiat in ante metus. Mattis molestie a iaculis at erat pellentesque adipiscing. Magna etiam tempor orci eu lobortis elementum. Purus sit amet luctus venenatis lectus magna fringilla urna. Morbi tempus iaculis urna id volutpat lacus laoreet non curabitur. Sagittis vitae et leo duis ut diam quam. Lectus quam id leo in vitae turpis massa sed elementum. Augue mauris augue neque gravida in. Ac ut consequat semper viverra nam. Tristique et egestas quis ipsum suspendisse ultrices gravida. Id neque aliquam vestibulum morbi blandit cursus risus. Dignissim cras tincidunt lobortis feugiat vivamus. Eu facilisis sed odio morbi quis commodo odio aenean. Nunc sed blandit libero volutpat sed cras ornare arcu. Neque volutpat ac tincidunt vitae semper quis lectus.
+
+Dignissim enim sit amet venenatis urna cursus eget nunc. Rutrum quisque non tellus orci ac auctor augue mauris augue. Amet est placerat in egestas erat. Massa tempor nec feugiat nisl pretium. Integer feugiat scelerisque varius morbi enim nunc. Massa enim nec dui nunc. Nulla facilisi cras fermentum odio eu feugiat pretium. Ac placerat vestibulum lectus mauris ultrices eros. Amet tellus cras adipiscing enim eu turpis. In nisl nisi scelerisque eu ultrices vitae auctor eu augue. Sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu. Ac auctor augue mauris augue neque gravida in fermentum et. In arcu cursus euismod quis viverra nibh. Non consectetur a erat nam at lectus urna duis convallis. Amet nulla facilisi morbi tempus iaculis urna. Fermentum leo vel orci porta non pulvinar neque laoreet suspendisse. Arcu cursus euismod quis viverra nibh. Sed risus ultricies tristique nulla aliquet enim tortor at auctor. Cursus sit amet dictum sit amet justo. Lacus vestibulum sed arcu non odio.
+
+Consectetur adipiscing elit ut aliquam purus. Elit eget gravida cum sociis natoque penatibus et magnis dis. Ut porttitor leo a diam sollicitudin tempor id eu. Faucibus turpis in eu mi bibendum neque egestas congue. Proin fermentum leo vel orci porta non pulvinar neque. Id velit ut tortor pretium viverra suspendisse potenti nullam ac. Eu ultrices vitae auctor eu augue ut. Tincidunt tortor aliquam nulla facilisi cras. Nunc id cursus metus aliquam eleifend. Consequat id porta nibh venenatis cras sed felis. Aliquet enim tortor at auctor. Tristique senectus et netus et malesuada. Aliquet porttitor lacus luctus accumsan tortor posuere ac. Egestas congue quisque egestas diam in. Sed faucibus turpis in eu mi bibendum neque. Ut faucibus pulvinar elementum integer enim neque volutpat.
+
+Laoreet non curabitur gravida arcu ac tortor dignissim convallis. At risus viverra adipiscing at in tellus. Morbi non arcu risus quis varius quam quisque id diam. Cras adipiscing enim eu turpis. Integer feugiat scelerisque varius morbi enim nunc. Phasellus vestibulum lorem sed risus ultricies. A iaculis at erat pellentesque adipiscing commodo elit at. Mauris vitae ultricies leo integer malesuada nunc vel. Ultricies integer quis auctor elit sed vulputate mi sit. Id porta nibh venenatis cras sed. Mi in nulla posuere sollicitudin aliquam. Nulla facilisi morbi tempus iaculis urna id volutpat lacus laoreet. Egestas congue quisque egestas diam in. Lectus magna fringilla urna porttitor rhoncus dolor purus non enim. Nibh tortor id aliquet lectus proin nibh. Pretium lectus quam id leo in vitae turpis massa. Dictum fusce ut placerat orci nulla pellentesque dignissim enim. Amet luctus venenatis lectus magna fringilla urna porttitor.
+
+Egestas purus viverra accumsan in nisl. Nibh tellus molestie nunc non blandit massa. Metus aliquam eleifend mi in nulla. Ultrices mi tempus imperdiet nulla malesuada. Turpis in eu mi bibendum neque egestas congue quisque egestas. Morbi enim nunc faucibus a pellentesque. Auctor urna nunc id cursus. Vitae auctor eu augue ut lectus arcu bibendum at. Faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget. Tristique et egestas quis ipsum suspendisse. Mattis aliquam faucibus purus in massa tempor. Sit amet facilisis magna etiam tempor orci eu.
+
+Porttitor rhoncus dolor purus non. Lacus luctus accumsan tortor posuere. Malesuada bibendum arcu vitae elementum curabitur vitae. Nibh sit amet commodo nulla facilisi. Dictumst quisque sagittis purus sit amet volutpat consequat mauris. Est placerat in egestas erat imperdiet sed euismod nisi porta. Ut etiam sit amet nisl. Montes nascetur ridiculus mus mauris vitae ultricies leo. Neque vitae tempus quam pellentesque nec nam. Luctus venenatis lectus magna fringilla urna porttitor rhoncus dolor.
+
+Malesuada proin libero nunc consequat interdum varius sit. Donec massa sapien faucibus et. Ut tristique et egestas quis ipsum. Diam ut venenatis tellus in metus. Leo urna molestie at elementum eu facilisis sed odio morbi. Est ullamcorper eget nulla facilisi etiam. Et egestas quis ipsum suspendisse ultrices gravida dictum fusce. Congue mauris rhoncus aenean vel elit scelerisque mauris pellentesque. Adipiscing elit duis tristique sollicitudin nibh sit amet. Lectus urna duis convallis convallis tellus id interdum. Integer feugiat scelerisque varius morbi enim nunc faucibus a pellentesque. Ac felis donec et odio pellentesque diam volutpat commodo. Dui faucibus in ornare quam viverra orci sagittis eu. Senectus et netus et malesuada. Amet risus nullam eget felis eget. Accumsan in nisl nisi scelerisque eu ultrices vitae auctor. Ut tristique et egestas quis ipsum suspendisse ultrices gravida. Nibh mauris cursus mattis molestie a iaculis at.
+
+Venenatis cras sed felis eget velit. Vitae congue eu consequat ac felis donec et. At augue eget arcu dictum varius duis at consectetur lorem. Justo eget magna fermentum iaculis eu non diam phasellus. Netus et malesuada fames ac turpis. Mi bibendum neque egestas congue quisque. Vel risus commodo viverra maecenas accumsan lacus vel. Est ullamcorper eget nulla facilisi. Facilisi nullam vehicula ipsum a arcu. Nisi est sit amet facilisis magna. Adipiscing tristique risus nec feugiat in fermentum posuere. Ultrices eros in cursus turpis. Dolor purus non enim praesent elementum facilisis. Viverra nam libero justo laoreet sit amet. Arcu vitae elementum curabitur vitae.
+
+Diam ut venenatis tellus in metus vulputate. Fermentum dui faucibus in ornare quam viverra orci sagittis. Id semper risus in hendrerit. Magna sit amet purus gravida quis blandit turpis cursus in. Enim ut tellus elementum sagittis vitae et leo. Pharetra convallis posuere morbi leo urna molestie. Nunc congue nisi vitae suscipit tellus. Quis hendrerit dolor magna eget est lorem ipsum. Tortor condimentum lacinia quis vel eros donec ac. Tempor orci eu lobortis elementum nibh tellus molestie nunc. Nulla pellentesque dignissim enim sit amet venenatis urna cursus. Vitae sapien pellentesque habitant morbi tristique senectus. Viverra justo nec ultrices dui sapien. Nunc scelerisque viverra mauris in aliquam sem fringilla ut. Odio aenean sed adipiscing diam donec adipiscing.
+
+Est placerat in egestas erat imperdiet sed euismod nisi. Non consectetur a erat nam at lectus urna. Mauris nunc congue nisi vitae suscipit tellus mauris a diam. Enim diam vulputate ut pharetra. Proin fermentum leo vel orci. Pellentesque habitant morbi tristique senectus et netus et. Quis ipsum suspendisse ultrices gravida dictum fusce. Nisi scelerisque eu ultrices vitae auctor. Tempor commodo ullamcorper a lacus vestibulum sed arcu non. Eget aliquet nibh praesent tristique magna. Amet facilisis magna etiam tempor. Nisi vitae suscipit tellus mauris a diam maecenas sed.
+
+Nunc aliquet bibendum enim facilisis gravida. Blandit cursus risus at ultrices mi. Tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium. Aliquet nibh praesent tristique magna sit amet. Massa placerat duis ultricies lacus sed turpis. Morbi non arcu risus quis varius quam quisque. Morbi tempus iaculis urna id. Facilisis mauris sit amet massa vitae tortor condimentum. Faucibus in ornare quam viverra orci sagittis eu volutpat odio. Vulputate dignissim suspendisse in est ante in nibh mauris. Lorem ipsum dolor sit amet consectetur adipiscing elit duis. Cras fermentum odio eu feugiat pretium nibh. Morbi blandit cursus risus at ultrices. Leo in vitae turpis massa sed elementum tempus egestas.
+
+Amet volutpat consequat mauris nunc congue nisi vitae suscipit. Nunc pulvinar sapien et ligula ullamcorper malesuada. Egestas pretium aenean pharetra magna ac. At varius vel pharetra vel turpis nunc eget lorem dolor. Etiam dignissim diam quis enim lobortis scelerisque fermentum dui faucibus. Ut tortor pretium viverra suspendisse potenti. Lacus suspendisse faucibus interdum posuere lorem ipsum dolor sit amet. Mauris pharetra et ultrices neque ornare aenean euismod elementum. Vel pretium lectus quam id leo in vitae turpis massa. Netus et malesuada fames ac turpis. Leo duis ut diam quam nulla porttitor massa id. Velit egestas dui id ornare arcu odio. Turpis massa tincidunt dui ut ornare. Enim sit amet venenatis urna cursus. Fames ac turpis egestas maecenas pharetra convallis. Pharetra massa massa ultricies mi quis hendrerit dolor magna eget. Ornare lectus sit amet est placerat in egestas erat.
+
+Ultrices gravida dictum fusce ut placerat orci nulla pellentesque. Sit amet commodo nulla facilisi nullam vehicula ipsum. Neque viverra justo nec ultrices dui. Posuere lorem ipsum dolor sit amet. Consectetur a erat nam at lectus urna duis convallis convallis. Enim nunc faucibus a pellentesque. Sed risus ultricies tristique nulla aliquet enim tortor at auctor. Blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque. Maecenas sed enim ut sem viverra aliquet eget. At erat pellentesque adipiscing commodo elit at. Enim nulla aliquet porttitor lacus.
+
+Justo eget magna fermentum iaculis eu non diam phasellus. Vitae et leo duis ut diam quam nulla. Mi quis hendrerit dolor magna eget. Feugiat in fermentum posuere urna nec tincidunt praesent semper feugiat. Rhoncus dolor purus non enim praesent. Sodales ut etiam sit amet nisl. Arcu odio ut sem nulla pharetra diam. Cursus sit amet dictum sit amet justo donec enim diam. Eu facilisis sed odio morbi quis commodo odio. Placerat duis ultricies lacus sed. Ac auctor augue mauris augue neque gravida in fermentum et.
+
+Lectus magna fringilla urna porttitor rhoncus dolor. Imperdiet proin fermentum leo vel orci porta non pulvinar neque. Sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum. Amet luctus venenatis lectus magna fringilla urna porttitor rhoncus dolor. Vestibulum lorem sed risus ultricies tristique nulla aliquet enim. Consequat nisl vel pretium lectus quam id leo. Cursus sit amet dictum sit. Hendrerit dolor magna eget est lorem. Pellentesque diam volutpat commodo sed. Arcu cursus euismod quis viverra nibh. Id venenatis a condimentum vitae sapien pellentesque. Massa massa ultricies mi quis hendrerit dolor magna. Laoreet id donec ultrices tincidunt arcu non sodales neque. Sagittis orci a scelerisque purus semper. Mauris vitae ultricies leo integer malesuada. A cras semper auctor neque vitae tempus. Neque viverra justo nec ultrices dui sapien eget mi proin. Malesuada fames ac turpis egestas integer eget aliquet. Non curabitur gravida arcu ac tortor.
+
+Sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque. Venenatis lectus magna fringilla urna porttitor rhoncus dolor purus. Magnis dis parturient montes nascetur ridiculus. Egestas tellus rutrum tellus pellentesque. Volutpat consequat mauris nunc congue nisi. Ullamcorper malesuada proin libero nunc consequat. Viverra tellus in hac habitasse platea dictumst vestibulum rhoncus. Gravida neque convallis a cras semper auctor neque vitae. Sed turpis tincidunt id aliquet. Vestibulum rhoncus est pellentesque elit ullamcorper dignissim. Ut aliquam purus sit amet luctus. Velit egestas dui id ornare arcu odio ut sem nulla. Bibendum ut tristique et egestas quis. Neque vitae tempus quam pellentesque. Amet consectetur adipiscing elit ut aliquam purus sit amet. Nisi vitae suscipit tellus mauris a diam maecenas sed enim.
+
+Nulla posuere sollicitudin aliquam ultrices sagittis orci a. Tempus imperdiet nulla malesuada pellentesque elit. Fringilla urna porttitor rhoncus dolor purus non enim. Tincidunt arcu non sodales neque sodales ut. Ac placerat vestibulum lectus mauris. Venenatis cras sed felis eget. Auctor eu augue ut lectus arcu bibendum at. Arcu felis bibendum ut tristique et egestas. Elementum nibh tellus molestie nunc non. Ut venenatis tellus in metus vulputate eu scelerisque felis. Tempus iaculis urna id volutpat lacus laoreet non curabitur gravida. In ante metus dictum at tempor commodo ullamcorper a. Porttitor rhoncus dolor purus non. Dolor magna eget est lorem ipsum dolor sit. Eget nulla facilisi etiam dignissim diam quis enim. Morbi enim nunc faucibus a pellentesque. Dui ut ornare lectus sit amet est placerat. Pellentesque adipiscing commodo elit at imperdiet dui accumsan sit.
+
+Elit at imperdiet dui accumsan sit amet nulla facilisi. Lectus sit amet est placerat. Massa tempor nec feugiat nisl pretium fusce id velit ut. Ipsum suspendisse ultrices gravida dictum fusce ut placerat. Consectetur adipiscing elit duis tristique sollicitudin nibh. Velit laoreet id donec ultrices tincidunt arcu non sodales. At elementum eu facilisis sed odio morbi. At erat pellentesque adipiscing commodo elit at imperdiet. Imperdiet nulla malesuada pellentesque elit. Mattis rhoncus urna neque viverra justo nec ultrices.
+
+Venenatis urna cursus eget nunc scelerisque. Quis auctor elit sed vulputate mi sit amet mauris. Nec feugiat in fermentum posuere urna nec tincidunt praesent. At augue eget arcu dictum varius duis. Congue quisque egestas diam in arcu. Nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum. Id aliquet risus feugiat in ante metus dictum at tempor. Urna condimentum mattis pellentesque id nibh tortor id. Lectus proin nibh nisl condimentum. A scelerisque purus semper eget duis at tellus at urna. Arcu dui vivamus arcu felis bibendum ut tristique et egestas. Amet volutpat consequat mauris nunc congue nisi vitae suscipit. Varius duis at consectetur lorem donec massa. Sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit. Praesent semper feugiat nibh sed pulvinar proin gravida hendrerit. Felis bibendum ut tristique et egestas quis.
+
+Pulvinar etiam non quam lacus. Lobortis feugiat vivamus at augue eget. Adipiscing enim eu turpis egestas pretium aenean. A cras semper auctor neque. Molestie nunc non blandit massa. Tincidunt augue interdum velit euismod in. Nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut. Eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim. Ac tincidunt vitae semper quis lectus nulla. Leo duis ut diam quam nulla porttitor. Ultricies mi eget mauris pharetra et ultrices neque ornare aenean. Commodo nulla facilisi nullam vehicula ipsum a arcu cursus. Tortor posuere ac ut consequat semper viverra nam. Adipiscing elit ut aliquam purus sit amet luctus venenatis. Ut sem nulla pharetra diam sit. Eget duis at tellus at urna condimentum mattis.
+
+Cras semper auctor neque vitae tempus quam. Dolor sit amet consectetur adipiscing elit pellentesque habitant. Neque volutpat ac tincidunt vitae semper quis lectus. Vitae sapien pellentesque habitant morbi tristique senectus et netus. Libero nunc consequat interdum varius sit amet mattis vulputate enim. Pharetra et ultrices neque ornare aenean euismod elementum. Maecenas sed enim ut sem viverra. Consectetur a erat nam at lectus urna duis. Ac orci phasellus egestas tellus rutrum tellus pellentesque. Et malesuada fames ac turpis. Dui sapien eget mi proin sed libero enim sed. Cras adipiscing enim eu turpis egestas pretium aenean pharetra. Egestas purus viverra accumsan in nisl nisi scelerisque eu. Posuere sollicitudin aliquam ultrices sagittis. Orci nulla pellentesque dignissim enim sit amet. Diam sit amet nisl suscipit adipiscing bibendum. Nunc sed id semper risus in. Tortor pretium viverra suspendisse potenti nullam. Nec feugiat in fermentum posuere urna nec tincidunt praesent semper. Viverra vitae congue eu consequat ac felis.
+
+Massa massa ultricies mi quis hendrerit dolor magna eget. Vitae turpis massa sed elementum tempus. Dignissim sodales ut eu sem. Lacus luctus accumsan tortor posuere ac ut. Velit euismod in pellentesque massa placerat duis ultricies. Pulvinar pellentesque habitant morbi tristique senectus et netus. Condimentum mattis pellentesque id nibh tortor id aliquet lectus proin. Morbi tincidunt augue interdum velit euismod in pellentesque massa placerat. Pellentesque pulvinar pellentesque habitant morbi. Magna fermentum iaculis eu non diam. Sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae. Euismod quis viverra nibh cras pulvinar. Purus ut faucibus pulvinar elementum integer enim neque volutpat ac. Amet risus nullam eget felis.
+
+Pellentesque id nibh tortor id aliquet lectus. Eu ultrices vitae auctor eu. Ut tristique et egestas quis ipsum suspendisse. In nibh mauris cursus mattis molestie a iaculis at erat. Tincidunt augue interdum velit euismod in pellentesque massa placerat. Vestibulum mattis ullamcorper velit sed. Porttitor eget dolor morbi non arcu risus quis varius quam. In hendrerit gravida rutrum quisque non. Faucibus purus in massa tempor nec feugiat. Semper eget duis at tellus at urna condimentum mattis pellentesque. Sed vulputate mi sit amet mauris commodo quis. Nunc id cursus metus aliquam eleifend mi in. Nibh nisl condimentum id venenatis a condimentum. Neque convallis a cras semper auctor neque vitae tempus.
+
+Arcu cursus vitae congue mauris rhoncus. Vitae aliquet nec ullamcorper sit amet risus nullam eget felis. Arcu bibendum at varius vel pharetra vel turpis nunc. Id faucibus nisl tincidunt eget nullam non nisi est sit. Ac felis donec et odio. Sollicitudin tempor id eu nisl nunc mi ipsum faucibus. Metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel. Sed augue lacus viverra vitae congue eu. Eget mauris pharetra et ultrices neque ornare aenean euismod elementum. Cursus turpis massa tincidunt dui. Tortor condimentum lacinia quis vel eros donec ac odio.

+ 184 - 0
packages/fcl-web/tests/integrationtests/fcgi_dump_request.pp

@@ -0,0 +1,184 @@
+program fcgi_dump_request;
+
+{$mode objfpc}{$H+}
+
+uses
+  Classes,
+  SysUtils,
+  httpDefs,
+  fpweb,
+  custweb,
+  custfcgi,
+  httpprotocol,
+  fpjson,
+  sha1;
+
+Type
+
+  { TMyCGIHandler }
+
+  TMyCGIHandler = Class(TFCgiHandler)
+  protected
+   function GetSHA1FileHash(const AFileName: string): string;
+  Public
+    procedure HandleRequest(ARequest : TRequest; AResponse : TResponse); override;
+    function DumpHeaders(ARequest: TRequest): TJSONObject;
+    function DumpContent(ARequest: TRequest): TJSONObject;
+    function DumpFiles(ARequest: TRequest): TJSONArray;
+  end;
+
+  TMyCGIApp = Class(TCustomFCgiApplication)
+  Protected
+   function InitializeWebHandler: TWebHandler; override;
+  end;
+
+var
+  WebApp: TMyCGIApp;
+
+Procedure TMyCGIHandler.HandleRequest(ARequest : Trequest; AResponse : TResponse);
+var
+  ResponseJson: TJSONObject;
+  ShouldShutdown: Boolean;
+begin
+  if not TryStrToBool(ARequest.QueryFields.Values['shutdown'], ShouldShutdown) then
+    ShouldShutdown := False;
+
+  ResponseJson := TJSONObject.Create();
+  try
+    ResponseJson.Add('headers', DumpHeaders(ARequest));
+    ResponseJson.Add('content', DumpContent(ARequest));
+    ResponseJson.Add('files', DumpFiles(ARequest));
+    if ShouldShutdown then
+      ResponseJson.Add('shutdown', True);
+    AResponse.Content := ResponseJson.AsJSON;
+  finally
+    ResponseJson.Free;
+  end;
+
+  // Usefull for testing of memory-leaks
+  if ShouldShutdown then
+    WebApp.Terminate;
+end;
+
+function TMyCGIHandler.DumpHeaders(ARequest: TRequest): TJSONObject;
+var
+  HeaderJson: TJSONObject;
+  CustomHeaderJson: TJSONObject;
+  Header: THeader;
+  i: Integer;
+begin
+  HeaderJson := TJSONObject.Create;
+  try
+    for Header := Low(Header) to High(Header) do
+      if ARequest.HeaderIsSet(Header) then
+        HeaderJson.Add(HTTPHeaderNames[Header], ARequest.GetHeader(Header));
+
+    if ARequest.CustomHeaders.Count > 0 then
+      begin
+      CustomHeaderJson := TJSONObject.Create;
+      HeaderJson.Add('custom', CustomHeaderJson);
+      for i := 0 to ARequest.CustomHeaders.Count -1 do
+        CustomHeaderJson.Add(ARequest.CustomHeaders.Names[i], ARequest.CustomHeaders.ValueFromIndex[i]);
+      end;
+
+    Result := HeaderJson;
+    HeaderJson := nil;
+  finally
+    HeaderJson.Free;
+  end;
+end;
+
+function TMyCGIHandler.DumpContent(ARequest: TRequest): TJSONObject;
+var
+  ContentJson: TJSONObject;
+  ContentFieldJson: TJSONArray;
+  i: Integer;
+begin
+  ContentJson := TJSONObject.Create;
+  try
+    if Length(ARequest.Content) > 250 then
+      ContentJson.Add('rawTrimmed', TJSONObject.Create([
+        'length', Length(ARequest.Content),
+        'start', Copy(ARequest.Content, 1, 120),
+        'end', Copy(ARequest.Content, Length(ARequest.Content)-79, 120)
+      ]))
+    else
+      ContentJson.Add('raw', ARequest.Content);
+
+    if ARequest.ContentFields.Count > 0 then
+      begin
+      ContentFieldJson := TJSONArray.Create;
+      ContentJson.Add('fields', ContentFieldJson);
+      for i := 0 to ARequest.ContentFields.Count -1 do
+        begin
+        ContentFieldJson.Add(TJSONObject.Create([
+          'name', ARequest.ContentFields.Names[i],
+          'value' , ARequest.ContentFields.ValueFromIndex[i]]));
+        end;
+      end;
+
+    Result := ContentJson;
+    ContentJson := nil;
+  finally
+    ContentJson.Free;
+  end;
+end;
+
+function TMyCGIHandler.DumpFiles(ARequest: TRequest): TJSONArray;
+var
+  FileJsonArr: TJSONArray;
+  FileJson: TJSONObject;
+  i: Integer;
+  UploadedFile: TUploadedFile;
+begin
+  FileJsonArr := TJSONArray.Create;
+  try
+    for i := 0 to ARequest.Files.Count -1 do
+      begin
+      UploadedFile := ARequest.Files.Files[i];
+      FileJson := TJSONObject.Create([
+        'filename', UploadedFile.FileName,
+        'localFillename', UploadedFile.LocalFileName,
+        'description', UploadedFile.Description,
+        'contentType', UploadedFile.ContentType,
+        'size', UploadedFile.Size,
+        'disposition', UploadedFile.Disposition,
+        'fieldname', UploadedFile.FieldName,
+        'sha1', GetSHA1FileHash(UploadedFile.LocalFileName)
+      ]);
+      FileJsonArr.Add(FileJson);
+      DeleteFile(UploadedFile.LocalFileName);
+      end;
+
+    Result := FileJsonArr;
+    FileJsonArr := nil;
+  finally
+    FileJsonArr.Free;
+  end;
+end;
+
+function TMyCGIHandler.GetSHA1FileHash(const AFileName: string): string;
+begin
+  if FileExists(AFileName) then
+    Result := SHA1Print(SHA1File(AFileName));
+end;
+
+Function TMyCGIApp.InitializeWebHandler: TWebHandler; 
+begin
+  Result:=TMyCgiHandler.Create(self);
+end;
+
+begin
+  WebApp := TMyCGIApp.Create(Nil);
+  With WebApp do
+    try
+      { Uncomment the port setting here if you want to run the
+       FastCGI application stand-alone (e.g. for NGINX) }
+      Port := 7005;
+      ProtocolOptions := [poReuseAddress];
+      Initialize;
+      Run;
+    finally
+      Free;
+    end;
+end.

+ 1034 - 0
packages/fcl-web/tests/integrationtests/fcl-web_integrationtests.jmx

@@ -0,0 +1,1034 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.4.1">
+  <hashTree>
+    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
+      <stringProp name="TestPlan.comments"></stringProp>
+      <boolProp name="TestPlan.functional_mode">false</boolProp>
+      <boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
+      <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
+      <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+        <collectionProp name="Arguments.arguments"/>
+      </elementProp>
+      <stringProp name="TestPlan.user_define_classpath"></stringProp>
+    </TestPlan>
+    <hashTree>
+      <Arguments guiclass="ArgumentsPanel" testclass="Arguments" testname="Local settings" enabled="true">
+        <collectionProp name="Arguments.arguments">
+          <elementProp name="host" elementType="Argument">
+            <stringProp name="Argument.name">host</stringProp>
+            <stringProp name="Argument.value">127.0.0.1</stringProp>
+            <stringProp name="Argument.metadata">=</stringProp>
+          </elementProp>
+          <elementProp name="protocol" elementType="Argument">
+            <stringProp name="Argument.name">protocol</stringProp>
+            <stringProp name="Argument.value">http</stringProp>
+            <stringProp name="Argument.metadata">=</stringProp>
+          </elementProp>
+          <elementProp name="uri" elementType="Argument">
+            <stringProp name="Argument.name">uri</stringProp>
+            <stringProp name="Argument.value">fcgi</stringProp>
+            <stringProp name="Argument.metadata">=</stringProp>
+          </elementProp>
+          <elementProp name="files_path" elementType="Argument">
+            <stringProp name="Argument.name">files_path</stringProp>
+            <stringProp name="Argument.value">${__BeanShell(import org.apache.jmeter.services.FileServer; FileServer.getFileServer().getBaseDir();)}${__BeanShell(File.separator,)}</stringProp>
+            <stringProp name="Argument.metadata">=</stringProp>
+            <stringProp name="Argument.desc">Location of the upload-files</stringProp>
+          </elementProp>
+        </collectionProp>
+      </Arguments>
+      <hashTree/>
+      <ConfigTestElement guiclass="HttpDefaultsGui" testclass="ConfigTestElement" testname="HTTP Request Defaults" enabled="true">
+        <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+          <collectionProp name="Arguments.arguments"/>
+        </elementProp>
+        <stringProp name="HTTPSampler.domain">${host}</stringProp>
+        <stringProp name="HTTPSampler.port"></stringProp>
+        <stringProp name="HTTPSampler.protocol">${protocol}</stringProp>
+        <stringProp name="HTTPSampler.contentEncoding"></stringProp>
+        <stringProp name="HTTPSampler.path">${uri}</stringProp>
+        <stringProp name="HTTPSampler.concurrentPool">6</stringProp>
+        <stringProp name="HTTPSampler.connect_timeout"></stringProp>
+        <stringProp name="HTTPSampler.response_timeout"></stringProp>
+      </ConfigTestElement>
+      <hashTree/>
+      <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
+        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
+        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
+          <boolProp name="LoopController.continue_forever">false</boolProp>
+          <stringProp name="LoopController.loops">1</stringProp>
+        </elementProp>
+        <stringProp name="ThreadGroup.num_threads">1</stringProp>
+        <stringProp name="ThreadGroup.ramp_time">1</stringProp>
+        <boolProp name="ThreadGroup.scheduler">false</boolProp>
+        <stringProp name="ThreadGroup.duration"></stringProp>
+        <stringProp name="ThreadGroup.delay"></stringProp>
+        <boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
+      </ThreadGroup>
+      <hashTree>
+        <GenericController guiclass="LogicControllerGui" testclass="GenericController" testname="Post small file" enabled="true"/>
+        <hashTree>
+          <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true">
+            <collectionProp name="HeaderManager.headers">
+              <elementProp name="" elementType="Header">
+                <stringProp name="Header.name">Content-Type</stringProp>
+                <stringProp name="Header.value">multipart/form-data; boundary=------------------------e6d533842bd07008</stringProp>
+              </elementProp>
+            </collectionProp>
+          </HeaderManager>
+          <hashTree/>
+          <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Post small file" enabled="true">
+            <boolProp name="HTTPSampler.postBodyRaw">true</boolProp>
+            <elementProp name="HTTPsampler.Arguments" elementType="Arguments">
+              <collectionProp name="Arguments.arguments">
+                <elementProp name="" elementType="HTTPArgument">
+                  <boolProp name="HTTPArgument.always_encode">false</boolProp>
+                  <stringProp name="Argument.value">--------------------------e6d533842bd07008&#xd;
+Content-Disposition: form-data; name=&quot;upload&quot;; filename=&quot;UploadFileSmall.txt&quot;&#xd;
+Content-Type: text/plain&#xd;
+&#xd;
+Small&#xd;
+&#xd;
+--------------------------e6d533842bd07008--</stringProp>
+                  <stringProp name="Argument.metadata">=</stringProp>
+                </elementProp>
+              </collectionProp>
+            </elementProp>
+            <stringProp name="HTTPSampler.domain"></stringProp>
+            <stringProp name="HTTPSampler.port"></stringProp>
+            <stringProp name="HTTPSampler.protocol"></stringProp>
+            <stringProp name="HTTPSampler.contentEncoding"></stringProp>
+            <stringProp name="HTTPSampler.path"></stringProp>
+            <stringProp name="HTTPSampler.method">POST</stringProp>
+            <boolProp name="HTTPSampler.follow_redirects">false</boolProp>
+            <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
+            <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+            <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
+            <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
+            <stringProp name="HTTPSampler.connect_timeout"></stringProp>
+            <stringProp name="HTTPSampler.response_timeout"></stringProp>
+          </HTTPSamplerProxy>
+          <hashTree>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.files[0].size</stringProp>
+              <stringProp name="EXPECTED_VALUE">7</stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.files[0].sha1</stringProp>
+              <stringProp name="EXPECTED_VALUE">d9ce7590765717c47c737add2ac11e0665eabbea</stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.files[0].contentType</stringProp>
+              <stringProp name="EXPECTED_VALUE">text/plain</stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.files[0].fieldname</stringProp>
+              <stringProp name="EXPECTED_VALUE">upload</stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.files[0].filename</stringProp>
+              <stringProp name="EXPECTED_VALUE">UploadFileSmall.txt</stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.content.raw</stringProp>
+              <stringProp name="EXPECTED_VALUE"></stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+          </hashTree>
+          <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Post small file with preamble" enabled="true">
+            <boolProp name="HTTPSampler.postBodyRaw">true</boolProp>
+            <elementProp name="HTTPsampler.Arguments" elementType="Arguments">
+              <collectionProp name="Arguments.arguments">
+                <elementProp name="" elementType="HTTPArgument">
+                  <boolProp name="HTTPArgument.always_encode">false</boolProp>
+                  <stringProp name="Argument.value">This is a message with multiple parts in MIME format.&#xd;
+--------------------------e6d533842bd07008&#xd;
+Content-Disposition: form-data; name=&quot;upload&quot;; filename=&quot;UploadFileSmall.txt&quot;&#xd;
+Content-Type: text/plain&#xd;
+&#xd;
+Small&#xd;
+&#xd;
+--------------------------e6d533842bd07008--</stringProp>
+                  <stringProp name="Argument.metadata">=</stringProp>
+                </elementProp>
+              </collectionProp>
+            </elementProp>
+            <stringProp name="HTTPSampler.domain"></stringProp>
+            <stringProp name="HTTPSampler.port"></stringProp>
+            <stringProp name="HTTPSampler.protocol"></stringProp>
+            <stringProp name="HTTPSampler.contentEncoding"></stringProp>
+            <stringProp name="HTTPSampler.path"></stringProp>
+            <stringProp name="HTTPSampler.method">POST</stringProp>
+            <boolProp name="HTTPSampler.follow_redirects">false</boolProp>
+            <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
+            <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+            <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
+            <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
+            <stringProp name="HTTPSampler.connect_timeout"></stringProp>
+            <stringProp name="HTTPSampler.response_timeout"></stringProp>
+          </HTTPSamplerProxy>
+          <hashTree>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.files[0].size</stringProp>
+              <stringProp name="EXPECTED_VALUE">7</stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.files[0].sha1</stringProp>
+              <stringProp name="EXPECTED_VALUE">d9ce7590765717c47c737add2ac11e0665eabbea</stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.files[0].contentType</stringProp>
+              <stringProp name="EXPECTED_VALUE">text/plain</stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.files[0].fieldname</stringProp>
+              <stringProp name="EXPECTED_VALUE">upload</stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.files[0].filename</stringProp>
+              <stringProp name="EXPECTED_VALUE">UploadFileSmall.txt</stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.content.raw</stringProp>
+              <stringProp name="EXPECTED_VALUE">This is a message with multiple parts in MIME format.</stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+          </hashTree>
+        </hashTree>
+        <GenericController guiclass="LogicControllerGui" testclass="GenericController" testname="Post small file (rfc1341)" enabled="true"/>
+        <hashTree>
+          <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true">
+            <collectionProp name="HeaderManager.headers">
+              <elementProp name="" elementType="Header">
+                <stringProp name="Header.name">Content-Type</stringProp>
+                <stringProp name="Header.value">multipart/form-data; boundary=&quot;------------------------e6d533842bd07008&quot;; type=Text/HTML</stringProp>
+              </elementProp>
+            </collectionProp>
+          </HeaderManager>
+          <hashTree/>
+          <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Post small file - test rfc1341 content type " enabled="true">
+            <boolProp name="HTTPSampler.postBodyRaw">true</boolProp>
+            <elementProp name="HTTPsampler.Arguments" elementType="Arguments">
+              <collectionProp name="Arguments.arguments">
+                <elementProp name="" elementType="HTTPArgument">
+                  <boolProp name="HTTPArgument.always_encode">false</boolProp>
+                  <stringProp name="Argument.value">--------------------------e6d533842bd07008&#xd;
+Content-Disposition: form-data; name=&quot;upload&quot;; filename=&quot;UploadFileSmall.txt&quot;&#xd;
+Content-Type: text/plain&#xd;
+&#xd;
+Small&#xd;
+&#xd;
+--------------------------e6d533842bd07008--</stringProp>
+                  <stringProp name="Argument.metadata">=</stringProp>
+                </elementProp>
+              </collectionProp>
+            </elementProp>
+            <stringProp name="HTTPSampler.domain"></stringProp>
+            <stringProp name="HTTPSampler.port"></stringProp>
+            <stringProp name="HTTPSampler.protocol"></stringProp>
+            <stringProp name="HTTPSampler.contentEncoding"></stringProp>
+            <stringProp name="HTTPSampler.path"></stringProp>
+            <stringProp name="HTTPSampler.method">POST</stringProp>
+            <boolProp name="HTTPSampler.follow_redirects">false</boolProp>
+            <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
+            <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+            <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
+            <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
+            <stringProp name="HTTPSampler.connect_timeout"></stringProp>
+            <stringProp name="HTTPSampler.response_timeout"></stringProp>
+          </HTTPSamplerProxy>
+          <hashTree>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.files[0].size</stringProp>
+              <stringProp name="EXPECTED_VALUE">7</stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.files[0].sha1</stringProp>
+              <stringProp name="EXPECTED_VALUE">d9ce7590765717c47c737add2ac11e0665eabbea</stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.files[0].contentType</stringProp>
+              <stringProp name="EXPECTED_VALUE">text/plain</stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.files[0].fieldname</stringProp>
+              <stringProp name="EXPECTED_VALUE">upload</stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.files[0].filename</stringProp>
+              <stringProp name="EXPECTED_VALUE">UploadFileSmall.txt</stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.content.raw</stringProp>
+              <stringProp name="EXPECTED_VALUE"></stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+          </hashTree>
+        </hashTree>
+        <GenericController guiclass="LogicControllerGui" testclass="GenericController" testname="Post other content-type (json)" enabled="true"/>
+        <hashTree>
+          <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true">
+            <collectionProp name="HeaderManager.headers">
+              <elementProp name="" elementType="Header">
+                <stringProp name="Header.name">Content-Type</stringProp>
+                <stringProp name="Header.value">application.json</stringProp>
+              </elementProp>
+            </collectionProp>
+          </HeaderManager>
+          <hashTree/>
+          <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Post other content-type (json)" enabled="true">
+            <boolProp name="HTTPSampler.postBodyRaw">true</boolProp>
+            <elementProp name="HTTPsampler.Arguments" elementType="Arguments">
+              <collectionProp name="Arguments.arguments">
+                <elementProp name="" elementType="HTTPArgument">
+                  <boolProp name="HTTPArgument.always_encode">false</boolProp>
+                  <stringProp name="Argument.value">{ &quot;name&quot;:&quot;some json data&quot;}</stringProp>
+                  <stringProp name="Argument.metadata">=</stringProp>
+                </elementProp>
+              </collectionProp>
+            </elementProp>
+            <stringProp name="HTTPSampler.domain"></stringProp>
+            <stringProp name="HTTPSampler.port"></stringProp>
+            <stringProp name="HTTPSampler.protocol"></stringProp>
+            <stringProp name="HTTPSampler.contentEncoding"></stringProp>
+            <stringProp name="HTTPSampler.path"></stringProp>
+            <stringProp name="HTTPSampler.method">POST</stringProp>
+            <boolProp name="HTTPSampler.follow_redirects">false</boolProp>
+            <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
+            <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+            <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
+            <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
+            <stringProp name="HTTPSampler.connect_timeout"></stringProp>
+            <stringProp name="HTTPSampler.response_timeout"></stringProp>
+          </HTTPSamplerProxy>
+          <hashTree>
+            <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+              <stringProp name="JSON_PATH">$.content.raw</stringProp>
+              <stringProp name="EXPECTED_VALUE">{ &quot;name&quot;:&quot;some json data&quot;}</stringProp>
+              <boolProp name="JSONVALIDATION">true</boolProp>
+              <boolProp name="EXPECT_NULL">false</boolProp>
+              <boolProp name="INVERT">false</boolProp>
+              <boolProp name="ISREGEX">false</boolProp>
+            </JSONPathAssertion>
+            <hashTree/>
+          </hashTree>
+        </hashTree>
+        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Post UploadFile1.txt" enabled="true">
+          <elementProp name="HTTPsampler.Files" elementType="HTTPFileArgs">
+            <collectionProp name="HTTPFileArgs.files">
+              <elementProp name="${files_path}/UploadFile1.txt" elementType="HTTPFileArg">
+                <stringProp name="File.path">${files_path}/UploadFile1.txt</stringProp>
+                <stringProp name="File.paramname">upload</stringProp>
+                <stringProp name="File.mimetype">text/plain</stringProp>
+              </elementProp>
+            </collectionProp>
+          </elementProp>
+          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+            <collectionProp name="Arguments.arguments"/>
+          </elementProp>
+          <stringProp name="HTTPSampler.domain"></stringProp>
+          <stringProp name="HTTPSampler.port"></stringProp>
+          <stringProp name="HTTPSampler.protocol"></stringProp>
+          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
+          <stringProp name="HTTPSampler.path"></stringProp>
+          <stringProp name="HTTPSampler.method">POST</stringProp>
+          <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
+          <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
+          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+          <boolProp name="HTTPSampler.DO_MULTIPART_POST">true</boolProp>
+          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
+          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
+          <stringProp name="HTTPSampler.response_timeout"></stringProp>
+        </HTTPSamplerProxy>
+        <hashTree>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].sha1</stringProp>
+            <stringProp name="EXPECTED_VALUE">3752bdd4053e56cc7a22ccc66b887cae20299171</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].size</stringProp>
+            <stringProp name="EXPECTED_VALUE">860</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].contentType</stringProp>
+            <stringProp name="EXPECTED_VALUE">text/plain</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].filename</stringProp>
+            <stringProp name="EXPECTED_VALUE">UploadFile1.txt</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].fieldname</stringProp>
+            <stringProp name="EXPECTED_VALUE">upload</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+        </hashTree>
+        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Post UploadFile2.txt" enabled="true">
+          <elementProp name="HTTPsampler.Files" elementType="HTTPFileArgs">
+            <collectionProp name="HTTPFileArgs.files">
+              <elementProp name="${files_path}/UploadFile2.txt" elementType="HTTPFileArg">
+                <stringProp name="File.path">${files_path}/UploadFile2.txt</stringProp>
+                <stringProp name="File.paramname">upload</stringProp>
+                <stringProp name="File.mimetype">text/plain</stringProp>
+              </elementProp>
+            </collectionProp>
+          </elementProp>
+          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+            <collectionProp name="Arguments.arguments"/>
+          </elementProp>
+          <stringProp name="HTTPSampler.domain"></stringProp>
+          <stringProp name="HTTPSampler.port"></stringProp>
+          <stringProp name="HTTPSampler.protocol"></stringProp>
+          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
+          <stringProp name="HTTPSampler.path"></stringProp>
+          <stringProp name="HTTPSampler.method">POST</stringProp>
+          <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
+          <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
+          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+          <boolProp name="HTTPSampler.DO_MULTIPART_POST">true</boolProp>
+          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
+          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
+          <stringProp name="HTTPSampler.response_timeout"></stringProp>
+        </HTTPSamplerProxy>
+        <hashTree>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].sha1</stringProp>
+            <stringProp name="EXPECTED_VALUE">7f125c999a6e0f78434d52f6658664e8de40b1c0</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].size</stringProp>
+            <stringProp name="EXPECTED_VALUE">1418</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].contentType</stringProp>
+            <stringProp name="EXPECTED_VALUE">text/plain</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].filename</stringProp>
+            <stringProp name="EXPECTED_VALUE">UploadFile2.txt</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].fieldname</stringProp>
+            <stringProp name="EXPECTED_VALUE">upload</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+        </hashTree>
+        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Post UploadFile3.txt" enabled="true">
+          <elementProp name="HTTPsampler.Files" elementType="HTTPFileArgs">
+            <collectionProp name="HTTPFileArgs.files">
+              <elementProp name="${files_path}/UploadFile3.txt" elementType="HTTPFileArg">
+                <stringProp name="File.path">${files_path}/UploadFile3.txt</stringProp>
+                <stringProp name="File.paramname">upload</stringProp>
+                <stringProp name="File.mimetype">text/plain</stringProp>
+              </elementProp>
+            </collectionProp>
+          </elementProp>
+          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+            <collectionProp name="Arguments.arguments"/>
+          </elementProp>
+          <stringProp name="HTTPSampler.domain"></stringProp>
+          <stringProp name="HTTPSampler.port"></stringProp>
+          <stringProp name="HTTPSampler.protocol"></stringProp>
+          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
+          <stringProp name="HTTPSampler.path"></stringProp>
+          <stringProp name="HTTPSampler.method">POST</stringProp>
+          <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
+          <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
+          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+          <boolProp name="HTTPSampler.DO_MULTIPART_POST">true</boolProp>
+          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
+          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
+          <stringProp name="HTTPSampler.response_timeout"></stringProp>
+        </HTTPSamplerProxy>
+        <hashTree>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].sha1</stringProp>
+            <stringProp name="EXPECTED_VALUE">a074ac7a91209126796b4cae95e31ada7e58b5c0</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].size</stringProp>
+            <stringProp name="EXPECTED_VALUE">77756</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].contentType</stringProp>
+            <stringProp name="EXPECTED_VALUE">text/plain</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].filename</stringProp>
+            <stringProp name="EXPECTED_VALUE">UploadFile3.txt</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].fieldname</stringProp>
+            <stringProp name="EXPECTED_VALUE">upload</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+        </hashTree>
+        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Post UploadFile1.txt multiple times" enabled="true">
+          <elementProp name="HTTPsampler.Files" elementType="HTTPFileArgs">
+            <collectionProp name="HTTPFileArgs.files">
+              <elementProp name="${files_path}/UploadFile1.txt" elementType="HTTPFileArg">
+                <stringProp name="File.path">${files_path}/UploadFile1.txt</stringProp>
+                <stringProp name="File.paramname">upload1</stringProp>
+                <stringProp name="File.mimetype">text/plain</stringProp>
+              </elementProp>
+              <elementProp name="${files_path}/UploadFile1.txt" elementType="HTTPFileArg">
+                <stringProp name="File.path">${files_path}/UploadFile1.txt</stringProp>
+                <stringProp name="File.paramname">upload2</stringProp>
+                <stringProp name="File.mimetype">text/plain</stringProp>
+              </elementProp>
+              <elementProp name="${files_path}/UploadFile1.txt" elementType="HTTPFileArg">
+                <stringProp name="File.path">${files_path}/UploadFile1.txt</stringProp>
+                <stringProp name="File.paramname">upload3</stringProp>
+                <stringProp name="File.mimetype">text/plain</stringProp>
+              </elementProp>
+              <elementProp name="${files_path}/UploadFile1.txt" elementType="HTTPFileArg">
+                <stringProp name="File.path">${files_path}/UploadFile1.txt</stringProp>
+                <stringProp name="File.paramname">upload4</stringProp>
+                <stringProp name="File.mimetype">text/plain</stringProp>
+              </elementProp>
+            </collectionProp>
+          </elementProp>
+          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+            <collectionProp name="Arguments.arguments"/>
+          </elementProp>
+          <stringProp name="HTTPSampler.domain"></stringProp>
+          <stringProp name="HTTPSampler.port"></stringProp>
+          <stringProp name="HTTPSampler.protocol"></stringProp>
+          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
+          <stringProp name="HTTPSampler.path"></stringProp>
+          <stringProp name="HTTPSampler.method">POST</stringProp>
+          <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
+          <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
+          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+          <boolProp name="HTTPSampler.DO_MULTIPART_POST">true</boolProp>
+          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
+          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
+          <stringProp name="HTTPSampler.response_timeout"></stringProp>
+        </HTTPSamplerProxy>
+        <hashTree>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].sha1</stringProp>
+            <stringProp name="EXPECTED_VALUE">3752bdd4053e56cc7a22ccc66b887cae20299171</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[2].sha1</stringProp>
+            <stringProp name="EXPECTED_VALUE">3752bdd4053e56cc7a22ccc66b887cae20299171</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[3].sha1</stringProp>
+            <stringProp name="EXPECTED_VALUE">3752bdd4053e56cc7a22ccc66b887cae20299171</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[1].sha1</stringProp>
+            <stringProp name="EXPECTED_VALUE">3752bdd4053e56cc7a22ccc66b887cae20299171</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[3].size</stringProp>
+            <stringProp name="EXPECTED_VALUE">860</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].size</stringProp>
+            <stringProp name="EXPECTED_VALUE">860</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].contentType</stringProp>
+            <stringProp name="EXPECTED_VALUE">text/plain</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].filename</stringProp>
+            <stringProp name="EXPECTED_VALUE">UploadFile1.txt</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[3].fieldname</stringProp>
+            <stringProp name="EXPECTED_VALUE">upload1</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+        </hashTree>
+        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Post UploadFile1.txt in combination with field" enabled="true">
+          <elementProp name="HTTPsampler.Files" elementType="HTTPFileArgs">
+            <collectionProp name="HTTPFileArgs.files">
+              <elementProp name="${files_path}/UploadFile1.txt" elementType="HTTPFileArg">
+                <stringProp name="File.path">${files_path}/UploadFile1.txt</stringProp>
+                <stringProp name="File.paramname">upload</stringProp>
+                <stringProp name="File.mimetype">text/plain</stringProp>
+              </elementProp>
+            </collectionProp>
+          </elementProp>
+          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+            <collectionProp name="Arguments.arguments">
+              <elementProp name="Param1" elementType="HTTPArgument">
+                <boolProp name="HTTPArgument.always_encode">false</boolProp>
+                <stringProp name="Argument.value">Value1</stringProp>
+                <stringProp name="Argument.metadata">=</stringProp>
+                <boolProp name="HTTPArgument.use_equals">true</boolProp>
+                <stringProp name="Argument.name">Param1</stringProp>
+              </elementProp>
+            </collectionProp>
+          </elementProp>
+          <stringProp name="HTTPSampler.domain"></stringProp>
+          <stringProp name="HTTPSampler.port"></stringProp>
+          <stringProp name="HTTPSampler.protocol"></stringProp>
+          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
+          <stringProp name="HTTPSampler.path"></stringProp>
+          <stringProp name="HTTPSampler.method">POST</stringProp>
+          <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
+          <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
+          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+          <boolProp name="HTTPSampler.DO_MULTIPART_POST">true</boolProp>
+          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
+          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
+          <stringProp name="HTTPSampler.response_timeout"></stringProp>
+        </HTTPSamplerProxy>
+        <hashTree>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].sha1</stringProp>
+            <stringProp name="EXPECTED_VALUE">3752bdd4053e56cc7a22ccc66b887cae20299171</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].size</stringProp>
+            <stringProp name="EXPECTED_VALUE">860</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].contentType</stringProp>
+            <stringProp name="EXPECTED_VALUE">text/plain</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].filename</stringProp>
+            <stringProp name="EXPECTED_VALUE">UploadFile1.txt</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.files[0].fieldname</stringProp>
+            <stringProp name="EXPECTED_VALUE">upload</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.content.fields[1].name</stringProp>
+            <stringProp name="EXPECTED_VALUE">Param1</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.content.fields[1].value</stringProp>
+            <stringProp name="EXPECTED_VALUE">Value1</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+        </hashTree>
+        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Post urlencoded" enabled="true">
+          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+            <collectionProp name="Arguments.arguments">
+              <elementProp name="Param1" elementType="HTTPArgument">
+                <boolProp name="HTTPArgument.always_encode">true</boolProp>
+                <stringProp name="Argument.value">Value1</stringProp>
+                <stringProp name="Argument.metadata">=</stringProp>
+                <boolProp name="HTTPArgument.use_equals">true</boolProp>
+                <stringProp name="Argument.name">Param1</stringProp>
+              </elementProp>
+            </collectionProp>
+          </elementProp>
+          <stringProp name="HTTPSampler.domain"></stringProp>
+          <stringProp name="HTTPSampler.port"></stringProp>
+          <stringProp name="HTTPSampler.protocol"></stringProp>
+          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
+          <stringProp name="HTTPSampler.path"></stringProp>
+          <stringProp name="HTTPSampler.method">POST</stringProp>
+          <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
+          <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
+          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+          <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
+          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
+          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
+          <stringProp name="HTTPSampler.response_timeout"></stringProp>
+        </HTTPSamplerProxy>
+        <hashTree>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.content.fields[0].name</stringProp>
+            <stringProp name="EXPECTED_VALUE">Param1</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.content.fields[0].value</stringProp>
+            <stringProp name="EXPECTED_VALUE">Value1</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.content.raw</stringProp>
+            <stringProp name="EXPECTED_VALUE"></stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+        </hashTree>
+      </hashTree>
+      <PostThreadGroup guiclass="PostThreadGroupGui" testclass="PostThreadGroup" testname="tearDown Thread Group" enabled="true">
+        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
+        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
+          <boolProp name="LoopController.continue_forever">false</boolProp>
+          <stringProp name="LoopController.loops">1</stringProp>
+        </elementProp>
+        <stringProp name="ThreadGroup.num_threads">1</stringProp>
+        <stringProp name="ThreadGroup.ramp_time">1</stringProp>
+        <boolProp name="ThreadGroup.scheduler">false</boolProp>
+        <stringProp name="ThreadGroup.duration"></stringProp>
+        <stringProp name="ThreadGroup.delay"></stringProp>
+        <boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
+      </PostThreadGroup>
+      <hashTree>
+        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Request shutdown (check for memory leaks manually)" enabled="true">
+          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+            <collectionProp name="Arguments.arguments">
+              <elementProp name="shutdown" elementType="HTTPArgument">
+                <boolProp name="HTTPArgument.always_encode">true</boolProp>
+                <stringProp name="Argument.value">true</stringProp>
+                <stringProp name="Argument.metadata">=</stringProp>
+                <boolProp name="HTTPArgument.use_equals">true</boolProp>
+                <stringProp name="Argument.name">shutdown</stringProp>
+              </elementProp>
+            </collectionProp>
+          </elementProp>
+          <stringProp name="HTTPSampler.domain"></stringProp>
+          <stringProp name="HTTPSampler.port"></stringProp>
+          <stringProp name="HTTPSampler.protocol"></stringProp>
+          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
+          <stringProp name="HTTPSampler.path"></stringProp>
+          <stringProp name="HTTPSampler.method">GET</stringProp>
+          <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
+          <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
+          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+          <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
+          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
+          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
+          <stringProp name="HTTPSampler.response_timeout"></stringProp>
+        </HTTPSamplerProxy>
+        <hashTree>
+          <JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
+            <stringProp name="JSON_PATH">$.shutdown</stringProp>
+            <stringProp name="EXPECTED_VALUE">true</stringProp>
+            <boolProp name="JSONVALIDATION">true</boolProp>
+            <boolProp name="EXPECT_NULL">false</boolProp>
+            <boolProp name="INVERT">false</boolProp>
+            <boolProp name="ISREGEX">false</boolProp>
+          </JSONPathAssertion>
+          <hashTree/>
+        </hashTree>
+      </hashTree>
+      <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="true">
+        <boolProp name="ResultCollector.error_logging">false</boolProp>
+        <objProp>
+          <name>saveConfig</name>
+          <value class="SampleSaveConfiguration">
+            <time>true</time>
+            <latency>true</latency>
+            <timestamp>true</timestamp>
+            <success>true</success>
+            <label>true</label>
+            <code>true</code>
+            <message>true</message>
+            <threadName>true</threadName>
+            <dataType>true</dataType>
+            <encoding>false</encoding>
+            <assertions>true</assertions>
+            <subresults>true</subresults>
+            <responseData>false</responseData>
+            <samplerData>false</samplerData>
+            <xml>false</xml>
+            <fieldNames>true</fieldNames>
+            <responseHeaders>false</responseHeaders>
+            <requestHeaders>false</requestHeaders>
+            <responseDataOnError>false</responseDataOnError>
+            <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
+            <assertionsResultsToSave>0</assertionsResultsToSave>
+            <bytes>true</bytes>
+            <sentBytes>true</sentBytes>
+            <url>true</url>
+            <threadCounts>true</threadCounts>
+            <idleTime>true</idleTime>
+            <connectTime>true</connectTime>
+          </value>
+        </objProp>
+        <stringProp name="filename"></stringProp>
+      </ResultCollector>
+      <hashTree/>
+      <ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="true">
+        <boolProp name="ResultCollector.error_logging">false</boolProp>
+        <objProp>
+          <name>saveConfig</name>
+          <value class="SampleSaveConfiguration">
+            <time>true</time>
+            <latency>true</latency>
+            <timestamp>true</timestamp>
+            <success>true</success>
+            <label>true</label>
+            <code>true</code>
+            <message>true</message>
+            <threadName>true</threadName>
+            <dataType>true</dataType>
+            <encoding>false</encoding>
+            <assertions>true</assertions>
+            <subresults>true</subresults>
+            <responseData>false</responseData>
+            <samplerData>false</samplerData>
+            <xml>false</xml>
+            <fieldNames>true</fieldNames>
+            <responseHeaders>false</responseHeaders>
+            <requestHeaders>false</requestHeaders>
+            <responseDataOnError>false</responseDataOnError>
+            <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
+            <assertionsResultsToSave>0</assertionsResultsToSave>
+            <bytes>true</bytes>
+            <sentBytes>true</sentBytes>
+            <url>true</url>
+            <threadCounts>true</threadCounts>
+            <idleTime>true</idleTime>
+            <connectTime>true</connectTime>
+          </value>
+        </objProp>
+        <stringProp name="filename"></stringProp>
+      </ResultCollector>
+      <hashTree/>
+    </hashTree>
+  </hashTree>
+</jmeterTestPlan>

+ 32 - 7
packages/pastojs/src/fppas2js.pp

@@ -1660,7 +1660,7 @@ type
       RaiseOnIncompatible: boolean): integer; override;
     // utility
     procedure RaiseMsg(const Id: TMaxPrecInt; MsgNumber: integer; const Fmt: String;
-      Args: array of {$IFDEF pas2js}jsvalue{$ELSE}const{$ENDIF}; ErrorPosEl: TPasElement); override;
+      Args: array of const; ErrorPosEl: TPasElement); override;
     function GetOverloadName(El: TPasElement): string;
     function GetBaseDescription(const R: TPasResolverResult; AddPath: boolean=
       false): string; override;
@@ -1961,9 +1961,9 @@ type
     // Error functions
     Procedure DoError(Id: TMaxPrecInt; Const Msg : String);
     Procedure DoError(Id: TMaxPrecInt; Const Msg : String;
-      const Args: array of {$IFDEF pas2js}jsvalue{$ELSE}const{$ENDIF});
+      const Args: array of const);
     Procedure DoError(Id: TMaxPrecInt; MsgNumber: integer; const MsgPattern: string;
-      const Args: array of {$IFDEF pas2js}jsvalue{$ELSE}const{$ENDIF}; El: TPasElement);
+      const Args: array of const; El: TPasElement);
     procedure RaiseNotSupported(El: TPasElement; AContext: TConvertContext; Id: TMaxPrecInt; const Msg: string = '');
     procedure RaiseIdentifierNotFound(Identifier: string; El: TPasElement; Id: TMaxPrecInt);
     procedure RaiseInconsistency(Id: TMaxPrecInt; El: TPasElement);
@@ -2039,6 +2039,7 @@ type
     Function CreateVarDecl(const aName: String; Init: TJSElement; El: TPasElement): TJSVarDeclaration; virtual;
     // JS literals
     Function CreateLiteralNumber(El: TPasElement; const n: TJSNumber): TJSLiteral; virtual;
+    Function CreateLiteralFloat(El: TPasElement; const n: TJSNumber): TJSElement; virtual;
     Function CreateLiteralHexNumber(El: TPasElement; const n: TMaxPrecInt; Digits: byte): TJSLiteral; virtual;
     Function CreateLiteralString(El: TPasElement; const s: string): TJSLiteral; virtual;
     Function CreateLiteralJSString(El: TPasElement; const s: TJSString): TJSLiteral; virtual;
@@ -7163,7 +7164,7 @@ begin
 end;
 
 procedure TPas2JSResolver.RaiseMsg(const Id: TMaxPrecInt; MsgNumber: integer;
-  const Fmt: String; Args: array of {$IFDEF pas2js}jsvalue{$ELSE}const{$ENDIF};
+  const Fmt: String; Args: array of const;
   ErrorPosEl: TPasElement);
 begin
   {$IFDEF VerbosePas2JS}
@@ -17705,7 +17706,7 @@ begin
   revkUInt:
     Result:=CreateLiteralNumber(El,TResEvalUInt(Value).UInt);
   revkFloat:
-    Result:=CreateLiteralNumber(El,TResEvalFloat(Value).FloatValue);
+    Result:=CreateLiteralFloat(El,TResEvalFloat(Value).FloatValue);
   {$IFDEF FPC_HAS_CPSTRING}
   revkString:
     Result:=CreateLiteralString(El,TResEvalString(Value).S);
@@ -24258,6 +24259,30 @@ begin
   Result.Value.AsNumber:=n;
 end;
 
+function TPasToJSConverter.CreateLiteralFloat(El: TPasElement;
+  const n: TJSNumber): TJSElement;
+var
+  DivExpr: TJSMultiplicativeExpressionDiv;
+  Lit: TJSLiteral;
+begin
+  if IsInfinite(n) then
+    begin
+    DivExpr:=TJSMultiplicativeExpressionDiv(CreateElement(TJSMultiplicativeExpressionDiv,El));
+    if n<0 then
+      DivExpr.A:=CreateLiteralNumber(El,-1)
+    else
+      DivExpr.A:=CreateLiteralNumber(El,1);
+    DivExpr.B:=CreateLiteralNumber(El,0);
+    Result:=DivExpr;
+    end
+  else
+    begin
+    Lit:=TJSLiteral(CreateElement(TJSLiteral,El));
+    Lit.Value.AsNumber:=n;
+    Result:=Lit;
+    end;
+end;
+
 function TPasToJSConverter.CreateLiteralHexNumber(El: TPasElement;
   const n: TMaxPrecInt; Digits: byte): TJSLiteral;
 begin
@@ -26779,7 +26804,7 @@ begin
 end;
 
 procedure TPasToJSConverter.DoError(Id: TMaxPrecInt; const Msg: String;
-  const Args: array of {$IFDEF pas2js}jsvalue{$ELSE}const{$ENDIF});
+  const Args: array of const);
 var
   E: EPas2JS;
 begin
@@ -26791,7 +26816,7 @@ end;
 
 procedure TPasToJSConverter.DoError(Id: TMaxPrecInt; MsgNumber: integer;
   const MsgPattern: string;
-  const Args: array of {$IFDEF pas2js}jsvalue{$ELSE}const{$ENDIF};
+  const Args: array of const;
   El: TPasElement);
 var
   E: EPas2JS;

+ 3 - 3
packages/pastojs/src/pas2jscompiler.pp

@@ -459,7 +459,7 @@ type
   Protected
     procedure CfgSyntaxError(const Msg: string);
     function ConditionEvalVariable(Sender: TCondDirectiveEvaluator; aName: String; out Value: string): boolean;
-    procedure ConditionEvalLog(Sender: TCondDirectiveEvaluator;  Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
+    procedure ConditionEvalLog(Sender: TCondDirectiveEvaluator;  Args: array of const);
     property ConditionEvaluator: TCondDirectiveEvaluator read FConditionEval;
     property CurrentCfgFilename: string read FCurrentCfgFilename;
     property CurrentCfgLineNumber: integer read FCurrentCfgLineNumber;
@@ -1946,7 +1946,7 @@ begin
 end;
 
 procedure TPas2JSConfigSupport.ConditionEvalLog(Sender: TCondDirectiveEvaluator;
-  Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
+  Args: array of const);
 begin
   CfgSyntaxError(SafeFormat(Sender.MsgPattern,Args));
 end;
@@ -2139,7 +2139,7 @@ function TPas2jsCompiler.MarkNeedBuilding(aFile: TPas2jsCompilerFile;
   Checked: TPasAnalyzerKeySet; var SrcFileCount: integer): boolean;
 
   procedure Mark(MsgNumber: integer;
-    Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
+    Args: array of const);
   begin
     if aFile.NeedBuild then exit;
     aFile.NeedBuild:=true;

+ 12 - 12
packages/pastojs/src/pas2jslogger.pp

@@ -162,23 +162,23 @@ type
     function FindMsg(MsgNumber: integer; ExceptionOnNotFound: boolean): TPas2jsMessage;
     procedure Sort;
     procedure LogRaw(const Msg: string); overload;
-    procedure LogRaw(Args: array of {$IFDEF Pas2JS}jsvalue{$ELSE}const{$ENDIF}); overload;
+    procedure LogRaw(Args: array of const); overload;
     procedure LogLn;
     procedure LogPlain(const Msg: string); overload;
-    procedure LogPlain(Args: array of {$IFDEF Pas2JS}jsvalue{$ELSE}const{$ENDIF}); overload;
+    procedure LogPlain(Args: array of const); overload;
     procedure LogMsg(MsgNumber: integer;
-      Args: array of {$IFDEF Pas2JS}jsvalue{$ELSE}const{$ENDIF};
+      Args: array of const;
       const Filename: string = ''; Line: integer = 0; Col: integer = 0;
       UseFilter: boolean = true);
     procedure Log(MsgType: TMessageType; Msg: string; MsgNumber: integer = 0;
       const Filename: string = ''; Line: integer = 0; Col: integer = 0;
       UseFilter: boolean = true);
     procedure LogMsgIgnoreFilter(MsgNumber: integer;
-      Args: array of {$IFDEF Pas2JS}jsvalue{$ELSE}const{$ENDIF});
+      Args: array of const);
     procedure LogExceptionBackTrace(E: Exception);
     function MsgTypeToStr(MsgType: TMessageType): string;
     function GetMsgText(MsgNumber: integer;
-      Args: array of {$IFDEF Pas2JS}jsvalue{$ELSE}const{$ENDIF}): string;
+      Args: array of const): string;
     function FormatMsg(MsgType: TMessageType; Msg: string; MsgNumber: integer = 0;
       const Filename: string = ''; Line: integer = 0; Col: integer = 0): string;
     function FormatJSONMsg(MsgType: TMessageType; Msg: string; MsgNumber: integer = 0;
@@ -192,7 +192,7 @@ type
     procedure CloseDebugLog;
     procedure DebugLogWriteLn(Msg: string); overload;
     function GetEncodingCaption: string;
-    class function Concatenate(Args: array of {$IFDEF Pas2JS}jsvalue{$ELSE}const{$ENDIF}): string;
+    class function Concatenate(Args: array of const): string;
   public
     property Encoding: string read FEncoding write SetEncoding; // normalized
     property MsgCount: integer read GetMsgCount;
@@ -810,7 +810,7 @@ begin
 end;
 
 function TPas2jsLogger.GetMsgText(MsgNumber: integer;
-  Args: array of {$IFDEF Pas2JS}jsvalue{$ELSE}const{$ENDIF}): string;
+  Args: array of const): string;
 var
   Msg: TPas2jsMessage;
 begin
@@ -825,7 +825,7 @@ begin
 end;
 
 procedure TPas2jsLogger.LogRaw(
-  Args: array of {$IFDEF Pas2JS}jsvalue{$ELSE}const{$ENDIF});
+  Args: array of const);
 begin
   LogRaw(Concatenate(Args));
 end;
@@ -870,7 +870,7 @@ begin
 end;
 
 class function TPas2jsLogger.Concatenate(
-  Args: array of {$IFDEF Pas2JS}jsvalue{$ELSE}const{$ENDIF}): string;
+  Args: array of const): string;
 var
   s: String;
   i: Integer;
@@ -940,13 +940,13 @@ begin
 end;
 
 procedure TPas2jsLogger.LogPlain(
-  Args: array of {$IFDEF Pas2JS}jsvalue{$ELSE}const{$ENDIF});
+  Args: array of const);
 begin
   LogPlain(Concatenate(Args));
 end;
 
 procedure TPas2jsLogger.LogMsg(MsgNumber: integer;
-  Args: array of {$IFDEF Pas2JS}jsvalue{$ELSE}const{$ENDIF};
+  Args: array of const;
   const Filename: string; Line: integer; Col: integer; UseFilter: boolean);
 var
   Msg: TPas2jsMessage;
@@ -977,7 +977,7 @@ begin
 end;
 
 procedure TPas2jsLogger.LogMsgIgnoreFilter(MsgNumber: integer;
-  Args: array of {$IFDEF Pas2JS}jsvalue{$ELSE}const{$ENDIF});
+  Args: array of const);
 begin
   LogMsg(MsgNumber,Args,'',0,0,false);
 end;

+ 2 - 2
packages/pastojs/src/pas2jspparser.pp

@@ -43,7 +43,7 @@ type
     constructor Create(AScanner: TPascalScanner;
       AFileResolver: TBaseFileResolver; AEngine: TPasTreeContainer); reintroduce;
     procedure RaiseParserError(MsgNumber: integer;
-      Args: array of {$IFDEF Pas2JS}jsvalue{$ELSE}const{$ENDIF});
+      Args: array of const);
     procedure ParseSubModule(var Module: TPasModule);
     property Log: TPas2jsLogger read FLog write FLog;
   end;
@@ -116,7 +116,7 @@ begin
 end;
 
 procedure TPas2jsPasParser.RaiseParserError(MsgNumber: integer;
-  Args: array of {$IFDEF Pas2JS}jsvalue{$ELSE}const{$ENDIF});
+  Args: array of const);
 var
   Msg: TPas2jsMessage;
 begin

+ 29 - 2
packages/pastojs/tests/tcmodules.pas

@@ -7125,11 +7125,15 @@ begin
   '  Test999 = 2.9999999999999;',
   '  Test111999 = 211199999999999000.0;',
   '  TestMinus111999 = -211199999999999000.0;',
+  '  Inf = 1.0 / 0.0;',
+  '  NegInf = -1.0 / 0.0;',
+  'procedure Run(d: double); external name ''Run'';',
   'var',
   '  d: double = b;',
   'begin',
   '  d:=1.0;',
   '  d:=1.0/3.0;',
+  '  d:=1.0/(3-2-1);',
   '  d:=1/3;',
   '  d:=5.0E-324;',
   '  d:=1.7E308;',
@@ -7162,6 +7166,8 @@ begin
   '  d:=double(MinSafeIntDouble2);',
   '  d:=MaxSafeIntDouble;',
   '  d:=default(double);',
+  '  Run(Inf);',
+  '  Run(NegInf);',
   '']);
   ConvertProgram;
   CheckSource('TestDouble',
@@ -7195,11 +7201,14 @@ begin
     'this.Test999 = 2.9999999999999;',
     'this.Test111999 = 211199999999999000.0;',
     'this.TestMinus111999 = -211199999999999000.0;',
-    'this.d = 4.4;'
-    ]),
+    'this.Inf = 1.0 / 0.0;',
+    'this.NegInf = -1.0 / 0.0;',
+    'this.d = 4.4;',
+    '']),
     LinesToStr([
     '$mod.d = 1.0;',
     '$mod.d = 1.0 / 3.0;',
+    '$mod.d = 1.0 / (3 - 2 - 1);',
     '$mod.d = 1 / 3;',
     '$mod.d = 5.0E-324;',
     '$mod.d = 1.7E308;',
@@ -7232,6 +7241,8 @@ begin
     '$mod.d = -9.007199254740992E15;',
     '$mod.d = 9007199254740991;',
     '$mod.d = 0.0;',
+    'Run(1 / 0);',
+    'Run(-1 / 0);',
     '']));
 end;
 
@@ -18003,11 +18014,20 @@ begin
   '{$modeswitch externalclass}',
   'type',
   '  TExtA = class external name ''ExtA''',
+  '  public type',
+  '    TExtB = class external name ''ExtB''',
+  '    public type',
+  '      TExtC = class external name ''ExtC''',
+  '        constructor New;',
+  '        constructor New(i: word);',
+  '      end;',
+  '    end;',
   '    constructor Create;',
   '    constructor Create(i: longint; j: longint = 2);',
   '  end;',
   'var',
   '  A: texta;',
+  '  C: texta.textb.textc;',
   'begin',
   '  a:=texta.create;',
   '  a:=texta(texta.create);',
@@ -18021,11 +18041,15 @@ begin
   '  a:=test1.texta.create;',
   '  a:=test1.texta.create();',
   '  a:=test1.texta.create(3);',
+  '  c:=texta.textb.textc.new;',
+  '  c:=texta.textb.textc.new();',
+  '  c:=texta.textb.textc.new(4);',
   '']);
   ConvertProgram;
   CheckSource('TestExternalClass_Constructor',
     LinesToStr([ // statements
     'this.A = null;',
+    'this.C = null;',
     '']),
     LinesToStr([ // $mod.$main
     '$mod.A = new ExtA.Create();',
@@ -18038,6 +18062,9 @@ begin
     '$mod.A = new ExtA.Create();',
     '$mod.A = new ExtA.Create();',
     '$mod.A = new ExtA.Create(3,2);',
+    '$mod.C = new ExtA.ExtB.ExtC();',
+    '$mod.C = new ExtA.ExtB.ExtC();',
+    '$mod.C = new ExtA.ExtB.ExtC(4);',
     '']));
 end;
 

+ 2 - 0
packages/qlunits/README.txt

@@ -11,3 +11,5 @@ The following units are available:
 The following examples are available:
 
     qlcube - draws a 3D rotating wireframe cube with QDOS drawing functions
+    mtinf - example of using the QDOS version of the System Variables
+    sms_info - example of using the SMSQ version of the System Variables

+ 11 - 16
packages/qlunits/examples/mtinf.pas

@@ -1,7 +1,7 @@
 {
-    Copyright (c) 2021 Karoly Balogh
+    Copyright (c) 2021 Karoly Balogh and Norman Dunbar
 
-    System info/System variables access on a Sinclair QL
+    System info/System variables access on a Sinclair QL, QDOS naming
     Example program for Free Pascal's Sinclair QL support
 
     This example program is in the Public Domain under the terms of
@@ -20,20 +20,15 @@ type
 var
   job_id: longint;
   ver_ascii: longint;
-  system_vars: pbyte;
+  system_vars: pSystemVariables;
 
 function get_id_str(const id: dword): string;
-const
-  QDOS = $D2540000;
-  SMS = $53324154; { S2AT }
-  SMSQ = $534D5351; { SMSQ }
-  ARGOS_THOR = $DC010000;
 begin
   case id of
-    QDOS: get_id_str:='QDOS';
-    SMS: get_id_str:='SMS';
-    SMSQ: get_id_str:='SMSQ';
-    ARGOS_THOR: get_id_str:='Thor (ARGOS)';
+    SYSID_QL: get_id_str:='QDOS';
+    SYSID_AT: get_id_str:='Atari (SMS)';
+    SYSID_SQ: get_id_str:='SMSQ';
+    SYSID_TH: get_id_str:='Thor (ARGOS)';
   else
     get_id_str:='unknown ($'+hexstr(id,8)+')';
   end;
@@ -43,11 +38,11 @@ begin
   job_id:=mt_inf(@system_vars,@ver_ascii);
 
   writeln('Job ID:',lo(job_id),' Tag:',hi(job_id));
-  writeln('Identification: ',get_id_str(pdword(@system_vars[SV_IDENT])^));
+  writeln('Identification: ',get_id_str(system_vars^.SV_IDENT));
   writeln('Version: ',Tver(ver_ascii));
 
   writeln('System vars are at: $',hexstr(system_vars));
-  writeln('Processor type: 680',hexstr(system_vars[SV_PTYP],2));
-  writeln('Monitor mode: ',system_vars[SV_TVMOD]);
-  writeln('Random number: ',pword(@system_vars[SV_RAND])^);
+  writeln('Processor type: 680',hexstr(system_vars^.SV_PTYP,2));
+  writeln('Monitor mode: ',system_vars^.SV_TVMOD);
+  writeln('Random number: ',system_vars^.SV_RAND);
 end.

+ 49 - 0
packages/qlunits/examples/sms_info.pas

@@ -0,0 +1,49 @@
+{
+    Copyright (c) 2021 Karoly Balogh and Norman Dunbar
+
+    System info/System variables access on a Sinclair QL, SMS naming
+    Example program for Free Pascal's Sinclair QL support
+
+    This example program is in the Public Domain under the terms of
+    Unlicense: http://unlicense.org/
+
+ **********************************************************************}
+
+program sms_info;
+
+uses
+  sms;
+
+type
+  Tver = array[0..3] of char;
+
+var
+  job_id: longint;
+  ver_ascii: longint;
+  system_vars: pSystemVariables;
+
+function get_id_str(const id: dword): string;
+begin
+  case id of
+    SYSID_QL: get_id_str:='QDOS';
+    SYSID_AT: get_id_str:='Atari (SMS)';
+    SYSID_SQ: get_id_str:='SMSQ';
+    SYSID_TH: get_id_str:='Thor (ARGOS)';
+  else
+    get_id_str:='unknown ($'+hexstr(id,8)+')';
+  end;
+end;
+
+begin
+  job_id:=sms_info(@system_vars,@ver_ascii);
+
+  writeln('Job ID:',lo(job_id),' Tag:',hi(job_id));
+  writeln('Identification: ',get_id_str(system_vars^.SYS_IDNT));
+  writeln('Version: ',Tver(ver_ascii));
+
+  writeln('System vars are at: $',hexstr(system_vars));
+  writeln('Processor type: 680',hexstr(system_vars^.SYS_PTYP,2));
+  writeln('Monitor mode: ',system_vars^.SYS_TMOD);
+  writeln('Random number: ',system_vars^.SYS_RAND);
+  writeln('Real Time Clock: ',system_vars^.SYS_RTC);
+end.

+ 5 - 0
packages/qlunits/fpmake.pp

@@ -37,6 +37,11 @@ begin
     P.ExamplePath.Add('examples');
     T:=P.Targets.AddExampleProgram('qlcube.pas');
     T:=P.Targets.AddExampleProgram('mtinf.pas');
+    T:=P.Targets.AddExampleProgram('sms_info.pas');
+
+    P.ExamplePath.Add('tests');
+    T:=P.Targets.AddExampleProgram('tsysvars.pas');
+    T:=P.Targets.AddExampleProgram('trecsize.pas');
 
 {$ifndef ALLPACKAGES}
     Run;

+ 181 - 0
packages/qlunits/src/qdos.pas

@@ -12,6 +12,7 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
  **********************************************************************}
+{$PACKRECORDS 2}
 
 unit qdos;
 
@@ -22,7 +23,14 @@ type
   Tchanid = longint;
   Tjobid = longint;
   Ttimeout = smallint;
+  Tcolour = byte;
 
+type
+  Pqlstr = ^Tqlstr;
+  Tqlstr = record
+    qs_strlen: word;
+    qs_str: array[0..0] of char;
+  end;
 
 const
   ERR_NC = -1;   { Operation not complete }
@@ -142,6 +150,179 @@ type
   end;
   PWindowDef = ^TWindowDef;
 
+type
+  Pqdos_queue = ^Tqdos_queue;
+  Tqdos_queue = record
+    q_nextq: Pqdos_queue;
+    q_end: pchar;
+    q_nextin: pchar;
+    q_nxtout: pchar;
+    q_queue: array[0..1] of char;
+  end;
+
+const
+  QDOSQUEUE_SIZE = $12;
+
+type
+  Tchan_defb = record
+    ch_len: dword;
+    ch_drivr: pbyte;
+    ch_owner: Tjobid;
+    ch_rflag: pbyte;
+    ch_tag: word;
+    ch_stat: byte;
+    ch_actn: byte;
+    ch_jobwt: Tjobid;
+  end;
+
+const
+  CHAN_DEFBSIZE = $18;
+
+type
+  Pser_cdefb = ^Tser_cdefb;
+  Tser_cdefb = record
+    ser_cdef: Tchan_defb;
+    ser_chnq: word;
+    ser_par: word;
+    ser_thsx: word;
+    ser_prot: word;
+    ser_rxq: Tqdos_queue;
+    ser_dum1: array[0..79] of byte;
+    ser_txq: Tqdos_queue;
+    ser_dum2: array[0..79] of byte;
+  end;
+
+const
+  SER_CDEFBSIZE = $E4;
+
+type
+  Tnet_cdefb = record
+    net_cdef: Tchan_defb;
+    net_hedr: byte;
+    net_self: byte;
+    net_blkl: byte;
+    net_blkh: byte;
+    net_type: byte;
+    net_nbyt: byte;
+    net_dchk: byte;
+    net_hchk: byte;
+    net_data: array[0..254] of byte;
+    net_rpnt: byte;
+  end;
+
+const
+  NET_CDEFBSIZE = $120;
+
+type
+  Tpipe_cdefb = record
+    ch_cdef: Tchan_defb;
+    ch_qin: Pqdos_queue;
+    ch_qout: Pqdos_queue;
+  end;
+
+const
+  PIPE_CDEFBSIZE = $20;
+
+type
+  Tscrn_info = record
+    sd_xmin: word;
+    sd_ymin: word;
+    sd_xsize: word;
+    sd_ysize: word;
+    sd_borwd: word;
+    sd_xpos: word;
+    sd_ypos: word;
+    sd_xinc: word;
+    sd_yinc: word;
+    sd_font: array[0..1] of pointer;
+    sd_scrb: pointer;
+    sd_pmask: dword;
+    sd_smask: dword;
+    sd_imask: dword;
+    sd_cattr: byte;
+    sd_curf: byte;
+    sd_pcolr: Tcolour;
+    sd_scolr: Tcolour;
+    sd_icolr: Tcolour;
+    sd_bcolr: Tcolour;
+    sd_nlsta: byte;
+    sd_fmod: byte;
+    sd_xorg: Tqlfloat;
+    sd_yorg: Tqlfloat;
+    sd_scal: Tqlfloat;
+    sd_fbuf: pointer;
+    sd_fuse: pointer;
+    sd_linel: word;
+  end;
+
+const
+  SCRN_INFOSIZE = $4E;
+
+type
+  Pscr_cdefb = ^Tscr_cdefb;
+  Tscr_cdefb = record
+    scr_cdef: Tchan_defb;
+    scr_info: Tscrn_info;
+  end;
+
+const
+  SCR_CDEFBSIZE = CHAN_DEFBSIZE + SCRN_INFOSIZE;
+
+const
+  CA_UNDERLINE = $1;
+  CA_FLASH = $2;
+  CA_TRANS = $4;
+  CA_XOR = $8;
+  CA_DOUBLE_HEIGHT = $10;
+  CA_EXT_WIDTH = $20;
+  CA_DBLE_WIDTH = $40;
+  CA_GRAF_POS_CHAR = $80;
+
+type
+  Tcon_union1 = record
+    sdu_linel: longint;
+    sdu_kbd: Tqdos_queue;
+  end;
+
+  Pcon_cdefb = ^Tcon_cdefb;
+  Tcon_cdefb = record
+    con_cdef: Tchan_defb;
+    con_info: Tscrn_info;
+    case boolean of
+      false:  ( sd_js: Tcon_union1 );
+      true:   ( sd_jm: Tqdos_queue );
+  end;
+
+const
+  CON_CDEFBSIZE = SCR_CDEFBSIZE + QDOSQUEUE_SIZE + 4;
+
+type
+  Pfs_cdefb = ^Tfs_cdefb;
+  Tfs_cdefb = record
+    fs_cdef: Tchan_defb;
+    fs_next: Pfs_cdefb;
+    fs_access: byte;
+    fs_drive: byte;
+    fs_filnr: word;
+    fs_nblok: word;
+    fs_nbyte: word;
+    fs_eblok: word;
+    fs_ebyte: word;
+    fs_cblock: pointer;
+    fs_updt: byte;
+    fs_res1: shortint;
+    fs_res2: longint;
+    fs_name: Tqlstr;
+    fs_pad: array[0..105] of byte;
+  end;
+
+const
+  FS_CDEFBSIZE = $a0;
+  FSCDEF_SIZE = FS_CDEFBSIZE; { inconsistently named alias, from C code }
+
+
+{ Variable/type includes before function declarations }
+{$i qdos_sysvars.inc}
 
 { the functions declared in qdosfuncs.inc are implemented in the system unit. They're included
   here via externals, do avoid double implementation of assembler wrappers. for this reason,

+ 146 - 0
packages/qlunits/src/qdos_sysvars.inc

@@ -0,0 +1,146 @@
+{
+    This file is part of the Free Pascal Sinclair QL support package.
+    Copyright (c) 2021 by Norman Dunbar
+
+    Include file to define the system variables record, QDOS naming
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+{$PACKRECORDS 2}
+
+{ This file holds the system variables for a QDOS system and uses
+  the QDOS (original) naming convention. ND. }
+
+Const
+  { System Identifier constants }
+  sysid_ql = $D2540000;    { QL (QDOS) system variable identifier }
+  sysid_at = $53324154;    { SMS Atari system variable identifier }
+  sysid_sq = $534D5351;    { SMSQ identifier }
+  sysid_th = $DC010000;    { Thor (ARGOS) system variable identifier }
+
+  { Display Type constants }
+  dtype_monitor = 0;
+  dtype_tv_625 = 1;
+  dtype_tv_525 = 2;
+
+Type
+  SystemVariables = record
+    sv_ident: Longint;  { $00 - system variables identifier }
+
+{
+  The following variables are the pointers which define the 
+  current state of the memory map.
+}
+    sv_cheap: Pointer;  { $04 - Start of Common Heap area }
+    sv_chpfr: Pointer; { $08 - First free space in Common Heap }
+    sv_free: Pointer;  { $0C - Start of free area }
+    sv_basic: Pointer; { $10 - Start of SuperBasic Area }
+    sv_trnsp: Pointer; { $14 - Start of Transient Program Area }
+    sv_trnfr: Pointer; { $18 - First free space in Transient Program Area }
+    sv_respr: Pointer; { $1C - Resident Procedure Area Base }
+    sv_ramt: Pointer;  { $20 - RAM Top (+1) }
+    sv_unused_24: Array [0..9] of Byte; { $24 - $2D, Unused }
+    sv_rand: Word;     { $2E - Random number }
+    sv_pollm: Word;    { $30 - Number of missed poll interrupts }
+    sv_tvmod: Byte;    { $32 - Display Type (0=normal, 1=TV PAL, 2=TV NSTC), <>2 = TV PAL }
+    sv_scrst: Byte;    { $33 - Display Frozen (0=active, <>0 = frozen) }
+    sv_mcsta: Byte;    { $34 - Copy of TV Register (MC_STAT) }
+    sv_pcint: Byte;    { $35 - Copy of Interrupt Register (PC_INTR) }
+    sv_unused_36: Byte; { $36 - Unused }
+    sv_netnr: Byte;    { $37 - Network node number }
+
+    sv_i2lst: Pointer; { $38 - Start of External Interrupt List }
+    sv_plist: Pointer; { $3C - Start of Polled Tasks List }
+    sv_shlst: Pointer; { $40 - Start of Scheduler Tasks List }
+    sv_drlst: Pointer; { $44 - Start of simple Device Driver List }
+    sv_ddlst: Pointer; { $48 - Start of Directory Driver List }
+    sv_keyq: Pointer;  { $4C - Current Keyboard Queue, 0 if none }
+    sv_trapv: Pointer; { $50 - Exception Redirection Table, 0 if none }
+
+    sv_btpnt: Pointer; { $54 - Most recent slave block entry }
+    sv_btbas: Pointer; { $58 - Start of Slave Block Table }
+    sv_bttop: Pointer; { $5C - End of Slave Block Table }
+
+    sv_jbtag: Word;    { $60   Current value of Job Tag }
+    sv_jbmax: Word;    { $62 - Highest Job Number so far }
+    sv_jbpnt: Pointer; { $64 - Current Job Table entry }
+    sv_jbbas: Pointer; { $68 - Job Table Base }
+    sv_jbtop: Pointer; { $6C - Job Table Top }
+
+    sv_chtag: Word;    { $70 - Current value of Channel Tag }
+    sv_chmax: Word;    { $72 - Highest Channel Number so far }
+    sv_chpnt: Pointer; { $74 - Last channel checked for I/O }
+    sv_chbas: Pointer; { $78 - Start of Channel Table }
+    sv_chtop: Pointer; { $7C - End of Channel Table }
+
+    sv_unused_80: Array [0..7] of Byte; { $80-$87, Unused }
+    sv_caps: Word;     { $88 - CAPS lock (0 if off, $FF00 if on) }
+    sv_arbuf: Word;    { $8A - Last Character (for auto-repeat) }
+                       { = $00xx if ALT not pressed
+                         = $xxFF if ALT pressed }
+    sv_ardel: Word;    { $8C - Repeat Delay (20ms units) }
+    sv_arfrq: Word;    { $8E - Repeat Frequency (20ms units) }
+    sv_arcnt: Word;    { $90 - Repeat Counter (decremented every 20ms) }
+    sv_cqch: Word;     { $92 - Change keyboard queue character }
+    sv_wp: Word;       { $94 - Should be MDV write protect status, but not implemented }
+    sv_sound: Word;    { $96 - Beeping? (0 if off, $FF00 if on) }
+    sv_ser1c: Pointer; { $98 - Address of SER1 input queue }
+    sv_ser2c: Pointer; { $9C - Address of SER2 input queue }
+    sv_tmode: Byte;    { $A0 - ULA transmit mode }
+                       { Bits 0-2: Baud rate number
+                         Bit 3   : 0 = SER1, 1 = SER2
+                         Bit 4   : MDV running }
+    sv_ptyp: Byte;     { $A1 - Processor Type $00=68000/8, $30=68030 etc. [SMSQ] }
+    sv_csub: Pointer;  { $A2 - Subroutine to jump to on Caps Lock }
+    sv_timo: Word;     { $A6 - Counter for timing serial output }
+    sv_timov: Word;    { $A8 - Initial value of sv_timo }
+                        {  Formula = (1200/baud+1, i.e. 
+                                     11 = 75   bps, 
+                                      5 = 300  bps, 
+                                      3 = 600  bps, 
+                                      2 = 1200 bps, 
+                                      1 = 2400 bps+) [QL] }
+    sv_fstat: Word;    { $AA - Cursor flash counter }
+
+{ 
+  The original QL had 66 unused bytes between $AC and $ED inclusive. Over time
+  these have been used by Toolkit 2, for example, for default devices etc. These
+  are defined with the SMS names as QDOS didn't have them. 
+}
+
+    sv_prgd: Pointer;  { $AC - Pointer to Program Default device }
+    sv_datd: Pointer;  { $B0 - Pointer to Data Default device }
+    sv_dstd: Pointer;  { $B4 - Pointer to Destination Default device }
+    sv_thgl: Pointer;  { $B8 - Pointer to ThinG List }
+    sv_unused_bc: Array [0..49] of Byte; { $BC-$ED Unused }
+    sv_mdrun: Byte;    { $EE - Which MDV drive is running? }
+    sv_mdcnt: Byte;    { $EF - MDV run-up run-down counter }
+    sv_mddid: Array [0..7] of Byte; { $F0 - Drive ID*4 of each microdrive [QL] }
+    sv_mdsta: Array [0..7] of Byte; { $F8 - MDV Status: 0=no pending ops [QL] }
+    sv_fsdef: Array [0..15] of Pointer; { $100 Long Pointers to File System Drive Definitions }
+    sv_unused_140: Array [0..3] of Byte; { $140 - Unused }
+    sv_xact: Byte;     { $144 - Set if TRANSLATE active [QDOS V1.10+, SMSQ, not SMS2] }
+    sv_unused_145: Byte; { $145 - Unused }
+    sv_xtab: Pointer;  { $146 - Pointer to TRANSLATE table [QDOS V1.10+, SMSQ, not SMS2] }
+    sv_erms: Pointer;  { $14A -Pointer to (QDOS) error message table [QDOS V1.10+, SMSQ, not SMS2] }
+    sv_unused_14e: Array [0..5] of Byte; { $014E-$0153, Unused }
+
+{
+  Offset $0154 is a table of 4 long words used by Taskmaster
+  but one which is also used by TURBO. I've used the most 
+  likely case here, Taskmaster is pretty much defunct.
+  (Famous last words?) 
+}
+
+    //sv_taskm: Array [0..3] of Longint; {$154 - 4 Long Used by Taskmaster }
+    sv_unused_154: Array [0..2] of Longint; { First 3 Taskmaster longs }
+    sv_turbo: Longint; { $160 - Used by Turbo }
+  end;
+
+  pSystemVariables = ^SystemVariables;

+ 4 - 0
packages/qlunits/src/sms.pas

@@ -12,6 +12,7 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
  **********************************************************************}
+{$PACKRECORDS 2}
 
 unit sms;
 
@@ -22,6 +23,9 @@ uses
   qdos;
 
 
+{ Variable/type includes before function declarations }
+{$i sms_sysvars.inc}
+
 { the functions declared in smsfuncs.inc are implemented in the system unit. They're included
   here via externals, do avoid double implementation of assembler wrappers. for this reason,
   smsfuncs.inc in packages/qlunits must be kept identical to the one in rtl/sinclairql (KB). }

+ 226 - 0
packages/qlunits/src/sms_sysvars.inc

@@ -0,0 +1,226 @@
+{
+    This file is part of the Free Pascal Sinclair QL support package.
+    Copyright (c) 2021 by Norman Dunbar
+
+    Include file to define the system variables record, SMSQ naming
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+{$PACKRECORDS 2}
+
+{ This file holds the system variables for an SMSQ system and uses
+  the SMSQ naming convention. ND. }
+
+Const
+  { System Identifier constants }
+  sysid_ql = $D2540000;    { QL (QDOS) system variable identifier }
+  sysid_at = $53324154;    { SMS Atari system variable identifier }
+  sysid_sq = $534D5351;    { SMSQ identifier }
+  sysid_th = $DC010000;    { Thor (ARGOS) system variable identifier }
+
+  { Display Type constants }
+  dtype_monitor = 0;
+  dtype_tv_625 = 1;
+  dtype_tv_525 = 2;
+
+  { Machine Identifier constants }
+  mtype_st = 0;
+  mtype_mega_st_rtc = 2;
+  mtype_stacy = 4;
+  mtype_ste = 6;
+  mtype_mega_ste = 8;
+  mtype_gold_card = $0A;
+  mtype_super_gold_card = $0C;
+  mtype_falcon = $10;
+  mtype_q40_q60 = $11;
+  mtype_smsqmulator = $14;
+  mtype_tt = $18;
+  mtype_qxl = $1C;
+  mtype_qpc = $1E;
+
+Type
+  SystemVariables = record
+    sys_idnt: Longint;  { system variables identifier }
+
+{
+  The following variables are the pointers which define the 
+  current state of the memory map.
+}
+    sys_chpb: Pointer;  { Common HeaP Base }
+    sys_chpf: Pointer;  { Common HeaP Free space pointer }
+    sys_fsbb: Pointer;  { Filing system Slave Block area Base }
+    sys_sbab: Pointer;  { 'QL S*Basic' Area Base }
+    sys_tpab: Pointer;  { Transient Program Area Base }
+    sys_tpaf: Pointer;  { Transient Program Area Free space pointer }
+    sys_rpab: Pointer;  { Resident Procedure Area Base }
+    sys_ramt: Pointer;  { RAM Top (+1) }
+    sys_mxfr: Pointer;  { Maximum return from free memory call [SMS] }
+    sys_rtc:  Longint;  { Real time (seconds) [SMS] }
+    sys_rtcf: Word;     { Real time fractional, count down [SMS] }
+    sys_rand: Word;     { RANDom number }
+
+    sys_pict: Word;     { Polling Interupt CounT }
+    sys_dtyp: Byte;     { Display TYPe (0=normal, 1=TV 625, 2=TV 525) }
+    sys_dfrz: Byte;     { Display FRoZen (T or F) }
+    sys_qlmr: Byte;     { QL Master chip Register value (Copy of MC_STAT) }
+    sys_qlir: Byte;     { QL Interrupt Register value (Copy of PC_INTR) }
+    sys_rshd: Byte;     { True to reschedule [SMS] }
+    sys_nnnr: Byte;     { Network Node NumbeR }
+
+{
+  The following system variables are pointers to the list of
+  tasks and drivers.
+}
+
+    sys_exil: Pointer;  { EXternal Interrupt action List }
+    sys_poll: Pointer;  { POLled action List }
+    sys_shdl: Pointer;  { ScHeDuler loop action List }
+    sys_iodl: Pointer;  { IO Driver List }
+    sys_fsdl: Pointer;  { Filing System Driver List }
+    sys_ckyq: Pointer;  { Current Keyboard Queue }
+    sys_ertb: Pointer;  { Exception Redirection Table Base }
+
+{
+  The following system variables are pointers to the resource
+  management tables. The slave block tables have 8 byte 
+  entries, whilst the others have 4 byte entries.
+}
+
+    { First the slave block tables }
+
+    sys_sbrp: Pointer;  { Slave Block Running Pointer }
+    sys_sbtb: Pointer;  { Slave Block Table Base }
+    sys_sbtt: Pointer;  { Slave Block Table Top }
+
+    { Then job stuff }
+
+    sys_jbtg: Word;     { Next JoB TaG }
+    sys_jbtp: Word;     { Highest JoB in table (ToP one) }
+    sys_jbpt: Pointer;  { Current JoB PoinTer }
+    sys_jbtb: Pointer;  { JoB Table Base }
+    sys_jbtt: Pointer;  { JoB Table Top }
+
+    { Then channel stuff. (Not SuperBASIC channels) }
+
+    sys_chtg: Word;     { Next CHannel TaG }
+    sys_chtp: Word;     { Highest CHannel in table (ToP one) }
+    sys_chpt: Pointer;  { Last checked CHannel PoinTer }
+    sys_chtb: Pointer;  { CHannel Table Base }
+    sys_chtt: Pointer;  { CHannel Table Top }
+
+    { Then odds and sods }
+
+    sys_frbl: Pointer;  { FRee Block List (to return to common heap) [SMS] }
+    sys_tsdd: Byte;     { Thor flag [THOR] }
+    sys_unused_85: array [0..2] of Byte; { Unused, offset = $85, $86 and $87 }
+{
+  The following variables contain information about how to 
+  treat the keyboard, and about other aspects of the
+  IPC and serial port communications.
+}
+
+    sys_caps: Word;     { CAPS lock (0 if off, $FF00 if on) }
+    sys_lchr: Word;     { Last CHaRacter (for auto-repeat) }
+    sys_rdel: Word;     { Repeat DELay (20ms units) }
+    sys_rtim: Word;     { Repeat TIMe (20ms units) }
+    sys_rcnt: Word;     { Repeat CouNTer (decremented every 20ms) }
+    sys_swtc: Word;     { SWiTch Keyboard queues Character }
+    sys_unused_94: array [0..1] of Byte;  { Unused, offset = $94 and $95 }
+    sys_qlbp: Word;     { QL BeePing (0 if off, $FF00 if on) }
+    sys_ser1: Pointer;  { Receive channel 1 queue address [QL] }
+    sys_ser2: Pointer;  { Receive channel 2 queue address [QL] }
+    sys_tmod: Byte;     { ZX8302 transmit mode (includes baudrate) (copy of PC_TCTRL) [QL] }
+    sys_ptyp: Byte;     { Processor TYPe $00=68000/8, $30=68030 etc. [SMSQ] }
+    sys_csub: Pointer;  { Subroutine to jump to on Caps Lock }
+
+    { Sys_stmo only on QL. Sys_dmiu/sys_mtyp on everything else. }
+    // sys_stmo: Word;     { Serial xmit timeout [QL] }
+
+    sys_dmiu: Byte;     { DMA in use? [SMS2, ST, SMSQ] }
+    sys_mtyp: Byte;     { Machine TYPe [SMSQ] }
+
+    { Sys_stmv on  QL Only. Redefined by other systems by sys_polf }
+    //sys_stmv: Word;   { Value of serial timeout }
+                        {  Formula = (1200/baud+1, i.e. 
+                                     11 = 75   bps, 
+                                      5 = 300  bps, 
+                                      3 = 600  bps, 
+                                      2 = 1200 bps, 
+                                      1 = 2400 bps+) [QL] }
+
+    sys_polf: Word;     { Polling frequency [SMSQ] }
+    sys_cfst: Word;     { Flashing cursor status }
+
+    { Filing system defaults }
+
+    sys_prgd: Pointer;  { Pointer to PRoGram Default [EXT][SMSQ] }
+    sys_datd: Pointer;  { Pointer to DATa Default [EXT][SMSQ] }
+    sys_dstd: Pointer;  { Pointer to DeSTination Default [EXT][SMSQ] }
+    sys_thgl: Pointer;  { Pointer to THinG List [EXT][SMSQ] }
+    sys_psf:  Pointer;  { Primary stack frame pointer [SMSQ] }
+    sys_200i: Byte;     { 200 Hz in service/interrupt 2 in service [SMSQ] }
+    sys_50i:  Byte;     { 50 Hz in service [SMSQ] }
+    sys_10i:  Byte;     { 10 Hz in service [SMSQ] }
+    sys_plrq: Byte;     { Poll requested (-ve for request) [SMSQ] }
+
+    sys_clnk: Pointer;  { Pointer to console linkage [SMSQ] }
+    sys_castat: Byte;   { -1 cache on, +1 instruction cache temp off [SMSQ] }
+    sys_casup: Byte;    { Cache suppressed timer [SMSQ] }
+    sys_iopr: Word;     { I/O priority [SMSQ] }
+    sys_cbas: Pointer;  { Current basic (copy of sys_jbpt) [SMSQ] }
+    sys_fpu:  Array [0..15] of Byte; { FPU stuff? [SMSQ] }
+    sys_prtc: Byte;     {  Set if real time clock protected [SMSQ] }
+    sys_pmem: Byte;     { Memory protection level [SMSQ, ST] }
+    sys_slug: Word;     { Slug level [SMSQ] }
+    sys_klock: Byte;    { Key lock [SMSQ/E] }
+    sys_unused_e5: Byte; { Not used, offset = $E5 }
+    sys_mtick: Word;    { Mini tick counter [SMSQ/E] }
+    sys_klnk: Pointer;  { Pointer to keyboard linkage [SMSQ/E] }
+    sys_unused_ec: Array [1..2] of Byte; { Not used, offset = $EC and $ED }
+
+    { Fixed filing system working area [QL] }
+
+    sys_mdrn: Byte;     { Which MDV drive is running? }
+    sys_mdct: Byte;     { MDV run-up run-down counter [QL] }
+    sys_mdid: Array [0..7] of Byte; { Drive ID*4 of each microdrive [QL] }
+    sys_mdst: Array [0..7] of Byte; { MDV Status: 0=no pending ops [QL] }
+    sys_fsdd: Array [0..15] of Pointer; { Long Pointers to Filing System Drive Definitions }
+
+    sys_fsch: Pointer;  { Linked list of Filing System CHannel blocks }
+    sys_xact: Byte;     { Set if TRANSLATE active [QDOS V1.10+, SMSQ, not SMS2] }
+    sys_unused_145: Byte; { Unused, offset = $0145 }
+    sys_xtab: Pointer;  { Pointer to TRANSLATE table [QDOS V1.10+, SMSQ, not SMS2] }
+    sys_erms: Pointer;  { Pointer to (QDOS) error message table [QDOS V1.10+, SMSQ, not SMS2] }
+
+    sys_mstab: Pointer; { Pointer to (SMSQ) message table [SMSQ]. }
+                        { This is a pointer to a 256 long word table of
+                          pointers to message groups. All undefined 
+                          message groups have a zero pointer. }
+    sys_unused_152: Array [0..1] of Byte; { Unused, Offset = $0152 and $0153 }
+
+    { Offset $0154 is a table of 4 long words used by Taskmaster
+      but one which is also used by TURBO. I've used the most 
+      likely case here, Taskmaster is pretty much defunct.
+      (Famous last words?) }
+    //sys_taskm: Array [0..3] of Longint; { 4 Long Used by Taskmaster }
+    sys_unused_154: Array [0..2] of Longint; { First 3 Taskmaster longs }
+    sys_turbo: Longint; { Used by Turbo }
+
+    sys_qsound: Longint; { Used by QSound }
+    sys_ldmlst: Pointer; { Language dependent module list [SMSQ] }
+    sys_lang: Word;      { Current language [SMSQ] }
+    sys_vers: Longint;   { Operating system version [SMSQ] }
+    sys_rthg: Byte;      { Use RECENT Thing (<>0 if yes) [SMSQ/E 3.24+] }
+    sys_xdly: Byte;      { Suspend delay after executing another job [SMSQ/E 3.13+] }
+    sys_ouch: Byte;      { Ouch flag (currently used to activate SGC debug) [SMSQ] }
+
+  end;
+
+  pSystemVariables = ^SystemVariables;
+

+ 2 - 0
packages/qlunits/src/smsfuncs.inc

@@ -13,4 +13,6 @@
 
  **********************************************************************}
 
+function sms_info(sys_vars: ppchar; ver_ascii: plongint): Tjobid; external name '_mt_inf';
+function iob_fbyt(chan: Tchanid; timeout: Ttimeout): longint; external name '_io_fbyte';
 function iof_mkdr(chan: Tchanid): longint; external name '_iof_mkdr';

+ 59 - 0
packages/qlunits/tests/trecsize.pas

@@ -0,0 +1,59 @@
+{
+    Copyright (c) 2021 Karoly Balogh
+
+    Test system record/structure sizes on a Sinclair QL
+    A test program for Free Pascal's Sinclair QL support
+
+    This test program is in the Public Domain under the terms of
+    Unlicense: http://unlicense.org/
+
+ **********************************************************************}
+
+program trecsize;
+
+uses
+  qdos;
+
+type
+  size_test = record
+    name: string[16];
+    size: longint;
+    size_of: longint;
+  end;
+
+const
+  record_sizes: array of size_test = (
+    { extend with more, as needed }
+    ( name: 'TQDOS_QUEUE'; size: QDOSQUEUE_SIZE; size_of: sizeof(Tqdos_queue) ),
+    ( name: 'TCHAN_DEFB'; size: CHAN_DEFBSIZE; size_of: sizeof(Tchan_defb) ),
+    ( name: 'TSER_CDEFB'; size: SER_CDEFBSIZE; size_of: sizeof(Tser_cdefb) ),
+    ( name: 'TNET_CDEFB'; size: NET_CDEFBSIZE; size_of: sizeof(Tnet_cdefb) ),
+    ( name: 'TSCRN_INFO'; size: SCRN_INFOSIZE; size_of: sizeof(Tscrn_info) ),
+    ( name: 'TSCR_CDEFB'; size: SCR_CDEFBSIZE; size_of: sizeof(Tscr_cdefb) ),
+    ( name: 'TCON_CDEFB'; size: CON_CDEFBSIZE; size_of: sizeof(Tcon_cdefb) ),
+    ( name: 'TFS_CDEFB'; size: FS_CDEFBSIZE; size_of: sizeof(Tfs_cdefb) )
+  );
+
+function test_record_sizes: boolean;
+var
+  i: longint;
+begin
+  test_record_sizes:=false;
+  for i:=low(record_sizes) to high(record_sizes) do
+    begin
+      with record_sizes[i] do
+        begin
+          writeln(name,' is ',size_of,' bytes, expected: ',size);
+          if size_of <> size then
+            exit;
+        end;
+    end;
+  test_record_sizes:=true;
+end;
+
+begin
+  if test_record_sizes then
+    writeln('All OK!')
+  else
+    writeln('Error! Wrong size!');
+end.

+ 62 - 0
packages/qlunits/tests/tsysvars.pas

@@ -0,0 +1,62 @@
+{
+    Copyright (c) 2021 Karoly Balogh
+
+    Test system variable offsets on a Sinclair QL
+    A test program for Free Pascal's Sinclair QL support
+
+    This test program is in the Public Domain under the terms of
+    Unlicense: http://unlicense.org/
+
+ **********************************************************************}
+
+program tsysvars;
+
+uses
+  qdos;
+
+var
+  system_vars: SystemVariables;
+
+type
+  offset_test = record
+    name: string[16];
+    offset: longint;
+    sysvar: pointer;
+  end;
+
+const
+  { example offsets. feel free to extend... }
+  sysvar_offsets: array of offset_test = (
+    ( name: 'SV_RAND'; offset: $2E; sysvar: @system_vars.SV_RAND ),
+    ( name: 'SV_TMODE'; offset: $A0; sysvar: @system_vars.SV_TMODE ),
+    ( name: 'SV_CSUB'; offset: $A2; sysvar: @system_vars.SV_CSUB ),
+    ( name: 'SV_PRGD'; offset: $AC; sysvar: @system_vars.SV_PRGD ),
+    ( name: 'SV_TURBO'; offset: $160; sysvar: @system_vars.SV_TURBO )
+  );
+
+function check_sysvar_offset(const test: offset_test): boolean;
+var
+  actual_offset: longint;
+begin
+  actual_offset:=pbyte(test.sysvar)-pbyte(@system_vars);
+  writeln(test.name,' at: ',actual_offset,' $',hexstr(actual_offset,3));
+  check_sysvar_offset:=(test.offset = actual_offset);
+end;
+
+function test_sysvar_offsets: boolean;
+var
+  i: longint;
+begin
+  test_sysvar_offsets:=false;
+  for i:=low(sysvar_offsets) to high(sysvar_offsets) do
+    if not check_sysvar_offset(sysvar_offsets[i]) then
+      exit;
+  test_sysvar_offsets:=true;
+end;
+
+begin
+  if test_sysvar_offsets then
+    writeln('All OK!')
+  else
+    writeln('Error! Wrong offset!');
+end.

+ 2 - 2
packages/rtl-objpas/src/inc/strutils.pp

@@ -222,7 +222,7 @@ function Dec2Numb(N: Longint; Len, Base: Byte): string;
 function Numb2Dec(S: string; Base: Byte): Longint;
 function IntToBin(Value: Longint; Digits, Spaces: Integer): string;
 function IntToBin(Value: Longint; Digits: Integer): string;
-function intToBin(Value: int64; Digits:integer): string;
+function IntToBin(Value: int64; Digits:integer): string;
 function IntToRoman(Value: Longint): string;
 function TryRomanToInt(S: String; out N: LongInt; Strictness: TRomanConversionStrictness = rcsRelaxed): Boolean;
 function RomanToInt(const S: string; Strictness: TRomanConversionStrictness = rcsRelaxed): Longint;
@@ -247,7 +247,7 @@ function PosSet (const c:string;const s : ansistring ):SizeInt;
 function PosSetEx (const c:TSysCharSet;const s : ansistring;count:Integer ):SizeInt;
 function PosSetEx (const c:string;const s : ansistring;count:Integer ):SizeInt;
 
-Procedure Removeleadingchars(VAR S : AnsiString; Const CSet:TSysCharset);
+Procedure RemoveLeadingchars(VAR S : AnsiString; Const CSet:TSysCharset);
 Procedure RemoveTrailingChars(VAR S : AnsiString;Const CSet:TSysCharset);
 Procedure RemovePadChars(VAR S : AnsiString;Const CSet:TSysCharset);
 

+ 6 - 6
rtl/aarch64/aarch64.inc

@@ -33,25 +33,25 @@ const
   fpu_exception_mask = fpu_ioe or fpu_dze or fpu_ofe or fpu_ufe or fpu_ixe or fpu_ide;
   fpu_exception_mask_to_status_mask_shift = 8;
 
-function getfpcr: dword; nostackframe; assembler;
+function getfpcr: qword; nostackframe; assembler;
   asm
     mrs x0,fpcr
   end;
 
 
-procedure setfpcr(val: dword); nostackframe; assembler;
+procedure setfpcr(val: qword); nostackframe; assembler;
   asm
     msr fpcr,x0
   end;
 
 
-function getfpsr: dword; nostackframe; assembler;
+function getfpsr: qword; nostackframe; assembler;
   asm
     mrs x0,fpsr
   end;
 
 
-procedure setfpsr(val: dword); nostackframe; assembler;
+procedure setfpsr(val: qword); nostackframe; assembler;
   asm
     msr fpsr, x0
   end;
@@ -69,7 +69,7 @@ const
 
 procedure RaisePendingExceptions;
   var
-    fpsr : dword;
+    fpsr : qword;
     f: TFPUException;
   begin
     fpsr:=getfpsr;
@@ -96,7 +96,7 @@ procedure RaisePendingExceptions;
   exceptions are not supported }
 procedure fpc_throwfpuexception;[public,alias:'FPC_THROWFPUEXCEPTION'];
   var
-    fpsr : dword;
+    fpsr : qword;
     f: TFPUException;
   begin
     { at this point, we know already, that an exception will be risen }

+ 1 - 0
rtl/avr/cpuinnr.inc

@@ -19,3 +19,4 @@
   in_avr_nop = fpc_in_cpu_first+4;
   in_avr_save = fpc_in_cpu_first+5;
   in_avr_restore = fpc_in_cpu_first+6;
+  in_avr_des = fpc_in_cpu_first+7;

+ 2 - 0
rtl/avr/intrinsics.pp

@@ -29,6 +29,8 @@ unit intrinsics;
     { Restores SREG }
     procedure avr_restore(old_sreg: byte); [INTERNPROC: in_avr_restore];
 
+    procedure avr_des(var data;var key;decrypt: boolean;round: byte);[INTERNPROC: in_avr_des];
+
   implementation
 
 end.

+ 2 - 2
rtl/inc/rttih.inc

@@ -11,7 +11,7 @@
 
  **********************************************************************}
 
-{ sadly MinEnumSize is not handled by Push/Pop :'( }
+{$PUSH}
 {$MINENUMSIZE 1   this saves a lot of memory }
 
 type
@@ -26,7 +26,7 @@ type
               tkDynArray,tkInterfaceRaw,tkProcVar,tkUString,tkUChar,
               tkHelper,tkFile,tkClassRef,tkPointer);
 
-{$MINENUMSIZE DEFAULT}
+{$POP}
 
 const
   { some Delphi-compatible aliases }

+ 2 - 2
rtl/linux/system.pp

@@ -685,11 +685,11 @@ begin
     result := stklen;
 end;
 
-{$if FPC_FULLVERSION>30200}
+{$if FPC_FULLVERSION>30300}
 {$if defined(CPUI386) or defined(CPUARM)}
 {$I abitag.inc}
 {$endif defined(CPUI386) or defined(CPUARM)}
-{$endif FPC_FULLVERSION>30200}
+{$endif FPC_FULLVERSION>30300}
 
 begin
 {$if defined(i386) and not defined(FPC_USE_LIBC)}

+ 3 - 2
rtl/objpas/classes/writer.inc

@@ -892,8 +892,9 @@ begin
     if PropType^.Kind<>tkClass then
       exit;
     ObjValue := TObject(GetObjectProp(Instance, PropInfo));
-    if not ObjValue.InheritsFrom(TComponent) or
-       not (csSubComponent in TComponent(ObjValue).ComponentStyle) then
+    if not (assigned(ObjValue) and
+            ObjValue.InheritsFrom(TComponent) and
+            (csSubComponent in TComponent(ObjValue).ComponentStyle)) then
       exit;
   end;
 

+ 3 - 2
rtl/objpas/types.pp

@@ -686,6 +686,7 @@ begin
   Result.x := apt.X;
   Result.y := apt.Y;
 end;
+
 { TRectF }
 
 function TRectF.GetHeight: Single;
@@ -712,8 +713,8 @@ function TRectF.Union(const r: TRectF): TRectF;
 begin
   result.left:=min(r.left,left);
   result.top:=min(r.top,top);
-  result.right:=min(r.right,right);
-  result.bottom:=min(r.bottom,bottom);
+  result.right:=max(r.right,right);
+  result.bottom:=max(r.bottom,bottom);
 end;
 
 procedure TRectF.Offset(const dx, dy: Single);

+ 89 - 0
rtl/riscv/riscv.inc

@@ -0,0 +1,89 @@
+{
+
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by the Free Pascal development team.
+
+    Processor dependent implementation for the system unit for
+    RiscV which is common to all RiscV types
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+{****************************************************************************
+                       fpu exception related stuff
+****************************************************************************}
+
+{$ifdef FPUFD}
+const
+  fpu_nx = 1 shl 0;
+  fpu_uf = 1 shl 1;
+  fpu_of = 1 shl 2;
+  fpu_dz = 1 shl 3;
+  fpu_nv = 1 shl 4;
+
+function getfflags: sizeuint; nostackframe; assembler;
+  asm
+    frflags a0
+  end;
+
+
+procedure setfflags(flags : sizeuint); nostackframe; assembler;
+  asm
+    fsflags a0
+  end;
+
+
+procedure RaisePendingExceptions;
+  var
+    fflags : sizeuint;
+    f: TFPUException;
+  begin
+    fflags:=getfflags;
+    if (fflags and fpu_dz) <> 0 then
+      float_raise(exZeroDivide);
+    if (fflags and fpu_of) <> 0 then
+      float_raise(exOverflow);
+    if (fflags and fpu_uf) <> 0 then
+      float_raise(exUnderflow);
+    if (fflags and fpu_nv) <> 0 then
+      float_raise(exInvalidOp);
+    if (fflags and fpu_nx) <> 0 then
+      float_raise(exPrecision);
+    { now the soft float exceptions }
+    for f in softfloat_exception_flags do
+      float_raise(f);
+  end;
+
+
+procedure fpc_throwfpuexception;[public,alias:'FPC_THROWFPUEXCEPTION'];
+  var
+    fflags : sizeuint;
+  begin
+    fflags:=getfflags;
+    { check, if the exception is masked }
+    if ((fflags and fpu_dz) <> 0) and (exZeroDivide in softfloat_exception_mask) then
+      fflags:=fflags and not(fpu_dz);
+    if ((fflags and fpu_of) <> 0) and (exOverflow in softfloat_exception_mask) then
+      fflags:=fflags and not(fpu_of);
+    if ((fflags and fpu_uf) <> 0) and (exUnderflow in softfloat_exception_mask) then
+      fflags:=fflags and not(fpu_uf);
+    if ((fflags and fpu_nv) <> 0) and (exInvalidOp in softfloat_exception_mask) then
+      fflags:=fflags and not(fpu_nv);
+    if ((fflags and fpu_nx) <> 0) and (exPrecision in softfloat_exception_mask) then
+      fflags:=fflags and not(fpu_nx);
+    setfflags(fflags);
+    if fflags<>0 then
+      RaisePendingExceptions;
+  end;
+{$endif FPUFD}
+
+procedure fpc_cpuinit;{$ifdef SYSTEMINLINE}inline;{$endif}
+  begin
+    softfloat_exception_mask:=[exPrecision,exUnderflow];
+  end;

+ 3 - 5
rtl/riscv32/riscv32.inc

@@ -4,7 +4,7 @@
     Copyright (c) 2008 by the Free Pascal development team.
 
     Processor dependent implementation for the system unit for
-    AVR
+    RiscV32
 
     See the file COPYING.FPC, included in this distribution,
     for details about the copyright.
@@ -15,10 +15,8 @@
 
  **********************************************************************}
 
-procedure fpc_cpuinit;{$ifdef SYSTEMINLINE}inline;{$endif}
-  begin
-  end;
-
+{ Common RiscV stuff }
+{$I ../riscv/riscv.inc}
 
 {$IFNDEF INTERNAL_BACKTRACE}
 {$define FPC_SYSTEM_HAS_GET_FRAME}

+ 3 - 73
rtl/riscv64/riscv64.inc

@@ -4,7 +4,7 @@
     Copyright (c) 2008 by the Free Pascal development team.
 
     Processor dependent implementation for the system unit for
-    AVR
+    RiscV64
 
     See the file COPYING.FPC, included in this distribution,
     for details about the copyright.
@@ -15,78 +15,8 @@
 
  **********************************************************************}
 
-{****************************************************************************
-                       fpu exception related stuff
-****************************************************************************}
-
-{$ifdef FPUFD}
-const
-  fpu_nx = 1 shl 0;
-  fpu_uf = 1 shl 1;
-  fpu_of = 1 shl 2;
-  fpu_dz = 1 shl 3;
-  fpu_nv = 1 shl 4;
-
-function getfflags: sizeuint; nostackframe; assembler;
-  asm
-    frflags a0
-  end;
-
-
-procedure setfflags(flags : sizeuint); nostackframe; assembler;
-  asm
-    fsflags a0
-  end;
-
-
-procedure RaisePendingExceptions;
-  var
-    fflags : sizeuint;
-    f: TFPUException;
-  begin
-    fflags:=getfflags;
-    if (fflags and fpu_dz) <> 0 then
-      float_raise(exZeroDivide);
-    if (fflags and fpu_of) <> 0 then
-      float_raise(exOverflow);
-    if (fflags and fpu_uf) <> 0 then
-      float_raise(exUnderflow);
-    if (fflags and fpu_nv) <> 0 then
-      float_raise(exInvalidOp);
-    if (fflags and fpu_nx) <> 0 then
-      float_raise(exPrecision);
-    { now the soft float exceptions }
-    for f in softfloat_exception_flags do
-      float_raise(f);
-  end;
-
-
-procedure fpc_throwfpuexception;[public,alias:'FPC_THROWFPUEXCEPTION'];
-  var
-    fflags : sizeuint;
-  begin
-    fflags:=getfflags;
-    { check, if the exception is masked }
-    if ((fflags and fpu_dz) <> 0) and (exZeroDivide in softfloat_exception_mask) then
-      fflags:=fflags and not(fpu_dz);
-    if ((fflags and fpu_of) <> 0) and (exOverflow in softfloat_exception_mask) then
-      fflags:=fflags and not(fpu_of);
-    if ((fflags and fpu_uf) <> 0) and (exUnderflow in softfloat_exception_mask) then
-      fflags:=fflags and not(fpu_uf);
-    if ((fflags and fpu_nv) <> 0) and (exInvalidOp in softfloat_exception_mask) then
-      fflags:=fflags and not(fpu_nv);
-    if ((fflags and fpu_nx) <> 0) and (exPrecision in softfloat_exception_mask) then
-      fflags:=fflags and not(fpu_nx);
-    setfflags(fflags);
-    if fflags<>0 then
-      RaisePendingExceptions;
-  end;
-{$endif FPUFD}
-
-procedure fpc_cpuinit;{$ifdef SYSTEMINLINE}inline;{$endif}
-  begin
-    softfloat_exception_mask:=[exPrecision,exUnderflow];
-  end;
+{ Common RiscV stuff }
+{$I ../riscv/riscv.inc}
 
 {****************************************************************************
                        stack frame related stuff

+ 2 - 0
rtl/sinclairql/smsfuncs.inc

@@ -13,4 +13,6 @@
 
  **********************************************************************}
 
+function sms_info(sys_vars: ppchar; ver_ascii: plongint): Tjobid; external name '_mt_inf';
+function iob_fbyt(chan: Tchanid; timeout: Ttimeout): longint; external name '_io_fbyte';
 function iof_mkdr(chan: Tchanid): longint; external name '_iof_mkdr';

+ 10 - 1
rtl/sinclairql/sysfile.inc

@@ -250,5 +250,14 @@ end;
 
 function do_isdevice(handle: thandle): boolean;
 begin
-  do_isdevice:=false;
+  { FIXME: See if this can be implemented properly on the QL. }
+
+  { Prefer to return true here as a default answer, as it is less harmful
+    than false. This basically determines if the file handle is a "device",
+    for example the console. Returning true here causes a flush before a
+    read on the file handle which is preferred for consoleio, and a few
+    other minor behavioral changes, for example shorter stacktraces.
+    Returning false will cause weird behavior and unprinted lines when
+    read() and write() is mixed during consoleio. }
+  do_isdevice:=true;
 end;

+ 82 - 16
rtl/sinclairql/system.pp

@@ -70,10 +70,21 @@ var
 
     {$endif defined(FPUSOFT)}
 
+type
+  QLConHandle = record
+    inputHandle: longint;
+    outputHandle: longint;
+    errorHandle: longint;
+    userData: pointer;
+  end;
+
+
+
 function SetQLJobName(const s: string): longint;
 function GetQLJobName: string;
 function GetQLJobNamePtr: pointer;
 
+procedure SetQLDefaultConExitMessage(const msg: PChar);
 
 implementation
 
@@ -265,17 +276,67 @@ begin
     end;
 end;
 
+const
+  QLDefaultConExitMessage: PChar = 'Press any key to exit';
+
+procedure SetQLDefaultConExitMessage(const msg: PChar);
+begin
+  QLDefaultConExitMessage:=msg;
+end;
+
+
+function QLOpenCon(var console: QLConHandle): boolean; weakexternal name 'QLOpenCon';
+procedure QLCloseCon(var console: QLConHandle); weakexternal name 'QLCloseCon';
+
+function DefaultQLOpenCon(var console: QLConHandle): boolean;
+var
+  r: TQLRect;
+begin
+  DefaultQLOpenCon:=false;
+  with console do
+    begin
+      inputHandle:=io_open('con_',Q_OPEN);
+      if inputHandle <= 0 then
+        exit;
+
+      outputHandle:=inputHandle;
+      errorHandle:=inputHandle;
+      userData:=nil;
+
+      r.q_width:=512;
+      r.q_height:=256;
+      r.q_x:=0;
+      r.q_y:=0;
+
+      sd_wdef(outputHandle,-1,2,1,@r);
+      sd_clear(outputHandle,-1);
+    end;
+  DefaultQLOpenCon:=true;
+end;
+
+procedure DefaultQLCloseCon(var console: QLConHandle);
+begin
+  with console do
+    begin
+      if assigned(QLDefaultConExitMessage) and (length(QLDefaultConExitMessage) > 0) then
+        begin
+          io_sstrg(outputHandle, -1, QLDefaultConExitMessage, length(QLDefaultConExitMessage));
+          io_fbyte(inputHandle, -1);
+        end;
+    end;
+end;
+
 {*****************************************************************************
                         System Dependent Entry code
 *****************************************************************************}
 var
   jobStackDataPtr: pointer; external name '__stackpointer_on_entry';
   program_name: shortstring; external name '__fpc_program_name';
+  QLCon: QLConHandle;
+  QLConOpen: boolean;
 
 { QL/QDOS specific startup }
 procedure SysInitQDOS;
-var
-  r: TQLRect;
 begin
   QL_ChannelIDNum:=pword(jobStackDataPtr)[0];
   QL_ChannelIDs:=@pword(jobStackDataPtr)[1];
@@ -284,17 +345,19 @@ begin
 
   SetQLJobName(program_name);
 
-  stdInputHandle:=io_open('con_',Q_OPEN);
-  stdOutputHandle:=stdInputHandle;
-  stdErrorHandle:=stdInputHandle;
-
-  r.q_width:=512;
-  r.q_height:=256;
-  r.q_x:=0;
-  r.q_y:=0;
+  if assigned(@QLOpenCon) then
+    QLConOpen:=QLOpenCon(QLCon)
+  else
+    QLConOpen:=DefaultQLOpenCon(QLCon);
+  if not QLConOpen then
+    halt(1);
 
-  sd_wdef(stdInputHandle,-1,2,1,@r);
-  sd_clear(stdInputHandle,-1);
+  with QLCon do
+    begin
+      stdInputHandle:=inputHandle;
+      stdOutputHandle:=outputHandle;
+      stdErrorHandle:=errorHandle;
+    end;
 end;
 
 {*****************************************************************************
@@ -304,16 +367,19 @@ end;
 procedure haltproc(e:longint); external name '_haltproc';
 
 procedure system_exit;
-const
-  anyKey: pchar = 'Press any key to exit';
 begin
   if assigned(args) then
     FreeMem(args);
   if assigned(argv) then
     FreeMem(argv);
 
-  io_sstrg(stdOutputHandle, -1, anyKey, length(anykey));
-  io_fbyte(stdInputHandle, -1);
+  if QLConOpen then
+    begin
+      if assigned(@QLCloseCon) then
+        QLCloseCon(QLCon)
+      else
+        DefaultQLCloseCon(QLCon);
+    end;
 
   stdInputHandle:=UnusedHandle;
   stdOutputHandle:=UnusedHandle;

+ 2 - 1
rtl/win32/sysinit.inc

@@ -31,8 +31,9 @@
    var
       tlsdir: record end; external name '__tls_used';
 
-    procedure LinkIn(p1,p2,p3: Pointer); inline;
+    function LinkIn(p1,p2,p3: Pointer): pointer;
       begin
+        LinkIn:=p1;
       end;
 {$endif}
 

+ 2 - 1
rtl/win64/sysinit.pp

@@ -36,8 +36,9 @@ unit sysinit;
    var
       tlsdir: record end; external name '_tls_used';
 
-    procedure LinkIn(p1,p2,p3: Pointer); inline;
+    function LinkIn(p1,p2,p3: Pointer): pointer;
       begin
+        LinkIn:=p1;
       end;
 {$endif}
 

+ 11 - 0
tests/test/tdes1.pp

@@ -0,0 +1,11 @@
+{ %cpu=avr }
+{ %norun }
+uses
+  intrinsics;
+var
+  data,key : array[0..7] of byte;
+begin
+  avr_des(data,key,true,1);
+end.
+
+  

+ 12 - 0
tests/test/tdes2.pp

@@ -0,0 +1,12 @@
+{ %fail }
+{ %cpu=avr }
+{ %norun }
+uses
+  intrinsics;
+var
+  data,key : array[0..7] of byte;
+begin
+  avr_des(data,key,true,100);
+end.
+
+  

+ 11 - 0
tests/webtbf/tw26016.pp

@@ -0,0 +1,11 @@
+{ %fail }
+program Project1;
+type
+   T1 = array of integer;
+   T2 = array of T1;
+   T3 = array of T2;
+var
+a: T3;
+begin
+   SetLength(a.[0].[0],1);
+end.

+ 22 - 0
tests/webtbs/tw38940.pp

@@ -0,0 +1,22 @@
+{ %OPT=-O3 }
+procedure Test;
+var b:boolean;
+    i:longint;
+begin
+// the following loop should be done 2 time, but it hangs up;
+ b:=true;
+ i:=0;
+ repeat
+   inc(i);
+   if i>2 then 
+     halt(1);
+   b:=not b; // first time b is set to false thats why the loop should be done again
+              // second time b is set to true thats why the loop should be leave,
+              // but hangs up
+ until b;
+end;
+
+begin
+  Test;
+  writeln('ok');
+end.

+ 2 - 2
utils/pas2js/docs/translation.html

@@ -2723,10 +2723,10 @@ function(){
     Destructors are not allowed.<br>
     Constructors are supported in four ways:
     <ul>
-      <li><i>constructor New</i> is translated to <i>new ExtClass(params)</i>.</li>
+      <li><i>constructor New</i> is translated to <i>new ExtClass(params)</i>, and for nested external class: <i>new ExtParentClass.ExtClass(Params)</i></li>
       <li><i>constructor New; external name ''GlobalFunc''</i> is translated to <i>new GlobalFunc(params)</i>.</li>
       <li><i>constructor SomeName; external name </i>'{}'</i> is translated to <i>{}</i>.</li>
-      <li>Otherwise it is translated to <i>new ExtClass.FuncName(params)</i>.</li>
+      <li>Otherwise it is translated to <i>new ExtClass.FuncName(params)</i>, and for nested external class: <i>new ExtParentClass.ExtClass.FuncName(params)</i>.</li>
     </ul>
 
     <table class="sample">

Some files were not shown because too many files changed in this diff