diff options
author | Chad Austin <caustin@gmail.com> | 2014-03-22 21:10:46 -0700 |
---|---|---|
committer | Chad Austin <chad@chadaustin.me> | 2014-03-28 23:56:40 -0700 |
commit | 464f4a3cace3eba27c145d347d031930b9630a51 (patch) | |
tree | e4ebd41b75ee637d5a774e62e78830dd71d6d212 | |
parent | 555cb8207b9b06f86284a88d97a74c43e20469fb (diff) |
make val::as<> compatible with asm.js
-rw-r--r-- | src/embind/embind.js | 88 | ||||
-rw-r--r-- | src/embind/emval.js | 7 | ||||
-rw-r--r-- | system/include/emscripten/bind.h | 13 | ||||
-rw-r--r-- | system/include/emscripten/val.h | 18 | ||||
-rw-r--r-- | system/lib/embind/bind.cpp | 41 | ||||
-rw-r--r-- | tests/embind/embind.test.js | 17 | ||||
-rw-r--r-- | tests/embind/embind_test.cpp | 7 |
7 files changed, 150 insertions, 41 deletions
diff --git a/src/embind/embind.js b/src/embind/embind.js index f0cd0c74..45d48f12 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1,6 +1,6 @@ /*global Module*/ /*global _malloc, _free, _memcpy*/ -/*global FUNCTION_TABLE, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32*/ +/*global FUNCTION_TABLE, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64*/ /*global readLatin1String*/ /*global __emval_register, _emval_handle_array, __emval_decref*/ /*global ___getTypeName*/ @@ -278,7 +278,9 @@ function __embind_register_void(rawType, name) { }); } -function __embind_register_bool(rawType, name, trueValue, falseValue) { +function __embind_register_bool(rawType, name, size, trueValue, falseValue) { + var shift = getShiftFromSize(size); + name = readLatin1String(name); registerType(rawType, { name: name, @@ -290,21 +292,70 @@ function __embind_register_bool(rawType, name, trueValue, falseValue) { 'toWireType': function(destructors, o) { return o ? trueValue : falseValue; }, + writeValueToPointer: function(value, pointer, _destructors) { + var heap; + if (size === 1) { + heap = HEAP8; + } else if (size === 2) { + heap = HEAP16; + } else if (size === 4) { + heap = HEAP32; + } else { + throw new TypeError("Unknown boolean type size: " + name); + } + heap[pointer >> shift] = this['toWireType'](_destructors, value); + }, destructorFunction: null, // This type does not need a destructor }); } +function getShiftFromSize(size) { + if (size === 1) { + return 0; + } else if (size === 2) { + return 1; + } else if (size === 4) { + return 2; + } else if (size === 8) { + return 3; + } else { + throw new TypeError('Unknown type size: ' + size); + } +} + +function integerWriteValueToPointer(shift, signed) { + if (shift === 0) { + return function(value, pointer, _destructors) { + var heap = signed ? HEAP8 : HEAPU8; + heap[pointer] = this['toWireType'](_destructors, value); + }; + } else if (shift === 1) { + return function(value, pointer, _destructors) { + var heap = signed ? HEAP16 : HEAPU16; + heap[pointer >> 1] = this['toWireType'](_destructors, value); + }; + } else if (shift === 2) { + return function(value, pointer, _destructors) { + var heap = signed ? HEAP32 : HEAPU32; + heap[pointer >> 2] = this['toWireType'](_destructors, value); + }; + } else { + throw new TypeError("Unknown integer type: " + name); + } +} + // When converting a number from JS to C++ side, the valid range of the number is // [minRange, maxRange], inclusive. -function __embind_register_integer(primitiveType, name, minRange, maxRange) { +function __embind_register_integer(primitiveType, name, size, minRange, maxRange) { name = readLatin1String(name); if (maxRange === -1) { // LLVM doesn't have signed and unsigned 32-bit types, so u32 literals come out as 'i32 -1'. Always treat those as max u32. maxRange = 4294967295; } + + var shift = getShiftFromSize(size); + registerType(primitiveType, { name: name, - minRange: minRange, - maxRange: maxRange, 'fromWireType': function(value) { return value; }, @@ -319,11 +370,13 @@ function __embind_register_integer(primitiveType, name, minRange, maxRange) { } return value | 0; }, + writeValueToPointer: integerWriteValueToPointer(shift, minRange !== 0), destructorFunction: null, // This type does not need a destructor }); } -function __embind_register_float(rawType, name) { +function __embind_register_float(rawType, name, size) { + var shift = getShiftFromSize(size); name = readLatin1String(name); registerType(rawType, { name: name, @@ -338,10 +391,20 @@ function __embind_register_float(rawType, name) { } return value; }, + writeValueToPointer: function(value, pointer, _destructors) { + var heap = (shift === 2) ? HEAPF32 : HEAPF64; + heap[pointer >> shift] = this['toWireType'](_destructors, value); + }, destructorFunction: null, // This type does not need a destructor }); } +// For types whose wire types are 32-bit pointers. +function simpleWriteValueToPointer(value, pointer, destructors) { + var wt = this['toWireType'](destructors, value); + HEAPU32[pointer >> 2] = wt; +} + function __embind_register_std_string(rawType, name) { name = readLatin1String(name); registerType(rawType, { @@ -394,6 +457,7 @@ function __embind_register_std_string(rawType, name) { } return ptr; }, + writeValueToPointer: simpleWriteValueToPointer, destructorFunction: function(ptr) { _free(ptr); }, }); } @@ -434,6 +498,7 @@ function __embind_register_std_wstring(rawType, charSize, name) { } return ptr; }, + writeValueToPointer: simpleWriteValueToPointer, destructorFunction: function(ptr) { _free(ptr); }, }); } @@ -450,6 +515,7 @@ function __embind_register_emval(rawType, name) { 'toWireType': function(destructors, value) { return __emval_register(value); }, + writeValueToPointer: simpleWriteValueToPointer, destructorFunction: null, // This type does not need a destructor }); } @@ -718,6 +784,7 @@ function __embind_finalize_value_array(rawTupleType) { } return ptr; }, + writeValueToPointer: simpleWriteValueToPointer, destructorFunction: rawDestructor, }]; }); @@ -819,6 +886,7 @@ function __embind_finalize_value_object(structType) { } return ptr; }, + writeValueToPointer: simpleWriteValueToPointer, destructorFunction: rawDestructor, }]; }); @@ -1003,6 +1071,8 @@ RegisteredPointer.prototype.destructor = function(ptr) { } }; +RegisteredPointer.prototype.writeValueToPointer = simpleWriteValueToPointer; + RegisteredPointer.prototype['fromWireType'] = function(ptr) { // ptr is a raw pointer (or a raw smartpointer) @@ -1627,8 +1697,11 @@ function __embind_register_smart_ptr( function __embind_register_enum( rawType, - name + name, + size, + isSigned ) { + var shift = getShiftFromSize(size); name = readLatin1String(name); function constructor() { @@ -1644,6 +1717,7 @@ function __embind_register_enum( 'toWireType': function(destructors, c) { return c.value; }, + writeValueToPointer: integerWriteValueToPointer(shift, isSigned), destructorFunction: null, }); exposePublicSymbol(name, constructor); diff --git a/src/embind/emval.js b/src/embind/emval.js index 039f1d61..6236a32d 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -205,13 +205,16 @@ function __emval_set_property(handle, key, value) { _emval_handle_array[handle].value[_emval_handle_array[key].value] = _emval_handle_array[value].value; } -function __emval_as(handle, returnType, destructorsRef) { +function __emval_as(handle, returnType, result, destructorsRef) { requireHandle(handle); returnType = requireRegisteredType(returnType, 'emval::as'); var destructors = []; var rd = __emval_register(destructors); HEAP32[destructorsRef >> 2] = rd; - return returnType['toWireType'](destructors, _emval_handle_array[handle].value); + returnType.writeValueToPointer( + _emval_handle_array[handle].value, + result, + destructors); } function parseParameters(argCount, argTypes, argWireTypes) { diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 390533f3..5ed05994 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -35,18 +35,21 @@ namespace emscripten { void _embind_register_bool( TYPEID boolType, const char* name, + size_t size, bool trueValue, bool falseValue); void _embind_register_integer( TYPEID integerType, const char* name, + size_t size, long minRange, unsigned long maxRange); void _embind_register_float( TYPEID floatType, - const char* name); + const char* name, + size_t size); void _embind_register_std_string( TYPEID stringType, @@ -163,7 +166,9 @@ namespace emscripten { void _embind_register_enum( TYPEID enumType, - const char* name); + const char* name, + size_t size, + bool isSigned); void _embind_register_enum_value( TYPEID enumType, @@ -1182,7 +1187,9 @@ namespace emscripten { enum_(const char* name) { _embind_register_enum( internal::TypeID<EnumType>::get(), - name); + name, + sizeof(EnumType), + std::is_signed<typename std::underlying_type<EnumType>::type>::value); } enum_& value(const char* name, EnumType value) { diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 19b1beb1..49b143c1 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -13,11 +13,6 @@ namespace emscripten { typedef struct _EM_VAL* EM_VAL; typedef struct _EM_DESTRUCTORS* EM_DESTRUCTORS; - // TODO: functions returning this are reinterpret_cast - // into the correct return type. this needs some thought - // for asm.js. - typedef void _POLYMORPHIC_RESULT; - void _emval_incref(EM_VAL value); void _emval_decref(EM_VAL value); @@ -40,7 +35,7 @@ namespace emscripten { EM_VAL _emval_get_module_property(const char* name); EM_VAL _emval_get_property(EM_VAL object, EM_VAL key); void _emval_set_property(EM_VAL object, EM_VAL key, EM_VAL value); - _POLYMORPHIC_RESULT _emval_as(EM_VAL value, TYPEID returnType, EM_DESTRUCTORS* runDestructors); + void _emval_as(EM_VAL value, TYPEID returnType, void* result, EM_DESTRUCTORS* destructors); EM_VAL _emval_call( EM_VAL value, @@ -297,16 +292,11 @@ namespace emscripten { typedef BindingType<T> BT; - typedef typename BT::WireType (*TypedAs)( - EM_VAL value, - TYPEID returnType, - EM_DESTRUCTORS* runDestructors); - TypedAs typedAs = reinterpret_cast<TypedAs>(&_emval_as); - + typename BT::WireType result; EM_DESTRUCTORS destructors; - typename BT::WireType wt = typedAs(handle, TypeID<T>::get(), &destructors); + _emval_as(handle, TypeID<T>::get(), &result, &destructors); DestructorsRunner dr(destructors); - return BT::fromWireType(wt); + return BT::fromWireType(result); } private: diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 12264dfd..f43d1ea1 100644 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -8,6 +8,7 @@ #include <algorithm>
#include <emscripten/emscripten.h>
#include <climits>
+#include <limits>
using namespace emscripten;
@@ -36,25 +37,39 @@ extern "C" { }
}
+namespace {
+ template<typename T>
+ static void register_integer(const char* name) {
+ using namespace internal;
+ _embind_register_integer(TypeID<T>::get(), name, sizeof(T), std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
+ }
+
+ template<typename T>
+ static void register_float(const char* name) {
+ using namespace internal;
+ _embind_register_float(TypeID<T>::get(), name, sizeof(T));
+ }
+}
+
EMSCRIPTEN_BINDINGS(native_and_builtin_types) {
using namespace emscripten::internal;
_embind_register_void(TypeID<void>::get(), "void");
- _embind_register_bool(TypeID<bool>::get(), "bool", true, false);
-
- _embind_register_integer(TypeID<char>::get(), "char", CHAR_MIN, CHAR_MAX);
- _embind_register_integer(TypeID<signed char>::get(), "signed char", SCHAR_MIN, SCHAR_MAX);
- _embind_register_integer(TypeID<unsigned char>::get(), "unsigned char", 0, UCHAR_MAX);
- _embind_register_integer(TypeID<signed short>::get(), "short", SHRT_MIN, SHRT_MAX);
- _embind_register_integer(TypeID<unsigned short>::get(), "unsigned short", 0, USHRT_MAX);
- _embind_register_integer(TypeID<signed int>::get(), "int", INT_MIN, INT_MAX);
- _embind_register_integer(TypeID<unsigned int>::get(), "unsigned int", 0, UINT_MAX);
- _embind_register_integer(TypeID<signed long>::get(), "long", LONG_MIN, LONG_MAX);
- _embind_register_integer(TypeID<unsigned long>::get(), "unsigned long", 0, ULONG_MAX);
+ _embind_register_bool(TypeID<bool>::get(), "bool", sizeof(bool), true, false);
+
+ register_integer<char>("char");
+ register_integer<signed char>("signed char");
+ register_integer<unsigned char>("unsigned char");
+ register_integer<signed short>("short");
+ register_integer<unsigned short>("unsigned short");
+ register_integer<signed int>("int");
+ register_integer<unsigned int>("unsigned int");
+ register_integer<signed long>("long");
+ register_integer<unsigned long>("unsigned long");
- _embind_register_float(TypeID<float>::get(), "float");
- _embind_register_float(TypeID<double>::get(), "double");
+ register_float<float>("float");
+ register_float<double>("double");
_embind_register_std_string(TypeID<std::string>::get(), "std::string");
_embind_register_std_wstring(TypeID<std::wstring>::get(), sizeof(wchar_t), "std::wstring");
diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 033b47b5..64b3e889 100644 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -1939,9 +1939,10 @@ module({ // Let the memory leak test superfixture check that no leaks occurred. }); - BaseFixture.extend("val::as built-in types", function() { - test("primitives", function() { + BaseFixture.extend("val::as", function() { + test("built-ins", function() { assert.equal(true, cm.val_as_bool(true)); + assert.equal(false, cm.val_as_bool(false)); assert.equal(127, cm.val_as_char(127)); assert.equal(32767, cm.val_as_short(32767)); assert.equal(65536, cm.val_as_int(65536)); @@ -1959,6 +1960,18 @@ module({ //var ab = cm.val_as_memory_view(new ArrayBuffer(13)); //assert.equal(13, ab.byteLength); }); + + test("value types", function() { + var tuple = [1, 2, 3, 4]; + assert.deepEqual(tuple, cm.val_as_value_array(tuple)); + + var struct = {x: 1, y: 2, z: 3, w: 4}; + assert.deepEqual(struct, cm.val_as_value_object(struct)); + }); + + test("enums", function() { + assert.equal(cm.Enum.ONE, cm.val_as_enum(cm.Enum.ONE)); + }); }); }); diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 6aa543ef..2f78fa2f 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -2323,5 +2323,12 @@ EMSCRIPTEN_BINDINGS(val_as) { function("val_as_string", &val_as<std::string>); function("val_as_wstring", &val_as<std::wstring>); function("val_as_val", &val_as<val>); + + function("val_as_value_object", &val_as<StructVector>); + function("val_as_value_array", &val_as<TupleVector>); + + function("val_as_enum", &val_as<Enum>); + + // memory_view is always JS -> C++ //function("val_as_memory_view", &val_as<memory_view>); } |