Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit 1f564da

Browse files
committed
[[ Bug 21387 ]] Provide means to create function ptr with abi
This patch adds a new low-level method `MCHandlerGetFunctionPtrWithAbi` which generates a function ptr for a given handler ref with a specific callling convention. This method is intended to be used by LCB modules which need to create callbacks to pass to foreign handlers on 32-bit Win32 and thus might require the non-default (cdecl) calling convention. On platforms other than 32-bit Win32, then method does the same as `MCHandlerGetFunctionPtr`. A new global (libfoundation) define has been added `__HAS_MULTIPLE_ABIS__` which is defined only for 32-bit Win32. This define is used to control the addition of an `other_closures` member to the internal `__MCHandler` value struct. This member is used to store a linked-list of closures (and function pointers) made for a given `MCHandlerRef` instance. The closure (and function pointer) for the default ABI, regardless of platform, is still stored within the `__MCHandler` value struct so only those for non- default ABIs are stored in the linked list.
1 parent 54b6627 commit 1f564da

File tree

3 files changed

+176
-34
lines changed

3 files changed

+176
-34
lines changed

libfoundation/include/foundation.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
110110
// __HAS_CORE_FOUNDATION__ will be defined if the platform has the CF libraries.
111111
#undef __HAS_CORE_FOUNDATION__
112112

