aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChad Austin <caustin@gmail.com>2014-03-22 21:10:46 -0700
committerChad Austin <chad@chadaustin.me>2014-03-28 23:56:40 -0700
commit464f4a3cace3eba27c145d347d031930b9630a51 (patch)
treee4ebd41b75ee637d5a774e62e78830dd71d6d212
parent555cb8207b9b06f86284a88d97a74c43e20469fb (diff)
make val::as<> compatible with asm.js
-rw-r--r--src/embind/embind.js88
-rw-r--r--src/embind/emval.js7
-rw-r--r--system/include/emscripten/bind.h13
-rw-r--r--system/include/emscripten/val.h18
-rw-r--r--system/lib/embind/bind.cpp41
-rw-r--r--tests/embind/embind.test.js17
-rw-r--r--tests/embind/embind_test.cpp7
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>);
}