diff options
Diffstat (limited to 'system')
-rwxr-xr-x[-rw-r--r--] | system/include/emscripten/bind.h | 1311 | ||||
-rw-r--r-- | system/include/emscripten/val.h | 259 | ||||
-rwxr-xr-x[-rw-r--r--] | system/include/emscripten/wire.h | 297 | ||||
-rw-r--r-- | system/lib/compiler-rt/LICENSE.TXT | 97 | ||||
-rw-r--r-- | system/lib/compiler-rt/divdi3.c | 47 | ||||
-rw-r--r-- | system/lib/compiler-rt/int_endianness.h | 116 | ||||
-rw-r--r-- | system/lib/compiler-rt/int_lib.h | 46 | ||||
-rw-r--r-- | system/lib/compiler-rt/int_math.h | 67 | ||||
-rw-r--r-- | system/lib/compiler-rt/int_types.h | 140 | ||||
-rw-r--r-- | system/lib/compiler-rt/int_util.h | 29 | ||||
-rw-r--r-- | system/lib/compiler-rt/muldi3.c | 56 | ||||
-rw-r--r-- | system/lib/compiler-rt/readme.txt | 20 | ||||
-rw-r--r-- | system/lib/compiler-rt/udivdi3.c | 36 | ||||
-rw-r--r-- | system/lib/compiler-rt/udivmoddi4.c | 251 | ||||
-rwxr-xr-x | system/lib/embind/bind.cpp | 100 |
15 files changed, 2354 insertions, 518 deletions
diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 55fda986..4d2f4ac8 100644..100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -3,11 +3,20 @@ #include <stddef.h> #include <assert.h> #include <string> +#include <functional> +#include <vector> +#include <map> #include <type_traits> #include <emscripten/val.h> #include <emscripten/wire.h> namespace emscripten { + enum class sharing_policy { + NONE = 0, + INTRUSIVE = 1, + BY_EMVAL = 2, + }; + namespace internal { typedef void (*GenericFunction)(); typedef long GenericEnumValue; @@ -19,150 +28,224 @@ namespace emscripten { const char* payload) __attribute__((noreturn)); void _embind_register_void( - TypeID voidType, + TYPEID voidType, const char* name); void _embind_register_bool( - TypeID boolType, + TYPEID boolType, const char* name, bool trueValue, bool falseValue); void _embind_register_integer( - TypeID integerType, - const char* name); + TYPEID integerType, + const char* name, + long minRange, + unsigned long maxRange); void _embind_register_float( - TypeID floatType, + TYPEID floatType, const char* name); - void _embind_register_cstring( - TypeID stringType, + void _embind_register_std_string( + TYPEID stringType, + const char* name); + + void _embind_register_std_wstring( + TYPEID stringType, + size_t charSize, const char* name); void _embind_register_emval( - TypeID emvalType, + TYPEID emvalType, const char* name); void _embind_register_function( const char* name, - TypeID returnType, unsigned argCount, - TypeID argTypes[], + TYPEID argTypes[], GenericFunction invoker, GenericFunction function); void _embind_register_tuple( - TypeID tupleType, + TYPEID tupleType, const char* name, GenericFunction constructor, GenericFunction destructor); void _embind_register_tuple_element( - TypeID tupleType, - TypeID elementType, + TYPEID tupleType, + TYPEID getterReturnType, GenericFunction getter, + void* getterContext, + TYPEID setterArgumentType, GenericFunction setter, - size_t memberPointerSize, - void* memberPointer); - - void _embind_register_tuple_element_accessor( - TypeID tupleType, - TypeID elementType, - GenericFunction staticGetter, - size_t getterSize, - void* getter, - GenericFunction staticSetter, - size_t setterSize, - void* setter); + void* setterContext); + + void _embind_finalize_tuple(TYPEID tupleType); void _embind_register_struct( - TypeID structType, - const char* name, + TYPEID structType, + const char* fieldName, GenericFunction constructor, GenericFunction destructor); void _embind_register_struct_field( - TypeID structType, - const char* name, - TypeID fieldType, + TYPEID structType, + const char* fieldName, + TYPEID getterReturnType, GenericFunction getter, + void* getterContext, + TYPEID setterArgumentType, GenericFunction setter, - size_t memberPointerSize, - void* memberPointer); + void* setterContext); + + void _embind_finalize_struct(TYPEID structType); + + void _embind_register_smart_ptr( + TYPEID pointerType, + TYPEID pointeeType, + const char* pointerName, + sharing_policy sharingPolicy, + GenericFunction getPointee, + GenericFunction constructor, + GenericFunction share, + GenericFunction destructor); void _embind_register_class( - TypeID classType, + TYPEID classType, + TYPEID pointerType, + TYPEID constPointerType, + TYPEID baseClassType, + GenericFunction getActualType, + GenericFunction upcast, + GenericFunction downcast, const char* className, GenericFunction destructor); void _embind_register_class_constructor( - TypeID classType, + TYPEID classType, unsigned argCount, - TypeID argTypes[], + TYPEID argTypes[], + GenericFunction invoker, GenericFunction constructor); - void _embind_register_class_method( - TypeID classType, + void _embind_register_class_function( + TYPEID classType, const char* methodName, - TypeID returnType, unsigned argCount, - TypeID argTypes[], + TYPEID argTypes[], GenericFunction invoker, - size_t memberFunctionSize, - void* memberFunction); + void* context); - void _embind_register_class_field( - TypeID classType, + void _embind_register_class_property( + TYPEID classType, const char* fieldName, - TypeID fieldType, + TYPEID getterReturnType, GenericFunction getter, + void* getterContext, + TYPEID setterArgumentType, GenericFunction setter, - size_t memberPointerSize, - void* memberPointer); + void* setterContext); - void _embind_register_class_classmethod( - TypeID classType, + void _embind_register_class_class_function( + TYPEID classType, const char* methodName, - TypeID returnType, unsigned argCount, - TypeID argTypes[], + TYPEID argTypes[], + GenericFunction invoker, GenericFunction method); void _embind_register_enum( - TypeID enumType, + TYPEID enumType, const char* name); void _embind_register_enum_value( - TypeID enumType, + TYPEID enumType, const char* valueName, GenericEnumValue value); void _embind_register_interface( - TypeID interfaceType, + TYPEID interfaceType, const char* name, GenericFunction constructor, GenericFunction destructor); + + void _embind_register_constant( + const char* name, + TYPEID constantType, + uintptr_t value); } + } +} - extern void registerStandardTypes(); +namespace emscripten { + //////////////////////////////////////////////////////////////////////////////// + // POLICIES + //////////////////////////////////////////////////////////////////////////////// - class BindingsDefinition { - public: - template<typename Function> - BindingsDefinition(Function fn) { - fn(); - } + template<int Index> + struct arg { + static constexpr int index = Index + 1; + }; + + struct ret_val { + static constexpr int index = 0; + }; + + /* + template<typename Slot> + struct allow_raw_pointer { + template<typename InputType, int Index> + struct Transform { + typedef typename std::conditional< + Index == Slot::index, + internal::AllowedRawPointer<typename std::remove_pointer<InputType>::type>, + InputType + >::type type; + }; + }; + */ + + // whitelist all raw pointers + struct allow_raw_pointers { + template<typename InputType, int Index> + struct Transform { + typedef typename std::conditional< + std::is_pointer<InputType>::value, + internal::AllowedRawPointer<typename std::remove_pointer<InputType>::type>, + InputType + >::type type; }; + }; + + // this is temporary until arg policies are reworked + template<typename Slot> + struct allow_raw_pointer : public allow_raw_pointers { + }; + + template<typename Signature> + typename std::add_pointer<Signature>::type select_overload(typename std::add_pointer<Signature>::type fn) { + return fn; + } + + namespace internal { + template<typename ClassType, typename Signature> + struct MemberFunctionType { + typedef Signature (ClassType::*type); + }; + } + + template<typename Signature, typename ClassType> + typename internal::MemberFunctionType<ClassType, Signature>::type select_overload(Signature (ClassType::*fn)) { + return fn; } -} -namespace emscripten { namespace internal { template<typename ReturnType, typename... Args> struct Invoker { static typename internal::BindingType<ReturnType>::WireType invoke( - ReturnType (fn)(Args...), + ReturnType (*fn)(Args...), typename internal::BindingType<Args>::WireType... args ) { return internal::BindingType<ReturnType>::toWireType( @@ -176,7 +259,7 @@ namespace emscripten { template<typename... Args> struct Invoker<void, Args...> { static void invoke( - void (fn)(Args...), + void (*fn)(Args...), typename internal::BindingType<Args>::WireType... args ) { return fn( @@ -186,22 +269,38 @@ namespace emscripten { }; } - template<typename ReturnType, typename... Args> - void function(const char* name, ReturnType (fn)(Args...)) { - internal::registerStandardTypes(); + //////////////////////////////////////////////////////////////////////////////// + // FUNCTIONS + //////////////////////////////////////////////////////////////////////////////// + + extern "C" { + void* __getDynamicPointerType(void* p); + } - internal::ArgTypeList<Args...> args; - internal::_embind_register_function( + template<typename ReturnType, typename... Args, typename... Policies> + void function(const char* name, ReturnType (*fn)(Args...), Policies...) { + using namespace internal; + typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, Args...> args; + _embind_register_function( name, - internal::getTypeID<ReturnType>(), args.count, args.types, - reinterpret_cast<internal::GenericFunction>(&internal::Invoker<ReturnType, Args...>::invoke), - reinterpret_cast<internal::GenericFunction>(fn)); + reinterpret_cast<GenericFunction>(&Invoker<ReturnType, Args...>::invoke), + reinterpret_cast<GenericFunction>(fn)); } namespace internal { template<typename ClassType, typename... Args> + ClassType* operator_new(Args... args) { + return new ClassType(args...); + } + + template<typename WrapperType, typename ClassType, typename... Args> + WrapperType wrapped_new(Args&&... args) { + return WrapperType(new ClassType(std::forward<Args>(args)...)); + } + + template<typename ClassType, typename... Args> ClassType* raw_constructor( typename internal::BindingType<Args>::WireType... args ) { @@ -215,302 +314,871 @@ namespace emscripten { delete ptr; } - template<typename ClassType, typename ReturnType, typename... Args> - struct MethodInvoker { - typedef ReturnType (ClassType::*MemberPointer)(Args...); + template<typename FunctionPointerType, typename ReturnType, typename ThisType, typename... Args> + struct FunctionInvoker { static typename internal::BindingType<ReturnType>::WireType invoke( - ClassType* ptr, - const MemberPointer& method, + FunctionPointerType* function, + typename internal::BindingType<ThisType>::WireType wireThis, typename internal::BindingType<Args>::WireType... args ) { return internal::BindingType<ReturnType>::toWireType( - (ptr->*method)( - internal::BindingType<Args>::fromWireType(args)... - ) + (*function)( + internal::BindingType<ThisType>::fromWireType(wireThis), + internal::BindingType<Args>::fromWireType(args)...) ); } }; - template<typename ClassType, typename... Args> - struct MethodInvoker<ClassType, void, Args...> { - typedef void (ClassType::*MemberPointer)(Args...); + template<typename FunctionPointerType, typename ThisType, typename... Args> + struct FunctionInvoker<FunctionPointerType, void, ThisType, Args...> { static void invoke( - ClassType* ptr, - const MemberPointer& method, + FunctionPointerType* function, + typename internal::BindingType<ThisType>::WireType wireThis, typename internal::BindingType<Args>::WireType... args ) { - return (ptr->*method)( - internal::BindingType<Args>::fromWireType(args)... - ); + (*function)( + internal::BindingType<ThisType>::fromWireType(wireThis), + internal::BindingType<Args>::fromWireType(args)...); } }; - template<typename ClassType, typename ReturnType, typename... Args> - struct ConstMethodInvoker { - typedef ReturnType (ClassType::*MemberPointer)(Args...) const; + template<typename MemberPointer, + typename ReturnType, + typename ThisType, + typename... Args> + struct MethodInvoker { static typename internal::BindingType<ReturnType>::WireType invoke( - const ClassType* ptr, const MemberPointer& method, + typename internal::BindingType<ThisType>::WireType wireThis, typename internal::BindingType<Args>::WireType... args ) { return internal::BindingType<ReturnType>::toWireType( - (ptr->*method)( + (internal::BindingType<ThisType>::fromWireType(wireThis)->*method)( internal::BindingType<Args>::fromWireType(args)... ) ); } }; - template<typename ClassType, typename... Args> - struct ConstMethodInvoker<ClassType, void, Args...> { - typedef void (ClassType::*MemberPointer)(Args...) const; + template<typename MemberPointer, + typename ThisType, + typename... Args> + struct MethodInvoker<MemberPointer, void, ThisType, Args...> { static void invoke( - const ClassType* ptr, const MemberPointer& method, + typename internal::BindingType<ThisType>::WireType wireThis, typename internal::BindingType<Args>::WireType... args ) { - return (ptr->*method)( + return (internal::BindingType<ThisType>::fromWireType(wireThis)->*method)( internal::BindingType<Args>::fromWireType(args)... ); } }; - template<typename ClassType, typename FieldType> - struct FieldAccess { - typedef FieldType ClassType::*MemberPointer; - typedef internal::BindingType<FieldType> FieldBinding; - typedef typename FieldBinding::WireType WireType; + template<typename InstanceType, typename MemberType> + struct MemberAccess { + typedef MemberType InstanceType::*MemberPointer; + typedef internal::BindingType<MemberType> MemberBinding; + typedef typename MemberBinding::WireType WireType; - static WireType get( - ClassType& ptr, - const MemberPointer& field + template<typename ClassType> + static WireType getWire( + const MemberPointer& field, + const ClassType& ptr ) { - return FieldBinding::toWireType(ptr.*field); + return MemberBinding::toWireType(ptr.*field); } - static void set( - ClassType& ptr, + template<typename ClassType> + static void setWire( const MemberPointer& field, + ClassType& ptr, WireType value ) { - ptr.*field = FieldBinding::fromWireType(value); + ptr.*field = MemberBinding::fromWireType(value); } + }; - template<typename Getter> - static WireType propertyGet( - ClassType& ptr, - const Getter& getter - ) { - return FieldBinding::toWireType(getter(ptr)); + // TODO: This could do a reinterpret-cast if sizeof(T) === sizeof(void*) + template<typename T> + inline void* getContext(const T& t) { + // not a leak because this is called once per binding + void* p = malloc(sizeof(T)); + assert(p); + memcpy(p, &t, sizeof(T)); + return p; + } + + template<typename T> + struct GetterPolicy; + + template<typename GetterReturnType, typename GetterThisType> + struct GetterPolicy<GetterReturnType (GetterThisType::*)() const> { + typedef GetterReturnType ReturnType; + typedef GetterReturnType (GetterThisType::*Context)() const; + + typedef internal::BindingType<ReturnType> Binding; + typedef typename Binding::WireType WireType; + + template<typename ClassType> + static WireType get(const Context& context, const ClassType& ptr) { + return Binding::toWireType((ptr.*context)()); } - template<typename Setter> - static void propertySet( - ClassType& ptr, - const Setter& setter, - WireType value - ) { - setter(ptr, FieldBinding::fromWireType(value)); + static void* getContext(Context context) { + return internal::getContext(context); + } + }; + + template<typename GetterReturnType, typename GetterThisType> + struct GetterPolicy<GetterReturnType (*)(const GetterThisType&)> { + typedef GetterReturnType ReturnType; + typedef GetterReturnType (*Context)(const GetterThisType&); + + typedef internal::BindingType<ReturnType> Binding; + typedef typename Binding::WireType WireType; + + template<typename ClassType> + static WireType get(const Context& context, const ClassType& ptr) { + return Binding::toWireType(context(ptr)); + } + + static void* getContext(Context context) { + return internal::getContext(context); + } + }; + + template<typename T> + struct SetterPolicy; + + template<typename SetterThisType, typename SetterArgumentType> + struct SetterPolicy<void (SetterThisType::*)(SetterArgumentType)> { + typedef SetterArgumentType ArgumentType; + typedef void (SetterThisType::*Context)(SetterArgumentType); + + typedef internal::BindingType<SetterArgumentType> Binding; + typedef typename Binding::WireType WireType; + + template<typename ClassType> + static void set(const Context& context, ClassType& ptr, WireType wt) { + (ptr.*context)(Binding::fromWireType(wt)); + } + + static void* getContext(Context context) { + return internal::getContext(context); + } + }; + + template<typename SetterThisType, typename SetterArgumentType> + struct SetterPolicy<void (*)(SetterThisType&, SetterArgumentType)> { + typedef SetterArgumentType ArgumentType; + typedef void (*Context)(SetterThisType&, SetterArgumentType); + + typedef internal::BindingType<SetterArgumentType> Binding; + typedef typename Binding::WireType WireType; + + template<typename ClassType> + static void set(const Context& context, ClassType& ptr, WireType wt) { + context(ptr, Binding::fromWireType(wt)); + } + + static void* getContext(Context context) { + return internal::getContext(context); } }; + + class noncopyable { + protected: + noncopyable() {} + ~noncopyable() {} + private: + noncopyable(const noncopyable&) = delete; + const noncopyable& operator=(const noncopyable&) = delete; + }; + + template<typename ClassType, typename ElementType> + typename BindingType<ElementType>::WireType get_by_index(int index, ClassType& ptr) { + return BindingType<ElementType>::toWireType(ptr[index]); + } + + template<typename ClassType, typename ElementType> + void set_by_index(int index, ClassType& ptr, typename BindingType<ElementType>::WireType wt) { + ptr[index] = BindingType<ElementType>::fromWireType(wt); + } } + template<int Index> + struct index { + }; + + //////////////////////////////////////////////////////////////////////////////// + // VALUE TUPLES + //////////////////////////////////////////////////////////////////////////////// + template<typename ClassType> - class value_tuple { + class value_tuple : public internal::noncopyable { public: value_tuple(const char* name) { - internal::registerStandardTypes(); - internal::_embind_register_tuple( - internal::getTypeID<ClassType>(), + using namespace internal; + _embind_register_tuple( + TypeID<ClassType>::get(), name, - reinterpret_cast<internal::GenericFunction>(&internal::raw_constructor<ClassType>), - reinterpret_cast<internal::GenericFunction>(&internal::raw_destructor<ClassType>)); - } - - template<typename ElementType> - value_tuple& element(ElementType ClassType::*field) { - internal::_embind_register_tuple_element( - internal::getTypeID<ClassType>(), - internal::getTypeID<ElementType>(), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::get), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::set), - sizeof(field), - &field); - - return *this; + reinterpret_cast<GenericFunction>(&raw_constructor<ClassType>), + reinterpret_cast<GenericFunction>(&raw_destructor<ClassType>)); } - template<typename ElementType> - value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, ElementType)) { - internal::_embind_register_tuple_element_accessor( - internal::getTypeID<ClassType>(), - internal::getTypeID<ElementType>(), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertyGet<ElementType(const ClassType&)>), - sizeof(getter), - &getter, - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertySet<void(ClassType&, ElementType)>), - sizeof(setter), - &setter); - return *this; + ~value_tuple() { + using namespace internal; + _embind_finalize_tuple(TypeID<ClassType>::get()); } - template<typename ElementType> - value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, const ElementType&)) { - internal::_embind_register_tuple_element_accessor( - internal::getTypeID<ClassType>(), - internal::getTypeID<ElementType>(), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertyGet<ElementType(const ClassType&)>), - sizeof(getter), - &getter, - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertySet<void(ClassType&, ElementType)>), - sizeof(setter), - &setter); + template<typename InstanceType, typename ElementType> + value_tuple& element(ElementType InstanceType::*field) { + using namespace internal; + _embind_register_tuple_element( + TypeID<ClassType>::get(), + TypeID<ElementType>::get(), + reinterpret_cast<GenericFunction>( + &MemberAccess<InstanceType, ElementType> + ::template getWire<ClassType>), + getContext(field), + TypeID<ElementType>::get(), + reinterpret_cast<GenericFunction>( + &MemberAccess<InstanceType, ElementType> + ::template setWire<ClassType>), + getContext(field)); return *this; } - template<typename ElementType> - value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, const ElementType&&)) { - internal::_embind_register_tuple_element_accessor( - internal::getTypeID<ClassType>(), - internal::getTypeID<ElementType>(), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertyGet<ElementType(const ClassType&)>), - sizeof(getter), - &getter, - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertySet<void(ClassType&, ElementType)>), - sizeof(setter), - &setter); + template<typename Getter, typename Setter> + value_tuple& element(Getter getter, Setter setter) { + using namespace internal; + typedef GetterPolicy<Getter> GP; + typedef SetterPolicy<Setter> SP; + _embind_register_tuple_element( + TypeID<ClassType>::get(), + TypeID<typename GP::ReturnType>::get(), + reinterpret_cast<GenericFunction>(&GP::template get<ClassType>), + GP::getContext(getter), + TypeID<typename SP::ArgumentType>::get(), + reinterpret_cast<GenericFunction>(&SP::template set<ClassType>), + SP::getContext(setter)); return *this; } - template<typename ElementType> - value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, ElementType&)) { - internal::_embind_register_tuple_element_accessor( - internal::getTypeID<ClassType>(), - internal::getTypeID<ElementType>(), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertyGet<ElementType(const ClassType&)>), - sizeof(getter), - &getter, - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertySet<void(ClassType&, ElementType)>), - sizeof(setter), - &setter); + template<int Index> + value_tuple& element(index<Index>) { + using namespace internal; + ClassType* null = 0; + typedef typename std::remove_reference<decltype((*null)[Index])>::type ElementType; + _embind_register_tuple_element( + TypeID<ClassType>::get(), + TypeID<ElementType>::get(), + reinterpret_cast<GenericFunction>(&internal::get_by_index<ClassType, ElementType>), + reinterpret_cast<void*>(Index), + TypeID<ElementType>::get(), + reinterpret_cast<GenericFunction>(&internal::set_by_index<ClassType, ElementType>), + reinterpret_cast<void*>(Index)); return *this; } }; + //////////////////////////////////////////////////////////////////////////////// + // VALUE STRUCTS + //////////////////////////////////////////////////////////////////////////////// + template<typename ClassType> - class value_struct { + class value_struct : public internal::noncopyable { public: value_struct(const char* name) { - internal::registerStandardTypes(); - internal::_embind_register_struct( - internal::getTypeID<ClassType>(), + using namespace internal; + _embind_register_struct( + TypeID<ClassType>::get(), name, - reinterpret_cast<internal::GenericFunction>(&internal::raw_constructor<ClassType>), - reinterpret_cast<internal::GenericFunction>(&internal::raw_destructor<ClassType>)); + reinterpret_cast<GenericFunction>(&raw_constructor<ClassType>), + reinterpret_cast<GenericFunction>(&raw_destructor<ClassType>)); + } + + ~value_struct() { + _embind_finalize_struct(internal::TypeID<ClassType>::get()); + } + + template<typename InstanceType, typename FieldType> + value_struct& field(const char* fieldName, FieldType InstanceType::*field) { + using namespace internal; + _embind_register_struct_field( + TypeID<ClassType>::get(), + fieldName, + TypeID<FieldType>::get(), + reinterpret_cast<GenericFunction>( + &MemberAccess<InstanceType, FieldType> + ::template getWire<ClassType>), + getContext(field), + TypeID<FieldType>::get(), + reinterpret_cast<GenericFunction>( + &MemberAccess<InstanceType, FieldType> + ::template setWire<ClassType>), + getContext(field)); + return *this; + } + + template<typename Getter, typename Setter> + value_struct& field( + const char* fieldName, + Getter getter, + Setter setter + ) { + using namespace internal; + typedef GetterPolicy<Getter> GP; + typedef SetterPolicy<Setter> SP; + _embind_register_struct_field( + TypeID<ClassType>::get(), + fieldName, + TypeID<typename GP::ReturnType>::get(), + reinterpret_cast<GenericFunction>(&GP::template get<ClassType>), + GP::getContext(getter), + TypeID<typename SP::ArgumentType>::get(), + reinterpret_cast<GenericFunction>(&SP::template set<ClassType>), + SP::getContext(setter)); + return *this; } - template<typename FieldType> - value_struct& field(const char* fieldName, FieldType ClassType::*field) { - internal::_embind_register_struct_field( - internal::getTypeID<ClassType>(), + template<int Index> + value_struct& field(const char* fieldName, index<Index>) { + using namespace internal; + ClassType* null = 0; + typedef typename std::remove_reference<decltype((*null)[Index])>::type ElementType; + _embind_register_struct_field( + TypeID<ClassType>::get(), fieldName, - internal::getTypeID<FieldType>(), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, FieldType>::get), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, FieldType>::set), - sizeof(field), - &field); - + TypeID<ElementType>::get(), + reinterpret_cast<GenericFunction>(&internal::get_by_index<ClassType, ElementType>), + reinterpret_cast<void*>(Index), + TypeID<ElementType>::get(), + reinterpret_cast<GenericFunction>(&internal::set_by_index<ClassType, ElementType>), + reinterpret_cast<void*>(Index)); return *this; } }; - // TODO: support class definitions without constructors. - // TODO: support external class constructors - template<typename ClassType> + //////////////////////////////////////////////////////////////////////////////// + // SMART POINTERS + //////////////////////////////////////////////////////////////////////////////// + + template<typename PointerType> + struct default_smart_ptr_trait { + static sharing_policy get_sharing_policy() { + return sharing_policy::NONE; + } + + static void* share(void* v) { + return 0; // no sharing + } + }; + + // specialize if you have a different pointer type + template<typename PointerType> + struct smart_ptr_trait : public default_smart_ptr_trait<PointerType> { + typedef typename PointerType::element_type element_type; + + static element_type* get(const PointerType& ptr) { + return ptr.get(); + } + }; + + template<typename PointeeType> + struct smart_ptr_trait<std::shared_ptr<PointeeType>> { + typedef std::shared_ptr<PointeeType> PointerType; + typedef typename PointerType::element_type element_type; + + static element_type* get(const PointerType& ptr) { + return ptr.get(); + } + + static sharing_policy get_sharing_policy() { + return sharing_policy::BY_EMVAL; + } + + static std::shared_ptr<PointeeType>* share(PointeeType* p, internal::EM_VAL v) { + return new std::shared_ptr<PointeeType>( + p, + val_deleter(val::take_ownership(v))); + } + + private: + class val_deleter { + public: + val_deleter() = delete; + explicit val_deleter(val v) + : v(v) + {} + void operator()(void const*) { + v(); + // eventually we'll need to support emptied out val + v = val::undefined(); + } + private: + val v; + }; + }; + + //////////////////////////////////////////////////////////////////////////////// + // CLASSES + //////////////////////////////////////////////////////////////////////////////// + + // abstract classes + template<typename T> + class wrapper : public T { + public: + explicit wrapper(val&& wrapped) + : wrapped(std::forward<val>(wrapped)) + {} + + template<typename ReturnType, typename... Args> + ReturnType call(const char* name, Args&&... args) const { + return Caller<ReturnType, Args...>::call(wrapped, name, std::forward<Args>(args)...); + } + + template<typename ReturnType, typename... Args, typename Default> + ReturnType optional_call(const char* name, Default def, Args&&... args) const { + if (has_function(name)) { + return Caller<ReturnType, Args...>::call(wrapped, name, std::forward<Args>(args)...); + } else { + return def(); + } + } + + private: + bool has_function(const char* name) const { + return wrapped.has_function(name); + } + + // this class only exists because you can't partially specialize function templates + template<typename ReturnType, typename... Args> + struct Caller { + static ReturnType call(const val& v, const char* name, Args&&... args) { + return v.call(name, std::forward<Args>(args)...).template as<ReturnType>(); + } + }; + + template<typename... Args> + struct Caller<void, Args...> { + static void call(const val& v, const char* name, Args&&... args) { + v.call_void(name, std::forward<Args>(args)...); + } + }; + + val wrapped; + }; + +#define EMSCRIPTEN_WRAPPER(T) \ + T(::emscripten::val&& v): wrapper(std::forward<::emscripten::val>(v)) {} + + namespace internal { + struct NoBaseClass { + template<typename ClassType> + static void verify() { + } + + static TYPEID get() { + return nullptr; + } + + template<typename ClassType> + static GenericFunction getUpcaster() { + return nullptr; + } + + template<typename ClassType> + static GenericFunction getDowncaster() { + return nullptr; + } + }; + + // NOTE: this returns the class type, not the pointer type + template<typename T> + inline TYPEID getActualType(T* ptr) { + assert(ptr); + return reinterpret_cast<TYPEID>(&typeid(*ptr)); + }; + } + + template<typename BaseClass> + struct base { + template<typename ClassType> + static void verify() { + static_assert(!std::is_same<ClassType, BaseClass>::value, "Base must not have same type as class"); + static_assert(std::is_base_of<BaseClass, ClassType>::value, "Derived class must derive from base"); + } + + static internal::TYPEID get() { + return internal::TypeID<BaseClass>::get(); + } + + template<typename ClassType> + static internal::GenericFunction getUpcaster() { + return reinterpret_cast<internal::GenericFunction>(&convertPointer<ClassType, BaseClass>); + } + + template<typename ClassType> + static internal::GenericFunction getDowncaster() { + return reinterpret_cast<internal::GenericFunction>(&convertPointer<BaseClass, ClassType>); + } + + template<typename From, typename To> + static To* convertPointer(From* ptr) { + return static_cast<To*>(ptr); + } + }; + + template<typename PointerType> + struct ptr { + typedef PointerType pointer_type; + }; + + namespace internal { + template<typename T> + struct is_ptr { + enum { value = false }; + }; + + template<typename T> + struct is_ptr<ptr<T>> { + enum { value = true }; + }; + + template<typename T> + struct SmartPtrIfNeeded { + template<typename U> + SmartPtrIfNeeded(U& cls) { + cls.template smart_ptr<T>(); + } + }; + + template<typename T> + struct SmartPtrIfNeeded<T*> { + template<typename U> + SmartPtrIfNeeded(U&) { + } + }; + }; + + template<typename ClassType, typename BaseSpecifier = internal::NoBaseClass> class class_ { public: - class_(const char* name) { - internal::registerStandardTypes(); - internal::_embind_register_class( - internal::getTypeID<ClassType>(), + class_() = delete; + + template<typename = typename std::enable_if<!internal::is_ptr<ClassType>::value>::type> + explicit class_(const char* name) { + using namespace internal; + + BaseSpecifier::template verify<ClassType>(); + + _embind_register_class( + TypeID<ClassType>::get(), + TypeID<AllowedRawPointer<ClassType>>::get(), + TypeID<AllowedRawPointer<const ClassType>>::get(), + BaseSpecifier::get(), + reinterpret_cast<GenericFunction>(&getActualType<ClassType>), + BaseSpecifier::template getUpcaster<ClassType>(), + BaseSpecifier::template getDowncaster<ClassType>(), name, - reinterpret_cast<internal::GenericFunction>(&internal::raw_destructor<ClassType>)); + reinterpret_cast<GenericFunction>(&raw_destructor<ClassType>)); + } + + template<typename PointerType> + class_& smart_ptr() { + using namespace internal; + + typedef smart_ptr_trait<PointerType> PointerTrait; + typedef typename PointerTrait::element_type PointeeType; + + static_assert(std::is_same<ClassType, typename std::remove_cv<PointeeType>::type>::value, "smart pointer must point to this class"); + + _embind_register_smart_ptr( + TypeID<PointerType>::get(), + TypeID<PointeeType>::get(), + typeid(PointerType).name(), + PointerTrait::get_sharing_policy(), + reinterpret_cast<GenericFunction>(&PointerTrait::get), + reinterpret_cast<GenericFunction>(&operator_new<PointerType>), + reinterpret_cast<GenericFunction>(&PointerTrait::share), + reinterpret_cast<GenericFunction>(&raw_destructor<PointerType>)); + return *this; + }; + + template<typename... ConstructorArgs, typename... Policies> + class_& constructor(Policies... policies) { + return constructor( + &internal::operator_new<ClassType, ConstructorArgs...>, + policies...); } - template<typename... ConstructorArgs> - class_& constructor() { - internal::ArgTypeList<ConstructorArgs...> args; - internal::_embind_register_class_constructor( - internal::getTypeID<ClassType>(), + template<typename... Args, typename... Policies> + class_& constructor(ClassType* (*factory)(Args...), Policies...) { + using namespace internal; + + typename WithPolicies<Policies...>::template ArgTypeList<AllowedRawPointer<ClassType>, Args...> args; + _embind_register_class_constructor( + TypeID<ClassType>::get(), args.count, args.types, - reinterpret_cast<internal::GenericFunction>(&internal::raw_constructor<ClassType, ConstructorArgs...>)); + reinterpret_cast<GenericFunction>(&Invoker<ClassType*, Args...>::invoke), + reinterpret_cast<GenericFunction>(factory)); return *this; } - template<typename ReturnType, typename... Args> - class_& method(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...)) { - internal::ArgTypeList<Args...> args; - internal::_embind_register_class_method( - internal::getTypeID<ClassType>(), + template<typename SmartPtr, typename... Args, typename... Policies> + class_& smart_ptr_constructor(SmartPtr (*factory)(Args...), Policies...) { + using namespace internal; + + smart_ptr<SmartPtr>(); + + typename WithPolicies<Policies...>::template ArgTypeList<SmartPtr, Args...> args; + _embind_register_class_constructor( + TypeID<ClassType>::get(), + args.count, + args.types, + reinterpret_cast<GenericFunction>(&Invoker<SmartPtr, Args...>::invoke), + reinterpret_cast<GenericFunction>(factory)); + return *this; + } + + template<typename WrapperType, typename PointerType = WrapperType*> + class_& allow_subclass() { + using namespace internal; + + auto cls = class_<WrapperType, base<ClassType>>(typeid(WrapperType).name()) + ; + SmartPtrIfNeeded<PointerType> _(cls); + + return class_function( + "implement", + &wrapped_new<PointerType, WrapperType, val>, + allow_raw_pointer<ret_val>()); + } + + template<typename ReturnType, typename... Args, typename... Policies> + class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...), Policies...) { + using namespace internal; + + typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, AllowedRawPointer<ClassType>, Args...> args; + _embind_register_class_function( + TypeID<ClassType>::get(), methodName, - internal::getTypeID<ReturnType>(), args.count, args.types, - reinterpret_cast<internal::GenericFunction>(&internal::MethodInvoker<ClassType, ReturnType, Args...>::invoke), - sizeof(memberFunction), - &memberFunction); + reinterpret_cast<GenericFunction>(&MethodInvoker<decltype(memberFunction), ReturnType, ClassType*, Args...>::invoke), + getContext(memberFunction)); return *this; } - template<typename ReturnType, typename... Args> - class_& method(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...) const) { - internal::ArgTypeList<Args...> args; - internal::_embind_register_class_method( - internal::getTypeID<ClassType>(), + template<typename ReturnType, typename... Args, typename... Policies> + class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...) const, Policies...) { + using namespace internal; + + typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, AllowedRawPointer<const ClassType>, Args...> args; + _embind_register_class_function( + TypeID<ClassType>::get(), + methodName, + args.count, + args.types, + reinterpret_cast<GenericFunction>(&MethodInvoker<decltype(memberFunction), ReturnType, const ClassType*, Args...>::invoke), + getContext(memberFunction)); + return *this; + } + + template<typename ReturnType, typename ThisType, typename... Args, typename... Policies> + class_& function(const char* methodName, ReturnType (*function)(ThisType, Args...), Policies...) { + using namespace internal; + + typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, ThisType, Args...> args; + _embind_register_class_function( + TypeID<ClassType>::get(), methodName, - internal::getTypeID<ReturnType>(), args.count, args.types, - reinterpret_cast<internal::GenericFunction>(&internal::ConstMethodInvoker<ClassType, ReturnType, Args...>::invoke), - sizeof(memberFunction), - &memberFunction); + reinterpret_cast<GenericFunction>(&FunctionInvoker<decltype(function), ReturnType, ThisType, Args...>::invoke), + getContext(function)); return *this; } - template<typename FieldType> - class_& field(const char* fieldName, FieldType ClassType::*field) { - internal::_embind_register_class_field( - internal::getTypeID<ClassType>(), + template<typename FieldType, typename = typename std::enable_if<!std::is_function<FieldType>::value>::type> + class_& property(const char* fieldName, const FieldType ClassType::*field) { + using namespace internal; + + _embind_register_class_property( + TypeID<ClassType>::get(), fieldName, - internal::getTypeID<FieldType>(), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, FieldType>::get), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, FieldType>::set), - sizeof(field), - &field); + TypeID<FieldType>::get(), + reinterpret_cast<GenericFunction>(&MemberAccess<ClassType, FieldType>::template getWire<ClassType>), + getContext(field), + 0, + 0, + 0); return *this; } - template<typename ReturnType, typename... Args> - class_& classmethod(const char* methodName, ReturnType (*classMethod)(Args...)) { - internal::ArgTypeList<Args...> args; - internal::_embind_register_class_classmethod( - internal::getTypeID<ClassType>(), + template<typename FieldType, typename = typename std::enable_if<!std::is_function<FieldType>::value>::type> + class_& property(const char* fieldName, FieldType ClassType::*field) { + using namespace internal; + + _embind_register_class_property( + TypeID<ClassType>::get(), + fieldName, + TypeID<FieldType>::get(), + reinterpret_cast<GenericFunction>(&MemberAccess<ClassType, FieldType>::template getWire<ClassType>), + getContext(field), + TypeID<FieldType>::get(), + reinterpret_cast<GenericFunction>(&MemberAccess<ClassType, FieldType>::template setWire<ClassType>), + getContext(field)); + return *this; + } + + template<typename Getter> + class_& property(const char* fieldName, Getter getter) { + using namespace internal; + typedef GetterPolicy<Getter> GP; + _embind_register_class_property( + TypeID<ClassType>::get(), + fieldName, + TypeID<typename GP::ReturnType>::get(), + reinterpret_cast<GenericFunction>(&GP::template get<ClassType>), + GP::getContext(getter), + 0, + 0, + 0); + return *this; + } + + template<typename Getter, typename Setter> + class_& property(const char* fieldName, Getter getter, Setter setter) { + using namespace internal; + typedef GetterPolicy<Getter> GP; + typedef SetterPolicy<Setter> SP; + _embind_register_class_property( + TypeID<ClassType>::get(), + fieldName, + TypeID<typename GP::ReturnType>::get(), + reinterpret_cast<GenericFunction>(&GP::template get<ClassType>), + GP::getContext(getter), + TypeID<typename SP::ArgumentType>::get(), + reinterpret_cast<GenericFunction>(&SP::template set<ClassType>), + SP::getContext(setter)); + return *this; + } + + template<typename ReturnType, typename... Args, typename... Policies> + class_& class_function(const char* methodName, ReturnType (*classMethod)(Args...), Policies...) { + using namespace internal; + + typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, Args...> args; + _embind_register_class_class_function( + TypeID<ClassType>::get(), methodName, - internal::getTypeID<ReturnType>(), args.count, args.types, - reinterpret_cast<internal::GenericFunction>(classMethod)); + reinterpret_cast<internal::GenericFunction>(&internal::Invoker<ReturnType, Args...>::invoke), + reinterpret_cast<GenericFunction>(classMethod)); return *this; } }; + //////////////////////////////////////////////////////////////////////////////// + // VECTORS + //////////////////////////////////////////////////////////////////////////////// + + namespace internal { + template<typename VectorType> + struct VectorAccess { + static val get( + const VectorType& v, + typename VectorType::size_type index + ) { + if (index < v.size()) { + return val(v[index]); + } else { + return val::undefined(); + } + } + + static bool set( + VectorType& v, + typename VectorType::size_type index, + const typename VectorType::value_type& value + ) { + v[index] = value; + return true; + } + }; + } + + template<typename T> + class_<std::vector<T>> register_vector(const char* name) { + typedef std::vector<T> VecType; + + void (VecType::*push_back)(const T&) = &VecType::push_back; + return class_<std::vector<T>>(name) + .template constructor<>() + .function("push_back", push_back) + .function("size", &VecType::size) + .function("get", &internal::VectorAccess<VecType>::get) + .function("set", &internal::VectorAccess<VecType>::set) + ; + } + + //////////////////////////////////////////////////////////////////////////////// + // MAPS + //////////////////////////////////////////////////////////////////////////////// + + namespace internal { + template<typename MapType> + struct MapAccess { + static val get( + const MapType& m, + const typename MapType::key_type& k + ) { + auto i = m.find(k); + if (i == m.end()) { + return val::undefined(); + } else { + return val(i->second); + } + } + + static void set( + MapType& m, + const typename MapType::key_type& k, + const typename MapType::mapped_type& v + ) { + m[k] = v; + } + }; + } + + template<typename K, typename V> + class_<std::map<K, V>> register_map(const char* name) { + typedef std::map<K,V> MapType; + + return class_<MapType>(name) + .template constructor<>() + .function("size", &MapType::size) + .function("get", internal::MapAccess<MapType>::get) + .function("set", internal::MapAccess<MapType>::set) + ; + } + + + //////////////////////////////////////////////////////////////////////////////// + // ENUMS + //////////////////////////////////////////////////////////////////////////////// + template<typename EnumType> class enum_ { public: enum_(const char* name) { _embind_register_enum( - internal::getTypeID<EnumType>(), + internal::TypeID<EnumType>::get(), name); } @@ -520,13 +1188,39 @@ namespace emscripten { static_assert(sizeof(value) <= sizeof(internal::GenericEnumValue), "enum type must fit in a GenericEnumValue"); _embind_register_enum_value( - internal::getTypeID<EnumType>(), + internal::TypeID<EnumType>::get(), name, static_cast<internal::GenericEnumValue>(value)); return *this; } }; + //////////////////////////////////////////////////////////////////////////////// + // CONSTANTS + //////////////////////////////////////////////////////////////////////////////// + + namespace internal { + template<typename T> + uintptr_t asGenericValue(T t) { + return static_cast<uintptr_t>(t); + } + + template<typename T> + uintptr_t asGenericValue(T* p) { + return reinterpret_cast<uintptr_t>(p); + } + } + + template<typename ConstantType> + void constant(const char* name, const ConstantType& v) { + using namespace internal; + typedef BindingType<const ConstantType&> BT; + _embind_register_constant( + name, + TypeID<const ConstantType&>::get(), + asGenericValue(BindingType<const ConstantType&>::toWireType(v))); + } + namespace internal { template<typename T> class optional { @@ -541,13 +1235,22 @@ namespace emscripten { } } - optional(const optional&) = delete; + optional(const optional& rhs) + : initialized(false) + { + *this = rhs; + } T& operator*() { assert(initialized); return *get(); } + const T& operator*() const { + assert(initialized); + return *get(); + } + explicit operator bool() const { return initialized; } @@ -560,89 +1263,47 @@ namespace emscripten { initialized = true; return *this; } - + + optional& operator=(const optional& o) { + if (initialized) { + get()->~T(); + } + if (o.initialized) { + new(get()) T(*o); + } + initialized = o.initialized; + return *this; + } + private: T* get() { return reinterpret_cast<T*>(&data); } + T const* get() const { + return reinterpret_cast<T const*>(&data); + } + bool initialized; typename std::aligned_storage<sizeof(T)>::type data; }; } +} - template<typename InterfaceType> - class wrapper : public InterfaceType { - public: - // Not necessary in any example so far, but appeases a compiler warning. - virtual ~wrapper() {} - - typedef InterfaceType interface; - - void initialize(internal::EM_VAL handle) { - if (jsobj) { - internal::_embind_fatal_error( - "Cannot initialize interface wrapper twice", - typeid(InterfaceType).name()); - } - jsobj = val::take_ownership(handle); - } - - template<typename ReturnType, typename... Args> - ReturnType call(const char* name, Args... args) { - assertInitialized(); - return Caller<ReturnType, Args...>::call(*jsobj, name, args...); - } - - private: - // this class only exists because you can't partially specialize function templates - template<typename ReturnType, typename... Args> - struct Caller { - static ReturnType call(val& v, const char* name, Args... args) { - return v.call(name, args...).template as<ReturnType>(); - } - }; - - template<typename... Args> - struct Caller<void, Args...> { - static void call(val& v, const char* name, Args... args) { - v.call(name, args...); +namespace emscripten { + namespace internal { + class BindingsDefinition { + public: + template<typename Function> + BindingsDefinition(Function fn) { + fn(); } }; - - void assertInitialized() { - if (!jsobj) { - internal::_embind_fatal_error( - "Cannot invoke call on uninitialized interface wrapper.", - typeid(InterfaceType).name()); - } - } - - internal::optional<val> jsobj; - }; - - namespace internal { - template<typename WrapperType> - WrapperType* create_interface_wrapper(EM_VAL e) { - WrapperType* p = new WrapperType; - p->initialize(e); - return p; - } } - - template<typename WrapperType> - class interface { - public: - typedef typename WrapperType::interface InterfaceType; - - interface(const char* name) { - _embind_register_interface( - internal::getTypeID<InterfaceType>(), - name, - reinterpret_cast<internal::GenericFunction>(&internal::create_interface_wrapper<WrapperType>), - reinterpret_cast<internal::GenericFunction>(&internal::raw_destructor<WrapperType>)); - } - }; } -#define EMSCRIPTEN_BINDINGS(fn) static emscripten::internal::BindingsDefinition anon_symbol(fn); +#define EMSCRIPTEN_BINDINGS(name) \ + static struct BindingInitializer_##name { \ + BindingInitializer_##name(); \ + } BindingInitializer_##name##_instance; \ + BindingInitializer_##name::BindingInitializer_##name() diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 96db9326..09cad80e 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -2,58 +2,136 @@ #include <stdint.h> // uintptr_t #include <emscripten/wire.h> +#include <vector> namespace emscripten { namespace internal { // Implemented in JavaScript. Don't call these directly. extern "C" { + void _emval_register_symbol(const char*); + typedef struct _EM_VAL* EM_VAL; void _emval_incref(EM_VAL value); void _emval_decref(EM_VAL value); + + EM_VAL _emval_new_array(); EM_VAL _emval_new_object(); - EM_VAL _emval_new_long(long value); - EM_VAL _emval_new_cstring(const char* str); - EM_VAL _emval_get_property(EM_VAL object, const char* key); - EM_VAL _emval_get_property_by_long(EM_VAL object, long key); - EM_VAL _emval_get_property_by_unsigned_long(EM_VAL object, unsigned long key); - void _emval_set_property(EM_VAL object, const char* key, EM_VAL value); - void _emval_set_property_by_int(EM_VAL object, long key, EM_VAL value); - void _emval_as(EM_VAL value, emscripten::internal::TypeID returnType); + EM_VAL _emval_undefined(); + EM_VAL _emval_null(); + EM_VAL _emval_new_cstring(const char*); + void _emval_take_value(TYPEID type/*, ...*/); + + EM_VAL _emval_new( + EM_VAL value, + unsigned argCount, + internal::TYPEID argTypes[] + /*, ... */); + + 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); + void _emval_as(EM_VAL value, TYPEID returnType); EM_VAL _emval_call( EM_VAL value, unsigned argCount, - internal::TypeID argTypes[] + internal::TYPEID argTypes[] /*, ... */); EM_VAL _emval_call_method( EM_VAL value, const char* methodName, unsigned argCount, - internal::TypeID argTypes[] + internal::TYPEID argTypes[] /*, ... */); + void _emval_call_void_method( + EM_VAL value, + const char* methodName, + unsigned argCount, + internal::TYPEID argTypes[] + /*, ...*/); + bool _emval_has_function( + EM_VAL value, + const char* methodName); } } + template<const char* address> + struct symbol_registrar { + symbol_registrar() { + internal::_emval_register_symbol(address); + } + }; + +#define EMSCRIPTEN_SYMBOL(name) \ + static const char name##_symbol[] = #name; \ + static const symbol_registrar<name##_symbol> name##_registrar + class val { public: + // missing operators: + // * delete + // * in + // * instanceof + // * typeof + // * ! ~ - + ++ -- + // * * / % + // * + - + // * << >> >>> + // * < <= > >= + // * == != === !== + // * & ^ | && || ?: + // + // exposing void, comma, and conditional is unnecessary + // same with: = += -= *= /= %= <<= >>= >>>= &= ^= |= + + static val array() { + return val(internal::_emval_new_array()); + } + static val object() { return val(internal::_emval_new_object()); - }; + } + + static val undefined() { + return val(internal::_emval_undefined()); + } + + static val null() { + return val(internal::_emval_null()); + } static val take_ownership(internal::EM_VAL e) { return val(e); } - explicit val(long l) - : handle(internal::_emval_new_long(l)) - {} + static val global(const char* name) { + return val(internal::_emval_get_global(name)); + } - explicit val(const char* str) - : handle(internal::_emval_new_cstring(str)) - {} + static val module_property(const char* name) { + return val(internal::_emval_get_module_property(name)); + } + + template<typename T> + explicit val(T&& value) { + 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))); + } val() = delete; + explicit val(const char* v) + : handle(internal::_emval_new_cstring(v)) + {} + + val(val&& v) + : handle(v.handle) + { + v.handle = 0; + } + val(const val& v) : handle(v.handle) { @@ -64,89 +142,132 @@ namespace emscripten { internal::_emval_decref(handle); } - val& operator=(const val& v) { - internal::_emval_incref(v.handle); + val& operator=(val&& v) { internal::_emval_decref(handle); handle = v.handle; + v.handle = 0; return *this; } - val get(const char* key) const { - return val(internal::_emval_get_property(handle, key)); + val& operator=(const val& v) { + internal::_emval_incref(v.handle); + internal::_emval_decref(handle); + handle = v.handle; + return *this; } - val get(int key) const { - return get(long(key)); + bool hasOwnProperty(const char* key) const { + return val::global("Object")["prototype"]["hasOwnProperty"].call("call", *this, val(key)).as<bool>(); } - val get(unsigned int key) const { - typedef unsigned long T; - return get(T(key)); - } + template<typename... Args> + val new_(Args&&... args) const { + using namespace internal; - val get(long key) const { - return val(internal::_emval_get_property_by_long(handle, key)); + WithPolicies<>::ArgTypeList<Args...> argList; + // 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( + handle, + argList.count, + argList.types, + toWireType(std::forward<Args>(args))...)); } - - val get(unsigned long key) const { - return val(internal::_emval_get_property_by_unsigned_long(handle, key)); + + template<typename T> + val operator[](const T& key) const { + return val(internal::_emval_get_property(handle, val(key).handle)); } - void set(const char* key, val v) { - internal::_emval_set_property(handle, key, v.handle); + template<typename T> + void set(const T& key, val v) { + internal::_emval_set_property(handle, val(key).handle, v.handle); } - void set(long key, val v) { - internal::_emval_set_property_by_int(handle, key, v.handle); - } + template<typename... Args> + val operator()(Args&&... args) { + using namespace internal; - template<typename ...Args> - val operator()(Args... args) { - internal::ArgTypeList<Args...> argList; - typedef internal::EM_VAL (*TypedCall)( - internal::EM_VAL, + WithPolicies<>::ArgTypeList<Args...> argList; + typedef EM_VAL (*TypedCall)( + EM_VAL, unsigned, - internal::TypeID argTypes[], - typename internal::BindingType<Args>::WireType...); - TypedCall typedCall = reinterpret_cast<TypedCall>(&internal::_emval_call); + TYPEID argTypes[], + typename BindingType<Args>::WireType...); + TypedCall typedCall = reinterpret_cast<TypedCall>(&_emval_call); return val( typedCall( handle, argList.count, argList.types, - internal::toWireType(args)...)); + toWireType(std::forward<Args>(args))...)); } template<typename ...Args> - val call(const char* name, Args... args) { - internal::ArgTypeList<Args...> argList; - typedef internal::EM_VAL (*TypedCall)( - internal::EM_VAL, + val call(const char* name, Args&&... args) const { + using namespace internal; + + WithPolicies<>::ArgTypeList<Args...> argList; + typedef EM_VAL (*TypedCall)( + EM_VAL, const char* name, unsigned, - internal::TypeID argTypes[], - typename internal::BindingType<Args>::WireType...); - TypedCall typedCall = reinterpret_cast<TypedCall>(&internal::_emval_call_method); + TYPEID argTypes[], + typename BindingType<Args>::WireType...); + TypedCall typedCall = reinterpret_cast<TypedCall>(&_emval_call_method); return val( typedCall( handle, name, argList.count, argList.types, - internal::toWireType(args)...)); + toWireType(std::forward<Args>(args))...)); + } + + template<typename ...Args> + void call_void(const char* name, Args&&... args) const { + using namespace internal; + + WithPolicies<>::ArgTypeList<Args...> argList; + typedef void (*TypedCall)( + EM_VAL, + const char* name, + unsigned, + TYPEID argTypes[], + typename BindingType<Args>::WireType...); + TypedCall typedCall = reinterpret_cast<TypedCall>(&_emval_call_void_method); + return typedCall( + handle, + name, + argList.count, + argList.types, + toWireType(std::forward<Args>(args))...); + } + + bool has_function(const char* name) const { + return _emval_has_function(handle, name); } template<typename T> T as() const { - typedef internal::BindingType<T> BT; + using namespace internal; + + typedef BindingType<T> BT; typedef typename BT::WireType (*TypedAs)( - internal::EM_VAL value, - emscripten::internal::TypeID returnType); - TypedAs typedAs = reinterpret_cast<TypedAs>(&internal::_emval_as); + EM_VAL value, + TYPEID returnType); + TypedAs typedAs = reinterpret_cast<TypedAs>(&_emval_as); - typename BT::WireType wt = typedAs(handle, internal::getTypeID<T>()); - internal::WireDeleter<T> deleter(wt); + typename BT::WireType wt = typedAs(handle, TypeID<T>::get()); + WireDeleter<T> deleter(wt); return BT::fromWireType(wt); } @@ -165,13 +286,27 @@ namespace emscripten { template<> struct BindingType<val> { typedef internal::EM_VAL WireType; - static WireType toWireType(val v) { + static WireType toWireType(const val& v) { _emval_incref(v.handle); return v.handle; } static val fromWireType(WireType v) { - return val(v); + return val::take_ownership(v); + } + static void destroy(WireType v) { } }; } + + template<typename T> + std::vector<T> vecFromJSArray(val v) { + auto l = v["length"].as<unsigned>(); + + std::vector<T> rv; + for(unsigned i = 0; i < l; ++i) { + rv.push_back(v[i].as<T>()); + } + + return rv; + }; } diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index fbf0897d..6fb15fc7 100644..100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -7,66 +7,110 @@ // // We'll call the on-the-wire type WireType. +#include <cstdlib> +#include <memory> +#include <string> + namespace emscripten { namespace internal { - typedef const struct _TypeID* TypeID; + typedef const struct _TYPEID* TYPEID; // This implementation is technically not legal, as it's not // required that two calls to typeid produce the same exact - // std::type_info instance. That said, it's likely to work. - // Should it not work in the future: replace TypeID with - // an int, and store all TypeInfo we see in a map, allocating - // new TypeIDs as we add new items to the map. + // std::type_info instance. That said, it's likely to work + // given Emscripten compiles everything into one binary. + // Should it not work in the future: replace TypeID with an + // int, and store all TypeInfo we see in a map, allocating new + // TypeIDs as we add new items to the map. template<typename T> - inline TypeID getTypeID() { - return reinterpret_cast<TypeID>(&typeid(T)); - } + struct TypeID { + static TYPEID get() { + return reinterpret_cast<TYPEID>(&typeid(T)); + } + }; - // count<> + template<typename T> + struct TypeID<std::unique_ptr<T>> { + static TYPEID get() { + return TypeID<T>::get(); + } + }; - template<typename... Args> - struct count; + template<typename T> + struct TypeID<T*> { + static_assert(!std::is_pointer<T*>::value, "Implicitly binding raw pointers is illegal. Specify allow_raw_pointer<arg<?>>"); + }; - template<> - struct count<> { - enum { value = 0 }; + template<typename T> + struct AllowedRawPointer { }; - template<typename T, typename... Args> - struct count<T, Args...> { - enum { value = 1 + count<Args...>::value }; + template<typename T> + struct TypeID<AllowedRawPointer<T>> { + static TYPEID get() { + return reinterpret_cast<TYPEID>(&typeid(T*)); + } }; + + // ExecutePolicies<> - // ArgTypeList<> + template<typename... Policies> + struct ExecutePolicies; - template<typename... Args> + template<> + struct ExecutePolicies<> { + template<typename T, int Index> + struct With { + typedef T type; + }; + }; + + template<typename Policy, typename... Remaining> + struct ExecutePolicies<Policy, Remaining...> { + template<typename T, int Index> + struct With { + typedef typename Policy::template Transform< + typename ExecutePolicies<Remaining...>::template With<T, Index>::type, + Index + >::type type; + }; + }; + + // ArgTypes<> + + template<int Index, typename... Args> struct ArgTypes; - template<> - struct ArgTypes<> { - static void fill(TypeID* argTypes) { + template<int Index> + struct ArgTypes<Index> { + template<typename... Policies> + static void fill(TYPEID* argTypes) { } }; - template<typename T, typename... Args> - struct ArgTypes<T, Args...> { - static void fill(TypeID* argTypes) { - *argTypes = getTypeID<T>(); - return ArgTypes<Args...>::fill(argTypes + 1); + template<int Index, typename T, typename... Remaining> + struct ArgTypes<Index, T, Remaining...> { + template<typename... Policies> + static void fill(TYPEID* argTypes) { + typedef typename ExecutePolicies<Policies...>::template With<T, Index>::type TransformT; + *argTypes = TypeID<TransformT>::get(); + return ArgTypes<Index + 1, Remaining...>::template fill<Policies...>(argTypes + 1); } }; - template<typename... Args> - struct ArgTypeList { - enum { args_count = count<Args...>::value }; - - ArgTypeList() { - count = args_count; - ArgTypes<Args...>::fill(types); - } + // WithPolicies<...>::ArgTypeList<...> + template<typename... Policies> + struct WithPolicies { + template<typename... Args> + struct ArgTypeList { + ArgTypeList() { + count = sizeof...(Args); + ArgTypes<0, Args...>::template fill<Policies...>(types); + } - unsigned count; - TypeID types[args_count]; + unsigned count; + TYPEID types[sizeof...(Args)]; + }; }; // BindingType<T> @@ -74,19 +118,18 @@ namespace emscripten { template<typename T> struct BindingType; -#define EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(type) \ - template<> \ - struct BindingType<type> { \ - typedef type WireType; \ - \ - constexpr static WireType toWireType(type v) { \ - return v; \ - } \ - constexpr static type fromWireType(WireType v) { \ - return v; \ - } \ - static void destroy(WireType) { \ - } \ +#define EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(type) \ + template<> \ + struct BindingType<type> { \ + typedef type WireType; \ + constexpr static WireType toWireType(const type& v) { \ + return v; \ + } \ + constexpr static type fromWireType(WireType v) { \ + return v; \ + } \ + static void destroy(WireType) { \ + } \ } EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(char); @@ -120,35 +163,75 @@ namespace emscripten { template<> struct BindingType<std::string> { - typedef char* WireType; - static WireType toWireType(std::string v) { - return strdup(v.c_str()); + typedef struct { + size_t length; + char data[1]; // trailing data + }* WireType; + static WireType toWireType(const std::string& v) { + WireType wt = (WireType)malloc(sizeof(size_t) + v.length()); + wt->length = v.length(); + memcpy(wt->data, v.data(), v.length()); + return wt; + } + static std::string fromWireType(WireType v) { + return std::string(v->data, v->length); } - static std::string fromWireType(char* v) { - return std::string(v); + static void destroy(WireType v) { + free(v); } }; template<> - struct BindingType<const std::string&> { - typedef char* WireType; - static WireType toWireType(std::string v) { - return strdup(v.c_str()); + struct BindingType<std::wstring> { + typedef struct { + size_t length; + wchar_t data[1]; // trailing data + }* WireType; + static WireType toWireType(const std::wstring& v) { + WireType wt = (WireType)malloc(sizeof(size_t) + v.length() * sizeof(wchar_t)); + wt->length = v.length(); + wmemcpy(wt->data, v.data(), v.length()); + return wt; + } + static std::wstring fromWireType(WireType v) { + return std::wstring(v->data, v->length); } - static std::string fromWireType(char* v) { - return std::string(v); + static void destroy(WireType v) { + free(v); } }; - template<typename Enum> - struct EnumBindingType { - typedef Enum WireType; + template<typename T> + struct BindingType<const T> : public BindingType<T> { + }; - static WireType toWireType(Enum v) { - return v; + template<typename T> + struct BindingType<T&> : public BindingType<T> { + }; + + template<typename T> + struct BindingType<const T&> : public BindingType<T> { + }; + + template<typename T> + struct BindingType<T&&> { + typedef typename BindingType<T>::WireType WireType; + static WireType toWireType(const T& v) { + return BindingType<T>::toWireType(v); } - static Enum fromWireType(WireType v) { - return v; + static T fromWireType(WireType wt) { + return BindingType<T>::fromWireType(wt); + } + }; + + template<typename T> + struct BindingType<T*> { + typedef T* WireType; + static WireType toWireType(T* p) { + return p; + } + static T* fromWireType(WireType wt) { + return wt; } }; @@ -157,33 +240,16 @@ namespace emscripten { typedef typename std::remove_reference<T>::type ActualT; typedef ActualT* WireType; - struct Marshaller { - explicit Marshaller(WireType wt) - : wireType(wt) - {} - - Marshaller(Marshaller&& wt) - : wireType(wt.wireType) - { - wt.wireType = 0; - } - - operator ActualT&() const { - return *wireType; - } - - private: - Marshaller() = delete; - Marshaller(const Marshaller&) = delete; - ActualT* wireType; - }; - - static WireType toWireType(T v) { + static WireType toWireType(const T& v) { return new T(v); } - static Marshaller fromWireType(WireType p) { - return Marshaller(p); + static WireType toWireType(T&& v) { + return new T(std::forward<T>(v)); + } + + static ActualT& fromWireType(WireType p) { + return *p; } static void destroy(WireType p) { @@ -191,19 +257,28 @@ namespace emscripten { } }; + // Is this necessary? template<typename T> - struct WireDeleter { + struct GenericBindingType<std::unique_ptr<T>> { typedef typename BindingType<T>::WireType WireType; - - WireDeleter(WireType wt) - : wt(wt) - {} - - ~WireDeleter() { - BindingType<T>::destroy(wt); + + static WireType toWireType(std::unique_ptr<T> p) { + return BindingType<T>::toWireType(*p); + } + }; + + template<typename Enum> + struct EnumBindingType { + typedef Enum WireType; + + static WireType toWireType(Enum v) { + return v; + } + static Enum fromWireType(WireType v) { + return v; + } + static void destroy(WireType) { } - - WireType wt; }; // catch-all generic binding @@ -215,9 +290,23 @@ namespace emscripten { {}; template<typename T> - auto toWireType(const T& v) -> typename BindingType<T>::WireType { - return BindingType<T>::toWireType(v); + auto toWireType(T&& v) -> typename BindingType<T>::WireType { + return BindingType<T>::toWireType(std::forward<T>(v)); } + template<typename T> + struct WireDeleter { + typedef typename BindingType<T>::WireType WireType; + + WireDeleter(WireType wt) + : wt(wt) + {} + + ~WireDeleter() { + BindingType<T>::destroy(wt); + } + + WireType wt; + }; } } diff --git a/system/lib/compiler-rt/LICENSE.TXT b/system/lib/compiler-rt/LICENSE.TXT new file mode 100644 index 00000000..6aab1f69 --- /dev/null +++ b/system/lib/compiler-rt/LICENSE.TXT @@ -0,0 +1,97 @@ +============================================================================== +compiler_rt License +============================================================================== + +The compiler_rt library is dual licensed under both the University of Illinois +"BSD-Like" license and the MIT license. As a user of this code you may choose +to use it under either license. As a contributor, you agree to allow your code +to be used under both. + +Full text of the relevant licenses is included below. + +============================================================================== + +University of Illinois/NCSA +Open Source License + +Copyright (c) 2009-2013 by the contributors listed in CREDITS.TXT + +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== + +Copyright (c) 2009-2013 by the contributors listed in CREDITS.TXT + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +============================================================================== +Copyrights and Licenses for Third Party Software Distributed with LLVM: +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + +The following pieces of software have additional or alternate copyrights, +licenses, and/or restrictions: + +Program Directory +------- --------- +mach_override lib/interception/mach_override diff --git a/system/lib/compiler-rt/divdi3.c b/system/lib/compiler-rt/divdi3.c new file mode 100644 index 00000000..09f4a04e --- /dev/null +++ b/system/lib/compiler-rt/divdi3.c @@ -0,0 +1,47 @@ +/* ===-- divdi3.c - Implement __divdi3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __divdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +du_int COMPILER_RT_ABI __udivmoddi4(du_int a, du_int b, du_int* rem); + +/* Returns: a / b */ + +COMPILER_RT_ABI di_int +__divdi3(di_int a, di_int b) +{ + const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1; + di_int s_a = a >> bits_in_dword_m1; /* s_a = a < 0 ? -1 : 0 */ + di_int s_b = b >> bits_in_dword_m1; /* s_b = b < 0 ? -1 : 0 */ + a = (a ^ s_a) - s_a; /* negate if s_a == -1 */ + b = (b ^ s_b) - s_b; /* negate if s_b == -1 */ + s_a ^= s_b; /*sign of quotient */ + return (__udivmoddi4(a, b, (du_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */ +} + +/* XXX EMSCRIPTEN */ + +COMPILER_RT_ABI di_int +__remdi3(di_int a, di_int b) +{ + const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1; + di_int s_a = a >> bits_in_dword_m1; /* s_a = a < 0 ? -1 : 0 */ + di_int s_b = b >> bits_in_dword_m1; /* s_b = b < 0 ? -1 : 0 */ + a = (a ^ s_a) - s_a; /* negate if s_a == -1 */ + b = (b ^ s_b) - s_b; /* negate if s_b == -1 */ + du_int rem; + __udivmoddi4(a, b, &rem); + return (rem ^ s_a) - s_a; /* negate if s_a == -1 */ +} + diff --git a/system/lib/compiler-rt/int_endianness.h b/system/lib/compiler-rt/int_endianness.h new file mode 100644 index 00000000..17905355 --- /dev/null +++ b/system/lib/compiler-rt/int_endianness.h @@ -0,0 +1,116 @@ +/* ===-- int_endianness.h - configuration header for compiler-rt ------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file is a configuration header for compiler-rt. + * This file is not part of the interface of this library. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef INT_ENDIANNESS_H +#define INT_ENDIANNESS_H + +#if defined(__SVR4) && defined(__sun) +#include <sys/byteorder.h> + +#if _BYTE_ORDER == _BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif _BYTE_ORDER == _LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif /* _BYTE_ORDER */ + +#endif /* Solaris and AuroraUX. */ + +/* .. */ + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__minix) +#include <sys/endian.h> + +#if _BYTE_ORDER == _BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif _BYTE_ORDER == _LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif /* _BYTE_ORDER */ + +#endif /* *BSD */ + +#if defined(__OpenBSD__) || defined(__Bitrig__) +#include <machine/endian.h> + +#if _BYTE_ORDER == _BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif _BYTE_ORDER == _LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif /* _BYTE_ORDER */ + +#endif /* OpenBSD and Bitrig. */ + +/* .. */ + +/* Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the compiler (at least with GCC) */ +#if defined(__APPLE__) && defined(__MACH__) || defined(__ellcc__ ) + +#ifdef __BIG_ENDIAN__ +#if __BIG_ENDIAN__ +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#endif +#endif /* __BIG_ENDIAN__ */ + +#ifdef __LITTLE_ENDIAN__ +#if __LITTLE_ENDIAN__ +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif +#endif /* __LITTLE_ENDIAN__ */ + +#endif /* Mac OSX */ + +/* .. */ + +#if defined(__linux__) +#include <endian.h> + +#if __BYTE_ORDER == __BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif /* __BYTE_ORDER */ + +#endif /* GNU/Linux */ + +#if defined(_WIN32) + +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 + +#endif /* Windows */ + +#if defined(EMSCRIPTEN) + +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 + +#endif /* emscripten */ + +/* . */ + +#if !defined(_YUGA_LITTLE_ENDIAN) || !defined(_YUGA_BIG_ENDIAN) +#error Unable to determine endian +#endif /* Check we found an endianness correctly. */ + +#endif /* INT_ENDIANNESS_H */ diff --git a/system/lib/compiler-rt/int_lib.h b/system/lib/compiler-rt/int_lib.h new file mode 100644 index 00000000..a87426c5 --- /dev/null +++ b/system/lib/compiler-rt/int_lib.h @@ -0,0 +1,46 @@ +/* ===-- int_lib.h - configuration header for compiler-rt -----------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file is a configuration header for compiler-rt. + * This file is not part of the interface of this library. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef INT_LIB_H +#define INT_LIB_H + +/* Assumption: Signed integral is 2's complement. */ +/* Assumption: Right shift of signed negative is arithmetic shift. */ +/* Assumption: Endianness is little or big (not mixed). */ + +/* ABI macro definitions */ + +#if __ARM_EABI__ +# define ARM_EABI_FNALIAS(aeabi_name, name) \ + void __aeabi_##aeabi_name() __attribute__((alias("__" #name))); +# define COMPILER_RT_ABI __attribute__((pcs("aapcs"))) +#else +# define ARM_EABI_FNALIAS(aeabi_name, name) +# define COMPILER_RT_ABI +#endif + +/* Include the standard compiler builtin headers we use functionality from. */ +#include <limits.h> +#include <stdint.h> +#include <stdbool.h> +#include <float.h> + +/* Include the commonly used internal type definitions. */ +#include "int_types.h" + +/* Include internal utility function declarations. */ +#include "int_util.h" + +#endif /* INT_LIB_H */ diff --git a/system/lib/compiler-rt/int_math.h b/system/lib/compiler-rt/int_math.h new file mode 100644 index 00000000..d6b4bdae --- /dev/null +++ b/system/lib/compiler-rt/int_math.h @@ -0,0 +1,67 @@ +/* ===-- int_math.h - internal math inlines ---------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===-----------------------------------------------------------------------=== + * + * This file is not part of the interface of this library. + * + * This file defines substitutes for the libm functions used in some of the + * compiler-rt implementations, defined in such a way that there is not a direct + * dependency on libm or math.h. Instead, we use the compiler builtin versions + * where available. This reduces our dependencies on the system SDK by foisting + * the responsibility onto the compiler. + * + * ===-----------------------------------------------------------------------=== + */ + +#ifndef INT_MATH_H +#define INT_MATH_H + +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +#define CRT_INFINITY __builtin_huge_valf() + +#define crt_isinf(x) __builtin_isinf((x)) +#define crt_isnan(x) __builtin_isnan((x)) + +/* Define crt_isfinite in terms of the builtin if available, otherwise provide + * an alternate version in terms of our other functions. This supports some + * versions of GCC which didn't have __builtin_isfinite. + */ +#if __has_builtin(__builtin_isfinite) +# define crt_isfinite(x) __builtin_isfinite((x)) +#else +# define crt_isfinite(x) \ + __extension__(({ \ + __typeof((x)) x_ = (x); \ + !crt_isinf(x_) && !crt_isnan(x_); \ + })) +#endif + +#define crt_copysign(x, y) __builtin_copysign((x), (y)) +#define crt_copysignf(x, y) __builtin_copysignf((x), (y)) +#define crt_copysignl(x, y) __builtin_copysignl((x), (y)) + +#define crt_fabs(x) __builtin_fabs((x)) +#define crt_fabsf(x) __builtin_fabsf((x)) +#define crt_fabsl(x) __builtin_fabsl((x)) + +#define crt_fmax(x, y) __builtin_fmax((x), (y)) +#define crt_fmaxf(x, y) __builtin_fmaxf((x), (y)) +#define crt_fmaxl(x, y) __builtin_fmaxl((x), (y)) + +#define crt_logb(x) __builtin_logb((x)) +#define crt_logbf(x) __builtin_logbf((x)) +#define crt_logbl(x) __builtin_logbl((x)) + +#define crt_scalbn(x, y) __builtin_scalbn((x), (y)) +#define crt_scalbnf(x, y) __builtin_scalbnf((x), (y)) +#define crt_scalbnl(x, y) __builtin_scalbnl((x), (y)) + +#endif /* INT_MATH_H */ diff --git a/system/lib/compiler-rt/int_types.h b/system/lib/compiler-rt/int_types.h new file mode 100644 index 00000000..fcce390f --- /dev/null +++ b/system/lib/compiler-rt/int_types.h @@ -0,0 +1,140 @@ +/* ===-- int_lib.h - configuration header for compiler-rt -----------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file is not part of the interface of this library. + * + * This file defines various standard types, most importantly a number of unions + * used to access parts of larger types. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef INT_TYPES_H +#define INT_TYPES_H + +#include "int_endianness.h" + +typedef int si_int; +typedef unsigned su_int; + +typedef long long di_int; +typedef unsigned long long du_int; + +typedef union +{ + di_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + su_int low; + si_int high; +#else + si_int high; + su_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} dwords; + +typedef union +{ + du_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + su_int low; + su_int high; +#else + su_int high; + su_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} udwords; + +#if __x86_64 + +typedef int ti_int __attribute__ ((mode (TI))); +typedef unsigned tu_int __attribute__ ((mode (TI))); + +typedef union +{ + ti_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + du_int low; + di_int high; +#else + di_int high; + du_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} twords; + +typedef union +{ + tu_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + du_int low; + du_int high; +#else + du_int high; + du_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} utwords; + +static inline ti_int make_ti(di_int h, di_int l) { + twords r; + r.s.high = h; + r.s.low = l; + return r.all; +} + +static inline tu_int make_tu(du_int h, du_int l) { + utwords r; + r.s.high = h; + r.s.low = l; + return r.all; +} + +#endif /* __x86_64 */ + +typedef union +{ + su_int u; + float f; +} float_bits; + +typedef union +{ + udwords u; + double f; +} double_bits; + +typedef struct +{ +#if _YUGA_LITTLE_ENDIAN + udwords low; + udwords high; +#else + udwords high; + udwords low; +#endif /* _YUGA_LITTLE_ENDIAN */ +} uqwords; + +typedef union +{ + uqwords u; + long double f; +} long_double_bits; + +#endif /* INT_TYPES_H */ + diff --git a/system/lib/compiler-rt/int_util.h b/system/lib/compiler-rt/int_util.h new file mode 100644 index 00000000..1348b85e --- /dev/null +++ b/system/lib/compiler-rt/int_util.h @@ -0,0 +1,29 @@ +/* ===-- int_util.h - internal utility functions ----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===-----------------------------------------------------------------------=== + * + * This file is not part of the interface of this library. + * + * This file defines non-inline utilities which are available for use in the + * library. The function definitions themselves are all contained in int_util.c + * which will always be compiled into any compiler-rt library. + * + * ===-----------------------------------------------------------------------=== + */ + +#ifndef INT_UTIL_H +#define INT_UTIL_H + +/** \brief Trigger a program abort (or panic for kernel code). */ +#define compilerrt_abort() compilerrt_abort_impl(__FILE__, __LINE__, \ + __FUNCTION__) + +void compilerrt_abort_impl(const char *file, int line, + const char *function) __attribute__((noreturn)); + +#endif /* INT_UTIL_H */ diff --git a/system/lib/compiler-rt/muldi3.c b/system/lib/compiler-rt/muldi3.c new file mode 100644 index 00000000..2dae44c1 --- /dev/null +++ b/system/lib/compiler-rt/muldi3.c @@ -0,0 +1,56 @@ +/* ===-- muldi3.c - Implement __muldi3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __muldi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a * b */ + +static +di_int +__muldsi3(su_int a, su_int b) +{ + dwords r; + const int bits_in_word_2 = (int)(sizeof(si_int) * CHAR_BIT) / 2; + const su_int lower_mask = (su_int)~0 >> bits_in_word_2; + r.s.low = (a & lower_mask) * (b & lower_mask); + su_int t = r.s.low >> bits_in_word_2; + r.s.low &= lower_mask; + t += (a >> bits_in_word_2) * (b & lower_mask); + r.s.low += (t & lower_mask) << bits_in_word_2; + r.s.high = t >> bits_in_word_2; + t = r.s.low >> bits_in_word_2; + r.s.low &= lower_mask; + t += (b >> bits_in_word_2) * (a & lower_mask); + r.s.low += (t & lower_mask) << bits_in_word_2; + r.s.high += t >> bits_in_word_2; + r.s.high += (a >> bits_in_word_2) * (b >> bits_in_word_2); + return r.all; +} + +/* Returns: a * b */ + +ARM_EABI_FNALIAS(lmul, muldi3) + +COMPILER_RT_ABI di_int +__muldi3(di_int a, di_int b) +{ + dwords x; + x.all = a; + dwords y; + y.all = b; + dwords r; + r.all = __muldsi3(x.s.low, y.s.low); + r.s.high += x.s.high * y.s.low + x.s.low * y.s.high; + return r.all; +} diff --git a/system/lib/compiler-rt/readme.txt b/system/lib/compiler-rt/readme.txt new file mode 100644 index 00000000..d10f53e4 --- /dev/null +++ b/system/lib/compiler-rt/readme.txt @@ -0,0 +1,20 @@ +These files are from compiler-rt, + +Last Changed Rev: 179380 +Last Changed Date: 2013-04-12 07:57:03 -0700 (Fri, 12 Apr 2013) + +=========================================================================== + +Changes: + + * add emscripten endianness to int_endianness.h + * add rem functions + +=========================================================================== + +Compile with something like + +./emcc system/lib/compiler-rt/*.c -Isystem/lib/compiler-rt/ -o rt.bc +./emcc -O2 -s ASM_JS=1 -g rt.bc -s LINKABLE=1 +manually replace Math_imul with Math.imul + diff --git a/system/lib/compiler-rt/udivdi3.c b/system/lib/compiler-rt/udivdi3.c new file mode 100644 index 00000000..3d55785c --- /dev/null +++ b/system/lib/compiler-rt/udivdi3.c @@ -0,0 +1,36 @@ +/* ===-- udivdi3.c - Implement __udivdi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __udivdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +du_int COMPILER_RT_ABI __udivmoddi4(du_int a, du_int b, du_int* rem); + +/* Returns: a / b */ + +COMPILER_RT_ABI du_int +__udivdi3(du_int a, du_int b) +{ + return __udivmoddi4(a, b, 0); +} + +/* XXX EMSCRIPTEN */ + +COMPILER_RT_ABI du_int +__uremdi3(du_int a, du_int b) +{ + du_int rem; + __udivmoddi4(a, b, &rem); + return rem; +} + diff --git a/system/lib/compiler-rt/udivmoddi4.c b/system/lib/compiler-rt/udivmoddi4.c new file mode 100644 index 00000000..57282d5b --- /dev/null +++ b/system/lib/compiler-rt/udivmoddi4.c @@ -0,0 +1,251 @@ +/* ===-- udivmoddi4.c - Implement __udivmoddi4 -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __udivmoddi4 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Effects: if rem != 0, *rem = a % b + * Returns: a / b + */ + +/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */ + +COMPILER_RT_ABI du_int +__udivmoddi4(du_int a, du_int b, du_int* rem) +{ + const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT; + const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT; + udwords n; + n.all = a; + udwords d; + d.all = b; + udwords q; + udwords r; + unsigned sr; + /* special cases, X is unknown, K != 0 */ + if (n.s.high == 0) + { + if (d.s.high == 0) + { + /* 0 X + * --- + * 0 X + */ + if (rem) + *rem = n.s.low % d.s.low; + return n.s.low / d.s.low; + } + /* 0 X + * --- + * K X + */ + if (rem) + *rem = n.s.low; + return 0; + } + /* n.s.high != 0 */ + if (d.s.low == 0) + { + if (d.s.high == 0) + { + /* K X + * --- + * 0 0 + */ + if (rem) + *rem = n.s.high % d.s.low; + return n.s.high / d.s.low; + } + /* d.s.high != 0 */ + if (n.s.low == 0) + { + /* K 0 + * --- + * K 0 + */ + if (rem) + { + r.s.high = n.s.high % d.s.high; + r.s.low = 0; + *rem = r.all; + } + return n.s.high / d.s.high; + } + /* K K + * --- + * K 0 + */ + if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */ + { + if (rem) + { + r.s.low = n.s.low; + r.s.high = n.s.high & (d.s.high - 1); + *rem = r.all; + } + return n.s.high >> __builtin_ctz(d.s.high); + } + /* K K + * --- + * K 0 + */ + sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high); + /* 0 <= sr <= n_uword_bits - 2 or sr large */ + if (sr > n_uword_bits - 2) + { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + /* 1 <= sr <= n_uword_bits - 1 */ + /* q.all = n.all << (n_udword_bits - sr); */ + q.s.low = 0; + q.s.high = n.s.low << (n_uword_bits - sr); + /* r.all = n.all >> sr; */ + r.s.high = n.s.high >> sr; + r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + } + else /* d.s.low != 0 */ + { + if (d.s.high == 0) + { + /* K X + * --- + * 0 K + */ + if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */ + { + if (rem) + *rem = n.s.low & (d.s.low - 1); + if (d.s.low == 1) + return n.all; + sr = __builtin_ctz(d.s.low); + q.s.high = n.s.high >> sr; + q.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + return q.all; + } + /* K X + * --- + *0 K + */ + sr = 1 + n_uword_bits + __builtin_clz(d.s.low) - __builtin_clz(n.s.high); + /* 2 <= sr <= n_udword_bits - 1 + * q.all = n.all << (n_udword_bits - sr); + * r.all = n.all >> sr; + * if (sr == n_uword_bits) + * { + * q.s.low = 0; + * q.s.high = n.s.low; + * r.s.high = 0; + * r.s.low = n.s.high; + * } + * else if (sr < n_uword_bits) // 2 <= sr <= n_uword_bits - 1 + * { + * q.s.low = 0; + * q.s.high = n.s.low << (n_uword_bits - sr); + * r.s.high = n.s.high >> sr; + * r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + * } + * else // n_uword_bits + 1 <= sr <= n_udword_bits - 1 + * { + * q.s.low = n.s.low << (n_udword_bits - sr); + * q.s.high = (n.s.high << (n_udword_bits - sr)) | + * (n.s.low >> (sr - n_uword_bits)); + * r.s.high = 0; + * r.s.low = n.s.high >> (sr - n_uword_bits); + * } + */ + q.s.low = (n.s.low << (n_udword_bits - sr)) & + ((si_int)(n_uword_bits - sr) >> (n_uword_bits-1)); + q.s.high = ((n.s.low << ( n_uword_bits - sr)) & + ((si_int)(sr - n_uword_bits - 1) >> (n_uword_bits-1))) | + (((n.s.high << (n_udword_bits - sr)) | + (n.s.low >> (sr - n_uword_bits))) & + ((si_int)(n_uword_bits - sr) >> (n_uword_bits-1))); + r.s.high = (n.s.high >> sr) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1)); + r.s.low = ((n.s.high >> (sr - n_uword_bits)) & + ((si_int)(n_uword_bits - sr - 1) >> (n_uword_bits-1))) | + (((n.s.high << (n_uword_bits - sr)) | + (n.s.low >> sr)) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1))); + } + else + { + /* K X + * --- + * K K + */ + sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high); + /* 0 <= sr <= n_uword_bits - 1 or sr large */ + if (sr > n_uword_bits - 1) + { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + /* 1 <= sr <= n_uword_bits */ + /* q.all = n.all << (n_udword_bits - sr); */ + q.s.low = 0; + q.s.high = n.s.low << (n_uword_bits - sr); + /* r.all = n.all >> sr; + * if (sr < n_uword_bits) + * { + * r.s.high = n.s.high >> sr; + * r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + * } + * else + * { + * r.s.high = 0; + * r.s.low = n.s.high; + * } + */ + r.s.high = (n.s.high >> sr) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1)); + r.s.low = (n.s.high << (n_uword_bits - sr)) | + ((n.s.low >> sr) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1))); + } + } + /* Not a special case + * q and r are initialized with: + * q.all = n.all << (n_udword_bits - sr); + * r.all = n.all >> sr; + * 1 <= sr <= n_udword_bits - 1 + */ + su_int carry = 0; + for (; sr > 0; --sr) + { + /* r:q = ((r:q) << 1) | carry */ + r.s.high = (r.s.high << 1) | (r.s.low >> (n_uword_bits - 1)); + r.s.low = (r.s.low << 1) | (q.s.high >> (n_uword_bits - 1)); + q.s.high = (q.s.high << 1) | (q.s.low >> (n_uword_bits - 1)); + q.s.low = (q.s.low << 1) | carry; + /* carry = 0; + * if (r.all >= d.all) + * { + * r.all -= d.all; + * carry = 1; + * } + */ + const di_int s = (di_int)(d.all - r.all - 1) >> (n_udword_bits - 1); + carry = s & 1; + r.all -= d.all & s; + } + q.all = (q.all << 1) | carry; + if (rem) + *rem = r.all; + return q.all; +} diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index b63a86aa..35d99dad 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -1,34 +1,80 @@ #include <emscripten/bind.h>
+#ifdef USE_CXA_DEMANGLE
+#include <../lib/libcxxabi/include/cxxabi.h>
+#endif
+#include <list>
+#include <vector>
+#include <typeinfo>
+#include <algorithm>
+#include <emscripten/emscripten.h>
+#include <climits>
using namespace emscripten;
-namespace emscripten {
- namespace internal {
- void registerStandardTypes() {
- static bool first = true;
- if (first) {
- first = false;
-
- _embind_register_void(getTypeID<void>(), "void");
-
- _embind_register_bool(getTypeID<bool>(), "bool", true, false);
-
- _embind_register_integer(getTypeID<char>(), "char");
- _embind_register_integer(getTypeID<signed char>(), "signed char");
- _embind_register_integer(getTypeID<unsigned char>(), "unsigned char");
- _embind_register_integer(getTypeID<signed short>(), "short");
- _embind_register_integer(getTypeID<unsigned short>(), "unsigned short");
- _embind_register_integer(getTypeID<signed int>(), "int");
- _embind_register_integer(getTypeID<unsigned int>(), "unsigned int");
- _embind_register_integer(getTypeID<signed long>(), "long");
- _embind_register_integer(getTypeID<unsigned long>(), "unsigned long");
-
- _embind_register_float(getTypeID<float>(), "float");
- _embind_register_float(getTypeID<double>(), "double");
-
- _embind_register_cstring(getTypeID<std::string>(), "std::string");
- _embind_register_emval(getTypeID<val>(), "emscripten::val");
- }
+extern "C" {
+ const char* __attribute__((used)) __getTypeName(const std::type_info* ti) {
+#ifdef USE_CXA_DEMANGLE
+ int stat;
+ char* demangled = abi::__cxa_demangle(ti->name(), NULL, NULL, &stat);
+ if (stat == 0 && demangled) {
+ return demangled;
}
+
+ switch (stat) {
+ case -1:
+ return strdup("<allocation failure>");
+ case -2:
+ return strdup("<invalid C++ symbol>");
+ case -3:
+ return strdup("<invalid argument>");
+ default:
+ return strdup("<unknown error>");
+ }
+#else
+ return strdup(ti->name());
+#endif
+ }
+}
+
+// TODO: fix in library.js or a proper emscripten libc
+extern "C" wchar_t *wmemset(wchar_t *dest, wchar_t c, size_t count) {
+ wchar_t *o = dest;
+ while (count--) {
+ *o++ = c;
+ }
+ return dest;
+}
+
+// TODO: fix in library.js or a proper emscripten libc
+extern "C" wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, size_t count) {
+ wchar_t *o = dest;
+ while (count--) {
+ *dest++ = *src++;
}
+ return dest;
+}
+
+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_float(TypeID<float>::get(), "float");
+ _embind_register_float(TypeID<double>::get(), "double");
+
+ _embind_register_std_string(TypeID<std::string>::get(), "std::string");
+ _embind_register_std_wstring(TypeID<std::wstring>::get(), sizeof(wchar_t), "std::wstring");
+ _embind_register_emval(TypeID<val>::get(), "emscripten::val");
}
|