ExternalLibraryFunction.st
changeset 24050 f39b5494bc52
parent 24048 1839f4b8eb2e
child 24051 f531b38415db
--- a/ExternalLibraryFunction.st	Wed Apr 10 05:58:34 2019 +0200
+++ b/ExternalLibraryFunction.st	Wed Apr 10 06:08:33 2019 +0200
@@ -1435,13 +1435,16 @@
 #   define __HI32(ll) (((ll)>>32) & 0xFFFFFFFFL)
 #  endif
 # endif
-
+# define MAX_NUM_STRUCT_ARGS    1
+# define MAX_NUM_STRUCT_FIELDS  4
 
     ffi_cif __cif;
     ffi_type *__argTypesIncludingThis[MAX_ARGS+1];
     ffi_type **__argTypes = __argTypesIncludingThis;
     ffi_type *__returnType = NULL;
     ffi_type *thisType;
+    ffi_type structTypes[MAX_NUM_STRUCT_ARGS];
+    ffi_type *structTypeFields[MAX_NUM_STRUCT_ARGS][MAX_NUM_STRUCT_FIELDS+1];
     ffi_abi __callType = FFI_DEFAULT_ABI;
 
 #else
@@ -1455,6 +1458,7 @@
 #endif
 
     int __numFloatOrDoubleArgs = 0;