113+
// __HAS_MULTIPLE_ABIS__ will be defined if the platform has more than one
114+
// function ABI
115+
#undef __HAS_MULTIPLE_ABIS__
116+
113117
////////////////////////////////////////////////////////////////////////////////
114118
//
115119
// CONFIGURE DEFINITIONS FOR WINDOWS
@@ -130,6 +134,7 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
130134
#define __i386__ 1
131135
#define __LP32__ 1
132136
#define __SMALL__ 1
137+
#define __HAS_MULTIPLE_ABIS__ 1
133138
#elif defined(_M_X64)
134139
#define __64_BIT__ 1
135140
#define __LITTLE_ENDIAN__ 1
@@ -3133,9 +3138,27 @@ MC_DLLEXPORT bool MCHandlerExternalInvoke(MCHandlerRef handler, MCValueRef *argu
31333138
* ExternalInvoke if the current thread is unknown. */
31343139
MC_DLLEXPORT /*copy*/ MCErrorRef MCHandlerTryToInvokeWithList(MCHandlerRef handler, MCProperListRef& x_arguments, MCValueRef& r_value);
31353140
MC_DLLEXPORT /*copy*/ MCErrorRef MCHandlerTryToExternalInvokeWithList(MCHandlerRef handler, MCProperListRef& x_arguments, MCValueRef& r_value);
3136-
3141+
3142+
/* Create a C function ptr which calls the given handler ref. The function ptr is
3143+
* stored in the handler ref and is freed when it is. On 32-bit Win32, the calling
3144+
* convention used is __cdecl. */
31373145
MC_DLLEXPORT bool MCHandlerGetFunctionPtr(MCHandlerRef handler, void*& r_func_ptr);
31383146

3147+
/* Create a C function ptr with a specific ABI. The function ptr is stored in the
3148+
* handler ref and is freed when it is. The ABI argument only has an effect on 32-bit
3149+
* Win32, on all other platforms it is ignored. */
3150+
enum MCHandlerAbiKind
3151+
{
3152+
kMCHandlerAbiDefault,
3153+
kMCHandlerAbiStdCall,
3154+
kMCHandlerAbiThisCall,
3155+
kMCHandlerAbiFastCall,
3156+
kMCHandlerAbiCDecl,
3157+
kMCHandlerAbiPascal,
3158+
kMCHandlerAbiRegister
3159+
};
3160+
MC_DLLEXPORT bool MCHandlerGetFunctionPtrWithAbi(MCHandlerRef handler, MCHandlerAbiKind p_convention, void*& r_func_ptr);
3161+
31393162
////////////////////////////////////////////////////////////////////////////////
31403163
//
31413164
// ERROR DEFINITIONS

libfoundation/src/foundation-handler.cpp

Lines changed: 137 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,13 @@ bool MCHandlerCreate(MCTypeInfoRef p_typeinfo, const MCHandlerCallbacks *p_callb
4141

4242
MCMemoryCopy(MCHandlerGetContext(self), p_context, p_callbacks -> size);
4343

44-
self -> typeinfo = MCValueRetain(p_typeinfo);
45-
self -> function_ptr = nil;
46-
self -> callbacks = p_callbacks;
44+
self->typeinfo = MCValueRetain(p_typeinfo);
45+
self->closure = nil;
46+
self->function_ptr = nil;
47+
#ifdef __HAS_MULTIPLE_ABIS__
48+
self->other_closures = nil;
49+
#endif
50+
self->callbacks = p_callbacks;
4751

4852
r_handler = self;
4953

@@ -336,40 +340,129 @@ static bool ensure_block_is_executable(void *p_block, size_t p_size)
336340
#endif
337341

338342
MC_DLLEXPORT_DEF
339-
bool MCHandlerGetFunctionPtr(MCHandlerRef self, void*& r_function_ptr)
343+
bool MCHandlerGetFunctionPtrWithAbi(MCHandlerRef self, MCHandlerAbiKind p_abi_kind, void*& r_function_ptr)
340344
{
341345
__MCAssertIsHandler(self);
342346

343-
if (self -> function_ptr != nil)
344-
{
345-
r_function_ptr = self -> function_ptr;
346-
return true;
347-
}
348-
349-
ffi_cif *t_cif;
350-
if (!MCHandlerTypeInfoGetLayoutType(self -> typeinfo, (int)FFI_DEFAULT_ABI, (void*&)t_cif))
351-
return false;
352-
353-
self -> closure = ffi_closure_alloc(sizeof(ffi_closure), &self -> function_ptr);
354-
if (self -> closure == nil)
355-
return MCErrorThrowOutOfMemory();
356-
357-
if (ffi_prep_closure_loc((ffi_closure *)self -> closure, t_cif, __exec_closure, self, self -> function_ptr) != FFI_OK)
358-
{
359-
ffi_closure_free(self -> closure);
360-
self -> closure = nil;
361-
return MCErrorThrowGeneric(MCSTR("unexpected libffi failure"));
362-
}
347+
ffi_abi t_abi;
348+
#ifdef __HAS_MULTIPLE_ABIS__
349+
switch (p_abi_kind)
350+
{
351+
case kMCHandlerAbiDefault:
352+
t_abi = FFI_DEFAULT_ABI;
353+
break;
354+
case kMCHandlerAbiStdCall:
355+
t_abi = FFI_STDCALL;
356+
break;
357+
case kMCHandlerAbiThisCall:
358+
t_abi = FFI_THISCALL;
359+
break;
360+
case kMCHandlerAbiFastCall:
361+
t_abi = FFI_FASTCALL;
362+
break;
363+
case kMCHandlerAbiCDecl:
364+
t_abi = FFI_MS_CDECL;
365+
break;
366+
case kMCHandlerAbiPascal:
367+
t_abi = FFI_PASCAL;
368+
break;
369+
case kMCHandlerAbiRegister:
370+
t_abi = FFI_REGISTER;
371+
break;
372+
default:
373+
return MCErrorThrowGeneric(MCSTR("invalid abi specified"));
374+
};
375+
#else
376+
t_abi = FFI_DEFAULT_ABI;
377+
#endif
363378

364-
/* Change the protection flags of the page range to read/write/exec. */
365-
if (!ensure_block_is_executable(self->closure,
366-
sizeof(ffi_closure)))
367-
{
368-
return MCErrorThrowGeneric(MCSTR("unable to generate executable closure trampoline"));
369-
}
370-
371-
r_function_ptr = self -> function_ptr;
372-
return true;
379+
/* If the ABI is default, and there is a function ptr in the main slot, then
380+
* return it. */
381+
if (t_abi == FFI_DEFAULT_ABI &&
382+
self->function_ptr != nil)
383+
{
384+
r_function_ptr = self->function_ptr;
385+
return true;
386+
}
387+
388+
#ifdef __HAS_MULTIPLE_ABIS__
389+
/* If there are auxiliary closures then search for one with a matching ABI
390+
* and return it, if found. */
391+
if (self->other_closures != nil)
392+
{
393+
for (__MCHandlerClosureWithAbi *t_closure_with_abi = self->other_closures;
394+
t_closure_with_abi != nil;
395+
t_closure_with_abi = t_closure_with_abi->next)
396+
{
397+
if (t_closure_with_abi->abi == t_abi)
398+
{
399+
r_function_ptr = t_closure_with_abi->function_ptr;
400+
return true;
401+
}
402+
}
403+
}
404+
#endif
405+
406+
ffi_cif *t_cif;
407+
if (!MCHandlerTypeInfoGetLayoutType(self->typeinfo, t_abi, (void*&)t_cif))
408+
return false;
409+
410+
void *t_closure, *t_function_ptr;
411+
t_closure = ffi_closure_alloc(sizeof(ffi_closure), &t_function_ptr);
412+
if (t_closure == nil)
413+
return MCErrorThrowOutOfMemory();
414+
415+
if (ffi_prep_closure_loc((ffi_closure *)t_closure, t_cif, __exec_closure, self, t_function_ptr) != FFI_OK)
416+
{
417+
ffi_closure_free(t_closure);
418+
return MCErrorThrowGeneric(MCSTR("unexpected libffi failure"));
419+
}
420+
421+
/* Change the protection flags of the page range to read/write/exec. */
422+
if (!ensure_block_is_executable(t_closure,
423+
sizeof(ffi_closure)))
424+
{
425+
ffi_closure_free(t_closure);
426+
return MCErrorThrowGeneric(MCSTR("unable to generate executable closure trampoline"));
427+
}
428+
429+
/* We now have a closure and function ptr, if it is of default ABI we store
430+
* it in the value struct. */
431+
if (t_abi == FFI_DEFAULT_ABI)
432+
{
433+
self->closure = t_closure;
434+
self->function_ptr = t_function_ptr;
435+
}
436+
437+
#ifdef __HAS_MULTIPLE_ABIS__
438+
/* If the ABI is non-default then we must link it into the closures list. */
439+
if (t_abi != FFI_DEFAULT_ABI)
440+
{
441+
__MCHandlerClosureWithAbi *t_closure_with_abi;
442+
if (!MCMemoryNew(t_closure_with_abi))
443+
{
444+
ffi_closure_free(t_closure);
445+
return MCErrorThrowOutOfMemory();
446+
}
447+
448+
t_closure_with_abi->next = self->other_closures;
449+
t_closure_with_abi->abi = t_abi;
450+
t_closure_with_abi->closure = t_closure;
451+
t_closure_with_abi->function_ptr = t_function_ptr;
452+
self->other_closures = t_closure_with_abi;
453+
}
454+
#endif
455+
456+
/* We've now stored the generated closure and function ptr so return the
457+
* requested one. */
458+
r_function_ptr = t_function_ptr;
459+
return true;
460+
}
461+
462+
MC_DLLEXPORT_DEF
463+
bool MCHandlerGetFunctionPtr(MCHandlerRef self, void*& r_function_ptr)
464+
{
465+
return MCHandlerGetFunctionPtrWithAbi(self, kMCHandlerAbiDefault, r_function_ptr);
373466
}
374467

375468
////////////////////////////////////////////////////////////////////////////////
@@ -378,6 +471,17 @@ void __MCHandlerDestroy(__MCHandler *self)
378471
{
379472
if (self -> function_ptr != nil)
380473
ffi_closure_free(self -> closure);
474+
475+
#ifdef __HAS_MULTIPLE_ABIS__
476+
/* Free any closures created with the non-default ABI. */
477+
while (self->other_closures != nil)
478+
{
479+
__MCHandlerClosureWithAbi *t_closure_with_abi = self->other_closures;
480+
self->other_closures = self->other_closures->next;
481+
ffi_closure_free(t_closure_with_abi->closure);
482+
MCMemoryDelete(t_closure_with_abi);
483+
}
484+
#endif
381485
}
382486

383487
hash_t __MCHandlerHash(__MCHandler *self)

libfoundation/src/foundation-private.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,12 +460,27 @@ struct __MCForeignValue: public __MCValue
460460

461461
////////
462462

463+
#ifdef __HAS_MULTIPLE_ABIS__
464+
struct __MCHandlerClosureWithAbi
465+
{
466+
__MCHandlerClosureWithAbi *next;
467+
int abi;
468+
void *closure;
469+
void *function_ptr;
470+
};
471+
#endif
472+
463473
struct __MCHandler: public __MCValue
464474
{
465475
MCTypeInfoRef typeinfo;
466476
const MCHandlerCallbacks *callbacks;
477+
/* We store the closure with default ABI in the value. */
467478
void *closure;
468479
void *function_ptr;
480+
#ifdef __HAS_MULTIPLE_ABIS__
481+
/* All closures with non-default ABIs are stored in a linked list. */
482+
__MCHandlerClosureWithAbi *other_closures;
483+
#endif
469484
char context[1];
470485
};
471486

0 commit comments

Comments
 (0)