aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChad Austin <chad@imvu.com>2013-05-03 18:20:26 -0700
committerChad Austin <chad@imvu.com>2013-05-17 12:56:48 -0700
commitfd8cbaa853ec9ea1f2c0c689e1729126c52368e4 (patch)
tree5359cad8a12b53f4d74dcd129945c6d08825a3c8
parent7f83ab2926947fda7181a7e67e76425f02da19c4 (diff)
Add support for (fast?) memory_view objects. If C++ passes a memory_view to JS, it gets converted into a typed array object on the other side. Intended for WebGL.
-rw-r--r--src/embind/embind.js30
-rw-r--r--src/embind/emval.js17
-rw-r--r--system/include/emscripten/bind.h4
-rw-r--r--system/include/emscripten/val.h1
-rw-r--r--system/include/emscripten/wire.h73
-rw-r--r--system/lib/embind/bind.cpp1
-rw-r--r--tests/embind/embind.test.js22
-rw-r--r--tests/embind/embind_test.cpp19
8 files changed, 159 insertions, 8 deletions
diff --git a/src/embind/embind.js b/src/embind/embind.js
index dfe4c014..d1508269 100644
--- a/src/embind/embind.js
+++ b/src/embind/embind.js
@@ -131,6 +131,7 @@ function extendError(baseErrorType, errorName) {
// from https://github.com/imvu/imvujs/blob/master/src/function.js
function createNamedFunction(name, body) {
+ name = makeLegalFunctionName(name);
/*jshint evil:true*/
return new Function(
"body",
@@ -453,6 +454,33 @@ function __embind_register_emval(rawType, name) {
});
}
+function __embind_register_memory_view(rawType, name) {
+ var typeMapping = [
+ Int8Array,
+ Uint8Array,
+ Int16Array,
+ Uint16Array,
+ Int32Array,
+ Uint32Array,
+ Float32Array,
+ Float64Array,
+ ];
+
+ name = readLatin1String(name);
+ registerType(rawType, {
+ name: name,
+ 'fromWireType': function(handle) {
+ var type = HEAP32[handle >> 2];
+ var size = HEAP32[(handle >> 2) + 1]; // in elements
+ var data = HEAP32[(handle >> 2) + 2]; // byte offset into emscripten heap
+ _free(handle);
+ var TA = typeMapping[type];
+ return new TA(HEAP8.buffer, data, size);
+ },
+ destructorFunction: function(ptr) { _free(ptr); },
+ });
+}
+
function runDestructors(destructors) {
while (destructors.length) {
var ptr = destructors.pop();
@@ -681,7 +709,7 @@ function __embind_finalize_tuple(rawTupleType) {
},
'toWireType': function(destructors, o) {
if (elementsLength !== o.length) {
- throw new TypeError("Incorrect number of tuple elements");
+ throw new TypeError("Incorrect number of tuple elements for " + reg.name + ": expected=" + elementsLength + ", actual=" + o.length);
}
var ptr = rawConstructor();
for (var i = 0; i < elementsLength; ++i) {
diff --git a/src/embind/emval.js b/src/embind/emval.js
index bfce63b6..96024269 100644
--- a/src/embind/emval.js
+++ b/src/embind/emval.js
@@ -1,5 +1,6 @@
/*global Module, Runtime*/
/*global HEAP32*/
+/*global createNamedFunction*/
/*global readLatin1String, writeStringToMemory*/
/*global requireRegisteredType, throwBindingError*/
@@ -192,11 +193,14 @@ function parseParameters(argCount, argTypes, argWireTypes) {
function __emval_call(handle, argCount, argTypes) {
requireHandle(handle);
+ var types = lookupTypes(argCount, argTypes);
+
+ var args = new Array(argCount);
+ for (var i = 0; i < argCount; ++i) {
+ args[i] = types[i].fromWireType(arguments[3 + i]);
+ }
+
var fn = _emval_handle_array[handle].value;
- var args = parseParameters(
- argCount,
- argTypes,
- Array.prototype.slice.call(arguments, 3));
var rv = fn.apply(undefined, args);
return __emval_register(rv);
}
@@ -214,7 +218,8 @@ function lookupTypes(argCount, argTypes, argWireTypes) {
function __emval_get_method_caller(argCount, argTypes) {
var types = lookupTypes(argCount, argTypes);
- return Runtime.addFunction(function(handle, name) {
+ var signatureName = types[0].name + "_$" + types.slice(1).map(function(t){return t.name;}).join("_") + "$";
+ return Runtime.addFunction(createNamedFunction(signatureName, function(handle, name) {
requireHandle(handle);
name = getStringOrSymbol(name);
@@ -225,7 +230,7 @@ function __emval_get_method_caller(argCount, argTypes) {
var obj = _emval_handle_array[handle].value;
return types[0].toWireType([], obj[name].apply(obj, args));
- });
+ }));
}
function __emval_has_function(handle, name) {
diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h
index d6d4f2c5..4be50c9d 100644
--- a/system/include/emscripten/bind.h
+++ b/system/include/emscripten/bind.h
@@ -59,6 +59,10 @@ namespace emscripten {
TYPEID emvalType,
const char* name);
+ void _embind_register_memory_view(
+ TYPEID memoryViewType,
+ const char* name);
+
void _embind_register_function(
const char* name,
unsigned argCount,
diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h
index 185cc935..b712d164 100644
--- a/system/include/emscripten/val.h
+++ b/system/include/emscripten/val.h
@@ -10,7 +10,6 @@ namespace emscripten {
extern "C" {
void _emval_register_symbol(const char*);
- typedef struct _EM_SIG* EM_SIG;
typedef struct _EM_VAL* EM_VAL;
void _emval_incref(EM_VAL value);
diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h
index e4ddfd04..32080e54 100644
--- a/system/include/emscripten/wire.h
+++ b/system/include/emscripten/wire.h
@@ -312,4 +312,77 @@ namespace emscripten {
WireType wt;
};
}
+
+ struct memory_view {
+ enum class Type {
+ Int8Array,
+ Uint8Array,
+ Int16Array,
+ Uint16Array,
+ Int32Array,
+ Uint32Array,
+ Float32Array,
+ Float64Array,
+ };
+
+ memory_view() = delete;
+ explicit memory_view(size_t size, const void* data)
+ : type(Type::Uint8Array)
+ , size(size)
+ , data(data)
+ {}
+ explicit memory_view(Type type, size_t size, const void* data)
+ : type(type)
+ , size(size)
+ , data(data)
+ {}
+
+ const Type type;
+ const size_t size; // in elements, not bytes
+ const void* const data;
+ };
+
+ inline memory_view typed_memory_view(size_t size, const int8_t* data) {
+ return memory_view(memory_view::Type::Int8Array, size, data);
+ }
+
+ inline memory_view typed_memory_view(size_t size, const uint8_t* data) {
+ return memory_view(memory_view::Type::Uint8Array, size, data);
+ }
+
+ inline memory_view typed_memory_view(size_t size, const int16_t* data) {
+ return memory_view(memory_view::Type::Int16Array, size, data);
+ }
+
+ inline memory_view typed_memory_view(size_t size, const uint16_t* data) {
+ return memory_view(memory_view::Type::Uint16Array, size, data);
+ }
+
+ inline memory_view typed_memory_view(size_t size, const int32_t* data) {
+ return memory_view(memory_view::Type::Int32Array, size, data);
+ }
+
+ inline memory_view typed_memory_view(size_t size, const uint32_t* data) {
+ return memory_view(memory_view::Type::Uint32Array, size, data);
+ }
+
+ inline memory_view typed_memory_view(size_t size, const float* data) {
+ return memory_view(memory_view::Type::Float32Array, size, data);
+ }
+
+ inline memory_view typed_memory_view(size_t size, const double* data) {
+ return memory_view(memory_view::Type::Float64Array, size, data);
+ }
+
+ namespace internal {
+ template<>
+ struct BindingType<memory_view> {
+ typedef memory_view* WireType;
+ static WireType toWireType(const memory_view& mv) {
+ WireType wt = (WireType)malloc(sizeof(memory_view));
+ new(wt) memory_view(mv);
+ return wt;
+ }
+ };
+ }
}
diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp
index ec1648a9..12264dfd 100644
--- a/system/lib/embind/bind.cpp
+++ b/system/lib/embind/bind.cpp
@@ -59,4 +59,5 @@ EMSCRIPTEN_BINDINGS(native_and_builtin_types) {
_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");
+ _embind_register_memory_view(TypeID<memory_view>::get(), "emscripten::memory_view");
}
diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js
index 52b2cad8..f9f035f2 100644
--- a/tests/embind/embind.test.js
+++ b/tests/embind/embind.test.js
@@ -1728,6 +1728,28 @@ module({
e.delete();
f.delete();
});
+
+ BaseFixture.extend("memory view", function() {
+ test("can pass memory view from C++ to JS", function() {
+ var views = [];
+ cm.callWithMemoryView(function(view) {
+ views.push(view);
+ });
+ assert.equal(3, views.length);
+
+ assert.instanceof(views[0], Uint8Array);
+ assert.equal(8, views[0].length);
+ assert.deepEqual([0, 1, 2, 3, 4, 5, 6, 7], [].slice.call(new Uint8Array(views[0])));
+
+ assert.instanceof(views[1], Float32Array);
+ assert.equal(4, views[1].length);
+ assert.deepEqual([1.5, 2.5, 3.5, 4.5], [].slice.call(views[1]));
+
+ assert.instanceof(views[2], Int16Array);
+ assert.equal(4, views[2].length);
+ assert.deepEqual([1000, 100, 10, 1], [].slice.call(views[2]));
+ });
+ });
});
/* global run_all_tests */
diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp
index 23761efc..e8ca0338 100644
--- a/tests/embind/embind_test.cpp
+++ b/tests/embind/embind_test.cpp
@@ -1148,6 +1148,25 @@ EMSCRIPTEN_BINDINGS(interface_tests) {
function("callDifferentArguments", &callDifferentArguments);
}
+template<typename T, size_t sizeOfArray>
+constexpr size_t getElementCount(T (&)[sizeOfArray]) {
+ return sizeOfArray;
+}
+
+static void callWithMemoryView(val v) {
+ // static so the JS test can read the memory after callTakeMemoryView runs
+ static unsigned char data[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+ v(memory_view(getElementCount(data), data));
+ static float f[] = { 1.5f, 2.5f, 3.5f, 4.5f };
+ v(typed_memory_view(getElementCount(f), f));
+ static short s[] = { 1000, 100, 10, 1 };
+ v(typed_memory_view(getElementCount(s), s));
+}
+
+EMSCRIPTEN_BINDINGS(memory_view_tests) {
+ function("callWithMemoryView", &callWithMemoryView);
+}
+
class HasExternalConstructor {
public:
HasExternalConstructor(const std::string& str)