mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-20 21:11:55 +02:00
+ add support for callbacks to the FFI invoke manager
git-svn-id: trunk@42071 -
This commit is contained in:
parent
0d6d3a1529
commit
9fa4a619d7
@ -624,11 +624,188 @@ begin
|
|||||||
{$endif}
|
{$endif}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
type
|
||||||
|
TFFIFunctionCallback = class(TFunctionCallCallback)
|
||||||
|
private
|
||||||
|
fFFIData: TFFIData;
|
||||||
|
fData: Pointer;
|
||||||
|
fCode: CodePointer;
|
||||||
|
fContext: Pointer;
|
||||||
|
private
|
||||||
|
class procedure ClosureFunc(aCIF: pffi_cif; aRet: Pointer; aArgs: PPointer; aUserData: Pointer); cdecl; static;
|
||||||
|
procedure PassToHandler(aRet: Pointer; aArgs: PPointer);
|
||||||
|
protected
|
||||||
|
function GetCodeAddress: CodePointer; override;
|
||||||
|
procedure CallHandler(constref aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer); virtual; abstract;
|
||||||
|
public
|
||||||
|
constructor Create(aContext: Pointer; aCallConv: TCallConv; constref aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags);
|
||||||
|
destructor Destroy; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TFFIFunctionCallbackMethod = class(TFFIFunctionCallback)
|
||||||
|
private
|
||||||
|
fHandler: TFunctionCallMethod;
|
||||||
|
protected
|
||||||
|
procedure CallHandler(constref aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer); override;
|
||||||
|
public
|
||||||
|
constructor Create(aHandler: TFunctionCallMethod; aContext: Pointer; aCallConv: TCallConv; constref aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags);
|
||||||
|
end;
|
||||||
|
|
||||||
|
TFFIFunctionCallbackProc = class(TFFIFunctionCallback)
|
||||||
|
private
|
||||||
|
fHandler: TFunctionCallProc;
|
||||||
|
protected
|
||||||
|
procedure CallHandler(constref aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer); override;
|
||||||
|
public
|
||||||
|
constructor Create(aHandler: TFunctionCallProc; aContext: Pointer; aCallConv: TCallConv; constref aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class procedure TFFIFunctionCallback.ClosureFunc(aCIF: pffi_cif; aRet: Pointer; aArgs: PPointer; aUserData: Pointer); cdecl;
|
||||||
|
var
|
||||||
|
this: TFFIFunctionCallback absolute aUserData;
|
||||||
|
begin
|
||||||
|
this.PassToHandler(aRet, aArgs);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TFFIFunctionCallback.PassToHandler(aRet: Pointer; aArgs: PPointer);
|
||||||
|
var
|
||||||
|
args: array of Pointer;
|
||||||
|
i, arglen, argidx: SizeInt;
|
||||||
|
resptr: Pointer;
|
||||||
|
{$ifdef USE_EXTENDED_AS_COMP_CURRENCY_RES}
|
||||||
|
{$ifndef FPC_COMP_IS_INT64}
|
||||||
|
rescomp: Comp;
|
||||||
|
{$endif}
|
||||||
|
{$ifndef FPC_CURR_IS_INT64}
|
||||||
|
rescurr: Currency;
|
||||||
|
{$endif}
|
||||||
|
{$endif}
|
||||||
|
begin
|
||||||
|
arglen := Length(fFFIData.Types);
|
||||||
|
if fFFIData.ResultIndex >= 0 then
|
||||||
|
Dec(arglen);
|
||||||
|
SetLength(args, arglen);
|
||||||
|
argidx := 0;
|
||||||
|
for i := 0 to High(fFFIData.Types) do begin
|
||||||
|
if i = fFFIData.ResultIndex then
|
||||||
|
Continue;
|
||||||
|
args[argidx] := aArgs[i];
|
||||||
|
if fFFIData.Indirect[i] then
|
||||||
|
args[argidx] := PPointer(aArgs[i])^
|
||||||
|
else
|
||||||
|
args[argidx] := aArgs[i];
|
||||||
|
Inc(argidx);
|
||||||
|
end;
|
||||||
|
|
||||||
|
if fFFIData.ResultIndex >= 0 then begin
|
||||||
|
if fFFIData.Indirect[fFFIData.ResultIndex] then
|
||||||
|
resptr := PPointer(aArgs[fFFIData.ResultIndex])^
|
||||||
|
else
|
||||||
|
resptr := aArgs[fFFIData.ResultIndex];
|
||||||
|
end else begin
|
||||||
|
{$ifdef USE_EXTENDED_AS_COMP_CURRENCY_RES}
|
||||||
|
resptr := Nil;
|
||||||
|
if Assigned(fFFIData.ResultTypeData) then begin
|
||||||
|
case fFFIData.ResultTypeData^.FloatType of
|
||||||
|
{$ifndef FPC_COMP_IS_INT64}
|
||||||
|
ftComp:
|
||||||
|
resptr := @rescomp;
|
||||||
|
{$endif}
|
||||||
|
{$ifndef FPC_CURR_IS_INT64}
|
||||||
|
ftCurr:
|
||||||
|
resptr := @rescurr;
|
||||||
|
{$endif}
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if not Assigned(resptr) then
|
||||||
|
{$endif}
|
||||||
|
resptr := aRet;
|
||||||
|
end;
|
||||||
|
|
||||||
|
CallHandler(args, resptr, fContext);
|
||||||
|
|
||||||
|
{$ifdef USE_EXTENDED_AS_COMP_CURRENCY_RES}
|
||||||
|
if Assigned(fFFIData.ResultTypeData) then begin
|
||||||
|
case fFFIData.ResultTypeData^.FloatType of
|
||||||
|
{$ifndef FPC_COMP_IS_INT64}
|
||||||
|
ftComp:
|
||||||
|
PExtended(aRet)^ := rescomp;
|
||||||
|
{$endif}
|
||||||
|
{$ifndef FPC_CURR_IS_INT64}
|
||||||
|
ftCurr:
|
||||||
|
PExtended(aRet) ^ := rescurr * 10000;
|
||||||
|
{$endif}
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
{$endif}
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TFFIFunctionCallback.GetCodeAddress: CodePointer;
|
||||||
|
begin
|
||||||
|
Result := fData;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TFFIFunctionCallback.Create(aContext: Pointer; aCallConv: TCallConv; constref aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags);
|
||||||
|
var
|
||||||
|
res: ffi_status;
|
||||||
|
begin
|
||||||
|
fContext := aContext;
|
||||||
|
|
||||||
|
CreateCIF(aArgs, [], aCallConv, aResultType, Nil, aFlags, fFFIData);
|
||||||
|
|
||||||
|
fData := ffi_closure_alloc(SizeOf(ffi_closure), @fCode);
|
||||||
|
if not Assigned(fData) or not Assigned(fCode) then
|
||||||
|
raise ERTTI.Create(SErrMethodImplCreateFailed);
|
||||||
|
|
||||||
|
res := ffi_prep_closure_loc(pffi_closure(fData), @fFFIData.CIF, @ClosureFunc, Self, fCode);
|
||||||
|
if res <> FFI_OK then
|
||||||
|
raise ERTTI.Create(SErrMethodImplCreateFailed);
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TFFIFunctionCallback.Destroy;
|
||||||
|
begin
|
||||||
|
if Assigned(fData) then
|
||||||
|
ffi_closure_free(fData);
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TFFIFunctionCallbackProc.Create(aHandler: TFunctionCallProc; aContext: Pointer; aCallConv: TCallConv; constref aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags);
|
||||||
|
begin
|
||||||
|
inherited Create(aContext, aCallConv, aArgs, aResultType, aFlags);
|
||||||
|
fHandler := aHandler;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TFFIFunctionCallbackProc.CallHandler(constref aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer);
|
||||||
|
begin
|
||||||
|
fHandler(aArgs, aResult, aContext);
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TFFIFunctionCallbackMethod.Create(aHandler: TFunctionCallMethod; aContext: Pointer; aCallConv: TCallConv; constref aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags);
|
||||||
|
begin
|
||||||
|
inherited Create(aContext, aCallConv, aArgs, aResultType, aFlags);
|
||||||
|
fHandler := aHandler;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TFFIFunctionCallbackMethod.CallHandler(constref aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer);
|
||||||
|
begin
|
||||||
|
fHandler(aArgs, aResult, aContext);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function FFICreateCallbackProc(aHandler: TFunctionCallProc; aCallConv: TCallConv; aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags; aContext: Pointer): TFunctionCallCallback;
|
||||||
|
begin
|
||||||
|
Result := TFFIFunctionCallbackProc.Create(aHandler, aContext, aCallConv, aArgs, aResultType, aFlags);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function FFICreateCallbackMethod(aHandler: TFunctionCallMethod; aCallConv: TCallConv; aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags; aContext: Pointer): TFunctionCallCallback;
|
||||||
|
begin
|
||||||
|
Result := TFFIFunctionCallbackMethod.Create(aHandler, aContext, aCallConv, aArgs, aResultType, aFlags);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
const
|
const
|
||||||
FFIManager: TFunctionCallManager = (
|
FFIManager: TFunctionCallManager = (
|
||||||
Invoke: @FFIInvoke;
|
Invoke: @FFIInvoke;
|
||||||
CreateCallbackProc: Nil;
|
CreateCallbackProc: @FFICreateCallbackProc;
|
||||||
CreateCallbackMethod: Nil;
|
CreateCallbackMethod: @FFICreateCallbackMethod;
|
||||||
);
|
);
|
||||||
|
|
||||||
var
|
var
|
||||||
|
Loading…
Reference in New Issue
Block a user