paxCompiler/Sources/PAXCOMP_PROG.pas
Dalibor Marković 9d0de424e8
Init
Signed-off-by: Dalibor Marković <dalibor31@gmail.com>
2024-07-06 22:28:12 +02:00

2704 lines
63 KiB
ObjectPascal

////////////////////////////////////////////////////////////////////////////
// PaxCompiler
// Site: http://www.paxcompiler.com
// Author: Alexander Baranovsky (paxscript@gmail.com)
// ========================================================================
// Copyright (c) Alexander Baranovsky, 2006-2014. All rights reserved.
// Code Version: 4.2
// ========================================================================
// Unit: PAXCOMP_PROG.pas
// ========================================================================
////////////////////////////////////////////////////////////////////////////
{$I PaxCompiler.def}
{$O-}
unit PAXCOMP_PROG;
interface
uses {$I uses.def}
TypInfo,
SysUtils,
Classes,
PaxInfos,
PAXCOMP_CONSTANTS,
PAXCOMP_TYPES,
PAXCOMP_SYS,
PAXCOMP_STDLIB,
PAXCOMP_SYMBOL_REC,
PAXCOMP_BASESYMBOL_TABLE,
PAXCOMP_LOCALSYMBOL_TABLE,
PAXCOMP_CLASSLST,
PAXCOMP_CLASSFACT,
PAXCOMP_DISASM,
PAXCOMP_TRYLST,
PAXCOMP_PAUSE,
PAXCOMP_RTI,
PAXCOMP_EVENT,
PAXCOMP_MAP,
PAXCOMP_TYPEINFO,
PAXCOMP_PROGLIST,
PAXCOMP_GC,
PAXCOMP_BASERUNNER,
PAXCOMP_INVOKE,
PaxInvoke;
type
TProgram = class;
TCallStackRec = class
public
EBP: Integer;
SubId: Integer;
NCall: Integer;
Prg: TProgram;
procedure SaveToStream(S: TStream);
procedure LoadFromStream(S: TStream);
end;
TCallStack = class(TTypedList)
private
function GetRecord(I: Integer): TCallStackRec;
public
function Push(EBP, SubId, NCall: Integer; Prg: TProgram): TCallStackRec;
procedure Pop;
function Top: TCallStackRec;
function IndexOf(SubId: Integer): Integer;
function LastIndexOf(SubId: Integer): Integer;
procedure SaveToStream(S: TStream);
procedure LoadFromStream(S: TStream);
property Records[I: Integer]: TCallStackRec read GetRecord; default;
end;
TTryStackRec = class
public
TryBlockNumber: Integer;
Prog: TProgram;
TR: TTryRec;
constructor Create;
destructor Destroy; override;
end;
TTryStack = class(TTypedList)
private
function GetRecord(I: Integer): TTryStackRec;
function GetTop: TTryStackRec;
public
function Push(ATryBlockNumber: Integer; AProg: TProgram): TTryStackRec;
procedure Pop;
function IndexOf(ATryBlockNumber: Integer): Integer;
procedure SaveToStream(S: TStream);
procedure LoadFromStream(S: TStream);
property Top: TTryStackRec read GetTop;
property Records[I: Integer]: TTryStackRec read GetRecord; default;
end;
TProgram = class(TBaseRunner)
private
fTryList: TTryList;
fTryStack: TTryStack;
fPauseRec: TPauseRec;
fESP0: Integer;
fCallStack: TCallStack;
InitialOffset: Integer;
fVirtualAllocProg: Boolean;
procedure SetVirtualAllocProg(value: Boolean);
function GetInteger(Shift: Integer): Integer;
function GetInt64(Shift: Integer): Int64;
function GetPChar(Shift: Integer): PChar;
function GetShortString(Shift: Integer): ShortString;
function GetRootProg: TProgram;
function GetTryStack: TTryStack;
function GetCallStack: TCallStack;
function GetESP0: Integer;
procedure SetESP0(value: Integer);
function GetCurrException: Exception;
procedure SetCurrException(value: Exception);
protected
function GetProgramSize: Integer; override;
function _VirtualAlloc(Address: Pointer;
Size, flAllocType, flProtect: Cardinal): Pointer; override;
procedure _VirtualFree(Address: Pointer; Size: Cardinal); override;
function GetVirtualAllocProg: Boolean;
function GetCodePtr: PBytes; override;
procedure DoOnReaderFindMethod(
Reader: TReader;
const MethodName: string;
var Address: Pointer;
var Error: Boolean);
public
EventHandlerList: TEventHandlerList;
ZList: TIntegerList;
OwnerEventHandlerMethod: TMethod;
{$IFDEF MSWINDOWS}
mbi: TMemoryBasicInformation;
{$ENDIF}
OldProtect: Cardinal;
IsProtected: Boolean;
IsPauseUpdated: Boolean;
ExitLevelId: Integer;
FinalizationOffset: Integer;
SourceLineFinally: Integer;
ModuleNameFinally: String;
PauseSEH: Boolean;
ExcFrame0: PExcFrame;
constructor Create; override;
destructor Destroy; override;
procedure Reset; override;
procedure ResetRun; override;
function GetDestructorAddress: Pointer; override;
procedure SaveToStream(S: TStream); override;
procedure LoadFromStream(S: TStream); override;
procedure Reallocate(NewCodeSize: Integer);
procedure AssignEventHandlerRunner(MethodAddress: Pointer;
Instance: TObject); override;
function GetCallStackCount: Integer; override;
function GetCallStackItem(I: Integer): Integer; override;
function GetCallStackLineNumber(I: Integer): Integer; override;
function GetCallStackModuleName(I: Integer): String; override;
function GetCallStackModuleIndex(I: Integer): Integer; override;
procedure RunInternal; override;
procedure Run; override;
procedure RunInitialization; override;
procedure RunExceptInitialization; override;
procedure RunFinalization; override;
procedure PushPtrs;
function GetPauseFlag: Integer;
procedure InitByteCodeLine;
function IsPaused: Boolean; override;
procedure Pause; override;
procedure DiscardPause; override;
procedure Terminate;
procedure RemovePause; override;
function Valid: Boolean; override;
procedure SetZList;
function GetImageCodePtr: Integer;
function GetImageAddress(const FullName: String; var MR: TMapRec): Integer;
function CreateScriptObject(const ScriptClassName: String;
const ParamList: array of const): TObject; override;
procedure DiscardDebugMode; override;
procedure RunEx;
procedure SaveState(S: TStream); override;
procedure LoadState(S: TStream); override;
procedure RebindEvents(AnInstance: TObject); override;
function CallFunc(const FullName: String;
This: Pointer;
const ParamList: array of OleVariant;
OverCount: Integer = 0): OleVariant; override;
function CallFuncEx(const FullName: String;
This: Pointer;
const ParamList: array of const;
IsConstructor: Boolean = false;
OverCount: integer = 0): Variant;
procedure Protect; override;
procedure UnProtect; override;
procedure ResetException;
procedure SetEntryPoint(EntryPoint: TPaxInvoke); override;
procedure ResetEntryPoint(EntryPoint: TPaxInvoke); override;
function GetParamAddress(Offset: Integer): Pointer; overload; override;
function GetLocalAddress(Offset: Integer): Pointer; overload; override;
function GetParamAddress(StackFrameNumber, Offset: Integer): Pointer; overload; override;
function GetLocalAddress(StackFrameNumber, Offset: Integer): Pointer; overload; override;
property Integers[Shift: Integer]: Integer read GetInteger;
property Int64s[Shift: Integer]: Int64 read GetInt64;
property PChars[Shift: Integer]: PChar read GetPChar;
property ShortStrings[Shift: Integer]: ShortString read GetShortString;
property TryList: TTryList read fTryList;
property PauseRec: TPauseRec read fPauseRec;
property RootTryStack: TTryStack read GetTryStack;
property RootCallStack: TCallStack read GetCallStack;
property RootESP0: Integer read GetESP0 write SetESP0;
property CurrException: Exception read GetCurrException write SetCurrException;
property VirtualAllocProg: Boolean
read GetVirtualAllocProg write SetVirtualAllocProg;
property RootProg: TProgram read GetRootProg;
end;
procedure ZZZ;
implementation
uses
PAXCOMP_PROGLIB,
PAXCOMP_JavaScript;
// TCallStackRec ---------------------------------------------------------------
procedure TCallStackRec.SaveToStream(S: TStream);
begin
S.Write(EBP, SizeOf(Integer));
S.Write(SubId, SizeOf(Integer));
S.Write(NCall, SizeOf(Integer));
end;
procedure TCallStackRec.LoadFromStream(S: TStream);
begin
S.Read(EBP, SizeOf(Integer));
S.Read(SubId, SizeOf(Integer));
S.Read(NCall, SizeOf(Integer));
end;
// TCallStack ------------------------------------------------------------------
function TCallStack.GetRecord(I: Integer): TCallStackRec;
begin
result := TCallStackRec(L[I]);
end;
function TCallStack.Push(EBP, SubId, NCall: Integer;
Prg: TProgram): TCallStackRec;
begin
result := TCallStackRec.Create;
result.EBP := EBP;
result.SubId := SubId;
result.NCall := NCall;
result.Prg := Prg;
L.Add(result);
end;
procedure TCallStack.Pop;
begin
RemoveAt(Count - 1);
end;
function TCallStack.Top: TCallStackRec;
begin
result := TCallStackRec(L[Count - 1]);
end;
function TCallStack.IndexOf(SubId: Integer): Integer;
var
I: Integer;
begin
result := -1;
for I := 0 to Count - 1 do
if Records[I].SubId = SubId then
begin
result := I;
Exit;
end;
end;
function TCallStack.LastIndexOf(SubId: Integer): Integer;
var
I: Integer;
begin
result := -1;
for I := Count - 1 downto 0 do
if Records[I].SubId = SubId then
begin
result := I;
Exit;
end;
end;
procedure TCallStack.SaveToStream(S: TStream);
var
I, K: Integer;
begin
K := Count;
S.Write(K, SizeOf(Integer));
for I := 0 to K - 1 do
Records[I].SaveToStream(S);
end;
procedure TCallStack.LoadFromStream(S: TStream);
var
I, K: Integer;
R: TCallStackRec;
begin
S.Read(K, SizeOf(Integer));
for I := 0 to K - 1 do
begin
R := TCallStackRec.Create;
R.LoadFromStream(S);
L.Add(R);
end;
end;
// TTryRec ---------------------------------------------------------------------
constructor TTryStackRec.Create;
begin
inherited;
end;
destructor TTryStackRec.Destroy;
begin
if TR <> nil then
FreeAndNil(TR);
inherited;
end;
// TTryStack -------------------------------------------------------------------
function TTryStack.GetRecord(I: Integer): TTryStackRec;
begin
result := TTryStackRec(L[I]);
end;
function TTryStack.GetTop: TTryStackRec;
begin
if Count = 0 then
raise PaxCompilerException.Create(errInternalError);
result := Records[Count - 1];
end;
function TTryStack.IndexOf(ATryBlockNumber: Integer): Integer;
var
I: Integer;
begin
result := -1;
for I := 0 to Count - 1 do
if Records[I].TryBlockNumber = ATryBlockNumber then
begin
result := I;
Exit;
end;
end;
function TTryStack.Push(ATryBlockNumber: Integer; AProg: TProgram): TTryStackRec;
begin
result := TTryStackRec.Create;
result.TryBlockNumber := ATryBlockNumber;
result.Prog := AProg;
result.TR := AProg.TryList[ATryBlockNumber].Clone;
L.Add(result);
end;
procedure TTryStack.Pop;
begin
Records[Count - 1].Free;
L.Delete(Count - 1);
end;
procedure TTryStack.SaveToStream(S: TStream);
var
I, K: Integer;
begin
K := Count;
S.Write(K, SizeOf(K));
for I := 0 to K - 1 do
with Records[I] do
begin
S.Write(TryBlockNumber, SizeOf(TryBlockNumber));
S.Write(Prog, SizeOf(Prog));
TR.SaveToStream(S);
end;
end;
procedure TTryStack.LoadFromStream(S: TStream);
var
I, K: Integer;
R: TTryStackRec;
begin
Clear;
S.Read(K, SizeOf(K));
for I := 0 to K - 1 do
begin
R := TTryStackRec.Create;
with R do
begin
S.Read(TryBlockNumber, SizeOf(TryBlockNumber));
S.Read(Prog, SizeOf(Prog));
TR := TTryRec.Create;
TR.LoadFromStream(S);
end;
L.Add(R);
end;
end;
// TProgram --------------------------------------------------------------------
constructor TProgram.Create;
begin
inherited Create;
{$IFDEF MSWINDOWS}
fVirtualAllocProg := true;
{$ENDIF}
CurrProg := Self;
fTryList := TTryList.Create;
fTryStack := TTryStack.Create;
fPauseRec := TPauseRec.Create;
EventHandlerList := TEventHandlerList.Create;
fCallStack := TCallStack.Create;
EPoint := nil;
PCUOwner := nil;
ZList := TIntegerList.Create;
IsRunning := false;
UseMapping := false;
end;
destructor TProgram.Destroy;
begin
ResetException;
UnloadDlls;
FreeAndNil(ZList);
FreeAndNil(fTryList);
FreeAndNil(fTryStack);
FreeAndNil(fPauseRec);
FreeAndNil(fCallStack);
try
Deallocate;
except
end;
FreeAndNil(EventHandlerList);
ClearCurrException;
inherited;
end;
procedure TProgram.Reset;
begin
inherited;
fImageDataPtr := 0;
ZList.Clear;
fTryList.Clear;
fTryStack.Clear;
fPauseRec.Clear;
EventHandlerList.Clear;
fCallStack.Clear;
RootInitCallStackCount := 0;
Deallocate;
EPoint := nil;
IsRunning := false;
RootIsEvent := false;
PauseSEH := false;
FinallyCount := 0;
PCULang := 0;
end;
procedure TProgram.ResetRun;
begin
fTryStack.Clear;
fPauseRec.Clear;
fCallStack.Clear;
RootInitCallStackCount := 0;
EPoint := nil;
IsRunning := false;
RootIsEvent := false;
PauseSEH := false;
end;
procedure TProgram.SetZList;
var
I, S: Integer;
P: Pointer;
begin
{$IFDEF PAX64}
for I:=0 to ZList.Count - 1 do
begin
S := ZList[I];
P := ShiftPointer(CodePtr, S + 2);
Pointer(P^) := CodePtr;
P := ShiftPointer(P, 10);
Pointer(P^) := DataPtr;
end;
{$ELSE}
for I:=0 to ZList.Count - 1 do
begin
S := ZList[I];
P := ShiftPointer(CodePtr, S + 1);
Pointer(P^) := CodePtr;
P := ShiftPointer(P, 5);
Pointer(P^) := DataPtr;
end;
{$ENDIF}
end;
function TProgram.GetInteger(Shift: Integer): Integer;
var
P: Pointer;
begin
P := ShiftPointer(DataPtr, Shift);
result := LongInt(P^);
end;
function TProgram.GetInt64(Shift: Integer): Int64;
var
P: Pointer;
begin
P := ShiftPointer(DataPtr, Shift);
result := Int64(P^);
end;
function TProgram.GetPChar(Shift: Integer): PChar;
var
P: Pointer;
begin
P := ShiftPointer(DataPtr, Shift);
result := PChar(P^);
end;
function TProgram.GetShortString(Shift: Integer): ShortString;
var
P: Pointer;
begin
P := ShiftPointer(DataPtr, Shift);
result := ShortString(P^);
end;
procedure TProgram.Reallocate(NewCodeSize: Integer);
var
buff: Pointer;
begin
if NewCodeSize = CodeSize then
Exit;
if NewCodeSize < CodeSize then
RaiseError(errInternalError, []);
Unprotect;
buff := _VirtualAlloc(nil, CodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Move(Prog^, buff^, CodeSize);
_VirtualFree(Prog, CodeSize);
Prog := _VirtualAlloc(nil, NewCodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Move(buff^, Prog^, CodeSize);
_VirtualFree(buff, CodeSize);
CodeSize := NewCodeSize;
Protect;
end;
function TProgram.Valid: Boolean;
begin
result := (Data <> nil) and (Prog <> nil);
end;
function TProgram.GetImageAddress(const FullName: String; var MR: TMapRec): Integer;
begin
result := 0;
MR := ScriptMapTable.Lookup(FullName);
if MR <> nil then
begin
case MR.Kind of
KindVAR, kindTYPE: result := GetImageDataPtr + MR.Offset;
KindSUB, KindCONSTRUCTOR, KindDESTRUCTOR:
begin
if MR.IsExternal then
result := 0
else
result := GetImageCodePtr + MR.Offset;
end;
end;
Exit;
end;
MR := HostMapTable.Lookup(FullName);
if MR <> nil then
if MR.Kind in KindSUBS + [KindVAR] then
begin
result := GetImageDataPtr + MR.Offset;
// result := Pointer(result^);
end;
end;
function TProgram.GetCodePtr: PBytes;
begin
result := Prog;
end;
function TProgram.GetPauseFlag: Integer;
var
P: Pointer;
begin
P := ShiftPointer(Data, H_Flag);
result := LongInt(P^);
end;
procedure TProgram.InitByteCodeLine;
var
P: Pointer;
begin
P := ShiftPointer(Data, H_ByteCodePtr);
LongInt(P^) := -1;
end;
function TProgram.GetImageCodePtr: Integer;
begin
result := GetImageDataPtr + DataSize;
end;
procedure TProgram.SaveToStream(S: TStream);
var
StartSize, EndSize, StartPos, EndPos, StreamSize: Integer;
CustomDataSize, CustomDataSizePos, temp: Integer;
SS: ShortString;
begin
StartSize := S.Size;
StartPos := S.Position;
S.Write(StreamSize, SizeOf(Integer));
S.Write(CompiledScriptVersion, SizeOf(CompiledScriptVersion));
PShortStringFromString(@ SS, TProgram.ClassName);
SaveShortStringToStream(SS, S);
CustomDataSize := 0;
CustomDataSizePos := S.Position;
S.Write(CustomDataSize, SizeOf(Integer));
if Assigned(OnSaveToStream) and IsRootProg then
begin
OnSaveToStream(Owner, S);
CustomDataSize := S.Position - CustomDataSizePos - 4;
if CustomDataSize > 0 then
begin
temp := S.Position;
S.Position := CustomDataSizePos;
S.Write(CustomDataSize, SizeOf(Integer));
S.Position := temp;
end
else
begin
CustomDataSize := 0;
S.Position := CustomDataSizePos;
S.Write(CustomDataSize, SizeOf(Integer));
end;
end;
S.Write(DataSize, SizeOf(Integer));
S.Write(fCodeSize, SizeOf(Integer));
fImageDataPtr := S.Position - StartPos;
S.Write(Data^, DataSize);
S.Write(Prog^, fCodeSize);
S.Write(JS_Record, SizeOf(JS_Record));
S.Write(ModeSEH, SizeOf(ModeSEH));
S.Write(PAX64, SizeOf(PAX64));
if GENERICS_ALLOWED then
S.Write(PCULang, SizeOf(PCULang));
ClassList.SaveToStream(S);
RunTimeModuleList.SaveToStream(S);
TryList.SaveToStream(S);
ZList.SaveToStream(S);
HostMapTable.SaveToStream(S);
ScriptMapTable.SaveToStream(S);
OffsetList.SaveToStream(S);
ExportList.SaveToStream(S);
MessageList.SaveToStream(S);
ProgTypeInfoList.SaveToStream(S);
ProgList.SaveToStream(S);
EndSize := S.Size;
EndPos := S.Position;
StreamSize := EndSize - StartSize;
S.Position := StartPos;
S.Write(StreamSize, SizeOf(Integer));
S.Position := EndPos;
end;
procedure TProgram.LoadFromStream(S: TStream);
var
Version: Integer;
K: Integer;
CustomDataSize, temp: Integer;
P: Pointer;
SS: ShortString;
ST: String;
begin
Deallocate;
S.Read(K, SizeOf(Integer));
S.Read(Version, SizeOf(CompiledScriptVersion));
if Version <> CompiledScriptVersion then
RaiseError(errIncorrectCompiledScriptVersion, []);
SS := LoadShortStringFromStream(S);
ST := TProgram.ClassName;
if not StrEql(StringFromPShortString(@SS), ST) then
RaiseError(errIncorrectCompiledScriptVersion, []);
S.Read(CustomDataSize, SizeOf(Integer));
if Assigned(OnLoadFromStream) and IsRootProg then
begin
temp := S.Position;
OnLoadFromStream(Owner, S);
if S.Position - temp <> CustomDataSize then
RaiseError(errIncorrectCustomDataSize, []);
end
else
if CustomDataSize > 0 then
begin
P := AllocMem(CustomDataSize);
try
S.Read(P^, CustomDataSize);
finally
FreeMem(P, CustomDataSize);
end;
end;
S.Read(fDataSize, SizeOf(Integer));
S.Read(fCodeSize, SizeOf(Integer));
Data := AllocMem(fDataSize);
Prog := _VirtualAlloc(nil, fCodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
S.Read(Data^, fDataSize);
S.Read(Prog^, fCodeSize);
S.Read(JS_Record, SizeOf(JS_Record));
S.Read(ModeSEH, SizeOf(ModeSEH));
S.Read(PAX64, SizeOf(PAX64));
if GENERICS_ALLOWED then
S.Read(PCULang, SizeOf(PCULang));
{$IFDEF MACOS}
ModeSEH := false;
{$ENDIF}
ClassList.Clear;
ClassList.LoadFromStream(S, Version);
RunTimeModuleList.Clear;
RunTimeModuleList.LoadFromStream(S);
TryList.Clear;
TryList.LoadFromStream(S);
ZList.Clear;
ZList.LoadFromStream(S);
HostMapTable.Clear;
HostMapTable.LoadFromStream(S);
ScriptMapTable.Clear;
ScriptMapTable.LoadFromStream(S);
OffsetList.Clear;
OffsetList.LoadFromStream(S);
ExportList.Clear;
ExportList.LoadFromStream(S);
MessageList.Clear;
MessageList.LoadFromStream(S);
ProgTypeInfoList.Clear;
ProgTypeInfoList.LoadFromStream(S);
ProgList.Clear;
ProgList.LoadFromStream(S, Self);
ProgList.SetPCUOwner(Self);
UseMapping := HostMapTable.Count > 0;
SetAddress(H_SelfPtr, Self);
SetAddress(H_ExceptionPtr, @ fCurrException);
RegisterDefinitions(GlobalSym);
if UseMapping then
begin
FreeAndNil(LocalSymbolTable);
LocalSymbolTable := TProgSymbolTable.Create(GlobalSym);
LocalSymbolTable.Reset;
RegisterDefinitions(LocalSymbolTable);
end;
SetZList;
SetupInterfaces(CodePtr);
ProgClassFactory.ForceCreate := true;
end;
function TProgram.IsPaused: Boolean;
begin
result := RootProg.PauseRec.ProgOffset > 0;
end;
{
procedure TProgram.Resume;
begin
if not IsPaused then
RaiseError(errProgramIsNotPaused, []);
Run;
end;
}
procedure TProgram.Pause;
var
P: Pointer;
begin
P := ShiftPointer(Data, H_Flag);
LongInt(P^) := 1;
end;
procedure TProgram.Terminate;
var
P: Pointer;
begin
P := ShiftPointer(Data, H_Flag);
LongInt(P^) := 2;
end;
procedure TProgram.RemovePause;
var
P: Pointer;
begin
P := ShiftPointer(Data, H_Flag);
LongInt(P^) := 0;
end;
procedure TProgram.Protect;
begin
{$IFDEF MSWINDOWS}
if IsProtected then
Exit;
VirtualQuery(Prog, mbi, sizeof(mbi));
// VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, OldProtect);
VirtualProtect(Prog, fCodeSize, PAGE_EXECUTE_READWRITE, OldProtect);
FlushInstructionCache(GetCurrentProcess, Prog, fCodeSize);
// Applications should call FlushInstructionCache if they generate or modify
// code in memory. The CPU cannot detect the change, and may execute the old
// code it cached.
{$ENDIF}
IsProtected := true;
end;
procedure TProgram.UnProtect;
begin
{$IFDEF MSWINDOWS}
if not IsProtected then
Exit;
// VirtualProtect(mbi.BaseAddress, mbi.RegionSize, OldProtect, OldProtect);
VirtualProtect(Prog, fCodeSize, OldProtect, OldProtect);
{$ENDIF}
IsProtected := false;
end;
procedure TProgram.ResetException;
var
aPrg : TProgram;
i : integer;
begin
for i := 0 to ProgList.count - 1 do
begin
aPrg := TProgram(ProgList.Records[i].Prog);
if (aPrg <> nil) then
aPrg.ResetException;
end;
if HasError then
begin
if fCurrException <> nil then
fCurrException.Free;
fCurrException := nil;
fPrevException := nil;
ExceptionRec := nil;
HasError := false;
fGC.Collect;
end;
end;
{$IFDEF PAX64}
function GetFS0: Pointer; assembler;
{$IFDEF FPC}
nostackframe; asm
{$ELSE}
asm
.NOFRAME
{$ENDIF}
mov rax, fs:[0]
end;
function GetRSP: IntPax; assembler;
{$IFDEF FPC}
nostackframe; asm
{$ELSE}
asm
.NOFRAME
{$ENDIF}
mov rax, rsp
end;
procedure CopyStackFrame(I: IntPax;
StackFrame: Pointer;
StackFrameSize, K: IntPax);
asm
mov rax, I
mov rbx, StackFrame
add rbx, StackFrameSize //!!
sub rbx, 8 //!!
mov rcx, K
@@loop:
mov rdx, [rbx]
mov [rax], rdx
sub rax, 8
sub rbx, 8
sub rcx, 1
cmp rcx, 0
jnz @@loop
end;
procedure AssignFS0(I: IntPax); assembler;
{$IFDEF FPC}
nostackframe; asm
{$ELSE}
asm
.NOFRAME
{$ENDIF}
mov fs:[0], rcx
end;
procedure AssignSegmentsAndJump(D, P0, P: Pointer;
_ESP, _EBP: IntPax); assembler;
asm
// assign code and data registers
mov rsi, D
mov rdi, P0
mov rax, P
mov rsp, _ESP
mov rbp, _EBP
jmp rax
end;
procedure AssignSegmentsAndCall(D, P: Pointer); assembler;
{$IFDEF FPC}
nostackframe; asm
{$ELSE}
asm
.NOFRAME
{$ENDIF}
push rbp
mov rbp, rsp
mov rsi, rcx
mov rdi, rdx
call rdx
pop rbp
ret
end;
procedure AssignSegments(D, P: Pointer); assembler;
{$IFDEF FPC}
nostackframe; asm
{$ELSE}
asm
.NOFRAME
{$ENDIF}
mov rsi, rcx
mov rdi, rdx
end;
procedure Assign_R14(P: Pointer); assembler;
{$IFDEF FPC}
nostackframe; asm
{$ELSE}
asm
.NOFRAME
{$ENDIF}
mov r14, rcx
end;
procedure Assign_R15(P: Pointer); assembler;
{$IFDEF FPC}
nostackframe; asm
{$ELSE}
asm
.NOFRAME
{$ENDIF}
mov r15, rcx
end;
procedure Call_R15; assembler;
{$IFDEF FPC}
nostackframe; asm
{$ELSE}
asm
.NOFRAME
{$ENDIF}
push rbp
sub rsp, $1000
mov rbp, rsp
// if EPoint.IsInternal then
// EPoint.PushArgumentsBackward
// else
// EPoint.PushArguments;
mov rcx, r14
call TInvoke.IsInternal
cmp al, 0
jz @@l1
mov rcx, r14
call TInvoke.PushArgumentsBackward
jmp @@l2
@@l1:
mov rcx, r14
call TInvoke.PushArguments
@@l2:
call r15
add rsp, $1000
pop rbp
ret
end;
{$ENDIF}
procedure TProgram.Run;
var
PaxFrame: PPaxExcFrame;
Delta: IntPax;
I: Integer;
D, P, P0, temp: Pointer;
ProgOffset: Integer;
Handled: Boolean;
_EBP, _ESP: IntPax;
TryRec: TTryRec;
ClsIndex: Integer;
ClassRec: TClassRec;
StackFrame: Pointer;
K: Integer;
SourceLine: Integer;
ModuleName: String;
CE: TExceptionClass;
PEpoint: Pointer;
StackFrameSize: Integer;
IsHaltException: Boolean;
IsPauseException: Boolean;
IsExitException: Boolean;
TryBlockNumber: Integer;
SelfPtr: TProgram;
HandledByExcept: Boolean;
label
Again;
begin
// PChars[0];
// ShortStrings[0];
Integers[0];
Int64s[0];
SourceLineFinally := -1;
ModuleNameFinally := '';
IsRootProg;
if ProgClassFactory.ForceCreate then
begin
CreateClassFactory;
ProgClassFactory.ForceCreate := false;
end;
IsRunning := true;
IsHalted := false;
IsPauseUpdated := false;
PEpoint := nil;
ProgOffset := 0;
Handled := false;
SelfPtr := Self;
with SelfPtr do
begin
D := Data;
P0 := Prog;
end;
SourceLine := -1;
ExitCode := 0;
IsHaltException := false;
IsPauseException := false;
RootInitCallStackCount := fCallStack.Count;
if IsPaused then
begin
Handled := true;
StackFrameSize := PauseRec.StackFrameSize;
K := StackFrameSize div 4;
StackFrame := PauseRec.StackFrame;
ProgOffset := PauseRec.ProgOffset;
_ESP := PauseRec._ESP;
_EBP := PauseRec._EBP;
PauseRec.ProgOffset := 0;
end;
RemovePause;
Again:
if HasError then
GetRootProg.ResetException;
HasError := false;
HandledByExcept := false;
try
if ModeSEH then
begin
{$IFDEF PAX64}
// temp := GetFS0;
{$ELSE}
asm
mov eax, fs:[0]
mov temp, eax
end;
{$ENDIF}
ExcFrame0 := temp;
end;
if Handled then
begin
Handled := false;
{$IFDEF PAX64}
I := GetRSP;
{$ELSE}
asm
mov I, esp
end;
{$ENDIF}
PaxFrame := PauseRec.PaxExcFrame1;
Delta := fESP0 - I;
fESP0 := I;
_ESP := _ESP - Delta;
_EBP := _EBP - Delta;
for I := 0 to fCallStack.Count - 1 do
fCallStack[I].EBP := fCallStack[I].EBP - Delta;
{$IFDEF PAX64}
// restore stack frame
I := fESP0 - 8;
CopyStackFrame(I, StackFrame, StackFrameSize, K);
P := Pointer(LongInt(P0) + ProgOffset);
if ModeSEH and PauseSEH then
begin
IntPax(PaxFrame) :=
Integer(PaxFrame) - Delta;
I := IntPax(PaxFrame);
AssignFS0(I);
while PaxFrame.Magic = PAX_SEH do
begin
PaxFrame^.hEBP := PaxFrame^.hEBP - Delta;
PaxFrame^.hESP := PaxFrame^.hESP - Delta;
PaxFrame^.Next := Pointer(Integer(PaxFrame^.Next) - Delta);
PaxFrame := PaxFrame^.Next;
end;
PaxFrame^.Next := Pointer(ExcFrame0);
PauseSEH := false;
end;
AssignSegmentsAndJump(D, P0, P, _ESP, _EBP);
// end of win64
{$ELSE} //win32
// restore stack frame
I := fESP0 - 4;
asm
mov eax, I
mov ebx, StackFrame
add ebx, StackFrameSize //!!
sub ebx, 4 //!!
mov ecx, K
@@loop:
mov edx, [ebx]
mov [eax], edx
sub eax, 4
// add ebx, 4
sub ebx, 4
sub ecx, 1
cmp ecx, 0
jnz @@loop
end;
P := Pointer(LongInt(P0) + ProgOffset);
if ModeSEH and PauseSEH then
begin
Integer(PaxFrame) :=
Integer(PaxFrame) - Delta;
I := Integer(PaxFrame);
asm
mov eax, I
mov fs:[0], eax
end;
while PaxFrame.Magic = PAX_SEH do
begin
PaxFrame^.hEBP := PaxFrame^.hEBP - Delta;
PaxFrame^.hESP := PaxFrame^.hESP - Delta;
PaxFrame^.Next := Pointer(Integer(PaxFrame^.Next) - Delta);
PaxFrame := PaxFrame^.Next;
end;
PaxFrame^.Next := Pointer(ExcFrame0);
PauseSEH := false;
end;
asm
// assign code and data registers
mov esi, D
mov edi, P0
mov eax, P
mov esp, _ESP
mov ebp, _EBP
jmp eax
end;
{$ENDIF} // win32
end
else
begin
InitByteCodeLine;
{$IFDEF PAX64}
_ESP := GetRSP();
{$ELSE}
asm
mov _ESP, esp
end;
{$ENDIF}
fESP0 := _ESP;
{$IFDEF PCU_EX}
RootProg.fESP0 := fESP0;
{$ENDIF}
if EPoint = nil then
begin
P := P0;
{$IFDEF PAX64}
AssignSegmentsAndCall(D, P);
{$ELSE}
asm
mov esi, D
mov edi, P
{$IFDEF MACOS}
add esp, - $0c
{$ENDIF}
call P
{$IFDEF MACOS}
add esp, $0c
{$ENDIF}
end;
{$ENDIF}
end
else
begin
if not EPoint.IsInternal then
EPoint.Setup;
PEpoint := EPoint;
// P := ShiftPointer(EPoint.Address, 14);
P := EPoint.Address;
{$IFDEF PAX64}
AssignSegments(D, P0);
Assign_R14(EPoint);
Assign_R15(P);
Call_R15;
EPoint.SaveResult;
{$ELSE}
asm
mov esi, D
mov edi, P0
end;
if EPoint.IsInternal then
EPoint.PushArgumentsBackward
else
EPoint.PushArguments;
asm
call P
end;
asm
mov ebx, PEpoint
cmp ebx, 0
jz @@Return
// if call convention is cdecl then pop arguments
mov ecx, [ebx + 28] // fCallConv
cmp ecx, ccCDECL
jnz @@Ret
mov ecx, [ebx + 8] // fStackSize
add esp, ecx
@@Ret:
mov ecx, [ebx + 32] // fResultType
cmp ecx, typeINTEGER
jnz @@RetDOUBLE
mov ecx, [ebx + 28] // fCallConv
cmp ecx, ccSAFECALL
jz @@Return
mov [ebx + INVOKE_RESULT_OFFSET], eax
jmp @@Return
//
@@RetDOUBLE:
cmp ecx, typeDOUBLE
jnz @@RetSINGLE
fstp qword ptr [ebx + INVOKE_RESULT_OFFSET]
jmp @@Return
//
@@RetSINGLE:
cmp ecx, typeSINGLE
jnz @@RetEXTENDED
fstp dword ptr [ebx + INVOKE_RESULT_OFFSET]
jmp @@Return
//
@@RetEXTENDED:
cmp ecx, typeEXTENDED
jnz @@RetCURRENCY
fstp tbyte ptr [ebx + INVOKE_RESULT_OFFSET]
jmp @@Return
//
@@RetCURRENCY:
cmp ecx, typeCURRENCY
jnz @@RetINT64
fistp qword ptr [ebx + INVOKE_RESULT_OFFSET]
jmp @@Return
//
@@RetINT64:
cmp ecx, typeINT64
jnz @@Return
mov [ebx + INVOKE_RESULT_OFFSET], eax
mov [ebx + INVOKE_RESULT_OFFSET + 4], edx
@@Return:
end;
{$ENDIF}
end;
end;
except
on E: Exception do
begin
if fTryStack.Count > 0 then
begin
TryBlockNumber := fTryStack.Top.TryBlockNumber;
SelfPtr := fTryStack.Top.Prog;
end
else
begin
SelfPtr := Self;
TryBlockNumber := 0;
end;
with SelfPtr do
begin
D := Data;
P0 := Prog;
SourceLine := GetSourceLine;
ModuleName := GetModuleName;
end;
IsExitException := E is PaxExitException;
IsPauseException := E is TPauseException;
IsHaltException := (E is THaltException) or
((E is EAbort) and (not IsPauseException) and (not IsExitException));
IsHalted := IsHaltException;
HasError := true;
if E is THaltException then
ExitCode := (E as THaltException).ExitCode;
with SelfPtr do
if RootTryStack.Count > 0 then
if (not IsPauseException) and (not IsHaltException) and
(TryBlockNumber >= 0) and (TryBlockNumber < TryList.Count) then
begin
// TryRec := TryList[TryBlockNumber];
TryRec := fTryStack.Top.TR;
_EBP := TryRec._EBP;
_ESP := TryRec._ESP;
K := TryRec.StackFrameSize div 4;
StackFrame := TryRec.StackFrame;
StackFrameSize := TryRec.StackFrameSize;
if TryRec.TryKind = tryFinally then
begin
ProcessingExceptBlock := false;
if SourceLineFinally = -1 then
begin
SourceLineFinally := GetSourceLine;
ModuleNameFinally := GetModuleName;
end;
end
else
begin
ProcessingExceptBlock := true;
HandledByExcept := true;
end;
if TryRec.ExceptOnInfo.Count = 0 then
ProgOffset := TryRec.ProgOffset
else
begin
for I:=0 to TryRec.ExceptOnInfo.Count - 1 do
begin
ClsIndex := TryRec.ExceptOnInfo.Keys[I];
ProgOffset := TryRec.ExceptOnInfo.Values[I];
if ClsIndex >= 0 then
begin
ClassRec := ClassList[ClsIndex];
if ClassRec.PClass <> nil then
begin
if E is ClassRec.PClass then
break;
if StrEql(ClassRec.PClass.ClassName, 'TJS_Object') then
break;
end;
end;
end;
end;
Handled := true;
end;
if Assigned(fCurrException) then
FreeAndNil(fCurrException);
fPrevException := nil;
if (not IsPauseException) and (not IsHaltException) then
begin
IntPax(CE) := IntPax(E.ClassType);
fCurrException := CE.Create(E.Message);
if Assigned(OnCustomExceptionHelper) then
OnCustomExceptionHelper(Owner, E, fCurrException);
end;
end; // on: E Exception
else
begin
// custom exception
end;
end; // try
RuntimeModuleList.TempBreakpoint.Clear;
if Handled then
begin
if Assigned(OnException) and RootExceptionIsAvailableForHostApplication then
if HandledByExcept then
OnException(Owner, fCurrException, ModuleName, SourceLine);
RootExceptionIsAvailableForHostApplication := true;
goto Again;
end
else
begin
IsRunning := false;
if (not SuspendFinalization) and (ProgTag <> 1) then
fGC.ClearObjects;
if HasError then
begin
if Assigned(OnHalt) and IsHaltException then
begin
OnHalt(Owner, ExitCode, ModuleName, SourceLine);
RootExceptionIsAvailableForHostApplication := true;
fPauseRec.Clear;
ClearCurrException;
Exit;
end
else if Assigned(OnPause) and IsPauseException then
begin
OnPause(Owner, ModuleName, SourceLine);
RootExceptionIsAvailableForHostApplication := true;
ClearCurrException;
Exit;
end;
if Assigned(OnUnhandledException) then
if fCurrException <> nil then
if RootExceptionIsAvailableForHostApplication then
begin
if SourceLineFinally = -1 then
OnUnhandledException(Owner, fCurrException, ModuleName, SourceLine)
else
OnUnhandledException(Owner, fCurrException, ModuleNameFinally, SourceLineFinally);
end;
RootExceptionIsAvailableForHostApplication := true;
end;
end;
ClearCurrException;
end;
{$O-}
procedure TProgram.RunInternal;
begin
Run;
end;
procedure TProgram.RunInitialization;
var
P: Pointer;
begin
if InitializationIsProcessed then
Exit;
Protect;
if fGC = RootGC then
fGC.Clear;
ProgList.RunInitialization;
P := ShiftPointer(Data, H_InitOnly);
LongInt(P^) := 2;
try
ProgTag := 1;
Run;
InitMessageList;
finally
ProgTag := 0;
LongInt(P^) := 0;
InitializationIsProcessed := true;
InitialOffset := GetInitializationOffset(CodePtr, CodeSize, PAX64);
end;
end;
procedure TProgram.RunExceptInitialization;
var
P: Pointer;
begin
if InitialOffset <= 0 then
InitialOffset := GetInitializationOffset(CodePtr, CodeSize, PAX64);
if InitialOffset = -1 then
Exit;
P := ShiftPointer(Data, H_BodyOnly);
if SuspendFinalization then
LongInt(P^) := 3
else
LongInt(P^) := 0;
EPoint := nil;
P := ShiftPointer(CodePtr, 1);
Move(InitialOffset, P^, 4);
try
Run;
finally
LongInt(P^) := 0;
end;
end;
procedure TProgram.RunFinalization;
var
P: Pointer;
Offset: Integer;
begin
if CodePtr = nil then
Exit;
ProgList.RunFinalization;
Offset := GetFinalizationOffset(CodePtr, CodeSize, PAX64);
if Offset = -1 then
Exit;
EPoint := nil;
P := ShiftPointer(CodePtr, 1);
Move(Offset, P^, 4);
try
Run;
finally
InitializationIsProcessed := false;
LongInt(P^) := 0;
Unprotect;
end;
end;
procedure TProgram.SaveState(S: TStream);
var
K: Integer;
begin
S.Write(DataPtr^, DataSize);
fCallStack.SaveToStream(S);
K := fTryStack.Count;
S.Write(K, SizeOf(Integer));
// fTryStack.SaveToStream(S);
end;
procedure TProgram.LoadState(S: TStream);
var
K: Integer;
begin
S.Read(DataPtr^, DataSize);
fCallStack.Clear;
fCallStack.LoadFromStream(S);
S.Read(K, SizeOf(Integer));
while fTryStack.Count > K do
fTryStack.Pop;
// fTryStack.LoadFromStream(S);
end;
{$IFDEF PAX64}
procedure TProgram.PushPtrs;
{$IFDEF FPC}
nostackframe; asm
{$ELSE}
asm
.NOFRAME
{$ENDIF}
mov rcx, [rsp]
push rcx
push rcx
mov rdx, [rax + 8]
mov [rsp + 8], rdx
mov rdx, [rax + 8 + 8]
mov [rsp + 8 + 8], rdx
end;
{$ELSE}
procedure TProgram.PushPtrs; assembler;
{$IFDEF FPC}
nostackframe; asm
{$ELSE}
asm
{$ENDIF}
mov ecx, [esp]
push ecx
push ecx
mov edx, [eax + 4]
mov [esp + 4], edx
mov edx, [eax + 8]
mov [esp + 8], edx
end;
{$ENDIF}
function TProgram.GetProgramSize: Integer;
begin
result := DataSize + CodeSize + 2;
end;
procedure TProgram.DiscardDebugMode;
begin
PAXCOMP_DISASM.DiscardDebugMode(CodePtr, CodeSize, PAX64);
end;
{$IFDEF PAX64}
procedure Call_M_2(Code, Data: Pointer); assembler;
asm
CALL RCX
end;
procedure Call_M(M: TMethod);
begin
Call_M_2(M.Code, M.Data);
end;
{$ENDIF}
{$IFDEF PAX64}
procedure TProgram.RunEx;
var
M: TMethod;
begin
M := OwnerEventHandlerMethod;
if Assigned(M.Code) then
begin
Call_M(M);
end
else
Run;
end;
{$ELSE}
procedure TProgram.RunEx;
var
M: TMethod;
begin
M := OwnerEventHandlerMethod;
if Assigned(M.Code) then
begin
asm
MOV EAX,DWORD PTR M.Data;
CALL M.Code;
end;
end
else
Run;
end;
{$ENDIF}
procedure TProgram.DoOnReaderFindMethod(
Reader: TReader;
const MethodName: string;
var Address: Pointer;
var Error: Boolean);
Var
aFullName: String;
ER: TEventHandlerRec;
MR: TMapRec;
M: TMethod;
begin
aFullName := ProgTypeInfoList.FindMethodFullName(Address);
Address := GetAddress(aFullName, MR);
M.Code := Address;
M.Data := gInstance;
Error := Address = Nil;
ER := EventHandlerList.Add(Self,
M.Code, M.Data,
GetCallConv(aFullName),
GetRetSize(aFullName));
M.Code := @ TEventHandlerRec.Invoke;
M.Data := ER;
// Address := nil;
end;
procedure TProgram.RebindEvents(AnInstance: TObject);
procedure _RebindEvents(Instance: TObject);
var
pti, PropType: PTypeInfo;
ptd: PTypeData;
Loop, nProps: Integer;
pProps: PPropList;
ppi: PPropInfo;
M: TMethod;
C: TComponent;
I: Integer;
aFullName: String;
ER: TEventHandlerRec;
begin
pti := Instance.ClassInfo;
if pti = nil then Exit;
ptd := GetTypeData(pti);
nProps := ptd^.PropCount;
if nProps > 0 then
begin
GetMem(pProps, SizeOf(PPropInfo) * nProps);
GetPropInfos(pti, pProps);
for Loop:=0 to nProps - 1 do
begin
{$ifdef fpc}
ppi := pProps^[Loop];
PropType := PPropInfo(ppi)^.PropType;
{$else}
ppi := pProps[Loop];
PropType := PPropInfo(ppi)^.PropType^;
{$endif}
if PropType^.Kind = tkMethod then
begin
M := GetMethodProp(Instance, ppi);
if Assigned(M.Code) and Assigned(M.Data) then
begin
aFullName := ProgTypeInfoList.FindMethodFullName(M.Code);
if AFullName = '' then
continue;
ER := EventHandlerList.Add(Self,
M.Code,
M.Data,
GetCallConv(aFullName),
GetRetSize(aFullName));
M.Code := @ TEventHandlerRec.Invoke;
M.Data := ER;
SetMethodProp(Instance, ppi, M);
end;
end;
end;
FreeMem(pProps, SizeOf(PPropInfo) * nProps);
end;
if Instance is TComponent then
begin
C := TComponent(Instance);
for I := 0 to C.ComponentCount - 1 do
_RebindEvents(C.Components[I]);
end;
end;
begin
_RebindEvents(AnInstance);
end;
{$IFDEF PAX64}
procedure ZZZ; assembler;
{$IFDEF FPC}
nostackframe; asm
{$ELSE}
asm
.NOFRAME
{$ENDIF}
pop rsi;
jmp rsi;
end;
{$ELSE}
procedure ZZZ;
{$IFDEF FPC}
nostackframe; asm
{$ELSE}
asm
{$ENDIF}
pop esi;
jmp esi;
end;
{$ENDIF}
function TProgram.CallFunc(const FullName: String;
This: Pointer;
const ParamList: array of OleVariant;
OverCount: Integer = 0): OleVariant;
const
MaxParam = 30;
var
Invoke, OldEPoint: TInvoke;
Address: Pointer;
MR: TMapRec;
OldESP0, I, NP, T: Integer;
Value: OleVariant;
{$IFNDEF PAXARM}
AnsiStrings: array [0..MaxParam] of AnsiString;
WideStrings: array [0..MaxParam] of WideString;
ShortStrings: array [0..MaxParam] of ShortString;
AnsiS: AnsiString;
{$ENDIF}
UnicStrings: array [0..MaxParam] of UnicString;
valueDouble: Double;
valueSingle: Single;
valueExtended: Extended;
valueCurrency: Currency;
UnicS: UnicString;
begin
Address := GetAddressEx(FullName, OverCount, MR);
if Address = nil then
RaiseError(errRoutineNotFound, [FullName]);
NP := MR.SubDesc.ParamList.Count;
if NP > System.Length(ParamList) then
RaiseError(errNotEnoughActualParameters, [])
else if NP < System.Length(ParamList) then
RaiseError(errTooManyActualParameters, []);
Invoke := TInvoke.Create;
Invoke.CallConv := MR.SubDesc.CallConv;
if MR.SubDesc.ResTypeId in
(OrdinalTypes + [typeCLASS, typeCLASSREF, typePOINTER, typePROC, typeINTERFACE]) then
Invoke.SetResType(typeINTEGER)
else
Invoke.SetResType(MR.SubDesc.ResTypeId);
Invoke.SetResSize(MR.SubDesc.RetSize);
Invoke.Address := Address;
Invoke.SetThis(This);
for I := 0 to NP - 1 do
begin
T := MR.SubDesc.ParamList[I].FinTypeId;
value := ParamList[I];
case T of
typeVOID: Invoke.AddArg(value, typeINTEGER);
typeBOOLEAN: Invoke.AddArg(value, typeINTEGER);
typeBYTE: Invoke.AddArg(value, typeINTEGER);
{$IFNDEF PAXARM}
typeANSICHAR: Invoke.AddArg(value, typeINTEGER);
typeANSISTRING:
begin
AnsiStrings[I] := AnsiString(value);
Invoke.AddArg(IntPax(AnsiStrings[I]), typeINTEGER);
end;
typeSHORTSTRING:
begin
ShortStrings[I] := ShortString(value);
Invoke.AddArg(LongInt(@ShortStrings[I]), typeINTEGER);
end;
typeWIDESTRING:
begin
WideStrings[I] := value;
Invoke.AddArg(IntPax(WideStrings[I]), typeINTEGER);
end;
{$ENDIF}
typeWORD: Invoke.AddArg(value, typeINTEGER);
typeINTEGER: Invoke.AddArg(value, typeINTEGER);
typeDOUBLE:
begin
valueDouble := value;
Invoke.AddArgByVal(valueDouble, SizeOf(Double));
end;
typePOINTER: Invoke.AddArg(LongInt(value), typeINTEGER);
typeRECORD: Invoke.AddArg(LongInt(value), typeINTEGER);
typeARRAY: Invoke.AddArg(LongInt(value), typeINTEGER);
typeALIAS: Invoke.AddArg(LongInt(value), typeINTEGER);
typeENUM: Invoke.AddArg(LongInt(value), typeINTEGER);
typePROC: Invoke.AddArg(LongInt(value), typeINTEGER);
typeSET: Invoke.AddArg(LongInt(value), typeINTEGER);
typeSINGLE:
begin
valueSingle := value;
Invoke.AddArgByVal(valueSingle, SizeOf(Single));
end;
typeEXTENDED:
begin
valueExtended := value;
Invoke.AddArgByVal(valueExtended, SizeOf(Extended));
end;
typeCLASS: Invoke.AddArg(LongInt(value), typeINTEGER);
typeCLASSREF: Invoke.AddArg(LongInt(value), typeINTEGER);
typeWIDECHAR: Invoke.AddArg(LongInt(value), typeINTEGER);
typeVARIANT:
begin
if MR.SubDesc.ParamList[I].ParamMod = PM_BYVAL then
Invoke.AddArg(value, typeVARIANT)
else
Invoke.AddArg(LongInt(@ParamList[I]), typeINTEGER);
end;
typeDYNARRAY: Invoke.AddArg(LongInt(value), typeINTEGER);
typeINT64: Invoke.AddArgByVal(value, SizeOf(Int64));
typeINTERFACE: Invoke.AddArg(LongInt(value), typeINTEGER);
typeCARDINAL: Invoke.AddArg(LongInt(value), typeINTEGER);
typeEVENT: Invoke.AddArg(LongInt(value), typeINTEGER);
typeCURRENCY:
begin
valueCurrency := value;
Invoke.AddArgByVal(valueCurrency, SizeOf(Single));
end;
typeSMALLINT: Invoke.AddArg(LongInt(value), typeINTEGER);
typeSHORTINT: Invoke.AddArg(LongInt(value), typeINTEGER);
typeWORDBOOL: Invoke.AddArg(LongInt(value), typeINTEGER);
typeLONGBOOL: Invoke.AddArg(LongInt(value), typeINTEGER);
typeBYTEBOOL: Invoke.AddArg(LongInt(value), typeINTEGER);
typeOLEVARIANT: Invoke.AddArg(value, typeVARIANT);
typeUNICSTRING:
begin
UnicStrings[I] := value;
Invoke.AddArg(IntPax(UnicStrings[I]), typeINTEGER);
end;
end;
end;
OldEPoint := EPoint;
OldESP0 := fESP0;
try
Invoke.SetUp;
EPoint := Invoke;
Run;
finally
Address := EPoint.GetResultPtr;
fESP0 := OldESP0;
EPoint := OldEPoint;
FreeAndNil(Invoke);
end;
case MR.SubDesc.ResTypeId of
typeVOID: result := Unassigned;
typeBOOLEAN: result := Boolean(Address^);
typeBYTE: result := Byte(Address^);
{$IFNDEF PAXARM}
typeANSICHAR: result := AnsiChar(Address^);
typeANSISTRING:
begin
AnsiS := AnsiString(Address^);
if Length(AnsiS) > 0 then
begin
Address := StrRefCountPtr(Pointer(AnsiS));
Integer(Address^) := Integer(Address^) - 1;
end;
result := AnsiS;
end;
typeSHORTSTRING: result := ShortString(Address^);
typeWIDESTRING: result := WideString(Address^);
{$ENDIF}
typeWORD: result := Word(Address^);
typeINTEGER: result := LongInt(Address^);
typeDOUBLE: result := Double(Address^);
typePOINTER: result := LongInt(Address^);
typeRECORD: result := LongInt(Address);
typeARRAY: result := LongInt(Address);
typeALIAS: result := Unassigned;
typeENUM: result := Byte(Address^);
typePROC: result := LongInt(Address^);
typeSET: result := LongInt(Address^);
typeSINGLE: result := Single(Address^);
typeEXTENDED: result := Extended(Address^);
typeCLASS: result := LongInt(Address^);
typeCLASSREF: result := LongInt(Address^);
typeWIDECHAR: result := WideChar(Address^);
typeVARIANT: result := Variant(Address^);
typeDYNARRAY: result := LongInt(Address^);
typeINT64: result := Integer(Address^);
typeINTERFACE: result := LongInt(Address^);
{$IFDEF VARIANTS}
typeCARDINAL: result := Cardinal(Address^);
{$ELSE}
typeCARDINAL: result := LongInt(Address^);
{$ENDIF}
typeEVENT: result := Unassigned;
typeCURRENCY: result := Currency(Address^);
typeSMALLINT: result := SmallInt(Address^);
typeSHORTINT: result := ShortInt(Address^);
typeWORDBOOL: result := WordBool(Address^);
typeLONGBOOL: result := LongBool(Address^);
typeBYTEBOOL: result := ByteBool(Address^);
typeOLEVARIANT: result := OleVariant(Address^);
typeUNICSTRING:
begin
UnicS := UnicString(Address^);
if Length(UnicS) > 0 then
begin
Address := StrRefCountPtr(Pointer(UnicS));
Integer(Address^) := Integer(Address^) - 1;
end;
result := UnicS;
end;
else
result := Integer(Address^);
end;
if IsHalted then
raise THaltException.Create(ExitCode);
end;
function TProgram.CallFuncEx(const FullName: String;
This: Pointer;
const ParamList: array of const;
IsConstructor: Boolean = false;
OverCount: integer = 0): Variant;
const
MaxParam = 30;
var
Invoke, OldEPoint: TInvoke;
Address: Pointer;
MR: TMapRec;
OldESP0, I, NP, T: Integer;
{$IFNDEF PAXARM}
AnsiStrings: array [0..MaxParam] of AnsiString;
ShortStrings: array [0..MaxParam] of ShortString;
WideStrings: array [0..MaxParam] of WideString;
{$ENDIF}
UnicStrings: array [0..MaxParam] of UnicString;
valueDouble: Double;
valueSingle: Single;
valueExtended: Extended;
valueCurrency: Currency;
valueInt64: Int64;
begin
Address := GetAddressEx(FullName, OverCount, MR);
if Address = nil then
RaiseError(errRoutineNotFound, [FullName]);
NP := MR.SubDesc.ParamList.Count;
if NP > System.Length(ParamList) then
RaiseError(errNotEnoughActualParameters, [])
else if NP < System.Length(ParamList) then
RaiseError(errTooManyActualParameters, []);
Invoke := TInvoke.Create;
Invoke.CallConv := MR.SubDesc.CallConv;
if MR.SubDesc.ResTypeId in
(OrdinalTypes + [typeCLASS, typeCLASSREF, typePOINTER, typePROC, typeINTERFACE]) then
Invoke.SetResType(typeINTEGER)
else
Invoke.SetResType(MR.SubDesc.ResTypeId);
Invoke.SetResSize(MR.SubDesc.RetSize);
Invoke.Address := Address;
Invoke.SetThis(This);
if IsConstructor then
Invoke.AddArg(1, typeINTEGER); // EDX
for I := 0 to NP - 1 do
begin
T := MR.SubDesc.ParamList[I].FinTypeId;
case T of
typeVOID: Invoke.AddArg(ParamList[I].VInteger, typeINTEGER);
typeBOOLEAN: Invoke.AddArg(ParamList[I].VBoolean, typeINTEGER);
typeBYTE: Invoke.AddArg(ParamList[I].VInteger, typeINTEGER);
{$IFNDEF PAXARM}
typeANSICHAR: Invoke.AddArg(ParamList[I].VChar, typeINTEGER);
typeANSISTRING:
begin
case ParamList[I].VType of
vtString: AnsiStrings[I] :=
PShortString(ParamList[I].VString)^;
vtAnsiString: AnsiStrings[I] :=
PAnsiString(ParamList[I].VAnsiString)^;
vtWideString: AnsiStrings[I] :=
AnsiString(PWideString(ParamList[I].VWideString)^);
{$IFDEF UNIC}
vtUnicodeString: AnsiStrings[I] :=
AnsiString(PUnicodeString(ParamList[I].VUnicodeString)^);
{$ENDIF}
vtVariant: AnsiStrings[I] :=
AnsiString(PVariant(ParamList[I].VVariant)^);
vtChar: AnsiStrings[I] :=
ParamList[I].VChar;
vtWideChar: AnsiStrings[I] :=
AnsiChar(ParamList[I].VWideChar);
end;
Invoke.AddArg(IntPax(AnsiStrings[I]), typeINTEGER);
end;
typeSHORTSTRING:
begin
case ParamList[I].VType of
vtString: ShortStrings[I] :=
PShortString(ParamList[I].VString)^;
vtAnsiString: ShortStrings[I] :=
PAnsiString(ParamList[I].VAnsiString)^;
vtWideString: ShortStrings[I] :=
ShortString(PWideString(ParamList[I].VWideString)^);
{$IFDEF UNIC}
vtUnicodeString: ShortStrings[I] :=
AnsiString(PUnicodeString(ParamList[I].VUnicodeString)^);
{$ENDIF}
vtVariant: ShortStrings[I] :=
ShortString(PVariant(ParamList[I].VVariant)^);
vtChar: ShortStrings[I] :=
ParamList[I].VChar;
vtWideChar: ShortStrings[I] :=
AnsiChar(ParamList[I].VWideChar);
end;
Invoke.AddArg(LongInt(@ShortStrings[I]), typeINTEGER);
end;
typeWIDESTRING:
begin
case ParamList[I].VType of
vtString: WideStrings[I] :=
WideString(PShortString(ParamList[I].VString)^);
vtAnsiString: WideStrings[I] :=
WideString(PAnsiString(ParamList[I].VAnsiString)^);
vtWideString: WideStrings[I] :=
PWideString(ParamList[I].VWideString)^;
{$IFDEF UNIC}
vtUnicodeString: WideStrings[I] :=
PUnicodeString(ParamList[I].VUnicodeString)^;
{$ENDIF}
vtVariant: WideStrings[I] :=
PVariant(ParamList[I].VVariant)^;
vtChar: WideStrings[I] :=
WideChar(ParamList[I].VChar);
vtWideChar: WideStrings[I] :=
ParamList[I].VWideChar;
vtPWideChar: WideStrings[I] :=
ParamList[I].VPWideChar;
end;
Invoke.AddArg(IntPax(WideStrings[I]), typeINTEGER);
end;
{$ENDIF}
typeWORD: Invoke.AddArg(ParamList[I].VInteger, typeINTEGER);
typeINTEGER: Invoke.AddArg(ParamList[I].VInteger, typeINTEGER);
typeDOUBLE:
begin
valueDouble := ParamList[I].VExtended^;
Invoke.AddArgByVal(valueDouble, SizeOf(Double));
end;
typePOINTER: Invoke.AddArg(LongInt(ParamList[I].VPointer), typeINTEGER);
typeRECORD: Invoke.AddArg(LongInt(ParamList[I].VPointer), typeINTEGER);
typeARRAY: Invoke.AddArg(LongInt(ParamList[I].VPointer), typeINTEGER);
typeALIAS: Invoke.AddArg(ParamList[I].VInteger, typeINTEGER);
typeENUM: Invoke.AddArg(ParamList[I].VInteger, typeINTEGER);
typePROC: Invoke.AddArg(LongInt(ParamList[I].VPointer), typeINTEGER);
typeSET: Invoke.AddArg(ParamList[I].VInteger, typeINTEGER);
typeSINGLE:
begin
valueSingle := ParamList[I].VExtended^;
Invoke.AddArgByVal(valueSingle, SizeOf(Single));
end;
typeEXTENDED:
begin
valueExtended := ParamList[I].VExtended^;
Invoke.AddArgByVal(valueExtended, SizeOf(Extended));
end;
typeCLASS: Invoke.AddArg(LongInt(ParamList[I].VObject), typeINTEGER);
typeCLASSREF: Invoke.AddArg(LongInt(ParamList[I].VPointer), typeINTEGER);
typeWIDECHAR: Invoke.AddArg(LongInt(ParamList[I].VWideChar), typeINTEGER);
typeVARIANT:
begin
if MR.SubDesc.ParamList[I].ParamMod = PM_BYVAL then
Invoke.AddArg(ParamList[I].VVariant^, typeVARIANT)
else
Invoke.AddArg(LongInt(ParamList[I].VVariant), typeINTEGER);
end;
typeDYNARRAY: Invoke.AddArg(LongInt(ParamList[I].VPointer), typeINTEGER);
typeINT64:
case ParamList[i].VType of
vtInteger: begin
valueInt64 := Int64(ParamList[I].VInteger);
Invoke.AddArgByVal(valueInt64, SizeOf(Int64));
end;
else
Invoke.AddArgByVal(ParamList[I].VInt64^, SizeOf(Int64));
end;
typeINTERFACE: Invoke.AddArg(LongInt(ParamList[I].VInterface), typeINTEGER);
typeCARDINAL: Invoke.AddArg(ParamList[I].VInteger, typeINTEGER);
typeEVENT: Invoke.AddArg(ParamList[I].VInteger, typeINTEGER);
typeCURRENCY:
begin
valueCurrency := ParamList[I].VExtended^;
Invoke.AddArgByVal(valueCurrency, SizeOf(Single));
end;
typeSMALLINT: Invoke.AddArg(ParamList[I].VInteger, typeINTEGER);
typeSHORTINT: Invoke.AddArg(ParamList[I].VInteger, typeINTEGER);
typeWORDBOOL: Invoke.AddArg(ParamList[I].VInteger, typeINTEGER);
typeLONGBOOL: Invoke.AddArg(ParamList[I].VInteger, typeINTEGER);
typeBYTEBOOL: Invoke.AddArg(ParamList[I].VInteger, typeINTEGER);
typeOLEVARIANT:
begin
if MR.SubDesc.ParamList[I].ParamMod = PM_BYVAL then
Invoke.AddArg(ParamList[I].VVariant^, typeVARIANT)
else
Invoke.AddArg(LongInt(ParamList[I].VVariant), typeINTEGER);
end;
typeUNICSTRING:
begin
case ParamList[I].VType of
{$IFNDEF PAXARM}
vtString: UnicStrings[I] :=
UnicString(PShortString(ParamList[I].VString)^);
vtAnsiString: UnicStrings[I] :=
UnicString(PAnsiString(ParamList[I].VAnsiString)^);
vtWideString: UnicStrings[I] :=
PWideString(ParamList[I].VWideString)^;
vtChar: UnicStrings[I] :=
WideChar(ParamList[I].VChar);
{$ENDIF}
{$IFDEF UNIC}
vtUnicodeString: UnicStrings[I] :=
PUnicodeString(ParamList[I].VUnicodeString)^;
{$ENDIF}
vtVariant: UnicStrings[I] :=
PVariant(ParamList[I].VVariant)^;
vtWideChar: UnicStrings[I] :=
ParamList[I].VWideChar;
vtPWideChar: UnicStrings[I] :=
ParamList[I].VPWideChar;
end;
Invoke.AddArg(IntPax(UnicStrings[I]), typeINTEGER);
end;
end;
end;
OldEPoint := EPoint;
OldESP0 := fESP0;
try
Invoke.SetUp;
EPoint := Invoke;
Run;
finally
Address := EPoint.GetResultPtr;
fESP0 := OldESP0;
EPoint := OldEPoint;
FreeAndNil(Invoke);
end;
case MR.SubDesc.ResTypeId of
typeVOID: result := Unassigned;
typeBOOLEAN: result := Boolean(Address^);
typeBYTE: result := Byte(Address^);
{$IFNDEF PAXARM}
typeANSICHAR: result := AnsiChar(Address^);
typeANSISTRING: result := AnsiString(Address^);
typeSHORTSTRING: result := ShortString(Address^);
typeWIDESTRING: result := WideString(Address^);
{$ENDIF}
typeWORD: result := Word(Address^);
typeINTEGER: result := LongInt(Address^);
typeDOUBLE: result := Double(Address^);
typePOINTER: result := LongInt(Address^);
typeRECORD: result := LongInt(Address);
typeARRAY: result := LongInt(Address);
typeALIAS: result := Unassigned;
typeENUM: result := Byte(Address^);
typePROC: result := LongInt(Address^);
typeSET: result := LongInt(Address^);
typeSINGLE: result := Single(Address^);
typeEXTENDED: result := Extended(Address^);
typeCLASS: result := LongInt(Address^);
typeCLASSREF: result := LongInt(Address^);
typeWIDECHAR: result := WideChar(Address^);
typeVARIANT: result := Variant(Address^);
typeDYNARRAY: result := LongInt(Address^);
typeINT64: result := LongInt(Address^);
typeINTERFACE: result := LongInt(Address^);
{$IFDEF VARIANTS}
typeCARDINAL: result := Cardinal(Address^);
{$ELSE}
typeCARDINAL: result := LongInt(Address^);
{$ENDIF}
typeEVENT: result := Unassigned;
typeCURRENCY: result := Currency(Address^);
typeSMALLINT: result := SmallInt(Address^);
typeSHORTINT: result := ShortInt(Address^);
typeWORDBOOL: result := WordBool(Address^);
typeLONGBOOL: result := LongBool(Address^);
typeBYTEBOOL: result := ByteBool(Address^);
typeOLEVARIANT: result := OleVariant(Address^);
typeUNICSTRING: result := UnicString(Address^);
else
result := LongInt(Address^);
end;
if IsHalted then
raise THaltException.Create(ExitCode);
end;
function TProgram.CreateScriptObject(const ScriptClassName: String;
const ParamList: array of const): TObject;
var
ClassIndex: Integer;
PClass: TClass;
MR: TMapRec;
NP: Integer;
V: Variant;
begin
result := nil;
ClassIndex := ClassList.IndexOf(ScriptClassName);
if ClassIndex = -1 then
RaiseError(errClassNotFound, [ScriptClassName]);
PClass := ClassList[ClassIndex].PClass;
NP := System.Length(ParamList);
MR := ScriptMapTable.LookupConstructor(ScriptClassName, NP);
if MR = nil then
Exit;
V := CallFuncEx(MR.FullName, PClass, ParamList, true, MR.SubDesc.OverCount);
result := TObject(TVarData(V).VInteger);
end;
function TProgram.GetTryStack: TTryStack;
begin
result := RootProg.fTryStack;
end;
function TProgram.GetCallStack: TCallStack;
begin
result := RootProg.fCallStack;
end;
function TProgram.GetESP0: Integer;
begin
result := RootProg.fESP0;
end;
procedure TProgram.SetESP0(value: Integer);
begin
RootProg.fESP0 := value;
end;
function TProgram.GetCurrException: Exception;
begin
result := fCurrException;
end;
procedure TProgram.SetCurrException(value: Exception);
begin
fCurrException := value;
end;
function TProgram.GetVirtualAllocProg: Boolean;
begin
result := RootProg.fVirtualAllocProg;
end;
procedure TProgram.SetVirtualAllocProg(value: Boolean);
begin
RootProg.fVirtualAllocProg := value;
end;
function TProgram._VirtualAlloc(Address: Pointer;
Size, flAllocType, flProtect: Cardinal): Pointer;
begin
{$IFDEF MSWINDOWS}
if VirtualAllocProg then
result := VirtualAlloc(Address, Size, flAllocType, flProtect)
else
result := AllocMem(Size);
{$ELSE}
result := AllocMem(Size);
{$ENDIF}
end;
procedure TProgram._VirtualFree(Address: Pointer; Size: Cardinal);
begin
{$IFDEF MSWINDOWS}
if VirtualAllocProg then
VirtualFree(Address, 0, MEM_RELEASE)
else
FreeMem(Address, Size);
{$ELSE}
FreeMem(Address, Size);
{$ENDIF}
end;
function TProgram.GetRootProg: TProgram;
begin
result := Self;
while result.PCUOwner <> nil do
result := result.PCUOwner as TProgram;
end;
function TProgram.GetCallStackCount: Integer;
begin
result := RootCallStack.Count;
end;
function TProgram.GetCallStackItem(I: Integer): Integer;
begin
if (I >= 0) and (I < GetCallStackCount) then
result := RootCallStack[I].SubId
else
result := 0;
end;
function TProgram.GetCallStackLineNumber(I: Integer): Integer;
var
N: Integer;
begin
if (I >= 0) and (I < GetCallStackCount) then
begin
N := RootCallStack[I].NCall;
if N = -1 then
begin
N := GetByteCodeLine;
RootCallStack[I].NCall := N;
end;
result := RunTimeModuleList.GetSourceLine(N);
end
else
result := 0;
end;
function TProgram.GetCallStackModuleName(I: Integer): String;
var
N: Integer;
begin
result := '';
if (I >= 0) and (I < GetCallStackCount) then
begin
N := RootCallStack[I].NCall;
if N = - 1 then
Exit;
result := RunTimeModuleList.GetModuleName(N);
end;
end;
function TProgram.GetCallStackModuleIndex(I: Integer): Integer;
var
N: Integer;
begin
result := -1;
if (I >= 0) and (I < GetCallStackCount) then
begin
N := RootCallStack[I].NCall;
if N = - 1 then
Exit;
result := RunTimeModuleList.GetModuleIndex(N);
end;
end;
procedure TProgram.DiscardPause;
begin
PauseRec.ProgOffset := 0;
end;
procedure TProgram.SetEntryPoint(EntryPoint: TPaxInvoke);
begin
if EntryPoint = nil then
EPoint := nil
else
begin
EPoint := TInvoke(EntryPoint.GetImplementation);
TInvoke(EntryPoint.GetImplementation).OldESP0 := RootESP0;
end;
end;
procedure TProgram.ResetEntryPoint(EntryPoint: TPaxInvoke);
begin
if EntryPoint = nil then
Exit
else
RootESP0 := TInvoke(EntryPoint.GetImplementation).OldESP0;
end;
procedure TProgram.AssignEventHandlerRunner(MethodAddress: Pointer;
Instance: TObject);
begin
OwnerEventHandlerMethod.Code := MethodAddress;
OwnerEventHandlerMethod.Data := Instance;
end;
function TProgram.GetDestructorAddress: Pointer;
begin
result := Address_DestroyObject;
end;
function TProgram.GetParamAddress(Offset: Integer): Pointer;
var
EBP_Value: IntPax;
begin
EBP_Value := RootCallStack.Top.EBP;
result := PauseRec.GetPtr(EBP_Value, Offset);
end;
function TProgram.GetLocalAddress(Offset: Integer): Pointer;
var
EBP_Value: IntPax;
begin
EBP_Value := RootCallStack.Top.EBP;
result := PauseRec.GetPtr(EBP_Value, Offset);
end;
function TProgram.GetParamAddress(StackFrameNumber, Offset: Integer): Pointer;
var
EBP_Value: IntPax;
begin
result := nil;
if StackFrameNumber >= 0 then
EBP_Value := RootCallStack[StackFrameNumber].EBP
else
Exit;
result := PauseRec.GetPtr(EBP_Value, Offset);
end;
function TProgram.GetLocalAddress(StackFrameNumber, Offset: Integer): Pointer;
var
EBP_Value: IntPax;
begin
result := nil;
if StackFrameNumber >= 0 then
EBP_Value := RootCallStack[StackFrameNumber].EBP
else
Exit;
result := PauseRec.GetPtr(EBP_Value, Offset);
end;
end.