aboutsummaryrefslogtreecommitdiff
path: root/system
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2014-03-31 17:28:55 -0700
committerAlon Zakai <alonzakai@gmail.com>2014-03-31 17:28:55 -0700
commitd75c0bca8116f7dcb5224c4cce971a0397faac48 (patch)
tree17a95d16afae30579aa52405413bca816dd4d974 /system
parent673d4315ab0d14846dfa2d966abd32400679fd43 (diff)
parentffed52a8ac686a54bfda83d722673c11b8e7093e (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.h15
-rw-r--r--system/include/emscripten/val.h200
-rw-r--r--system/include/emscripten/wire.h2
-rw-r--r--system/lib/embind/bind.cpp41
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");