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

Commit 3c9189e

Browse files
committed
[[ Toolchain ]] Generate shims with uniform signature for binding array
This patch changes the type of the ordinal binding array from void* to void (*)(void *rv, void **av). The latter type means that the function can be called directly with the argumenst as prepped for ffi_call, but without using ffi_call. Shims are generated which call the actual function, taking arguments from the av array, and putting the result in rv. In order to support generating the shims, query methods have been added to the ScriptBuilder API which compute the 'primitive' (C) types of things in the handler signature. This allows C code to be generated which calls the function correctly. This approach is needed as it is much better not to use function pointer conversions in Emscripten and this approach eliminates the need. Additionally it gives us an extra point of checking of (C) foreign handlers as at link time, emscripten will emit errors if the signature of a function in one place is inconsistent with another.
1 parent 5af9f69 commit 3c9189e

File tree

7 files changed

+424
-12
lines changed

7 files changed

+424
-12
lines changed

libscript/include/libscript/script.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,54 @@ void MCScriptEmitBytecodeInModuleA(MCScriptModuleBuilderRef builder, uindex_t op
412412

413413
void MCScriptEmitPositionForBytecodeInModule(MCScriptModuleBuilderRef builder, MCNameRef file, uindex_t line);
414414

415+
/* These methods are used to build shims for builtin foreign handlers. They
416+
allow lc-compiles 'emit' module to get the details of a handler type. The
417+
types returned are the raw types of the arguments after taking into account
418+
mode which means we only (currently) need void, pointer, bool and the number
419+
types (both fixed and C). We need to enumerate them all separately, as some
420+
int types change depending on the architecture. */
421+
422+
enum MCScriptForeignPrimitiveType
423+
{
424+
kMCScriptForeignPrimitiveTypeUnknown,
425+
kMCScriptForeignPrimitiveTypeVoid,
426+
kMCScriptForeignPrimitiveTypePointer,
427+
kMCScriptForeignPrimitiveTypeSInt8,
428+
kMCScriptForeignPrimitiveTypeUInt8,
429+
kMCScriptForeignPrimitiveTypeSInt16,
430+
kMCScriptForeignPrimitiveTypeUInt16,
431+
kMCScriptForeignPrimitiveTypeSInt32,
432+
kMCScriptForeignPrimitiveTypeUInt32,
433+
kMCScriptForeignPrimitiveTypeSInt64,
434+
kMCScriptForeignPrimitiveTypeUInt64,
435+
kMCScriptForeignPrimitiveTypeSIntSize,
436+
kMCScriptForeignPrimitiveTypeUIntSize,
437+
kMCScriptForeignPrimitiveTypeSIntPtr,
438+
kMCScriptForeignPrimitiveTypeUIntPtr,
439+
kMCScriptForeignPrimitiveTypeFloat32,
440+
kMCScriptForeignPrimitiveTypeFloat64,
441+
kMCScriptForeignPrimitiveTypeCBool,
442+
kMCScriptForeignPrimitiveTypeCChar,
443+
kMCScriptForeignPrimitiveTypeCSChar,
444+
kMCScriptForeignPrimitiveTypeCUChar,
445+
kMCScriptForeignPrimitiveTypeCSShort,
446+
kMCScriptForeignPrimitiveTypeCUShort,
447+
kMCScriptForeignPrimitiveTypeCSInt,
448+
kMCScriptForeignPrimitiveTypeCUInt,
449+
kMCScriptForeignPrimitiveTypeCSLong,
450+
kMCScriptForeignPrimitiveTypeCULong,
451+
kMCScriptForeignPrimitiveTypeCSLongLong,
452+
kMCScriptForeignPrimitiveTypeCULongLong,
453+
kMCScriptForeignPrimitiveTypeCFloat,
454+
kMCScriptForeignPrimitiveTypeCDouble,
455+
kMCScriptForeignPrimitiveTypeSInt,
456+
kMCScriptForeignPrimitiveTypeUInt,
457+
};
458+
459+
MCScriptForeignPrimitiveType MCScriptQueryForeignHandlerReturnTypeInModule(MCScriptModuleBuilderRef build, uindex_t type_index);
460+
uindex_t MCScriptQueryForeignHandlerParameterCountInModule(MCScriptModuleBuilderRef build, uindex_t type_index);
461+
MCScriptForeignPrimitiveType MCScriptQueryForeignHandlerParameterTypeInModule(MCScriptModuleBuilderRef build, uindex_t type_index, uindex_t arg_index);
462+
415463
////////////////////////////////////////////////////////////////////////////////
416464

417465
#endif

libscript/src/script-builder.cpp

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,3 +1861,205 @@ void MCScriptEmitPositionForBytecodeInModule(MCScriptModuleBuilderRef self, MCNa
18611861
}
18621862

18631863
////////////////////////////////////////////////////////////////////////////////
1864+
1865+
static MCScriptForeignPrimitiveType
1866+
MCScriptMapTypeToForeignPrimitiveTypeInModule(MCScriptModuleBuilderRef self, uindex_t p_type_index, bool p_is_return_type = false)
1867+
{
1868+
MCScriptType *t_type = self->module.types[p_type_index];
1869+
if (t_type->kind == kMCScriptTypeKindDefined)
1870+
{
1871+
auto t_def_type = static_cast<MCScriptDefinedType *>(t_type);
1872+
1873+
MCNameRef t_name = nullptr;
1874+
1875+
MCScriptDefinition *t_def = self->module.definitions[t_def_type->index];
1876+
if (t_def->kind == kMCScriptDefinitionKindType)
1877+
{
1878+
uindex_t t_other_type_index = static_cast<MCScriptTypeDefinition *>(t_def)->type;
1879+
MCScriptType *t_other_type = self->module.types[t_other_type_index];
1880+
if (t_other_type->kind != kMCScriptTypeKindForeign)
1881+
{
1882+
return MCScriptMapTypeToForeignPrimitiveTypeInModule(self, t_other_type_index);
1883+
}
1884+
1885+
t_name = self->module.definition_names[t_def_type->index];
1886+
}
1887+
else if (t_def->kind == kMCScriptDefinitionKindExternal)
1888+
{
1889+
const MCScriptImportedDefinition& t_imp_def = self->module.imported_definitions[static_cast<MCScriptExternalDefinition *>(t_def)->index];
1890+
t_name = t_imp_def.name;
1891+
}
1892+
else
1893+
{
1894+
MCLog("can't handle type of kind %d", t_def->kind);
1895+
return kMCScriptForeignPrimitiveTypeUnknown;
1896+
}
1897+
1898+
if (p_is_return_type &&
1899+
MCStringIsEqualToCString(MCNameGetString(t_name),
1900+
"undefined",
1901+
kMCStringOptionCompareCaseless))
1902+
{
1903+
return kMCScriptForeignPrimitiveTypeVoid;
1904+
}
1905+
1906+
/* This list must be kept up to date with all types which we bind to
1907+
* to in foreign handlers in the modules embedded in the engine. */
1908+
static struct { const char *name; MCScriptForeignPrimitiveType type; } s_ext_mappings[] =
1909+
{
1910+
/* Foundation Types */
1911+
{ "undefined", kMCScriptForeignPrimitiveTypePointer },
1912+
{ "any", kMCScriptForeignPrimitiveTypePointer },
1913+
1914+
{ "Boolean", kMCScriptForeignPrimitiveTypePointer },
1915+
{ "Number", kMCScriptForeignPrimitiveTypePointer },
1916+
{ "String", kMCScriptForeignPrimitiveTypePointer },
1917+
{ "Data", kMCScriptForeignPrimitiveTypePointer },
1918+
{ "Array", kMCScriptForeignPrimitiveTypePointer },
1919+
{ "List", kMCScriptForeignPrimitiveTypePointer },
1920+
1921+
/* Foreign C Types */
1922+
{ "SInt8", kMCScriptForeignPrimitiveTypeSInt8 },
1923+
{ "UInt8", kMCScriptForeignPrimitiveTypeUInt8 },
1924+
{ "SInt16", kMCScriptForeignPrimitiveTypeSInt16 },
1925+
{ "UInt16", kMCScriptForeignPrimitiveTypeUInt16 },
1926+
{ "SInt32", kMCScriptForeignPrimitiveTypeSInt32 },
1927+
{ "UInt32", kMCScriptForeignPrimitiveTypeUInt32 },
1928+
{ "SInt64", kMCScriptForeignPrimitiveTypeSInt64 },
1929+
{ "UInt64", kMCScriptForeignPrimitiveTypeUInt64 },
1930+
1931+
{ "CSIntSize", kMCScriptForeignPrimitiveTypeSIntSize },
1932+
{ "CUIntSize", kMCScriptForeignPrimitiveTypeUIntSize },
1933+
{ "CSIntPtr", kMCScriptForeignPrimitiveTypeSIntPtr },
1934+
{ "CUIntPtr", kMCScriptForeignPrimitiveTypeUIntPtr },
1935+
1936+
{ "CBool", kMCScriptForeignPrimitiveTypeCBool },
1937+
{ "CChar", kMCScriptForeignPrimitiveTypeCChar },
1938+
{ "CSChar", kMCScriptForeignPrimitiveTypeCSChar },
1939+
{ "CUChar", kMCScriptForeignPrimitiveTypeCUChar },
1940+
{ "CSShort", kMCScriptForeignPrimitiveTypeCSShort },
1941+
{ "CUShort", kMCScriptForeignPrimitiveTypeCUShort },
1942+
{ "CSInt", kMCScriptForeignPrimitiveTypeCSInt },
1943+
{ "CUInt", kMCScriptForeignPrimitiveTypeCUInt },
1944+
{ "CSLong", kMCScriptForeignPrimitiveTypeCSLong },
1945+
{ "CULong", kMCScriptForeignPrimitiveTypeCULong },
1946+
{ "CULongLong", kMCScriptForeignPrimitiveTypeCSLongLong },
1947+
{ "CULongLong", kMCScriptForeignPrimitiveTypeCULongLong },
1948+
{ "CDouble", kMCScriptForeignPrimitiveTypeCDouble },
1949+
{ "CFloat", kMCScriptForeignPrimitiveTypeCFloat },
1950+
{ "LCSInt", kMCScriptForeignPrimitiveTypeSInt },
1951+
{ "LCUInt", kMCScriptForeignPrimitiveTypeUInt },
1952+
1953+
{ "Float32", kMCScriptForeignPrimitiveTypeFloat32 },
1954+
{ "Float64", kMCScriptForeignPrimitiveTypeFloat64 },
1955+
1956+
{ "Pointer", kMCScriptForeignPrimitiveTypePointer },
1957+
1958+
{ "ZStringUTF8", kMCScriptForeignPrimitiveTypePointer },
1959+
1960+
/* Java FFI Types */
1961+
{ "JObject", kMCScriptForeignPrimitiveTypePointer },
1962+
1963+
/* Extra Foundation Types */
1964+
{ "Stream", kMCScriptForeignPrimitiveTypePointer },
1965+
1966+
/* Canvas Types */
1967+
{ "Rectangle", kMCScriptForeignPrimitiveTypePointer },
1968+
{ "Point", kMCScriptForeignPrimitiveTypePointer },
1969+
{ "Image", kMCScriptForeignPrimitiveTypePointer },
1970+
{ "Color", kMCScriptForeignPrimitiveTypePointer },
1971+
{ "Paint", kMCScriptForeignPrimitiveTypePointer },
1972+
{ "SolidPaint", kMCScriptForeignPrimitiveTypePointer },
1973+
{ "Pattern", kMCScriptForeignPrimitiveTypePointer },
1974+
{ "Gradient", kMCScriptForeignPrimitiveTypePointer },
1975+
{ "GradientStop", kMCScriptForeignPrimitiveTypePointer },
1976+
{ "Path", kMCScriptForeignPrimitiveTypePointer },
1977+
{ "Effect", kMCScriptForeignPrimitiveTypePointer },
1978+
{ "Font", kMCScriptForeignPrimitiveTypePointer },
1979+
{ "Canvas", kMCScriptForeignPrimitiveTypePointer },
1980+
{ "Transform", kMCScriptForeignPrimitiveTypePointer },
1981+
1982+
/* Engine Types */
1983+
{ "Widget", kMCScriptForeignPrimitiveTypePointer },
1984+
{ "ScriptObject", kMCScriptForeignPrimitiveTypePointer },
1985+
};
1986+
1987+
for(const auto t_mapping : s_ext_mappings)
1988+
{
1989+
if (MCStringIsEqualToCString(MCNameGetString(t_name), t_mapping.name, kMCStringOptionCompareCaseless))
1990+
{
1991+
return t_mapping.type;
1992+
}
1993+
}
1994+
1995+
return kMCScriptForeignPrimitiveTypeUnknown;
1996+
}
1997+
else if (t_type->kind == kMCScriptTypeKindForeign)
1998+
{
1999+
return kMCScriptForeignPrimitiveTypeUnknown;
2000+
}
2001+
else if (t_type->kind == kMCScriptTypeKindOptional)
2002+
{
2003+
return kMCScriptForeignPrimitiveTypePointer;
2004+
}
2005+
else if (t_type->kind == kMCScriptTypeKindForeignHandler ||
2006+
t_type->kind == kMCScriptTypeKindHandler)
2007+
{
2008+
return kMCScriptForeignPrimitiveTypePointer;
2009+
}
2010+
2011+
return kMCScriptForeignPrimitiveTypeUnknown;
2012+
}
2013+
2014+
MCScriptForeignPrimitiveType
2015+
MCScriptQueryForeignHandlerReturnTypeInModule(MCScriptModuleBuilderRef self, uindex_t p_type_index)
2016+
{
2017+
if (self->module.types[p_type_index]->kind != kMCScriptTypeKindForeignHandler)
2018+
{
2019+
return kMCScriptForeignPrimitiveTypeUnknown;
2020+
}
2021+
2022+
auto t_handler_type = static_cast<MCScriptHandlerType *>(self -> module . types[p_type_index]);
2023+
2024+
return MCScriptMapTypeToForeignPrimitiveTypeInModule(self, t_handler_type->return_type, true);
2025+
}
2026+
2027+
uindex_t
2028+
MCScriptQueryForeignHandlerParameterCountInModule(MCScriptModuleBuilderRef self, uindex_t p_type_index)
2029+
{
2030+
if (self->module.types[p_type_index]->kind != kMCScriptTypeKindForeignHandler)
2031+
{
2032+
return 0;
2033+
}
2034+
2035+
auto t_handler_type = static_cast<MCScriptHandlerType *>(self -> module . types[p_type_index]);
2036+
2037+
return t_handler_type->parameter_count;
2038+
2039+
}
2040+
2041+
MCScriptForeignPrimitiveType
2042+
MCScriptQueryForeignHandlerParameterTypeInModule(MCScriptModuleBuilderRef self, uindex_t p_type_index, uindex_t p_arg_index)
2043+
{
2044+
if (self->module.types[p_type_index]->kind != kMCScriptTypeKindForeignHandler)
2045+
{
2046+
return kMCScriptForeignPrimitiveTypeUnknown;
2047+
}
2048+
2049+
auto t_handler_type = static_cast<MCScriptHandlerType *>(self -> module . types[p_type_index]);
2050+
if (p_arg_index >= t_handler_type->parameter_count)
2051+
{
2052+
return kMCScriptForeignPrimitiveTypeUnknown;
2053+
}
2054+
2055+
/* Non-in modes map to a primitive pointer type from the point of view of
2056+
FFI. */
2057+
if (t_handler_type->parameters[p_arg_index].mode != kMCScriptHandlerTypeParameterModeIn)
2058+
{
2059+
return kMCScriptForeignPrimitiveTypePointer;
2060+
}
2061+
2062+
return MCScriptMapTypeToForeignPrimitiveTypeInModule(self, t_handler_type->parameters[p_arg_index].type);
2063+
}
2064+
2065+
////////////////////////////////////////////////////////////////////////////////

libscript/src/script-execute.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,12 @@ class MCScriptForeignInvocation
149149
m_argument_values,
150150
m_argument_count);
151151
}
152-
else
152+
else if (p_handler->is_builtin)
153+
{
154+
((void(*)(void*, void**))p_handler->native.function)(p_result_slot_ptr,
155+
m_argument_values);
156+
}
157+
else
153158
{
154159
ffi_call((ffi_cif *)p_handler -> native . function_cif,
155160
(void(*)())p_handler -> native . function,

libscript/src/script-instance.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,7 @@ __MCScriptResolveForeignFunctionBinding(MCScriptInstanceRef p_instance,
652652
MCTypeConvertStringToLongInteger(p_handler->binding, t_ordinal))
653653
{
654654
p_handler->native.function = p_instance->module->builtins[t_ordinal];
655+
p_handler->is_builtin = true;
655656
r_abi = FFI_DEFAULT_ABI;
656657
if (r_bound != nullptr)
657658
{
@@ -782,6 +783,7 @@ __MCScriptResolveForeignFunctionBinding(MCScriptInstanceRef p_instance,
782783
}
783784

784785
p_handler -> native . function = t_pointer;
786+
p_handler->is_builtin = false;
785787
}
786788
else if (MCStringIsEqualToCString(*t_language,
787789
"cpp",
@@ -809,6 +811,7 @@ __MCScriptResolveForeignFunctionBinding(MCScriptInstanceRef p_instance,
809811
else if (MCStringIsEqualToCString(*t_language, "java", kMCStringOptionCompareExact))
810812
{
811813
p_handler -> is_java = true;
814+
p_handler->is_builtin = false;
812815

813816
p_handler -> java . call_type = __MCScriptGetJavaCallType(*t_class,
814817
*t_function,

libscript/src/script-module.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -735,17 +735,20 @@ bool MCScriptEnsureModuleIsUsable(MCScriptModuleRef self)
735735
MCScriptForeignType *t_type;
736736
t_type = static_cast<MCScriptForeignType *>(self -> types[i]);
737737

738+
bool t_is_builtin = false;
738739
void *t_symbol = nullptr;
739740
integer_t t_ordinal = 0;
740741
if (self->builtins != nullptr &&
741742
MCTypeConvertStringToLongInteger(t_type->binding, t_ordinal))
742743
{
743744
t_symbol = self->builtins[t_ordinal];
745+
t_is_builtin = true;
744746
}
745747
else
746748
{
747749
t_symbol = MCSLibraryLookupSymbol(MCScriptGetLibrary(),
748750
t_type->binding);
751+
t_is_builtin = false;
749752
}
750753

751754
if (t_symbol == nullptr)
@@ -758,8 +761,18 @@ bool MCScriptEnsureModuleIsUsable(MCScriptModuleRef self)
758761
}
759762

760763
/* The symbol is a function that returns a type info reference. */
761-
MCTypeInfoRef (*t_type_func)(void) = (MCTypeInfoRef (*)(void)) t_symbol;
762-
t_typeinfo = MCValueRetain(t_type_func());
764+
if (t_is_builtin)
765+
{
766+
MCTypeInfoRef t_typeinfo_bare;
767+
void (*t_type_func_builtin)(void*rv, void**av) = (void(*)(void*, void**))t_symbol;
768+
t_type_func_builtin(&t_typeinfo_bare, nullptr);
769+
t_typeinfo = t_typeinfo_bare;
770+
}
771+
else
772+
{
773+
MCTypeInfoRef (*t_type_func)(void) = (MCTypeInfoRef (*)(void)) t_symbol;
774+
t_typeinfo = t_type_func();
775+
}
763776
}
764777
break;
765778
case kMCScriptTypeKindRecord:

libscript/src/script-private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ struct MCScriptForeignHandlerDefinition: public MCScriptCommonHandlerDefinition
342342
// Bound function information - not pickled.
343343
bool is_java: 1;
344344
bool is_bound: 1;
345+
bool is_builtin: 1;
345346

346347
union
347348
{

0 commit comments

Comments
 (0)