- live browsing of Self object memory -

lobby traitsforeignFct

This object provides a higher level interface to foreign 
     functions than that provided by the raw fctProxy objects. It knows 
     about code files and cooperates with them and the linker to recover 
     from dead function proxies. All this is transparent to the client.

CopyDowns: vector

CreatorPath: traits foreignFct

Module: foreign

parent* = traits fctProxy
noOfArgs:IfFail: =
( 
    n > argCoercions size ifTrue: [
        errBlk value: 'can\'t have more args than type coercions'.
    ].
    resend.noOfArgs: n IfFail: errBlk)
reviveIfFail: =
( 
    "The way a foreignFct object recovers from a dead fctProxy is by
     calling the linker to load the code (if necessary), and then look
     up the entry point."

     isLive ifTrue: [^ self].   "Just an optimization."
     codeFile loadIfUnloadedIfFail: [|:e| ^ errBlk value: e].
     codeFile lookupFunction: (entryPointFromName: fctName)
                 ResultProxy: kill
                      IfFail: errBlk)
statePrintString = ( fctName)

calling

call:IfFail: =
( 
    resend.call: arg1 IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.call: (coerce: arg1 To: (argCoercions at: 0))
                 IfFail: errBlk.
        ] False: [
            errBlk value: e. 
        ]
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
call:With:IfFail: =
( 
    resend.call: arg1 With: arg2 IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.call: (coerce: arg1 To: (argCoercions at: 0))
                   With: (coerce: arg2 To: (argCoercions at: 1))
                 IfFail: errBlk.
        ] False: [
            errBlk value: e. 
        ].
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
call:With:With:IfFail: =
( 
    resend.call: arg1 With: arg2 With: arg3 IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.call: (coerce: arg1 To: (argCoercions at: 0))
                   With: (coerce: arg2 To: (argCoercions at: 1))
                   With: (coerce: arg3 To: (argCoercions at: 2))
                 IfFail: errBlk.
        ] False: [
            errBlk value: e. 
        ].
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
call:With:With:With:IfFail: =
( 
    resend.call: arg1 With: arg2 With: arg3 With: arg4 IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.call: (coerce: arg1 To: (argCoercions at: 0))
                   With: (coerce: arg2 To: (argCoercions at: 1))
                   With: (coerce: arg3 To: (argCoercions at: 2))
                   With: (coerce: arg4 To: (argCoercions at: 3))
                 IfFail: errBlk.
        ] False: [
            errBlk value: e. 
        ].
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
call:With:With:With:With:IfFail: =
( 
    resend.call: arg1 With: arg2 With: arg3 With: arg4 With: arg5 
              IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.call: (coerce: arg1 To: (argCoercions at: 0))
                   With: (coerce: arg2 To: (argCoercions at: 1))
                   With: (coerce: arg3 To: (argCoercions at: 2))
                   With: (coerce: arg4 To: (argCoercions at: 3))
                   With: (coerce: arg5 To: (argCoercions at: 4))
                 IfFail: errBlk.
        ] False: [
            errBlk value: e. 
        ].
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
call:With:With:With:With:With:IfFail: =
( 
    resend.call: arg1 With: arg2 With: arg3 With: arg4 With: arg5 
     With: arg6 IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.call: (coerce: arg1 To: (argCoercions at: 0))
                   With: (coerce: arg2 To: (argCoercions at: 1))
                   With: (coerce: arg3 To: (argCoercions at: 2))
                   With: (coerce: arg4 To: (argCoercions at: 3))
                   With: (coerce: arg5 To: (argCoercions at: 4))
                   With: (coerce: arg6 To: (argCoercions at: 5))
                 IfFail: errBlk.
        ] False: [
            errBlk value: e. 
        ].
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
call:With:With:With:With:With:With:IfFail: =
( 
    resend.call: arg1 With: arg2 With: arg3 With: arg4 With: arg5
     With: arg6 With: arg7 IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.call: (coerce: arg1 To: (argCoercions at: 0))
                   With: (coerce: arg2 To: (argCoercions at: 1))
                   With: (coerce: arg3 To: (argCoercions at: 2))
                   With: (coerce: arg4 To: (argCoercions at: 3))
                   With: (coerce: arg5 To: (argCoercions at: 4))
                   With: (coerce: arg6 To: (argCoercions at: 5))
                   With: (coerce: arg7 To: (argCoercions at: 6))
                 IfFail: errBlk.
        ] False: [
            errBlk value: e. 
        ].
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
call:With:With:With:With:With:With:With:IfFail: =
( 
    resend.call: arg1 With: arg2 With: arg3 With: arg4 With: arg5 
     With: arg6 With: arg7 With: arg8 IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.call: (coerce: arg1 To: (argCoercions at: 0))
                   With: (coerce: arg2 To: (argCoercions at: 1))
                   With: (coerce: arg3 To: (argCoercions at: 2))
                   With: (coerce: arg4 To: (argCoercions at: 3))
                   With: (coerce: arg5 To: (argCoercions at: 4))
                   With: (coerce: arg6 To: (argCoercions at: 5))
                   With: (coerce: arg7 To: (argCoercions at: 6))
                   With: (coerce: arg8 To: (argCoercions at: 7))
                 IfFail: errBlk.
        ] False: [
            errBlk value: e. 
        ].
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
call:With:With:With:With:With:With:With:With:IfFail: =
( 
    resend.call: arg1 With: arg2 With: arg3 With: arg4 With: arg5 
     With: arg6 With: arg7 With: arg8 With: arg9 IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.call: (coerce: arg1 To: (argCoercions at: 0))
                   With: (coerce: arg2 To: (argCoercions at: 1))
                   With: (coerce: arg3 To: (argCoercions at: 2))
                   With: (coerce: arg4 To: (argCoercions at: 3))
                   With: (coerce: arg5 To: (argCoercions at: 4))
                   With: (coerce: arg6 To: (argCoercions at: 5))
                   With: (coerce: arg7 To: (argCoercions at: 6))
                   With: (coerce: arg8 To: (argCoercions at: 7))
                   With: (coerce: arg9 To: (argCoercions at: 8))
                 IfFail: errBlk.
        ] False: [
            errBlk value: e. 
        ].
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
call:With:With:With:With:With:With:With:With:With:IfFail: =
( 
    resend.call: arg1 With: arg2 With: arg3 With: arg4 With: arg5 
     With: arg6 With: arg7 With: arg8 With: arg9 With: arg10
              IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.call: (coerce: arg1 To: (argCoercions at: 0))
                   With: (coerce: arg2 To: (argCoercions at: 1))
                   With: (coerce: arg3 To: (argCoercions at: 2))
                   With: (coerce: arg4 To: (argCoercions at: 3))
                   With: (coerce: arg5 To: (argCoercions at: 4))
                   With: (coerce: arg6 To: (argCoercions at: 5))
                   With: (coerce: arg7 To: (argCoercions at: 6))
                   With: (coerce: arg8 To: (argCoercions at: 7))
                   With: (coerce: arg9 To: (argCoercions at: 8))
                   With: (coerce: arg10 To: (argCoercions at: 9))
                 IfFail: errBlk.
        ] False: [
            errBlk value: e. 
        ].
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
callAndConvertIfFail: =
( 
    resend.callAndConvertIfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.callAndConvertIfFail: errBlk.
        ]
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
callAndConvertWith:And:IfFail: =
( 
    resend.callAndConvertWith: a1 And: x1 IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.callAndConvertWith: a1 And: x1 
                               IfFail: errBlk
        ]
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
callAndConvertWith:And:With:And:IfFail: =
( 
    resend.callAndConvertWith: a1 And: x1 With: a2 And: x2
                 IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.callAndConvertWith: a1 And: x1 
                                 With: a2 And: x2 
                               IfFail: errBlk
        ]
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
callAndConvertWith:And:With:And:With:And:IfFail: =
( 
    resend.callAndConvertWith: a1 And: x1 With: a2 And: x2 
                   With: a3 And: x3
                 IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.callAndConvertWith: a1 And: x1 
                                 With: a2 And: x2 
                                 With: a3 And: x3 
                               IfFail: errBlk
        ]
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
callAndConvertWith:And:With:And:With:And:With:And:IfFail: =
( 
    resend.callAndConvertWith: a1 And: x1 With: a2 And: x2 
                   With: a3 And: x3 With: a4 And: x4
                 IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.callAndConvertWith: a1 And: x1 
                                 With: a2 And: x2 
                                 With: a3 And: x3 
                                 With: a4 And: x4 
                               IfFail: errBlk
        ]
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
callAndConvertWith:And:With:And:With:And:With:And:With:And:IfFail: =
( 
    resend.callAndConvertWith: a1 And: x1 With: a2 And: x2 
                   With: a3 And: x3 With: a4 And: x4 
                   With: a5 And: x5
                 IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.callAndConvertWith: a1 And: x1 
                                 With: a2 And: x2 
                                 With: a3 And: x3 
                                 With: a4 And: x4 
                                 With: a5 And: x5 
                               IfFail: errBlk
        ]
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
callAndConvertWith:And:With:And:With:And:With:And:With:And:With:And:IfFail: =
( 
    resend.callAndConvertWith: a1 And: x1 With: a2 And: x2 
                   With: a3 And: x3 With: a4 And: x4 
                   With: a5 And: x5 With: a6 And: x6
                 IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.callAndConvertWith: a1 And: x1 
                                 With: a2 And: x2 
                                 With: a3 And: x3 
                                 With: a4 And: x4 
                                 With: a5 And: x5 
                                 With: a6 And: x6 
                               IfFail: errBlk
        ]
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
callAndConvertWith:And:With:And:With:And:With:And:With:And:With:And:With:And:IfFail: =
( 
    resend.callAndConvertWith: a1 And: x1 With: a2 And: x2 
                   With: a3 And: x3 With: a4 And: x4 
                   With: a5 And: x5 With: a6 And: x6
                   With: a7 And: x7
                 IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.callAndConvertWith: a1 And: x1 
                                 With: a2 And: x2 
                                 With: a3 And: x3 
                                 With: a4 And: x4 
                                 With: a5 And: x5 
                                 With: a6 And: x6 
                                 With: a7 And: x7 
                               IfFail: errBlk
        ]
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
callAndConvertWith:And:With:And:With:And:With:And:With:And:With:And:With:And:With:And:IfFail: =
( 
    resend.callAndConvertWith: a1 And: x1 With: a2 And: x2 
                   With: a3 And: x3 With: a4 And: x4 
                   With: a5 And: x5 With: a6 And: x6
                   With: a7 And: x7 With: a8 And: x8
                 IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.callAndConvertWith: a1 And: x1 
                                 With: a2 And: x2 
                                 With: a3 And: x3 
                                 With: a4 And: x4 
                                 With: a5 And: x5 
                                 With: a6 And: x6 
                                 With: a7 And: x7 
                                 With: a8 And: x8 
                               IfFail: errBlk
        ]
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
callAndConvertWith:And:With:And:With:And:With:And:With:And:With:And:With:And:With:And:With:And:IfFail: =
( 
    resend.callAndConvertWith: a1 And: x1 With: a2 And: x2 
                   With: a3 And: x3 With: a4 And: x4 
                   With: a5 And: x5 With: a6 And: x6
                   With: a7 And: x7 With: a8 And: x8 
                   With: a9 And: x9
                 IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.callAndConvertWith: a1 And: x1 
                                 With: a2 And: x2 
                                 With: a3 And: x3 
                                 With: a4 And: x4 
                                 With: a5 And: x5 
                                 With: a6 And: x6 
                                 With: a7 And: x7 
                                 With: a8 And: x8 
                                 With: a9 And: x9 
                               IfFail: errBlk
        ]
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
callAndConvertWith:And:With:And:With:And:With:And:With:And:With:And:With:And:With:And:With:And:With:And:IfFail: =
( 
    resend.callAndConvertWith: a1 And: x1 With: a2 And: x2 
                   With: a3 And: x3 With: a4 And: x4 
                   With: a5 And: x5 With: a6 And: x6
                   With: a7 And: x7 With: a8 And: x8 
                   With: a9 And: x9 With: a10 And: x10
                 IfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.callAndConvertWith: a1 And: x1 
                                 With: a2 And: x2 
                                 With: a3 And: x3 
                                 With: a4 And: x4 
                                 With: a5 And: x5 
                                 With: a6 And: x6 
                                 With: a7 And: x7 
                                 With: a8 And: x8 
                                 With: a9 And: x9 
                                 With: a10 And: x10 
                               IfFail: errBlk
        ]
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
callIfFail: =
( 
    resend.callIfFail: [|:e|
        ('badTypeError'   isPrefixOf: e) ||
        ['deadProxyError' isPrefixOf: e] ifTrue: [
            reviveIfFail: [|:e| ^ errBlk value: e].
            resend.callIfFail: errBlk.
        ] False: [
            errBlk value: e. 
        ].
    ])
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.
coerce:To: =
( 
    'i' = type ifTrue: [^ arg asSmallInteger].
    'f' = type ifTrue: [^ arg asFloat].
    'b' = type ifTrue: [^ arg asVMByteVector].
    'p' = type ifTrue: [^ arg revive].
    ' ' = type ifTrue: [^ arg].
    error: 'foreignFct: unknown argument coercion: ', type)
