Browse Source

* synchronized with trunk

git-svn-id: branches/wasm@46785 -
nickysn 5 years ago
parent
commit
be16e3a347

+ 1 - 0
.gitattributes

@@ -16166,6 +16166,7 @@ tests/test/units/sysutils/tstrcmp.pp svneol=native#text/plain
 tests/test/units/sysutils/tstrtobool.pp svneol=native#text/plain
 tests/test/units/sysutils/tstrtobool.pp svneol=native#text/plain
 tests/test/units/sysutils/tunifile.pp svneol=native#text/plain
 tests/test/units/sysutils/tunifile.pp svneol=native#text/plain
 tests/test/units/sysutils/tuplow.pp svneol=native#text/plain
 tests/test/units/sysutils/tuplow.pp svneol=native#text/plain
+tests/test/units/sysutils/tw37374.pp svneol=native#text/plain
 tests/test/units/sysutils/twstralloc.pp svneol=native#text/plain
 tests/test/units/sysutils/twstralloc.pp svneol=native#text/plain
 tests/test/units/sysutils/twstrcmp.pp svneol=native#text/plain
 tests/test/units/sysutils/twstrcmp.pp svneol=native#text/plain
 tests/test/units/types/ttbitconverter.pp svneol=native#text/pascal
 tests/test/units/types/ttbitconverter.pp svneol=native#text/pascal

+ 10 - 3
compiler/defcmp.pas

@@ -59,7 +59,8 @@ interface
           cdo_allow_variant,
           cdo_allow_variant,
           cdo_parameter,
           cdo_parameter,
           cdo_warn_incompatible_univ,
           cdo_warn_incompatible_univ,
-          cdo_strict_undefined_check  // undefined defs are incompatible to everything except other undefined defs
+          cdo_strict_undefined_check,  // undefined defs are incompatible to everything except other undefined defs
+          cdo_equal_check              // this call is only to check equality -> shortcut some expensive checks
        );
        );
        tcompare_defs_options = set of tcompare_defs_option;
        tcompare_defs_options = set of tcompare_defs_option;
 
 
@@ -1703,7 +1704,13 @@ implementation
            objectdef :
            objectdef :
              begin
              begin
                { object pascal objects }
                { object pascal objects }
-               if (def_from.typ=objectdef) and
+               { don't call def_is_related if we came here from equal_defs, because
+                   1) this can never result in an "equal result", and
+                   2) def_is_related itself calls equal_defs again for each class in
+                      the hierarchy, which will call compare_defs_ext, which will again
+                      call def_is_related -> quadratic complexity explosion }
+               if not(cdo_equal_check in cdoptions) and
+                  (def_from.typ=objectdef) and
                   (def_is_related(tobjectdef(def_from),tobjectdef(def_to))) then
                   (def_is_related(tobjectdef(def_from),tobjectdef(def_to))) then
                 begin
                 begin
                   doconv:=tc_equal;
                   doconv:=tc_equal;
@@ -2001,7 +2008,7 @@ implementation
       begin
       begin
         { Compare defs with nothingn and no explicit typecasts and
         { Compare defs with nothingn and no explicit typecasts and
           searching for overloaded operators is not needed }
           searching for overloaded operators is not needed }
-        equal_defs:=(compare_defs_ext(def_from,def_to,nothingn,convtyp,pd,[])>=te_equal);
+        equal_defs:=(compare_defs_ext(def_from,def_to,nothingn,convtyp,pd,[cdo_equal_check])>=te_equal);
       end;
       end;
 
 
 
 

+ 3 - 0
compiler/ncgrtti.pas

@@ -133,6 +133,9 @@ implementation
                   { Skip forward defs }
                   { Skip forward defs }
                   if (oo_is_forward in tobjectdef(def).objectoptions) then
                   if (oo_is_forward in tobjectdef(def).objectoptions) then
                     continue;
                     continue;
+                  { skip unique type aliases, they use the RTTI from the parent class }
+                  if tobjectdef(def).is_unique_objpasdef then
+                    continue;
                   write_persistent_type_info(tobjectdef(def).symtable,is_global);
                   write_persistent_type_info(tobjectdef(def).symtable,is_global);
                 end;
                 end;
               procdef :
               procdef :

+ 33 - 0
compiler/ncgutil.pas

@@ -588,6 +588,34 @@ implementation
 
 
 
 
     procedure gen_alloc_regvar(list:TAsmList;sym: tabstractnormalvarsym; allocreg: boolean);
     procedure gen_alloc_regvar(list:TAsmList;sym: tabstractnormalvarsym; allocreg: boolean);
+
+      procedure set_para_regvar_initial_location;
+        var
+          paraloc: PCGParalocation;
+          loc: tlocation;
+          regtype: tregistertype;
+          reg: tregister;
+          size: tcgint;
+        begin
+          tparavarsym(sym).paraloc[calleeside].get_location(loc);
+          size:=tparavarsym(sym).paraloc[calleeside].IntSize;
+          paraloc:=tparavarsym(sym).paraloc[calleeside].Location;
+          reg:=sym.initialloc.register;
+          regtype:=getregtype(reg);
+          repeat
+            loc.reference.offset:=paraloc^.reference.offset;
+            cg.rg[regtype].set_reg_initial_location(reg,loc.reference);
+            dec(size,tcgsize2size[paraloc^.Size]);
+{$if defined(cpu8bitalu) or defined(cpu16bitalu)}
+            if cg.has_next_reg[getsupreg(reg)] then
+              reg:=cg.GetNextReg(reg)
+            else
+{$endif}
+              reg:=sym.initialloc.registerhi;
+            paraloc:=paraloc^.Next;
+          until size=0;
+        end;
+
       var
       var
         usedef: tdef;
         usedef: tdef;
         varloc: tai_varloc;
         varloc: tai_varloc;
@@ -674,6 +702,11 @@ implementation
 {$endif cpu64bitalu and not cpuhighleveltarget}
 {$endif cpu64bitalu and not cpuhighleveltarget}
           varloc:=tai_varloc.create(sym,sym.initialloc.register);
           varloc:=tai_varloc.create(sym,sym.initialloc.register);
         list.concat(varloc);
         list.concat(varloc);
+        { Notify the register allocator about memory location of
+          the register which holds a value of a stack parameter }
+        if (sym.typ=paravarsym) and
+          (tparavarsym(sym).paraloc[calleeside].Location^.Loc=LOC_REFERENCE) then
+          set_para_regvar_initial_location;
       end;
       end;
 
 
 
 

+ 18 - 7
compiler/ncgvmt.pas

@@ -699,11 +699,16 @@ implementation
 
 
     function CreateWrapperName(_class : tobjectdef;AImplIntf : TImplementedInterface;i : longint;pd : tprocdef) : string;
     function CreateWrapperName(_class : tobjectdef;AImplIntf : TImplementedInterface;i : longint;pd : tprocdef) : string;
       var
       var
+        realintfdef: tobjectdef;
         tmpstr : AnsiString;
         tmpstr : AnsiString;
         hs : string;
         hs : string;
         crc : DWord;
         crc : DWord;
       begin
       begin
-        tmpstr:=_class.objname^+'_$_'+AImplIntf.IntfDef.objname^+'_$_'+tostr(i)+'_$_'+pd.mangledname;
+        realintfdef:=AImplIntf.IntfDef;
+        while realintfdef.is_unique_objpasdef do
+          realintfdef:=realintfdef.childof;
+
+        tmpstr:=_class.objname^+'_$_'+realintfdef.objname^+'_$_'+tostr(i)+'_$_'+pd.mangledname;
         if length(tmpstr)>100 then
         if length(tmpstr)>100 then
           begin
           begin
             crc:=0;
             crc:=0;
@@ -749,14 +754,18 @@ implementation
         pd: tprocdef;
         pd: tprocdef;
         siid,
         siid,
         siidstr: tsymstr;
         siidstr: tsymstr;
+        nonuniqueintf: tobjectdef;
       begin
       begin
+        nonuniqueintf:=AImplIntf.IntfDef;
+        while nonuniqueintf.is_unique_objpasdef do
+          nonuniqueintf:=nonuniqueintf.childof;
         tcb.maybe_begin_aggregate(interfaceentrydef);
         tcb.maybe_begin_aggregate(interfaceentrydef);
         { GUID (or nil for Corba interfaces) }
         { GUID (or nil for Corba interfaces) }
         tcb.next_field:=tabstractrecorddef(interfaceentrydef).symtable.Find('IIDREF') as tfieldvarsym;
         tcb.next_field:=tabstractrecorddef(interfaceentrydef).symtable.Find('IIDREF') as tfieldvarsym;
         siid:='';
         siid:='';
-        if AImplIntf.IntfDef.objecttype in [odt_interfacecom] then
+        if nonuniqueintf.objecttype in [odt_interfacecom] then
           begin
           begin
-            siid:=make_mangledname('IID',AImplIntf.IntfDef.owner,AImplIntf.IntfDef.objname^);
+            siid:=make_mangledname('IID',nonuniqueintf.owner,nonuniqueintf.objname^);
             tcb.emit_tai(Tai_const.Create_sym_offset(
             tcb.emit_tai(Tai_const.Create_sym_offset(
               current_asmdata.RefAsmSymbol(siid,AT_DATA,true),0),cpointerdef.getreusable(rec_tguid));
               current_asmdata.RefAsmSymbol(siid,AT_DATA,true),0),cpointerdef.getreusable(rec_tguid));
           end
           end
@@ -766,7 +775,7 @@ implementation
         { VTable }
         { VTable }
         tcb.next_field:=tabstractrecorddef(interfaceentrydef).symtable.Find('VTABLE') as tfieldvarsym;
         tcb.next_field:=tabstractrecorddef(interfaceentrydef).symtable.Find('VTABLE') as tfieldvarsym;
         tcb.queue_init(voidpointertype);
         tcb.queue_init(voidpointertype);
