Browse Source

* correctly handle non-static functions where the result is passed as a parameter (the order is "Self/VMT, Result, other Args" there)

git-svn-id: trunk@37387 -
svenbarth 7 years ago
parent
commit
5edbdd5a00
1 changed files with 22 additions and 5 deletions
  1. 22 5
      packages/libffi/src/ffi.manager.pp

+ 22 - 5
packages/libffi/src/ffi.manager.pp

@@ -315,12 +315,15 @@ var
   argindirect: array of Pointer;
   argindirect: array of Pointer;
   rtype: pffi_type;
   rtype: pffi_type;
   rvalue: ffi_arg;
   rvalue: ffi_arg;
-  i, arglen, argoffset: LongInt;
+  i, arglen, argoffset, retidx, argstart: LongInt;
   cif: ffi_cif;
   cif: ffi_cif;
   retparam: Boolean;
   retparam: Boolean;
 begin
 begin
   aResultValue := TValue.Empty;
   aResultValue := TValue.Empty;
 
 
+  if not (fcfStatic in aFlags) and (Length(aArgs) = 0) then
+    raise EInvocationError.Create(SErrMissingSelfParam);
+
   case aCallConv of
   case aCallConv of
 {$if defined(CPUI386)}
 {$if defined(CPUI386)}
     ccReg:
     ccReg:
@@ -358,22 +361,36 @@ begin
   if retparam then begin
   if retparam then begin
     Inc(arglen);
     Inc(arglen);
     argoffset := 1;
     argoffset := 1;
-  end else
+    retidx := 0;
+  end else begin
     argoffset := 0;
     argoffset := 0;
+    retidx := -1;
+  end;
 
 
   SetLength(argtypes, arglen);
   SetLength(argtypes, arglen);
   SetLength(argvalues, arglen);
   SetLength(argvalues, arglen);
   SetLength(argindirect, arglen);
   SetLength(argindirect, arglen);
 
 
-  for i := Low(aArgs) to High(aArgs) do begin
+  { the order is Self/Vmt (if any), Result param (if any), other params }
+
+  if not (fcfStatic in aFlags) and retparam then begin
+    argtypes[0] := TypeInfoToFFIType(aArgs[0].Value.TypeInfo);
+    argvalues[0] := ValueToFFIValue(aArgs[0].Value, argindirect[0], False);
+    if retparam then
+      Inc(retidx);
+    argstart := 1;
+  end else
+    argstart := 0;
+
+  for i := Low(aArgs) + argstart to High(aArgs) do begin
     argtypes[i - Low(aArgs) + Low(argtypes) + argoffset] := TypeInfoToFFIType(aArgs[i].Value.TypeInfo);
     argtypes[i - Low(aArgs) + Low(argtypes) + argoffset] := TypeInfoToFFIType(aArgs[i].Value.TypeInfo);
     argvalues[i - Low(aArgs) + Low(argtypes) + argoffset] := ValueToFFIValue(aArgs[i].Value, argindirect[i + argoffset], False);
     argvalues[i - Low(aArgs) + Low(argtypes) + argoffset] := ValueToFFIValue(aArgs[i].Value, argindirect[i + argoffset], False);
   end;
   end;
 
 
   if retparam then begin
   if retparam then begin
-    argtypes[0] := TypeInfoToFFIType(aResultType);
+    argtypes[retidx] := TypeInfoToFFIType(aResultType);
     TValue.Make(Nil, aResultType, aResultValue);
     TValue.Make(Nil, aResultType, aResultValue);
-    argvalues[0] := ValueToFFIValue(aResultValue, argindirect[0], True);
+    argvalues[retidx] := ValueToFFIValue(aResultValue, argindirect[retidx], True);
     rtype := @ffi_type_void;
     rtype := @ffi_type_void;
   end else begin
   end else begin
     rtype := TypeInfoToFFIType(aResultType);
     rtype := TypeInfoToFFIType(aResultType);