FpDebug: Speed up fpdebug (GoNamedChild) by creating hashes for symbol names / Create Hash-lookup field for units to skip some CU

git-svn-id: trunk@63808 -
This commit is contained in:
martin 2020-08-22 20:27:10 +00:00
parent 24a3af8855
commit 24d48052e3
2 changed files with 133 additions and 27 deletions

View File

@ -1256,7 +1256,9 @@ begin
while i > 0 do begin
dec(i);
CU := FDwarf.CompilationUnits[i];
if CU = SkipCompUnit then
if (CU = SkipCompUnit) or
(not CU.KnownNameHashes^[ANameInfo.NameHash and KnownNameHashesBitMask])
then
continue;
//DebugLn(FPDBG_DWARF_SEARCH, ['TDbgDwarf.FindIdentifier search UNIT Name=', CU.FileName]);
@ -1275,7 +1277,6 @@ begin
break;
end;
CU.ScanAllEntries;
if InfoEntry.GoNamedChildEx(ANameInfo) then begin
if InfoEntry.IsAddressInStartScope(FAddress) then begin
// only variables are marked "external", but types not / so we may need all top level
@ -1429,6 +1430,12 @@ begin
//debugln(FPDBG_DWARF_SEARCH, ['TDbgDwarf.FindIdentifier Searching ', dbgs(InfoEntry.FScope, CU)]);
StartScopeIdx := InfoEntry.ScopeIndex;
tg := InfoEntry.AbbrevTag;
if (tg = DW_TAG_compile_unit) and
(not CU.KnownNameHashes^[NameInfo.NameHash and KnownNameHashesBitMask])
then
break;
//if InfoEntry.Abbrev = nil then
// exit;
@ -1462,7 +1469,6 @@ begin
end;
tg := InfoEntry.AbbrevTag;
if (tg = DW_TAG_class_type) or (tg = DW_TAG_structure_type) then begin
if FindSymbolInStructure(AName,NameInfo, InfoEntry, Result) then begin
exit; // TODO: check error

View File