-        tcb.queue_emit_asmsym(fintfvtablelabels[intfindex],AImplIntf.VtblImplIntf.IntfDef);
+        tcb.queue_emit_asmsym(fintfvtablelabels[intfindex],nonuniqueintf);
         { IOffset field }
         { IOffset field }
         case AImplIntf.VtblImplIntf.IType of
         case AImplIntf.VtblImplIntf.IType of
           etFieldValue, etFieldValueClass,
           etFieldValue, etFieldValueClass,
@@ -792,20 +801,20 @@ implementation
 
 
         { IIDStr }
         { IIDStr }
         tcb.next_field:=tabstractrecorddef(interfaceentrydef).symtable.Find('IIDSTRREF') as tfieldvarsym;
         tcb.next_field:=tabstractrecorddef(interfaceentrydef).symtable.Find('IIDSTRREF') as tfieldvarsym;
-        siidstr:=make_mangledname('IIDSTR',AImplIntf.IntfDef.owner,AImplIntf.IntfDef.objname^);
+        siidstr:=make_mangledname('IIDSTR',nonuniqueintf.owner,nonuniqueintf.objname^);
         tcb.queue_init(cpointerdef.getreusable(cshortstringtype));
         tcb.queue_init(cpointerdef.getreusable(cshortstringtype));
         tcb.queue_emit_asmsym(
         tcb.queue_emit_asmsym(
           current_asmdata.RefAsmSymbol(
           current_asmdata.RefAsmSymbol(
             siidstr,
             siidstr,
             AT_DATA,
             AT_DATA,
             true),
             true),
-          cpointerdef.getreusable(carraydef.getreusable(cansichartype,length(AImplIntf.IntfDef.iidstr^)+1)));
+          cpointerdef.getreusable(carraydef.getreusable(cansichartype,length(nonuniqueintf.iidstr^)+1)));
         { IType }
         { IType }
         tcb.next_field:=tabstractrecorddef(interfaceentrydef).symtable.Find('ITYPE') as tfieldvarsym;
         tcb.next_field:=tabstractrecorddef(interfaceentrydef).symtable.Find('ITYPE') as tfieldvarsym;
         tcb.emit_ord_const(aint(AImplIntf.VtblImplIntf.IType),interfaceentrytypedef);
         tcb.emit_ord_const(aint(AImplIntf.VtblImplIntf.IType),interfaceentrytypedef);
         tcb.maybe_end_aggregate(interfaceentrydef);
         tcb.maybe_end_aggregate(interfaceentrydef);
 
 
-        if findunitsymtable(AImplIntf.IntfDef.owner).moduleid<>findunitsymtable(_Class.owner).moduleid then
+        if findunitsymtable(nonuniqueintf.owner).moduleid<>findunitsymtable(_Class.owner).moduleid then
           begin
           begin
             if siid<>'' then
             if siid<>'' then
               current_module.add_extern_asmsym(siid,AB_EXTERNAL,AT_DATA);
               current_module.add_extern_asmsym(siid,AB_EXTERNAL,AT_DATA);
@@ -1300,6 +1309,8 @@ implementation
                   if ([df_generic,df_genconstraint]*def.defoptions<>[]) or
                   if ([df_generic,df_genconstraint]*def.defoptions<>[]) or
                      (oo_is_forward in tobjectdef(def).objectoptions) then
                      (oo_is_forward in tobjectdef(def).objectoptions) then
                     continue;
                     continue;
+                  if tobjectdef(def).is_unique_objpasdef then
+                    continue;
                   do_write_vmts(tobjectdef(def).symtable,is_global);
                   do_write_vmts(tobjectdef(def).symtable,is_global);
                   { Write also VMT if not done yet }
                   { Write also VMT if not done yet }
                   if not(ds_vmt_written in def.defstates) then
                   if not(ds_vmt_written in def.defstates) then

+ 8 - 4
compiler/pdecl.pas

@@ -674,7 +674,8 @@ implementation
          gentypename,genorgtypename : TIDString;
          gentypename,genorgtypename : TIDString;
          newtype  : ttypesym;
          newtype  : ttypesym;
          sym      : tsym;
          sym      : tsym;
-         hdef     : tdef;
+         hdef,
+         hdef2    : tdef;
          defpos,storetokenpos : tfileposinfo;
          defpos,storetokenpos : tfileposinfo;
          old_block_type : tblock_type;
          old_block_type : tblock_type;
          old_checkforwarddefs: TFPObjectList;
          old_checkforwarddefs: TFPObjectList;
@@ -927,9 +928,11 @@ implementation
                       if is_object(hdef) or
                       if is_object(hdef) or
                          is_class_or_interface_or_dispinterface(hdef) then
                          is_class_or_interface_or_dispinterface(hdef) then
                         begin
                         begin
-                          { just create a child class type; this is
+                          { just create a copy that is a child of the original class class type; this is
                             Delphi-compatible }
                             Delphi-compatible }
-                          hdef:=cobjectdef.create(tobjectdef(hdef).objecttype,genorgtypename,tobjectdef(hdef),true);
+                          hdef2:=tstoreddef(hdef).getcopy;
+                          tobjectdef(hdef2).childof:=tobjectdef(hdef);
+                          hdef:=hdef2;
                         end
                         end
                       else
                       else
                         begin
                         begin
@@ -959,6 +962,7 @@ implementation
                              (tabstractpointerdef(hdef).pointeddef.typ=forwarddef) then
                              (tabstractpointerdef(hdef).pointeddef.typ=forwarddef) then
                             current_module.checkforwarddefs.add(hdef);
                             current_module.checkforwarddefs.add(hdef);
                         end;
                         end;
+
                       include(hdef.defoptions,df_unique);
                       include(hdef.defoptions,df_unique);
                     end;
                     end;
                   if not assigned(hdef.typesym) then
                   if not assigned(hdef.typesym) then
@@ -1114,7 +1118,7 @@ implementation
                       finalize_class_external_status(tobjectdef(hdef));
                       finalize_class_external_status(tobjectdef(hdef));
 
 
                     { Build VMT indexes, skip for type renaming and forward classes }
                     { Build VMT indexes, skip for type renaming and forward classes }
-                    if (hdef.typesym=newtype) and
+                    if not istyperenaming and
                        not(oo_is_forward in tobjectdef(hdef).objectoptions) then
                        not(oo_is_forward in tobjectdef(hdef).objectoptions) then
                       build_vmt(tobjectdef(hdef));
                       build_vmt(tobjectdef(hdef));
 
 

+ 69 - 20
compiler/rgobj.pas

@@ -93,9 +93,10 @@ unit rgobj;
       end;
       end;
 
 
       Treginfoflag=(
       Treginfoflag=(
-        ri_coalesced,   { the register is coalesced with other register }
-        ri_selected,    { the register is put to selectstack }
-        ri_spill_read   { the register contains a value loaded from a spilled register }
+        ri_coalesced,       { the register is coalesced with other register }
+        ri_selected,        { the register is put to selectstack }
+        ri_spill_read,      { the register contains a value loaded from a spilled register }
+        ri_has_initial_loc  { the register has the initial memory location (e.g. a parameter in the stack) }
       );
       );
       Treginfoflagset=set of Treginfoflag;
       Treginfoflagset=set of Treginfoflag;
 
 
@@ -189,6 +190,8 @@ unit rgobj;
         procedure add_edge(u,v:Tsuperregister);
         procedure add_edge(u,v:Tsuperregister);
         { translates a single given imaginary register to it's real register }
         { translates a single given imaginary register to it's real register }
         procedure translate_register(var reg : tregister);
         procedure translate_register(var reg : tregister);
+        { sets the initial memory location of the register }
+        procedure set_reg_initial_location(reg: tregister; const ref: treference);
       protected
       protected
         maxreginfo,
         maxreginfo,
         maxreginfoinc,
         maxreginfoinc,
@@ -293,6 +296,7 @@ unit rgobj;
         function get_live_start(reg : tsuperregister) : tai;
         function get_live_start(reg : tsuperregister) : tai;
         procedure set_live_end(reg : tsuperregister;t : tai);
         procedure set_live_end(reg : tsuperregister;t : tai);
         function get_live_end(reg : tsuperregister) : tai;
         function get_live_end(reg : tsuperregister) : tai;
+        procedure alloc_spillinfo(max_reg: Tsuperregister);
 {$ifdef DEBUG_SPILLCOALESCE}
 {$ifdef DEBUG_SPILLCOALESCE}
         procedure write_spill_stats;
         procedure write_spill_stats;
 {$endif DEBUG_SPILLCOALESCE}
 {$endif DEBUG_SPILLCOALESCE}
@@ -637,10 +641,18 @@ unit rgobj;
           i8086 where indexed memory access instructions allow only
           i8086 where indexed memory access instructions allow only
           few registers as arguments and additionally the calling convention
           few registers as arguments and additionally the calling convention
           provides no general purpose volatile registers.
           provides no general purpose volatile registers.
+          
+          Also spill registers which have the initial memory location
+          and are used only once. This allows to access the memory location
+          directly, without preloading it to a register.
         }
         }
         for i:=first_imaginary to maxreg-1 do
         for i:=first_imaginary to maxreg-1 do
-          if reginfo[i].real_reg_interferences>=usable_registers_cnt then
-            spillednodes.add(i);
+          with reginfo[i] do
+            if (real_reg_interferences>=usable_registers_cnt) or
+               { also spill registers which have the initial memory location
+                 and are used only once }
+               ((ri_has_initial_loc in flags) and (weight<=200)) then
+              spillednodes.add(i);
         if spillednodes.length<>0 then
         if spillednodes.length<>0 then
           begin
           begin
             spill_registers(list,headertai);
             spill_registers(list,headertai);
@@ -859,6 +871,19 @@ unit rgobj;
       end;
       end;
 
 
 
 
+    procedure trgobj.alloc_spillinfo(max_reg: Tsuperregister);
+      var
+        j: longint;
+      begin
+        if Length(spillinfo)<max_reg then
+          begin
+            j:=Length(spillinfo);
+            SetLength(spillinfo,max_reg);
+            fillchar(spillinfo[j],sizeof(spillinfo[0])*(Length(spillinfo)-j),0);
+          end;
+      end;
+
+
     procedure trgobj.add_reg_instruction(instr:Tai;r:tregister;aweight:longint);
     procedure trgobj.add_reg_instruction(instr:Tai;r:tregister;aweight:longint);
       var
       var
         supreg : tsuperregister;
         supreg : tsuperregister;
