Bläddra i källkod

Merge remote-tracking branch 'origin/main' into wasm_js_promise_integration

Nikolay Nikolov 2 år sedan
förälder
incheckning
8bd18fc6d3

+ 16 - 2
compiler/ncnv.pas

@@ -2508,7 +2508,10 @@ implementation
                             not is_self_sym(tsym(pcapturedsyminfo(tprocdef(pd).capturedsyms[0])^.sym))
                             not is_self_sym(tsym(pcapturedsyminfo(tprocdef(pd).capturedsyms[0])^.sym))
                           )
                           )
                         ) then
                         ) then
-                      internalerror(2021060801);
+                      begin
+                        result:=cerrornode.create;
+                        exit;
+                      end;
 
 
                     { so that insert_self_and_vmt_para correctly inserts the
                     { so that insert_self_and_vmt_para correctly inserts the
                       Self, cause it otherwise skips that for anonymous functions }
                       Self, cause it otherwise skips that for anonymous functions }
@@ -2619,7 +2622,10 @@ implementation
                 else if tprocvardef(totypedef).is_addressonly then
                 else if tprocvardef(totypedef).is_addressonly then
                   begin
                   begin
                     if assigned(tprocdef(pd).capturedsyms) and (tprocdef(pd).capturedsyms.count>0) then
                     if assigned(tprocdef(pd).capturedsyms) and (tprocdef(pd).capturedsyms.count>0) then
-                      internalerror(2021060802);
+                      begin
+                        result:=cerrornode.create;
+                        exit;
+                      end;
 
 
                     { remove framepointer and Self parameters }
                     { remove framepointer and Self parameters }
                     for i:=tprocdef(pd).parast.symlist.count-1 downto 0 do
                     for i:=tprocdef(pd).parast.symlist.count-1 downto 0 do
@@ -3172,6 +3178,14 @@ implementation
                                  not(is_open_array(left.resultdef)) and
                                  not(is_open_array(left.resultdef)) and
                                  not(is_array_constructor(left.resultdef)) and
                                  not(is_array_constructor(left.resultdef)) and
                                  not(is_array_of_const(left.resultdef)) and
                                  not(is_array_of_const(left.resultdef)) and
+                                 { if the from type is an anonymous function then
+                                   don't blindly convert it if the size is the same
+                                   as compare_defs_ext already determined that the
+                                   anonymous function is not compatible }
+                                 not(
+                                   (left.resultdef.typ=procdef) and
+                                   (po_anonymous in tprocdef(left.resultdef).procoptions)
+                                 ) and
                                  (left.resultdef.size=resultdef.size) and
                                  (left.resultdef.size=resultdef.size) and
                                  { disallow casts of const nodes }
                                  { disallow casts of const nodes }
                                  (not is_constnode(left) or
                                  (not is_constnode(left) or

+ 94 - 60
compiler/pparautl.pas

@@ -76,6 +76,8 @@ implementation
 
 
 
 
     procedure insert_funcret_para(pd:tabstractprocdef);
     procedure insert_funcret_para(pd:tabstractprocdef);
+      const
+        name_result='result';
       var
       var
         storepos : tfileposinfo;
         storepos : tfileposinfo;
         vs       : tparavarsym;
         vs       : tparavarsym;
@@ -87,7 +89,8 @@ implementation
            { if this was originally an anonymous function then this was already
            { if this was originally an anonymous function then this was already
              done earlier }
              done earlier }
            not ((pd.typ=procdef) and tprocdef(pd).was_anonymous) and
            not ((pd.typ=procdef) and tprocdef(pd).was_anonymous) and
-           paramanager.ret_in_param(pd.returndef,pd) then
+           paramanager.ret_in_param(pd.returndef,pd) and
+           not assigned(pd.parast.find(name_result)) then
          begin
          begin
            storepos:=current_tokenpos;
            storepos:=current_tokenpos;
            if pd.typ=procdef then
            if pd.typ=procdef then
@@ -113,7 +116,7 @@ implementation
            else
            else
              paranr:=paranr_result;
              paranr:=paranr_result;
            { Generate result variable accessing function result }
            { Generate result variable accessing function result }
-           vs:=cparavarsym.create('$result',paranr,vs_var,pd.returndef,[vo_is_funcret,vo_is_hidden_para]);
+           vs:=cparavarsym.create('$'+name_result,paranr,vs_var,pd.returndef,[vo_is_funcret,vo_is_hidden_para]);
            pd.parast.insertsym(vs);
            pd.parast.insertsym(vs);
            { Store this symbol as funcretsym for procedures }
            { Store this symbol as funcretsym for procedures }
            if pd.typ=procdef then
            if pd.typ=procdef then
@@ -125,12 +128,15 @@ implementation
 
 
 
 
     procedure insert_parentfp_para(pd:tabstractprocdef);
     procedure insert_parentfp_para(pd:tabstractprocdef);
+      const
+        name_parentfp='parentfp';
       var
       var
         storepos : tfileposinfo;
         storepos : tfileposinfo;
         vs       : tparavarsym;
         vs       : tparavarsym;
         paranr   : longint;
         paranr   : longint;
       begin
       begin
-        if pd.parast.symtablelevel>normal_function_level then
+        if (pd.parast.symtablelevel>normal_function_level) and
+           not assigned(pd.parast.find(name_parentfp)) then
           begin
           begin
             storepos:=current_tokenpos;
             storepos:=current_tokenpos;
             if pd.typ=procdef then
             if pd.typ=procdef then
@@ -157,14 +163,14 @@ implementation
                not assigned(pd.owner.defowner) or
                not assigned(pd.owner.defowner) or
                (pd.owner.defowner.typ<>procdef) then
                (pd.owner.defowner.typ<>procdef) then
               begin
               begin
-                vs:=cparavarsym.create('$parentfp',paranr,vs_value
+                vs:=cparavarsym.create('$'+name_parentfp,paranr,vs_value
                       ,parentfpvoidpointertype,[vo_is_parentfp,vo_is_hidden_para]);
                       ,parentfpvoidpointertype,[vo_is_parentfp,vo_is_hidden_para]);
               end
               end
             else
             else
               begin
               begin
                 if not assigned(tprocdef(pd.owner.defowner).parentfpstruct) then
                 if not assigned(tprocdef(pd.owner.defowner).parentfpstruct) then
                   build_parentfpstruct(tprocdef(pd.owner.defowner));
                   build_parentfpstruct(tprocdef(pd.owner.defowner));
-                vs:=cparavarsym.create('$parentfp',paranr,vs_value,
+                vs:=cparavarsym.create('$'+name_parentfp,paranr,vs_value,
                       tprocdef(pd.owner.defowner).parentfpstructptrtype,[vo_is_parentfp,vo_is_hidden_para]);
                       tprocdef(pd.owner.defowner).parentfpstructptrtype,[vo_is_parentfp,vo_is_hidden_para]);
               end;
               end;
             pd.parast.insertsym(vs);
             pd.parast.insertsym(vs);
@@ -175,6 +181,11 @@ implementation
 
 
 
 
     procedure insert_self_and_vmt_para(pd:tabstractprocdef);
     procedure insert_self_and_vmt_para(pd:tabstractprocdef);
+      const
+        name_cmd='_cmd';
+        name_self='self';
+        name_block_literal='_block_literal';
+        name_vmt='vmt';
       var
       var
         storepos : tfileposinfo;
         storepos : tfileposinfo;
         vs       : tparavarsym;
         vs       : tparavarsym;
@@ -188,55 +199,65 @@ implementation
            is_objc_class_or_protocol(tprocdef(pd).struct) and
            is_objc_class_or_protocol(tprocdef(pd).struct) and
            (pd.parast.symtablelevel=normal_function_level) then
            (pd.parast.symtablelevel=normal_function_level) then
           begin
           begin
-            { insert Objective-C self and selector parameters }
-            vs:=cparavarsym.create('$_cmd',paranr_objc_cmd,vs_value,objc_seltype,[vo_is_msgsel,vo_is_hidden_para]);
-            pd.parast.insertsym(vs);
-            { make accessible to code }
-            sl:=tpropaccesslist.create;
-            sl.addsym(sl_load,vs);
-            aliasvs:=cabsolutevarsym.create_ref('_CMD',objc_seltype,sl);
-            include(aliasvs.varoptions,vo_is_msgsel);
-            tlocalsymtable(tprocdef(pd).localst).insertsym(aliasvs);
-
-            if (po_classmethod in pd.procoptions) then
-              { compatible with what gcc does }
-              hdef:=objc_idtype
-            else
-              hdef:=tprocdef(pd).struct;
+            if not assigned(pd.parast.find(name_cmd)) or
+                not assigned(pd.parast.find(name_self)) then
+              begin
+                { insert Objective-C self and selector parameters }
+                vs:=cparavarsym.create('$'+name_cmd,paranr_objc_cmd,vs_value,objc_seltype,[vo_is_msgsel,vo_is_hidden_para]);
+                pd.parast.insertsym(vs);
+                { make accessible to code }
+                sl:=tpropaccesslist.create;
+                sl.addsym(sl_load,vs);
+                aliasvs:=cabsolutevarsym.create_ref('_CMD',objc_seltype,sl);
+                include(aliasvs.varoptions,vo_is_msgsel);
+                tlocalsymtable(tprocdef(pd).localst).insertsym(aliasvs);
 
 
-            vs:=cparavarsym.create('$self',paranr_objc_self,vs_value,hdef,[vo_is_self,vo_is_hidden_para]);
-            pd.parast.insertsym(vs);
+                if (po_classmethod in pd.procoptions) then
+                  { compatible with what gcc does }
+                  hdef:=objc_idtype
+                else
+                  hdef:=tprocdef(pd).struct;
+
+                vs:=cparavarsym.create('$'+name_self,paranr_objc_self,vs_value,hdef,[vo_is_self,vo_is_hidden_para]);
+                pd.parast.insertsym(vs);
+              end;
           end
           end
         else if (pd.typ=procvardef) and
         else if (pd.typ=procvardef) and
            pd.is_methodpointer then
            pd.is_methodpointer then
           begin
           begin
-            { Generate self variable }
-            vs:=cparavarsym.create('$self',paranr_self,vs_value,voidpointertype,[vo_is_self,vo_is_hidden_para]);
-            pd.parast.insertsym(vs);
+            if not assigned(pd.parast.find(name_self)) then
+              begin
+                { Generate self variable }
+                vs:=cparavarsym.create('$'+name_self,paranr_self,vs_value,voidpointertype,[vo_is_self,vo_is_hidden_para]);
+                pd.parast.insertsym(vs);
+              end;
           end
           end
         { while only procvardefs of this type can be declared in Pascal code,
         { while only procvardefs of this type can be declared in Pascal code,
           internally we also generate procdefs of this type when creating
           internally we also generate procdefs of this type when creating
           block wrappers }
           block wrappers }
         else if (po_is_block in pd.procoptions) then
         else if (po_is_block in pd.procoptions) then
           begin
           begin
-            { generate the first hidden parameter, which is a so-called "block
-              literal" describing the block and containing its invocation
-              procedure  }
-            hdef:=cpointerdef.getreusable(get_block_literal_type_for_proc(pd));
-            { mark as vo_is_parentfp so that proc2procvar comparisons will
-              succeed when assigning arbitrary routines to the block }
-            vs:=cparavarsym.create('$_block_literal',paranr_blockselfpara,vs_value,
-              hdef,[vo_is_hidden_para,vo_is_parentfp]
-            );
-            pd.parast.insertsym(vs);
-            if pd.typ=procdef then
+            if not assigned(pd.parast.find('$'+name_block_literal)) then
               begin
               begin
-                { make accessible to code }
-                sl:=tpropaccesslist.create;
-                sl.addsym(sl_load,vs);
-                aliasvs:=cabsolutevarsym.create_ref('FPC_BLOCK_SELF',hdef,sl);
-                include(aliasvs.varoptions,vo_is_parentfp);
-                tlocalsymtable(tprocdef(pd).localst).insertsym(aliasvs);
+                { generate the first hidden parameter, which is a so-called "block
+                  literal" describing the block and containing its invocation
+                  procedure  }
+                hdef:=cpointerdef.getreusable(get_block_literal_type_for_proc(pd));
+                { mark as vo_is_parentfp so that proc2procvar comparisons will
+                  succeed when assigning arbitrary routines to the block }
+                vs:=cparavarsym.create('$'+name_block_literal,paranr_blockselfpara,vs_value,
+                  hdef,[vo_is_hidden_para,vo_is_parentfp]
+                );
+                pd.parast.insertsym(vs);
+                if pd.typ=procdef then
+                  begin
+                    { make accessible to code }
+                    sl:=tpropaccesslist.create;
+                    sl.addsym(sl_load,vs);
+                    aliasvs:=cabsolutevarsym.create_ref('FPC_BLOCK_SELF',hdef,sl);
+                    include(aliasvs.varoptions,vo_is_parentfp);
+                    tlocalsymtable(tprocdef(pd).localst).insertsym(aliasvs);
+                  end;
               end;
               end;
           end
           end
         else
         else
@@ -264,9 +285,10 @@ implementation
                          { no vmt for record/type helper constructors }
                          { no vmt for record/type helper constructors }
                          is_objectpascal_helper(tprocdef(pd).struct) and
                          is_objectpascal_helper(tprocdef(pd).struct) and
                          (tobjectdef(tprocdef(pd).struct).extendeddef.typ<>objectdef)
                          (tobjectdef(tprocdef(pd).struct).extendeddef.typ<>objectdef)
-                       )) then
+                       )) and
+                   not assigned(pd.parast.find(name_vmt)) then
                  begin
                  begin
