diff options
author | Alon Zakai <alonzakai@gmail.com> | 2014-03-31 17:28:55 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2014-03-31 17:28:55 -0700 |
commit | d75c0bca8116f7dcb5224c4cce971a0397faac48 (patch) | |
tree | 17a95d16afae30579aa52405413bca816dd4d974 /system | |
parent | 673d4315ab0d14846dfa2d966abd32400679fd43 (diff) | |
parent | ffed52a8ac686a54bfda83d722673c11b8e7093e (diff) |
Merge pull request #2264 from imvu/incoming-with-fastcomp-asm.js-emval-2
Make emscripten::val compatible with fastcomp/asm.js
Diffstat (limited to 'system')
-rw-r--r-- | system/include/emscripten/bind.h | 15 | ||||
-rw-r--r-- | system/include/emscripten/val.h | 200 | ||||
-rw-r--r-- | system/include/emscripten/wire.h | 2 | ||||
-rw-r--r-- | system/lib/embind/bind.cpp | 41 |
4 files changed, 191 insertions, 67 deletions
diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 390533f3..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; @@ -35,18 +33,21 @@ namespace emscripten { void _embind_register_bool( TYPEID boolType, const char* name, + size_t size, bool trueValue, bool falseValue); void _embind_register_integer( TYPEID integerType, const char* name, + size_t size, long minRange, unsigned long maxRange); void _embind_register_float( TYPEID floatType, - const char* name); + const char* name, + size_t size); void _embind_register_std_string( TYPEID stringType, @@ -163,7 +164,9 @@ namespace emscripten { void _embind_register_enum( TYPEID enumType, - const char* name); + const char* name, + size_t size, + bool isSigned); void _embind_register_enum_value( TYPEID enumType, @@ -1182,7 +1185,9 @@ namespace emscripten { enum_(const char* name) { _embind_register_enum( internal::TypeID<EnumType>::get(), - name); + name, + sizeof(EnumType), + std::is_signed<typename std::underlying_type<EnumType>::type>::value); } enum_& value(const char* name, EnumType value) { diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 19b1beb1..e217c959 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 { @@ -12,12 +13,10 @@ namespace emscripten { typedef struct _EM_VAL* EM_VAL; 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; - // TODO: functions returning this are reinterpret_cast - // into the correct return type. this needs some thought - // for asm.js. - typedef void _POLYMORPHIC_RESULT; - void _emval_incref(EM_VAL value); void _emval_decref(EM_VAL value); @@ -28,37 +27,45 @@ namespace emscripten { EM_VAL _emval_undefined(); EM_VAL _emval_null(); EM_VAL _emval_new_cstring(const char*); - void _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[] - /*, ... */); + internal::TYPEID argTypes[], + EM_VAR_ARGS argv); EM_VAL _emval_get_global(const char* name); EM_VAL _emval_get_module_property(const char* name); EM_VAL _emval_get_property(EM_VAL object, EM_VAL key); void _emval_set_property(EM_VAL object, EM_VAL key, EM_VAL value); - _POLYMORPHIC_RESULT _emval_as(EM_VAL value, TYPEID returnType, EM_DESTRUCTORS* runDestructors); + EM_GENERIC_WIRE_TYPE _emval_as(EM_VAL value, TYPEID returnType, EM_DESTRUCTORS* destructors); EM_VAL _emval_call( EM_VAL value, unsigned argCount, - internal::TYPEID argTypes[] - /*, ... */); + internal::TYPEID argTypes[], + EM_VAR_ARGS argv); - // DO NOT call this more than once per signature. It will leak function pointer offsets! - GenericFunction _emval_get_method_caller( + // DO NOT call this more than once per signature. It will + // leak generated function objects! + EM_METHOD_CALLER _emval_get_method_caller( unsigned argCount, // including return value internal::TYPEID argTypes[]); + EM_GENERIC_WIRE_TYPE _emval_call_method( + EM_METHOD_CALLER caller, + EM_VAL handle, + const char* methodName, + EM_DESTRUCTORS* destructors, + EM_VAR_ARGS argv); bool _emval_has_function( EM_VAL value, const char* methodName); } template<const char* address> - struct symbol_registrar { + struct symbol_registrar { symbol_registrar() { internal::_emval_register_symbol(address); } @@ -66,19 +73,21 @@ namespace emscripten { template<typename ReturnType, typename... Args> struct Signature { + /* typedef typename BindingType<ReturnType>::WireType (*MethodCaller)( EM_VAL value, const char* methodName, EM_DESTRUCTORS* destructors, typename BindingType<Args>::WireType...); + */ - static MethodCaller get_method_caller() { - static MethodCaller fp = reinterpret_cast<MethodCaller>(init_method_caller()); - return fp; + static EM_METHOD_CALLER get_method_caller() { + static EM_METHOD_CALLER mc = init_method_caller(); + return mc; } private: - static GenericFunction init_method_caller() { + static EM_METHOD_CALLER init_method_caller() { WithPolicies<>::ArgTypeList<ReturnType, Args...> args; return _emval_get_method_caller(args.count, args.types); } @@ -100,19 +109,119 @@ namespace emscripten { EM_DESTRUCTORS destructors; }; + template<typename WireType> + struct GenericWireTypeConverter { + static WireType from(double wt) { + return static_cast<WireType>(wt); + } + }; + + template<typename Pointee> + struct GenericWireTypeConverter<Pointee*> { + static Pointee* from(double wt) { + return reinterpret_cast<Pointee*>(static_cast<uintptr_t>(wt)); + } + }; + + template<typename T> + T fromGenericWireType(double g) { + typedef typename BindingType<T>::WireType WireType; + WireType wt = GenericWireTypeConverter<WireType>::from(g); + 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 { + unsigned u; + float f; + 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->w[0].f = 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; - auto wireType = caller( + EM_GENERIC_WIRE_TYPE result = _emval_call_method( + caller, handle, methodName, &destructors, - toWireType(std::forward<Args>(args))...); + argv); DestructorsRunner rd(destructors); - return BindingType<ReturnType>::fromWireType(wireType); + return fromGenericWireType<ReturnType>(result); } }; @@ -121,12 +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; - caller( + _emval_call_method( + caller, handle, methodName, &destructors, - toWireType(std::forward<Args>(args))...); + argv); DestructorsRunner rd(destructors); // void requires no translation } @@ -185,9 +296,13 @@ namespace emscripten { template<typename T> explicit val(T&& value) { + using namespace internal; + typedef internal::BindingType<T> BT; - auto taker = reinterpret_cast<internal::EM_VAL (*)(internal::TYPEID, typename BT::WireType)>(&internal::_emval_take_value); - handle = taker(internal::TypeID<T>::get(), BT::toWireType(std::forward<T>(value))); + WireTypePack<T> argv(std::forward<T>(value)); + handle = _emval_take_value( + internal::TypeID<T>::get(), + argv); } val() = delete; @@ -235,20 +350,15 @@ 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? - typedef EM_VAL (*TypedNew)( - EM_VAL, - unsigned, - TYPEID argTypes[], - typename BindingType<Args>::WireType...); - TypedNew typedNew = reinterpret_cast<TypedNew>(&_emval_new); return val( - typedNew( + _emval_new( handle, argList.count, argList.types, - toWireType(std::forward<Args>(args))...)); + argv)); } template<typename T> @@ -266,18 +376,13 @@ namespace emscripten { using namespace internal; WithPolicies<>::ArgTypeList<Args...> argList; - typedef EM_VAL (*TypedCall)( - EM_VAL, - unsigned, - TYPEID argTypes[], - typename BindingType<Args>::WireType...); - TypedCall typedCall = reinterpret_cast<TypedCall>(&_emval_call); + WireTypePack<Args...> argv(std::forward<Args>(args)...); return val( - typedCall( + _emval_call( handle, argList.count, argList.types, - toWireType(std::forward<Args>(args))...)); + argv)); } template<typename ReturnValue, typename... Args> @@ -297,16 +402,13 @@ namespace emscripten { typedef BindingType<T> BT; - typedef typename BT::WireType (*TypedAs)( - EM_VAL value, - TYPEID returnType, - EM_DESTRUCTORS* runDestructors); - TypedAs typedAs = reinterpret_cast<TypedAs>(&_emval_as); - EM_DESTRUCTORS destructors; - typename BT::WireType wt = typedAs(handle, TypeID<T>::get(), &destructors); + EM_GENERIC_WIRE_TYPE result = _emval_as( + handle, + TypeID<T>::get(), + &destructors); DestructorsRunner dr(destructors); - return BT::fromWireType(wt); + return fromGenericWireType<T>(result); } private: 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)(); diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 12264dfd..f43d1ea1 100644 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -8,6 +8,7 @@ #include <algorithm>
#include <emscripten/emscripten.h>
#include <climits>
+#include <limits>
using namespace emscripten;
@@ -36,25 +37,39 @@ extern "C" { }
}
+namespace {
+ template<typename T>
+ static void register_integer(const char* name) {
+ using namespace internal;
+ _embind_register_integer(TypeID<T>::get(), name, sizeof(T), std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
+ }
+
+ template<typename T>
+ static void register_float(const char* name) {
+ using namespace internal;
+ _embind_register_float(TypeID<T>::get(), name, sizeof(T));
+ }
+}
+
EMSCRIPTEN_BINDINGS(native_and_builtin_types) {
using namespace emscripten::internal;
_embind_register_void(TypeID<void>::get(), "void");
- _embind_register_bool(TypeID<bool>::get(), "bool", true, false);
-
- _embind_register_integer(TypeID<char>::get(), "char", CHAR_MIN, CHAR_MAX);
- _embind_register_integer(TypeID<signed char>::get(), "signed char", SCHAR_MIN, SCHAR_MAX);
- _embind_register_integer(TypeID<unsigned char>::get(), "unsigned char", 0, UCHAR_MAX);
- _embind_register_integer(TypeID<signed short>::get(), "short", SHRT_MIN, SHRT_MAX);
- _embind_register_integer(TypeID<unsigned short>::get(), "unsigned short", 0, USHRT_MAX);
- _embind_register_integer(TypeID<signed int>::get(), "int", INT_MIN, INT_MAX);
- _embind_register_integer(TypeID<unsigned int>::get(), "unsigned int", 0, UINT_MAX);
- _embind_register_integer(TypeID<signed long>::get(), "long", LONG_MIN, LONG_MAX);
- _embind_register_integer(TypeID<unsigned long>::get(), "unsigned long", 0, ULONG_MAX);
+ _embind_register_bool(TypeID<bool>::get(), "bool", sizeof(bool), true, false);
+
+ register_integer<char>("char");
+ register_integer<signed char>("signed char");
+ register_integer<unsigned char>("unsigned char");
+ register_integer<signed short>("short");
+ register_integer<unsigned short>("unsigned short");
+ register_integer<signed int>("int");
+ register_integer<unsigned int>("unsigned int");
+ register_integer<signed long>("long");
+ register_integer<unsigned long>("unsigned long");
- _embind_register_float(TypeID<float>::get(), "float");
- _embind_register_float(TypeID<double>::get(), "double");
+ register_float<float>("float");
+ register_float<double>("double");
_embind_register_std_string(TypeID<std::string>::get(), "std::string");
_embind_register_std_wstring(TypeID<std::wstring>::get(), sizeof(wchar_t), "std::wstring");
|