Browse Source

Redesign RTTISizeAndOp to return more useful information.

Rika Ichinose 11 months ago
parent
commit
6de766e40a
3 changed files with 69 additions and 50 deletions
  1. 5 6
      rtl/inc/dynarr.inc
  2. 52 39
      rtl/inc/rtti.inc
  3. 12 5
      rtl/inc/rttidecl.inc

+ 5 - 6
rtl/inc/dynarr.inc

@@ -146,7 +146,7 @@ procedure fpc_dynarray_setlength(var p : pointer;pti : pointer;
      ti : pointer;
      ti : pointer;
      elesize : sizeint;
      elesize : sizeint;
      eletype,eletypemngd : pointer;
      eletype,eletypemngd : pointer;
-     movsize : sizeint;
+     movsize,_size : sizeint;
 
 
   begin
   begin
      { negative or zero length? }
      { negative or zero length? }
@@ -181,8 +181,8 @@ procedure fpc_dynarray_setlength(var p : pointer;pti : pointer;
      if not(assigned(p)) then
      if not(assigned(p)) then
        begin
        begin
           newp:=AllocMem(size);
           newp:=AllocMem(size);
-          { call int_InitializeArray for management operators }
-          if assigned(eletypemngd) and (PTypeKind(eletype)^ in [tkRecord, tkObject]) then
+          { call int_InitializeArray for management operators; not required if no operators as memory is already zeroed }
+          if assigned(eletypemngd) and (PTypeKind(eletype)^ in [tkRecord, tkObject, tkArray]) and (RTTIManagementAndSize(eletype, rotInitialize, _size)=manCustom) then
             int_InitializeArray(pointer(newp)+sizeof(tdynarray), eletype, dims[0]);
             int_InitializeArray(pointer(newp)+sizeof(tdynarray), eletype, dims[0]);
        end
        end
      else
      else
@@ -204,7 +204,7 @@ procedure fpc_dynarray_setlength(var p : pointer;pti : pointer;
                if size-sizeof(tdynarray)>movsize then
                if size-sizeof(tdynarray)>movsize then
                  begin
                  begin
                    fillchar((pointer(newp)+sizeof(tdynarray)+movsize)^,size-sizeof(tdynarray)-movsize,0);
                    fillchar((pointer(newp)+sizeof(tdynarray)+movsize)^,size-sizeof(tdynarray)-movsize,0);
-                   if assigned(eletypemngd) and (PTypeKind(eletype)^ in [tkRecord, tkObject]) then
+                   if assigned(eletypemngd) and (PTypeKind(eletype)^ in [tkRecord, tkObject, tkArray]) and (RTTIManagementAndSize(eletype, rotInitialize, _size)=manCustom) then
                      int_InitializeArray(pointer(newp)+sizeof(tdynarray)+movsize, eletype, dims[0]-movelen);
                      int_InitializeArray(pointer(newp)+sizeof(tdynarray)+movsize, eletype, dims[0]-movelen);
                  end;
                  end;
 
 
@@ -238,8 +238,7 @@ procedure fpc_dynarray_setlength(var p : pointer;pti : pointer;
                newp := realp;
                newp := realp;
                fillchar((pointer(newp)+sizeof(tdynarray)+elesize*(newp^.high+1))^,
                fillchar((pointer(newp)+sizeof(tdynarray)+elesize*(newp^.high+1))^,
                  (dims[0]-newp^.high-1)*elesize,0);
                  (dims[0]-newp^.high-1)*elesize,0);
-               { call int_InitializeArray for management operators }
-               if assigned(eletypemngd) and (PTypeKind(eletype)^ in [tkRecord, tkObject]) then
+               if assigned(eletypemngd) and (PTypeKind(eletype)^ in [tkRecord, tkObject, tkArray]) and (RTTIManagementAndSize(eletype, rotInitialize, _size)=manCustom) then
                  int_InitializeArray(pointer(newp)+sizeof(tdynarray)+elesize*(newp^.high+1),
                  int_InitializeArray(pointer(newp)+sizeof(tdynarray)+elesize*(newp^.high+1),
                    eletype, dims[0]-newp^.high-1);
                    eletype, dims[0]-newp^.high-1);
             end;
             end;

+ 52 - 39
rtl/inc/rtti.inc

@@ -43,37 +43,60 @@ begin
   end
   end
 end;
 end;
 
 
-function RTTISizeAndOp(typeInfo: Pointer;
-  const expectedManagementOp: TRTTIRecOpType; out hasManagementOp: boolean): SizeInt;
+{ result = manBuiltin means e.g. that initialization is simply zeroing and can be omitted if the memory is already zeroed, as in dynarr.inc. }
+function RTTIManagementAndSize(typeInfo: Pointer; op: TRTTIRecOpType; out size: SizeInt): TRTTIManagement;
+var
+  ri: PRecordInfoInit;
+  elem, eElem: PRecordElement;
+  newMan: TRTTIManagement;
+  _initrtti: pointer;
+  _size: SizeInt;
 begin
 begin
-  hasManagementOp:=false;
   case PTypeKind(typeinfo)^ of
   case PTypeKind(typeinfo)^ of
     tkAString,tkWString,tkUString,
     tkAString,tkWString,tkUString,
     tkInterface,tkDynarray:
     tkInterface,tkDynarray:
-      result:=sizeof(Pointer);
+      begin
+        size:=sizeof(Pointer);
+        result:=manBuiltin;
+      end;
 {$ifdef FPC_HAS_FEATURE_VARIANTS}
 {$ifdef FPC_HAS_FEATURE_VARIANTS}
     tkVariant:
     tkVariant:
-      result:=sizeof(TVarData);
+      begin
+        size:=sizeof(TVarData);
+        result:=manBuiltin;
+      end;
 {$endif FPC_HAS_FEATURE_VARIANTS}
 {$endif FPC_HAS_FEATURE_VARIANTS}
     tkArray:
     tkArray:
-      result:=RTTIArraySize(typeinfo);
-    tkObject:
-      result:=RTTIRecordSize(typeinfo);
+      begin
+        typeInfo:=aligntoqword(typeInfo+2+PByte(typeInfo)[1]);
+        size:=PArrayInfo(typeInfo)^.Size;
+        result:=RTTIManagementAndSize(PArrayInfo(typeInfo)^.ElInfo^, op, _size);
+      end;
+    tkObject,
     tkRecord:
     tkRecord:
-      with RTTIRecordOp(typeInfo,typeInfo)^ do
-        begin
-          result:=Size;
-          hasManagementOp := Assigned(RecordOp);
-          if hasManagementOp then
-            case expectedManagementOp of
-              rotInitialize: hasManagementOp:=Assigned(RecordOp^.Initialize);
-              rotFinalize: hasManagementOp:=Assigned(RecordOp^.Finalize);
-              rotAddRef: hasManagementOp:=Assigned(RecordOp^.AddRef);
-              rotCopy: hasManagementOp:=Assigned(RecordOp^.Copy);
-            end;
-        end;
+      begin
+        ri:=RTTIRecordOp(typeInfo, _initrtti);
+        size:=ri^.Size;
+        if Assigned(ri^.RecordOp) and Assigned(ri^.RecordOp^.Ops[op]) then
+          result:=manCustom
+        else
+          begin
+            result:=manNone;
+            elem:=AlignTypeData(Pointer(@ri^.Count)+SizeOf(ri^.Count));
+            eElem:=elem+ri^.Count;
+            while elem<>eElem do
+              begin
+                newMan:=RTTIManagementAndSize(elem^.TypeInfo^, op, _size);
+                if newMan<>manNone then
+                  result:=newMan;
+                if newMan=manCustom then
+                  break;
+                inc(elem);
+              end;
+          end;
+      end;
   else
   else
-    result:=-1;
+    result:=manNone; { Size undefined, ultimately can be always correct to support unmanaged scenarios. }
   end;
   end;
 end;
 end;
 
 
@@ -310,13 +333,11 @@ begin
             { Process elements with rtti }
             { Process elements with rtti }
             for i:=1 to EleCount Do
             for i:=1 to EleCount Do
               begin
               begin
-                Info:=PRecordElement(Temp)^.TypeInfo^;
                 Offset:=PRecordElement(Temp)^.Offset;
                 Offset:=PRecordElement(Temp)^.Offset;
-                Inc(PRecordElement(Temp));
                 if Offset>expectedoffset then
                 if Offset>expectedoffset then
                   move((Src+expectedoffset)^,(Dest+expectedoffset)^,Offset-expectedoffset);
                   move((Src+expectedoffset)^,(Dest+expectedoffset)^,Offset-expectedoffset);
-                copiedsize:=fpc_Copy_internal(Src+Offset,Dest+Offset,Info);
-                expectedoffset:=Offset+copiedsize;
+                expectedoffset:=Offset+fpc_Copy_internal(Src+Offset,Dest+Offset,PRecordElement(Temp)^.TypeInfo^);
+                Inc(PRecordElement(Temp));
               end;
               end;
             { elements remaining? }
             { elements remaining? }
             if result>expectedoffset then
             if result>expectedoffset then
@@ -354,10 +375,8 @@ end;
 procedure fpc_initialize_array(data,typeinfo : pointer;count : SizeInt); [public,alias:'FPC_INITIALIZE_ARRAY']; compilerproc;
 procedure fpc_initialize_array(data,typeinfo : pointer;count : SizeInt); [public,alias:'FPC_INITIALIZE_ARRAY']; compilerproc;
   var
   var
     i, size : SizeInt;
     i, size : SizeInt;
-    hasManagementOp: boolean;
   begin
   begin
-    size:=RTTISizeAndOp(typeinfo, rotInitialize, hasManagementOp);
-    if (size>0) or hasManagementOp then
+    if RTTIManagementAndSize(typeinfo, rotInitialize, size)<>manNone then
       for i:=0 to count-1 do
       for i:=0 to count-1 do
         int_initialize(data+size*i,typeinfo);
         int_initialize(data+size*i,typeinfo);
   end;
   end;
@@ -365,11 +384,9 @@ procedure fpc_initialize_array(data,typeinfo : pointer;count : SizeInt); [public
 
 
 procedure fpc_finalize_array(data,typeinfo : pointer;count : SizeInt); [Public,Alias:'FPC_FINALIZE_ARRAY'];  compilerproc;
 procedure fpc_finalize_array(data,typeinfo : pointer;count : SizeInt); [Public,Alias:'FPC_FINALIZE_ARRAY'];  compilerproc;
   var
   var
-     i, size: SizeInt;
-    hasManagementOp: boolean;
+    i, size : SizeInt;
   begin
   begin
-    size:=RTTISizeAndOp(typeinfo, rotFinalize, hasManagementOp);
-    if (size>0) or hasManagementOp then
+    if RTTIManagementAndSize(typeinfo, rotFinalize, size)<>manNone then
       for i:=0 to count-1 do
       for i:=0 to count-1 do
         int_finalize(data+size*i,typeinfo);
         int_finalize(data+size*i,typeinfo);
   end;
   end;
@@ -377,11 +394,9 @@ procedure fpc_finalize_array(data,typeinfo : pointer;count : SizeInt); [Public,A
 
 
 procedure fpc_addref_array(data,typeinfo: pointer; count: SizeInt); [public,alias:'FPC_ADDREF_ARRAY']; compilerproc;
 procedure fpc_addref_array(data,typeinfo: pointer; count: SizeInt); [public,alias:'FPC_ADDREF_ARRAY']; compilerproc;
   var
   var
-    i, size: SizeInt;
-    hasManagementOp: boolean;
+    i, size : SizeInt;
   begin
   begin
-    size:=RTTISizeAndOp(typeinfo, rotAddRef, hasManagementOp);
-    if (size>0) or hasManagementOp then
+    if RTTIManagementAndSize(typeinfo, rotAddRef, size)<>manNone then
       for i:=0 to count-1 do
       for i:=0 to count-1 do
         int_addref(data+size*i,typeinfo);
         int_addref(data+size*i,typeinfo);
   end;
   end;
@@ -406,10 +421,8 @@ procedure FinalizeArray(p, typeInfo: Pointer; count: SizeInt);
 procedure CopyArray(dest, source, typeInfo: Pointer; count: SizeInt);
 procedure CopyArray(dest, source, typeInfo: Pointer; count: SizeInt);
   var
   var
     i, size: SizeInt;
     i, size: SizeInt;
-    hasManagementOp: boolean;
   begin
   begin
-    size:=RTTISizeAndOp(typeinfo, rotCopy, hasManagementOp);
-    if (size>0) or hasManagementOp then
+    if RTTIManagementAndSize(typeinfo, rotCopy, size)<>manNone then
       for i:=0 to count-1 do
       for i:=0 to count-1 do
         fpc_Copy_internal(source+size*i, dest+size*i, typeInfo);
         fpc_Copy_internal(source+size*i, dest+size*i, typeInfo);
   end;
   end;

+ 12 - 5
rtl/inc/rttidecl.inc

@@ -73,17 +73,23 @@ type
   PRecordInfoInit=^TRecordInfoInit;
   PRecordInfoInit=^TRecordInfoInit;
   TRTTIRecVarOp=procedure(ARec: Pointer);
   TRTTIRecVarOp=procedure(ARec: Pointer);
   TRTTIRecCopyOp=procedure(ASrc, ADest: Pointer);
   TRTTIRecCopyOp=procedure(ASrc, ADest: Pointer);
-  TRTTIRecOpType=(rotAny, rotInitialize, rotFinalize, rotAddRef, rotCopy);
+  TRTTIRecOpType=(rotInitialize, rotFinalize, rotAddRef, rotCopy);
+  TRTTIManagement=(manNone, manBuiltin, manCustom);
   PRTTIRecordOpVMT=^TRTTIRecordOpVMT;
   PRTTIRecordOpVMT=^TRTTIRecordOpVMT;
   TRTTIRecordOpVMT=
   TRTTIRecordOpVMT=
 {$ifdef USE_PACKED}
 {$ifdef USE_PACKED}
   packed
   packed
 {$endif USE_PACKED}
 {$endif USE_PACKED}
   record
   record
-    Initialize: TRTTIRecVarOp;
-    Finalize: TRTTIRecVarOp;
-    AddRef: TRTTIRecVarOp;
-    Copy: TRTTIRecCopyOp;
+    case cardinal of
+      0:
+      (
+        Initialize: TRTTIRecVarOp;
+        Finalize: TRTTIRecVarOp;
+        AddRef: TRTTIRecVarOp;
+        Copy: TRTTIRecCopyOp;
+      );
+      1: (Ops: array[TRTTIRecOpType] of CodePointer);
   end;
   end;
 
 
   TRTTIRecordOpOffsetEntry =
   TRTTIRecordOpOffsetEntry =
@@ -151,6 +157,7 @@ type
       );
       );
   end;
   end;
 
 
+function RTTIManagementAndSize(typeInfo: Pointer; op: TRTTIRecOpType; out size: SizeInt): TRTTIManagement; forward;
 function RTTIRecordMopInitTable(ti: Pointer): PRTTIRecordOpOffsetTable; forward;
 function RTTIRecordMopInitTable(ti: Pointer): PRTTIRecordOpOffsetTable; forward;
 
 
 {$pop}
 {$pop}