-                   vs:=cparavarsym.create('$vmt',paranr_vmt,vs_value,cclassrefdef.create(tprocdef(pd).struct),[vo_is_vmt,vo_is_hidden_para]);
+                   vs:=cparavarsym.create('$'+name_vmt,paranr_vmt,vs_value,cclassrefdef.create(tprocdef(pd).struct),[vo_is_vmt,vo_is_hidden_para]);
                    pd.parast.insertsym(vs);
                    pd.parast.insertsym(vs);
                  end;
                  end;
 
 
@@ -291,10 +313,10 @@ implementation
                       vsp:=vs_var;
                       vsp:=vs_var;
                     hdef:=selfdef;
                     hdef:=selfdef;
                   end;
                   end;
-                vs:=tparavarsym(pd.parast.find('self'));
+                vs:=tparavarsym(pd.parast.find(name_self));
                 if not assigned(vs) or (vs.typ<>paravarsym) or (vs.vardef<>hdef) then
                 if not assigned(vs) or (vs.typ<>paravarsym) or (vs.vardef<>hdef) then
                   begin
                   begin
-                    vs:=cparavarsym.create('$self',paranr_self,vsp,hdef,[vo_is_self,vo_is_hidden_para]);
+                    vs:=cparavarsym.create('$'+name_self,paranr_self,vsp,hdef,[vo_is_self,vo_is_hidden_para]);
                     pd.parast.insertsym(vs);
                     pd.parast.insertsym(vs);
                   end;
                   end;
 
 
@@ -384,7 +406,11 @@ implementation
 
 
 
 
     procedure insert_hidden_para(p:TObject;arg:pointer);
     procedure insert_hidden_para(p:TObject;arg:pointer);
+      const
+        name_high = 'high';
+        name_typinfo = 'typinfo';
       var
       var
+        n   : tsymstr;
         hvs : tparavarsym;
         hvs : tparavarsym;
         pd  : tabstractprocdef absolute arg;
         pd  : tabstractprocdef absolute arg;
       begin
       begin
@@ -415,19 +441,23 @@ implementation
            { needs high parameter ? }
            { needs high parameter ? }
            if paramanager.push_high_param(varspez,vardef,pd.proccalloption) then
            if paramanager.push_high_param(varspez,vardef,pd.proccalloption) then
              begin
              begin