@ -113,6 +113,12 @@ type
{$PACKRECORDS C}
{%endregion Dwarf Header Structures }
const
KnownNameHashesBitMask = $7FF; // 256 bytes
type
TKnownNameHashesArray = bitpacked array [0..KnownNameHashesBitMask] of Boolean;
PKnownNameHashesArray = ^TKnownNameHashesArray;
{%region Abbreviation Data / Section "debug_abbrev"}
{ TDwarfAbbrev }
TDwarfAbbrevFlag = (
@ -200,6 +206,7 @@ type
TNameSearchInfo = record
NameUpper, NameLower: String;
NameHash: Word;
end;
{%region Information Entry / Section "debug_info"}
@ -222,6 +229,7 @@ type
TDwarfScopeInfoRec = record
Link: Integer;
Entry: Pointer;
NameHash: Word;
end;
PDwarfScopeInfoRec = ^TDwarfScopeInfoRec;
@ -240,6 +248,7 @@ type
FIndex: Integer;
function GetChild: TDwarfScopeInfo; inline;
function GetChildIndex: Integer; inline;
function GetCurrent: PDwarfScopeInfoRec;
function GetEntry: Pointer; inline;
function GetNext: TDwarfScopeInfo; inline;
function GetNextIndex: Integer; inline;
@ -255,6 +264,7 @@ type
function IsValid: Boolean; inline;
property Index: Integer read FIndex write SetIndex;
property Entry: Pointer read GetEntry;
property Current: PDwarfScopeInfoRec read GetCurrent;
function HasParent: Boolean; inline;
function HasNext: Boolean; inline;
@ -317,6 +327,8 @@ type
function HasAttrib(AnAttrib: Cardinal): Boolean; inline;
property AttribForm[AnIdx: Integer]: Cardinal read GetAttribForm;
procedure ComputeKnownHashes(AKNownHashes: PKnownNameHashesArray);
function GoNamedChild(AName: String): Boolean;
// find in enum too // TODO: control search with a flags param, if needed
function GoNamedChildEx(const ANameInfo: TNameSearchInfo): Boolean;
@ -581,9 +593,11 @@ type
FScope: TDwarfScopeInfo;
FScopeList: TDwarfScopeList;
FScannedToEnd: Boolean;
FKnownNameHashes: TKnownNameHashesArray;
procedure BuildAddressMap;
function GetAddressMap: TMap;
function GetKnownNameHashes: PKnownNameHashesArray; inline;
function GetUnitName: String;
function ReadTargetAddressFromDwarfSection(var AData: Pointer; AIncPointer: Boolean = False): TFpDbgMemLocation;
function ReadDwarfSectionOffsetOrLenFromDwarfSection(var AData: Pointer; AIncPointer: Boolean = False): TFpDbgMemLocation;
@ -604,7 +618,6 @@ type
function ReadValue(AAttribute: Pointer; AForm: Cardinal; out AValue: TByteDynArray; AnFormString: Boolean = False): Boolean;
// Read a value that contains an address. The address is evaluated using MapAddressToNewValue
function ReadAddressValue(AAttribute: Pointer; AForm: Cardinal; out AValue: QWord): Boolean;
public
constructor Create(AOwner: TFpDwarfInfo; ADebugFile: PDwarfDebugFile; ADataOffset: QWord; ALength: QWord; AVersion: Word; AAbbrevOffset: QWord; AAddressSize: Byte; AIsDwarf64: Boolean); virtual;
destructor Destroy; override;
@ -647,7 +660,7 @@ type
property InfoDataLength: QWord read FLength; // length of info
property AddressMap: TMap read GetAddressMap;
property AbbrevList: TDwarfAbbrevList read FAbbrevList;
property KnownNameHashes: PKnownNameHashesArray read GetKnownNameHashes; // Only for TOP-LEVEL entries
end;
{ TFpDwarfInfo }
@ -772,6 +785,7 @@ function NameInfoForSearch(const AName: String): TNameSearchInfo;
begin
Result.NameLower := UTF8LowerCase(AName);
Result.NameUpper := UTF8UpperCase(AName);
Result.NameHash := objpas.Hash(Result.NameUpper) and $7fff or $8000;
end;
function Dbgs(AInfoData: Pointer; ACompUnit: TDwarfCompilationUnit): String;
@ -1632,6 +1646,13 @@ begin
Result := -1;
end;
function TDwarfScopeInfo.GetCurrent: PDwarfScopeInfoRec;
begin
Result := nil;
if IsValid then
Result := @FScopeList^.List[FIndex];
end;
function TDwarfScopeInfo.GetParent: TDwarfScopeInfo;
var
l: Integer;
@ -2520,6 +2541,55 @@ begin
end;
end;
procedure TDwarfInformationEntry.ComputeKnownHashes(
AKNownHashes: PKnownNameHashesArray);
var
EntryName: PChar;
NextTopLevel: Integer;
h: LongWord;
InEnum: Boolean;
begin
InEnum := False;
if not HasValidScope then
exit;
NextTopLevel := 0;
dec(FScope.FIndex);
while (FScope.Index < FScope.FScopeList^.HighestKnown) do begin
inc(FScope.FIndex);
ScopeChanged;
PrepareAbbrev;
if not (dafHasName in FAbbrev^.flags) then begin
if FScope.Index >= NextTopLevel then
NextTopLevel := FScope.GetNextIndex;
Continue;
end;
if not ReadValue(DW_AT_name, EntryName) then begin
if FScope.Index >= NextTopLevel then
NextTopLevel := FScope.GetNextIndex;
Continue;
end;
h := objpas.Hash(UTF8UpperCase(EntryName)) and $7fff or $8000;
FScope.Current^.NameHash := h;
if (FScope.Index >= NextTopLevel) or InEnum then
AKNownHashes^[h and KnownNameHashesBitMask] := True;
if FScope.Index >= NextTopLevel then begin
InEnum := False;
if FAbbrev^.tag = DW_TAG_enumeration_type then begin
InEnum := True;
NextTopLevel := FScope.GetNextIndex;
Continue;
end;
end;
if FScope.Index >= NextTopLevel then
NextTopLevel := FScope.GetNextIndex;
end;
end;
function TDwarfInformationEntry.GetScopeIndex: Integer;
begin
Result := FScope.Index;
@ -2573,6 +2643,7 @@ var
EntryName: PChar;
InEnum: Boolean;
ParentScopIdx: Integer;
sc: PDwarfScopeInfoRec;
begin
Result := False;
InEnum := False;
@ -2583,22 +2654,31 @@ begin
exit;
while true do begin
while HasValidScope do begin
sc := FScope.Current;
if sc^.NameHash = 0 then begin
GoNext;
Continue;
end;
PrepareAbbrev;
if not (dafHasName in FAbbrev^.flags) then begin
assert(false);
GoNext;
Continue;
end;
if not ReadValue(DW_AT_name, EntryName) then begin
GoNext;
Continue;
end;
if (sc^.NameHash = ANameInfo.NameHash) then begin
if not ReadValue(DW_AT_name, EntryName) then begin
GoNext;
Continue;
end;
if CompareUtf8BothCase(PChar(ANameInfo.NameUpper), PChar(ANameInfo.nameLower), EntryName) then begin
// TODO: check DW_AT_start_scope;
DebugLn(FPDBG_DWARF_SEARCH, ['GoNamedChildEX found ', dbgs(FScope, FCompUnit), ' Result=', DbgSName(Self), ' FOR ', ANameInfo.nameLower]);
Result := True;
exit;
if CompareUtf8BothCase(PChar(ANameInfo.NameUpper), PChar(ANameInfo.nameLower), EntryName) then begin
// TODO: check DW_AT_start_scope;
DebugLn(FPDBG_DWARF_SEARCH, ['GoNamedChildEX found ', dbgs(FScope, FCompUnit), ' Result=', DbgSName(Self), ' FOR ', ANameInfo.nameLower]);
Result := True;
exit;
end;
end;
if FAbbrev^.tag = DW_TAG_enumeration_type then begin
@ -2626,6 +2706,7 @@ function TDwarfInformationEntry.GoNamedChildMatchCaseEx(
const ANameInfo: TNameSearchInfo): Boolean;
var
EntryName: PChar;
sc: PDwarfScopeInfoRec;
begin
Result := False;
if ANameInfo.NameUpper = '' then
@ -2635,25 +2716,34 @@ begin
exit;
while HasValidScope do begin
sc := FScope.Current;
if sc^.NameHash = 0 then begin
GoNext;
Continue;
end;
PrepareAbbrev;
if not (dafHasName in FAbbrev^.flags) then begin
Assert(false);
GoNext;
Continue;
end;
if not ReadValue(DW_AT_name, EntryName) then begin
GoNext;
Continue;
if (sc^.NameHash = ANameInfo.NameHash) then begin
if not ReadValue(DW_AT_name, EntryName) then begin
GoNext;
Continue;
end;
if CompareMem(PChar(ANameInfo.nameLower), @EntryName, Length(EntryName)) then begin
// TODO: check DW_AT_start_scope;
DebugLn(FPDBG_DWARF_SEARCH, ['GoNamedChildEX found ', dbgs(FScope, FCompUnit), ' Result=', DbgSName(Self), ' FOR ', ANameInfo.nameLower]);
Result := True;
exit;
end;
end;
if CompareMem(PChar(ANameInfo.nameLower), @EntryName, Length(EntryName)) then begin
// TODO: check DW_AT_start_scope;
DebugLn(FPDBG_DWARF_SEARCH, ['GoNamedChildEX found ', dbgs(FScope, FCompUnit), ' Result=', DbgSName(Self), ' FOR ', ANameInfo.nameLower]);
Result := True;
exit;
end;
GoNext;
GoNext;
end;
end;
@ -3827,6 +3917,11 @@ begin
Result := FAddressMap;
end;
function TDwarfCompilationUnit.GetKnownNameHashes: PKnownNameHashesArray;
begin
Result := @FKnownNameHashes;
end;
function TDwarfCompilationUnit.FullFileName(const AFileName: string): String;
begin
Result := AFileName;
@ -3870,8 +3965,6 @@ var
begin
if FAddressMapBuild then Exit;
ScanAllEntries;
Scope := FScope;
ScopeIdx := Scope.Index;
@ -4015,6 +4108,7 @@ var
Form: Cardinal;
StatementListOffs, Offs: QWord;
Scope: TDwarfScopeInfo;
InfoEntry: TDwarfInformationEntry;
begin
//DebugLn(FPDBG_DWARF_VERBOSE, ['-- compilation unit --']);
//DebugLn(FPDBG_DWARF_VERBOSE, [' data offset: ', ADataOffset]);
@ -4069,6 +4163,12 @@ begin
end;
FValid := True;
ScanAllEntries;
InfoEntry := TDwarfInformationEntry.Create(Self, nil);
InfoEntry.ScopeIndex := FirstScope.Index;
InfoEntry.ComputeKnownHashes(@FKnownNameHashes);
InfoEntry.ReleaseReference;
AttribList.EvalCount := 0;
/// TODO: (dafHasName in Abbrev.flags)
if LocateAttribute(Scope.Entry, DW_AT_name, AttribList, Attrib, Form)