@@ -2106,7 +2131,20 @@ unit rgobj;
       end;
       end;
 
 
 
 
-    procedure Trgobj.translate_registers(list:TAsmList);
+    procedure trgobj.set_reg_initial_location(reg: tregister; const ref: treference);
+      var
+        supreg: TSuperRegister;
+      begin
+        supreg:=getsupreg(reg);
+        if supreg>=maxreg then
+          internalerror(2020090501);
+        alloc_spillinfo(supreg+1);
+        spillinfo[supreg].spilllocation:=ref;
+        include(reginfo[supreg].flags,ri_has_initial_loc);
+      end;
+
+
+    procedure trgobj.translate_registers(list: TAsmList);
 
 
       function get_reg_name_full(r: tregister): string;
       function get_reg_name_full(r: tregister): string;
         var
         var
@@ -2332,13 +2370,7 @@ unit rgobj;
         writeln('trgobj.spill_registers: Spilling ',spillednodes.length,' nodes');
         writeln('trgobj.spill_registers: Spilling ',spillednodes.length,' nodes');
 {$endif DEBUG_SPILLCOALESCE}
 {$endif DEBUG_SPILLCOALESCE}
         { after each round of spilling, more registers could be used due to allocations for spilling }
         { after each round of spilling, more registers could be used due to allocations for spilling }
-        if Length(spillinfo)<maxreg then
-          begin
-            j:=Length(spillinfo);
-            SetLength(spillinfo,maxreg);
-            fillchar(spillinfo[j],sizeof(spillinfo[0])*(Length(spillinfo)-j),0);
-          end;
-
+        alloc_spillinfo(maxreg);
         { Allocate temps and insert in front of the list }
         { Allocate temps and insert in front of the list }
         templist:=TAsmList.create;
         templist:=TAsmList.create;
         { Safe: this procedure is only called if there are spilled nodes. }
         { Safe: this procedure is only called if there are spilled nodes. }
@@ -2363,13 +2395,17 @@ unit rgobj;
               { Clear all interferences of the spilled register. }
               { Clear all interferences of the spilled register. }
               clear_interferences(t);
               clear_interferences(t);
 
 
-              getnewspillloc:=true;
+              getnewspillloc:=not (ri_has_initial_loc in reginfo[t].flags);
+              if not getnewspillloc then
+                spill_temps^[t]:=spillinfo[t].spilllocation;
 
 
               { check if we can "coalesce" spilled nodes. To do so, it is required that they do not
               { check if we can "coalesce" spilled nodes. To do so, it is required that they do not
                 interfere but are connected by a move instruction
                 interfere but are connected by a move instruction
 
 
                 doing so might save some mem->mem moves }
                 doing so might save some mem->mem moves }
-              if (cs_opt_level3 in current_settings.optimizerswitches) and assigned(reginfo[t].movelist) then
+              if (cs_opt_level3 in current_settings.optimizerswitches) and
+                 getnewspillloc and
+                 assigned(reginfo[t].movelist) then
                 for j:=0 to reginfo[t].movelist^.header.count-1 do
                 for j:=0 to reginfo[t].movelist^.header.count-1 do
                   begin
                   begin
                     x:=Tmoveins(reginfo[t].movelist^.data[j]).x;
                     x:=Tmoveins(reginfo[t].movelist^.data[j]).x;
@@ -2427,6 +2463,17 @@ unit rgobj;
                         supreg:=getsupreg(reg);
                         supreg:=getsupreg(reg);
                         if supregset_in(regs_to_spill_set,supreg) then
                         if supregset_in(regs_to_spill_set,supreg) then
                           begin
                           begin
+                            { Remove loading of the register from its initial memory location
+                              (e.g. load of a stack parameter to the register). }
+                            if (ratype=ra_alloc) and
+                               (ri_has_initial_loc in reginfo[supreg].flags) and
+                               (instr<>nil) then
+                              begin
+                                list.remove(instr);
+                                FreeAndNil(instr);
+                                dec(reginfo[supreg].weight,100);
+                              end;
+                            { Remove the regalloc }
                             q:=Tai(p.next);
                             q:=Tai(p.next);
                             list.remove(p);
                             list.remove(p);
                             p.free;
                             p.free;
@@ -2466,7 +2513,7 @@ unit rgobj;
         {Safe: this procedure is only called if there are spilled nodes.}
         {Safe: this procedure is only called if there are spilled nodes.}
         with spillednodes do
         with spillednodes do
           for i:=0 to length-1 do
           for i:=0 to length-1 do
-            tg.ungettemp(list,spill_temps^[buf^[i]]);
+            tg.ungetiftemp(list,spill_temps^[buf^[i]]);
         freemem(spill_temps);
         freemem(spill_temps);
       end;
       end;
 
 
@@ -2872,7 +2919,7 @@ unit rgobj;
         all_weight,spill_weight,d: double;
         all_weight,spill_weight,d: double;
       begin
       begin
         max_weight:=1;
         max_weight:=1;
-        for i:=0 to high(spillinfo) do
+        for i:=first_imaginary to maxreg-1 do
           with reginfo[i] do
           with reginfo[i] do
             if weight>max_weight then
             if weight>max_weight then
               max_weight:=weight;
               max_weight:=weight;
@@ -2880,12 +2927,14 @@ unit rgobj;
         spillingcounter:=0;
         spillingcounter:=0;
         spill_weight:=0;
         spill_weight:=0;
         all_weight:=0;
         all_weight:=0;
-        for i:=0 to high(spillinfo) do
+        for i:=first_imaginary to maxreg-1 do
           with reginfo[i] do
           with reginfo[i] do
             begin
             begin
-              d:=weight/max_weight*count_uses;
+              d:=weight/max_weight;
               all_weight:=all_weight+d;
               all_weight:=all_weight+d;
-              if spillinfo[i].spilled then
+              if (weight>100) and
+                 (i<=high(spillinfo)) and
+                 spillinfo[i].spilled then
                 begin
                 begin
                   inc(spillingcounter);
                   inc(spillingcounter);
                   spill_weight:=spill_weight+d;
                   spill_weight:=spill_weight+d;

+ 32 - 9
compiler/symdef.pas

@@ -511,6 +511,7 @@ interface
           function  needs_separate_initrtti : boolean;override;
           function  needs_separate_initrtti : boolean;override;
           function  has_non_trivial_init_child(check_parent:boolean):boolean;override;
           function  has_non_trivial_init_child(check_parent:boolean):boolean;override;
           function  rtti_mangledname(rt:trttitype):TSymStr;override;
           function  rtti_mangledname(rt:trttitype):TSymStr;override;
+          function  is_unique_objpasdef: boolean;
           function  vmt_mangledname : TSymStr;
           function  vmt_mangledname : TSymStr;
           function  vmt_def: trecorddef;
           function  vmt_def: trecorddef;
           procedure check_forwards; override;
           procedure check_forwards; override;
@@ -3900,6 +3901,8 @@ implementation
 
 
     constructor tclassrefdef.create(def:tdef);
     constructor tclassrefdef.create(def:tdef);
       begin
       begin
+         while tobjectdef(def).is_unique_objpasdef do
+           def:=tobjectdef(def).childof;
          inherited create(classrefdef,def);
          inherited create(classrefdef,def);
          if df_specialization in tstoreddef(def).defoptions then
          if df_specialization in tstoreddef(def).defoptions then
            genericdef:=cclassrefdef.create(tstoreddef(def).genericdef);
            genericdef:=cclassrefdef.create(tstoreddef(def).genericdef);
@@ -7890,7 +7893,10 @@ implementation
       begin
       begin
         if not(oo_has_vmt in objectoptions) then
         if not(oo_has_vmt in objectoptions) then
           Message1(parser_n_object_has_no_vmt,objrealname^);
           Message1(parser_n_object_has_no_vmt,objrealname^);
-        vmt_mangledname:=make_mangledname('VMT',owner,objname^);
+        if not is_unique_objpasdef then
+          vmt_mangledname:=make_mangledname('VMT',owner,objname^)
+        else
+          vmt_mangledname:=childof.vmt_mangledname;
       end;
       end;
 
 
 
 
@@ -7899,13 +7905,18 @@ implementation
         where: tsymtable;
         where: tsymtable;
         vmttypesym: tsymentry;
         vmttypesym: tsymentry;
       begin
       begin
-        where:=get_top_level_symtable(true);
-        vmttypesym:=where.Find('vmtdef$'+mangledparaname);
-        if not assigned(vmttypesym) or
-           (vmttypesym.typ<>symconst.typesym) or
-           (ttypesym(vmttypesym).typedef.typ<>recorddef) then
-          internalerror(2015052501);
-        result:=trecorddef(ttypesym(vmttypesym).typedef);
+        if not is_unique_objpasdef then
+          begin
+            where:=get_top_level_symtable(true);
+            vmttypesym:=where.Find('vmtdef$'+mangledparaname);
+            if not assigned(vmttypesym) or
+               (vmttypesym.typ<>symconst.typesym) or
+               (ttypesym(vmttypesym).typedef.typ<>recorddef) then
+              internalerror(2015052501);
+            result:=trecorddef(ttypesym(vmttypesym).typedef);
+          end
+        else
+          result:=childof.vmt_def;
       end;
       end;
 
 
 
 
@@ -7971,7 +7982,12 @@ implementation
     function tobjectdef.rtti_mangledname(rt: trttitype): TSymStr;
     function tobjectdef.rtti_mangledname(rt: trttitype): TSymStr;
       begin
       begin
         if not(objecttype in [odt_objcclass,odt_objcprotocol]) then
         if not(objecttype in [odt_objcclass,odt_objcprotocol]) then
