Browse Source

+ add method to retrieve a list of management operator/field offset pairs for a specific management operator inside a structured type (no matter how deeply nested they are)

git-svn-id: trunk@39689 -
svenbarth 7 years ago
parent
commit
21e7ddaac7
1 changed files with 90 additions and 1 deletions
  1. 90 1
      compiler/symtable.pas

+ 90 - 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
@@ -120,6 +126,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 +138,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 +493,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 +1174,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;
 
 
@@ -1608,6 +1632,71 @@ 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 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;