aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2014-02-10 15:16:14 -0800
committerAlon Zakai <alonzakai@gmail.com>2014-02-10 15:16:14 -0800
commited896c9c00edc7c7bdd4c4cfaca057509c3cd628 (patch)
treea4721bedbe82d57cff7f6a94dbd2ed8e5b8425dc
parent8eb52e34be029cd7f276871c830b02fdf53ed00c (diff)
parentb5cf147e6ce7a8d3277342d87beec76290a578bf (diff)
Merge pull request #2099 from waywardmonkeys/upstream-from-imvu
Upstream from imvu
-rwxr-xr-xscons-tools/emscripten.py5
-rw-r--r--src/embind/emval.js36
-rw-r--r--system/include/emscripten/bind.h52
-rw-r--r--system/include/emscripten/val.h55
-rw-r--r--system/include/emscripten/wire.h32
-rw-r--r--tests/embind/embind.test.js72
-rw-r--r--tests/embind/embind_test.cpp61
7 files changed, 235 insertions, 78 deletions
diff --git a/scons-tools/emscripten.py b/scons-tools/emscripten.py
index b4912aaa..4c48083e 100755
--- a/scons-tools/emscripten.py
+++ b/scons-tools/emscripten.py
@@ -316,6 +316,11 @@ def generate(env):
def depend_on_embedder(target, source, env):
env.Depends(target, env['JS_EMBEDDER'])
+ files = []
+ for src in source:
+ for dirpath, dirnames, filenames in os.walk(str(src.srcnode())):
+ files.extend(map(lambda p: os.path.join(dirpath, p), filenames))
+ env.Depends(target, env.Value(sorted(files)))
return target, source
def embed_files_in_js(target, source, env, for_signature):
diff --git a/src/embind/emval.js b/src/embind/emval.js
index 0d075188..039f1d61 100644
--- a/src/embind/emval.js
+++ b/src/embind/emval.js
@@ -3,7 +3,7 @@
/*global new_*/
/*global createNamedFunction*/
/*global readLatin1String, writeStringToMemory*/
-/*global requireRegisteredType, throwBindingError*/
+/*global requireRegisteredType, throwBindingError, runDestructors*/
/*jslint sub:true*/ /* The symbols 'fromWireType' and 'toWireType' must be accessed via array notation to be closure-safe since craftInvokerFunction crafts functions as strings that can't be closured. */
var Module = Module || {};
@@ -79,6 +79,12 @@ function __emval_decref(handle) {
}
}
+function __emval_run_destructors(handle) {
+ var destructors = _emval_handle_array[handle].value;
+ runDestructors(destructors);
+ __emval_decref(handle);
+}
+
function __emval_new_array() {
return __emval_register([]);
}
@@ -199,11 +205,12 @@ 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) {
+function __emval_as(handle, returnType, destructorsRef) {
requireHandle(handle);
returnType = requireRegisteredType(returnType, 'emval::as');
var destructors = [];
- // caller owns destructing
+ var rd = __emval_register(destructors);
+ HEAP32[destructorsRef >> 2] = rd;
return returnType['toWireType'](destructors, _emval_handle_array[handle].value);
}
@@ -242,14 +249,20 @@ function lookupTypes(argCount, argTypes, argWireTypes) {
return a;
}
+function allocateDestructors(destructorsRef) {
+ var destructors = [];
+ HEAP32[destructorsRef >> 2] = __emval_register(destructors);
+ return destructors;
+}
+
function __emval_get_method_caller(argCount, argTypes) {
var types = lookupTypes(argCount, argTypes);
var retType = types[0];
var signatureName = retType.name + "_$" + types.slice(1).map(function (t) { return t.name; }).join("_") + "$";
- var args1 = ["addFunction", "createNamedFunction", "requireHandle", "getStringOrSymbol", "_emval_handle_array", "retType"];
- var args2 = [Runtime.addFunction, createNamedFunction, requireHandle, getStringOrSymbol, _emval_handle_array, retType];
+ var args1 = ["addFunction", "createNamedFunction", "requireHandle", "getStringOrSymbol", "_emval_handle_array", "retType", "allocateDestructors"];
+ var args2 = [Runtime.addFunction, createNamedFunction, requireHandle, getStringOrSymbol, _emval_handle_array, retType, allocateDestructors];
var argsList = ""; // 'arg0, arg1, arg2, ... , argN'
var argsListWired = ""; // 'arg0Wired, ..., argNWired'
@@ -261,16 +274,17 @@ function __emval_get_method_caller(argCount, argTypes) {
}
var invokerFnBody =
- "return addFunction(createNamedFunction('" + signatureName + "', function (handle, name" + argsListWired + ") {\n" +
- "requireHandle(handle);\n" +
- "name = getStringOrSymbol(name);\n";
+ "return addFunction(createNamedFunction('" + signatureName + "', function (handle, name, destructorsRef" + argsListWired + ") {\n" +
+ " requireHandle(handle);\n" +
+ " name = getStringOrSymbol(name);\n";
for (var i = 0; i < argCount - 1; ++i) {
- invokerFnBody += "var arg" + i + " = argType" + i + ".fromWireType(arg" + i + "Wired);\n";
+ invokerFnBody += " var arg" + i + " = argType" + i + ".fromWireType(arg" + i + "Wired);\n";
}
invokerFnBody +=
- "var obj = _emval_handle_array[handle].value;\n" +
- "return retType.toWireType(null, obj[name](" + argsList + "));\n" +
+ " var obj = _emval_handle_array[handle].value;\n" +
+ " var rv = obj[name](" + argsList + ");\n" +
+ " return retType.toWireType(allocateDestructors(destructorsRef), rv);\n" +
"}));\n";
args1.push(invokerFnBody);
diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h
index 403d8084..4d7547a1 100644
--- a/system/include/emscripten/bind.h
+++ b/system/include/emscripten/bind.h
@@ -533,6 +533,8 @@ namespace emscripten {
template<typename ClassType>
class value_array : public internal::noncopyable {
public:
+ typedef ClassType class_type;
+
value_array(const char* name) {
using namespace internal;
_embind_register_value_array(
@@ -605,6 +607,8 @@ namespace emscripten {
template<typename ClassType>
class value_object : public internal::noncopyable {
public:
+ typedef ClassType class_type;
+
value_object(const char* name) {
using namespace internal;
_embind_register_value_object(
@@ -689,6 +693,10 @@ namespace emscripten {
static void* share(void* v) {
return 0; // no sharing
}
+
+ static PointerType* construct_null() {
+ return new PointerType;
+ }
};
// specialize if you have a different pointer type
@@ -720,6 +728,10 @@ namespace emscripten {
val_deleter(val::take_ownership(v)));
}
+ static PointerType* construct_null() {
+ return new PointerType;
+ }
+
private:
class val_deleter {
public:
@@ -745,6 +757,8 @@ namespace emscripten {
template<typename T>
class wrapper : public T {
public:
+ typedef T class_type;
+
explicit wrapper(val&& wrapped)
: wrapped(std::forward<val>(wrapped))
{}
@@ -794,13 +808,14 @@ namespace emscripten {
// 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 {
+ typedef BaseClass class_type;
+
template<typename ClassType>
static void verify() {
static_assert(!std::is_same<ClassType, BaseClass>::value, "Base must not have same type as class");
@@ -847,6 +862,9 @@ namespace emscripten {
template<typename ClassType, typename BaseSpecifier = internal::NoBaseClass>
class class_ {
public:
+ typedef ClassType class_type;
+ typedef BaseSpecifier base_specifier;
+
class_() = delete;
explicit class_(const char* name) {
@@ -867,7 +885,7 @@ namespace emscripten {
}
template<typename PointerType>
- class_& smart_ptr() {
+ const class_& smart_ptr() const {
using namespace internal;
typedef smart_ptr_trait<PointerType> PointerTrait;
@@ -881,21 +899,21 @@ namespace emscripten {
typeid(PointerType).name(),
PointerTrait::get_sharing_policy(),
reinterpret_cast<GenericFunction>(&PointerTrait::get),
- reinterpret_cast<GenericFunction>(&operator_new<PointerType>),
+ reinterpret_cast<GenericFunction>(&PointerTrait::construct_null),
reinterpret_cast<GenericFunction>(&PointerTrait::share),
reinterpret_cast<GenericFunction>(&raw_destructor<PointerType>));
return *this;
};
template<typename... ConstructorArgs, typename... Policies>
- class_& constructor(Policies... policies) {
+ const class_& constructor(Policies... policies) const {
return constructor(
&internal::operator_new<ClassType, ConstructorArgs...>,
policies...);
}
template<typename... Args, typename ReturnType, typename... Policies>
- class_& constructor(ReturnType (*factory)(Args...), Policies...) {
+ const class_& constructor(ReturnType (*factory)(Args...), Policies...) const {
using namespace internal;
// TODO: allows all raw pointers... policies need a rethink
@@ -910,7 +928,7 @@ namespace emscripten {
}
template<typename SmartPtr, typename... Args, typename... Policies>
- class_& smart_ptr_constructor(SmartPtr (*factory)(Args...), Policies...) {
+ const class_& smart_ptr_constructor(SmartPtr (*factory)(Args...), Policies...) const {
using namespace internal;
smart_ptr<SmartPtr>();
@@ -926,7 +944,7 @@ namespace emscripten {
}
template<typename WrapperType, typename PointerType = WrapperType*>
- class_& allow_subclass() {
+ const class_& allow_subclass() const {
using namespace internal;
auto cls = class_<WrapperType, base<ClassType>>(typeid(WrapperType).name())
@@ -940,7 +958,7 @@ namespace emscripten {
}
template<typename ReturnType, typename... Args, typename... Policies>
- class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...), Policies...) {
+ const class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...), Policies...) const {
using namespace internal;
typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, AllowedRawPointer<ClassType>, Args...> args;
@@ -955,7 +973,7 @@ namespace emscripten {
}
template<typename ReturnType, typename... Args, typename... Policies>
- class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...) const, Policies...) {
+ const class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...) const, Policies...) const {
using namespace internal;
typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, AllowedRawPointer<const ClassType>, Args...> args;
@@ -970,7 +988,7 @@ namespace emscripten {
}
template<typename ReturnType, typename ThisType, typename... Args, typename... Policies>
- class_& function(const char* methodName, ReturnType (*function)(ThisType, Args...), Policies...) {
+ const class_& function(const char* methodName, ReturnType (*function)(ThisType, Args...), Policies...) const {
using namespace internal;
typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, ThisType, Args...> args;
@@ -985,7 +1003,7 @@ namespace emscripten {
}
template<typename FieldType, typename = typename std::enable_if<!std::is_function<FieldType>::value>::type>
- class_& property(const char* fieldName, const FieldType ClassType::*field) {
+ const class_& property(const char* fieldName, const FieldType ClassType::*field) const {
using namespace internal;
_embind_register_class_property(
@@ -1001,7 +1019,7 @@ namespace emscripten {
}
template<typename FieldType, typename = typename std::enable_if<!std::is_function<FieldType>::value>::type>
- class_& property(const char* fieldName, FieldType ClassType::*field) {
+ const class_& property(const char* fieldName, FieldType ClassType::*field) const {
using namespace internal;
_embind_register_class_property(
@@ -1017,7 +1035,7 @@ namespace emscripten {
}
template<typename Getter>
- class_& property(const char* fieldName, Getter getter) {
+ const class_& property(const char* fieldName, Getter getter) const {
using namespace internal;
typedef GetterPolicy<Getter> GP;
_embind_register_class_property(
@@ -1033,7 +1051,7 @@ namespace emscripten {
}
template<typename Getter, typename Setter>
- class_& property(const char* fieldName, Getter getter, Setter setter) {
+ const class_& property(const char* fieldName, Getter getter, Setter setter) const {
using namespace internal;
typedef GetterPolicy<Getter> GP;
typedef SetterPolicy<Setter> SP;
@@ -1050,7 +1068,7 @@ namespace emscripten {
}
template<typename ReturnType, typename... Args, typename... Policies>
- class_& class_function(const char* methodName, ReturnType (*classMethod)(Args...), Policies...) {
+ const class_& class_function(const char* methodName, ReturnType (*classMethod)(Args...), Policies...) const {
using namespace internal;
typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, Args...> args;
@@ -1157,6 +1175,8 @@ namespace emscripten {
template<typename EnumType>
class enum_ {
public:
+ typedef EnumType enum_type;
+
enum_(const char* name) {
_embind_register_enum(
internal::TypeID<EnumType>::get(),
@@ -1199,7 +1219,7 @@ namespace emscripten {
_embind_register_constant(
name,
TypeID<const ConstantType&>::get(),
- asGenericValue(BindingType<const ConstantType&>::toWireType(v)));
+ asGenericValue(BT::toWireType(v)));
}
}
diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h
index b712d164..19b1beb1 100644
--- a/system/include/emscripten/val.h
+++ b/system/include/emscripten/val.h
@@ -11,10 +11,18 @@ namespace emscripten {
void _emval_register_symbol(const char*);
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);
+ void _emval_run_destructors(EM_DESTRUCTORS handle);
+
EM_VAL _emval_new_array();
EM_VAL _emval_new_object();
EM_VAL _emval_undefined();
@@ -32,7 +40,8 @@ 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);
- void _emval_as(EM_VAL value, TYPEID returnType);
+ _POLYMORPHIC_RESULT _emval_as(EM_VAL value, TYPEID returnType, EM_DESTRUCTORS* runDestructors);
+
EM_VAL _emval_call(
EM_VAL value,
unsigned argCount,
@@ -57,7 +66,11 @@ namespace emscripten {
template<typename ReturnType, typename... Args>
struct Signature {
- typedef typename BindingType<ReturnType>::WireType (*MethodCaller)(EM_VAL value, const char* methodName, typename BindingType<Args>::WireType...);
+ typedef typename BindingType<ReturnType>::WireType (*MethodCaller)(
+ EM_VAL value,
+ const char* methodName,
+ EM_DESTRUCTORS* destructors,
+ typename BindingType<Args>::WireType...);
static MethodCaller get_method_caller() {
static MethodCaller fp = reinterpret_cast<MethodCaller>(init_method_caller());
@@ -71,15 +84,34 @@ namespace emscripten {
}
};
+ struct DestructorsRunner {
+ public:
+ explicit DestructorsRunner(EM_DESTRUCTORS d)
+ : destructors(d)
+ {}
+ ~DestructorsRunner() {
+ _emval_run_destructors(destructors);
+ }
+
+ DestructorsRunner(const DestructorsRunner&) = delete;
+ void operator=(const DestructorsRunner&) = delete;
+
+ private:
+ EM_DESTRUCTORS destructors;
+ };
+
template<typename ReturnType, typename... Args>
struct MethodCaller {
static ReturnType call(EM_VAL handle, const char* methodName, Args&&... args) {
auto caller = Signature<ReturnType, Args...>::get_method_caller();
+
+ EM_DESTRUCTORS destructors;
auto wireType = caller(
handle,
methodName,
+ &destructors,
toWireType(std::forward<Args>(args))...);
- WireDeleter<ReturnType> deleter(wireType);
+ DestructorsRunner rd(destructors);
return BindingType<ReturnType>::fromWireType(wireType);
}
};
@@ -88,10 +120,15 @@ namespace emscripten {
struct MethodCaller<void, Args...> {
static void call(EM_VAL handle, const char* methodName, Args&&... args) {
auto caller = Signature<void, Args...>::get_method_caller();
- return caller(
+
+ EM_DESTRUCTORS destructors;
+ caller(
handle,
methodName,
+ &destructors,
toWireType(std::forward<Args>(args))...);
+ DestructorsRunner rd(destructors);
+ // void requires no translation
}
};
}
@@ -262,11 +299,13 @@ namespace emscripten {
typedef typename BT::WireType (*TypedAs)(
EM_VAL value,
- TYPEID returnType);
+ TYPEID returnType,
+ EM_DESTRUCTORS* runDestructors);
TypedAs typedAs = reinterpret_cast<TypedAs>(&_emval_as);
- typename BT::WireType wt = typedAs(handle, TypeID<T>::get());
- WireDeleter<T> deleter(wt);
+ EM_DESTRUCTORS destructors;
+ typename BT::WireType wt = typedAs(handle, TypeID<T>::get(), &destructors);
+ DestructorsRunner dr(destructors);
return BT::fromWireType(wt);
}
@@ -292,8 +331,6 @@ namespace emscripten {
static val fromWireType(WireType v) {
return val::take_ownership(v);
}
- static void destroy(WireType v) {
- }
};
}
diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h
index a5892216..c3ce8dd0 100644
--- a/system/include/emscripten/wire.h
+++ b/system/include/emscripten/wire.h
@@ -7,6 +7,7 @@
//
// We'll call the on-the-wire type WireType.
+#include <stdio.h>
#include <cstdlib>
#include <memory>
#include <string>
@@ -130,8 +131,6 @@ namespace emscripten {
constexpr static type fromWireType(WireType v) { \
return v; \
} \
- static void destroy(WireType) { \
- } \
}
EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(char);
@@ -160,8 +159,6 @@ namespace emscripten {
static bool fromWireType(WireType wt) {
return wt;
}
- static void destroy(WireType) {
- }
};
template<>
@@ -179,9 +176,6 @@ namespace emscripten {
static std::string fromWireType(WireType v) {
return std::string(v->data, v->length);
}
- static void destroy(WireType v) {
- free(v);
- }
};
template<>
@@ -199,9 +193,6 @@ namespace emscripten {
static std::wstring fromWireType(WireType v) {
return std::wstring(v->data, v->length);
}
- static void destroy(WireType v) {
- free(v);
- }
};
template<typename T>
@@ -254,10 +245,6 @@ namespace emscripten {
static ActualT& fromWireType(WireType p) {
return *p;
}
-
- static void destroy(WireType p) {
- delete p;
- }
};
// Is this necessary?
@@ -280,8 +267,6 @@ namespace emscripten {
static Enum fromWireType(WireType v) {
return v;
}
- static void destroy(WireType) {
- }
};
// catch-all generic binding
@@ -296,21 +281,6 @@ namespace emscripten {
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;
- };
}
struct memory_view {
diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js
index da81a81e..5ca972be 100644
--- a/tests/embind/embind.test.js
+++ b/tests/embind/embind.test.js
@@ -55,7 +55,7 @@ module({
});
});
});
-
+
}
BaseFixture.extend("access to base class members", function() {
@@ -609,7 +609,7 @@ module({
assert.equal("0", cm.unsigned_int_to_string(0));
assert.equal("0", cm.long_to_string(0));
assert.equal("0", cm.unsigned_long_to_string(0));
-
+
// all types should have positive values.
assert.equal("5", cm.char_to_string(5));
assert.equal("5", cm.signed_char_to_string(5));
@@ -650,7 +650,7 @@ module({
assert.equal("-32768", cm.short_to_string(-32768));
assert.equal("-2147483648", cm.int_to_string(-2147483648));
assert.equal("-2147483648", cm.long_to_string(-2147483648));
-
+
// passing out of range values should fail.
assert.throws(TypeError, function() { cm.char_to_string(-129); });
assert.throws(TypeError, function() { cm.char_to_string(128); });
@@ -733,7 +733,7 @@ module({
test("overloading of derived class member functions", function() {
var foo = new cm.MultipleOverloadsDerived();
-
+
// NOTE: In C++, default lookup rules will hide overloads from base class if derived class creates them.
// In JS, we make the base class overloads implicitly available. In C++, they would need to be explicitly
// invoked, like foo.MultipleOverloads::Func(10);
@@ -748,7 +748,7 @@ module({
assert.equal(foo.WhichFuncCalled(), 4);
foo.delete();
});
-
+
test("overloading of class static functions", function() {
assert.equal(cm.MultipleOverloads.StaticFunc(10), 1);
assert.equal(cm.MultipleOverloads.WhichStaticFuncCalled(), 1);
@@ -1441,7 +1441,7 @@ module({
test("repr includes enum value", function() {
assert.equal('<#Enum_ONE {}>', IMVU.repr(cm.Enum.ONE));
assert.equal('<#Enum_TWO {}>', IMVU.repr(cm.Enum.TWO));
- });
+ });
}
test("instanceof", function() {
@@ -1591,7 +1591,7 @@ module({
test("returning a new shared pointer from interfaces implemented in JS code does not leak", function() {
var impl = cm.AbstractClass.implement({
returnsSharedPtr: function() {
- return cm.embind_test_return_smart_derived_ptr();
+ return cm.embind_test_return_smart_derived_ptr().deleteLater();
}
});
cm.callReturnsSharedPtrMethod(impl);
@@ -1644,7 +1644,7 @@ module({
});
if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well!
-
+
BaseFixture.extend("unbound types", function() {
function assertMessage(fn, message) {
var e = assert.throws(cm.UnboundTypeError, fn);
@@ -1689,7 +1689,7 @@ module({
},
'Cannot construct HasConstructorUsingUnboundArgumentAndUnboundBase due to unbound types: 18SecondUnboundClass');
});
-
+
test('class function with unbound argument', function() {
var x = new cm.BoundClass;
assertMessage(
@@ -1719,12 +1719,12 @@ module({
}, 'Cannot access BoundClass.property due to unbound types: 12UnboundClass');
x.delete();
});
-
+
// todo: tuple elements
// todo: tuple element accessors
// todo: struct fields
});
-
+
}
BaseFixture.extend("noncopyable", function() {
@@ -1743,6 +1743,10 @@ module({
BaseFixture.extend("constants", function() {
assert.equal(10, cm.INT_CONSTANT);
+
+ assert.equal(1, cm.STATIC_CONST_INTEGER_VALUE_1);
+ assert.equal(1000, cm.STATIC_CONST_INTEGER_VALUE_1000);
+
assert.equal("some string", cm.STRING_CONSTANT);
assert.deepEqual([1, 2, 3, 4], cm.VALUE_ARRAY_CONSTANT);
assert.deepEqual({x:1,y:2,z:3,w:4}, cm.VALUE_OBJECT_CONSTANT);
@@ -1888,6 +1892,52 @@ module({
sh.delete();
});
});
+
+ BaseFixture.extend("val::as from pointer to value", function() {
+ test("calling as on pointer with value makes a copy", function() {
+ var sh1 = new cm.StringHolder("Hello world");
+ var sh2 = cm.return_StringHolder_copy(sh1);
+ assert.equal("Hello world", sh1.get());
+ assert.equal("Hello world", sh2.get());
+ assert.false(sh1.isAliasOf(sh2));
+ sh2.delete();
+ sh1.delete();
+ });
+
+ test("calling function that returns a StringHolder", function() {
+ var sh1 = new cm.StringHolder("Hello world");
+ var sh2 = cm.call_StringHolder_func(function() {
+ return sh1;
+ });
+ assert.equal("Hello world", sh1.get());
+ assert.equal("Hello world", sh2.get());
+ assert.false(sh1.isAliasOf(sh2));
+ sh2.delete();
+ sh1.delete();
+ });
+ });
+
+ BaseFixture.extend("mixin", function() {
+ test("can call mixin method", function() {
+ var a = new cm.DerivedWithMixin();
+ assert.instanceof(a, cm.Base);
+ assert.equal(10, a.get10());
+ a.delete();
+ });
+ });
+
+ test("returning a cached new shared pointer from interfaces implemented in JS code does not leak", function() {
+ var derived = cm.embind_test_return_smart_derived_ptr();
+ var impl = cm.AbstractClass.implement({
+ returnsSharedPtr: function() {
+ return derived;
+ }
+ });
+ cm.callReturnsSharedPtrMethod(impl);
+ impl.delete();
+ derived.delete();
+ // Let the memory leak test superfixture check that no leaks occurred.
+ });
});
/* global run_all_tests */
diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp
index d6b27bce..4efc4bd8 100644
--- a/tests/embind/embind_test.cpp
+++ b/tests/embind/embind_test.cpp
@@ -1283,6 +1283,7 @@ std::shared_ptr<HeldBySmartPtr> takesHeldBySmartPtrSharedPtr(std::shared_ptr<Hel
namespace emscripten {
template<typename T>
struct smart_ptr_trait<CustomSmartPtr<T>> {
+ typedef CustomSmartPtr<T> pointer_type;
typedef T element_type;
static sharing_policy get_sharing_policy() {
@@ -1297,6 +1298,10 @@ namespace emscripten {
++ptr->refcount; // implement an adopt API?
return CustomSmartPtr<T>(ptr);
}
+
+ static pointer_type* construct_null() {
+ return new pointer_type;
+ }
};
}
@@ -2210,8 +2215,20 @@ EMSCRIPTEN_BINDINGS(read_only_properties) {
;
}
+struct StaticConstIntStruct {
+ static const int STATIC_CONST_INTEGER_VALUE_1;
+ static const int STATIC_CONST_INTEGER_VALUE_1000;
+};
+
+const int StaticConstIntStruct::STATIC_CONST_INTEGER_VALUE_1 = 1;
+const int StaticConstIntStruct::STATIC_CONST_INTEGER_VALUE_1000 = 1000;
+
EMSCRIPTEN_BINDINGS(constants) {
constant("INT_CONSTANT", 10);
+
+ constant("STATIC_CONST_INTEGER_VALUE_1", StaticConstIntStruct::STATIC_CONST_INTEGER_VALUE_1);
+ constant("STATIC_CONST_INTEGER_VALUE_1000", StaticConstIntStruct::STATIC_CONST_INTEGER_VALUE_1000);
+
constant("STRING_CONSTANT", std::string("some string"));
TupleVector tv(1, 2, 3, 4);
@@ -2243,3 +2260,47 @@ void clear_StringHolder(StringHolder& sh) {
EMSCRIPTEN_BINDINGS(references) {
function("clear_StringHolder", &clear_StringHolder);
}
+
+StringHolder return_StringHolder_copy(val func) {
+ return func.as<StringHolder>();
+}
+
+StringHolder call_StringHolder_func(val func) {
+ return func().as<StringHolder>();
+}
+
+EMSCRIPTEN_BINDINGS(return_values) {
+ function("return_StringHolder_copy", &return_StringHolder_copy);
+ function("call_StringHolder_func", &call_StringHolder_func);
+}
+
+
+struct Mixin {
+ int get10() const {
+ return 10;
+ }
+};
+
+template<typename ClassBinding>
+const ClassBinding& registerMixin(const ClassBinding& binding) {
+ // need a wrapper for implicit conversion from DerivedWithMixin to Mixin
+ struct Local {
+ static int get10(const typename ClassBinding::class_type& self) {
+ return self.get10();
+ }
+ };
+
+ return binding
+ .function("get10", &Local::get10)
+ ;
+}
+
+class DerivedWithMixin : public Base, public Mixin {
+};
+
+EMSCRIPTEN_BINDINGS(mixins) {
+ registerMixin(
+ class_<DerivedWithMixin, base<Base>>("DerivedWithMixin")
+ .constructor<>()
+ );
+}