-          result:=inherited rtti_mangledname(rt)
+          begin
+            if not is_unique_objpasdef then
+              result:=inherited rtti_mangledname(rt)
+            else
+              result:=childof.rtti_mangledname(rt)
+          end
         else
         else
           begin
           begin
             { necessary in case of a dynamic array of nsobject, or
             { necessary in case of a dynamic array of nsobject, or
@@ -8054,6 +8070,13 @@ implementation
           end;
           end;
       end;
       end;
 
 
+    function tobjectdef.is_unique_objpasdef: boolean;
+        begin
+          result:=
+            (df_unique in defoptions) and
+            is_class_or_interface_or_dispinterface(self)
+        end;
+
 
 
     function tobjectdef.members_need_inittable : boolean;
     function tobjectdef.members_need_inittable : boolean;
       begin
       begin

+ 4 - 0
compiler/symtable.pas

@@ -3607,6 +3607,10 @@ implementation
         formalnameptr,
         formalnameptr,
         foundnameptr: pshortstring;
         foundnameptr: pshortstring;
       begin
       begin
+        while pd.is_unique_objpasdef do
+          begin
+            pd:=pd.childof;
+          end;
         { not a formal definition -> return it }
         { not a formal definition -> return it }
         if not(oo_is_formal in pd.objectoptions) then
         if not(oo_is_formal in pd.objectoptions) then
           begin
           begin

+ 57 - 45
compiler/systems/t_freertos.pas

@@ -96,10 +96,10 @@ begin
   prtobj:='';
   prtobj:='';
 {$else}
 {$else}
   prtobj:='prt0';
   prtobj:='prt0';
-{$endif}
   cprtobj:='cprt0';
   cprtobj:='cprt0';
   if linklibc then
   if linklibc then
     prtobj:=cprtobj;
     prtobj:=cprtobj;
+{$endif}
 
 
   { Open link.res file }
   { Open link.res file }
   LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
   LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
@@ -132,14 +132,18 @@ begin
       LinkRes.AddFileName(s);
       LinkRes.AddFileName(s);
     end;
     end;
 
 
-  { try to add crti and crtbegin if linking to C }
-  if linklibc then
-   begin
-     if librarysearchpath.FindFile('crtbegin.o',false,s) then
-      LinkRes.AddFileName(s);
-     if librarysearchpath.FindFile('crti.o',false,s) then
-      LinkRes.AddFileName(s);
-   end;
+  { xtensa FreeRTOS links always against libc, the runtime needs it }
+  if not(target_info.system in [system_xtensa_freertos]) then
+    begin
+      { try to add crti and crtbegin if linking to C }
+      if linklibc then
+       begin
+         if librarysearchpath.FindFile('crtbegin.o',false,s) then
+          LinkRes.AddFileName(s);
+         if librarysearchpath.FindFile('crti.o',false,s) then
+          LinkRes.AddFileName(s);
+       end;
+    end;
 
 
   while not ObjectFiles.Empty do
   while not ObjectFiles.Empty do
    begin
    begin
@@ -165,50 +169,58 @@ begin
         end;
         end;
     end;
     end;
 
 
-   LinkRes.Add(')');
-
-   { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
-     here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
-   linklibc:=false;
-   while not SharedLibFiles.Empty do
+  { xtensa FreeRTOS links always against libc, the runtime needs it }
+  if not(target_info.system in [system_xtensa_freertos]) then
     begin
     begin
-     S:=SharedLibFiles.GetFirst;
-     if s<>'c' then
+     { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
+       here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
+     linklibc:=false;
+     while not SharedLibFiles.Empty do
       begin
       begin
-       i:=Pos(target_info.sharedlibext,S);
-       if i>0 then
-        Delete(S,i,255);
-       LinkRes.Add('-l'+s);
-      end
-     else
+       S:=SharedLibFiles.GetFirst;
+       if s<>'c' then
+        begin
+         i:=Pos(target_info.sharedlibext,S);
+         if i>0 then
+          Delete(S,i,255);
+         LinkRes.Add('-l'+s);
+        end
+       else
+        begin
+         LinkRes.Add('-l'+s);
+         linklibc:=true;
+        end;
+      end;
+     { be sure that libc&libgcc is the last lib }
+     if linklibc then
       begin
       begin
-       LinkRes.Add('-l'+s);
-       linklibc:=true;
+       LinkRes.Add('-lc');
+       LinkRes.Add('-lgcc');
       end;
       end;
     end;
     end;
-   { be sure that libc&libgcc is the last lib }
-   if linklibc then
+
+  LinkRes.Add(')');
+
+  { xtensa FreeRTOS links always against libc }
+  if not(target_info.system in [system_xtensa_freertos]) then
     begin
     begin
-     LinkRes.Add('-lc');
-     LinkRes.Add('-lgcc');
+      { objects which must be at the end }
+      if linklibc then
+       begin
+         found1:=librarysearchpath.FindFile('crtend.o',false,s1);
+         found2:=librarysearchpath.FindFile('crtn.o',false,s2);
+         if found1 or found2 then
+          begin
+            LinkRes.Add('INPUT(');
+            if found1 then
+             LinkRes.AddFileName(s1);
+            if found2 then
+             LinkRes.AddFileName(s2);
+            LinkRes.Add(')');
+          end;
+       end;
     end;
     end;
 
 
-  { objects which must be at the end }
-  if linklibc then
-   begin
-     found1:=librarysearchpath.FindFile('crtend.o',false,s1);
-     found2:=librarysearchpath.FindFile('crtn.o',false,s2);
-     if found1 or found2 then
-      begin
-        LinkRes.Add('INPUT(');
-        if found1 then
-         LinkRes.AddFileName(s1);
-        if found2 then
-         LinkRes.AddFileName(s2);
-        LinkRes.Add(')');
-      end;
-   end;
-
 {$ifdef ARM}
 {$ifdef ARM}
   with embedded_controllers[current_settings.controllertype] do
   with embedded_controllers[current_settings.controllertype] do
     with linkres do
     with linkres do

+ 32 - 12
compiler/xtensa/cgcpu.pas

@@ -286,7 +286,8 @@ implementation
           (href.index<>NR_NO) or
           (href.index<>NR_NO) or
           ((op=A_L8UI) and ((href.offset<0) or (href.offset>255))) or
           ((op=A_L8UI) and ((href.offset<0) or (href.offset>255))) or
           ((op in [A_L16SI,A_L16UI]) and ((href.offset<0) or (href.offset>510) or (href.offset mod 2<>0))) or
           ((op in [A_L16SI,A_L16UI]) and ((href.offset<0) or (href.offset>510) or (href.offset mod 2<>0))) or
-          ((op=A_L32I) and ((href.offset<0) or (href.offset>1020) or (href.offset mod 4<>0))) then
+          ((op=A_L32I) and ((href.offset<0) or (href.offset>1020) or (href.offset mod 4<>0))) or
+          ((href.base=NR_NO) and (href.index=NR_NO)) then
           fixref(list,href);
           fixref(list,href);
 
 
         list.concat(taicpu.op_reg_ref(op,reg,href));
         list.concat(taicpu.op_reg_ref(op,reg,href));
@@ -329,15 +330,21 @@ implementation
         l : tasmlabel;
         l : tasmlabel;
       begin
       begin
         { create consts entry }
         { create consts entry }
-        if assigned(ref.symbol) or (ref.offset<-2048) or (ref.offset>2047) then
+        if assigned(ref.symbol) or (ref.offset<-2048) or (ref.offset>2047) or
+          ((ref.base=NR_NO) and (ref.index=NR_NO)) then
           begin
           begin
             reference_reset(tmpref,4,[]);
             reference_reset(tmpref,4,[]);
             tmpreg:=NR_NO;
             tmpreg:=NR_NO;
 
 
             { load consts entry }
             { load consts entry }
             tmpreg:=getintregister(list,OS_INT);
             tmpreg:=getintregister(list,OS_INT);
-            tmpref.symbol:=create_data_entry(ref.symbol,ref.offset);
-            list.concat(taicpu.op_reg_ref(A_L32R,tmpreg,tmpref));
+            if ref.symbol=nil then
+              a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg)
+            else
+              begin
+                tmpref.symbol:=create_data_entry(ref.symbol,ref.offset);
+                list.concat(taicpu.op_reg_ref(A_L32R,tmpreg,tmpref));
+              end;
 
 
             if ref.base<>NR_NO then
             if ref.base<>NR_NO then
               begin
               begin
@@ -1053,15 +1060,28 @@ implementation
             tmpreg1  := GetIntRegister(list, OS_INT);
             tmpreg1  := GetIntRegister(list, OS_INT);
             a_load_const_reg(list, OS_INT, Count, countreg);
             a_load_const_reg(list, OS_INT, Count, countreg);
             current_asmdata.getjumplabel(lab);
             current_asmdata.getjumplabel(lab);
-            a_label(list, lab);
-            list.concat(taicpu.op_reg_ref(A_L32I, tmpreg1, src));
-            list.concat(taicpu.op_reg_ref(A_S32I, tmpreg1, dst));
-            list.concat(taicpu.op_reg_reg_const(A_ADDI, src.base, src.base, 4));
-            list.concat(taicpu.op_reg_reg_const(A_ADDI, dst.base, dst.base, 4));
-            list.concat(taicpu.op_reg_reg_const(A_ADDI, countreg, countreg, -1));
-            a_cmp_const_reg_label(list,OS_INT,OC_GT,0,countreg,lab);
+            if CPUXTENSA_HAS_LOOPS in cpu_capabilities[current_settings.cputype] then
+              begin
+                list.concat(taicpu.op_reg_sym(A_LOOP, countreg, lab));
+                list.concat(taicpu.op_reg_ref(A_L32I, tmpreg1, src));
+                list.concat(taicpu.op_reg_ref(A_S32I, tmpreg1, dst));
+                list.concat(taicpu.op_reg_reg_const(A_ADDI, src.base, src.base, 4));
+                list.concat(taicpu.op_reg_reg_const(A_ADDI, dst.base, dst.base, 4));
+                a_label(list, lab);
+              end
+            else
+              begin
+                a_label(list, lab);
+                list.concat(taicpu.op_reg_ref(A_L32I, tmpreg1, src));
+                list.concat(taicpu.op_reg_ref(A_S32I, tmpreg1, dst));
+                list.concat(taicpu.op_reg_reg_const(A_ADDI, src.base, src.base, 4));
+                list.concat(taicpu.op_reg_reg_const(A_ADDI, dst.base, dst.base, 4));
+                list.concat(taicpu.op_reg_reg_const(A_ADDI, countreg, countreg, -1));
+                a_cmp_const_reg_label(list,OS_INT,OC_NE,0,countreg,lab);
+                { keep the registers alive }
+                list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
+              end;
             { keep the registers alive }
             { keep the registers alive }
-            list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
             list.concat(taicpu.op_reg_reg(A_MOV,src.base,src.base));
             list.concat(taicpu.op_reg_reg(A_MOV,src.base,src.base));
             list.concat(taicpu.op_reg_reg(A_MOV,dst.base,dst.base));
             list.concat(taicpu.op_reg_reg(A_MOV,dst.base,dst.base));
             len := len mod 4;
             len := len mod 4;

+ 3 - 2
compiler/xtensa/cpuinfo.pas

@@ -139,7 +139,8 @@ Const
         CPUXTENSA_HAS_SEXT,
         CPUXTENSA_HAS_SEXT,
         CPUXTENSA_HAS_BOOLEAN_OPTION,
         CPUXTENSA_HAS_BOOLEAN_OPTION,
         CPUXTENSA_HAS_MUL32HIGH,
         CPUXTENSA_HAS_MUL32HIGH,
-        CPUXTENSA_HAS_DIV
+        CPUXTENSA_HAS_DIV,
+        CPUXTENSA_HAS_LOOPS
       );
       );
 
 
    tfpuflags =
    tfpuflags =
@@ -153,7 +154,7 @@ Const
      (
      (
        { cpu_none     } [],
        { cpu_none     } [],
        { cpu_lx106    } [],
        { cpu_lx106    } [],
-       { cpu_lx6      } [CPUXTENSA_REGWINDOW, CPUXTENSA_HAS_SEXT, CPUXTENSA_HAS_BOOLEAN_OPTION, CPUXTENSA_HAS_MUL32HIGH, CPUXTENSA_HAS_DIV]
+       { cpu_lx6      } [CPUXTENSA_REGWINDOW, CPUXTENSA_HAS_SEXT, CPUXTENSA_HAS_BOOLEAN_OPTION, CPUXTENSA_HAS_MUL32HIGH, CPUXTENSA_HAS_DIV, CPUXTENSA_HAS_LOOPS]
      );
      );
 
 
    fpu_capabilities : array[tfputype] of set of tfpuflags =
    fpu_capabilities : array[tfputype] of set of tfpuflags =

+ 24 - 56
compiler/xtensa/cpupara.pas

@@ -80,61 +80,28 @@ unit cpupara;
 
 
 
 
     function getparaloc(p : tdef) : tcgloc;
     function getparaloc(p : tdef) : tcgloc;
-
       begin
       begin
-         { Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
-           if push_addr_param for the def is true
-         }
-         case p.typ of
-            orddef:
-              result:=LOC_REGISTER;
-            floatdef:
-              result:=LOC_REGISTER;
-            enumdef:
-              result:=LOC_REGISTER;
-            pointerdef:
-              result:=LOC_REGISTER;
-            formaldef:
-              result:=LOC_REGISTER;
-            classrefdef:
-              result:=LOC_REGISTER;
-            procvardef:
-              result:=LOC_REGISTER;
-            recorddef:
-              if p.size>24 then
-                result:=LOC_REFERENCE
-              else
-                result:=LOC_REGISTER;
-            objectdef:
-              if is_object(p) and (p.size>24) then
-                result:=LOC_REFERENCE
-              else
-                result:=LOC_REGISTER;
-            stringdef:
-              if is_shortstring(p) or is_longstring(p) then
-                result:=LOC_REFERENCE
-              else
-                result:=LOC_REGISTER;
-            filedef:
-              result:=LOC_REGISTER;
-            arraydef:
-              if is_dynamic_array(p) or (p.size<=24) then
-                getparaloc:=LOC_REGISTER
-              else
-                result:=LOC_REFERENCE;
-            setdef:
-              if is_smallset(p) then
-                result:=LOC_REGISTER
-              else
-                result:=LOC_REFERENCE;
-            variantdef:
-              result:=LOC_REGISTER;
-            { avoid problems with errornous definitions }
-            errordef:
-              result:=LOC_REGISTER;
-            else
-              internalerror(2020082501);
-         end;
+        case p.typ of
+          orddef,
+          floatdef,
+          enumdef,
+          pointerdef,
+          formaldef,
+          classrefdef,
+          procvardef,
+          recorddef,
+          objectdef,
+          stringdef,
+          filedef,
+          arraydef,
+          setdef,
+          variantdef,
+          { avoid problems with errornous definitions }
+          errordef:
+            result:=LOC_REGISTER;
+          else
+            internalerror(2020082501);
+        end;
       end;
       end;
 
 
 
 
@@ -379,7 +346,7 @@ unit cpupara;
 
 
         locpara:=getparaloc(paradef);
         locpara:=getparaloc(paradef);
 
 
-        if (locpara=LOC_REGISTER) and ((maxintreg-curintreg+1)*4<paradef.size) then
+        if (maxintreg-curintreg+1)*4<paralen then
           begin
           begin
             locpara:=LOC_REFERENCE;
             locpara:=LOC_REFERENCE;
             curintreg:=maxintreg+1;
             curintreg:=maxintreg+1;
@@ -389,7 +356,7 @@ unit cpupara;
         loc.size:=paracgsize;
         loc.size:=paracgsize;
         loc.intsize:=paralen;
         loc.intsize:=paralen;
         loc.def:=paradef;
         loc.def:=paradef;
-        if (locpara=LOC_REGISTER) and (is_64bit(paradef)) and
+        if (locpara=LOC_REGISTER) and (paradef.alignment>4) and
            odd(curintreg-RS_A2) then
            odd(curintreg-RS_A2) then
           inc(curintreg);
           inc(curintreg);
         if (paralen = 0) then
         if (paralen = 0) then
@@ -455,6 +422,7 @@ unit cpupara;
                  else
                  else
                    paraloc^.reference.index:=current_procinfo.framepointer;
                    paraloc^.reference.index:=current_procinfo.framepointer;
 
 
+                 cur_stack_offset:=align(cur_stack_offset,paradef.alignment);
                  paraloc^.reference.offset:=cur_stack_offset;
                  paraloc^.reference.offset:=cur_stack_offset;
 
 
                  inc(cur_stack_offset,align(paralen,4));
                  inc(cur_stack_offset,align(paralen,4));

+ 4 - 1
compiler/xtensa/ncpumat.pas

@@ -236,7 +236,10 @@ implementation
               OS_32:
               OS_32:
                 cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_XOR,OS_32,tcgint($80000000),left.location.register,location.register);
                 cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_XOR,OS_32,tcgint($80000000),left.location.register,location.register);
               OS_64:
               OS_64:
