Browse Source

The Important Ones:
- 39683, 39684, 39685, 39686 (rework of Interface Method RTTI)
- 39687, 39688, 39689, 39690, 39709, 39710 (change of PPU version)

git-svn-id: branches/fixes_3_2@39809 -

marco 6 years ago
parent
commit
edf32cd5dc

+ 53 - 0
compiler/aasmcnst.pas

@@ -365,6 +365,9 @@ type
      { emit an ordinal constant }
      { emit an ordinal constant }
      procedure emit_ord_const(value: int64; def: tdef);
      procedure emit_ord_const(value: int64; def: tdef);
 
 
+     { emit a reference to a pooled shortstring constant }
+     procedure emit_pooled_shortstring_const_ref(const str:shortstring);
+
      { begin a potential aggregate type. Must be called for any type
      { begin a potential aggregate type. Must be called for any type
        that consists of multiple tai constant data entries, or that
        that consists of multiple tai constant data entries, or that
        represents an aggregate at the Pascal level (a record, a non-dynamic
        represents an aggregate at the Pascal level (a record, a non-dynamic
@@ -1846,6 +1849,56 @@ implementation
      end;
      end;
 
 
 
 
+   procedure ttai_typedconstbuilder.emit_pooled_shortstring_const_ref(const str:shortstring);
+     var
+       pool : thashset;
+       entry : phashsetitem;
+       strlab : tasmlabel;
+       l : longint;
+       pc : pansichar;
+       datadef : tdef;
+       strtcb : ttai_typedconstbuilder;
+     begin
+       pool:=current_asmdata.ConstPools[sp_shortstr];
+
+       entry:=pool.FindOrAdd(@str[1],length(str));
+
+       { :-(, we must generate a new entry }
+       if not assigned(entry^.Data) then
+         begin
+           current_asmdata.getglobaldatalabel(strlab);
+
+           { include length and terminating zero for quick conversion to pchar }
+           l:=length(str);
+           getmem(pc,l+2);
+           move(str[1],pc[1],l);
+           pc[0]:=chr(l);
+           pc[l+1]:=#0;
+
+           datadef:=carraydef.getreusable(cansichartype,l+2);
+
+           { we start a new constbuilder as we don't know whether we're called
+             from inside an internal constbuilder }
+           strtcb:=ctai_typedconstbuilder.create([tcalo_is_lab,tcalo_make_dead_strippable,tcalo_apply_constalign]);
+
+           strtcb.maybe_begin_aggregate(datadef);
+           strtcb.emit_tai(Tai_string.Create_pchar(pc,l+2),datadef);
+           strtcb.maybe_end_aggregate(datadef);
+
+           current_asmdata.asmlists[al_typedconsts].concatList(
+             strtcb.get_final_asmlist(strlab,datadef,sec_rodata_norel,strlab.name,const_align(sizeof(pint)))
+           );
+           strtcb.free;
+
+           entry^.Data:=strlab;
+         end
+       else
+         strlab:=tasmlabel(entry^.Data);
+
+       emit_tai(tai_const.Create_sym(strlab),charpointertype);
+     end;
+
+
    procedure ttai_typedconstbuilder.maybe_begin_aggregate(def: tdef);
    procedure ttai_typedconstbuilder.maybe_begin_aggregate(def: tdef);
      begin
      begin
        begin_aggregate_internal(def,false);
        begin_aggregate_internal(def,false);

+ 2 - 1
compiler/aasmdata.pas

@@ -96,7 +96,8 @@ interface
          sp_objcprotocolrefs,
          sp_objcprotocolrefs,
          sp_varsets,
          sp_varsets,
          sp_floats,
          sp_floats,
-         sp_guids
+         sp_guids,
+         sp_paraloc
       );
       );
       
       
     const
     const

+ 134 - 35
compiler/ncgrtti.pas

@@ -65,7 +65,7 @@ interface
         procedure write_callconv(tcb:ttai_typedconstbuilder;def:tabstractprocdef);
         procedure write_callconv(tcb:ttai_typedconstbuilder;def:tabstractprocdef);
         procedure write_paralocs(tcb:ttai_typedconstbuilder;para:pcgpara);
         procedure write_paralocs(tcb:ttai_typedconstbuilder;para:pcgpara);
         procedure write_param_flag(tcb:ttai_typedconstbuilder;parasym:tparavarsym);
         procedure write_param_flag(tcb:ttai_typedconstbuilder;parasym:tparavarsym);
-        procedure write_record_init_flag(tcb:ttai_typedconstbuilder;value:longword);
+        procedure write_mop_offset_table(tcb:ttai_typedconstbuilder;def:tabstractrecorddef;mop:tmanagementoperator);
       public
       public
         constructor create;
         constructor create;
         procedure write_rtti(def:tdef;rt:trttitype);
         procedure write_rtti(def:tdef;rt:trttitype);
@@ -175,7 +175,6 @@ implementation
                               TRTTIWriter
                               TRTTIWriter
 ***************************************************************************}
 ***************************************************************************}
 
 
-
     procedure TRTTIWriter.write_methods(tcb:ttai_typedconstbuilder;st:tsymtable;visibilities:tvisibilities);
     procedure TRTTIWriter.write_methods(tcb:ttai_typedconstbuilder;st:tsymtable;visibilities:tvisibilities);
       var
       var
         rtticount,
         rtticount,
@@ -230,7 +229,7 @@ implementation
                       write_methodkind(tcb,def);
                       write_methodkind(tcb,def);
                       tcb.emit_ord_const(def.paras.count,u16inttype);
                       tcb.emit_ord_const(def.paras.count,u16inttype);
                       tcb.emit_ord_const(def.callerargareasize,ptrsinttype);
                       tcb.emit_ord_const(def.callerargareasize,ptrsinttype);
-                      tcb.emit_shortstring_const(sym.realname);
+                      tcb.emit_pooled_shortstring_const_ref(sym.realname);
 
 
                       for k:=0 to def.paras.count-1 do
                       for k:=0 to def.paras.count-1 do
                         begin
                         begin
@@ -245,7 +244,8 @@ implementation
                           else
                           else
                             write_rtti_reference(tcb,para.vardef,fullrtti);
                             write_rtti_reference(tcb,para.vardef,fullrtti);
                           write_param_flag(tcb,para);
                           write_param_flag(tcb,para);
-                          tcb.emit_shortstring_const(para.realname);
+
+                          tcb.emit_pooled_shortstring_const_ref(para.realname);
 
 
                           write_paralocs(tcb,@para.paraloc[callerside]);
                           write_paralocs(tcb,@para.paraloc[callerside]);
 
 
@@ -348,27 +348,64 @@ implementation
       var
       var
         locs : trttiparalocs;
         locs : trttiparalocs;
         i : longint;
         i : longint;
+        pool : THashSet;
+        entry : PHashSetItem;
+        loclab : TAsmLabel;
+        loctcb : ttai_typedconstbuilder;
+        datadef : tdef;
       begin
       begin
         locs:=paramanager.cgparalocs_to_rttiparalocs(para^.location);
         locs:=paramanager.cgparalocs_to_rttiparalocs(para^.location);
         if length(locs)>high(byte) then
         if length(locs)>high(byte) then
           internalerror(2017010601);
           internalerror(2017010601);
-        tcb.begin_anonymous_record('',defaultpacking,min(reqalign,SizeOf(PInt)),
-          targetinfos[target_info.system]^.alignment.recordalignmin,
-          targetinfos[target_info.system]^.alignment.maxCrecordalign);
-        tcb.emit_ord_const(length(locs),u8inttype);
-        for i:=low(locs) to high(locs) do
+
+        if length(locs)=0 then
+          begin
+            { *shrugs* }
+            tcb.emit_tai(Tai_const.Create_nil_codeptr,voidpointertype);
+            exit;
+          end;
+
+        { do we have such a paraloc already in the pool? }
+        pool:=current_asmdata.ConstPools[sp_paraloc];
+
+        entry:=pool.FindOrAdd(@locs[0],length(locs)*sizeof(trttiparaloc));
+
+        if not assigned(entry^.Data) then
           begin
           begin
-            tcb.begin_anonymous_record('',defaultpacking,min(reqalign,SizeOf(PInt)),
+            current_asmdata.getglobaldatalabel(loclab);
+
+            loctcb:=ctai_typedconstbuilder.create([tcalo_is_lab,tcalo_make_dead_strippable,tcalo_apply_constalign]);
+
+            loctcb.begin_anonymous_record('',defaultpacking,min(reqalign,SizeOf(PInt)),
               targetinfos[target_info.system]^.alignment.recordalignmin,
               targetinfos[target_info.system]^.alignment.recordalignmin,
               targetinfos[target_info.system]^.alignment.maxCrecordalign);
               targetinfos[target_info.system]^.alignment.maxCrecordalign);
-            tcb.emit_ord_const(locs[i].loctype,u8inttype);
-            tcb.emit_ord_const(locs[i].regsub,u8inttype);
-            tcb.emit_ord_const(locs[i].regindex,u16inttype);
-            { the corresponding type for aint is alusinttype }
-            tcb.emit_ord_const(locs[i].offset,alusinttype);
-            tcb.end_anonymous_record;
-          end;
-        tcb.end_anonymous_record;
+            loctcb.emit_ord_const(length(locs),u8inttype);
+            for i:=low(locs) to high(locs) do
+              begin
+                loctcb.begin_anonymous_record('',defaultpacking,min(reqalign,SizeOf(PInt)),
+                  targetinfos[target_info.system]^.alignment.recordalignmin,
+                  targetinfos[target_info.system]^.alignment.maxCrecordalign);
+                loctcb.emit_ord_const(locs[i].loctype,u8inttype);
+                loctcb.emit_ord_const(locs[i].regsub,u8inttype);
+                loctcb.emit_ord_const(locs[i].regindex,u16inttype);
+                { the corresponding type for aint is alusinttype }
+                loctcb.emit_ord_const(locs[i].offset,alusinttype);
+                loctcb.end_anonymous_record;
+              end;
+            datadef:=loctcb.end_anonymous_record;
+
+            current_asmdata.asmlists[al_typedconsts].concatList(
+              loctcb.get_final_asmlist(loclab,datadef,sec_rodata_norel,loclab.name,const_align(sizeof(pint)))
+            );
+
+            loctcb.free;
+
+            entry^.data:=loclab;
+          end
+        else
+          loclab:=TAsmLabel(entry^.Data);
+
+        tcb.emit_tai(Tai_const.Create_sym(loclab),voidpointertype);
       end;
       end;
 
 
 
 
@@ -416,13 +453,79 @@ implementation
       end;
       end;
 
 
 
 
-    procedure TRTTIWriter.write_record_init_flag(tcb:ttai_typedconstbuilder;value:longword);
+    function compare_mop_offset_entry(item1,item2:pointer):longint;
+      var
+        entry1: pmanagementoperator_offset_entry absolute item1;
+        entry2: pmanagementoperator_offset_entry absolute item2;
+      begin
+        if entry1^.offset<entry2^.offset then
+          result:=-1
+        else if entry1^.offset>entry2^.offset then
+          result:=1
+        else
+          result:=0;
+      end;
+
+
+    procedure TRTTIWriter.write_mop_offset_table(tcb:ttai_typedconstbuilder;def:tabstractrecorddef;mop:tmanagementoperator);
+      var
+        list : tfplist;
+        datatcb : ttai_typedconstbuilder;
+        tbllbl : TAsmLabel;
+        entry : pmanagementoperator_offset_entry;
+        datadef,entrydef : tdef;
+        i : longint;
+        pdef : tobjectdef;
       begin
       begin
-        { keep this in sync with the type declaration of TRecordInfoInitFlag(s)
-          in both rttidecl.inc and typinfo.pp }
-        if target_info.endian=endian_big then
-          value:=reverse_longword(value);
-        tcb.emit_ord_const(value,u32inttype);
+        list:=tfplist.create;
+        tabstractrecordsymtable(def.symtable).get_managementoperator_offset_list(mop,list);
+        if (def.typ=objectdef) then
+          begin
+            pdef:=tobjectdef(def).childof;
+            while assigned(pdef) do
+              begin
+                tabstractrecordsymtable(pdef.symtable).get_managementoperator_offset_list(mop,list);
+                pdef:=pdef.childof;
+              end;
+            list.sort(@compare_mop_offset_entry);
+          end;
+        if list.count=0 then
+          tcb.emit_tai(tai_const.create_nil_dataptr,voidpointertype)
+        else
+          begin
+            tcb.start_internal_data_builder(current_asmdata.AsmLists[al_rtti],sec_rodata,'',datatcb,tbllbl);
+
+            datatcb.begin_anonymous_record('',defaultpacking,min(reqalign,SizeOf(PInt)),
+              targetinfos[target_info.system]^.alignment.recordalignmin,
+              targetinfos[target_info.system]^.alignment.maxCrecordalign);
+            datatcb.emit_ord_const(list.count,u32inttype);
+
+            entrydef:=get_recorddef(itp_init_mop_offset_entry,[voidcodepointertype,sizeuinttype],defaultpacking);
+
+            for i:=0 to list.count-1 do
+              begin
+                entry:=pmanagementoperator_offset_entry(list[i]);
+
+                datatcb.maybe_begin_aggregate(entrydef);
+
+                datatcb.queue_init(voidcodepointertype);
+                datatcb.queue_emit_proc(entry^.pd);
+
+                datatcb.queue_init(sizeuinttype);
+                datatcb.queue_emit_ordconst(entry^.offset,sizeuinttype);
+
+                datatcb.maybe_end_aggregate(entrydef);
+
+                dispose(entry);
+              end;
+
+            datadef:=datatcb.end_anonymous_record;
+
+            tcb.finish_internal_data_builder(datatcb,tbllbl,datadef,sizeof(pint));
+
+            tcb.emit_tai(tai_const.Create_sym(tbllbl),voidpointertype);
+          end;
+        list.free;
       end;
       end;
 
 
 
 
@@ -1213,10 +1316,8 @@ implementation
            { store rtti management operators only for init table }
            { store rtti management operators only for init table }
            if (rt=initrtti) then
            if (rt=initrtti) then
              begin
              begin
-               riif:=0;
-               if def.has_non_trivial_init_child(false) then
-                 riif:=riif or riifNonTrivialChild;
-               write_record_init_flag(tcb,riif);
+               { for now records don't have the initializer table }
+               tcb.emit_tai(Tai_const.Create_nil_dataptr,voidpointertype);
                if (trecordsymtable(def.symtable).managementoperators=[]) then
                if (trecordsymtable(def.symtable).managementoperators=[]) then
                  tcb.emit_tai(Tai_const.Create_nil_dataptr,voidpointertype)
                  tcb.emit_tai(Tai_const.Create_nil_dataptr,voidpointertype)
                else
                else
@@ -1369,12 +1470,11 @@ implementation
             { pointer to management operators available only for initrtti }
             { pointer to management operators available only for initrtti }
             if (rt=initrtti) then
             if (rt=initrtti) then
               begin
               begin
-                riif:=0;
-                if def.has_non_trivial_init_child(false) then
-                  riif:=riif or riifNonTrivialChild;
-                if assigned(def.childof) and def.childof.has_non_trivial_init_child(true) then
-                  riif:=riif or riifParentHasNonTrivialChild;
-                write_record_init_flag(tcb,riif);
+                { initializer table only available for classes currently }
+                if def.objecttype=odt_class then
+                  write_mop_offset_table(tcb,def,mop_initialize)
+                else
+                  tcb.emit_tai(Tai_const.Create_nil_dataptr,voidpointertype);
                 tcb.emit_tai(Tai_const.Create_nil_dataptr,voidpointertype);
                 tcb.emit_tai(Tai_const.Create_nil_dataptr,voidpointertype);
               end;
               end;
             { enclosing record takes care of alignment }
             { enclosing record takes care of alignment }
@@ -1905,7 +2005,6 @@ implementation
           current_module.add_extern_asmsym(s,AB_EXTERNAL,AT_DATA);
           current_module.add_extern_asmsym(s,AB_EXTERNAL,AT_DATA);
       end;
       end;
 
 
-
     procedure TRTTIWriter.write_rtti(def:tdef;rt:trttitype);
     procedure TRTTIWriter.write_rtti(def:tdef;rt:trttitype);
       var
       var
         tcb: ttai_typedconstbuilder;
         tcb: ttai_typedconstbuilder;

+ 5 - 71
compiler/ncgvmt.pas

@@ -69,15 +69,6 @@ interface
         procedure intf_create_vtbl(tcb: ttai_typedconstbuilder; AImplIntf: TImplementedInterface; intfindex: longint);
         procedure intf_create_vtbl(tcb: ttai_typedconstbuilder; AImplIntf: TImplementedInterface; intfindex: longint);
         procedure intf_gen_intf_ref(tcb: ttai_typedconstbuilder; AImplIntf: TImplementedInterface; intfindex: longint; interfaceentrydef, interfaceentrytypedef: tdef);
         procedure intf_gen_intf_ref(tcb: ttai_typedconstbuilder; AImplIntf: TImplementedInterface; intfindex: longint; interfaceentrydef, interfaceentrytypedef: tdef);
         procedure intf_write_table(tcb: ttai_typedconstbuilder; out lab: TAsmLabel; out intftabledef: trecorddef);
         procedure intf_write_table(tcb: ttai_typedconstbuilder; out lab: TAsmLabel; out intftabledef: trecorddef);
-        { get a table def of the form
-            record
-              count: countdef;
-              elements: array[0..count-1] of elementdef
-            end;
-          Returns both the outer record and the inner arraydef
-        }
-        procedure gettabledef(prefix: tinternaltypeprefix; countdef, elementdef: tdef; count: longint; packrecords: shortint; out recdef: trecorddef; out arrdef: tarraydef);
-        function getrecorddef(prefix: tinternaltypeprefix; const fields: array of tdef; packrecords: shortint): trecorddef;
         { generates the message tables for a class }
         { generates the message tables for a class }
         procedure genstrmsgtab(tcb: ttai_typedconstbuilder; out lab: tasmlabel; out msgstrtabledef: trecorddef);
         procedure genstrmsgtab(tcb: ttai_typedconstbuilder; out lab: tasmlabel; out msgstrtabledef: trecorddef);
         procedure genintmsgtab(tcb: ttai_typedconstbuilder; out lab: tasmlabel; out msginttabledef: trecorddef);
         procedure genintmsgtab(tcb: ttai_typedconstbuilder; out lab: tasmlabel; out msginttabledef: trecorddef);
@@ -302,7 +293,7 @@ implementation
            Instead of 0 as the upper bound, use the actual upper bound
            Instead of 0 as the upper bound, use the actual upper bound
          }
          }
          msgstrentry:=search_system_type('TMSGSTRTABLE').typedef;
          msgstrentry:=search_system_type('TMSGSTRTABLE').typedef;
