From aa05c2ee438ed1904ef90ebaebe3193dccd7f222 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 28 Mar 2014 23:38:09 -0700 Subject: Instead of varargs, which depend on the compiler, manually build the varargs packs on the stack. --- system/include/emscripten/bind.h | 2 - system/include/emscripten/val.h | 102 +++++++++++++++++++++++++++++++++++---- system/include/emscripten/wire.h | 2 + 3 files changed, 95 insertions(+), 11 deletions(-) (limited to 'system') diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 5ed05994..872f279b 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -17,8 +17,6 @@ namespace emscripten { BY_EMVAL = 2, }; -#define EMSCRIPTEN_ALWAYS_INLINE __attribute__((always_inline)) - namespace internal { typedef long GenericEnumValue; diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 74e4e702..e364727c 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -2,6 +2,7 @@ #include // uintptr_t #include +#include #include namespace emscripten { @@ -14,6 +15,7 @@ namespace emscripten { typedef struct _EM_DESTRUCTORS* EM_DESTRUCTORS; typedef struct _EM_METHOD_CALLER* EM_METHOD_CALLER; typedef double EM_GENERIC_WIRE_TYPE; + typedef const void* EM_VAR_ARGS; void _emval_incref(EM_VAL value); void _emval_decref(EM_VAL value); @@ -26,13 +28,13 @@ namespace emscripten { EM_VAL _emval_null(); EM_VAL _emval_new_cstring(const char*); - EM_VAL _emval_take_value(TYPEID type, ...); + EM_VAL _emval_take_value(TYPEID type, EM_VAR_ARGS argv); EM_VAL _emval_new( EM_VAL value, unsigned argCount, internal::TYPEID argTypes[], - ...); + EM_VAR_ARGS argv); EM_VAL _emval_get_global(const char* name); EM_VAL _emval_get_module_property(const char* name); @@ -44,7 +46,7 @@ namespace emscripten { EM_VAL value, unsigned argCount, internal::TYPEID argTypes[], - ...); + EM_VAR_ARGS argv); // DO NOT call this more than once per signature. It will // leak generated function objects! @@ -56,7 +58,7 @@ namespace emscripten { EM_VAL handle, const char* methodName, EM_DESTRUCTORS* destructors, - ...); + EM_VAR_ARGS argv); bool _emval_has_function( EM_VAL value, const char* methodName); @@ -128,18 +130,96 @@ namespace emscripten { return BindingType::fromWireType(wt); } + template + struct PackSize; + + template<> + struct PackSize<> { + static constexpr size_t value = 0; + }; + + template + struct PackSize { + static constexpr size_t value = (sizeof(typename BindingType::WireType) + 7) / 8 + PackSize::value; + }; + + union GenericWireType { + union { + int i; + unsigned u; + const void* p; + } w[2]; + double d; + }; + static_assert(sizeof(GenericWireType) == 8, "GenericWireType must be 8 bytes"); + static_assert(alignof(GenericWireType) == 8, "GenericWireType must be 8-byte-aligned"); + + inline void writeGenericWireType(GenericWireType*& cursor, float wt) { + cursor->d = wt; + ++cursor; + } + + inline void writeGenericWireType(GenericWireType*& cursor, double wt) { + cursor->d = wt; + ++cursor; + } + + template + void writeGenericWireType(GenericWireType*& cursor, T* wt) { + cursor->w[0].p = wt; + ++cursor; + } + + inline void writeGenericWireType(GenericWireType*& cursor, const memory_view& wt) { + cursor[0].w[0].u = static_cast(wt.type); + cursor[0].w[1].u = wt.size; + cursor[1].w[0].p = wt.data; + cursor += 2; + } + + template + void writeGenericWireType(GenericWireType*& cursor, T wt) { + cursor->w[0].u = static_cast(wt); + ++cursor; + } + + inline void writeGenericWireTypes(GenericWireType*&) { + } + + template + EMSCRIPTEN_ALWAYS_INLINE void writeGenericWireTypes(GenericWireType*& cursor, First&& first, Rest&&... rest) { + writeGenericWireType(cursor, BindingType::toWireType(std::forward(first))); + writeGenericWireTypes(cursor, std::forward(rest)...); + } + + template + struct WireTypePack { + WireTypePack(Args&&... args) { + GenericWireType* cursor = elements.data(); + writeGenericWireTypes(cursor, std::forward(args)...); + } + + operator EM_VAR_ARGS() const { + return elements.data(); + } + + private: + std::array::value> elements; + }; + template struct MethodCaller { static ReturnType call(EM_VAL handle, const char* methodName, Args&&... args) { auto caller = Signature::get_method_caller(); + WireTypePack argv(std::forward(args)...); EM_DESTRUCTORS destructors; EM_GENERIC_WIRE_TYPE result = _emval_call_method( caller, handle, methodName, &destructors, - toWireType(std::forward(args))...); + argv); DestructorsRunner rd(destructors); return fromGenericWireType(result); } @@ -150,13 +230,14 @@ namespace emscripten { static void call(EM_VAL handle, const char* methodName, Args&&... args) { auto caller = Signature::get_method_caller(); + WireTypePack argv(std::forward(args)...); EM_DESTRUCTORS destructors; _emval_call_method( caller, handle, methodName, &destructors, - toWireType(std::forward(args))...); + argv); DestructorsRunner rd(destructors); // void requires no translation } @@ -218,9 +299,10 @@ namespace emscripten { using namespace internal; typedef internal::BindingType BT; + WireTypePack argv(std::forward(value)); handle = _emval_take_value( internal::TypeID::get(), - BT::toWireType(std::forward(value))); + argv); } val() = delete; @@ -268,6 +350,7 @@ namespace emscripten { using namespace internal; WithPolicies<>::ArgTypeList argList; + WireTypePack argv(std::forward(args)...); // todo: this is awfully similar to operator(), can we // merge them somehow? return val( @@ -275,7 +358,7 @@ namespace emscripten { handle, argList.count, argList.types, - toWireType(std::forward(args))...)); + argv)); } template @@ -293,12 +376,13 @@ namespace emscripten { using namespace internal; WithPolicies<>::ArgTypeList argList; + WireTypePack argv(std::forward(args)...); return val( _emval_call( handle, argList.count, argList.types, - toWireType(std::forward(args))...)); + argv)); } template diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index c3ce8dd0..05b3ac33 100644 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -12,6 +12,8 @@ #include #include +#define EMSCRIPTEN_ALWAYS_INLINE __attribute__((always_inline)) + namespace emscripten { namespace internal { typedef void (*GenericFunction)(); -- cgit v1.2.3-70-g09d2