Browse Source

* also take param flags into consideration

git-svn-id: trunk@39890 -
svenbarth 6 years ago
parent
commit
b91c856e38
1 changed files with 108 additions and 103 deletions
  1. 108 103
      packages/libffi/src/ffi.manager.pp

+ 108 - 103
packages/libffi/src/ffi.manager.pp

@@ -41,7 +41,7 @@ begin
   Dispose(t);
 end;
 
-function TypeInfoToFFIType(aTypeInfo: PTypeInfo): pffi_type; forward;
+function TypeInfoToFFIType(aTypeInfo: PTypeInfo; aFlags: TParamFlags): pffi_type; forward;
 
 function RecordOrObjectToFFIType(aTypeInfo: PTypeInfo): pffi_type;
 var
@@ -99,7 +99,7 @@ begin
       Dec(remoffset, SizeOf(Byte))
     end;
     { now add the real field type }
-    AddElement(TypeInfoToFFIType(field^.TypeRef));
+    AddElement(TypeInfoToFFIType(field^.TypeRef, []));
     Inc(field);
     curoffset := field^.FldOffset;
   end;
@@ -153,7 +153,7 @@ begin
   Tpffi_typeArray(Result^.elements) := elements;
 end;
 
-function TypeInfoToFFIType(aTypeInfo: PTypeInfo): pffi_type;
+function TypeInfoToFFIType(aTypeInfo: PTypeInfo; aFlags: TParamFlags): pffi_type;
 
   function TypeKindName: String;
   begin
@@ -167,103 +167,106 @@ begin
   Result := @ffi_type_void;
   if Assigned(aTypeInfo) then begin
     td := GetTypeData(aTypeInfo);
-    case aTypeInfo^.Kind of
-      tkInteger,
-      tkEnumeration,
-      tkBool,
-      tkInt64,
-      tkQWord:
-        case td^.OrdType of
-          otSByte:
-            Result := @ffi_type_sint8;
-          otUByte:
-            Result := @ffi_type_uint8;
-          otSWord:
-            Result := @ffi_type_sint16;
-          otUWord:
-            Result := @ffi_type_uint16;
-          otSLong:
-            Result := @ffi_type_sint32;
-          otULong:
-            Result := @ffi_type_uint32;
-          otSQWord:
-            Result := @ffi_type_sint64;
-          otUQWord:
-            Result := @ffi_type_uint64;
-        end;
-      tkChar:
-        Result := @ffi_type_uint8;
-      tkFloat:
-        case td^.FloatType of
-          ftSingle:
-            Result := @ffi_type_float;
-          ftDouble:
-            Result := @ffi_type_double;
-          ftExtended:
-            Result := @ffi_type_longdouble;
-          ftComp:
-{$ifndef FPC_HAS_TYPE_EXTENDED}
-            Result := @ffi_type_sint64;
-{$else}
-            Result := @ffi_type_longdouble;
-{$endif}
-          ftCurr:
-            Result := @ffi_type_sint64;
-        end;
-      tkSet:
-        case td^.OrdType of
-          otUByte: begin
-            if td^.SetSize = 1 then
-              Result := @ffi_type_uint8
-            else begin
-              { ugh... build a of suitable record }
-              Result := SetToFFIType(td^.SetSize);
+    if aFlags * [pfArray, pfOut, pfVar, pfConstRef] <> [] then
+      Result := @ffi_type_pointer
+    else
+      case aTypeInfo^.Kind of
+        tkInteger,
+        tkEnumeration,
+        tkBool,
+        tkInt64,
+        tkQWord:
+          case td^.OrdType of
+            otSByte:
+              Result := @ffi_type_sint8;
+            otUByte:
+              Result := @ffi_type_uint8;
+            otSWord:
+              Result := @ffi_type_sint16;
+            otUWord:
+              Result := @ffi_type_uint16;
+            otSLong:
+              Result := @ffi_type_sint32;
+            otULong:
+              Result := @ffi_type_uint32;
+            otSQWord:
+              Result := @ffi_type_sint64;
+            otUQWord:
+              Result := @ffi_type_uint64;
+          end;
+        tkChar:
+          Result := @ffi_type_uint8;
+        tkFloat:
+          case td^.FloatType of
+            ftSingle:
+              Result := @ffi_type_float;
+            ftDouble:
+              Result := @ffi_type_double;
+            ftExtended:
+              Result := @ffi_type_longdouble;
+            ftComp:
+  {$ifndef FPC_HAS_TYPE_EXTENDED}
+              Result := @ffi_type_sint64;
+  {$else}
+              Result := @ffi_type_longdouble;
+  {$endif}
+            ftCurr:
+              Result := @ffi_type_sint64;
+          end;
+        tkSet:
+          case td^.OrdType of
+            otUByte: begin
+              if td^.SetSize = 1 then
+                Result := @ffi_type_uint8
+              else begin
+                { ugh... build a of suitable record }
+                Result := SetToFFIType(td^.SetSize);
+              end;
             end;
+            otUWord:
+              Result := @ffi_type_uint16;
+            otULong:
+              Result := @ffi_type_uint32;
           end;