The "call:With:..." and "callAndConvert:With:And:..." in foreignFct objects gives transparent coercion and retry if the receiver or an argument is a dead proxy or has the wrong type.

copying

copyName: =
( 
        copyName: n 
    ArgCoercions: '            '
      ResultType: 'unknown' 
          IfFail: raiseError)
This is the only copying method that does not require a type signature. Supplying a type signature is strongly encouraged. Use a space for those args you don't want coerced.
copyName:ArgCoercions:ResultType:Path: = ( copyName: n ArgCoercions: t ResultType: r Path: p IfFail: raiseError)
copyName:ArgCoercions:ResultType:Path:IfFail: =
( 
    copy initName: n 
     ArgCoercions: t 
       ResultType: r
         CodeFile: (foreignCodeDB at: p 
                              IfFail: [|:e| ^ errBlk value: e])
         IfFail: errBlk)
initName:ArgCoercions:ResultType:CodeFile:IfFail: =
( 
    fctName:      n.
    argCoercions: t.
    resultType:   r.
    codeFile:     cf.
    reviveIfFail: errBlk. "To get early err msg if things fail.")

filing out

isImmutableForFilingOut = true
storeStringIfFail: =
( 
    prototypeName, 
    ' copyName: ',      (fctName printStringSize: maxSmallInt),
    ' ArgCoercions: ',  (argCoercions printString),
    ' ResultType: ',    (resultType printString),
    ' Path: ',          (codeFile path printStringSize: maxSmallInt))
storeStringNeeds = ( prototypeName sendTo: lobby)
prototypeName = 'foreignFct'

naming

currentOsVariant* = traits foreignFct osVariants linuxhooked up to an os variant in postFileIn
initializeOsVariant = ( currentOsVariant: host osVariantName sendTo: osVariants)
osVariants = traits foreignFct osVariants
currentOsVariant: =
( | tfMir |
    tfMir: (reflect: traits foreignFct).
    "need to use define cause modules may not be working yet"
    tfMir frozenDefine: (tfMir copyAt: 'currentOsVariant'
                          PutContents: (reflect: variant)).
    self)
use a constant slot for speed
entryName:Language:IfFail: =
( 
    "This method maps the source name of a foreign routine to the
     corresponding entry point. Presently this method just prepends 
     an '_' to the name of the function. This is valid for fcts that 
     are glued in, since all glue uses C linking conventions. This may 
     change in the future, in which case the language may be involved in
     the mapping."
    entryPointFromName: name)