Hi all!
We have #doesNotUnderstand:, which is sent to the receiver when a message cannot be understood. Default reaction in Object is to raise MessageNotUnderstood exception. What if we could have a similar mechanism for FFI calls: #doesNotCoerce:for:. The receiver would be the one that made that call, should be an instance of ExternalLibrary, but could be any object. The arguments would be a pair of (argObject, argType) and the message (like the argument for doesNotUnderstand:) that represents the FFI call. The pair of (argObject, argType) could be expressed as FFICallArgument: FFICallArgument argObject ... <Object> argType ... <ExternalType> I suppose that such a new class would have to be reserved in the special objects array. An alternative would be to just use Array. Keep it simple. ;-) Default reaction could be to implement #doesNotCoerce:for: in Object (as *FFI-Kernel extension) to raise FFICallArgumentNotCoerced exception (to be implemented). Also, we could implement manual coercion in ExternaLibrary to, for example, wrap atomics into their aliasing structures. ExternalLibrary >> #doesNotCoerce: callArg for: message | argObject argType argIndex wrappedArg | argObject := callArg first. "or argObject accessor" argType := callArg second. "or argType accessor" argIndex := message arguments indexOf: argObject. wrappedArg := argType referentClass fromHandle: argObject. message arguments beWritableObject. "Just in case ;-)" message at: argIndex put: wrappedArg. ^ message sendTo: self Please share your thoughts. :-) Best, Marcel |
Hi all, again. :-)
I am aware that such a mechanism would have to be implemented in 2-times-7 different places: Best, Marcel
|
Hi Marcel, Forget about FFIPlugin it's legacy I'm currently changing ThreadedFFIPlugin to: - enable passing ExternalData as atomicType by value The use case is the one of ExternalVariable - enable ExternalData to have an ExternalStructure or ExternalTypeAlias as type inst. var. and enable passing that to a corresponding ExternalStructure/ExternalStructure pointer/ExternalTypeAlias/ ExternalTypeAlias pointer - returning a new ExternalTypeAlias when returning such type by value This way, we can make FFI a bit safer than using those void * Le ven. 19 juin 2020 à 13:45, Marcel Taeumel <[hidden email]> a écrit :
|
Hi Nicolas.
> - enable ExternalData to have an ExternalStructure or ExternalTypeAlias as type inst. var. This does not sound right. But I think you mean that "type" in ExternalData could be a struct type and the plugin would automatically coerce it correctly. That's good. :-) "type" in ExternalData must always be an instance of ExternalType. > This way, we can make FFI a bit safer than using those void * Sounds good. Best, Marcel P.S.: I think I messed up with the name "ExternalTypeAlias". Hmpf. Because is a subclass of ExternalStructure, not ExternalType. Well. :-)
|
Le ven. 19 juin 2020 à 15:46, Marcel Taeumel <[hidden email]> a écrit :
I see what you mean. But, that's not exactly how it works. ExternalStructureFoo (the class, not an instance) acts as an ExternalType surrogate. See: ExternalType structTypeNamed: #FFISmallStruct1. It will answer FFISmallStruct1, so FFISmallStruct1 is a type somehow, a structType more exactly (or a type alias). I suggest to use that as ExternalData type whenever we have a pointer to a FFISmallStruct1 or an array of FFISmallStruct1. It also make FFI type checking super easy, because we already pass the FFISmallStruct1 as argClass (only when passing struct by value by now, but I suggest extending it when passing FFISmallStruct1 *, which currently is not even possible - we have to declare void *)
|
Hi Nicolas.
>ExternalStructureFoo (the class, not an instance) acts as an ExternalType > surrogate.Well, only by name. Not by object identity. > ExternalType structTypeNamed: #FFISmallStruct1. > It will answer FFISmallStruct1, so FFISmallStruct1 is a type somehow, a> structType more exactly (or a type alias). Well, #structTypeNamed: answers an instance of ExternalType whose referentClass points to the structure class, which is FFISmallStruct in this example. Yet, the VM / plugin does not care about the name here. It only cares about instances of ExternalType and to which referentClass those types point. Best, Marcel
|
Maybe this helps: FFISmallStruct1 externalType == (ExternalType structTypeNamed: FFISmallStruct1 className). FFISmallStruct1 externalType referentClass == FFISmallStruct1. FFISmallStruct1 new isKindOf: ExternalStructure. FFISmallStruct1 externalType isKindOf: ExternalType. ExternalTypeAlias inheritsFrom: ExternalStructure. "!!!" Best, Marcel
|
In reply to this post by marcel.taeumel
Hi all!
What would be the "best English" for such a mechanism? anExternalLibrary doesNotCoerce: aCallArg for: aMessage. anExternalLibrary doesNotCoerce: aCallArg in: aMessage. anExternalLibrary cannotCoerce: aCallArg for: aMessage. anExternalLibrary cannotCoerce: aCallArg in: aMessage. ... Best, Marcel
|
In reply to this post by marcel.taeumel
Le ven. 19 juin 2020 à 16:02, Marcel Taeumel <[hidden email]> a écrit :
Ah sorry, my mistake. I indeed need to go thru referentClass to achieve what I was thinking of. Thanks!
Since we pass argClass, we can simply check against ExternalData type referentClass.
|
In reply to this post by marcel.taeumel
Hi Marcel: On Fri, 19 Jun 2020 at 1:15 pm, Marcel Taeumel <[hidden email]> wrote:
I don't like the idea of adding a plugin-specific mechanism like this to the VM. I know it's not as convenient, but maybe something similar can be achieved with error codes in fallback code? There already is BAD_ARGUMENT, maybe there's a way to encode which argument is bad in the error code? Fabio
|
Hi Fabio,
> I don't like the idea of adding a plugin-specific mechanism like this to the VM. Why is that? The implementation strategy would be very clear: like #doesNotUnderstand:. It's just a new entry on the special objects array. > There already is BAD_ARGUMENT, maybe there's a way to encode which argument is bad in the error code? That wouldn't be any better. We could not support on-the-fly packaging of arguments for FFI calls by relying on just the error code. Without on-the-fly packaging, the FFI call could likely be unsafe (e.g. everybody using 'int' instead of the enum type as proposed in the library) or awkward to program (e.g., Alien callbacks require Smalltalk blocks to be warpped into Callback objects). Best, Marcel
|
On Mon, Jun 22, 2020 at 9:44 AM Marcel Taeumel <[hidden email]> wrote: > > > Hi Fabio, > > > I don't like the idea of adding a plugin-specific mechanism like this to the VM. > > Why is that? The implementation strategy would be very clear: like #doesNotUnderstand:. It's just a new entry on the special objects array. There are very few mechanisms like this (aboutToReturn, cannotInterpret, mustBeBoolean, ...), none of them are plugin-specific. I'd also prefer to keep the number of special objects as small as possible, the FFIPlugin already reserves quite many of them. > > > There already is BAD_ARGUMENT, maybe there's a way to encode which argument is bad in the error code? > > That wouldn't be any better. We could not support on-the-fly packaging of arguments for FFI calls by relying on just the error code. Without on-the-fly packaging, the FFI call could likely be unsafe (e.g. everybody using 'int' instead of the enum type as proposed in the library) or awkward to program (e.g., Alien callbacks require Smalltalk blocks to be warpped into Callback objects). More importantly, I don't think this type of automatic conversion should be part of the FFIPlugin, I'd much rather see it being built on top of the existing infrastructure. Why can't there be a mechanism that looks at the FFI call in question and converts arguments before executing it? Fabio > > Best, > Marcel > > Am 20.06.2020 22:05:29 schrieb Fabio Niephaus <[hidden email]>: > > Hi Marcel: > > On Fri, 19 Jun 2020 at 1:15 pm, Marcel Taeumel > wrote: > > > > > Hi all! > > > > We have #doesNotUnderstand:, which is sent to the receiver when a message > > cannot be understood. Default reaction in Object is to raise > > MessageNotUnderstood exception. > > > > What if we could have a similar mechanism for FFI calls: > > #doesNotCoerce:for:. The receiver would be the one that made that call, > > should be an instance of ExternalLibrary, but could be any object. The > > arguments would be a pair of (argObject, argType) and the message (like the > > argument for doesNotUnderstand:) that represents the FFI call. > > > > I don't like the idea of adding a plugin-specific mechanism like this to > the VM. I know it's not as convenient, but maybe something similar can be > achieved with error codes in fallback code? There already is BAD_ARGUMENT, > maybe there's a way to encode which argument is bad in the error code? > > Fabio > > > > The pair of (argObject, argType) could be expressed as FFICallArgument: > > > > FFICallArgument > > argObject ... |
Le lun. 22 juin 2020 à 12:47, Fabio Niephaus <[hidden email]> a écrit :
Exactly, that's how UFFI works. Easier to handle error, easier to handle automatic coercion or other application specific hook. While implementing HDF5, I've patched DLLCC in VW too: the key is to use double dispatching on parameter type specification and actual argument class, instead of large sequences of if (like we find in our plugin). This way, I can marshall my application specific data at will. > |
Free forum by Nabble | Edit this page |