+               n:=name_high+name;
+               if not assigned(owner.find(n)) then
+                 begin
 {$ifdef cpu8bitalu}
 {$ifdef cpu8bitalu}
-               if is_shortstring(vardef) then
-                 hvs:=cparavarsym.create('$high'+name,paranr+1,vs_const,aluuinttype,[vo_is_high_para,vo_is_hidden_para])
-               else
+                   if is_shortstring(vardef) then
+                     hvs:=cparavarsym.create('$'+n,paranr+1,vs_const,aluuinttype,[vo_is_high_para,vo_is_hidden_para])
+                   else
 {$endif cpu8bitalu}
 {$endif cpu8bitalu}
-                 hvs:=cparavarsym.create('$high'+name,paranr+1,vs_const,sizesinttype,[vo_is_high_para,vo_is_hidden_para]);
-               hvs.symoptions:=[];
-               owner.insertsym(hvs);
-               { don't place to register if it will be accessed from implicit finally block }
-               if (varspez=vs_value) and
-                  is_open_array(vardef) and
-                  is_managed_type(vardef) then
-                 hvs.varregable:=vr_none;
+                     hvs:=cparavarsym.create('$'+n,paranr+1,vs_const,sizesinttype,[vo_is_high_para,vo_is_hidden_para]);
+                   hvs.symoptions:=[];
+                   owner.insertsym(hvs);
+                   { don't place to register if it will be accessed from implicit finally block }
+                   if (varspez=vs_value) and
+                      is_open_array(vardef) and
+                      is_managed_type(vardef) then
+                     hvs.varregable:=vr_none;
+                 end;
              end
              end
            else
            else
             begin
             begin
@@ -448,9 +478,13 @@ implementation
                end;
                end;
               if (vardef.typ=formaldef) and (Tformaldef(vardef).typed) then
               if (vardef.typ=formaldef) and (Tformaldef(vardef).typed) then
                 begin
                 begin
-                  hvs:=cparavarsym.create('$typinfo'+name,paranr+1,vs_const,voidpointertype,
-                                          [vo_is_typinfo_para,vo_is_hidden_para]);
-                  owner.insertsym(hvs);
+                  n:=name_typinfo+name;
+                  if not assigned(owner.find(n)) then
+                    begin
+                      hvs:=cparavarsym.create('$'+n,paranr+1,vs_const,voidpointertype,
+                                              [vo_is_typinfo_para,vo_is_hidden_para]);
+                      owner.insertsym(hvs);
+                    end;
                 end;
                 end;
             end;
             end;
          end;
          end;

+ 12 - 12
compiler/procdefutil.pas

@@ -1138,6 +1138,7 @@ implementation
       invokename : tsymstr;
       invokename : tsymstr;
       i : longint;
       i : longint;
       outerself,
       outerself,
+      fpsym,
       selfsym,
       selfsym,
       sym : tsym;
       sym : tsym;
       info : pcapturedsyminfo;
       info : pcapturedsyminfo;
@@ -1146,7 +1147,6 @@ implementation
       invokedef,
       invokedef,
       parentdef,
       parentdef,
       curpd : tprocdef;
       curpd : tprocdef;
-      syms : tfpobjectlist;
     begin
     begin
       capturer:=nil;
       capturer:=nil;
       result:=funcref_intf_for_proc(pd,fileinfo_to_suffix(pd.fileinfo));
       result:=funcref_intf_for_proc(pd,fileinfo_to_suffix(pd.fileinfo));
@@ -1203,24 +1203,24 @@ implementation
           pd.procsym.realname:=invokename;
           pd.procsym.realname:=invokename;
           pd.parast.symtablelevel:=normal_function_level;
           pd.parast.symtablelevel:=normal_function_level;
           pd.localst.symtablelevel:=normal_function_level;
           pd.localst.symtablelevel:=normal_function_level;
-          { collect all hidden parameters and especially the self parameter (if any) }
+          { retrieve framepointer and self parameters if any }
+          fpsym:=nil;
           selfsym:=nil;
           selfsym:=nil;
-          syms:=tfpobjectlist.create(false);
           for i:=0 to pd.parast.symlist.count-1 do
           for i:=0 to pd.parast.symlist.count-1 do
             begin
             begin
               sym:=tsym(pd.parast.symlist[i]);
               sym:=tsym(pd.parast.symlist[i]);
               if sym.typ<>paravarsym then
               if sym.typ<>paravarsym then
                 continue;
                 continue;
-              if vo_is_self in tparavarsym(sym).varoptions then
-                selfsym:=sym
-              else if vo_is_hidden_para in tparavarsym(sym).varoptions then
-                syms.add(sym);
+              if vo_is_parentfp in tparavarsym(sym).varoptions then
+                fpsym:=sym
+              else if vo_is_self in tparavarsym(sym).varoptions then
+                selfsym:=sym;
+              if assigned(fpsym) and assigned(selfsym) then
+                break;
             end;
             end;
-          { get rid of the hidden parameters; they will be added again during
-            buildvmt of the capturer }
-          for i:=0 to syms.count-1 do
-            pd.parast.deletesym(tsym(syms[i]));
-          syms.free;
+          { get rid of the framepointer parameter }
+          if assigned(fpsym) then
+            pd.parast.deletesym(fpsym);
           outerself:=nil;
           outerself:=nil;
           { complain about all symbols that can't be captured and add the symbols
           { complain about all symbols that can't be captured and add the symbols
             to this procdefs capturedsyms if it isn't a top level function }
             to this procdefs capturedsyms if it isn't a top level function }

+ 15 - 4
compiler/riscv/agrvgas.pas

@@ -245,13 +245,24 @@ unit agrvgas;
         result := inherited MakeCmdLine;
         result := inherited MakeCmdLine;
         Replace(result,'$ARCH',arch_str[current_settings.fputype=fpu_fd,current_settings.cputype]);
         Replace(result,'$ARCH',arch_str[current_settings.fputype=fpu_fd,current_settings.cputype]);
 {$ifdef RISCV32}
 {$ifdef RISCV32}
-        Replace(result,'$ABI','ilp32');
+      case target_info.abi of
+        abi_riscv_ilp32:
+          Replace(result,'$ABI','ilp32');
+        abi_riscv_ilp32f:
+          Replace(result,'$ABI','ilp32f');
+	else
+          Replace(result,'$ABI','ilp32d');
+      end;
 {$endif RISCV32}
 {$endif RISCV32}
 {$ifdef RISCV64}
 {$ifdef RISCV64}
-        if target_info.abi=abi_riscv_hf then
-          Replace(result,'$ABI','lp64d')
-        else
+      case target_info.abi of
+        abi_riscv_lp64:
           Replace(result,'$ABI','lp64');
           Replace(result,'$ABI','lp64');
+        abi_riscv_lp64f:
+          Replace(result,'$ABI','lp64f');
+	else
+          Replace(result,'$ABI','lp64d');
+      end;
 {$endif RISCV64}
 {$endif RISCV64}
       end;
       end;
 
 

+ 2 - 2
compiler/systems/i_embed.pas

@@ -645,7 +645,7 @@ unit i_embed;
             first_parm_offset : 8;
             first_parm_offset : 8;
             stacksize    : 262144;
             stacksize    : 262144;
             stackalign   : 4;
             stackalign   : 4;
-            abi : abi_default;
+            abi : abi_riscv_ilp32;
             llvmdatalayout : 'e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:64:128-a0:0:64-n32-S32';
             llvmdatalayout : 'e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:64:128-a0:0:64-n32-S32';
           );
           );
 
 
@@ -712,7 +712,7 @@ unit i_embed;
             first_parm_offset : 16;
             first_parm_offset : 16;
             stacksize    : 262144;
             stacksize    : 262144;
             stackalign   : 8;
             stackalign   : 8;
-            abi : abi_default;
+            abi : abi_riscv_lp64;
             llvmdatalayout : 'e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:64:128-a0:0:64-n32-S32';
             llvmdatalayout : 'e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:64:128-a0:0:64-n32-S32';
           );
           );
 
 