-                cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_XOR,OS_32,tcgint($80000000),left.location.registerhi,location.registerhi);
+                begin
+                  cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_XOR,OS_32,tcgint($80000000),left.location.registerhi,location.registerhi);
+                  cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,left.location.register64.reglo,location.register64.reglo);
+                end;
             else
             else
               internalerror(2014033101);
               internalerror(2014033101);
             end;
             end;

+ 101 - 25
packages/pastojs/src/fppas2js.pp

@@ -1516,7 +1516,7 @@ type
       override;
       override;
     procedure SpecializeGenericImpl(SpecializedItem: TPRSpecializedItem);
     procedure SpecializeGenericImpl(SpecializedItem: TPRSpecializedItem);
       override;
       override;
-    function SpecializeNeedsDelay(SpecializedItem: TPRSpecializedItem): TPasElement; virtual;
+    function SpecializeParamsNeedDelay(SpecializedItem: TPRSpecializedItem): TPasElement; virtual;
     function CreateLongName(SpecializedItem: TPRSpecializedItem): string; virtual;
     function CreateLongName(SpecializedItem: TPRSpecializedItem): string; virtual;
   protected
   protected
     const
     const
@@ -1909,6 +1909,7 @@ type
     Procedure FindAvailableLocalName(var aName: string; JSExpr: TJSElement);
     Procedure FindAvailableLocalName(var aName: string; JSExpr: TJSElement);
     Function GetImplJSProcScope(El: TPasElement; Src: TJSSourceElements;
     Function GetImplJSProcScope(El: TPasElement; Src: TJSSourceElements;
       AContext: TConvertContext): TPas2JSProcedureScope;
       AContext: TConvertContext): TPas2JSProcedureScope;
