diff options
author | Chad Austin <caustin@gmail.com> | 2014-03-28 23:38:09 -0700 |
---|---|---|
committer | Chad Austin <chad@chadaustin.me> | 2014-03-28 23:56:42 -0700 |
commit | aa05c2ee438ed1904ef90ebaebe3193dccd7f222 (patch) | |
tree | c2d9cf91ac01aab096e5d42b0545aceb39061ee9 | |
parent | 0ee1cab6034ce6ef51e9f612873603182dffa248 (diff) |
Instead of varargs, which depend on the compiler, manually build the varargs packs on the stack.
-rw-r--r-- | system/include/emscripten/bind.h | 2 | ||||
-rw-r--r-- | system/include/emscripten/val.h | 102 | ||||
-rw-r--r-- | system/include/emscripten/wire.h | 2 |
3 files changed, 95 insertions, 11 deletions
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 <stdint.h> // uintptr_t #include <emscripten/wire.h> +#include <array> #include <vector> 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<T>::fromWireType(wt); } + template<typename... Args> + struct PackSize; + + template<> + struct PackSize<> { + static constexpr size_t value = 0; + }; + + template<typename Arg, typename... Args> + struct PackSize<Arg, Args...> { + static constexpr size_t value = (sizeof(typename BindingType<Arg>::WireType) + 7) / 8 + PackSize<Args...>::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<typename T> + 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<unsigned>(wt.type); + cursor[0].w[1].u = wt.size; + cursor[1].w[0].p = wt.data; + cursor += 2; + } + + template<typename T> + void writeGenericWireType(GenericWireType*& cursor, T wt) { + cursor->w[0].u = static_cast<unsigned>(wt); + ++cursor; + } + + inline void writeGenericWireTypes(GenericWireType*&) { + } + + template<typename First, typename... Rest> + EMSCRIPTEN_ALWAYS_INLINE void writeGenericWireTypes(GenericWireType*& cursor, First&& first, Rest&&... rest) { + writeGenericWireType(cursor, BindingType<First>::toWireType(std::forward<First>(first))); + writeGenericWireTypes(cursor, std::forward<Rest>(rest)...); + } + + template<typename... Args> + struct WireTypePack { + WireTypePack(Args&&... args) { + GenericWireType* cursor = elements.data(); + writeGenericWireTypes(cursor, std::forward<Args>(args)...); + } + + operator EM_VAR_ARGS() const { + return elements.data(); + } + + private: + std::array<GenericWireType, PackSize<Args...>::value> elements; + }; + template<typename ReturnType, typename... Args> struct MethodCaller { static ReturnType call(EM_VAL handle, const char* methodName, Args&&... args) { auto caller = Signature<ReturnType, Args...>::get_method_caller(); + WireTypePack<Args...> argv(std::forward<Args>(args)...); EM_DESTRUCTORS destructors; EM_GENERIC_WIRE_TYPE result = _emval_call_method( caller, handle, methodName, &destructors, - toWireType(std::forward<Args>(args))...); + argv); DestructorsRunner rd(destructors); return fromGenericWireType<ReturnType>(result); } @@ -150,13 +230,14 @@ namespace emscripten { static void call(EM_VAL handle, const char* methodName, Args&&... args) { auto caller = Signature<void, Args...>::get_method_caller(); + WireTypePack<Args...> argv(std::forward<Args>(args)...); EM_DESTRUCTORS destructors; _emval_call_method( caller, handle, methodName, &destructors, - toWireType(std::forward<Args>(args))...); + argv); DestructorsRunner rd(destructors); // void requires no translation } @@ -218,9 +299,10 @@ namespace emscripten { using namespace internal; typedef internal::BindingType<T> BT; + WireTypePack<T> argv(std::forward<T>(value)); handle = _emval_take_value( internal::TypeID<T>::get(), - BT::toWireType(std::forward<T>(value))); + argv); } val() = delete; @@ -268,6 +350,7 @@ namespace emscripten { using namespace internal; WithPolicies<>::ArgTypeList<Args...> argList; + WireTypePack<Args...> argv(std::forward<Args>(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>(args))...)); + argv)); } template<typename T> @@ -293,12 +376,13 @@ namespace emscripten { using namespace internal; WithPolicies<>::ArgTypeList<Args...> argList; + WireTypePack<Args...> argv(std::forward<Args>(args)...); return val( _emval_call( handle, argList.count, argList.types, - toWireType(std::forward<Args>(args))...)); + argv)); } template<typename ReturnValue, typename... Args> 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 <memory> #include <string> +#define EMSCRIPTEN_ALWAYS_INLINE __attribute__((always_inline)) + namespace emscripten { namespace internal { typedef void (*GenericFunction)(); |