-          otUWord:
-            Result := @ffi_type_uint16;
-          otULong:
-            Result := @ffi_type_uint32;
-        end;
-      tkWChar,
-      tkUChar:
-        Result := @ffi_type_uint16;
-      tkInterface,
-      tkAString,
-      tkUString,
-      tkWString,
-      tkInterfaceRaw,
-      tkProcVar,
-      tkDynArray,
-      tkClass,
-      tkClassRef,
-      tkPointer:
-        Result := @ffi_type_pointer;
-      tkMethod:
-        Result := RecordOrObjectToFFIType(TypeInfo(TMethod));
-      tkSString:
-        { since shortstrings are rather large they're passed as references }
-        Result := @ffi_type_pointer;
-      tkObject:
-        { passed around as pointer as well }
-        Result := @ffi_type_pointer;
-      tkArray:
-        { arrays are passed as pointers to be compatible to C }
-        Result := @ffi_type_pointer;
-      tkRecord:
-        Result := RecordOrObjectToFFIType(aTypeInfo);
-      tkVariant:
-        Result := RecordOrObjectToFFIType(TypeInfo(tvardata));
-      //tkLString: ;
-      //tkHelper: ;
-      //tkFile: ;
-      else
-        raise EInvocationError.CreateFmt(SErrTypeKindNotSupported, [TypeKindName]);
-    end;
+        tkWChar,
+        tkUChar:
+          Result := @ffi_type_uint16;
+        tkInterface,
+        tkAString,
+        tkUString,
+        tkWString,
+        tkInterfaceRaw,
+        tkProcVar,
+        tkDynArray,
+        tkClass,
+        tkClassRef,
+        tkPointer:
+          Result := @ffi_type_pointer;
+        tkMethod:
+          Result := RecordOrObjectToFFIType(TypeInfo(TMethod));
+        tkSString:
+          { since shortstrings are rather large they're passed as references }
+          Result := @ffi_type_pointer;
+        tkObject:
+          { passed around as pointer as well }
+          Result := @ffi_type_pointer;
+        tkArray:
+          { arrays are passed as pointers to be compatible to C }
+          Result := @ffi_type_pointer;
+        tkRecord:
+          Result := RecordOrObjectToFFIType(aTypeInfo);
+        tkVariant:
+          Result := RecordOrObjectToFFIType(TypeInfo(tvardata));
+        //tkLString: ;
+        //tkHelper: ;
+        //tkFile: ;
+        else
+          raise EInvocationError.CreateFmt(SErrTypeKindNotSupported, [TypeKindName]);
+      end;
   end;
 end;
 
-function ValueToFFIValue(constref aValue: Pointer; aKind: TTypeKind; aIsResult: Boolean): Pointer;
+function ValueToFFIValue(constref aValue: Pointer; aKind: TTypeKind; aFlags: TParamFlags; aIsResult: Boolean): Pointer;
 const
   ResultTypeNeedsIndirection = [
    tkAString,
@@ -274,7 +277,9 @@ const
   ];
 begin
   Result := aValue;
-  if (aKind = tkSString) or (aIsResult and (aKind in ResultTypeNeedsIndirection)) then
+  if (aKind = tkSString) or
+      (aIsResult and (aKind in ResultTypeNeedsIndirection)) or
+      (aFlags * [pfArray, pfOut, pfVar, pfConstRef] <> []) then
     Result := @aValue;
 end;
 
@@ -444,8 +449,8 @@ 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].Info.ParamType);
-    argvalues[0] := ValueToFFIValue(aArgs[0].ValueRef, aArgs[0].Info.ParamType^.Kind, False);
+    argtypes[0] := TypeInfoToFFIType(aArgs[0].Info.ParamType, aArgs[0].Info.ParamFlags);
+    argvalues[0] := ValueToFFIValue(aArgs[0].ValueRef, aArgs[0].Info.ParamType^.Kind, aArgs[0].Info.ParamFlags, False);
     if retparam then
       Inc(retidx);
     argstart := 1;
@@ -453,16 +458,16 @@ begin
     argstart := 0;
 
   for i := Low(aArgs) + argstart to High(aArgs) do begin
-    argtypes[i - Low(aArgs) + Low(argtypes) + argoffset] := TypeInfoToFFIType(aArgs[i].Info.ParamType);
-    argvalues[i - Low(aArgs) + Low(argtypes) + argoffset] := ValueToFFIValue(aArgs[i].ValueRef, aArgs[i].Info.ParamType^.Kind, False);
+    argtypes[i - Low(aArgs) + Low(argtypes) + argoffset] := TypeInfoToFFIType(aArgs[i].Info.ParamType, aArgs[i].Info.ParamFlags);
+    argvalues[i - Low(aArgs) + Low(argtypes) + argoffset] := ValueToFFIValue(aArgs[i].ValueRef, aArgs[i].Info.ParamType^.Kind, aArgs[i].Info.ParamFlags, False);
   end;
 
   if retparam then begin
-    argtypes[retidx] := TypeInfoToFFIType(aResultType);
-    argvalues[retidx] := ValueToFFIValue(aResultValue, aResultType^.Kind, True);
+    argtypes[retidx] := TypeInfoToFFIType(aResultType, []);
+    argvalues[retidx] := ValueToFFIValue(aResultValue, aResultType^.Kind, [], True);
     rtype := @ffi_type_void;
   end else begin
-    rtype := TypeInfoToFFIType(aResultType);
+    rtype := TypeInfoToFFIType(aResultType, []);
   end;
 
   if ffi_prep_cif(@cif, abi, arglen, rtype, @argtypes[0]) <> FFI_OK then