-         gettabledef(itp_vmt_tstringmesssagetable,s32inttype,msgstrentry,count,0,msgstrtabledef,msgarraydef);
+         get_tabledef(itp_vmt_tstringmesssagetable,s32inttype,msgstrentry,count,0,msgstrtabledef,msgarraydef);
          { outer record (TStringMessageTable) }
          { outer record (TStringMessageTable) }
          datatcb.maybe_begin_aggregate(msgstrtabledef);
          datatcb.maybe_begin_aggregate(msgstrtabledef);
          datatcb.emit_tai(Tai_const.Create_32bit(count),s32inttype);
          datatcb.emit_tai(Tai_const.Create_32bit(count),s32inttype);
@@ -356,7 +347,7 @@ implementation
                 method : codepointer;
                 method : codepointer;
              end;
              end;
          }
          }
-         msginttabledef:=getrecorddef(itp_vmt_intern_msgint_table,[u32inttype,voidcodepointertype],0);
+         msginttabledef:=get_recorddef(itp_vmt_intern_msgint_table,[u32inttype,voidcodepointertype],0);
          { from objpas.inc:
          { from objpas.inc:
              TMsgInt = record
              TMsgInt = record
                 count : longint;
                 count : longint;
@@ -364,7 +355,7 @@ implementation
              end;
              end;
          }
          }
          tcb.start_internal_data_builder(current_asmdata.AsmLists[al_const],sec_rodata,_class.vmt_mangledname,datatcb,lab);
          tcb.start_internal_data_builder(current_asmdata.AsmLists[al_const],sec_rodata,_class.vmt_mangledname,datatcb,lab);