+ 1 - 1
compiler/systems/i_linux.pas

@@ -1309,7 +1309,7 @@ unit i_linux;
             first_parm_offset : 0;
             first_parm_offset : 0;
             stacksize    : 32*1024*1024;
             stacksize    : 32*1024*1024;
             stackalign   : 8;
             stackalign   : 8;
-            abi : abi_riscv_hf;
+            abi : abi_riscv_ilp32;
             llvmdatalayout : 'e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64';
             llvmdatalayout : 'e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64';
           );
           );
 
 

+ 7 - 0
compiler/wasm32/agllvmmc.pas

@@ -241,7 +241,14 @@ implementation
             else
             else
               begin
               begin
                 result:=result+'nan';
                 result:=result+'nan';
+{$ifndef CPUMIPS}
                 if fraction<>(int64(1) shl (fraction_bits-1)) then
                 if fraction<>(int64(1) shl (fraction_bits-1)) then
+{$else CPUMIPS}
+                { Legacy mips fpu has a different representation of 'standard' nan }
+                { Signalling bit is clear to signify non-signalling }
+                { Standard non-signalling NaN thus has all other bits set }
+                if fraction<>((int64(1) shl (fraction_bits-1))-1) then
+{$endif CPUMIPS}
                   result:=result+'(0x'+HexStr(fraction,fraction_hexdigits)+')';
                   result:=result+'(0x'+HexStr(fraction,fraction_hexdigits)+')';
               end;
               end;
           end
           end

+ 4 - 4
packages/chm/src/chmfilewriter.pas

@@ -574,7 +574,7 @@ var
   Fini      : TMemIniFile;  // TMemInifile is more compatible with Delphi. Delphi's API based TIniFile fails on .hhp files.
   Fini      : TMemIniFile;  // TMemInifile is more compatible with Delphi. Delphi's API based TIniFile fails on .hhp files.
   secs,strs : TStringList;
   secs,strs : TStringList;
   i,j       : Integer;
   i,j       : Integer;
-  section   : TSectionEnum;
+  _section  : TSectionEnum;
   nd        : TChmContextNode;
   nd        : TChmContextNode;
 
 
 begin
 begin
@@ -615,10 +615,10 @@ begin
 
 
   for i:=0 to secs.count-1 do
   for i:=0 to secs.count-1 do
     begin
     begin
-      section:=FindSectionName(Uppercase(Secs[i]));
-      if section<>secunknown then
+      _section:=FindSectionName(Uppercase(Secs[i]));
+      if _section<>secunknown then
         fini.readsectionvalues(secs[i] ,strs);
         fini.readsectionvalues(secs[i] ,strs);
-      case section of
+      case _section of
       secOptions   : readinioptions(strs);
       secOptions   : readinioptions(strs);
       secWindows   : for j:=0 to strs.count-1 do
       secWindows   : for j:=0 to strs.count-1 do
                        FWindows.add(TCHMWindow.Create(strs[j]));
                        FWindows.add(TCHMWindow.Create(strs[j]));

+ 8 - 8
packages/chm/src/chmls.lpr

@@ -40,7 +40,7 @@ type
   { TListObject }
   { TListObject }
 
 
   TListObject = class
   TListObject = class
-    Section  : Integer;
+    _Section : Integer;
     count    : integer;
     count    : integer;
     donotpage: boolean;
     donotpage: boolean;
     nameonly : boolean;
     nameonly : boolean;
@@ -196,7 +196,7 @@ procedure TListObject.OnFileEntry(Name: String; Offset, UncompressedSize,
   ASection: Integer);
   ASection: Integer);
 begin
 begin
   Inc(Count);
   Inc(Count);
-  if (Section > -1) and (ASection <> Section) then Exit;
+  if (_Section > -1) and (ASection <> _Section) then Exit;
   if (Count = 1) or ((Count mod 40 = 0) and not donotpage) then
   if (Count = 1) or ((Count mod 40 = 0) and not donotpage) then
     begin
     begin
       Write(StdErr, '<Section> ');
       Write(StdErr, '<Section> ');
@@ -274,7 +274,7 @@ end;
 var donotpage:boolean=false;
 var donotpage:boolean=false;
     name_only :boolean=false;
     name_only :boolean=false;
 
 
-procedure ListChm(Const Name:string;Section:Integer);
+procedure ListChm(Const Name:string;_Section:Integer);
 var
 var
   ITS: TITSFReader;
   ITS: TITSFReader;
   Stream: TFileStream;
   Stream: TFileStream;
@@ -289,7 +289,7 @@ begin
 
 
   Stream := TFileStream.Create(name, fmOpenRead);
   Stream := TFileStream.Create(name, fmOpenRead);
   JunkObject := TListObject.Create;
   JunkObject := TListObject.Create;
-  JunkObject.Section:=Section;
+  JunkObject._Section:=_Section;
   JunkObject.Count:=0;
   JunkObject.Count:=0;
   JunkObject.DoNotPage:=DoNotPage;
   JunkObject.DoNotPage:=DoNotPage;
   JunkObject.NameOnly:=Name_Only;
   JunkObject.NameOnly:=Name_Only;
@@ -1002,7 +1002,7 @@ Var
   Params,
   Params,
   OptionIndex : Longint;
   OptionIndex : Longint;
   cmd         : TCmdEnum;
   cmd         : TCmdEnum;
-  section     : Integer = -1;
+  _section    : Integer = -1;
 
 
 // Start of program
 // Start of program
 begin
 begin
@@ -1043,15 +1043,15 @@ begin
     case cmd of
     case cmd of
       cmdlist : begin
       cmdlist : begin
                   case length(localparams) of
                   case length(localparams) of
-                    1 : ListChm(localparams[0],Section);
+                    1 : ListChm(localparams[0],_Section);
                     2 : begin
                     2 : begin
-                          if not TryStrToInt(localparams[1],section) then
+                          if not TryStrToInt(localparams[1],_section) then
                             begin
                             begin
                               writeln(stderr,' Invalid value for section ',localparams[2]);
                               writeln(stderr,' Invalid value for section ',localparams[2]);
                               usage;
                               usage;
                               halt(1);
                               halt(1);
                             end;
                             end;
-                          ListChm(localparams[0],Section);
+                          ListChm(localparams[0],_Section);
                         end;
                         end;
                   else
                   else
                     WrongNrParam(cmdnames[cmd],length(localparams));
                     WrongNrParam(cmdnames[cmd],length(localparams));

+ 1 - 1
packages/chm/src/chmreader.pas

@@ -50,7 +50,7 @@ type
   end;
   end;
   { TITSFReader }
   { TITSFReader }
 
 
-  TFileEntryForEach = procedure(Name: String; Offset, UncompressedSize, Section: Integer) of object;
+  TFileEntryForEach = procedure(Name: String; Offset, UncompressedSize, _Section: Integer) of object;
 
 
   TITSFReader = class(TObject)
   TITSFReader = class(TObject)
   protected
   protected

+ 39 - 22
packages/fcl-base/src/syncobjs.pp

@@ -100,7 +100,7 @@ implementation
 {$ifdef MSWindows}
 {$ifdef MSWindows}
 uses Windows;
 uses Windows;
 
 
-function CoWaitForMultipleObjects(nCount:DWORD; lpHandles : PWOHandleArray; bWaitAll:WINBOOL; dwMilliseconds:DWORD):DWORD; external 'kernel32' name 'CoWaitForMultipleObjects';
+function CoWaitForMultipleHandles(dwFlags, dwTimeout: DWORD; cHandles: ULONG; pHandles: PWOHandleArray; out lpdwindex: DWORD): HRESULT; stdcall; external 'ole32.dll' name 'CoWaitForMultipleHandles';
 {$endif}
 {$endif}
 
 
 
 
