diff options
Diffstat (limited to 'tests/embind')
-rw-r--r-- | tests/embind/embind.benchmark.js | 201 | ||||
-rwxr-xr-x | tests/embind/embind.test.js | 164 | ||||
-rw-r--r-- | tests/embind/embind_benchmark.cpp | 344 | ||||
-rw-r--r-- | tests/embind/embind_test.cpp | 124 | ||||
-rw-r--r-- | tests/embind/shell.html | 94 |
5 files changed, 861 insertions, 66 deletions
diff --git a/tests/embind/embind.benchmark.js b/tests/embind/embind.benchmark.js new file mode 100644 index 00000000..4ce9355c --- /dev/null +++ b/tests/embind/embind.benchmark.js @@ -0,0 +1,201 @@ +function _increment_counter_benchmark_js(N) { + var ctr = _get_counter(); + var a = _emscripten_get_now(); + for(i = 0; i < N; ++i) { + _increment_counter(); + _increment_counter(); + _increment_counter(); + _increment_counter(); + _increment_counter(); + _increment_counter(); + _increment_counter(); + _increment_counter(); + _increment_counter(); + _increment_counter(); + } + var b = _emscripten_get_now(); + var ctr2 = _get_counter(); + Module.print("JS increment_counter " + N + " iters: " + (b-a) + " msecs. result: " + (ctr2-ctr)); +} + +function _increment_class_counter_benchmark_embind_js(N) { + var foo = new Module['Foo'](); + var a = _emscripten_get_now(); + for(i = 0; i < N; ++i) { + foo['incr_class_counter'](); + foo['incr_class_counter'](); + foo['incr_class_counter'](); + foo['incr_class_counter'](); + foo['incr_class_counter'](); + foo['incr_class_counter'](); + foo['incr_class_counter'](); + foo['incr_class_counter'](); + foo['incr_class_counter'](); + foo['incr_class_counter'](); + } + var b = _emscripten_get_now(); + Module.print("JS embind increment_class_counter " + N + " iters: " + (b-a) + " msecs. result: " + foo['class_counter_val']()); + foo['delete'](); +} + +function _returns_input_benchmark_js() { + var a = _emscripten_get_now(); + var t = 0; + for(i = 0; i < 100000; ++i) { + t += _returns_input(i); + t += _returns_input(i); + t += _returns_input(i); + t += _returns_input(i); + t += _returns_input(i); + t += _returns_input(i); + t += _returns_input(i); + t += _returns_input(i); + t += _returns_input(i); + t += _returns_input(i); + } + var b = _emscripten_get_now(); + Module.print("JS returns_input 100000 iters: " + (b-a) + " msecs. result: " + t); +} + +function _sum_int_benchmark_js() { + var a = _emscripten_get_now(); + var r = 0; + for(i = 0; i < 100000; ++i) { + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + } + var b = _emscripten_get_now(); + Module.print("JS sum_int 100000 iters: " + (b-a) + " msecs. result: " + r); +} + +function _sum_float_benchmark_js() { + var a = _emscripten_get_now(); + var r = 0; + for(i = 0; i < 100000; ++i) { + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + } + var b = _emscripten_get_now(); + Module.print("JS sum_float 100000 iters: " + (b-a) + " msecs. result: " + r); +} + +function _increment_counter_benchmark_embind_js(N) { + var ctr = _get_counter(); + var a = _emscripten_get_now(); + for(i = 0; i < N; ++i) { + Module['increment_counter'](); + Module['increment_counter'](); + Module['increment_counter'](); + Module['increment_counter'](); + Module['increment_counter'](); + Module['increment_counter'](); + Module['increment_counter'](); + Module['increment_counter'](); + Module['increment_counter'](); + Module['increment_counter'](); + } + var b = _emscripten_get_now(); + var ctr2 = _get_counter(); + Module.print("JS embind increment_counter " + N + " iters: " + (b-a) + " msecs. result: " + (ctr2-ctr)); +} + +function _returns_input_benchmark_embind_js() { + var a = _emscripten_get_now(); + var t = 0; + for(i = 0; i < 100000; ++i) { + t += Module['returns_input'](i); + t += Module['returns_input'](i); + t += Module['returns_input'](i); + t += Module['returns_input'](i); + t += Module['returns_input'](i); + t += Module['returns_input'](i); + t += Module['returns_input'](i); + t += Module['returns_input'](i); + t += Module['returns_input'](i); + t += Module['returns_input'](i); + } + var b = _emscripten_get_now(); + Module.print("JS embind returns_input 100000 iters: " + (b-a) + " msecs. result: " + t); +} + +function _sum_int_benchmark_embind_js() { + var a = _emscripten_get_now(); + var r = 0; + for(i = 0; i < 100000; ++i) { + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + } + var b = _emscripten_get_now(); + Module.print("JS embind sum_int 100000 iters: " + (b-a) + " msecs. result: " + r); +} + +function _sum_float_benchmark_embind_js() { + var a = _emscripten_get_now(); + var r = 0; + for(i = 0; i < 100000; ++i) { + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + } + var b = _emscripten_get_now(); + Module.print("JS embind sum_float 100000 iters: " + (b-a) + " msecs. result: " + r); +} + +function _move_gameobjects_benchmark_embind_js() { + var N = 10000; + var objects = []; + for(i = 0; i < N; ++i) { + objects.push(Module['create_game_object']()); + } + + var a = _emscripten_get_now(); + for(i = 0; i < N; ++i) { + var t = objects[i]['GetTransform'](); + var pos = Module['add'](t['GetPosition'](), [2, 0, 1]); + var rot = Module['add'](t['GetRotation'](), [0.1, 0.2, 0.3]); + t['SetPosition'](pos); + t['SetRotation'](rot); + t['delete'](); + } + var b = _emscripten_get_now(); + + var accum = [0,0,0]; + for(i = 0; i < N; ++i) { + var t = objects[i]['GetTransform'](); + accum = Module['add'](Module['add'](accum, t['GetPosition']()), t['GetRotation']()); + t['delete'](); + } + + Module.print("JS embind move_gameobjects " + N + " iters: " + (b-a) + " msecs. Result: " + (accum[0] + accum[1] + accum[2])); +} diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 290fed72..8ef46ad8 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -143,33 +143,49 @@ module({ var e = assert.throws(cm.BindingError, function() { cm.Derived.prototype.setMember.call(a, "foo"); }); - assert.equal('Derived.setMember incompatible with "this" of type HasTwoBases', e.message); + assert.equal('Expected null or instance of Derived, got an instance of Base2', e.message); a.delete(); + + // Base1 and Base2 both have the method 'getField()' exposed - make sure + // that calling the Base2 function with a 'this' instance of Base1 doesn't accidentally work! + var b = new cm.Base1; + var e = assert.throws(cm.BindingError, function() { + cm.Base2.prototype.getField.call(b); + }); + assert.equal('Expected null or instance of Base2, got an instance of Base1', e.message); + b.delete(); }); test("calling method with invalid this throws error", function() { var e = assert.throws(cm.BindingError, function() { cm.Derived.prototype.setMember.call(undefined, "foo"); }); - if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! - // got Error: expected: Derived.setMember with invalid "this": undefined, actual: Derived.setMember incompatible with "this" of type Object - assert.equal('Derived.setMember with invalid "this": undefined', e.message); - } + assert.equal('Cannot pass "[object global]" as a Derived*', e.message); + + var e = assert.throws(cm.BindingError, function() { + cm.Derived.prototype.setMember.call(true, "foo"); + }); + assert.equal('Cannot pass "true" as a Derived*', e.message); + + var e = assert.throws(cm.BindingError, function() { + cm.Derived.prototype.setMember.call(null, "foo"); + }); + assert.equal('Cannot pass "[object global]" as a Derived*', e.message); + + var e = assert.throws(cm.BindingError, function() { + cm.Derived.prototype.setMember.call(42, "foo"); + }); + assert.equal('Cannot pass "42" as a Derived*', e.message); var e = assert.throws(cm.BindingError, function() { cm.Derived.prototype.setMember.call("this", "foo"); }); - if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! - // TODO got 'Derived.setMember incompatible with "this" of type Object' - assert.equal('Derived.setMember with invalid "this": this', e.message); - } + assert.equal('Cannot pass "this" as a Derived*', e.message); var e = assert.throws(cm.BindingError, function() { cm.Derived.prototype.setMember.call({}, "foo"); }); - if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! - assert.equal('Derived.setMember incompatible with "this" of type Object', e.message); - } + assert.equal('Cannot pass "[object Object]" as a Derived*', e.message); }); test("setting and getting property on unrelated class throws error", function() { @@ -388,6 +404,59 @@ module({ }); }); + BaseFixture.extend("string", function() { + test("non-ascii strings", function() { + var expected = ''; + for (var i = 0; i < 128; ++i) { + expected += String.fromCharCode(128 + i); + } + assert.equal(expected, cm.get_non_ascii_string()); + }); + + test("passing non-8-bit strings from JS to std::string throws", function() { + assert.throws(cm.BindingError, function() { + cm.emval_test_take_and_return_std_string("\u1234"); + }); + }); + + test("can't pass integers as strings", function() { + var e = assert.throws(cm.BindingError, function() { + cm.emval_test_take_and_return_std_string(10); + }); + }); + + test("can pass Uint8Array to std::string", function() { + var e = cm.emval_test_take_and_return_std_string(new Uint8Array([65, 66, 67, 68])); + assert.equal('ABCD', e); + }); + + test("can pass Int8Array to std::string", function() { + var e = cm.emval_test_take_and_return_std_string(new Int8Array([65, 66, 67, 68])); + assert.equal('ABCD', e); + }); + + test("can pass ArrayBuffer to std::string", function() { + var e = cm.emval_test_take_and_return_std_string((new Int8Array([65, 66, 67, 68])).buffer); + assert.equal('ABCD', e); + }); + + test("non-ascii wstrings", function() { + var expected = String.fromCharCode(10) + + String.fromCharCode(1234) + + String.fromCharCode(2345) + + String.fromCharCode(65535); + assert.equal(expected, cm.get_non_ascii_wstring()); + }); + + test("passing unicode string into C++", function() { + var expected = String.fromCharCode(10) + + String.fromCharCode(1234) + + String.fromCharCode(2345) + + String.fromCharCode(65535); + assert.equal(expected, cm.take_and_return_std_wstring(expected)); + }); + }); + BaseFixture.extend("embind", function() { test("value creation", function() { assert.equal(15, cm.emval_test_new_integer()); @@ -837,6 +906,37 @@ module({ assert.equal(0, cm.count_emval_handles()); }); + test("class properties can be methods", function() { + var a = {}; + var b = {foo: 'foo'}; + var c = new cm.ValHolder(a); + assert.equal(a, c.val); + c.val = b; + assert.equal(b, c.val); + c.delete(); + }); + + test("class properties can be read-only", function() { + var a = {}; + var h = new cm.ValHolder(a); + assert.equal(a, h.val_readonly); + var e = assert.throws(cm.BindingError, function() { + h.val_readonly = 10; + }); + assert.equal('ValHolder.val_readonly is a read-only property', e.message); + h.delete(); + }); + + test("read-only member field", function() { + var a = new cm.HasReadOnlyProperty(10); + assert.equal(10, a.i); + var e = assert.throws(cm.BindingError, function() { + a.i = 20; + }); + assert.equal('HasReadOnlyProperty.i is a read-only property', e.message); + a.delete(); + }); + test("class instance $$ property is non-enumerable", function() { var c = new cm.ValHolder(undefined); assert.deepEqual([], Object.keys(c)); @@ -1415,24 +1515,6 @@ module({ }); }); - BaseFixture.extend("JavaScript interface", function() { - this.setUp(function() { - this.testobj = { - "method1": function() { return 111; }, - "method2": function() { return 222; } - }; - }); - - test("pass js object to c++ and call its method", function() { - var obj = new cm.JSInterfaceHolder(this.testobj); - assert.equal(111, obj.callMethod("method1")); - assert.equal(222, obj.callMethod("method2")); - assert.equal(111, obj.callMethodUsingSharedPtr("method1")); - assert.equal(222, obj.callMethodUsingSharedPtr("method2")); - obj.delete(); - }); - }); - BaseFixture.extend("abstract methods", function() { test("can call abstract methods", function() { var obj = cm.getAbstractClass(); @@ -1454,6 +1536,28 @@ module({ assert.equal(expected, cm.callAbstractMethod(impl)); impl.delete(); }); + + test("can implement optional methods in JavaScript", function() { + var expected = "my JS string"; + function MyImplementation() { + this.rv = expected; + } + MyImplementation.prototype.optionalMethod = function() { + return this.rv; + }; + + var impl = cm.AbstractClass.implement(new MyImplementation); + assert.equal(expected, impl.optionalMethod(expected)); + assert.equal(expected, cm.callOptionalMethod(impl, expected)); + impl.delete(); + }); + + test("if not implemented then optional method runs default", function() { + var impl = cm.AbstractClass.implement({}); + assert.equal("optionalfoo", impl.optionalMethod("foo")); + assert.equal("optionalfoo", cm.callOptionalMethod(impl, "foo")); + impl.delete(); + }); }); BaseFixture.extend("registration order", function() { diff --git a/tests/embind/embind_benchmark.cpp b/tests/embind/embind_benchmark.cpp new file mode 100644 index 00000000..80abc7e7 --- /dev/null +++ b/tests/embind/embind_benchmark.cpp @@ -0,0 +1,344 @@ +#include <stdio.h> +#include <emscripten.h> +#include <bind.h> +#include <memory> + +int counter = 0; + +extern "C" +{ + +int __attribute__((noinline)) get_counter() +{ + return counter; +} + +void __attribute__((noinline)) increment_counter() +{ + ++counter; +} + +int __attribute__((noinline)) sum_int(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int v9) +{ + return v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9; +} + +float __attribute__((noinline)) sum_float(float v1, float v2, float v3, float v4, float v5, float v6, float v7, float v8, float v9) +{ + return v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9; +} + +int __attribute__((noinline)) returns_input(int i) +{ + return i; +} + +extern void increment_counter_benchmark_js(int N); +extern void returns_input_benchmark_js(); +extern void sum_int_benchmark_js(); +extern void sum_float_benchmark_js(); + +extern void increment_counter_benchmark_embind_js(int N); +extern void returns_input_benchmark_embind_js(); +extern void sum_int_benchmark_embind_js(); +extern void sum_float_benchmark_embind_js(); + +extern void increment_class_counter_benchmark_embind_js(int N); +extern void move_gameobjects_benchmark_embind_js(); +} + +class Vec3 +{ +public: + Vec3():x(0),y(0),z(0) {} + Vec3(float x_, float y_, float z_):x(x_),y(y_),z(z_) {} + float x,y,z; +}; + +Vec3 add(const Vec3 &lhs, const Vec3 &rhs) { return Vec3(lhs.x+rhs.x, lhs.y+rhs.y, lhs.z+rhs.z); } + +class Transform +{ +public: + Transform():scale(1) {} + + Vec3 pos; + Vec3 rot; + float scale; + + Vec3 __attribute__((noinline)) GetPosition() const { return pos; } + Vec3 __attribute__((noinline)) GetRotation() const { return rot; } + float __attribute__((noinline)) GetScale() const { return scale; } + + void __attribute__((noinline)) SetPosition(const Vec3 &pos_) { pos = pos_; } + void __attribute__((noinline)) SetRotation(const Vec3 &rot_) { rot = rot_; } + void __attribute__((noinline)) SetScale(float scale_) { scale = scale_; } +}; +typedef std::shared_ptr<Transform> TransformPtr; + +class GameObject +{ +public: + GameObject() + { + transform = std::make_shared<Transform>(); + } + std::shared_ptr<Transform> transform; + + TransformPtr __attribute__((noinline)) GetTransform() const { return transform; } +}; +typedef std::shared_ptr<GameObject> GameObjectPtr; + +GameObjectPtr create_game_object() +{ + return std::make_shared<GameObject>(); +} + +class Foo +{ +public: + Foo() + :class_counter(0) + { + } + + void __attribute__((noinline)) incr_global_counter() + { + ++counter; + } + + void __attribute__((noinline)) incr_class_counter() + { + ++class_counter; + } + + int class_counter_val() const + { + return class_counter; + } + + int class_counter; +}; + +EMSCRIPTEN_BINDINGS(benchmark) +{ + using namespace emscripten; + + class_<GameObject>("GameObject") + .smart_ptr<GameObjectPtr>() + .function("GetTransform", &GameObject::GetTransform); + + class_<Transform>("Transform") + .smart_ptr<TransformPtr>() + .function("GetPosition", &Transform::GetPosition) + .function("GetRotation", &Transform::GetRotation) + .function("GetScale", &Transform::GetScale) + .function("SetPosition", &Transform::SetPosition) + .function("SetRotation", &Transform::SetRotation) + .function("SetScale", &Transform::SetScale); + + value_tuple<Vec3>("Vec3") + .element(&Vec3::x) + .element(&Vec3::y) + .element(&Vec3::z); + + function("create_game_object", &create_game_object); + function("add", &add); + + function("get_counter", &get_counter); + function("increment_counter", &increment_counter); + function("returns_input", &returns_input); + function("sum_int", &sum_int); + function("sum_float", &sum_float); + + class_<Foo>("Foo") + .constructor<>() + .function("incr_global_counter", &Foo::incr_global_counter) + .function("incr_class_counter", &Foo::incr_class_counter) + .function("class_counter_val", &Foo::class_counter_val); +} + +void __attribute__((noinline)) emscripten_get_now_benchmark(int N) +{ + volatile float t = emscripten_get_now(); + for(int i = 0; i < N; ++i) + { + emscripten_get_now(); + emscripten_get_now(); + emscripten_get_now(); + emscripten_get_now(); + emscripten_get_now(); + emscripten_get_now(); + emscripten_get_now(); + emscripten_get_now(); + emscripten_get_now(); + emscripten_get_now(); + } + volatile float t2 = emscripten_get_now(); + printf("C++ emscripten_get_now %d iters: %f msecs.\n", N, (t2-t)); +} + +void __attribute__((noinline)) increment_counter_benchmark(int N) +{ + volatile float t = emscripten_get_now(); + for(int i = 0; i < N; ++i) + { + increment_counter(); + increment_counter(); + increment_counter(); + increment_counter(); + increment_counter(); + increment_counter(); + increment_counter(); + increment_counter(); + increment_counter(); + increment_counter(); + } + volatile float t2 = emscripten_get_now(); + printf("C++ increment_counter %d iters: %f msecs.\n", N, (t2-t)); +} + +void __attribute__((noinline)) increment_class_counter_benchmark(int N) +{ + Foo foo; + volatile float t = emscripten_get_now(); + for(int i = 0; i < N; ++i) + { + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + } + volatile float t2 = emscripten_get_now(); + printf("C++ increment_class_counter %d iters: %f msecs. result: %d\n", N, (t2-t), foo.class_counter); +} + +void __attribute__((noinline)) returns_input_benchmark() +{ + volatile int r = 0; + volatile float t = emscripten_get_now(); + for(int i = 0; i < 100000; ++i) + { + r += returns_input(i); + r += returns_input(i); + r += returns_input(i); + r += returns_input(i); + r += returns_input(i); + r += returns_input(i); + r += returns_input(i); + r += returns_input(i); + r += returns_input(i); + r += returns_input(i); + } + volatile float t2 = emscripten_get_now(); + printf("C++ returns_input 100000 iters: %f msecs.\n", (t2-t)); +} + +void __attribute__((noinline)) sum_int_benchmark() +{ + volatile float t = emscripten_get_now(); + volatile int r = 0; + for(int i = 0; i < 100000; ++i) + { + r += sum_int(i,2,3,4,5,6,7,8,9); + r += sum_int(i,2,3,4,5,6,7,8,9); + r += sum_int(i,2,3,4,5,6,7,8,9); + r += sum_int(i,2,3,4,5,6,7,8,9); + r += sum_int(i,2,3,4,5,6,7,8,9); + r += sum_int(i,2,3,4,5,6,7,8,9); + r += sum_int(i,2,3,4,5,6,7,8,9); + r += sum_int(i,2,3,4,5,6,7,8,9); + r += sum_int(i,2,3,4,5,6,7,8,9); + r += sum_int(i,2,3,4,5,6,7,8,9); + } + volatile float t2 = emscripten_get_now(); + printf("C++ sum_int 100000 iters: %f msecs.\n", (t2-t)); +} + +void __attribute__((noinline)) sum_float_benchmark() +{ + volatile float f = 0.f; + volatile float t = emscripten_get_now(); + for(int i = 0; i < 100000; ++i) + { + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + } + volatile float t2 = emscripten_get_now(); + printf("C++ sum_float 100000 iters: %f msecs.\n", (t2-t)); +} + +void __attribute__((noinline)) move_gameobjects_benchmark() +{ + const int N = 10000; + GameObjectPtr objects[N]; + for(int i = 0; i < N; ++i) + objects[i] = create_game_object(); + + volatile float t = emscripten_get_now(); + for(int i = 0; i < N; ++i) + { + TransformPtr t = objects[i]->GetTransform(); + Vec3 pos = add(t->GetPosition(), Vec3(2.f, 0.f, 1.f)); + Vec3 rot = add(t->GetRotation(), Vec3(0.1f, 0.2f, 0.3f)); + t->SetPosition(pos); + t->SetRotation(rot); + } + volatile float t2 = emscripten_get_now(); + + Vec3 accum; + for(int i = 0; i < N; ++i) + accum = add(add(accum, objects[i]->GetTransform()->GetPosition()), objects[i]->GetTransform()->GetRotation()); + printf("C++ move_gameobjects %d iters: %f msecs. Result: %f\n", N, (t2-t), accum.x+accum.y+accum.z); +} + +int main() +{ + for(int i = 1000; i <= 100000; i *= 10) + emscripten_get_now_benchmark(i); + + printf("\n"); + for(int i = 1000; i <= 100000; i *= 10) + { + increment_counter_benchmark(i); + increment_counter_benchmark_js(i); + increment_counter_benchmark_embind_js(i); + printf("\n"); + } + + for(int i = 1000; i <= 100000; i *= 10) + { + increment_class_counter_benchmark(i); + increment_class_counter_benchmark_embind_js(i); + printf("\n"); + } + + returns_input_benchmark(); + returns_input_benchmark_js(); + returns_input_benchmark_embind_js(); + printf("\n"); + sum_int_benchmark(); + sum_int_benchmark_js(); + sum_int_benchmark_embind_js(); + printf("\n"); + sum_float_benchmark(); + sum_float_benchmark_js(); + sum_float_benchmark_embind_js(); + printf("\n"); + move_gameobjects_benchmark(); + move_gameobjects_benchmark_embind_js(); +} diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 1384406a..f2359955 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -79,6 +79,24 @@ unsigned emval_test_sum(val v) { return rv;
}
+std::string get_non_ascii_string() {
+ char c[128 + 1];
+ c[128] = 0;
+ for (int i = 0; i < 128; ++i) {
+ c[i] = 128 + i;
+ }
+ return c;
+}
+
+std::wstring get_non_ascii_wstring() {
+ std::wstring ws(4, 0);
+ ws[0] = 10;
+ ws[1] = 1234;
+ ws[2] = 2345;
+ ws[3] = 65535;
+ return ws;
+}
+
std::string emval_test_take_and_return_const_char_star(const char* str) {
return str;
}
@@ -91,6 +109,10 @@ std::string emval_test_take_and_return_std_string_const_ref(const std::string& s return str;
}
+std::wstring take_and_return_std_wstring(std::wstring str) {
+ return str;
+}
+
std::function<std::string (std::string)> emval_test_get_function_ptr() {
return emval_test_take_and_return_std_string;
}
@@ -651,8 +673,6 @@ private: std::string name_;
};
-// todo: does it need to be polymorphic?
-// todo: virtual diamond pattern
class PolyDiamondBase {
public:
PolyDiamondBase():
@@ -1043,20 +1063,6 @@ std::vector<std::shared_ptr<StringHolder>> emval_test_return_shared_ptr_vector() return sharedStrVector;
}
-class JSInterfaceHolder {
-public:
- JSInterfaceHolder(JSInterface &jsobj) : jsobj_(jsobj) {
- ptr_ = JSInterface::cloneToSharedPtr(jsobj_);
- }
-
- int callMethod(std::string method) { return jsobj_.call<int>(method.c_str()); }
- int callMethodUsingSharedPtr(std::string method) { return ptr_->call<int>(method.c_str()); }
-
-private:
- JSInterface jsobj_;
- std::shared_ptr<JSInterface> ptr_;
-};
-
void test_string_with_vec(const std::string& p1, std::vector<std::string>& v1) {
// THIS DOES NOT WORK -- need to get as val and then call vecFromJSArray
printf("%s\n", p1.c_str());
@@ -1074,8 +1080,13 @@ class AbstractClass { public:
virtual ~AbstractClass() {}
virtual std::string abstractMethod() const = 0;
+ virtual std::string optionalMethod(std::string s) const {
+ return "optional" + s;
+ }
};
+EMSCRIPTEN_SYMBOL(optionalMethod);
+
class AbstractClassWrapper : public wrapper<AbstractClass> {
public:
EMSCRIPTEN_WRAPPER(AbstractClassWrapper);
@@ -1083,6 +1094,11 @@ public: std::string abstractMethod() const {
return call<std::string>("abstractMethod");
}
+ std::string optionalMethod(std::string s) const {
+ return optional_call<std::string>(optionalMethod_symbol, [&] {
+ return AbstractClass::optionalMethod(s);
+ }, s);
+ }
};
class ConcreteClass : public AbstractClass {
@@ -1099,6 +1115,10 @@ std::string callAbstractMethod(AbstractClass& ac) { return ac.abstractMethod();
}
+std::string callOptionalMethod(AbstractClass& ac, std::string s) {
+ return ac.optionalMethod(s);
+}
+
class HasExternalConstructor {
public:
HasExternalConstructor(const std::string& str)
@@ -1454,8 +1474,6 @@ EMSCRIPTEN_BINDINGS(constants) { }
EMSCRIPTEN_BINDINGS(tests) {
- register_js_interface();
-
register_vector<int>("IntegerVector");
register_vector<char>("CharVector");
register_vector<unsigned>("VectorUnsigned");
@@ -1481,9 +1499,12 @@ EMSCRIPTEN_BINDINGS(tests) { function("const_ref_adder", &const_ref_adder);
function("emval_test_sum", &emval_test_sum);
+ function("get_non_ascii_string", &get_non_ascii_string);
+ function("get_non_ascii_wstring", &get_non_ascii_wstring);
//function("emval_test_take_and_return_const_char_star", &emval_test_take_and_return_const_char_star);
function("emval_test_take_and_return_std_string", &emval_test_take_and_return_std_string);
function("emval_test_take_and_return_std_string_const_ref", &emval_test_take_and_return_std_string_const_ref);
+ function("take_and_return_std_wstring", &take_and_return_std_wstring);
//function("emval_test_take_and_return_CustomStruct", &emval_test_take_and_return_CustomStruct);
@@ -1527,6 +1548,8 @@ EMSCRIPTEN_BINDINGS(tests) { .function("getConstVal", &ValHolder::getConstVal)
.function("getValConstRef", &ValHolder::getValConstRef)
.function("setVal", &ValHolder::setVal)
+ .property("val", &ValHolder::getVal, &ValHolder::setVal)
+ .property("val_readonly", &ValHolder::getVal)
.class_function("makeConst", &ValHolder::makeConst, allow_raw_pointer<ret_val>())
.class_function("makeValHolder", &ValHolder::makeValHolder)
.class_function("some_class_method", &ValHolder::some_class_method)
@@ -1550,7 +1573,7 @@ EMSCRIPTEN_BINDINGS(tests) { class_<std::function<std::string(std::string)>>("StringFunctorString")
.constructor<>()
- .calloperator<std::string, std::string>("opcall")
+ .function("opcall", &std::function<std::string(std::string)>::operator())
;
function("emval_test_get_function_ptr", &emval_test_get_function_ptr);
@@ -1790,6 +1813,11 @@ EMSCRIPTEN_BINDINGS(tests) { function("embind_attempt_to_modify_smart_pointer_when_passed_by_value", embind_attempt_to_modify_smart_pointer_when_passed_by_value);
function("embind_save_smart_base_pointer", embind_save_smart_base_pointer);
+ class_<Base1>("Base1")
+ .constructor()
+ .function("getField", &Base1::getField)
+ ;
+
class_<Base2>("Base2")
.function("getField", &Base2::getField)
.property("field", &Base2::field2)
@@ -1845,12 +1873,6 @@ EMSCRIPTEN_BINDINGS(tests) { register_map<std::string, int>("StringIntMap");
function("embind_test_get_string_int_map", embind_test_get_string_int_map);
- class_<JSInterfaceHolder>("JSInterfaceHolder")
- .constructor<JSInterface&>()
- .function("callMethod", &JSInterfaceHolder::callMethod)
- .function("callMethodUsingSharedPtr", &JSInterfaceHolder::callMethodUsingSharedPtr)
- ;
-
function("embind_test_new_Object", &embind_test_new_Object);
function("embind_test_new_factory", &embind_test_new_factory);
@@ -1858,10 +1880,12 @@ EMSCRIPTEN_BINDINGS(tests) { .smart_ptr<std::shared_ptr<AbstractClass>>()
.allow_subclass<AbstractClassWrapper>()
.function("abstractMethod", &AbstractClass::abstractMethod)
+ .function("optionalMethod", &AbstractClass::optionalMethod)
;
function("getAbstractClass", &getAbstractClass);
function("callAbstractMethod", &callAbstractMethod);
+ function("callOptionalMethod", &callOptionalMethod);
class_<HasExternalConstructor>("HasExternalConstructor")
.constructor(&createHasExternalConstructor)
@@ -1901,8 +1925,8 @@ EMSCRIPTEN_BINDINGS(tests) { function("long_to_string", &long_to_string);
function("unsigned_long_to_string", &unsigned_long_to_string);
- function("overloaded_function", (int(*)(int))&overloaded_function);
- function("overloaded_function", (int(*)(int, int))&overloaded_function);
+ function("overloaded_function", select_overload<int(int)>(&overloaded_function));
+ function("overloaded_function", select_overload<int(int, int)>(&overloaded_function));
class_<MultipleCtors>("MultipleCtors")
.constructor<int>()
|