-         gettabledef(itp_vmt_msgint_table_entries,s32inttype,msginttabledef,count,0,msgintdef,msgintarrdef);
+         get_tabledef(itp_vmt_msgint_table_entries,s32inttype,msginttabledef,count,0,msgintdef,msgintarrdef);
          datatcb.maybe_begin_aggregate(msgintdef);
          datatcb.maybe_begin_aggregate(msgintdef);
          datatcb.emit_tai(Tai_const.Create_32bit(count),s32inttype);
          datatcb.emit_tai(Tai_const.Create_32bit(count),s32inttype);
          if assigned(root) then
          if assigned(root) then
@@ -549,7 +540,7 @@ implementation
                      addr : codepointer;
                      addr : codepointer;
                   end;
                   end;
               }
               }
-              lists.methodnamerec:=getrecorddef(itp_vmt_intern_tmethodnamerec,[cpointerdef.getreusable(cshortstringtype),voidcodepointertype],1);
+              lists.methodnamerec:=get_recorddef(itp_vmt_intern_tmethodnamerec,[cpointerdef.getreusable(cshortstringtype),voidcodepointertype],1);
               { from objpas.inc:
               { from objpas.inc:
                   tmethodnametable = packed record
                   tmethodnametable = packed record
                     count : dword;
                     count : dword;
@@ -557,7 +548,7 @@ implementation
                   end;
                   end;
                }
                }
               tcb.start_internal_data_builder(current_asmdata.AsmLists[al_const],sec_rodata,_class.vmt_mangledname,lists.pubmethodstcb,lab);
               tcb.start_internal_data_builder(current_asmdata.AsmLists[al_const],sec_rodata,_class.vmt_mangledname,lists.pubmethodstcb,lab);
