Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
23bdb06
Fix compiler state corruption after an exception in the OnUses handler
TetzkatLipHoka Jul 11, 2026
c8454f3
Fix dynamic array parameters and results on the Rtti.Invoke call path
TetzkatLipHoka Jul 11, 2026
8762b2e
Fix operator precedence hole in IsCompatibleType
TetzkatLipHoka Jul 11, 2026
6ae339b
Make failing interface/object casts catchable by script try/except
TetzkatLipHoka Jul 11, 2026
69a9019
IDispatchInvoke: pass IDispatch arguments as VT_DISPATCH
TetzkatLipHoka Jul 11, 2026
ec63090
Support assigning Variants and cross-typed interfaces to interface va…
TetzkatLipHoka Jul 11, 2026
21ce4b3
Report which LoadData stage failed instead of failing silently
TetzkatLipHoka Jul 11, 2026
740dbc7
Raise instead of silently dropping a property with an unresolved type
TetzkatLipHoka Jul 11, 2026
ad34e3a
Restore Delphi 7 compatibility
TetzkatLipHoka Jul 11, 2026
18fa493
Support constant ranges in set literals: ['0'..'9']
TetzkatLipHoka Jul 11, 2026
23338d4
Add a 'raise' statement and the ParamCount/ParamStr builtins
TetzkatLipHoka Jul 11, 2026
9895fb5
Register host types directly from RTTI: AddType(PTypeInfo) and AddRec…
TetzkatLipHoka Jul 11, 2026
4737b9e
Add debug/watch helpers: PSVariantToString overload, StringToPSVarian…
TetzkatLipHoka Jul 11, 2026
d81ca05
Merge branch 'fix/invokecall-dynarrays' into integration/all-fixes
TetzkatLipHoka Jul 11, 2026
bd1fdee
Merge branch 'fix/iscompatibletype-precedence' into integration/all-f…
TetzkatLipHoka Jul 11, 2026
e17e766
Merge branch 'fix/catchable-cast-errors' into integration/all-fixes
TetzkatLipHoka Jul 11, 2026
bcaaa61
Merge branch 'fix/idispatch-vt-dispatch' into integration/all-fixes
TetzkatLipHoka Jul 11, 2026
0808c79
Merge branch 'feature/variant-interface-casts' into integration/all-f…
TetzkatLipHoka Jul 11, 2026
ee18f9a
Merge branch 'fix/loaddata-error-messages' into integration/all-fixes
TetzkatLipHoka Jul 11, 2026
e463bea
Merge branch 'fix/registerproperty-silent-failure' into integration/a…
TetzkatLipHoka Jul 11, 2026
89dea94
Merge branch 'fix/delphi7-compatibility' into integration/all-fixes
TetzkatLipHoka Jul 11, 2026
a05bb8a
Merge branch 'feature/set-range-literals' into integration/all-fixes
TetzkatLipHoka Jul 11, 2026
a69ad7b
Merge branch 'feature/raise-paramstr' into integration/all-fixes
TetzkatLipHoka Jul 11, 2026
79bd6da
Merge branch 'feature/rtti-addtype' into integration/all-fixes
TetzkatLipHoka Jul 11, 2026
4e27c02
Merge branch 'feature/debug-helpers' into integration/all-fixes
TetzkatLipHoka Jul 11, 2026
38273d4
PS_NATIVESTRINGS foundation: native tbt-string types and Ansi base types
TetzkatLipHoka Jul 11, 2026
7a0f655
PS_NATIVESTRINGS: width-neutral char handling in PSSetAnsiString and …
TetzkatLipHoka Jul 11, 2026
bc9a46e
PS_NATIVESTRINGS: bytecode buffers are always byte strings
TetzkatLipHoka Jul 11, 2026
aac2783
PS_NATIVESTRINGS: width-aware string payload I/O in bytecode stream
TetzkatLipHoka Jul 11, 2026
665ad05
PS_NATIVESTRINGS: width-aware tokenizer
TetzkatLipHoka Jul 11, 2026
6f88062
PS_NATIVESTRINGS: real Ansi script types and PWideChar support
TetzkatLipHoka Jul 11, 2026
320221d
PS_NATIVESTRINGS: call marshaling for the Ansi and PWideChar types
TetzkatLipHoka Jul 11, 2026
8179099
PS_NATIVESTRINGS: width-correct array-of-const marshaling
TetzkatLipHoka Jul 11, 2026
17d0107
PS_NATIVESTRINGS: DLL import name handling
TetzkatLipHoka Jul 11, 2026
7fd89ec
PS_NATIVESTRINGS: FPC ARM/AArch64/PowerPC call marshaling (review-based)
TetzkatLipHoka Jul 11, 2026
cb83f36
Fix FPC compilation of uPSRuntime
TetzkatLipHoka Jul 11, 2026
0b799fa
PS_NATIVESTRINGS: FPC-safe Variant-to-string conversions
TetzkatLipHoka Jul 11, 2026
c76357f
PS_NATIVESTRINGS: p-char VTypes in Rtti-path array-of-const
TetzkatLipHoka Jul 11, 2026
5c10a6f
PS_NATIVESTRINGS: btChar values are SizeOf(TbtChar) wide in memory
TetzkatLipHoka Jul 11, 2026
1c35f79
x64: pass by-value dynamic arrays as pointer value on FPC 3+
TetzkatLipHoka Jul 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 129 additions & 14 deletions Source/InvokeCall.inc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
type
ptbtChar = ^tbtchar;
ptbtAnsiChar = ^tbtAnsiChar;
PtbtPChar = ^tbtPChar;
ptbtWideChar = ^tbtwidechar;
ptbtString = ^TbtString;
Expand All @@ -19,12 +20,15 @@ type
DataString: TArray<TArray<tbtString>>;
DataPointer: TArray<TArray<Pointer>>;
DataPChar: TArray<TArray<tbtPChar>>;
DataPAnsiChar: TArray<TArray<PAnsiChar>>;
DataPWideChar: TArray<TArray<PWideChar>>;
DataVariant: TArray<TArray<Variant>>;
{$IFNDEF PS_NOINT64}
DataS64: TArray<TArray<Int64>>;
DataU64: TArray<TArray<UInt64>>;
{$ENDIF}
DataChar: TArray<TArray<tbtChar>>;
DataAnsiChar: TArray<TArray<tbtAnsiChar>>;
{$IFNDEF PS_NOWIDESTRING}
DataWideString: TArray<TArray<tbtWideString>>;
DataWideChar: TArray<TArray<tbtWideChar>>;
Expand All @@ -49,6 +53,7 @@ var
methodValue: TValue;
rttiType: TRttiType;
elemIFC: TPSVariantIFC;
elemTypes: TArray<TPSBaseType>;
begin
Result := Assigned(aValue^.aType) and (IPointer(aValue^.aType) > $FFFF);
if Result then
Expand All @@ -67,6 +72,14 @@ begin
btExtended: aValues := aValues + [TValue.From<Extended>(PExtended(aValue^.dta)^)];
//10
btString: aValues := aValues + [TValue.From<TbtString>(pTbtString(aValue^.dta)^)];
//32
btAnsiString: aValues := aValues + [TValue.From<AnsiString>(PAnsiString(aValue^.dta)^)];
//31
btAnsiChar: aValues := aValues + [TValue.From<AnsiChar>(PAnsiChar(aValue^.dta)^)];
//33 - nil is passed as pointer to #0, matching the asm paths
btPAnsiChar: if Pointer(aValue^.dta^) = nil
then aValues := aValues + [TValue.From<PAnsiChar>(PAnsiChar(''))]
else aValues := aValues + [TValue.From<PAnsiChar>(PPAnsiChar(aValue^.dta)^)];
//11
btRecord: aValues := aValues + [TValue.From<Pointer>(aValue^.dta)];
//12
Expand Down Expand Up @@ -161,6 +174,26 @@ begin
aValues := aValues + [TValue.From<Pointer>(@aOpenArrayData^.DataPChar[High(aOpenArrayData^.DataPChar)][0])];
aValues := aValues + [TValue.From<NativeInt>(l_high)];
end;
btPAnsiChar: begin
aOpenArrayData^.DataPAnsiChar := aOpenArrayData^.DataPAnsiChar + [[]];
SetLength(aOpenArrayData^.DataPAnsiChar[High(aOpenArrayData^.DataPAnsiChar)], l_high + 1);
for i := 0 to l_high do begin
elemIFC := PSGetArrayField(aValue^, i);
aOpenArrayData^.DataPAnsiChar[High(aOpenArrayData^.DataPAnsiChar)][i] := PPAnsiChar(elemIFC.Dta)^;
end;
aValues := aValues + [TValue.From<Pointer>(@aOpenArrayData^.DataPAnsiChar[High(aOpenArrayData^.DataPAnsiChar)][0])];
aValues := aValues + [TValue.From<NativeInt>(l_high)];
end;
btPWideChar: begin
aOpenArrayData^.DataPWideChar := aOpenArrayData^.DataPWideChar + [[]];
SetLength(aOpenArrayData^.DataPWideChar[High(aOpenArrayData^.DataPWideChar)], l_high + 1);
for i := 0 to l_high do begin
elemIFC := PSGetArrayField(aValue^, i);
aOpenArrayData^.DataPWideChar[High(aOpenArrayData^.DataPWideChar)][i] := PPWideChar(elemIFC.Dta)^;
end;
aValues := aValues + [TValue.From<Pointer>(@aOpenArrayData^.DataPWideChar[High(aOpenArrayData^.DataPWideChar)][0])];
aValues := aValues + [TValue.From<NativeInt>(l_high)];
end;
btVariant, btNotificationVariant: begin
//For array of variant we need IntPIFVariantToVariant to get actual Variant values
aOpenArrayData^.DataVariant := aOpenArrayData^.DataVariant + [[]];
Expand Down Expand Up @@ -207,6 +240,16 @@ begin
aValues := aValues + [TValue.From<Pointer>(@aOpenArrayData^.DataChar[High(aOpenArrayData^.DataChar)][0])];
aValues := aValues + [TValue.From<NativeInt>(l_high)];
end;
btAnsiChar: begin
aOpenArrayData^.DataAnsiChar := aOpenArrayData^.DataAnsiChar + [[]];
SetLength(aOpenArrayData^.DataAnsiChar[High(aOpenArrayData^.DataAnsiChar)], l_high + 1);
for i := 0 to l_high do begin
elemIFC := PSGetArrayField(aValue^, i);
aOpenArrayData^.DataAnsiChar[High(aOpenArrayData^.DataAnsiChar)][i] := ptbtAnsiChar(elemIFC.Dta)^;
end;
aValues := aValues + [TValue.From<Pointer>(@aOpenArrayData^.DataAnsiChar[High(aOpenArrayData^.DataAnsiChar)][0])];
aValues := aValues + [TValue.From<NativeInt>(l_high)];
end;
{$IFNDEF PS_NOWIDESTRING}
btWideString: begin
aOpenArrayData^.DataWideString := aOpenArrayData^.DataWideString + [[]];
Expand Down Expand Up @@ -272,15 +315,33 @@ begin
btPointer: begin
//For array of const we need TValueArrayToArrayOfConst to get a TVarRec array
SetLength(arr, 0);
SetLength(elemTypes, l_high + 1);
for i := 0 to l_high do begin
elemIFC := PSGetArrayField(aValue^, i);
elemTypes[i] := elemIFC.aType.BaseType;
if not PSVariantIFCToTValue(@elemIFC, arr, aValues1, aValues2, aOpenArrayData, aSelf) then begin
Result := False;
Exit;
end;
end;
aValues1 := aValues1 + arr;
arr_varrec := TValueArrayToArrayOfConst(arr);
{ TValueArrayToArrayOfConst turns p-char TValues into plain
vtPointer entries; consumers like Format need the proper
p-char VTypes (the data slot is shared, only VType differs) }
for i := 0 to High(arr_varrec) do
case elemTypes[i] of
btPChar:
{$if SizeOf(TbtChar) = 2}
arr_varrec[i].VType := vtPWideChar;
{$else}
arr_varrec[i].VType := vtPChar;
{$ifend}
btPAnsiChar: arr_varrec[i].VType := vtPChar;
{$IFNDEF PS_NOWIDESTRING}
btPWideChar: arr_varrec[i].VType := vtPWideChar;
{$ENDIF}
end;
aValues2 := aValues2 + arr_varrec;
aValues := aValues + [TValue.From<Pointer>(@arr_varrec[0])];
aValues := aValues + [TValue.From<NativeInt>(l_high)];
Expand All @@ -290,8 +351,9 @@ begin
exit;
end;
end
else //dynarray = just push pointer
aValues := aValues + [TValue.From<Pointer>(aValue^.dta)];
else //dynamic array by value: pass the array pointer itself, not
//the address of the slot holding it (that crashed the callee)
aValues := aValues + [TValue.From<Pointer>(PPointer(aValue^.dta)^)];
end;
//13
btPointer: aValues := aValues + [TValue.From<Pointer>(aValue^.dta)];
Expand All @@ -313,6 +375,11 @@ begin
btWideString: aValues := aValues + [TValue.From<tbtWideString>(ptbtWideString(aValue^.dta)^)];
//20
btWideChar: aValues := aValues + [TValue.From<tbtWideChar>(ptbtWideChar(aValue^.dta)^)];
//30
// nil is passed as pointer to #0, matching the asm paths (EmptyPchar in x86.inc/x64.inc)
btPWideChar: if Pointer(aValue^.dta^) = nil
then aValues := aValues + [TValue.From<PWideChar>(PWideChar(''))]
else aValues := aValues + [TValue.From<PWideChar>(pPWideChar(aValue^.dta)^)];
{$ENDIF}
//21
btProcPtr:
Expand Down Expand Up @@ -386,6 +453,8 @@ var SysCalConv : TCallConv;
ctx: TRTTIContext;
RttiType : TRttiType;
ResValue : TValue;
ArrTypeInfo: PTypeInfo;
BorrowList: TPSPCharBorrowList;
begin
Result := False;
IsStatic := _Self = nil;
Expand Down Expand Up @@ -418,11 +487,17 @@ begin
if fvar.varparam then
begin { var param }
case fvar.aType.BaseType of
btArray, btVariant, btSet, btStaticArray, btRecord, btInterface, btClass, {$IFNDEF PS_NOWIDESTRING} btWideString, btWideChar, {$ENDIF}
btArray, btVariant, btSet, btStaticArray, btRecord, btInterface, btClass, {$IFNDEF PS_NOWIDESTRING} btWideString, btWideChar, btPWideChar, {$ENDIF}
btAnsiString, btAnsiChar, btPAnsiChar,
btU8, btS8, btU16, btS16, btU32, btS32, btSingle, btDouble, btExtended, btString, btPChar, btChar, btCurrency,
btUnicodeString
{$IFNDEF PS_NOINT64}, bts64, btU64{$ENDIF}:
Arg := TValue.From<Pointer>( Pointer(fvar.dta) );
begin
// the callee may overwrite P-Char slots (directly or inside
// records/static arrays); borrow their ownership around the call
PSBorrowPCharOwnership(fvar.aType, fvar.dta, BorrowList);
Arg := TValue.From<Pointer>( Pointer(fvar.dta) );
end;
else
begin
Exit;
Expand All @@ -443,6 +518,7 @@ begin
{$ENDIF CPUX86}