@@ -204,30 +204,51 @@ end;
 
 
 {$IFDEF MSWINDOWS}
 {$IFDEF MSWINDOWS}
 class function THandleObject.WaitForMultiple(const HandleObjs: THandleObjectArray; Timeout: Cardinal; AAll: Boolean; out SignaledObj: THandleObject; UseCOMWait: Boolean = False; Len: Integer = 0): TWaitResult;
 class function THandleObject.WaitForMultiple(const HandleObjs: THandleObjectArray; Timeout: Cardinal; AAll: Boolean; out SignaledObj: THandleObject; UseCOMWait: Boolean = False; Len: Integer = 0): TWaitResult;
+const COWAIT_DEFAULT = 0;
+      COWAIT_WAITALL = 1;
+      RPC_S_CALLPENDING = HRESULT($80010115);
 var
 var
-  ret: Integer;
-  AmountHandles: Integer;
+  HandleIndex: SizeInt;
+  ret, CoWaitFlags, SignaledIndex: DWord;
+  WOHandles: TWOHandleArray;
 begin
 begin
-  AmountHandles := Length(HandleObjs);
-  if AmountHandles = 0 then
+  if Len = 0 then
+    Len := Length(HandleObjs);
+
+  if Len = 0 then
     raise ESyncObjectException.Create(SErrEventZeroNotAllowed);
     raise ESyncObjectException.Create(SErrEventZeroNotAllowed);
 
 
-  if AmountHandles > MAXIMUM_WAIT_OBJECTS then
+  if Len > Length(HandleObjs) then
+    raise ESyncObjectException.Create(SErrEventTooManyHandles);
+
+  if Len > MAXIMUM_WAIT_OBJECTS then
     raise ESyncObjectException.CreateFmt(SErrEventMaxObjects, [MAXIMUM_WAIT_OBJECTS]);
     raise ESyncObjectException.CreateFmt(SErrEventMaxObjects, [MAXIMUM_WAIT_OBJECTS]);
 
 
-  if Len > AmountHandles then
-    raise ESyncObjectException.Create(SErrEventTooManyHandles);
+  for HandleIndex := 0 to Len - 1 do
+    WOHandles[HandleIndex] := Windows.HANDLE(HandleObjs[HandleIndex].Handle);
 
 
   // what about UseCOMWait?
   // what about UseCOMWait?
-  {$IFDEF MSWINDOWS}
   if UseCOMWait Then
   if UseCOMWait Then
     begin
     begin
-      SetLastError(ERROR_SUCCESS); // only for "alertable" objects
-      ret := CoWaitForMultipleObjects(Len, @HandleObjs, AAll, Timeout);
-    end
-  else
-  {$ENDIF}
-    ret := WaitForMultipleObjects(Len, @HandleObjs, AAll, Timeout);
+      SetLastError(ERROR_SUCCESS); // workaround for mutexes, see docs on CoWaitForMultipleHandles.
+      CoWaitFlags := COWAIT_DEFAULT;
+      if AAll then
+        CoWaitFlags := CoWaitFlags or COWAIT_WAITALL;
+      case CoWaitForMultipleHandles(CoWaitFlags, Timeout, Len, @WOHandles, SignaledIndex) of
+        S_OK:
+          begin
+            if not AAll then
+              SignaledObj := HandleObjs[SignaledIndex];
+            Exit(wrSignaled);
+          end;
+        RPC_S_CALLPENDING:
+          Exit(wrTimeout);
+        else
+          Exit(wrError);
+      end;
+    end;
+
+  ret := WaitForMultipleObjects(Len, @WOHandles, AAll, Timeout);
 
 
   if (ret >= WAIT_OBJECT_0) and (ret < (WAIT_OBJECT_0 + Len)) then
   if (ret >= WAIT_OBJECT_0) and (ret < (WAIT_OBJECT_0 + Len)) then
     begin
     begin
@@ -245,13 +266,9 @@ begin
 
 
   case ret of
   case ret of
     WAIT_TIMEOUT:
     WAIT_TIMEOUT:
-      begin
-        Result := wrTimeout;
-      end;
-    Integer(WAIT_FAILED): // w/o: Warning: Range check error while evaluating constants (4294967295 must be between -2147483648 and 2147483647)
-      begin
-        Result := wrError;
-      end;
+      Result := wrTimeout;
+    else
+      Result := wrError;
   end;
   end;
 end;
 end;
 {$endif}
 {$endif}

+ 2 - 0
packages/fcl-pdf/examples/.gitignore

@@ -3,3 +3,5 @@ testfppdf
 *.exe
 *.exe
 *.pdf
 *.pdf
 fonts
 fonts
+lib
+pdfdump

+ 1 - 1
packages/fcl-pdf/examples/pdfdump.pp

@@ -382,7 +382,7 @@ begin
     // P.ResolveObjects:=False;
     // P.ResolveObjects:=False;
     P.ParseDocument(Doc);
     P.ParseDocument(Doc);
     if isPageText in FSections then
     if isPageText in FSections then
-      P.ResolveToUnicodeCMaps(Doc);
+      P.DoResolveToUnicodeCMaps(Doc);
     For S in FSections do
     For S in FSections do
       begin
       begin
       Case s of
       Case s of

+ 44 - 9
packages/fcl-pdf/examples/testfppdf.lpr

@@ -27,6 +27,8 @@ uses
 
 
 type
 type
 
 
+  { TPDFTestApp }
+
   TPDFTestApp = class(TCustomApplication)
   TPDFTestApp = class(TCustomApplication)
   private
   private
     FPage: integer;
     FPage: integer;
@@ -42,6 +44,7 @@ type
     function    SetUpDocument: TPDFDocument;
     function    SetUpDocument: TPDFDocument;
     procedure   SaveDocument(D: TPDFDocument);
     procedure   SaveDocument(D: TPDFDocument);
     procedure   EmptyPage;
     procedure   EmptyPage;
+    procedure   TableOfContents(D: TPDFDocument; APage: integer);
     procedure   SimpleText(D: TPDFDocument; APage: integer);
     procedure   SimpleText(D: TPDFDocument; APage: integer);
     procedure   SimpleLinesRaw(D: TPDFDocument; APage: integer);
     procedure   SimpleLinesRaw(D: TPDFDocument; APage: integer);
     procedure   SimpleLines(D: TPDFDocument; APage: integer);
     procedure   SimpleLines(D: TPDFDocument; APage: integer);
@@ -62,7 +65,7 @@ var
   Application: TPDFTestApp;
   Application: TPDFTestApp;
 
 
 const
 const
-  cPageCount: integer = 8;
+  cPageCount: integer = 9;
 
 
 function TPDFTestApp.SetUpDocument: TPDFDocument;
 function TPDFTestApp.SetUpDocument: TPDFDocument;
 var
 var
@@ -141,6 +144,37 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TPDFTestApp.TableOfContents(D: TPDFDocument; APage: integer);
+const
+  pagesarr: array [1..8] of String = ('Sample Text', 'Basic Shapes', 'Advanced Drawing',
+    'Sample Line Drawing (DrawLineStyle)', 'Sample Line Drawing (DrawLine)', 'Sample Image Support',
+    'Matrix transform', 'Landscape Page');
+var
+  P : TPDFPage;
+  FtTitle, FtText, i: integer;
+begin
+  P := D.Pages[APage];
+
+  // create the fonts to be used (use one of the 14 Adobe PDF standard fonts)
+  FtTitle := D.AddFont('Helvetica');
+  FtText := D.AddFont('Courier');
+
+  { Page title }
+  P.SetFont(FtTitle, 23);
+  P.SetColor(clBlack, false);
+  P.WriteText(25, 20, 'Table of contents');
+
+  // -----------------------------------
+  { references to document pages }
+  P.SetFont(FtText, 12);
+  P.SetColor(clBlack, false);
+  for i := Low(pagesarr) to High(pagesarr) do
+  begin
+    P.WriteText(25, 40 + 10 * i, pagesarr[i] + StringOfChar('.', 60 - Length(pagesarr[i])) + IntToStr(i));
+    P.AddInternalLink(25, 40 + 10 * i, 160, 5, i, false);
+  end;
+end;
+
 { all units of measure are in millimeters }
 { all units of measure are in millimeters }
 procedure TPDFTestApp.SimpleText(D: TPDFDocument; APage: integer);
 procedure TPDFTestApp.SimpleText(D: TPDFDocument; APage: integer);
 var
 var