-              gettabledef(itp_vmt_intern_tmethodnametable,u32inttype,lists.methodnamerec,count,1,pubmethodsdef,pubmethodsarraydef);
+              get_tabledef(itp_vmt_intern_tmethodnametable,u32inttype,lists.methodnamerec,count,1,pubmethodsdef,pubmethodsarraydef);
               { begin tmethodnametable }
               { begin tmethodnametable }
               lists.pubmethodstcb.maybe_begin_aggregate(pubmethodsdef);
               lists.pubmethodstcb.maybe_begin_aggregate(pubmethodsdef);
               { emit count field }
               { emit count field }
@@ -881,63 +872,6 @@ implementation
       end;
       end;
 
 
 
 
-    procedure TVMTWriter.gettabledef(prefix: tinternaltypeprefix; countdef, elementdef: tdef; count: longint; packrecords: shortint; out recdef: trecorddef; out arrdef: tarraydef);
-      var
-        fields: tfplist;
-        name: TIDString;
-        srsym: tsym;
-        srsymtable: tsymtable;
-      begin
-        { already created a message string table with this number of elements
-          in this unit -> reuse the def }
-        name:=internaltypeprefixName[prefix]+tostr(count);
-        if searchsym_type(copy(name,2,length(name)),srsym,srsymtable) then
-          begin
-            recdef:=trecorddef(ttypesym(srsym).typedef);
-            arrdef:=tarraydef(trecordsymtable(recdef.symtable).findfieldbyoffset(countdef.size).vardef);
-            exit
-          end;
-        recdef:=crecorddef.create_global_internal(name,packrecords,
-          targetinfos[target_info.system]^.alignment.recordalignmin,
-          targetinfos[target_info.system]^.alignment.maxCrecordalign);
-        fields:=tfplist.create;
-        fields.add(countdef);
-        if count>0 then
-          begin
-            arrdef:=carraydef.create(0,count-1,sizeuinttype);
-            arrdef.elementdef:=elementdef;
-            fields.add(arrdef);
-          end
-        else
-          arrdef:=nil;
-        recdef.add_fields_from_deflist(fields);
-        fields.free;
-      end;
-
-
-    function TVMTWriter.getrecorddef(prefix: tinternaltypeprefix; const fields: array of tdef; packrecords: shortint): trecorddef;
-      var
-        fieldlist: tfplist;
-        srsym: tsym;
-        srsymtable: tsymtable;
-        i: longint;
-      begin
-        if searchsym_type(copy(internaltypeprefixName[prefix],2,length(internaltypeprefixName[prefix])),srsym,srsymtable) then
-          begin
-            result:=trecorddef(ttypesym(srsym).typedef);
-            exit
-          end;
-        fieldlist:=tfplist.create;
-        for i:=low(fields) to high(fields) do
-          fieldlist.add(fields[i]);
-        result:=crecorddef.create_global_internal(internaltypeprefixName[prefix],packrecords,
-          targetinfos[target_info.system]^.alignment.recordalignmin,
-          targetinfos[target_info.system]^.alignment.maxCrecordalign);
-        result.add_fields_from_deflist(fieldlist);
-        fieldlist.free;
-      end;
-
-
   { Write interface identifiers to the data section }
   { Write interface identifiers to the data section }
   procedure TVMTWriter.writeinterfaceids(list: TAsmList);
   procedure TVMTWriter.writeinterfaceids(list: TAsmList);
     var
     var

+ 1 - 1
compiler/ppu.pas

@@ -43,7 +43,7 @@ type
 {$endif Test_Double_checksum}
 {$endif Test_Double_checksum}
 
 
 const
 const
-  CurrentPPUVersion = 201;
+  CurrentPPUVersion = 202;
 
 
 { unit flags }
 { unit flags }
   uf_init                = $000001; { unit has initialization section }
   uf_init                = $000001; { unit has initialization section }

+ 2 - 0
compiler/symconst.pas

@@ -734,6 +734,7 @@ type
     itp_rtti_set_outer,
     itp_rtti_set_outer,
     itp_rtti_set_inner,
     itp_rtti_set_inner,
     itp_init_record_operators,
     itp_init_record_operators,
+    itp_init_mop_offset_entry,
     itp_threadvar_record,
     itp_threadvar_record,
     itp_objc_method_list,
     itp_objc_method_list,
     itp_objc_proto_list,
     itp_objc_proto_list,
