mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-14 06:59:14 +02:00
FpDebug: Add cache for flatten intrinsic. / Ensure the same TFpDbgSimpleLocationContext object is used for each watch (on the Parser-expression), so it can act as key.
This commit is contained in:
parent
948829d942
commit
e98a5d2b44
@ -90,18 +90,21 @@ type
|
|||||||
private
|
private
|
||||||
FAnAddress: TDBGPtr;
|
FAnAddress: TDBGPtr;
|
||||||
FAutoFillRegisters: boolean;
|
FAutoFillRegisters: boolean;
|
||||||
|
FContext: TFpDbgSimpleLocationContext;
|
||||||
FFrameAdress: TDBGPtr;
|
FFrameAdress: TDBGPtr;
|
||||||
FThread: TDbgThread;
|
FThread: TDbgThread;
|
||||||
FIsSymbolResolved: boolean;
|
FIsSymbolResolved: boolean;
|
||||||
FSymbol: TFpSymbol;
|
FSymbol: TFpSymbol;
|
||||||
FRegisterValueList: TDbgRegisterValueList;
|
FRegisterValueList: TDbgRegisterValueList;
|
||||||
FIndex: integer;
|
FIndex: integer;
|
||||||
|
function GetContext: TFpDbgSimpleLocationContext;
|
||||||
function GetFunctionName: string;
|
function GetFunctionName: string;
|
||||||
function GetProcSymbol: TFpSymbol;
|
function GetProcSymbol: TFpSymbol;
|
||||||
function GetLine: integer;
|
function GetLine: integer;
|
||||||
function GetRegisterValueList: TDbgRegisterValueList;
|
function GetRegisterValueList: TDbgRegisterValueList;
|
||||||
function GetSourceFile: string;
|
function GetSourceFile: string;
|
||||||
function GetSrcClassName: string;
|
function GetSrcClassName: string;
|
||||||
|
procedure SetContext(AValue: TFpDbgSimpleLocationContext);
|
||||||
public
|
public
|
||||||
constructor create(AThread: TDbgThread; AnIndex: integer; AFrameAddress, AnAddress: TDBGPtr);
|
constructor create(AThread: TDbgThread; AnIndex: integer; AFrameAddress, AnAddress: TDBGPtr);
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@ -115,6 +118,7 @@ type
|
|||||||
property ProcSymbol: TFpSymbol read GetProcSymbol;
|
property ProcSymbol: TFpSymbol read GetProcSymbol;
|
||||||
property Index: integer read FIndex;
|
property Index: integer read FIndex;
|
||||||
property AutoFillRegisters: boolean read FAutoFillRegisters write FAutoFillRegisters;
|
property AutoFillRegisters: boolean read FAutoFillRegisters write FAutoFillRegisters;
|
||||||
|
property Context: TFpDbgSimpleLocationContext read GetContext write SetContext;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TDbgCallstackEntryList }
|
{ TDbgCallstackEntryList }
|
||||||
@ -850,6 +854,8 @@ type
|
|||||||
|
|
||||||
TDebugOutputEvent = procedure(Sender: TObject; ProcessId, ThreadId: Integer; AMessage: String) of object;
|
TDebugOutputEvent = procedure(Sender: TObject; ProcessId, ThreadId: Integer; AMessage: String) of object;
|
||||||
|
|
||||||
|
TFpDbgDataCache = class(specialize TFPGMapObject<Pointer, TObject>);
|
||||||
|
|
||||||
{ TDbgProcess }
|
{ TDbgProcess }
|
||||||
|
|
||||||
TDbgProcess = class(TDbgInstance)
|
TDbgProcess = class(TDbgInstance)
|
||||||
@ -867,6 +873,7 @@ type
|
|||||||
FWatchPointData: TFpWatchPointData;
|
FWatchPointData: TFpWatchPointData;
|
||||||
FProcessConfig: TDbgProcessConfig;
|
FProcessConfig: TDbgProcessConfig;
|
||||||
FConfig: TDbgConfig;
|
FConfig: TDbgConfig;
|
||||||
|
FGlobalCache: TFpDbgDataCache;
|
||||||
function DoGetCfiFrameBase(AContext: TFpDbgLocationContext; out AnError: TFpError): TDBGPtr;
|
function DoGetCfiFrameBase(AContext: TFpDbgLocationContext; out AnError: TFpError): TDBGPtr;
|
||||||
function DoGetFrameBase(AContext: TFpDbgLocationContext; out AnError: TFpError): TDBGPtr;
|
function DoGetFrameBase(AContext: TFpDbgLocationContext; out AnError: TFpError): TDBGPtr;
|
||||||
function GetDisassembler: TDbgAsmDecoder;
|
function GetDisassembler: TDbgAsmDecoder;
|
||||||
@ -1041,6 +1048,7 @@ type
|
|||||||
property Disassembler: TDbgAsmDecoder read GetDisassembler;
|
property Disassembler: TDbgAsmDecoder read GetDisassembler;
|
||||||
property ThreadMap: TThreadMap read FThreadMap;
|
property ThreadMap: TThreadMap read FThreadMap;
|
||||||
property Config: TDbgConfig read FConfig;
|
property Config: TDbgConfig read FConfig;
|
||||||
|
property GlobalCache: TFpDbgDataCache read FGlobalCache write FGlobalCache;
|
||||||
end;
|
end;
|
||||||
TDbgProcessClass = class of TDbgProcess;
|
TDbgProcessClass = class of TDbgProcess;
|
||||||
|
|
||||||
@ -1843,6 +1851,11 @@ begin
|
|||||||
result := '';
|
result := '';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgCallstackEntry.GetContext: TFpDbgSimpleLocationContext;
|
||||||
|
begin
|
||||||
|
Result := FContext;
|
||||||
|
end;
|
||||||
|
|
||||||
function TDbgCallstackEntry.GetLine: integer;
|
function TDbgCallstackEntry.GetLine: integer;
|
||||||
var
|
var
|
||||||
Symbol: TFpSymbol;
|
Symbol: TFpSymbol;
|
||||||
@ -1893,6 +1906,17 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TDbgCallstackEntry.SetContext(AValue: TFpDbgSimpleLocationContext);
|
||||||
|
begin
|
||||||
|
if FContext = AValue then
|
||||||
|
exit;
|
||||||
|
if FContext <> nil then
|
||||||
|
FContext.ReleaseReference;
|
||||||
|
FContext := AValue;
|
||||||
|
if FContext <> nil then
|
||||||
|
FContext.AddReference;
|
||||||
|
end;
|
||||||
|
|
||||||
constructor TDbgCallstackEntry.create(AThread: TDbgThread; AnIndex: integer; AFrameAddress, AnAddress: TDBGPtr);
|
constructor TDbgCallstackEntry.create(AThread: TDbgThread; AnIndex: integer; AFrameAddress, AnAddress: TDBGPtr);
|
||||||
begin
|
begin
|
||||||
FThread := AThread;
|
FThread := AThread;
|
||||||
@ -1906,6 +1930,7 @@ destructor TDbgCallstackEntry.Destroy;
|
|||||||
begin
|
begin
|
||||||
FreeAndNil(FRegisterValueList);
|
FreeAndNil(FRegisterValueList);
|
||||||
ReleaseRefAndNil(FSymbol);
|
ReleaseRefAndNil(FSymbol);
|
||||||
|
FContext.ReleaseReference;
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -2534,6 +2559,7 @@ begin
|
|||||||
FOSDbgClasses := AnOsClasses;
|
FOSDbgClasses := AnOsClasses;
|
||||||
FProcessConfig := AProcessConfig;
|
FProcessConfig := AProcessConfig;
|
||||||
|
|
||||||
|
FGlobalCache := TFpDbgDataCache.Create;
|
||||||
FBreakpointList := TFpInternalBreakpointList.Create(False);
|
FBreakpointList := TFpInternalBreakpointList.Create(False);
|
||||||
FWatchPointList := TFpInternalBreakpointList.Create(False);
|
FWatchPointList := TFpInternalBreakpointList.Create(False);
|
||||||
FThreadMap := TThreadMap.Create(itu4, SizeOf(TDbgThread));
|
FThreadMap := TThreadMap.Create(itu4, SizeOf(TDbgThread));
|
||||||
@ -2594,6 +2620,7 @@ begin
|
|||||||
FreeItemsInMap(FLibMap);
|
FreeItemsInMap(FLibMap);
|
||||||
FLibMap.ClearAddedAndRemovedLibraries;
|
FLibMap.ClearAddedAndRemovedLibraries;
|
||||||
|
|
||||||
|
FGlobalCache.Free;
|
||||||
FreeAndNil(FWatchPointData);
|
FreeAndNil(FWatchPointData);
|
||||||
FBreakTargetHandler.BreakMap := nil;
|
FBreakTargetHandler.BreakMap := nil;
|
||||||
FreeAndNil(FBreakMap);
|
FreeAndNil(FBreakMap);
|
||||||
@ -2665,9 +2692,16 @@ begin
|
|||||||
|
|
||||||
if Frame <> nil then begin
|
if Frame <> nil then begin
|
||||||
Addr := Frame.AnAddress;
|
Addr := Frame.AnAddress;
|
||||||
Ctx := TFpDbgSimpleLocationContext.Create(MemManager, Addr, DBGPTRSIZE[Mode], AThreadId, AStackFrame);
|
Ctx := Frame.Context;
|
||||||
Ctx.SetFrameBaseCallback(@DoGetFrameBase);
|
if Ctx <> nil then begin
|
||||||
Ctx.SetCfaFrameBaseCallback(@DoGetCfiFrameBase);
|
Ctx.AddReference;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
Ctx := TFpDbgSimpleLocationContext.Create(MemManager, Addr, DBGPTRSIZE[Mode], AThreadId, AStackFrame);
|
||||||
|
Ctx.SetFrameBaseCallback(@DoGetFrameBase);
|
||||||
|
Ctx.SetCfaFrameBaseCallback(@DoGetCfiFrameBase);
|
||||||
|
Frame.Context := Ctx;
|
||||||
|
end;
|
||||||
sym := Frame.ProcSymbol;
|
sym := Frame.ProcSymbol;
|
||||||
if sym <> nil then
|
if sym <> nil then
|
||||||
Result := sym.CreateSymbolScope(Ctx);
|
Result := sym.CreateSymbolScope(Ctx);
|
||||||
@ -2956,6 +2990,7 @@ var
|
|||||||
t: TDbgThread;
|
t: TDbgThread;
|
||||||
begin
|
begin
|
||||||
ClearAddedAndRemovedLibraries;
|
ClearAddedAndRemovedLibraries;
|
||||||
|
FGlobalCache.Clear;
|
||||||
|
|
||||||
for t in FThreadMap do
|
for t in FThreadMap do
|
||||||
t.DoBeforeProcessLoop;
|
t.DoBeforeProcessLoop;
|
||||||
@ -3030,6 +3065,7 @@ var
|
|||||||
Iterator: TMapIterator;
|
Iterator: TMapIterator;
|
||||||
Thread: TDbgThread;
|
Thread: TDbgThread;
|
||||||
begin
|
begin
|
||||||
|
GlobalCache.Clear;
|
||||||
Iterator := TLockedMapIterator.Create(FThreadMap);
|
Iterator := TLockedMapIterator.Create(FThreadMap);
|
||||||
try
|
try
|
||||||
Iterator.First;
|
Iterator.First;
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
unit FpPascalParser;
|
unit FpPascalParser;
|
||||||
|
|
||||||
{$mode objfpc}{$H+}
|
{$mode objfpc}{$H+}
|
||||||
|
{$ModeSwitch advancedrecords}
|
||||||
{$IFDEF INLINE_OFF}{$INLINE OFF}{$ENDIF}
|
{$IFDEF INLINE_OFF}{$INLINE OFF}{$ENDIF}
|
||||||
{$IF FPC_Fullversion=30202}{$Optimization NOPEEPHOLE}{$ENDIF}
|
{$IF FPC_Fullversion=30202}{$Optimization NOPEEPHOLE}{$ENDIF}
|
||||||
{$TYPEDADDRESS on}
|
{$TYPEDADDRESS on}
|
||||||
@ -34,7 +35,7 @@ interface
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, sysutils, math, fgl, DbgIntfBaseTypes, FpDbgInfo, FpdMemoryTools, FpErrorMessages,
|
Classes, sysutils, math, fgl, DbgIntfBaseTypes, FpDbgInfo, FpdMemoryTools, FpErrorMessages,
|
||||||
FpDbgDwarf, FpWatchResultData,
|
FpDbgDwarf, FpWatchResultData, FpDbgClasses,
|
||||||
{$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif},
|
{$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif},
|
||||||
LazClasses;
|
LazClasses;
|
||||||
|
|
||||||
@ -77,6 +78,7 @@ type
|
|||||||
private
|
private
|
||||||
FAutoDeref: Boolean;
|
FAutoDeref: Boolean;
|
||||||
FError: TFpError;
|
FError: TFpError;
|
||||||
|
FGlobalCache: TFpDbgDataCache;
|
||||||
FScope: TFpDbgSymbolScope;
|
FScope: TFpDbgSymbolScope;
|
||||||
FFixPCharIndexAccess: Boolean;
|
FFixPCharIndexAccess: Boolean;
|
||||||
FHasPCharIndexAccess: Boolean;
|
FHasPCharIndexAccess: Boolean;
|
||||||
@ -119,6 +121,7 @@ type
|
|||||||
// - Only valid, as long as the expression is not destroyed
|
// - Only valid, as long as the expression is not destroyed
|
||||||
property ResultValue: TFpValue read GetResultValue;
|
property ResultValue: TFpValue read GetResultValue;
|
||||||
property OnFunctionCall: TFpPascalParserCallFunctionProc read FOnFunctionCall write FOnFunctionCall;
|
property OnFunctionCall: TFpPascalParserCallFunctionProc read FOnFunctionCall write FOnFunctionCall;
|
||||||
|
property GlobalCache: TFpDbgDataCache read FGlobalCache write FGlobalCache;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -186,6 +189,8 @@ type
|
|||||||
TFpPascalExpressionPart; virtual;
|
TFpPascalExpressionPart; virtual;
|
||||||
function CanHaveOperatorAsNext: Boolean; virtual; // True
|
function CanHaveOperatorAsNext: Boolean; virtual; // True
|
||||||
function HandleSeparator(ASeparatorType: TSeparatorType; var APart: TFpPascalExpressionPart): Boolean; virtual; // False
|
function HandleSeparator(ASeparatorType: TSeparatorType; var APart: TFpPascalExpressionPart): Boolean; virtual; // False
|
||||||
|
|
||||||
|
procedure GetFirstLastChar(out AFirst, ALast: PChar); virtual;
|
||||||
public
|
public
|
||||||
constructor Create(AExpression: TFpPascalExpression; AStartChar: PChar; AnEndChar: PChar = nil);
|
constructor Create(AExpression: TFpPascalExpression; AStartChar: PChar; AnEndChar: PChar = nil);
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@ -218,6 +223,7 @@ type
|
|||||||
protected
|
protected
|
||||||
procedure Init; override;
|
procedure Init; override;
|
||||||
procedure ResetEvaluationRecursive; override;
|
procedure ResetEvaluationRecursive; override;
|
||||||
|
procedure GetFirstLastChar(out AFirst, ALast: PChar); override;
|
||||||
function DebugDump(AIndent: String; AWithResults: Boolean): String; override;
|
function DebugDump(AIndent: String; AWithResults: Boolean): String; override;
|
||||||
public
|
public
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@ -330,6 +336,7 @@ type
|
|||||||
FIsClosed: boolean;
|
FIsClosed: boolean;
|
||||||
FIsClosing: boolean;
|
FIsClosing: boolean;
|
||||||
FAfterComma: Integer;
|
FAfterComma: Integer;
|
||||||
|
FFullEndChar: PChar;
|
||||||
function GetAfterComma: Boolean;
|
function GetAfterComma: Boolean;
|
||||||
protected
|
protected
|
||||||
procedure Init; override;
|
procedure Init; override;
|
||||||
@ -339,8 +346,9 @@ type
|
|||||||
function HandleNextPartInBracket(APart: TFpPascalExpressionPart): TFpPascalExpressionPart; virtual;
|
function HandleNextPartInBracket(APart: TFpPascalExpressionPart): TFpPascalExpressionPart; virtual;
|
||||||
procedure SetAfterCommaFlag;
|
procedure SetAfterCommaFlag;
|
||||||
property AfterComma: Boolean read GetAfterComma;
|
property AfterComma: Boolean read GetAfterComma;
|
||||||
|
procedure GetFirstLastChar(out AFirst, ALast: PChar); override;
|
||||||
public
|
public
|
||||||
procedure CloseBracket;
|
procedure CloseBracket(AStartChar: PChar; AnEndChar: PChar = nil);
|
||||||
function HandleNextPart(APart: TFpPascalExpressionPart): TFpPascalExpressionPart; override;
|
function HandleNextPart(APart: TFpPascalExpressionPart): TFpPascalExpressionPart; override;
|
||||||
procedure HandleEndOfExpression; override;
|
procedure HandleEndOfExpression; override;
|
||||||
property IsClosed: boolean read FIsClosed;
|
property IsClosed: boolean read FIsClosed;
|
||||||
@ -2299,6 +2307,7 @@ type
|
|||||||
TFpValueFlatteArray = class(TFpValueConstArray)
|
TFpValueFlatteArray = class(TFpValueConstArray)
|
||||||
private
|
private
|
||||||
FList: TRefCntObjList;
|
FList: TRefCntObjList;
|
||||||
|
FFullEvaluated: boolean;
|
||||||
protected
|
protected
|
||||||
function GetOrdHighBound: Int64; override;
|
function GetOrdHighBound: Int64; override;
|
||||||
public
|
public
|
||||||
@ -2308,6 +2317,92 @@ type
|
|||||||
function GetMember(AIndex: Int64): TFpValue; override;
|
function GetMember(AIndex: Int64): TFpValue; override;
|
||||||
function GetMemberCount: Integer; override;
|
function GetMemberCount: Integer; override;
|
||||||
end;
|
end;
|
||||||
|
PFpValueFlatteArray = ^TFpValueFlatteArray;
|
||||||
|
|
||||||
|
{ TFpPascalExpressionCacheFlattenKey }
|
||||||
|
|
||||||
|
TFpPascalExpressionCacheFlattenKey = record
|
||||||
|
Ctx: TFpDbgLocationContext;
|
||||||
|
Key: String;
|
||||||
|
class operator = (a,b: TFpPascalExpressionCacheFlattenKey): boolean;
|
||||||
|
class operator < (a,b: TFpPascalExpressionCacheFlattenKey): boolean;
|
||||||
|
class operator > (a,b: TFpPascalExpressionCacheFlattenKey): boolean;
|
||||||
|
end;
|
||||||
|
PFpPascalExpressionCacheFlattenKey = ^TFpPascalExpressionCacheFlattenKey;
|
||||||
|
|
||||||
|
{ TFpPascalExpressionCacheFlatten }
|
||||||
|
|
||||||
|
TFpPascalExpressionCacheFlatten = class(specialize TFPGMap<TFpPascalExpressionCacheFlattenKey, TFpValueFlatteArray>)
|
||||||
|
private
|
||||||
|
function DoKeyPtrComp(Key1, Key2: Pointer): Integer;
|
||||||
|
protected
|
||||||
|
procedure Deref(Item: Pointer); override;
|
||||||
|
public
|
||||||
|
constructor Create;
|
||||||
|
function Add(const AKey: TFpPascalExpressionCacheFlattenKey; const AData: TFpValueFlatteArray): Integer; inline;
|
||||||
|
function Replace(const AKey: TFpPascalExpressionCacheFlattenKey; const AData: TFpValueFlatteArray): Integer; inline;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TFpPascalExpressionCacheFlattenKey }
|
||||||
|
|
||||||
|
class operator TFpPascalExpressionCacheFlattenKey. = (a, b: TFpPascalExpressionCacheFlattenKey
|
||||||
|
): boolean;
|
||||||
|
begin
|
||||||
|
Result := (a.Ctx = b.Ctx) and (a.Key = b.Key);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class operator TFpPascalExpressionCacheFlattenKey.<(a, b: TFpPascalExpressionCacheFlattenKey
|
||||||
|
): boolean;
|
||||||
|
begin
|
||||||
|
raise Exception.Create('not supported');
|
||||||
|
end;
|
||||||
|
|
||||||
|
class operator TFpPascalExpressionCacheFlattenKey.>(a, b: TFpPascalExpressionCacheFlattenKey
|
||||||
|
): boolean;
|
||||||
|
begin
|
||||||
|
raise Exception.Create('not supported');
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TFpPascalExpressionCacheFlatten }
|
||||||
|
|
||||||
|
function TFpPascalExpressionCacheFlatten.DoKeyPtrComp(Key1, Key2: Pointer): Integer;
|
||||||
|
begin
|
||||||
|
if PFpPascalExpressionCacheFlattenKey(Key1)^ = PFpPascalExpressionCacheFlattenKey(Key2)^
|
||||||
|
then Result := 0
|
||||||
|
else Result := -1; // no sorting needed
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TFpPascalExpressionCacheFlatten.Deref(Item: Pointer);
|
||||||
|
begin
|
||||||
|
Finalize(TFpPascalExpressionCacheFlattenKey(Item^));
|
||||||
|
PFpValueFlatteArray(Pointer(PByte(Item)+KeySize))^.ReleaseReference;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TFpPascalExpressionCacheFlatten.Create;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
OnKeyPtrCompare := @DoKeyPtrComp;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TFpPascalExpressionCacheFlatten.Add(const AKey: TFpPascalExpressionCacheFlattenKey;
|
||||||
|
const AData: TFpValueFlatteArray): Integer;
|
||||||
|
begin
|
||||||
|
while Count >= 5 do
|
||||||
|
Delete(0);
|
||||||
|
AData.AddReference;
|
||||||
|
Result := inherited Add(AKey, AData);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TFpPascalExpressionCacheFlatten.Replace(const AKey: TFpPascalExpressionCacheFlattenKey;
|
||||||
|
const AData: TFpValueFlatteArray): Integer;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
i := IndexOf(AKey);
|
||||||
|
if i >= 0 then
|
||||||
|
Delete(i);
|
||||||
|
Result := Add(AKey, AData);
|
||||||
|
end;
|
||||||
|
|
||||||
{ TFpValueFlatteArray }
|
{ TFpValueFlatteArray }
|
||||||
|
|
||||||
@ -2377,6 +2472,7 @@ var
|
|||||||
ShowNil, ShowNoMember, ShowRecurse, ShowSeen, ShowErrAny, DerefPtr: Boolean;
|
ShowNil, ShowNoMember, ShowRecurse, ShowSeen, ShowErrAny, DerefPtr: Boolean;
|
||||||
MaxCnt: integer;
|
MaxCnt: integer;
|
||||||
TpSym: TFpSymbol;
|
TpSym: TFpSymbol;
|
||||||
|
CacheKey: TFpPascalExpressionCacheFlattenKey;
|
||||||
|
|
||||||
procedure AddErrToList(AnErr: TFpError);
|
procedure AddErrToList(AnErr: TFpError);
|
||||||
var
|
var
|
||||||
@ -2555,6 +2651,7 @@ var
|
|||||||
OName: String;
|
OName: String;
|
||||||
OVal, CustomMaxCnt, LastParamNeg: Boolean;
|
OVal, CustomMaxCnt, LastParamNeg: Boolean;
|
||||||
PParent: TFpPascalExpressionPartContainer;
|
PParent: TFpPascalExpressionPartContainer;
|
||||||
|
ListCache: TFpPascalExpressionCacheFlatten;
|
||||||
begin
|
begin
|
||||||
Result := nil;
|
Result := nil;
|
||||||
if not CheckArgumentCount(AParams, 2, 999) then
|
if not CheckArgumentCount(AParams, 2, 999) then
|
||||||
@ -2562,6 +2659,24 @@ begin
|
|||||||
|
|
||||||
if not GetArg(AParams, 1, TmpVal, 'Value required') then exit;
|
if not GetArg(AParams, 1, TmpVal, 'Value required') then exit;
|
||||||
|
|
||||||
|
ListCache := nil;
|
||||||
|
if (FExpression.GlobalCache <> nil) then begin
|
||||||
|
CacheKey.Ctx := FExpression.Scope.LocationContext;
|
||||||
|
CacheKey.Key := Parent.GetFullText;
|
||||||
|
i := FExpression.GlobalCache.IndexOf(Pointer(TFpPascalExpressionPartIntrinsic));
|
||||||
|
if i >= 0 then begin
|
||||||
|
ListCache := TFpPascalExpressionCacheFlatten(FExpression.GlobalCache.Data[i]);
|
||||||
|
i := ListCache.IndexOf(CacheKey);
|
||||||
|
if i >= 0 then begin
|
||||||
|
Result := ListCache.Data[i];
|
||||||
|
if Res.FFullEvaluated then begin
|
||||||
|
Res.AddReference;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
ShowNil := True;
|
ShowNil := True;
|
||||||
ShowNoMember := True;
|
ShowNoMember := True;
|
||||||
ShowRecurse := True;
|
ShowRecurse := True;
|
||||||
@ -2646,8 +2761,13 @@ begin
|
|||||||
|
|
||||||
if (Itm <> nil) and (Itm.ResultValue <> nil) then
|
if (Itm <> nil) and (Itm.ResultValue <> nil) then
|
||||||
if CustomMaxCnt
|
if CustomMaxCnt
|
||||||
then MaxCnt := Min(MaxCnt, Itm.ResultValue.AsInteger+1)
|
then MaxCnt := Min(MaxCnt, Itm.ResultValue.AsInteger+101) // Cache 100 extra
|
||||||
else MaxCnt := Itm.ResultValue.AsInteger+1;
|
else MaxCnt := Itm.ResultValue.AsInteger+101;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if (Result <> nil) and (Res.FList.Count >= MaxCnt) then begin// cached
|
||||||
|
Res.AddReference;
|
||||||
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Result := TFpValueFlatteArray.Create(0);
|
Result := TFpValueFlatteArray.Create(0);
|
||||||
@ -2663,10 +2783,18 @@ begin
|
|||||||
exit;
|
exit;
|
||||||
|
|
||||||
Seen.Add(DA);
|
Seen.Add(DA);
|
||||||
FlattenRecurse(TmpVal);
|
Res.FFullEvaluated := FlattenRecurse(TmpVal);
|
||||||
finally
|
finally
|
||||||
Seen.Free;
|
Seen.Free;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if (FExpression.GlobalCache <> nil) then begin
|
||||||
|
if ListCache = nil then begin
|
||||||
|
ListCache := TFpPascalExpressionCacheFlatten.Create;
|
||||||
|
FExpression.GlobalCache[Pointer(TFpPascalExpressionPartIntrinsic)] := ListCache;
|
||||||
|
end;
|
||||||
|
ListCache.Replace(CacheKey, Res);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TFpPascalExpressionPartIntrinsic.DoFlattenPlaceholder(
|
function TFpPascalExpressionPartIntrinsic.DoFlattenPlaceholder(
|
||||||
@ -3272,7 +3400,7 @@ var
|
|||||||
SetParserError(fpErrPasParserWrongOpenBracket_p, [GetFirstToken(CurPtr), PosFromPChar(BracketPart.StartChar), BracketPart.GetText(MAX_ERR_EXPR_QUOTE_LEN)]);
|
SetParserError(fpErrPasParserWrongOpenBracket_p, [GetFirstToken(CurPtr), PosFromPChar(BracketPart.StartChar), BracketPart.GetText(MAX_ERR_EXPR_QUOTE_LEN)]);
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
TFpPascalExpressionPartBracket(BracketPart).CloseBracket;
|
TFpPascalExpressionPartBracket(BracketPart).CloseBracket(CurPtr, TokenEndPtr-1);
|
||||||
CurPart := BracketPart;
|
CurPart := BracketPart;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -3929,6 +4057,12 @@ begin
|
|||||||
Result := (Parent <> nil) and Parent.HandleSeparator(ASeparatorType, APart);
|
Result := (Parent <> nil) and Parent.HandleSeparator(ASeparatorType, APart);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TFpPascalExpressionPart.GetFirstLastChar(out AFirst, ALast: PChar);
|
||||||
|
begin
|
||||||
|
AFirst := FStartChar;
|
||||||
|
ALast := FEndChar;
|
||||||
|
end;
|
||||||
|
|
||||||
function TFpPascalExpressionPart.DebugText(AIndent: String; AWithResults: Boolean): String;
|
function TFpPascalExpressionPart.DebugText(AIndent: String; AWithResults: Boolean): String;
|
||||||
begin
|
begin
|
||||||
Result := Format('%s%s at %d: "%s"',
|
Result := Format('%s%s at %d: "%s"',
|
||||||
@ -4030,6 +4164,21 @@ begin
|
|||||||
Items[i].ResetEvaluationRecursive;
|
Items[i].ResetEvaluationRecursive;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TFpPascalExpressionPartContainer.GetFirstLastChar(out AFirst, ALast: PChar);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
f, l: PChar;
|
||||||
|
begin
|
||||||
|
inherited GetFirstLastChar(AFirst, ALast);
|
||||||
|
for i := 0 to Count -1 do begin
|
||||||
|
Items[i].GetFirstLastChar(f,l);
|
||||||
|
if (AFirst = nil) or ( (f <> nil) and (f < AFirst) ) then
|
||||||
|
AFirst := f;
|
||||||
|
if (ALast = nil) or ( (l <> nil) and (l > ALast) ) then
|
||||||
|
ALast := l;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TFpPascalExpressionPartContainer.DebugDump(AIndent: String;
|
function TFpPascalExpressionPartContainer.DebugDump(AIndent: String;
|
||||||
AWithResults: Boolean): String;
|
AWithResults: Boolean): String;
|
||||||
var
|
var
|
||||||
@ -4059,13 +4208,7 @@ var
|
|||||||
p: TFpPascalExpressionPart;
|
p: TFpPascalExpressionPart;
|
||||||
Len: Integer;
|
Len: Integer;
|
||||||
begin
|
begin
|
||||||
s := FStartChar;
|
GetFirstLastChar(s,e);
|
||||||
e := FEndChar;
|
|
||||||
for i := 0 to Count - 1 do begin
|
|
||||||
p := Items[i];
|
|
||||||
if p.FStartChar < s then s := p.FStartChar;
|
|
||||||
if p.FEndChar > e then e := p.FEndChar;
|
|
||||||
end;
|
|
||||||
|
|
||||||
if e <> nil
|
if e <> nil
|
||||||
then Len := e - s + 1
|
then Len := e - s + 1
|
||||||
@ -4142,8 +4285,19 @@ begin
|
|||||||
FAfterComma := Count;
|
FAfterComma := Count;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TFpPascalExpressionPartBracket.CloseBracket;
|
procedure TFpPascalExpressionPartBracket.GetFirstLastChar(out AFirst, ALast: PChar);
|
||||||
begin
|
begin
|
||||||
|
if FFullEndChar <> nil then begin
|
||||||
|
AFirst := FStartChar;
|
||||||
|
ALast := FFullEndChar;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
inherited GetFirstLastChar(AFirst, ALast);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TFpPascalExpressionPartBracket.CloseBracket(AStartChar: PChar; AnEndChar: PChar);
|
||||||
|
begin
|
||||||
|
FFullEndChar := AnEndChar;
|
||||||
if AfterComma then begin
|
if AfterComma then begin
|
||||||
SetError(fpErrPasParserMissingExprAfterComma, [GetText(MAX_ERR_EXPR_QUOTE_LEN), GetPos]);
|
SetError(fpErrPasParserMissingExprAfterComma, [GetText(MAX_ERR_EXPR_QUOTE_LEN), GetPos]);
|
||||||
exit;
|
exit;
|
||||||
|
@ -1142,6 +1142,7 @@ begin
|
|||||||
APasExpr := TFpPascalExpression.Create(AnExpression, FExpressionScope, True);
|
APasExpr := TFpPascalExpression.Create(AnExpression, FExpressionScope, True);
|
||||||
APasExpr.IntrinsicPrefix := TFpDebugDebuggerProperties(FDebugger.GetProperties).IntrinsicPrefix;
|
APasExpr.IntrinsicPrefix := TFpDebugDebuggerProperties(FDebugger.GetProperties).IntrinsicPrefix;
|
||||||
APasExpr.AutoDeref := TFpDebugDebuggerProperties(FDebugger.GetProperties).AutoDeref;
|
APasExpr.AutoDeref := TFpDebugDebuggerProperties(FDebugger.GetProperties).AutoDeref;
|
||||||
|
APasExpr.GlobalCache := FDebugger.DbgController.CurrentProcess.GlobalCache;
|
||||||
APasExpr.Parse;
|
APasExpr.Parse;
|
||||||
try
|
try
|
||||||
if FAllowFunctions and (dfEvalFunctionCalls in FDebugger.EnabledFeatures) then
|
if FAllowFunctions and (dfEvalFunctionCalls in FDebugger.EnabledFeatures) then
|
||||||
@ -1181,6 +1182,7 @@ begin
|
|||||||
PasExpr2 := TFpPascalExpression.Create(CastName+'('+AnExpression+')', FExpressionScope, True);
|
PasExpr2 := TFpPascalExpression.Create(CastName+'('+AnExpression+')', FExpressionScope, True);
|
||||||
PasExpr2.IntrinsicPrefix := TFpDebugDebuggerProperties(FDebugger.GetProperties).IntrinsicPrefix;
|
PasExpr2.IntrinsicPrefix := TFpDebugDebuggerProperties(FDebugger.GetProperties).IntrinsicPrefix;
|
||||||
PasExpr2.AutoDeref := TFpDebugDebuggerProperties(FDebugger.GetProperties).AutoDeref;
|
PasExpr2.AutoDeref := TFpDebugDebuggerProperties(FDebugger.GetProperties).AutoDeref;
|
||||||
|
PasExpr2.GlobalCache := FDebugger.DbgController.CurrentProcess.GlobalCache;
|
||||||
PasExpr2.Parse;
|
PasExpr2.Parse;
|
||||||
PasExpr2.ResultValue;
|
PasExpr2.ResultValue;
|
||||||
if PasExpr2.Valid then begin
|
if PasExpr2.Valid then begin
|
||||||
|
Loading…
Reference in New Issue
Block a user