+    int numStructArgs = 0;
 
     union u {
         INT iVal;
@@ -2044,89 +2048,134 @@
             } else if (__isStringLike(arg)) {
                 if (async == true) {
 badArgForAsyncCall: ;
-                    DEBUGCODE_IF( @global(Verbose), {
-                        printf("invalidArgument: arg%d not allowed for async call [%d]\n", i+1, __LINE__);
-                    })
-                    __FAIL__(@symbol(BadArgForAsyncCall))
-                }
-                __argValues[i].pointerVal = (void *)(__stringVal(arg));
-            } else if (__isBytes(arg) || __isWords(arg) || __isLongs(arg)) {
-                char *p = (char *)(__byteArrayVal(arg));
-                int nInstBytes;
-                OBJ cls;
-
-                if (async == true) goto badArgForAsyncCall;
-                cls = __qClass(arg);
-                nInstBytes = __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
-                __argValues[i].pointerVal = p + nInstBytes;
-            } else {
-                DEBUGCODE_IF( @global(Verbose), {
-                    printf("invalidArgument: arg%d non pointer value [%d]\n", i+1, __LINE__);
-                })
-                __FAIL__(@symbol(InvalidArgument))
-            }
-            argValuePtr = &(__argValues[i].pointerVal);;
-
-        } else if (typeSymbol == @symbol(bool)) {
-            thisType = TYPE_UINT;
-
-            if (arg == true) {
-                __argValues[i].iVal = 1;
-            } else if (arg == false) {
-                __argValues[i].iVal = 0;
-            } else if (__isSmallInteger(arg)) {
-                __argValues[i].iVal = __intVal(arg);
-            } else {
-                __argValues[i].iVal = __unsignedLongIntVal(arg);
-                if (__argValues[i].iVal == 0) {
-                    DEBUGCODE_IF( @global(Verbose), {
-                        printf("invalidArgument: arg%d non bool value [%d]\n", i+1, __LINE__);
-                    })
-                    __FAIL__(@symbol(InvalidArgument))
-                }
-            }
-            argValuePtr = &(__argValues[i].iVal);
-        } else {
-            if (__isSymbol(typeSymbol)
-             && ((argValueClass = __GLOBAL_GET(typeSymbol)) != nil)) {
-                if (! __isBehaviorLike(argValueClass)) {
-                    __FAIL__(@symbol(NonBehaviorArgumentType))
-                }
-                if (! __qIsSubclassOfExternalAddress(argValueClass)) {
-                    __FAIL__(@symbol(NonExternalAddressArgumentType))
-                }
-                goto commonPointerTypeArg; /* sorry */
-            } else {
-                __FAIL__(@symbol(UnknownArgumentType))
-            }
-        }
-
-        __argTypes[i] = thisType;
-        __argValuePointers[i] = argValuePtr;
-
-        if ((thisType == TYPE_FLOAT) || (thisType == TYPE_DOUBLE)) {
-            __numFloatOrDoubleArgs++;
-        }
-        DEBUGCODE_IF( @global(Verbose), {
-            char *typeString = "TYPE_OTHER";
-
-            if (thisType == TYPE_POINTER) {
-                typeString = "TYPE_POINTER";
-            } else if (thisType == TYPE_VOID) {
-                typeString = "TYPE_VOID";
-            } else if (thisType == TYPE_FLOAT) {
-                typeString = "TYPE_FLOAT";
-            } else if (thisType == TYPE_DOUBLE) {
-                typeString = "TYPE_DOUBLE";
-            } else if (thisType == TYPE_UINT) {
-                typeString = "TYPE_UINT";
-            } else if (thisType == TYPE_SINT) {
-                typeString = "TYPE_SINT";
-            }
-            printf("arg%d: %"_lx_" type:%"_lx_" (%s)\n",
-                        i+1,
-                        (INT)(__argValues[i].iVal), (INT)thisType, typeString);
-        })
+		    DEBUGCODE_IF( @global(Verbose), {
+			printf("invalidArgument: arg%d not allowed for async call [%d]\n", i+1, __LINE__);
+		    })
+		    __FAIL__(@symbol(BadArgForAsyncCall))
+		}
+		__argValues[i].pointerVal = (void *)(__stringVal(arg));
+	    } else if (__isBytes(arg) || __isWords(arg) || __isLongs(arg)) {
+		char *p = (char *)(__byteArrayVal(arg));
+		int nInstBytes;
+		OBJ cls;
+
+		if (async == true) goto badArgForAsyncCall;
+		cls = __qClass(arg);
+		nInstBytes = __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
+		__argValues[i].pointerVal = p + nInstBytes;
+	    } else {
+		DEBUGCODE_IF( @global(Verbose), {
+		    printf("invalidArgument: arg%d non pointer value [%d]\n", i+1, __LINE__);
+		})
+		__FAIL__(@symbol(InvalidArgument))
+	    }
+	    argValuePtr = &(__argValues[i].pointerVal);;
+
+	} else if (typeSymbol == @symbol(bool)) {
+	    thisType = TYPE_UINT;
+
+	    if (arg == true) {
+		__argValues[i].iVal = 1;
+	    } else if (arg == false) {
+		__argValues[i].iVal = 0;
+	    } else if (__isSmallInteger(arg)) {
+		__argValues[i].iVal = __intVal(arg);
+	    } else {
+		__argValues[i].iVal = __unsignedLongIntVal(arg);
+		if (__argValues[i].iVal == 0) {
+		    DEBUGCODE_IF( @global(Verbose), {
+			printf("invalidArgument: arg%d non bool value [%d]\n", i+1, __LINE__);
+		    })
+		    __FAIL__(@symbol(InvalidArgument))
+		}
+	    }
+	    argValuePtr = &(__argValues[i].iVal);
+	} else {
+	    if (__isSymbol(typeSymbol)
+	     && ((argValueClass = __GLOBAL_GET(typeSymbol)) != nil)) {
+		if (! __isBehaviorLike(argValueClass)) {
+		    __FAIL__(@symbol(NonBehaviorArgumentType))
+		}
+		if (! __qIsSubclassOfExternalAddress(argValueClass)) {
+		    __FAIL__(@symbol(NonExternalAddressArgumentType))
+		}
+		goto commonPointerTypeArg; /* sorry */
+	    } else {
+		if (__isArray(typeSymbol)) {
+		    // struct
+		    int numFields = __arraySize(typeSymbol);
+		    int i;
+		    ffi_type **fieldTypes;
+
+		    if (numStructArgs >= MAX_NUM_STRUCT_ARGS) {
+			__FAIL__(@symbol(TooManyStructArguments))
+		    }
+		    if (numFields > MAX_NUM_STRUCT_FIELDS) {
+			__FAIL__(@symbol(TooManyStructFields))
+		    }
+		    fieldTypes = &(structTypeFields[numStructArgs][0]);
+
+		    structTypes[numStructArgs].size = 0;
+		    structTypes[numStructArgs].alignment = 0;
+		    structTypes[numStructArgs].elements = fieldTypes;
+		    for (i=0; i<numFields; i++) {
+			OBJ fieldTypeSymbol = __arrayVal(typeSymbol)[i];
+
+			if (fieldTypeSymbol == @symbol(float)) {
+			    fieldTypes[i] = TYPE_FLOAT;
+			} else if (fieldTypeSymbol == @symbol(double)) {
+			    fieldTypes[i] = TYPE_DOUBLE;
+			} else if (fieldTypeSymbol == @symbol(int)) {
+			    fieldTypes[i] = TYPE_SINT;
+			} else {
+			    __FAIL__(@symbol(UnsupportedFieldType))
+			}
+		    }
+		    fieldTypes[i] = NULL;
+		    thisType = &(structTypes[numStructArgs]);
+		    numStructArgs++;
+		    // arg must be either a byteArray or externalBytes pointing to the struct
+		    // i.e. a CDatum's underlying storage
+		    if (__isByteArray(arg)) {
+			if (async == true) goto badArgForAsyncCall;
+			argValuePtr = (void *)(__byteArrayVal(arg));
+		    } else if (__isExternalAddressLike(arg)) {
+			argValuePtr = (void *)(__externalAddressVal(arg));
+		    } else if (__isExternalBytesLike(arg)) {
+			argValuePtr = (void *)(__externalBytesVal(arg));
+		    } else {
+			__FAIL__(@symbol(InvalidArgument))
+		    }
+		}
+	    }
+	}
+
+	__argTypes[i] = thisType;
+	__argValuePointers[i] = argValuePtr;
+
+	if ((thisType == TYPE_FLOAT) || (thisType == TYPE_DOUBLE)) {
+	    __numFloatOrDoubleArgs++;
+	}
+	DEBUGCODE_IF( @global(Verbose), {
+	    char *typeString = "TYPE_OTHER";
+
+	    if (thisType == TYPE_POINTER) {
+		typeString = "TYPE_POINTER";
+	    } else if (thisType == TYPE_VOID) {
+		typeString = "TYPE_VOID";
+	    } else if (thisType == TYPE_FLOAT) {
+		typeString = "TYPE_FLOAT";
+	    } else if (thisType == TYPE_DOUBLE) {
+		typeString = "TYPE_DOUBLE";
+	    } else if (thisType == TYPE_UINT) {
+		typeString = "TYPE_UINT";
+	    } else if (thisType == TYPE_SINT) {
+		typeString = "TYPE_SINT";
+	    }
+	    printf("arg%d: %"_lx_" type:%"_lx_" (%s)\n",
+			i+1,
+			(INT)(__argValues[i].iVal), (INT)thisType, typeString);
+	})
     }
     failureInfo = nil;