@@ -873,6 +874,7 @@ inherited_objectoptions : tobjectoptions = [oo_has_virtual,oo_has_private,oo_has
        '$rtti_set_outer$',
        '$rtti_set_outer$',
        '$rtti_set_inner$',
        '$rtti_set_inner$',
        '$init_record_operators$',
        '$init_record_operators$',
+       '$init_mop_offset_entry$',
        '$threadvar_record$',
        '$threadvar_record$',
        '$objc_method_list$',
        '$objc_method_list$',
        '$objc_proto_list$',
        '$objc_proto_list$',

+ 82 - 0
compiler/symdef.pas

@@ -1206,6 +1206,15 @@ interface
     function getparaencoding(def:tdef):tstringencoding; inline;
     function getparaencoding(def:tdef):tstringencoding; inline;
 
 
     function get_threadvar_record(def: tdef; out index_field, non_mt_data_field: tsym): trecorddef;
     function get_threadvar_record(def: tdef; out index_field, non_mt_data_field: tsym): trecorddef;
+    function get_recorddef(prefix:tinternaltypeprefix;const fields:array of tdef; packrecords:shortint): trecorddef;
+    { get a table def of the form
+        record
+          count: countdef;
+          elements: array[0..count-1] of elementdef
+        end;
+      Returns both the outer record and the inner arraydef
+    }
+    procedure get_tabledef(prefix:tinternaltypeprefix;countdef,elementdef:tdef;count:longint;packrecords:shortint;out recdef:trecorddef;out arrdef:tarraydef);
 
 
 implementation
 implementation
 
 
@@ -1320,6 +1329,79 @@ implementation
       end;
       end;
 
 
 
 
+    function get_recorddef(prefix:tinternaltypeprefix; const fields:array of tdef; packrecords:shortint): trecorddef;
+      var
+        fieldlist: tfplist;
+        srsym: tsym;
+        srsymtable: tsymtable;
+        i: longint;
+        name : TIDString;
+      begin
+        name:=copy(internaltypeprefixName[prefix],2,length(internaltypeprefixName[prefix]));
+        if searchsym_type(name,srsym,srsymtable) then
+          begin
+            result:=trecorddef(ttypesym(srsym).typedef);
+            exit
+          end;
+        { also always search in the current module (symtables are popped for
+          RTTI related code already) }
+        if searchsym_in_module(pointer(current_module),name,srsym,srsymtable) then
+          begin
+            result:=trecorddef(ttypesym(srsym).typedef);
+            exit;
+          end;
+        fieldlist:=tfplist.create;
+        for i:=low(fields) to high(fields) do
+          fieldlist.add(fields[i]);
+        result:=crecorddef.create_global_internal(internaltypeprefixName[prefix],packrecords,
+          targetinfos[target_info.system]^.alignment.recordalignmin,
+          targetinfos[target_info.system]^.alignment.maxCrecordalign);
+        result.add_fields_from_deflist(fieldlist);
+        fieldlist.free;
+      end;
+
+
+    procedure get_tabledef(prefix:tinternaltypeprefix;countdef,elementdef:tdef;count:longint;packrecords:shortint;out recdef:trecorddef;out arrdef:tarraydef);
+      var
+        fields: tfplist;
+        name: TIDString;
+        srsym: tsym;
+        srsymtable: tsymtable;
+      begin
+        { already created a message string table with this number of elements
+          in this unit -> reuse the def }
+        name:=internaltypeprefixName[prefix]+tostr(count);
+        if searchsym_type(copy(name,2,length(name)),srsym,srsymtable) then
+          begin
+            recdef:=trecorddef(ttypesym(srsym).typedef);
+            arrdef:=tarraydef(trecordsymtable(recdef.symtable).findfieldbyoffset(countdef.size).vardef);
+            exit
+          end;
+        { also always search in the current module (symtables are popped for
+          RTTI related code already) }
+        if searchsym_in_module(pointer(current_module),copy(name,2,length(name)),srsym,srsymtable) then
+          begin
+            recdef:=trecorddef(ttypesym(srsym).typedef);
+            arrdef:=tarraydef(trecordsymtable(recdef.symtable).findfieldbyoffset(countdef.size).vardef);
+            exit;
+          end;
+        recdef:=crecorddef.create_global_internal(name,packrecords,
+          targetinfos[target_info.system]^.alignment.recordalignmin,
+          targetinfos[target_info.system]^.alignment.maxCrecordalign);
+        fields:=tfplist.create;
+        fields.add(countdef);
+        if count>0 then
+          begin
+            arrdef:=carraydef.create(0,count-1,sizeuinttype);
+            arrdef.elementdef:=elementdef;
+            fields.add(arrdef);
+          end
+        else
+          arrdef:=nil;
+        recdef.add_fields_from_deflist(fields);
+        fields.free;
+      end;
+
     function make_mangledname(const typeprefix:TSymStr;st:TSymtable;const suffix:TSymStr):TSymStr;
     function make_mangledname(const typeprefix:TSymStr;st:TSymtable;const suffix:TSymStr):TSymStr;
       var
       var
         s,
         s,

+ 104 - 1
compiler/symtable.pas

@@ -91,6 +91,12 @@ interface
        tllvmshadowsymtable = class;
        tllvmshadowsymtable = class;
 {$endif llvm}
 {$endif llvm}
 
 
+       tmanagementoperator_offset_entry = record
+         pd : tprocdef;
+         offset : asizeint;
+       end;
+       pmanagementoperator_offset_entry = ^tmanagementoperator_offset_entry;
+
        tabstractrecordsymtable = class(tstoredsymtable)
        tabstractrecordsymtable = class(tstoredsymtable)
 {$ifdef llvm}
 {$ifdef llvm}
        private
        private
@@ -104,6 +110,7 @@ interface
           padalignment : shortint;   { size to a multiple of which the symtable has to be rounded up }
           padalignment : shortint;   { size to a multiple of which the symtable has to be rounded up }
           recordalignmin,            { local equivalents of global settings, so that records can }
           recordalignmin,            { local equivalents of global settings, so that records can }
           maxCrecordalign: shortint; { be created with custom settings internally }
           maxCrecordalign: shortint; { be created with custom settings internally }
+          has_fields_with_mop : tmanagementoperators; { whether any of the fields has the need for a management operator (or one of the field's fields) }
           constructor create(const n:string;usealign,recordminalign,recordmaxCalign:shortint);
           constructor create(const n:string;usealign,recordminalign,recordmaxCalign:shortint);
           destructor destroy;override;
           destructor destroy;override;
           procedure ppuload(ppufile:tcompilerppufile);override;
           procedure ppuload(ppufile:tcompilerppufile);override;
@@ -120,6 +127,10 @@ interface
           function is_packed: boolean;
           function is_packed: boolean;
           function has_single_field(out def:tdef): boolean;
           function has_single_field(out def:tdef): boolean;
           function get_unit_symtable: tsymtable;
           function get_unit_symtable: tsymtable;
+          { collects all management operators of the specified type in list (which
+            is not cleared); the entries are copies and thus must be freed by the
+            caller }
+          procedure get_managementoperator_offset_list(mop:tmanagementoperator;list:tfplist);
         protected
         protected
           { size in bytes including padding }
           { size in bytes including padding }
           _datasize      : asizeint;
           _datasize      : asizeint;
@@ -128,8 +139,12 @@ interface
           databitsize    : asizeint;
           databitsize    : asizeint;
           { size in bytes of padding }
           { size in bytes of padding }
           _paddingsize   : word;
           _paddingsize   : word;
+          { array of tmanagementoperator_offset_entry lists; only assigned if
+            they had been queried once by get_management_operator_list }
+          mop_list : array[tmanagementoperator] of tfplist;
           procedure setdatasize(val: asizeint);
           procedure setdatasize(val: asizeint);
           function getfieldoffset(sym: tfieldvarsym; base: asizeint; var globalfieldalignment: shortint): asizeint;
           function getfieldoffset(sym: tfieldvarsym; base: asizeint; var globalfieldalignment: shortint): asizeint;
+          procedure do_get_managementoperator_offset_list(data:tobject;arg:pointer);
         public
         public
           function iscurrentunit: boolean; override;
           function iscurrentunit: boolean; override;
           property datasize : asizeint read _datasize write setdatasize;
           property datasize : asizeint read _datasize write setdatasize;
@@ -479,7 +494,6 @@ implementation
                              TStoredSymtable
                              TStoredSymtable
 *****************************************************************************}
 *****************************************************************************}
 
 
-
     constructor tstoredsymtable.create(const s:string);
     constructor tstoredsymtable.create(const s:string);
       begin
       begin
         inherited create(s);
         inherited create(s);
@@ -1161,11 +1175,22 @@ implementation
 
 
 
 
     destructor tabstractrecordsymtable.destroy;
     destructor tabstractrecordsymtable.destroy;
+      var
+        mop : tmanagementoperator;
+        mopofs : pmanagementoperator_offset_entry;
+        i : longint;
       begin
       begin
 {$ifdef llvm}
 {$ifdef llvm}
         if refcount=1 then
         if refcount=1 then
           fllvmst.free;
           fllvmst.free;
 {$endif llvm}
 {$endif llvm}
+        for mop in tmanagementoperator do
+          begin
+            if assigned(mop_list[mop]) then
+              for i:=0 to mop_list[mop].count-1 do
+                dispose(pmanagementoperator_offset_entry(mop_list[mop][i]));
+            mop_list[mop].free;
+          end;
         inherited destroy;
         inherited destroy;
       end;
       end;
 
 
@@ -1179,6 +1204,7 @@ implementation
         recordalignmin:=shortint(ppufile.getbyte);
         recordalignmin:=shortint(ppufile.getbyte);
         if (usefieldalignment=C_alignment) then
         if (usefieldalignment=C_alignment) then
           fieldalignment:=shortint(ppufile.getbyte);
           fieldalignment:=shortint(ppufile.getbyte);
+        ppufile.getsmallset(has_fields_with_mop);
         inherited ppuload(ppufile);
         inherited ppuload(ppufile);
       end;
       end;
 
 
@@ -1196,6 +1222,10 @@ implementation
          ppufile.putbyte(byte(recordalignmin));
          ppufile.putbyte(byte(recordalignmin));
          if (usefieldalignment=C_alignment) then
          if (usefieldalignment=C_alignment) then
            ppufile.putbyte(byte(fieldalignment));
            ppufile.putbyte(byte(fieldalignment));
+         { it's not really a "symtableoption", but loading this from the record
+           def requires storing the set in the recorddef at least between
+           ppuload and deref/derefimpl }
+         ppufile.putsmallset(has_fields_with_mop);
          ppufile.writeentry(ibrecsymtableoptions);
          ppufile.writeentry(ibrecsymtableoptions);
 
 
          inherited ppuwrite(ppufile);
          inherited ppuwrite(ppufile);
@@ -1259,6 +1289,11 @@ implementation
         sym.visibility:=vis;
         sym.visibility:=vis;
         { this symbol can't be loaded to a register }
         { this symbol can't be loaded to a register }
         sym.varregable:=vr_none;
         sym.varregable:=vr_none;
+        { management operators }
+        if sym.vardef.typ in [recorddef,objectdef] then
+          has_fields_with_mop:=has_fields_with_mop + tabstractrecordsymtable(tabstractrecorddef(sym.vardef).symtable).has_fields_with_mop;
+        if sym.vardef.typ=recorddef then
+          has_fields_with_mop:=has_fields_with_mop + trecordsymtable(trecorddef(sym.vardef).symtable).managementoperators;
         { Calculate field offset }
         { Calculate field offset }
         l:=sym.getsize;
         l:=sym.getsize;
         vardef:=sym.vardef;
         vardef:=sym.vardef;
@@ -1608,6 +1643,74 @@ implementation
           result:=result.defowner.owner;
           result:=result.defowner.owner;
       end;
       end;
 
 
+
+    procedure tabstractrecordsymtable.do_get_managementoperator_offset_list(data:tobject;arg:pointer);
+      var
+        sym : tsym absolute data;
+        fsym : tfieldvarsym absolute data;
+        mop : tmanagementoperator absolute arg;
+        entry : pmanagementoperator_offset_entry;
+        sublist : tfplist;
+        i : longint;
+      begin
+        if sym.typ<>fieldvarsym then
+          exit;
+        if not is_record(fsym.vardef) and not is_object(fsym.vardef) and not is_cppclass(fsym.vardef) then
+          exit;
+        if not assigned(mop_list[mop]) then
+          internalerror(2018082303);
+
+        if is_record(fsym.vardef) then
+          begin
+            if mop in trecordsymtable(trecorddef(fsym.vardef).symtable).managementoperators then
+              begin
+                new(entry);
+                entry^.pd:=search_management_operator(mop,fsym.vardef);
+                if not assigned(entry^.pd) then
+                  internalerror(2018082302);
+                entry^.offset:=fsym.fieldoffset;
+                mop_list[mop].add(entry);
+              end;
+          end;
+
+        sublist:=tfplist.create;
+        tabstractrecordsymtable(tabstractrecorddef(fsym.vardef).symtable).get_managementoperator_offset_list(mop,sublist);
+        for i:=0 to sublist.count-1 do
+          begin
+            entry:=pmanagementoperator_offset_entry(sublist[i]);
+            entry^.offset:=entry^.offset+fsym.fieldoffset;
+            mop_list[mop].add(entry);
+          end;
+        { we don't need to remove the entries as they become part of list }
+        sublist.free;
+      end;
+
+    procedure tabstractrecordsymtable.get_managementoperator_offset_list(mop:tmanagementoperator;list:tfplist);
+      var
+        i : longint;
+        entry,entrycopy : pmanagementoperator_offset_entry;
+      begin
+        if not assigned(list) then
+          internalerror(2018082301);
+        if mop=mop_none then
+          exit;
+        if not (mop in has_fields_with_mop) then
+          { none of the fields or one of the field's fields has the requested operator }
+          exit;
+        if not assigned(mop_list[mop]) then
+          begin
+            mop_list[mop]:=tfplist.create;
+            SymList.ForEachCall(@do_get_managementoperator_offset_list,pointer(ptruint(mop)));
+          end;
+        for i:=0 to mop_list[mop].count-1 do
+          begin
+            entry:=pmanagementoperator_offset_entry(mop_list[mop][i]);
+            New(entrycopy);
+            entrycopy^:=entry^;
+            list.add(entrycopy);
+          end;
+      end;
+
     procedure tabstractrecordsymtable.setdatasize(val: asizeint);
     procedure tabstractrecordsymtable.setdatasize(val: asizeint);
       begin
       begin
         _datasize:=val;
         _datasize:=val;

+ 7 - 3
compiler/utils/ppuutils/ppudump.pp

@@ -654,6 +654,8 @@ end;
                              Read Routines
                              Read Routines
 ****************************************************************************}
 ****************************************************************************}
 
 
+function readmanagementoperatoroptions(const space : string;const name : string):tmanagementoperators;forward;
+
 procedure readrecsymtableoptions;
 procedure readrecsymtableoptions;
 var
 var
   usefieldalignment : shortint;
   usefieldalignment : shortint;
@@ -669,6 +671,7 @@ begin
   writeln([space,' recordalignmin: ',shortint(ppufile.getbyte)]);
   writeln([space,' recordalignmin: ',shortint(ppufile.getbyte)]);
   if (usefieldalignment=C_alignment) then
   if (usefieldalignment=C_alignment) then
     writeln([space,' fieldalignment: ',shortint(ppufile.getbyte)]);
     writeln([space,' fieldalignment: ',shortint(ppufile.getbyte)]);
+  readmanagementoperatoroptions(space,'Fields have MOPs');
 end;
 end;
 
 
 procedure readsymtableoptions(const s: string);
 procedure readsymtableoptions(const s: string);
@@ -2330,7 +2333,7 @@ end;
 
 
 
 
 
 
-function readmanagementoperatoroptions(const space : string):tmanagementoperators;
+function readmanagementoperatoroptions(const space : string;const name : string):tmanagementoperators;
 { type is in unit symconst }
 { type is in unit symconst }
 { Management operator options
 { Management operator options
   tmanagementoperator=(
   tmanagementoperator=(
@@ -2366,7 +2369,8 @@ begin
          if first then
          if first then
            begin
            begin
              write(space);
              write(space);
-             write('Management operators: ');
+             write(name);
+             write(': ');
              first:=false;
              first:=false;
            end
            end
          else
          else
@@ -3360,7 +3364,7 @@ begin
                  objdef.Size:=getasizeint;
                  objdef.Size:=getasizeint;
                  writeln([space,'         DataSize : ',objdef.Size]);
                  writeln([space,'         DataSize : ',objdef.Size]);
                  writeln([space,'      PaddingSize : ',getword]);
                  writeln([space,'      PaddingSize : ',getword]);
-                 readmanagementoperatoroptions(space);
+                 readmanagementoperatoroptions(space,'Management operators');
                end;
                end;
              {read the record definitions and symbols}
              {read the record definitions and symbols}
              if not(df_copied_def in current_defoptions) then
              if not(df_copied_def in current_defoptions) then

+ 16 - 16
rtl/inc/objpas.inc

@@ -382,8 +382,9 @@
 {$ifndef VER3_0}
 {$ifndef VER3_0}
         var
         var
            vmt  : PVmt;
            vmt  : PVmt;
-           temp : pointer;
-           flags : TRecordInfoInitFlags;
+           inittable : pointer;
+           mopinittable : PRTTIRecordOpOffsetTable;
+           i : longint;
 {$endif VER3_0}
 {$endif VER3_0}
         begin
         begin
            { the size is saved at offset 0 }
            { the size is saved at offset 0 }
@@ -397,23 +398,22 @@
 {$ifndef VER3_0}
 {$ifndef VER3_0}
            { for management operators like initialize call int_initialize }
            { for management operators like initialize call int_initialize }
            vmt := PVmt(self);
            vmt := PVmt(self);
-           while vmt<>nil do
+           if assigned(vmt) then
              begin
              begin
-               Temp:= vmt^.vInitTable;
-               if assigned(Temp) then
+               inittable:=vmt^.vInitTable;
+               if assigned(inittable) then
                  begin
                  begin
-                   flags:=RecordRTTIInitFlags(Temp);
-                   if riifNonTrivialChild in flags then
-                     { The RTTI format matches one for records, except the type
-                       is tkClass. Since RecordRTTI does not check the type,
-                       calling it yields the desired result. }
-                     RecordRTTI(Instance,Temp,@int_initialize);
-                   { no need to continue complex initializing up the inheritance
-                     tree if none of the parents require it anyway }
-                   if not (riifParentHasNonTrivialChild in flags) then
-                     break;
+                   mopinittable:=RTTIRecordMopInitTable(inittable);
+                   if assigned(mopinittable) then
+                     begin
+                       {$push}
+                       { ensure that no range check errors pop up with the [0..0] array }
+                       {$R-}
+                       for i:=0 to mopinittable^.Count-1 do
+                         TRTTIRecVarOp(mopinittable^.Entries[i].ManagmentOperator)(PByte(Instance)+mopinittable^.Entries[i].FieldOffset);
+                       {$pop}
+                     end;
                  end;
                  end;
-               vmt:= vmt^.vParent;
              end;
              end;
 {$endif VER3_0}
 {$endif VER3_0}
 
 

+ 2 - 2
rtl/inc/rtti.inc

@@ -138,10 +138,10 @@ end;
 
 
 
 
 {$ifndef VER3_0}
 {$ifndef VER3_0}
-function RecordRTTIInitFlags(ti: Pointer): TRecordInfoInitFlags;
+function RTTIRecordMopInitTable(ti: Pointer): PRTTIRecordOpOffsetTable;
 begin
 begin
   ti:=aligntoqword(ti+2+PByte(ti)[1]);
   ti:=aligntoqword(ti+2+PByte(ti)[1]);
-  Result:=PRecordInfoInit(ti)^.Flags;
+  Result:=PRecordInfoInit(ti)^.InitRecordOpTable;
 end;
 end;
 {$endif VER3_0}
 {$endif VER3_0}
 
 

+ 19 - 19
rtl/inc/rttidecl.inc

@@ -92,24 +92,24 @@ type
     Copy: TRTTIRecCopyOp;
     Copy: TRTTIRecCopyOp;
   end;
   end;
 
 
-{$ifndef VER3_0}
-{$push}
-
-{ better alignment for TRecordInfoInit }
-{ keep in sync with ncgrtti.TRTTIWriter.write_record_init_flag() and typinfo.pp }
-{ ToDo: different values for 8/16-bit platforms? }
-{$minenumsize 4}
-{$packset 4}
-
-  TRecordInfoInitFlag = (
-    riifNonTrivialChild,
-    { only relevant for classes }
-    riifParentHasNonTrivialChild
-  );
-  TRecordInfoInitFlags = set of TRecordInfoInitFlag;
+  TRTTIRecordOpOffsetEntry =
+{$ifdef USE_PACKED}
+  packed
+{$endif USE_PACKED}
+  record
+    ManagmentOperator: CodePointer;
+    FieldOffset: SizeUInt;
+  end;
 
 
-{$pop}
-{$endif}
+  TRTTIRecordOpOffsetTable =
+{$ifdef USE_PACKED}
+  packed
+{$endif USE_PACKED}
+  record
+    Count: LongWord;
+    Entries: array[0..0] of TRTTIRecordOpOffsetEntry;
+  end;
+  PRTTIRecordOpOffsetTable = ^TRTTIRecordOpOffsetTable;
 
 
   TRecordInfoInit=
   TRecordInfoInit=
 {$ifdef USE_PACKED}
 {$ifdef USE_PACKED}
@@ -119,7 +119,7 @@ type
     Terminator: Pointer;
     Terminator: Pointer;
     Size: Longint;
     Size: Longint;
 {$ifndef VER3_0}
 {$ifndef VER3_0}
-    Flags: TRecordInfoInitFlags;
+    InitRecordOpTable: PRTTIRecordOpOffsetTable;
     RecordOp: PRTTIRecordOpVMT;
     RecordOp: PRTTIRecordOpVMT;
 {$endif VER3_0}
 {$endif VER3_0}
     Count: Longint;
     Count: Longint;
@@ -148,7 +148,7 @@ type
 
 
 
 
 {$ifndef VER3_0}
 {$ifndef VER3_0}
-function RecordRTTIInitFlags(ti: Pointer): TRecordInfoInitFlags; forward;
+function RTTIRecordMopInitTable(ti: Pointer): PRTTIRecordOpOffsetTable; forward;
 {$endif VER3_0}
 {$endif VER3_0}
 
 
 {$ifdef VER3_0}
 {$ifdef VER3_0}

+ 43 - 52
rtl/objpas/typinfo.pp

@@ -328,15 +328,15 @@ unit TypInfo;
       {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
       {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
       record
       record
       private
       private
-        function GetParaLocs: PParameterLocations; inline;
         function GetTail: Pointer; inline;
         function GetTail: Pointer; inline;
         function GetNext: PVmtMethodParam; inline;
         function GetNext: PVmtMethodParam; inline;
+        function GetName: ShortString; inline;
       public
       public
         ParamType: PPTypeInfo;
         ParamType: PPTypeInfo;
         Flags: TParamFlags;
         Flags: TParamFlags;
-        Name: ShortString;
-        { ParaLocs: TParameterLocations; }
-        property ParaLocs: PParameterLocations read GetParaLocs;
+        NamePtr: PShortString;
+        ParaLocs: PParameterLocations;
+        property Name: ShortString read GetName;
         property Tail: Pointer read GetTail;
         property Tail: Pointer read GetTail;
         property Next: PVmtMethodParam read GetNext;
         property Next: PVmtMethodParam read GetNext;
       end;
       end;
@@ -352,15 +352,17 @@ unit TypInfo;
         function GetResultLocs: PParameterLocations; inline;
         function GetResultLocs: PParameterLocations; inline;
         function GetTail: Pointer; inline;
         function GetTail: Pointer; inline;
         function GetNext: PIntfMethodEntry; inline;
         function GetNext: PIntfMethodEntry; inline;
+        function GetName: ShortString; inline;
       public
       public
         ResultType: PPTypeInfo;
         ResultType: PPTypeInfo;
         CC: TCallConv;
         CC: TCallConv;
         Kind: TMethodKind;
         Kind: TMethodKind;
         ParamCount: Word;
         ParamCount: Word;
         StackSize: SizeInt;
         StackSize: SizeInt;
-        Name: ShortString;
+        NamePtr: PShortString;
         { Params: array[0..ParamCount - 1] of TVmtMethodParam }
         { Params: array[0..ParamCount - 1] of TVmtMethodParam }
-        { ResultLocs: TParameterLocations (if ResultType != Nil) }
+        { ResultLocs: PParameterLocations (if ResultType != Nil) }
+        property Name: ShortString read GetName;
         property Param[Index: Word]: PVmtMethodParam read GetParam;
         property Param[Index: Word]: PVmtMethodParam read GetParam;
         property ResultLocs: PParameterLocations read GetResultLocs;
         property ResultLocs: PParameterLocations read GetResultLocs;
         property Tail: Pointer read GetTail;
         property Tail: Pointer read GetTail;
@@ -408,25 +410,24 @@ unit TypInfo;
         Entries: array[0..0] of TVmtMethodEntry;
         Entries: array[0..0] of TVmtMethodEntry;
       end;
       end;
 
 
+      TRecOpOffsetEntry =
+      {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
+      packed
+      {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
+      record
+        ManagementOperator: CodePointer;
+        FieldOffset: SizeUInt;
+      end;
 
 
-{$ifndef VER3_0}
-{$push}
-
-{ better alignment for TRecordInfoInit }
-{ keep in sync with ncgrtti.TRTTIWriter.write_record_init_flag() and rttidecl.inc }
-{ ToDo: different values for 8/16-bit platforms? }
-{$minenumsize 4}
-{$packset 4}
-
-      TRecordInfoInitFlag = (
-        riifNonTrivialChild,
-        { only relevant for classes }
-        riifParentHasNonTrivialChild
-      );
-      TRecordInfoInitFlags = set of TRecordInfoInitFlag;
-
-{$pop}
-{$endif}
+      TRecOpOffsetTable =
+      {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
+      packed
+      {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
+      record
+        Count: LongWord;
+        Entries: array[0..0] of TRecOpOffsetEntry;
+      end;
+      PRecOpOffsetTable = ^TRecOpOffsetTable;
 
 
       PRecInitData = ^TRecInitData;
       PRecInitData = ^TRecInitData;
       TRecInitData =
       TRecInitData =
@@ -437,7 +438,7 @@ unit TypInfo;
         Terminator: Pointer;
         Terminator: Pointer;
         Size: Integer;
         Size: Integer;
 {$ifndef VER3_0}
 {$ifndef VER3_0}
-        Flags: TRecordInfoInitFlags;
+        InitOffsetOp: PRecOpOffsetTable;
         ManagementOp: Pointer;
         ManagementOp: Pointer;
 {$endif}
 {$endif}
         ManagedFieldCount: Integer;
         ManagedFieldCount: Integer;
@@ -2960,14 +2961,9 @@ end;
 
 
 { TVmtMethodParam }
 { TVmtMethodParam }
 
 
-function TVmtMethodParam.GetParaLocs: PParameterLocations;
-begin
-  Result := PParameterLocations(aligntoptr(PByte(@Name[0]) + Length(Name) + Sizeof(Name[0])));
-end;
-
 function TVmtMethodParam.GetTail: Pointer;
 function TVmtMethodParam.GetTail: Pointer;
 begin
 begin
-  Result := ParaLocs^.Tail;
+  Result := PByte(@ParaLocs) + SizeOf(ParaLocs);
 end;
 end;
 
 
 function TVmtMethodParam.GetNext: PVmtMethodParam;
 function TVmtMethodParam.GetNext: PVmtMethodParam;
@@ -2975,6 +2971,11 @@ begin
   Result := PVmtMethodParam(aligntoptr(Tail));
   Result := PVmtMethodParam(aligntoptr(Tail));
 end;
 end;
 
 
+function TVmtMethodParam.GetName: ShortString;
+begin
+  Result := NamePtr^;
+end;
+
 { TIntfMethodEntry }
 { TIntfMethodEntry }
 
 
 function TIntfMethodEntry.GetParam(Index: Word): PVmtMethodParam;
 function TIntfMethodEntry.GetParam(Index: Word): PVmtMethodParam;
@@ -2982,39 +2983,24 @@ begin
   if Index >= ParamCount then
   if Index >= ParamCount then
     Result := Nil
     Result := Nil
   else
   else
-    begin
-      Result := PVmtMethodParam(aligntoptr(PByte(@Name[0]) + SizeOf(Name[0]) + Length(Name)));
-      while Index > 0 do
-        begin
-          Result := Result^.Next;
-          Dec(Index);
-        end;
-    end;
+    Result := PVmtMethodParam(PByte(aligntoptr(PByte(@NamePtr) + SizeOf(NamePtr))) + Index * PtrUInt(aligntoptr(Pointer(SizeOf(TVmtMethodParam)))));
 end;
 end;
 
 
 function TIntfMethodEntry.GetResultLocs: PParameterLocations;
 function TIntfMethodEntry.GetResultLocs: PParameterLocations;
 begin
 begin
   if not Assigned(ResultType) then
   if not Assigned(ResultType) then
     Result := Nil
     Result := Nil
-  else if ParamCount = 0 then
-    Result := PParameterLocations(aligntoptr(PByte(@Name[0]) + SizeOf(Name[0]) + Length(Name)))
   else
   else
-    Result := PParameterLocations(aligntoptr(Param[ParamCount - 1]^.Tail));
+    Result := PParameterLocations(PByte(aligntoptr(PByte(@NamePtr) + SizeOf(NamePtr))) + ParamCount * PtrUInt(aligntoptr(Pointer(SizeOf(TVmtMethodParam)))));
 end;
 end;
 
 
 function TIntfMethodEntry.GetTail: Pointer;
 function TIntfMethodEntry.GetTail: Pointer;
-var
-  retloc: PParameterLocations;
 begin
 begin
+  Result := PByte(@NamePtr) + SizeOf(NamePtr);
+  if ParamCount > 0 then
+    Result := PByte(aligntoptr(Result)) + ParamCount * PtrUInt(aligntoptr(Pointer(SizeOf(TVmtMethodParam))));
   if Assigned(ResultType) then
   if Assigned(ResultType) then
-    begin
-      retloc := ResultLocs;
-      Result := PByte(@retloc^.Count) + SizeOf(retloc^.Count) + SizeOf(TParameterLocation) * retloc^.Count;
-    end
-  else if ParamCount = 0 then
-    Result := PByte(@Name[0]) + Length(Name) + SizeOf(Byte)
-  else
-    Result := Param[ParamCount - 1]^.Tail;
+    Result := PByte(aligntoptr(Result)) + SizeOf(PParameterLocations);
 end;
 end;
 
 
 function TIntfMethodEntry.GetNext: PIntfMethodEntry;
 function TIntfMethodEntry.GetNext: PIntfMethodEntry;
@@ -3022,6 +3008,11 @@ begin
   Result := PIntfMethodEntry(aligntoptr(Tail));
   Result := PIntfMethodEntry(aligntoptr(Tail));
 end;
 end;
 
 
+function TIntfMethodEntry.GetName: ShortString;
+begin
+  Result := NamePtr^;
+end;
+
 { TIntfMethodTable }
 { TIntfMethodTable }
 
 
 function TIntfMethodTable.GetMethod(Index: Word): PIntfMethodEntry;
 function TIntfMethodTable.GetMethod(Index: Word): PIntfMethodEntry;