@@ -837,14 +871,15 @@ begin
 
 
     if FPage = -1 then
     if FPage = -1 then
     begin
     begin
-      SimpleText(FDoc, 0);
-      SimpleShapes(FDoc, 1);
-      AdvancedShapes(FDoc, 2);
-      SimpleLines(FDoc, 3);
-      SimpleLinesRaw(FDoc, 4);
-      SimpleImage(FDoc, 5);
-      SampleMatrixTransform(FDoc, 6);
-      SampleLandscape(FDoc, 7);
+      TableOfContents(FDoc, 0);
+      SimpleText(FDoc, 1);
+      SimpleShapes(FDoc, 2);
+      AdvancedShapes(FDoc, 3);
+      SimpleLines(FDoc, 4);
+      SimpleLinesRaw(FDoc, 5);
+      SimpleImage(FDoc, 6);
+      SampleMatrixTransform(FDoc, 7);
+      SampleLandscape(FDoc, 8);
     end
     end
     else
     else
     begin
     begin

+ 33 - 5
packages/fcl-pdf/src/fppdf.pp

@@ -785,6 +785,8 @@ type
     procedure CubicCurveToY(ACtrl1, ATo: TPDFCoord; const ALineWidth: TPDFFloat; AStroke: Boolean = True); overload;
     procedure CubicCurveToY(ACtrl1, ATo: TPDFCoord; const ALineWidth: TPDFFloat; AStroke: Boolean = True); overload;
     { Define a rectangle that becomes a clickable hotspot, referencing the URI argument. }
     { Define a rectangle that becomes a clickable hotspot, referencing the URI argument. }
     Procedure AddExternalLink(const APosX, APosY, AWidth, AHeight: TPDFFloat; const AURI: string; ABorder: boolean = false);
     Procedure AddExternalLink(const APosX, APosY, AWidth, AHeight: TPDFFloat; const AURI: string; ABorder: boolean = false);
+    { Define a rectangle that becomes a clickable hotspot, referencing the document page. }
+    Procedure AddInternalLink(const APosX, APosY, AWidth, AHeight: TPDFFloat; const APageIndex: Integer; ABorder: boolean = false);
     { This returns the paper height, converted to whatever UnitOfMeasure is set too }
     { This returns the paper height, converted to whatever UnitOfMeasure is set too }
     function GetPaperHeight: TPDFFloat;
     function GetPaperHeight: TPDFFloat;
     Function HasImages : Boolean;
     Function HasImages : Boolean;
@@ -908,9 +910,11 @@ type
     FHeight: TPDFFloat;
     FHeight: TPDFFloat;
     FURI: string;
     FURI: string;
     FBorder: boolean;
     FBorder: boolean;
+    FExternalLink: Boolean;
   public
   public
     constructor Create(const ADocument: TPDFDocument); override; overload;
     constructor Create(const ADocument: TPDFDocument); override; overload;
-    constructor Create(const ADocument: TPDFDocument; const ALeft, ABottom, AWidth, AHeight: TPDFFloat; const AURI: String; const ABorder: Boolean = false); overload;
+    constructor Create(const ADocument: TPDFDocument; const ALeft, ABottom, AWidth, AHeight: TPDFFloat; const AURI: String; const ABorder: Boolean = false;
+      const AExternalLink: Boolean = true); overload;
   end;
   end;
 
 
 
 
@@ -2146,7 +2150,7 @@ begin
 end;
 end;
 
 
 constructor TPDFAnnot.Create(const ADocument: TPDFDocument; const ALeft, ABottom, AWidth, AHeight: TPDFFloat;
 constructor TPDFAnnot.Create(const ADocument: TPDFDocument; const ALeft, ABottom, AWidth, AHeight: TPDFFloat;
-  const AURI: String; const ABorder: Boolean);
+  const AURI: String; const ABorder: Boolean; const AExternalLink: Boolean);
 begin
 begin
   Create(ADocument);
   Create(ADocument);
   FLeft := ALeft;
   FLeft := ALeft;
@@ -2155,6 +2159,7 @@ begin
   FHeight := AHeight;
   FHeight := AHeight;
   FURI := AURI;
   FURI := AURI;
   FBorder := ABorder;
   FBorder := ABorder;
+  FExternalLink := AExternalLink;
 end;
 end;
 
 
 { TPDFAnnotList }
 { TPDFAnnotList }
@@ -2806,6 +2811,21 @@ begin
   Annots.Add(an);
   Annots.Add(an);
 end;
 end;
 
 
+procedure TPDFPage.AddInternalLink(const APosX, APosY, AWidth, AHeight: TPDFFloat;
+    const APageIndex: Integer; ABorder: boolean);
+var
+  an: TPDFAnnot;
+  p1, p2: TPDFCoord;
+begin
+  p1 := Matrix.Transform(APosX, APosY);
+  DoUnitConversion(p1);
+  p2.X := AWidth;
+  p2.Y := AHeight;
+  DoUnitConversion(p2);
+  an := TPDFAnnot.Create(Document, p1.X, p1.Y, p2.X, p2.Y, Format('[%d]', [APageIndex]), ABorder, False);
+  Annots.Add(an);
+end;
+
 function TPDFPage.GetPaperHeight: TPDFFloat;
 function TPDFPage.GetPaperHeight: TPDFFloat;
 begin
 begin
   case FUnitOfMeasure of
   case FUnitOfMeasure of
@@ -5635,9 +5655,17 @@ begin
 
 
   ADict := CreateDictionary;
   ADict := CreateDictionary;
   lDict.AddElement('A', ADict);
   lDict.AddElement('A', ADict);
-  ADict.AddName('Type', 'Action');
-  ADict.AddName('S', 'URI');
-  ADict.AddString('URI', an.FURI);
+  if an.FExternalLink then
+  begin
+    ADict.AddName('Type', 'Action');
+    ADict.AddName('S', 'URI');
+    ADict.AddString('URI', an.FURI);
+  end
+  else
+  begin
+    ADict.AddName('S', 'GoTo');
+    ADict.AddName('D' + an.FURI, '');
+  end;
 
 
   result := GlobalXRefCount-1;
   result := GlobalXRefCount-1;
 end;
 end;

+ 23 - 33
rtl/i386/i386.inc

@@ -2031,48 +2031,38 @@ procedure fpc_cpucodeinit;
 {$define FPC_SYSTEM_HAS_ANSISTR_DECR_REF}
 {$define FPC_SYSTEM_HAS_ANSISTR_DECR_REF}
 Procedure fpc_AnsiStr_Decr_Ref (Var S : Pointer); [Public,Alias:'FPC_ANSISTR_DECR_REF']; compilerproc; nostackframe; assembler;
 Procedure fpc_AnsiStr_Decr_Ref (Var S : Pointer); [Public,Alias:'FPC_ANSISTR_DECR_REF']; compilerproc; nostackframe; assembler;
 asm
 asm
-        cmpl    $0,(%eax)
-        je      .Lquit
-        pushl   %esi
-        movl    (%eax),%esi
-        subl    $12,%esi           // points to start of allocation
+        movl    (%eax),%edx
+        testl   %edx,%edx
+        jz      .Lquit
         movl    $0,(%eax)          // s:=nil
         movl    $0,(%eax)          // s:=nil
-        cmpl    $0,4(%esi)         // exit if refcount<0
-        jl      .Lj3596
+        cmpl    $0,-8(%edx)        // exit if refcount<0
+        jl      .Lquit
   {$ifdef FPC_PIC}
   {$ifdef FPC_PIC}