IsConstr := (Integer(CallingConv) and 64) <> 0;
try
if not assigned(res) then
begin
Invoke(Address, Args, SysCalConv, nil); { ignore return }
Expand All @@ -463,6 +539,9 @@ begin
btExtended: PExtended(res.dta)^ := Extended(Invoke(Address,Args,SysCalConv,TypeInfo(Extended),IsStatic).AsExtended);
//10
btString: tbtString(res.dta^) := tbtString(Invoke(Address,Args,SysCalConv,TypeInfo(tbtString),IsStatic).AsString);
btAnsiString: AnsiString(res.dta^) := AnsiString(Invoke(Address,Args,SysCalConv,TypeInfo(AnsiString),IsStatic).AsType<AnsiString>());
btAnsiChar: PAnsiChar(res.dta)^ := AnsiChar(Invoke(Address,Args,SysCalConv,TypeInfo(AnsiChar),IsStatic).AsType<AnsiChar>());
btPAnsiChar: TbtAnsiString(res.dta^) := TbtAnsiString(PAnsiChar(Invoke(Address,Args,SysCalConv,TypeInfo(PAnsiChar),IsStatic).AsType<PAnsiChar>()));
{$IFNDEF FPC}
//11
btRecord:
Expand All @@ -478,16 +557,42 @@ begin
//12
btArray: //need to check with open arrays
begin
for RttiType in ctx.GetTypes do
if (RttiType.Name.ToUpper.EndsWith(String(res.aType.FExportName))) and (RttiType.TypeKind = tkDynArray) then
begin
ResValue := Invoke(Address,Args,SysCalConv,RttiType.Handle,IsStatic);
if ResValue.GetArrayLength > 0 then
CopyArrayContents(res.dta, ResValue.GetReferenceToRawData, 1, res.aType)
else
res.dta := nil;
Break;
end;
// Invoke needs a dynamic array type info only for the result ABI
// (identical for all dynamic arrays) and to release the TValue's
// reference afterwards. The element-wise handling below uses the
// script's own type record, so for the TValue any type info with the
// right managed kind of element suffices.
ArrTypeInfo := nil;
case TPSTypeRec_Array(res.aType).ArrayType.BaseType of
btString: ArrTypeInfo := TypeInfo(TArray<tbtString>);
{$IFNDEF PS_NOWIDESTRING}
btWideString: ArrTypeInfo := TypeInfo(TArray<tbtWideString>);
btUnicodeString: ArrTypeInfo := TypeInfo(TArray<tbtUnicodeString>);
{$ENDIF}
btVariant: ArrTypeInfo := TypeInfo(TArray<Variant>);
btInterface: ArrTypeInfo := TypeInfo(TArray<IInterface>);
btArray, btRecord, btStaticArray:
// nested containers: prefer the host's own array type (exact
// element layout), located by the exported type name
for RttiType in ctx.GetTypes do
if (RttiType.TypeKind = tkDynArray) and (res.aType.FExportName <> '') and
(RttiType.Name.ToUpper.EndsWith(String(res.aType.FExportName))) then
begin
ArrTypeInfo := RttiType.Handle;
Break;
end;
else
// unmanaged elements: releasing the reference is a plain block
// free, any element type will do
ArrTypeInfo := TypeInfo(TArray<Byte>);
end;
if ArrTypeInfo = nil then
Exit; // fail the call instead of silently returning an empty array
ResValue := Invoke(Address, Args, SysCalConv, ArrTypeInfo, IsStatic);
// reference-assign into the script slot using the script's own type
// record; this also clears the slot correctly for empty results (the
// old code corrupted the IFC record by setting res.dta to nil)
CopyArrayContents(res.dta, ResValue.GetReferenceToRawData, 1, res.aType);
end;
//13
btPointer: res.dta := Pointer(Invoke(Address,Args,SysCalConv,TypeInfo(Pointer),IsStatic).AsType<Pointer>);
Expand Down Expand Up @@ -529,6 +634,13 @@ begin
{$ELSE}
ptbtWideChar(res.dta)^ := tbtWideChar(Invoke(Address,Args,SysCalConv,TypeInfo(tbtWideChar),IsStatic).AsType<tbtWideChar>());
{$ENDIF}
//30
btPWideChar:
{$IFDEF FPC}
tbtunicodestring(res.dta^) := tbtunicodestring(PWideChar(Invoke(Address,Args,SysCalConv,TypeInfo(PWideChar),IsStatic).AsOrdinal));
{$ELSE}
tbtunicodestring(res.dta^) := tbtunicodestring(PWideChar(Invoke(Address,Args,SysCalConv,TypeInfo(PWideChar),IsStatic).AsType<PWideChar>()));
{$ENDIF}
{$ENDIF}
//21
btProcPtr:
Expand Down Expand Up @@ -606,6 +718,9 @@ begin
Exit;
end; { case }
end; //assigned(res)
finally
PSReownPCharOwnership(BorrowList);
end;
SetLength(Args, 0);
SetLength(old_Args, 0);
SetLength(old_Args2, 0);
Expand Down
9 changes: 9 additions & 0 deletions Source/PascalScript.inc
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,17 @@ Defines:
PS_NOWIDESTRING
PS_NOINT64
PS_DELPHIDIV
PS_NATIVESTRINGS - tbtChar/tbtPChar/tbtString follow the host compiler's
native string types (Unicode on Delphi 2009+): host
functions registered with tbtString parameters match the
width the engine passes, and the script types
PChar/AnsiChar/AnsiString/PAnsiChar become fully usable
(btPWideChar and the always-Ansi base types).
Default: not defined - behavior is unchanged.
}

{.$DEFINE PS_NATIVESTRINGS}

{$UNDEF DEBUG}

{$IFDEF CLX}
Expand Down
Loading