diff --git a/src/Makefile_Eolian_Js.am b/src/Makefile_Eolian_Js.am index 32cf893bf6..b15fa877c6 100644 --- a/src/Makefile_Eolian_Js.am +++ b/src/Makefile_Eolian_Js.am @@ -25,11 +25,11 @@ include Makefile_Eolian_Js_Helper.am if EFL_ENABLE_TESTS if HAVE_NODEJS -TESTS += tests/eolian_js/eolian_js_suite.js +TESTS += tests/eolian_js/eolian_js_suite.sh check_LTLIBRARIES += tests/eolian_js/libeolian_js_suite.la -tests/eolian_js/eolian_js_suite.js: tests/eolian_js/eolian_js_suite_mod.node +tests/eolian_js/eolian_js_suite.sh: tests/eolian_js/eolian_js_suite_mod.node tests/eolian_js/eolian_js_suite_mod.node: tests/eolian_js/libeolian_js_suite.la $(AM_V_CP)$(CP) $(top_builddir)/src/tests/eolian_js/.libs/libeolian_js_suite.so $(top_builddir)/src/tests/eolian_js/eolian_js_suite_mod.node diff --git a/src/bindings/js/eina_js/eina_js_compatibility.hh b/src/bindings/js/eina_js/eina_js_compatibility.hh index fb36e4ee3d..7a4671424c 100644 --- a/src/bindings/js/eina_js/eina_js_compatibility.hh +++ b/src/bindings/js/eina_js/eina_js_compatibility.hh @@ -927,8 +927,9 @@ compatibility_return_type cast_function(compatibility_callback_info_type args) char* class_name = *str; auto ctor = ::efl::eina::js::get_class_constructor(class_name); - return compatibility_return - (new_v8_external_instance(ctor, ::eo_ref(eo), isolate), args); + auto obj = new_v8_external_instance(ctor, ::eo_ref(eo), isolate); + efl::eina::js::make_weak(isolate, obj, [eo]{ ::eo_unref(eo); }); + return compatibility_return(obj, args); } else { diff --git a/src/bindings/js/eina_js/eina_js_container.cc b/src/bindings/js/eina_js/eina_js_container.cc index 60c53e0e74..82246c5fcb 100644 --- a/src/bindings/js/eina_js/eina_js_container.cc +++ b/src/bindings/js/eina_js/eina_js_container.cc @@ -54,11 +54,14 @@ v8::Local concat(eina_container_base& lhs, v8::Isolate* isolate, v8:: , &typeinfo_rhs = typeid(rhs); if(!typeinfo_lhs.before(typeinfo_rhs) && !typeinfo_rhs.before(typeinfo_lhs)) { + auto ptr = rhs.concat(lhs); v8::Handle a[] = - {efl::eina::js::compatibility_new(isolate, rhs.concat(lhs))}; + {efl::eina::js::compatibility_new(isolate, ptr)}; assert(!!*instance_templates[lhs.get_container_type()].handle()); v8::Local result = instance_templates[lhs.get_container_type()].handle()->NewInstance(1, a); + if (ptr) + efl::eina::js::make_weak(isolate, result, [ptr]{ delete ptr; }); return result; } else @@ -95,9 +98,12 @@ v8::Local slice(eina_container_base& self, v8::Isolate* isolate, v8:: else return v8::Undefined(isolate); - v8::Handle a[] = {efl::eina::js::compatibility_new(isolate, self.slice(i, j))}; + auto ptr = self.slice(i, j); + v8::Handle a[] = {efl::eina::js::compatibility_new(isolate, ptr)}; v8::Local result = instance_templates[self.get_container_type()].handle() ->NewInstance(1, a); + if (ptr) + efl::eina::js::make_weak(isolate, result, [ptr]{ delete ptr; }); return result; } @@ -154,6 +160,7 @@ compatibility_return_type new_eina_list_internal(compatibility_callback_info_typ eina_container_base* p = new eina_list; compatibility_set_pointer_internal_field (args.This(), 0, dynamic_cast(p)); + efl::eina::js::make_weak(args.GetIsolate(), args.This(), [p]{ delete p; }); } else { @@ -182,6 +189,7 @@ compatibility_return_type new_eina_list(compatibility_callback_info_type args) eina_container_base* p = new eina_list; compatibility_set_pointer_internal_field (args.This(), 0, dynamic_cast(p)); + efl::eina::js::make_weak(args.GetIsolate(), args.This(), [p]{ delete p; }); return compatibility_return(); } else if (args.Length() == 1 && args[0]->IsString()) @@ -195,6 +203,7 @@ compatibility_return_type new_eina_list(compatibility_callback_info_type args) } compatibility_set_pointer_internal_field (args.This(), 0, dynamic_cast(p)); + efl::eina::js::make_weak(args.GetIsolate(), args.This(), [p]{ delete p; }); return compatibility_return(); } } @@ -212,6 +221,7 @@ compatibility_return_type new_eina_array_internal(compatibility_callback_info_ty eina_container_base* p = new eina_array; compatibility_set_pointer_internal_field (args.This(), 0, dynamic_cast(p)); + efl::eina::js::make_weak(args.GetIsolate(), args.This(), [p]{ delete p; }); } else { @@ -240,6 +250,7 @@ compatibility_return_type new_eina_array(compatibility_callback_info_type args) eina_container_base* p = new eina_array; compatibility_set_pointer_internal_field (args.This(), 0, dynamic_cast(p)); + efl::eina::js::make_weak(args.GetIsolate(), args.This(), [p]{ delete p; }); return compatibility_return(); } else if (args.Length() == 1 && args[0]->IsString()) @@ -253,6 +264,7 @@ compatibility_return_type new_eina_array(compatibility_callback_info_type args) } compatibility_set_pointer_internal_field (args.This(), 0, dynamic_cast(p)); + efl::eina::js::make_weak(args.GetIsolate(), args.This(), [p]{ delete p; }); return compatibility_return(); } } diff --git a/src/bindings/js/eina_js/eina_js_container.hh b/src/bindings/js/eina_js/eina_js_container.hh index 21343fd6da..62fe22c0cd 100644 --- a/src/bindings/js/eina_js/eina_js_container.hh +++ b/src/bindings/js/eina_js/eina_js_container.hh @@ -273,6 +273,11 @@ struct eina_container_common : eina_container_type_specific(isolate, "Indexed attribution was not implemented."))); return v8::Undefined(isolate); } + + typename C::native_handle_type release_native_handle() + { + return _container.release_native_handle(); + } C _container; typedef C container_type; }; diff --git a/src/bindings/js/eina_js/eina_js_get_value_from_c.hh b/src/bindings/js/eina_js/eina_js_get_value_from_c.hh index 204c497431..653a96ebaf 100644 --- a/src/bindings/js/eina_js/eina_js_get_value_from_c.hh +++ b/src/bindings/js/eina_js/eina_js_get_value_from_c.hh @@ -143,7 +143,9 @@ inline v8::Local get_value_from_c(Eo* v, v8::Isolate* isolate, const char* class_name) { auto ctor = ::efl::eina::js::get_class_constructor(class_name); - return new_v8_external_instance(ctor, v, isolate); + auto obj = new_v8_external_instance(ctor, ::eo_ref(v), isolate); + efl::eina::js::make_weak(isolate, obj, [v]{ ::eo_unref(v); }); + return obj; } inline v8::Local @@ -151,23 +153,32 @@ get_value_from_c(const Eo* v, v8::Isolate* isolate, const char* class_name) { // TODO: implement const objects? auto ctor = ::efl::eina::js::get_class_constructor(class_name); - return new_v8_external_instance(ctor, const_cast(v), isolate); + auto obj = new_v8_external_instance(ctor, ::eo_ref(v), isolate); + efl::eina::js::make_weak(isolate, obj, [v]{ ::eo_unref(v); }); + return obj; } template inline v8::Local -get_value_from_c(struct_ptr_tag v, v8::Isolate* isolate, const char* class_name) +get_value_from_c(struct_ptr_tag v, v8::Isolate* isolate, const char* class_name) { - // TODO: implement const structs? + using nonconst_type = typename std::remove_const::type; + bool own = false; // TODO: handle ownership + auto ptr = const_cast(v.value); auto ctor = ::efl::eina::js::get_class_constructor(class_name); - return new_v8_external_instance(ctor, const_cast::type>(v.value), isolate); + auto obj = new_v8_external_instance(ctor, ptr, isolate); + if (own) + efl::eina::js::make_weak(isolate, obj, [ptr]{ free(ptr); }); + return obj; } template inline v8::Local get_value_from_c(struct_tag v, v8::Isolate* isolate, const char* class_name) { - return get_value_from_c(struct_ptr_tag{new T(v.value)}, isolate, class_name); + T* s = static_cast(malloc(sizeof(T))); + *s = v.value; + return get_value_from_c(struct_ptr_tag{s}, isolate, class_name); } template @@ -175,8 +186,16 @@ inline v8::Local get_value_from_c(efl::eina::js::complex_tag v, v8::Isolate* isolate, const char*) { using wrapped_type = typename container_wrapper::type; + bool own = false; // TODO: handle ownership auto a = new ::efl::eina::accessor{v.value}; - return export_accessor(*a , isolate, K::class_name()); + auto obj = export_accessor(*a , isolate, K::class_name()); + efl::eina::js::make_weak(isolate, obj, [a, own] + { + if (!own) + a->release_native_handle(); + delete a; + }); + return obj; } template @@ -191,18 +210,34 @@ template inline v8::Local get_value_from_c(efl::eina::js::complex_tag v, v8::Isolate* isolate, const char*) { - // TODO: use unique_ptr for eina_array to avoid leak ? - auto o = new ::efl::eina::js::range_eina_array(v.value); + bool own = false; // TODO: handle ownership + auto o = new ::efl::eina::js::eina_array(v.value); auto ctor = get_array_instance_template(); - return new_v8_external_instance(ctor, o, isolate); + auto obj = new_v8_external_instance(ctor, o, isolate); + efl::eina::js::make_weak(isolate, obj, [o, own] + { + if (!own) + o->release_native_handle(); + delete o; + }); + return obj; } template inline v8::Local -get_value_from_c(efl::eina::js::complex_tag v, v8::Isolate* isolate, const char* class_name) +get_value_from_c(efl::eina::js::complex_tag v, v8::Isolate* isolate, const char*) { - // TODO: implement const array? - return get_value_from_c(efl::eina::js::complex_tag{const_cast(v.value)}, isolate, class_name); + bool own = false; // TODO: handle ownership + auto o = new ::efl::eina::js::range_eina_array(const_cast(v.value)); + auto ctor = get_array_instance_template(); + auto obj = new_v8_external_instance(ctor, o, isolate); + efl::eina::js::make_weak(isolate, obj, [o, own] + { + if (!own) + o->release_native_handle(); + delete o; + }); + return obj; } template @@ -245,18 +280,34 @@ template inline v8::Local get_value_from_c(efl::eina::js::complex_tag v, v8::Isolate* isolate, const char*) { - // TODO: ensure eina_list ownership ??? - auto o = new ::efl::eina::js::range_eina_list(v.value); + bool own = false; // TODO: handle ownership + auto o = new ::efl::eina::js::eina_list(v.value); auto ctor = get_list_instance_template(); - return new_v8_external_instance(ctor, o, isolate); + auto obj = new_v8_external_instance(ctor, o, isolate); + efl::eina::js::make_weak(isolate, obj, [o, own] + { + if (!own) + o->release_native_handle(); + delete o; + }); + return obj; } template inline v8::Local -get_value_from_c(efl::eina::js::complex_tag v, v8::Isolate* isolate, const char* class_name) +get_value_from_c(efl::eina::js::complex_tag v, v8::Isolate* isolate, const char*) { - // TODO: implement const list? - return get_value_from_c(efl::eina::js::complex_tag{const_cast(v.value)}, isolate, class_name); + bool own = false; // TODO: handle ownership + auto o = new ::efl::eina::js::range_eina_list(const_cast(v.value)); + auto ctor = get_list_instance_template(); + auto obj = new_v8_external_instance(ctor, o, isolate); + efl::eina::js::make_weak(isolate, obj, [o, own] + { + if (!own) + o->release_native_handle(); + delete o; + }); + return obj; } diff --git a/src/bindings/js/eina_js/eina_js_value.cc b/src/bindings/js/eina_js/eina_js_value.cc index 5b5b822160..c7377ae857 100644 --- a/src/bindings/js/eina_js/eina_js_value.cc +++ b/src/bindings/js/eina_js/eina_js_value.cc @@ -54,6 +54,9 @@ compatibility_return_type eina_value_constructor(compatibility_callback_info_typ std::unique_ptr ptr(new value(value_cast(args[0]))); compatibility_set_pointer_internal_field(args.This(), 0, ptr.get()); + auto v = ptr.get(); + if (v) + efl::eina::js::make_weak(isolate, args.This(), [v]{ delete v; }); ptr.release(); } catch(const std::bad_cast &e) { v8::Local je = compatibility_new(isolate); diff --git a/src/bindings/js/eo_js/eo_js_construct_from_eo.hh b/src/bindings/js/eo_js/eo_js_construct_from_eo.hh index 287aaa748c..8008d16892 100644 --- a/src/bindings/js/eo_js/eo_js_construct_from_eo.hh +++ b/src/bindings/js/eo_js/eo_js_construct_from_eo.hh @@ -20,6 +20,7 @@ inline eina::js::compatibility_return_type construct_from_eo(eina::js::compatibi { Eo* eo = static_cast(v8::External::Cast(*args[0])->Value()); args.This()->SetInternalField(0, args[0]); + ::eo_ref(eo); efl::eina::js::make_weak(args.GetIsolate(), args.This(), [eo] { eo_unref(eo); }); return eina::js::compatibility_return(); } diff --git a/src/bindings/js/eo_js/eo_js_event.hh b/src/bindings/js/eo_js/eo_js_event.hh index 280aeacae6..b589e5d6cc 100644 --- a/src/bindings/js/eo_js/eo_js_event.hh +++ b/src/bindings/js/eo_js/eo_js_event.hh @@ -100,6 +100,7 @@ inline eina::js::compatibility_return_type on_event(eina::js::compatibility_call event_callback_information* i = new event_callback_information {event, {isolate, eina::js::compatibility_cast(f)}}; eo_event_callback_add(eo, event->event, event->event_callback, i); + efl::eina::js::make_weak(isolate, self, [i]{ delete i; }); } else { diff --git a/src/bindings/js/eo_js/eo_js_struct.hh b/src/bindings/js/eo_js/eo_js_struct.hh index 731f9d093c..eba0c74d37 100644 --- a/src/bindings/js/eo_js/eo_js_struct.hh +++ b/src/bindings/js/eo_js/eo_js_struct.hh @@ -42,8 +42,10 @@ eina::js::compatibility_return_type new_struct(eina::js::compatibility_callback_ if(args.Length() == 0) { - S* p = new S{}; - eina::js::compatibility_set_pointer_internal_field(args.This(), 0, static_cast(p)); + void* p = std::malloc(sizeof(S)); + std::memset(p, 0, sizeof(S)); + eina::js::compatibility_set_pointer_internal_field(args.This(), 0, p); + efl::eina::js::make_weak(args.GetIsolate(), args.This(), [p]{ free(p); }); } else { diff --git a/src/tests/eolian_js/eolian_js_suite.js b/src/tests/eolian_js/eolian_js_suite.js index 66e55962f2..2c45eb3af4 100755 --- a/src/tests/eolian_js/eolian_js_suite.js +++ b/src/tests/eolian_js/eolian_js_suite.js @@ -795,6 +795,22 @@ startTest("method_iterator_of_structs", function() { // assert(a[0] === 42); // }); +// Garbage Collection // +startTest("gc_object", function() { + var freed = false; + (function() { + var obj = new TestObject(null); + obj.on("del", function() { + printInfo('Object destructed') + freed = true; + }); + }()); + printInfo('going to garbage collect'); + global.gc(); + printInfo('is object destructed?'); + assert(freed); +}); + startTest("new Constructor_Method_Class", function() { var obj = new ConstructorMethodClass(null, 5, 10.0); assert(obj); diff --git a/src/tests/eolian_js/eolian_js_suite.sh b/src/tests/eolian_js/eolian_js_suite.sh new file mode 100755 index 0000000000..6b78a5097b --- /dev/null +++ b/src/tests/eolian_js/eolian_js_suite.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +BASEDIR=$(dirname $0) +/usr/bin/env node --expose-gc $BASEDIR/eolian_js_suite.js