-	pushl	%ebx
-        call	fpc_geteipasebx
-        addl	$_GLOBAL_OFFSET_TABLE_,%ebx
-        movl	ismultithread@GOT(%ebx),%ebx
-        movl	(%ebx),%ebx
-        cmp	$0, %ebx
-	popl    %ebx
+        call	fpc_geteipasecx
+        addl	$_GLOBAL_OFFSET_TABLE_,%ecx
+        movl	ismultithread@GOT(%ecx),%ecx
+        cmpl	$0,(%ecx)
   {$else FPC_PIC}
   {$else FPC_PIC}
         cmpl    $0,ismultithread
         cmpl    $0,ismultithread
   {$endif FPC_PIC}
   {$endif FPC_PIC}
-        jne     .Lj3610
-        decl    4(%esi)
-        je      .Lj3620
-        jmp     .Lj3596
-.Lj3610:
-        leal    4(%esi),%eax
-        call    cpudeclocked
-        testb   %al,%al
-        je      .Lj3596
-.Lj3620:
-        movl    %esi,%eax
-        { freemem is not an assembler leaf function like fpc_geteipasebx and cpudeclocked, so it
+        je      .Lskiplock
+        .byte   0xF0               // LOCK prefix, jumped over if IsMultiThread = false. FPC assembler does not accept disjoint LOCK mnemonic.
+.Lskiplock:
+        decl    -8(%edx)
+        jz      .Lfree
+.Lquit:
+        ret
+.Lfree:
+        leal    -12(%edx),%eax     // points to start of allocation
+        { freemem is not an assembler leaf function like fpc_geteipasecx, so it
           needs to be called with proper stack alignment }
           needs to be called with proper stack alignment }
 {$ifdef FPC_SYSTEM_STACKALIGNMENT16}
 {$ifdef FPC_SYSTEM_STACKALIGNMENT16}
-        leal    -8(%esp),%esp
-{$endif FPC_SYSTEM_STACKALIGNMENT16}
+        leal    -12(%esp),%esp
         call    FPC_FREEMEM
         call    FPC_FREEMEM
-{$ifdef FPC_SYSTEM_STACKALIGNMENT16}
-        leal    8(%esp),%esp
+        leal    12(%esp),%esp
+{$else  FPC_SYSTEM_STACKALIGNMENT16}
+        jmp     FPC_FREEMEM        // can perform a tail call
 {$endif FPC_SYSTEM_STACKALIGNMENT16}
 {$endif FPC_SYSTEM_STACKALIGNMENT16}
-.Lj3596:
-        popl    %esi
-.Lquit:
 end;
 end;
 
 
 function fpc_truely_ansistr_unique(Var S : Pointer): Pointer; forward;
 function fpc_truely_ansistr_unique(Var S : Pointer): Pointer; forward;

+ 14 - 14
rtl/win/systhrd.inc

@@ -545,25 +545,25 @@ end;
 type 
 type 
       PWOHandleArray = ^THandle;
       PWOHandleArray = ^THandle;
 
 
-function CoWaitForMultipleObjects(nCount:DWORD; lpHandles : PWOHandleArray; bWaitAll:LONGBOOL; dwMilliseconds:DWORD):DWORD; external 'ole32.dll' name 'CoWaitForMultipleObjects';
+function CoWaitForMultipleHandles(dwFlags, dwTimeout: DWORD; cHandles: uint32; pHandles: PWOHandleArray; out lpdwindex: DWORD): HRESULT; stdcall; external 'ole32.dll' name 'CoWaitForMultipleHandles';
 
 
 function intbasiceventWaitFor(Timeout : Cardinal;state:peventstate;UseCOMWait: Boolean = False) : longint;
 function intbasiceventWaitFor(Timeout : Cardinal;state:peventstate;UseCOMWait: Boolean = False) : longint;
-
-var ret : Integer;
+const COWAIT_DEFAULT = 0;
+      RPC_S_CALLPENDING = HRESULT($80010115);
+var SignaledIndex : DWORD;
 begin
 begin
    if UseComWait Then
    if UseComWait Then
-     ret:=CoWaitForMultipleObjects(1,PWOHandleArray(@state), True, Timeout)
+     case CoWaitForMultipleHandles(COWAIT_DEFAULT, Timeout, 1, PWOHandleArray(@state), SignaledIndex) of
+       S_OK: Result := wrSignaled;
+       RPC_S_CALLPENDING: Result := wrTimeout;
+       else Result := wrError;
+     end
    else 
    else 
-     ret:=WaitForSingleObject(THandle(state), Timeout);
-
-   case ret of
-    WAIT_ABANDONED: Result := wrAbandoned;
-    WAIT_OBJECT_0: Result := wrSignaled;
-    WAIT_TIMEOUT: Result := wrTimeout;
-    WAIT_FAILED: Result := wrError;
-  else
-    Result := wrError;
-  end;
+     case WaitForSingleObject(THandle(state), Timeout) of
+       WAIT_OBJECT_0: Result := wrSignaled;
+       WAIT_TIMEOUT: Result := wrTimeout;
+       else result := wrError; { WAIT_FAILED or any other value. Note that only mutex waits can return WAIT_ABANDONED. }
+     end;
 end;
 end;
 
 
 function intRTLEventCreate: PRTLEvent;
 function intRTLEventCreate: PRTLEvent;

+ 16 - 54
rtl/x86_64/x86_64.inc

@@ -1009,20 +1009,10 @@ function declocked(var l : longint) : boolean;assembler; nostackframe;
 {$else FPC_PIC}
 {$else FPC_PIC}
      cmpl       $0,IsMultithread(%rip)
      cmpl       $0,IsMultithread(%rip)
 {$endif FPC_PIC}
 {$endif FPC_PIC}
-{$ifndef win64}
-     mov        %rdi, %rcx
-{$endif win64}
-     jz         .Ldeclockednolock
-     lock
-     decl       (%rcx)
-     setzb      %al
-     ret
-{$ifndef VER3_2}
-    .p2align 4,,10
-{$endif VER3_2}
-    .p2align 3
-.Ldeclockednolock:
-     decl       (%rcx)
+     jz         .Ldeclockedskiplock
+     .byte      0xF0 // LOCK prefix.
+.Ldeclockedskiplock:
+     decl       {$ifdef win64} (%rcx) {$else} (%rdi) {$endif}
      setzb      %al
      setzb      %al
   end;
   end;
 
 
@@ -1038,20 +1028,10 @@ function declocked(var l : int64) : boolean;assembler; nostackframe;
 {$else FPC_PIC}
 {$else FPC_PIC}
      cmpl       $0,IsMultithread(%rip)
      cmpl       $0,IsMultithread(%rip)
 {$endif FPC_PIC}
 {$endif FPC_PIC}
-{$ifndef win64}
-     mov        %rdi, %rcx
-{$endif win64}
-     jz         .Ldeclockednolock
-     lock
-     decq       (%rcx)
-     setzb      %al
-     ret
-{$ifndef VER3_2}
-    .p2align 4,,10
-{$endif VER3_2}
-    .p2align 3
-.Ldeclockednolock:
-     decq       (%rcx)
+     jz         .Ldeclockedskiplock
+     .byte      0xF0 // LOCK prefix.
+.Ldeclockedskiplock:
+     decq       {$ifdef win64} (%rcx) {$else} (%rdi) {$endif}
      setzb      %al
      setzb      %al
   end;
   end;
 
 
@@ -1068,19 +1048,10 @@ procedure inclocked(var l : longint);assembler; nostackframe;
 {$else FPC_PIC}
 {$else FPC_PIC}
      cmpl       $0,IsMultithread(%rip)
      cmpl       $0,IsMultithread(%rip)
 {$endif FPC_PIC}
 {$endif FPC_PIC}
-{$ifndef win64}
-     mov        %rdi, %rcx
-{$endif win64}
-     jz         .Linclockednolock
-     lock
-     incl       (%rcx)
-     ret
-{$ifndef VER3_2}
-    .p2align 4,,10
-{$endif VER3_2}
-    .p2align 3
-.Linclockednolock:
-     incl       (%rcx)
+     jz         .Linclockedskiplock
+     .byte      0xF0 // LOCK prefix.
+.Linclockedskiplock:
+     incl       {$ifdef win64} (%rcx) {$else} (%rdi) {$endif}
   end;
   end;
 
 
 
 
