Skip to content

Commit 78cfcd3

Browse files
committed
[[ ForeignCallbacks ]] Implement basic version of C callable LCB closures.
Code to compute the FFI layout type for handler types has been moved into MCHandlerTypeInfo. Additionally, an MCHandlerGetFunctionPtr API has been added which attempts to create and then return a C function pointer which will execute the HandlerRef. In order to ensure that the Handler value and its closure are not released it is important to keep the handler value in a variable for the lifetime the function pointer is required.
1 parent bb41e4a commit 78cfcd3

6 files changed

Lines changed: 260 additions & 71 deletions

File tree

libfoundation/include/foundation.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1637,7 +1637,10 @@ MC_DLLEXPORT MCHandlerTypeFieldMode MCHandlerTypeInfoGetParameterMode(MCTypeInfo
16371637

16381638
// Return the type of the index'th parameter.
16391639
MC_DLLEXPORT MCTypeInfoRef MCHandlerTypeInfoGetParameterType(MCTypeInfoRef typeinfo, uindex_t index);
1640-
1640+
1641+
// Returns the 'native' layout ptr (an ffi_cif) for the handler type
1642+
MC_DLLEXPORT bool MCHandlerTypeInfoGetLayoutType(MCTypeInfoRef typeinfo, int abi, void*& r_cif);
1643+
16411644
//////////
16421645

16431646
MC_DLLEXPORT bool MCErrorTypeInfoCreate(MCNameRef domain, MCStringRef message, MCTypeInfoRef& r_typeinfo);
@@ -2605,6 +2608,8 @@ MC_DLLEXPORT const MCHandlerCallbacks *MCHandlerGetCallbacks(MCHandlerRef handle
26052608

26062609
MC_DLLEXPORT bool MCHandlerInvoke(MCHandlerRef handler, MCValueRef *arguments, uindex_t argument_count, MCValueRef& r_value);
26072610
MC_DLLEXPORT /*copy*/ MCErrorRef MCHandlerTryToInvokeWithList(MCHandlerRef handler, MCProperListRef& x_arguments, MCValueRef& r_value);
2611+
2612+
MC_DLLEXPORT bool MCHandlerGetFunctionPtr(MCHandlerRef handler, void*& r_func_ptr);
26082613

26092614
////////////////////////////////////////////////////////////////////////////////
26102615
//

libfoundation/src/foundation-handler.cpp

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include <foundation.h>
1818
#include <foundation-auto.h>
1919

20+
#include <ffi.h>
21+
2022
#include "foundation-private.h"
2123

2224
////////////////////////////////////////////////////////////////////////////////
@@ -33,6 +35,7 @@ bool MCHandlerCreate(MCTypeInfoRef p_typeinfo, const MCHandlerCallbacks *p_callb
3335
MCMemoryCopy(MCHandlerGetContext(self), p_context, p_callbacks -> size);
3436

3537
self -> typeinfo = MCValueRetain(p_typeinfo);
38+
self -> function_ptr = nil;
3639
self -> callbacks = p_callbacks;
3740

3841
r_handler = self;
@@ -90,10 +93,141 @@ const MCHandlerCallbacks *MCHandlerGetCallbacks(MCHandlerRef self)
9093

9194
////////////////////////////////////////////////////////////////////////////////
9295

96+
static void __exec_closure(ffi_cif *cif, void *ret, void **args, void *user_data)
97+
{
98+
MCHandlerRef t_handler;
99+
t_handler = (MCHandlerRef)user_data;
100+
101+
MCTypeInfoRef t_signature;
102+
t_signature = t_handler -> typeinfo;
103+
104+
uindex_t t_arity;
105+
t_arity = MCHandlerTypeInfoGetParameterCount(t_signature);
106+
107+
MCValueRef t_value_result;
108+
MCValueRef t_value_args[16];
109+
uindex_t t_arg_index;
110+
t_arg_index = 0;
111+
t_value_result = nil;
112+
for(t_arg_index = 0; t_arg_index < t_arity; t_arg_index++)
113+
{
114+
MCHandlerTypeFieldMode t_mode;
115+
t_mode = MCHandlerTypeInfoGetParameterMode(t_signature, t_arg_index);
116+
117+
MCTypeInfoRef t_type;
118+
t_type = MCHandlerTypeInfoGetParameterType(t_signature, t_arg_index);
119+
120+
if (t_mode != kMCHandlerTypeFieldModeIn)
121+
abort();
122+
123+
MCResolvedTypeInfo t_resolved_type;
124+
if (!MCTypeInfoResolve(t_type, t_resolved_type))
125+
{
126+
MCErrorThrowGeneric(nil);
127+
goto error_exit;
128+
}
129+
130+
if (MCTypeInfoIsForeign(t_resolved_type . type))
131+
{
132+
const MCForeignTypeDescriptor *t_descriptor;
133+
t_descriptor = MCForeignTypeInfoGetDescriptor(t_resolved_type . type);
134+
if (t_descriptor -> defined != nil &&
135+
!t_descriptor -> defined(args[t_arg_index]))
136+
t_value_args[t_arg_index] = MCValueRetain(kMCNull);
137+
else
138+
{
139+
if (t_descriptor -> bridgetype != kMCNullTypeInfo)
140+
{
141+
if (!t_descriptor -> doimport(args[t_arg_index], false, t_value_args[t_arg_index]))
142+
goto error_exit;
143+
}
144+
else
145+
{
146+
if (!MCForeignValueCreateAndRelease(t_resolved_type . named_type, args[t_arg_index], (MCForeignValueRef&)t_value_args[t_arg_index]))
147+
goto error_exit;
148+
}
149+
}
150+
}
151+
else
152+
{
153+
t_value_args[t_arg_index] = MCValueRetain((MCValueRef)args[t_arg_index]);
154+
}
155+
}
156+
157+
if (!MCHandlerInvoke(t_handler, t_value_args, t_arity, t_value_result))
158+
goto error_exit;
159+
160+
MCTypeInfoRef t_return_type;
161+
t_return_type = MCHandlerTypeInfoGetReturnType(t_signature);
162+
163+
MCResolvedTypeInfo t_resolved_return_type;
164+
t_return_type = MCHandlerTypeInfoGetReturnType(t_signature);
165+
if (!MCTypeInfoResolve(t_return_type, t_resolved_return_type))
166+
{
167+
MCErrorThrowGeneric(nil);
168+
goto error_exit;
169+
}
170+
171+
if (t_resolved_return_type . named_type != kMCNullTypeInfo)
172+
{
173+
if (MCTypeInfoIsForeign(t_resolved_return_type . type))
174+
{
175+
const MCForeignTypeDescriptor *t_descriptor;
176+
t_descriptor = MCForeignTypeInfoGetDescriptor(t_resolved_return_type . type);
177+
if (!t_descriptor -> doexport(t_value_result, true, ret))
178+
goto error_exit;
179+
}
180+
else
181+
{
182+
*(MCValueRef *)ret = t_value_result;
183+
t_value_result = nil;
184+
}
185+
}
186+
187+
return;
188+
189+
error_exit:
190+
if (t_value_result != nil)
191+
MCValueRelease(t_value_result);
192+
for(uindex_t i = 0; i < t_arg_index; i++)
193+
MCValueRelease(t_value_args[i]);
194+
}
195+
196+
bool MCHandlerGetFunctionPtr(MCHandlerRef self, void*& r_function_ptr)
197+
{
198+
if (self -> function_ptr != nil)
199+
{
200+
r_function_ptr = self -> function_ptr;
201+
return true;
202+
}
203+
204+
ffi_cif *t_cif;
205+
if (!MCHandlerTypeInfoGetLayoutType(self -> typeinfo, (int)FFI_DEFAULT_ABI, (void*&)t_cif))
206+
return false;
207+
208+
self -> closure = ffi_closure_alloc(sizeof(ffi_closure), &self -> function_ptr);
209+
if (self -> closure == nil)
210+
return MCErrorThrowOutOfMemory();
211+
212+
if (ffi_prep_closure_loc((ffi_closure *)self -> closure, t_cif, __exec_closure, self, self -> function_ptr) != FFI_OK)
213+
{
214+
ffi_closure_free(self -> closure);
215+
self -> closure = nil;
216+
return MCErrorThrowGeneric(nil);
217+
}
218+
219+
r_function_ptr = self -> function_ptr;
220+
return true;
221+
}
222+
223+
////////////////////////////////////////////////////////////////////////////////
224+
93225
void __MCHandlerDestroy(__MCHandler *self)
94226
{
95227
if (self -> callbacks -> release != nil)
96228
self -> callbacks -> release(MCHandlerGetContext(self));
229+
if (self -> function_ptr != nil)
230+
ffi_closure_free(self -> function_ptr);
97231
}
98232

99233
hash_t __MCHandlerHash(__MCHandler *self)

libfoundation/src/foundation-private.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ enum
6565
kMCTypeInfoTypeIsForeign = 251,
6666
};
6767

68+
struct MCHandlerTypeLayout
69+
{
70+
MCHandlerTypeLayout *next;
71+
int abi;
72+
char cif[1];
73+
};
74+
6875
struct __MCTypeInfo: public __MCValue
6976
{
7077
union
@@ -89,6 +96,8 @@ struct __MCTypeInfo: public __MCValue
8996
MCHandlerTypeFieldInfo *fields;
9097
uindex_t field_count;
9198
MCTypeInfoRef return_type;
99+
void **layout_args;
100+
MCHandlerTypeLayout *layouts;
92101
} handler;
93102
struct
94103
{
@@ -421,6 +430,8 @@ struct __MCHandler: public __MCValue
421430
{
422431
MCTypeInfoRef typeinfo;
423432
const MCHandlerCallbacks *callbacks;
433+
void *closure;
434+
void *function_ptr;
424435
char context[1];
425436
};
426437

libfoundation/src/foundation-typeinfo.cpp

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,9 @@ bool MCHandlerTypeInfoCreate(const MCHandlerTypeFieldInfo *p_fields, index_t p_f
721721

722722
self -> handler . return_type = MCValueRetain(p_return_type);
723723

724+
self -> handler . layout_args= nil;
725+
self -> handler . layouts = nil;
726+
724727
if (MCValueInterAndRelease(self, r_typeinfo))
725728
return true;
726729

@@ -771,6 +774,103 @@ MCTypeInfoRef MCHandlerTypeInfoGetParameterType(MCTypeInfoRef unresolved_self, u
771774
return self -> handler . fields[p_index] . type;
772775
}
773776

777+
bool MCHandlerTypeInfoGetLayoutType(MCTypeInfoRef unresolved_self, int p_abi, void*& r_cif)
778+
{
779+
MCTypeInfoRef self;
780+
self = __MCTypeInfoResolve(unresolved_self);
781+
782+
MCAssert((self -> flags & kMCTypeInfoTypeCodeMask) == kMCValueTypeCodeHandler);
783+
784+
// If a layout for the given ABI already exists, then return it.
785+
for(MCHandlerTypeLayout *t_layout = self -> handler . layouts; t_layout != nil; t_layout = t_layout -> next)
786+
if (t_layout -> abi == p_abi)
787+
{
788+
r_cif = &t_layout -> cif;
789+
return true;
790+
}
791+
792+
// If we haven't computed the layout args yet, do so.
793+
if (self -> handler . layout_args == nil)
794+
{
795+
MCTypeInfoRef t_return_type;
796+
t_return_type = self -> handler . return_type;
797+
798+
MCResolvedTypeInfo t_resolved_return_type;
799+
if (!MCTypeInfoResolve(t_return_type, t_resolved_return_type))
800+
return MCErrorThrowGeneric(nil);
801+
802+
ffi_type *t_ffi_return_type;
803+
if (t_return_type != kMCNullTypeInfo)
804+
{
805+
if (MCTypeInfoIsForeign(t_resolved_return_type . type))
806+
t_ffi_return_type = (ffi_type *)MCForeignTypeInfoGetLayoutType(t_resolved_return_type . type);
807+
else
808+
t_ffi_return_type = &ffi_type_pointer;
809+
}
810+
else
811+
t_ffi_return_type = &ffi_type_void;
812+
813+
uindex_t t_arity;
814+
t_arity = self -> handler . field_count;
815+
816+
ffi_type **t_ffi_arg_types;
817+
if (!MCMemoryNewArray(t_arity + 1, t_ffi_arg_types))
818+
return false;
819+
820+
t_ffi_arg_types[0] = t_ffi_return_type;
821+
822+
bool t_success;
823+
t_success = true;
824+
for(uindex_t i = 0; t_success && i < t_arity; i++)
825+
{
826+
MCTypeInfoRef t_type;
827+
MCHandlerTypeFieldMode t_mode;
828+
t_type = self -> handler . fields[i] . type;
829+
t_mode = self -> handler . fields[i] . mode;
830+
831+
MCResolvedTypeInfo t_resolved_type;
832+
if (!MCTypeInfoResolve(t_type, t_resolved_type))
833+
{
834+
t_success = false;
835+
break;
836+
}
837+
838+
if (t_mode == kMCHandlerTypeFieldModeIn)
839+
{
840+
if (MCTypeInfoIsForeign(t_resolved_type . type))
841+
t_ffi_arg_types[i + 1] = (ffi_type *)MCForeignTypeInfoGetLayoutType(t_resolved_type . type);
842+
else
843+
t_ffi_arg_types[i + 1] = &ffi_type_pointer;
844+
}
845+
else
846+
t_ffi_arg_types[i + 1] = &ffi_type_pointer;
847+
}
848+
849+
if (!t_success)
850+
return MCErrorThrowGeneric(nil);
851+
852+
self -> handler . layout_args = (void **)t_ffi_arg_types;
853+
}
854+
855+
// Now we must create a new layout object.
856+
MCHandlerTypeLayout *t_layout;
857+
if (!MCMemoryAllocate(sizeof(MCHandlerTypeLayout) + sizeof(ffi_cif), t_layout))
858+
return false;
859+
860+
if (ffi_prep_cif((ffi_cif *)&t_layout -> cif, (ffi_abi)p_abi, self -> handler . field_count, (ffi_type *)self -> handler . layout_args[0], (ffi_type **)(self -> handler . layout_args + 1)) != FFI_OK)
861+
{
862+
MCMemoryDeallocate(t_layout);
863+
return MCErrorThrowGeneric(nil);
864+
}
865+
866+
t_layout -> next = self -> handler . layouts;
867+
self -> handler . layouts = t_layout;
868+
869+
r_cif = &t_layout -> cif;
870+
871+
return true;
872+
}
873+
774874
////////////////////////////////////////////////////////////////////////////////
775875

776876
bool MCErrorTypeInfoCreate(MCNameRef p_domain, MCStringRef p_message, MCTypeInfoRef& r_typeinfo)
@@ -954,6 +1054,14 @@ void __MCTypeInfoDestroy(__MCTypeInfo *self)
9541054
}
9551055
MCValueRelease(self -> handler . return_type);
9561056
MCMemoryDeleteArray(self -> handler . fields);
1057+
MCMemoryDeleteArray(self -> handler . layout_args);
1058+
while(self -> handler . layouts != nil)
1059+
{
1060+
MCHandlerTypeLayout *t_layout;
1061+
t_layout = self -> handler . layouts;
1062+
self -> handler . layouts = self -> handler . layouts -> next;
1063+
MCMemoryDeallocate(t_layout);
1064+
}
9571065
}
9581066
else if (t_ext_typecode == kMCValueTypeCodeError)
9591067
{

0 commit comments

Comments
 (0)