+    Function SpecializeNeedsDelay(El: TPasGenericType; AContext: TConvertContext): boolean; virtual;
     // Never create an element manually, always use the below functions
     // Never create an element manually, always use the below functions
     Function CreateElement(C: TJSElementClass; Src: TPasElement): TJSElement; virtual;
     Function CreateElement(C: TJSElementClass; Src: TPasElement): TJSElement; virtual;
     Function CreateFreeOrNewInstanceExpr(Ref: TResolvedReference;
     Function CreateFreeOrNewInstanceExpr(Ref: TResolvedReference;
@@ -5027,7 +5028,7 @@ begin
 
 
   El:=SpecializedItem.SpecializedEl;
   El:=SpecializedItem.SpecializedEl;
   if (El is TPasGenericType)
   if (El is TPasGenericType)
-      and (SpecializeNeedsDelay(SpecializedItem)<>nil) then
+      and (SpecializeParamsNeedDelay(SpecializedItem)<>nil) then
     TPas2JSResolverHub(Hub).AddJSDelaySpecialize(TPasGenericType(El));
     TPas2JSResolverHub(Hub).AddJSDelaySpecialize(TPasGenericType(El));
 
 
   if El is TPasMembersType then
   if El is TPasMembersType then
@@ -5044,7 +5045,7 @@ begin
     end;
     end;
 end;
 end;
 
 
-function TPas2JSResolver.SpecializeNeedsDelay(
+function TPas2JSResolver.SpecializeParamsNeedDelay(
   SpecializedItem: TPRSpecializedItem): TPasElement;
   SpecializedItem: TPRSpecializedItem): TPasElement;
 // finds first specialize param defined later than the generic
 // finds first specialize param defined later than the generic
 // For example: generic in the unit interface, param in implementation
 // For example: generic in the unit interface, param in implementation
@@ -14729,7 +14730,7 @@ var
   C: TClass;
   C: TClass;
   AssignSt: TJSSimpleAssignStatement;
   AssignSt: TJSSimpleAssignStatement;
   NeedInitFunction, HasConstructor, IsJSFunction, NeedClassExt,
   NeedInitFunction, HasConstructor, IsJSFunction, NeedClassExt,
-    SpecializeNeedsDelay: Boolean;
+    SpecializeDelay: Boolean;
   Proc: TPasProcedure;
   Proc: TPasProcedure;
 begin
 begin
   Result:=nil;
   Result:=nil;
@@ -14760,14 +14761,14 @@ begin
       end;
       end;
     FreeAndNil(Scope.MsgIntToProc);
     FreeAndNil(Scope.MsgIntToProc);
     FreeAndNil(Scope.MsgStrToProc);
     FreeAndNil(Scope.MsgStrToProc);
-    SpecializeNeedsDelay:=aResolver.SpecializeNeedsDelay(Scope.SpecializedFromItem)<>nil;
+    SpecializeDelay:=SpecializeNeedsDelay(El,AContext);
     end
     end
   else
   else
     begin
     begin
     Scope:=nil;
     Scope:=nil;
     IsTObject:=(El.AncestorType=nil) and (El.ObjKind=okClass) and SameText(El.Name,'TObject');
     IsTObject:=(El.AncestorType=nil) and (El.ObjKind=okClass) and SameText(El.Name,'TObject');
     Ancestor:=El.AncestorType;
     Ancestor:=El.AncestorType;
-    SpecializeNeedsDelay:=false;
+    SpecializeDelay:=false;
     end;
     end;
 
 
   // create call 'rtl.createClass(' or 'rtl.createInterface('
   // create call 'rtl.createClass(' or 'rtl.createInterface('
@@ -14874,7 +14875,7 @@ begin
         end;
         end;
 
 
       // add class members: types and class vars
       // add class members: types and class vars
-      if SpecializeNeedsDelay then
+      if SpecializeDelay then
         DelayFuncContext:=CreateDelayedInitFunction(El,Src,FuncContext,DelaySrc);
         DelayFuncContext:=CreateDelayedInitFunction(El,Src,FuncContext,DelaySrc);
       if El.ObjKind in ([okClass]+okAllHelpers) then
       if El.ObjKind in ([okClass]+okAllHelpers) then
         begin
         begin
@@ -14912,7 +14913,7 @@ begin
             RaiseNotSupported(P,FuncContext,20161221233338);
             RaiseNotSupported(P,FuncContext,20161221233338);
           if NewEl<>nil then
           if NewEl<>nil then
             begin
             begin
-            if SpecializeNeedsDelay and not (P is TPasProcedure) then
+            if SpecializeDelay and not (P is TPasProcedure) then
               AddToSourceElements(DelaySrc,NewEl)
               AddToSourceElements(DelaySrc,NewEl)
             else
             else
               AddToSourceElements(Src,NewEl);
               AddToSourceElements(Src,NewEl);
@@ -14980,7 +14981,7 @@ begin
         AddClassMessageIds(El,Src,FuncContext,pbivnMessageInt);
         AddClassMessageIds(El,Src,FuncContext,pbivnMessageInt);
         AddClassMessageIds(El,Src,FuncContext,pbivnMessageStr);
         AddClassMessageIds(El,Src,FuncContext,pbivnMessageStr);
         // add RTTI init function
         // add RTTI init function
-        if SpecializeNeedsDelay then
+        if SpecializeDelay then
           AddClassRTTI(El,DelaySrc,DelayFuncContext)
           AddClassRTTI(El,DelaySrc,DelayFuncContext)
         else
         else
           AddClassRTTI(El,Src,FuncContext);
           AddClassRTTI(El,Src,FuncContext);
@@ -15478,7 +15479,7 @@ var
   Prop: TJSObjectLiteralElement;
   Prop: TJSObjectLiteralElement;
   aResolver: TPas2JSResolver;
   aResolver: TPas2JSResolver;
   Scope: TPas2JSProcTypeScope;
   Scope: TPas2JSProcTypeScope;
-  SpecializeNeedsDelay: Boolean;
+  SpecializeDelay: Boolean;
   FuncSt: TJSFunctionDeclarationStatement;
   FuncSt: TJSFunctionDeclarationStatement;
   AssignSt: TJSSimpleAssignStatement;
   AssignSt: TJSSimpleAssignStatement;
 begin
 begin
@@ -15498,8 +15499,7 @@ begin
     RaiseNotSupported(El,AContext,20181231112029);
     RaiseNotSupported(El,AContext,20181231112029);
 
 
   Scope:=El.CustomData as TPas2JSProcTypeScope;
   Scope:=El.CustomData as TPas2JSProcTypeScope;
-  SpecializeNeedsDelay:=(Scope<>nil)
-           and (aResolver.SpecializeNeedsDelay(Scope.SpecializedFromItem)<>nil);
+  SpecializeDelay:=(Scope<>nil) and SpecializeNeedsDelay(El,AContext);
 
 
   // module.$rtti.$ProcVar("name",function(){})
   // module.$rtti.$ProcVar("name",function(){})
   if El.IsReferenceTo then
   if El.IsReferenceTo then
@@ -15514,7 +15514,7 @@ begin
     Prop:=Obj.Elements.AddElement;
     Prop:=Obj.Elements.AddElement;
     InnerCall:=CreateCallExpression(El);
     InnerCall:=CreateCallExpression(El);
 
 
-    if SpecializeNeedsDelay then
+    if SpecializeDelay then
       begin
       begin
       Prop.Name:=TJSString(GetBIName(pbivnRTTIProc_InitSpec));
       Prop.Name:=TJSString(GetBIName(pbivnRTTIProc_InitSpec));
       // init: function(){ this.procsig = rtl.newTIProcSignature(...) }
       // init: function(){ this.procsig = rtl.newTIProcSignature(...) }
@@ -15610,7 +15610,7 @@ var
 var
 var
   aResolver: TPas2JSResolver;
   aResolver: TPas2JSResolver;
   Scope: TPas2JSArrayScope;
   Scope: TPas2JSArrayScope;
-  SpecializeNeedsDelay: Boolean;
+  SpecializeDelay: Boolean;
   AssignSt: TJSSimpleAssignStatement;
   AssignSt: TJSSimpleAssignStatement;
   CallName, ArrName: String;
   CallName, ArrName: String;
   Obj: TJSObjectLiteral;
   Obj: TJSObjectLiteral;
@@ -15644,8 +15644,7 @@ begin
   {$ENDIF}
   {$ENDIF}
 
 
   Scope:=El.CustomData as TPas2JSArrayScope;
   Scope:=El.CustomData as TPas2JSArrayScope;
-  SpecializeNeedsDelay:=(Scope<>nil)
-           and (aResolver.SpecializeNeedsDelay(Scope.SpecializedFromItem)<>nil);
+  SpecializeDelay:=(Scope<>nil) and (SpecializeNeedsDelay(El,AContext));
 
 
   ProcScope:=nil;
   ProcScope:=nil;
   Src:=nil;
   Src:=nil;
@@ -15793,7 +15792,7 @@ begin
         until false;
         until false;
         end;
         end;
       // eltype: ref
       // eltype: ref
-      if not SpecializeNeedsDelay then
+      if not SpecializeDelay then
         begin
         begin
         Prop:=Obj.Elements.AddElement;
         Prop:=Obj.Elements.AddElement;
         Prop.Name:=TJSString(GetBIName(pbivnRTTIArray_ElType));
         Prop.Name:=TJSString(GetBIName(pbivnRTTIArray_ElType));
@@ -16823,6 +16822,7 @@ var
   aResolver: TPas2JSResolver;
   aResolver: TPas2JSResolver;
 begin
 begin
   if not IsElementUsed(El) then exit;
   if not IsElementUsed(El) then exit;
+  if not SpecializeNeedsDelay(El,AContext) then exit;
   C:=El.ClassType;
   C:=El.ClassType;
   if (C=TPasRecordType)
   if (C=TPasRecordType)
       or (C=TPasClassType) then
       or (C=TPasClassType) then
@@ -22495,6 +22495,84 @@ begin
   Result:=AContext.Resolver.GetTopLvlProcScope(El);
   Result:=AContext.Resolver.GetTopLvlProcScope(El);
 end;
 end;
 
 
+function TPasToJSConverter.SpecializeNeedsDelay(El: TPasGenericType;
+  AContext: TConvertContext): boolean;
+var
+  SpecItem: TPRSpecializedItem;
+  C: TClass;
+  Members: TFPList;
+  ChildEl: TPasElement;
+  PasVar: TPasVariable;
+  aResolver: TPas2JSResolver;
+  PasVarType: TPasType;
+  IsRecord, NeedInitFunction: Boolean;
+  aClass: TPasClassType;
+  ClassScope: TPas2JSClassScope;
+  IntfKind: String;
+  i: Integer;
+begin
+  Result:=false;
+  aResolver:=AContext.Resolver;
+  if aResolver=nil then exit;
+  if not (El.CustomData is TPasGenericScope) then exit;
+  SpecItem:=TPasGenericScope(El.CustomData).SpecializedFromItem;
+  if aResolver.SpecializeParamsNeedDelay(SpecItem)=nil then
+    exit; // params are declared in front of generic -> no need to delay
+
+  if HasTypeInfo(El,AContext) then
+    exit(true); // RTTI -> delay needed
+
+  C:=El.ClassType;
+  if El.InheritsFrom(TPasMembersType) then
+    begin
+    IsRecord:=C=TPasRecordType;
+
+    if C=TPasClassType then
+      begin
+      aClass:=TPasClassType(El);
+      ClassScope:=TPas2JSClassScope(El.CustomData);
+      if aClass.ObjKind=okInterface then
+        begin
+        IntfKind:='';
+        if (ClassScope.AncestorScope=nil) and (not (coNoTypeInfo in Options)) then
+          case aClass.InterfaceType of
+          citCom: IntfKind:='com';
+          citCorba: ; // default
+          else
+            RaiseNotSupported(El,AContext,20200905132130);
+          end;
+        NeedInitFunction:=(pcsfPublished in ClassScope.Flags) or (IntfKind<>'');
+        if not NeedInitFunction then
+          exit; // interface without init function -> no need to delay
+        end;
+      end;
+
+    Members:=TPasMembersType(El).Members;
+    for i:=0 to Members.Count-1 do
+      begin
+      ChildEl:=TPasElement(Members[i]);
+      if not IsElementUsed(ChildEl) then continue;
+      if ChildEl is TPasVariable then
+        begin
+        PasVar:=TPasVariable(ChildEl);
+        if ChildEl.ClassType=TPasConst then
+        else if ChildEl.ClassType=TPasVariable then
+          begin
+          if (not IsRecord) and (PasVar.VarModifiers*[vmClass, vmStatic]=[]) then
+            continue; // class field -> no delay needed
+          end
+        else
+          continue;
+        PasVarType:=aResolver.ResolveAliasType(PasVar.VarType);
+        if (PasVarType.ClassType=TPasRecordType) then
+          exit(true) // global record -> needs delay (Eventually: check if it uses one of the after params)
+        else if (PasVarType.ClassType=TPasArrayType) and (length(TPasArrayType(PasVarType).Ranges)>0) then
+          exit(true); // global static array -> needs delay (Eventually: check if it uses one of the after params)
+        end;
+      end;
+    end;
+end;
+
 function TPasToJSConverter.CreateUnary(Members: array of string; E: TJSElement): TJSUnary;
 function TPasToJSConverter.CreateUnary(Members: array of string; E: TJSElement): TJSUnary;
 var
 var
   unary: TJSUnary;
   unary: TJSUnary;
@@ -24986,7 +25064,6 @@ function TPasToJSConverter.ConvertRecordType(El: TPasRecordType;
   AContext: TConvertContext): TJSElement;
   AContext: TConvertContext): TJSElement;
 var
 var
   aResolver: TPas2JSResolver;
   aResolver: TPas2JSResolver;
-  RecScope: TPas2JSRecordScope;
   DelaySrc: TJSSourceElements;
   DelaySrc: TJSSourceElements;
   DelayFuncContext: TFunctionContext;
   DelayFuncContext: TFunctionContext;
   Call: TJSCallExpression;
   Call: TJSCallExpression;
@@ -25001,7 +25078,7 @@ var
   PasVar: TPasVariable;
   PasVar: TPasVariable;
   PasVarType: TPasType;
   PasVarType: TPasType;
   NewFields, Vars, Methods: TFPList;
   NewFields, Vars, Methods: TFPList;
-  ok, IsComplex, SpecializeNeedsDelay: Boolean;
+  ok, IsComplex, SpecializeDelay: Boolean;
   VarSt: TJSVariableStatement;
   VarSt: TJSVariableStatement;
 begin
 begin
   Result:=nil;
   Result:=nil;
@@ -25020,8 +25097,7 @@ begin
   DelayFuncContext:=nil;
   DelayFuncContext:=nil;
   ok:=false;
   ok:=false;
   try
   try
-    RecScope:=TPas2JSRecordScope(El.CustomData);
-    SpecializeNeedsDelay:=aResolver.SpecializeNeedsDelay(RecScope.SpecializedFromItem)<>nil;
+    SpecializeDelay:=SpecializeNeedsDelay(El,AContext);
 
 
     // rtl.recNewT()
     // rtl.recNewT()
     Call:=CreateCallExpression(El);
     Call:=CreateCallExpression(El);
@@ -25076,7 +25152,7 @@ begin
     Vars:=TFPList.Create;
     Vars:=TFPList.Create;
     Methods:=TFPList.Create;
     Methods:=TFPList.Create;
     IsComplex:=false;
     IsComplex:=false;
-    if SpecializeNeedsDelay then
+    if SpecializeDelay then
       DelayFuncContext:=CreateDelayedInitFunction(El,Src,FuncContext,DelaySrc);
       DelayFuncContext:=CreateDelayedInitFunction(El,Src,FuncContext,DelaySrc);
     for i:=0 to El.Members.Count-1 do
     for i:=0 to El.Members.Count-1 do
       begin
       begin
@@ -25088,7 +25164,7 @@ begin
       if C=TPasVariable then
       if C=TPasVariable then
         begin
         begin
         PasVar:=TPasVariable(P);
         PasVar:=TPasVariable(P);
-        if ClassVarModifiersType*PasVar.VarModifiers*[vmClass, vmStatic]<>[] then
+        if PasVar.VarModifiers*[vmClass, vmStatic]<>[] then
           IsComplex:=true
           IsComplex:=true
         else if aResolver<>nil then
         else if aResolver<>nil then
           begin
           begin
@@ -25151,7 +25227,7 @@ begin
         RaiseNotSupported(P,FuncContext,20190105105436);
         RaiseNotSupported(P,FuncContext,20190105105436);
       if NewEl<>nil then
       if NewEl<>nil then
         begin
         begin
-        if SpecializeNeedsDelay and not (P is TPasProcedure) then
+        if SpecializeDelay and not (P is TPasProcedure) then
           AddToSourceElements(DelaySrc,NewEl)
           AddToSourceElements(DelaySrc,NewEl)
         else
         else
           AddToSourceElements(Src,NewEl);
           AddToSourceElements(Src,NewEl);
@@ -25178,7 +25254,7 @@ begin
     // add RTTI init function
     // add RTTI init function
     if (aResolver<>nil) and HasTypeInfo(El,FuncContext) then
     if (aResolver<>nil) and HasTypeInfo(El,FuncContext) then
       begin
       begin
-      if SpecializeNeedsDelay then
+      if SpecializeDelay then
         CreateRecordRTTI(El,DelaySrc,DelayFuncContext)
         CreateRecordRTTI(El,DelaySrc,DelayFuncContext)
       else
       else
         CreateRecordRTTI(El,Src,FuncContext);
         CreateRecordRTTI(El,Src,FuncContext);

+ 10 - 3
rtl/objpas/sysutils/fmtflt.inc

@@ -298,11 +298,13 @@ var
   Function FormatExponent(ASign: FChar; aExponent: Integer) : FString;
   Function FormatExponent(ASign: FChar; aExponent: Integer) : FString;
 
 
   begin
   begin
-    Result:=IntToStr(aExponent);
+    if E = 0 then
+      aExponent := 0;
+    Result:=IntToStr(Abs(aExponent));
     Result:=StringOfChar('0',ExpSize-Length(Result))+Result;
     Result:=StringOfChar('0',ExpSize-Length(Result))+Result;
     if (aExponent<0) then
     if (aExponent<0) then
       Result:='-'+Result
       Result:='-'+Result
-    else if (aExponent>0) and (aSign='+') then
+    else if (aExponent>=0) and (aSign='+') then
       Result:=aSign+Result;
       Result:=aSign+Result;
   end;
   end;
 
 
@@ -383,7 +385,12 @@ begin
                 Inc(I);
                 Inc(I);
               end;
               end;
             end;
             end;
-          end;  
+          end
+        else if I< SectionLength Then
+          begin
+          inc(I);
+          ToResult(Section[i]);
+          end;
         end;
         end;
       else
       else
         ToResult(C);
         ToResult(C);

+ 193 - 0
tests/test/units/sysutils/tw37374.pp

@@ -0,0 +1,193 @@
+program formatfloat_test;
+
+uses
+  SysUtils//, MyFormatFloat
+  ;
+
+var
+  fails: Integer = 0;
+  testCount: Integer = 0;
+
+  procedure Test(AFormat: String; AValue: Double; AResult: String);
+  var
+    s: String;
+  begin
+    s := FormatFloat(AFormat, AValue);
+    if s <> AResult then
+    begin
+      WriteLn('Format(' + AFormat + ', ', AValue:0:6, ') --> ', s, '; SHOULD BE: ', AResult);
+      inc(fails);
+    end;
+    inc(testCount);
+  end;
+
+const
+  VALUES: array[0..4] of Double = (0, 0.00001234, 0.123456, 1.23456, 1123.4567);
+var
+  fmt: String;
+
+begin
+  DefaultFormatSettings.DecimalSeparator := '.';
+  DefaultFormatSettings.ThousandSeparator := ',';
+
+  fmt := '0.00';
+  Test(fmt, VALUES[0], '0.00');
+  Test(fmt, VALUES[1], '0.00');
+  Test(fmt, VALUES[2], '0.12');
+  Test(fmt, VALUES[3], '1.23');
+  Test(fmt, VALUES[4], '1123.46');
+  Test(fmt, -VALUES[1], '-0.00');
+  Test(fmt, -VALUES[2], '-0.12');
+  Test(fmt, -VALUES[3], '-1.23');
+  Test(fmt, -VALUES[4], '-1123.46');
+
+  fmt := '.00';
+  Test(fmt, VALUES[0], '.00');
+  Test(fmt, VALUES[1], '.00');
+  Test(fmt, VALUES[2], '.12');
+  Test(fmt, VALUES[3], '1.23');
+  Test(fmt, VALUES[4], '1123.46');
+  Test(fmt, -VALUES[1], '-.00');
+  Test(fmt, -VALUES[2], '-.12');
+  Test(fmt, -VALUES[3], '-1.23');
+  Test(fmt, -VALUES[4], '-1123.46');
+
+  fmt := '0.00000###';
+  Test(fmt, VALUES[0], '0.00000');
+  Test(fmt, VALUES[1], '0.00001234');
+  Test(fmt, VALUES[2], '0.123456');
+  Test(fmt, VALUES[3], '1.23456');
+  Test(fmt, VALUES[4], '1123.45670');
+  Test(fmt, -VALUES[1], '-0.00001234');
+  Test(fmt, -VALUES[2], '-0.123456');
+  Test(fmt, -VALUES[3], '-1.23456');
+  Test(fmt, -VALUES[4], '-1123.45670');
+
+  fmt := '000';
+  Test(fmt, VALUES[0], '000');
+  Test(fmt, VALUES[1], '000');
+  Test(fmt, VALUES[2], '000');
+  Test(fmt, VALUES[3], '001');
+  Test(fmt, VALUES[4], '1123');
+  Test(fmt, -VALUES[1], '-000');
+  Test(fmt, -VALUES[2], '-000');
+  Test(fmt, -VALUES[3], '-001');
+  Test(fmt, -VALUES[4], '-1123');
+
+  fmt := '0.00E+00';
+  Test(fmt, VALUES[0], '0.00E+00');
+  Test(fmt, VALUES[1], '1.23E-05');
+  Test(fmt, VALUES[2], '1.23E-01');
+  Test(fmt, VALUES[3], '1.23E+00');
+  Test(fmt, VALUES[4], '1.12E+03');
+  Test(fmt, -VALUES[1], '-1.23E-05');
+  Test(fmt, -VALUES[2], '-1.23E-01');
+  Test(fmt, -VALUES[3], '-1.23E+00');
+  Test(fmt, -VALUES[4], '-1.12E+03');
+
+  fmt := '0.00E-00';
+  Test(fmt, VALUES[0], '0.00E00');
+  Test(fmt, VALUES[1], '1.23E-05');
+  Test(fmt, VALUES[2], '1.23E-01');
+  Test(fmt, VALUES[3], '1.23E00');
+  Test(fmt, VALUES[4], '1.12E03');
+  Test(fmt, -VALUES[1], '-1.23E-05');
+  Test(fmt, -VALUES[2], '-1.23E-01');
+  Test(fmt, -VALUES[3], '-1.23E00');
+  Test(fmt, -VALUES[4], '-1.12E03');
+
+  fmt := '0.00 EUR';
+  Test(fmt, VALUES[0], '0.00 EUR');
+  Test(fmt, VALUES[1], '0.00 EUR');
+  Test(fmt, VALUES[2], '0.12 EUR');
+  Test(fmt, VALUES[3], '1.23 EUR');
+  Test(fmt, VALUES[4], '1123.46 EUR');
+  Test(fmt, -VALUES[1], '-0.00 EUR');
+  Test(fmt, -VALUES[2], '-0.12 EUR');
+  Test(fmt, -VALUES[3], '-1.23 EUR');
+  Test(fmt, -VALUES[4], '-1123.46 EUR');
+
+  fmt := '0.00 "EUR"';
+  Test(fmt, VALUES[0], '0.00 EUR');
+  Test(fmt, VALUES[1], '0.00 EUR');
+  Test(fmt, VALUES[2], '0.12 EUR');
+  Test(fmt, VALUES[3], '1.23 EUR');
+  Test(fmt, VALUES[4], '1123.46 EUR');
+  Test(fmt, -VALUES[1], '-0.00 EUR');
+  Test(fmt, -VALUES[2], '-0.12 EUR');
+  Test(fmt, -VALUES[3], '-1.23 EUR');
+  Test(fmt, -VALUES[4], '-1123.46 EUR');
+
+  fmt := '0.00"E+00"';
+  Test(fmt, VALUES[0], '0.00E+00');
+  Test(fmt, VALUES[1], '0.00E+00');
+  Test(fmt, VALUES[2], '0.12E+00');
+  Test(fmt, VALUES[3], '1.23E+00');
+  Test(fmt, VALUES[4], '1123.46E+00');
+  Test(fmt, -VALUES[1], '-0.00E+00');
+  Test(fmt, -VALUES[2], '-0.12E+00');
+  Test(fmt, -VALUES[3], '-1.23E+00');
+  Test(fmt, -VALUES[4], '-1123.46E+00');
+
+  fmt := '#,##0.0';
+  Test(fmt, VALUES[0], '0.0');
+  Test(fmt, VALUES[1], '0.0');
+  Test(fmt, VALUES[2], '0.1');
+  Test(fmt, VALUES[3], '1.2');
+  Test(fmt, VALUES[4], '1,123.5');
+  Test(fmt, -VALUES[1], '-0.0');
+  Test(fmt, -VALUES[2], '-0.1');
+  Test(fmt, -VALUES[3], '-1.2');
+  Test(fmt, -VALUES[4], '-1,123.5');
+
+  fmt := ',0.0';
+  Test(fmt, VALUES[0], '0.0');
+  Test(fmt, VALUES[1], '0.0');
+  Test(fmt, VALUES[2], '0.1');
+  Test(fmt, VALUES[3], '1.2');
+  Test(fmt, VALUES[4], '1,123.5');
+  Test(fmt, -VALUES[1], '-0.0');
+  Test(fmt, -VALUES[2], '-0.1');
+  Test(fmt, -VALUES[3], '-1.2');
+  Test(fmt, -VALUES[4], '-1,123.5');
+
+  fmt := '#,##0.00;(#,##0.00);zero';
+  Test(fmt, VALUES[0], 'zero');
+  Test(fmt, VALUES[1], '0.00');
+  Test(fmt, VALUES[2], '0.12');
+  Test(fmt, VALUES[3], '1.23');
+  Test(fmt, VALUES[4], '1,123.46');
+  Test(fmt, -VALUES[1], '(0.00)');
+  Test(fmt, -VALUES[2], '(0.12)');
+  Test(fmt, -VALUES[3], '(1.23)');
+  Test(fmt, -VALUES[4], '(1,123.46)');
+
+  fmt := '#,##0.00 EUR;(#,##0.00 EUR);zero';
+  Test(fmt, VALUES[0], 'zero');
+  Test(fmt, VALUES[1], '0.00 EUR');
+  Test(fmt, VALUES[2], '0.12 EUR');
+  Test(fmt, VALUES[3], '1.23 EUR');
+  Test(fmt, VALUES[4], '1,123.46 EUR');
+  Test(fmt, -VALUES[1], '(0.00 EUR)');
+  Test(fmt, -VALUES[2], '(0.12 EUR)');
+  Test(fmt, -VALUES[3], '(1.23 EUR)');
+  Test(fmt, -VALUES[4], '(1,123.46 EUR)');
+
+  fmt := 'EUR #,##0.00;(EUR #,##0.00);-';
+  Test(fmt, VALUES[0], '-');
+  Test(fmt, VALUES[1], 'EUR 0.00');
+  Test(fmt, VALUES[2], 'EUR 0.12');
+  Test(fmt, VALUES[3], 'EUR 1.23');
+  Test(fmt, VALUES[4], 'EUR 1,123.46');
+  Test(fmt, -VALUES[1], '(EUR 0.00)');
+  Test(fmt, -VALUES[2], '(EUR 0.12)');
+  Test(fmt, -VALUES[3], '(EUR 1.23)');
+  Test(fmt, -VALUES[4], '(EUR 1,123.46)');
+
+  WriteLn(testCount, ' tests executed.');
+  if fails = 0 then
+    WriteLn('All tests passed.')
+  else
+    halt(1);
+end.
+

+ 52 - 7
tests/webtbs/tw29367.pp

@@ -13,18 +13,63 @@ type
   end;
   end;
 
 
 constructor TFoo.create;
 constructor TFoo.create;
-begin end;
+begin
+  writeln('TFoo.create');
+end;
 
 
 constructor TBaz.create;
 constructor TBaz.create;
-begin end;
+begin
+  inherited;
+  writeln('TBaz.create');
+end;
+
+var
+  test1tbar: boolean;
+
+procedure test1(o: TFoo; error: longint); overload;
+begin
+  writeln('test1 tfoo');
+  o.free;
+  if test1tbar then
+    halt(error);
+end;
+
+procedure test1(o: TBar; error: longint); overload;
+begin
+  writeln('test1 tbar');
+  o.free;
+  if not test1tbar then
+    halt(error);
+end;
 
 
+var
+  b: tbar;
 begin
 begin
   if not tbar.inheritsfrom(tfoo) then
   if not tbar.inheritsfrom(tfoo) then
-    halt(1);
+    begin
+      writeln('error 1');
+      halt(1);
+    end;
   if not tbaz.inheritsfrom(tbar) then
   if not tbaz.inheritsfrom(tbar) then
-    halt(2);
-  if tbar.classname<>'TBar' then
-    halt(3);
+    begin
+      writeln('error 2');
+      halt(2);
+   end;
+  if tbar.classname<>'TFoo' then
+    begin
+      writeln('error 3');
+      halt(3);
+    end;
   if tfoo.classname<>'TFoo' then
   if tfoo.classname<>'TFoo' then
-    halt(4);
+    begin
+      writeln('error 4');
+      halt(4);
+    end;
+  TBaz.create.free;
+  test1tbar:=false;
+  test1(tfoo.create,5);
+  test1(tbar.create,6);
+  b:=tbar.create;
+  test1tbar:=true;
+  test1(b,7);
 end.
 end.

+ 7 - 0
tests/webtbs/tw8180.pp

@@ -10,7 +10,14 @@ type
 
 
 var
 var
   x : tcl;
   x : tcl;
+  p: pointer;
+  i: iunknown;
 begin
 begin
   x:=tcl.create;
   x:=tcl.create;
   x._Addref;
   x._Addref;
+  i:=x as iunknown;
+  if (x as iunknown).queryinterface(xstr,p) <> S_OK then
+    halt(1);
+  if (x as iunknown).queryinterface(iinterface,p) <> S_OK then
+    halt(2);
 end.
 end.