@@ -1096,19 +1067,10 @@ procedure inclocked(var l : int64);assembler; nostackframe;
 {$else FPC_PIC}
 {$else FPC_PIC}
      cmpl       $0,IsMultithread(%rip)
      cmpl       $0,IsMultithread(%rip)
 {$endif FPC_PIC}
 {$endif FPC_PIC}
-{$ifndef win64}
-     mov        %rdi, %rcx
-{$endif win64}
-     jz         .Linclockednolock
-     lock
-     incq       (%rcx)
-     ret
-{$ifndef VER3_2}
-    .p2align 4,,10
-{$endif VER3_2}
-    .p2align 3
-.Linclockednolock:
-     incq       (%rcx)
+     jz         .Linclockedskiplock
+     .byte      0xF0 // LOCK prefix.
+.Linclockedskiplock:
+     incq       {$ifdef win64} (%rcx) {$else} (%rdi) {$endif}
   end;
   end;
 
 
 
 

+ 15 - 0
tests/webtbf/tw40221a.pp

@@ -0,0 +1,15 @@
+{ %FAIL }
+
+{$mode objfpc} {$modeswitch anonymousfunctions}
+procedure Main;
+var
+	c: int32;
+begin
+	c := 12;
+	TProcedure(procedure begin writeln(c); end);
+end;
+
+begin
+	Main;
+end.
+

+ 17 - 0
tests/webtbf/tw40221b.pp

@@ -0,0 +1,17 @@
+{ %FAIL }
+
+{$mode objfpc} {$modeswitch anonymousfunctions}
+procedure Main;
+type
+  TProcMethod = procedure of object;
+var
+	c: int32;
+begin
+	c := 12;
+	TProcMethod(procedure begin writeln(c); end);
+end;
+
+begin
+	Main;
+end.
+

+ 36 - 0
tests/webtbs/tw40143.pp

@@ -0,0 +1,36 @@
+{ %NORUN }
+
+program tw40143;
+
+{$Mode objfpc}{$H+}
+{$ModeSwitch anonymousfunctions}
+{$ModeSwitch functionreferences}
+{$ModeSwitch nestedprocvars}
+
+type
+  TVoidFunc = reference to procedure;
+  TFuncMaker = reference to function(const thing: string): TVoidFunc;
+
+procedure something;
+  begin
+    writeln('something...');
+  end;
+
+procedure main;
+  var
+    cool_bingo: TVoidFunc;
+    coolifier: TFuncMaker;
+  begin
+    coolifier := function (const thing: string): TVoidFunc
+    begin
+      // result := procedure begin writeln('cool ', thing) end;
+      result := TVoidFunc(@something);
+    end;
+    cool_bingo := coolifier('bingo');
+    cool_bingo();
+  end;
+
+begin
+  main;
+end.
+

+ 36 - 0
tests/webtbs/tw40144.pp

@@ -0,0 +1,36 @@
+{ %NORUN }
+
+program tw40144;
+
+{$Mode objfpc}{$H+}
+{$ModeSwitch anonymousfunctions}
+{$ModeSwitch functionreferences}
+{$ModeSwitch nestedprocvars}
+
+type
+  TVoidFunc = reference to procedure;
+  TFuncMaker = reference to function(const thing: string): TVoidFunc;
+
+procedure main;
+  var
+    cool_bingo: TVoidFunc;
+    coolifier: TFuncMaker;
+  begin
+    cool_bingo := default(TVoidFunc);
+    coolifier := default(TFuncMaker);
+    coolifier := function (const thing: string): TVoidFunc
+    var
+      func: TVoidFunc;
+    begin
+      result := default(TVoidFunc); // <-- This is line 23
+      func := procedure begin writeln('cool ', thing) end;
+      result := func;
+    end;
+    cool_bingo := coolifier('bingo');
+    cool_bingo();
+  end;
+
+begin
+  main;
+end.
+

+ 35 - 0
tests/webtbs/tw40145.pp

@@ -0,0 +1,35 @@
+{ %NORUN }
+
+program tw40145;
+
+{$Mode objfpc}{$H+}
+{$ModeSwitch anonymousfunctions}
+{$ModeSwitch functionreferences}
+{$ModeSwitch nestedprocvars}
+
+type
+  TVoidFunc = reference to procedure;
+  TFuncMaker = reference to function(const thing: string): TVoidFunc;
+
+procedure main;
+  var
+    cool_bingo: TVoidFunc;
+    coolifier: TFuncMaker;
+  begin
+    cool_bingo := default(TVoidFunc);
+    coolifier := default(TFuncMaker);
+    coolifier := function (const thing: string): TVoidFunc
+    var
+      func: TVoidFunc;
+    begin
+      func := procedure begin writeln('cool ', thing) end;
+      result := func; // <-- This is line 24
+    end;
+    cool_bingo := coolifier('bingo');
+    cool_bingo();
+  end;
+
+begin
+  main;
+end.
+

+ 25 - 0
tests/webtbs/tw40308.pp

@@ -0,0 +1,25 @@
+program tw40308;
+
+{$mode delphi}
+{$modeswitch anonymousfunctions}
+{$modeswitch functionreferences}
+
+//uses
+//  SysUtils;
+
+type
+  TFunc1 = reference to function (P1: Integer): String;
+
+function GetTestFunc1(P2: Integer): TFunc1;
+begin
+  Result := function (P1: Integer): String begin
+      Result := '3'; // <-- Error: Internal error 2011010304
+      //Result := IntToStr(P1 + P2);
+    end;
+end;
+
+begin
+  if GetTestFunc1(1)(2) <> '3' then
+    Halt(1);
+end.
+

+ 65 - 0
tests/webtbs/tw40315.pp

@@ -0,0 +1,65 @@
+program tw40315;
+//This program compiles and runs in Delphi and in FPC. (at least should run in FPC)
+//It is intentionally designed this way.
+//It compiles without errors or warnings in Delphi and delivers the expected result.
+
+{$ifdef FPC}
+  {$mode objfpc}{$H+}
+  {$modeswitch functionreferences}
+  {$modeswitch anonymousfunctions}
+  // {$warn 5036 off}// "Warning: (5036) Local variable "$Capturer" does not seem to be initialized"
+{$endif}
+uses
+  {$IFDEF UNIX}
+  //cthreads,
+  {$ENDIF}
+  Classes,Sysutils { you can add units after this };
+
+type  TfuncS = reference to function:String;
+      TfuncF = reference to function(s:String):TfuncS;
+var   f_inner: TfuncS;
+      f_outer: TfuncF;
+
+procedure caller;
+begin
+  f_inner();
+end;
+
+procedure main;
+
+var str: String;
+   // f_outer: TfuncF;  // <---- doesnt compile in FPC when this is uncommented, but compiles and runs ok in Delphi
+
+begin
+
+    str := 'Hello World!';
+
+    f_outer := function(s:String):TfuncS //This captures local and persistent copy of "str"
+    begin
+      Result := function:String // <---- Access violation here, when Line "Result:=s" is commented out and when it is compiled.
+      begin
+        Result := s;  // <---- project1.lpr(37,9) Error: Internal error 2011010304
+                      // if the line is commented out it compiles, but gives access violation at runtime
+
+        Writeln(s);
+      end;
+      Writeln('Outer function was called');
+    end;
+    f_inner := f_outer(str);   //This instantiates the outer function and f_inner and captures their local context.
+
+    SetLength(str,0); //Erase the string content
+
+    Writeln('now calling f_inner');
+    caller();  //This line prints the string s="Hello World!", which was captured by the outer function.
+               //f_inner will be called from an external context, this is just for test and demonstration
+end;
+
+begin
+  main;
+  Writeln('Now the context of "main()" is lost. Can we still print the string "str"?');
+  //if f_inner()='Hello World!' then writeln('Yes! :-)') else writeln ('No! :-(');
+  if f_inner()<>'Hello World!' then
+    Halt(1);
+
+  //readln;
+end.