Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support automatic heap-copies of temporary objects #113

Open
tim-janik opened this issue Jul 13, 2019 · 2 comments
Open

Support automatic heap-copies of temporary objects #113

tim-janik opened this issue Jul 13, 2019 · 2 comments

Comments

@tim-janik
Copy link
Contributor

Hi @pmed.

After more than 2 years, I'm still dragging along an important v8pp patch for heap-allocated temporary objects in my fork (in fact it's the only reason I still need to keep my own fork).

See, I have a large number of auto generated C++ functions (from IDL), some of which return temporary objects, and a large number of corresponding auto generated .set ("accessor", &ObjectType::accessor) method registrations.

I'd really like to find a way to upstream the possibility of automatically copying return values that are temporary objects onto the heap, so they can be passed on to V8. My patch essentially adds a one-liner to convert<T>::to_v8(), that does import_external (new Class (value)).
Since you didn't seem to like to take the patch in #39 (comment), I'm trying to find another way:

  1. I need to avoid changing all my auto-generated C++ functions (or to manually sort them apart for ones that return a temporary class and those that don't).

  2. I need to avoid changing hand-picked .set ("accessor", &ObjectType::accessor) statements. I could change all of them easily though, if that helped...

So I'd like to have your feedback on what could work:

  • Would a variant of .set() be acceptable, e.g. .xset ("accessor", &ObjectType::accessor) where xset() works exactly like set() for all types but additionally copies temporary return values instead of just throwing "failed to wrap C++ object"?

  • Or, would my patch be acceptable, if convert::to_v8() is special cased, so it only creates a heap copy if std::is_copy_constructible<T>::value or if std::is_move_constructible<T>::value?

  • Or, since you mentioned in Question: function that returns object by value #39 that you wanted some explicit user involvement to enable the copies, would a define like V8PP_AUTO_COPY_TEMPORARIES (defaulting to false) help to accept and activate the patch?

  • Are there any other ways I'm missing?

Here's the latest version of my patch (against v1.6.0): tim-janik@f272053

Here's the original patch (against v1.4.1): tim-janik@cda26b6

PS: FWIW, I'd consider #39 essentially answered and closable. This issue in contrast is about actually merging functionality that seems to be useful to several downstream projects.

pmed added a commit that referenced this issue Jul 21, 2019
…r_traits

A wrapped function may return a wrapped C++ object, so we need to use
appropriate converter specialization (e.g. `convert<std::shared_ptr<T>`) for
such a wrapped class `T`.

Reusing `call_from_v8_traits<F>::arg_converter<return_type, Traits>` meta-function
to get the converter type in `forward_ret()` for the certain function result type.

Extracted `call_from_v8_traits<F>::arg_converter<Arg, Traits>` to use a type
instead of argument index.

Added optional `Traits = raw_ptr_traits` template argument to `wrap_function()`
and `wrap_function_template()` in order to allow `forward_function()`
instantiation for the specified `Traits`

Work in context of issue #113
pmed added a commit that referenced this issue Jul 21, 2019
Added `class_::auto_wrap_objects()` function to set an `auto_wrap_objects_`
flag in the `object_registry` for a wrapped class.

Added `class_::find_object(obj)` overloaded function for an object reference, to
create a clone of the `obj` with `Traits::clone()` and to wrap the cloned object
for the JavaScript side, if no such an instance was found.

Added `clone(T const& src)` template function into `raw_ptr_traits, `shared_ptr_traits`,
to create a copy of `src` with a copy constructor of class T.

Using the added `class_::find_object(obj)` overloading in `convert<T>` specializations
for a wrapped class T references, both for `raw_ptr_traits and `shared_ptr_traits`.

Added a simple test case with a function returning an unwrapped C++ object, and
accessing it from JavaScript. The returned objects shall be valid in JavaScript,
since the `vpp8:class_.auto_wrap_objects(true)` for the test class.
pmed added a commit that referenced this issue Jul 21, 2019
Added `class_::auto_wrap_objects()` function to set an `auto_wrap_objects_`
flag in the `object_registry` for a wrapped class.

Added `class_::find_object(obj)` overloaded function for an object reference, to
create a clone of the `obj` with `Traits::clone()` and to wrap the cloned object
for the JavaScript side, if no such an instance was found.

Added `clone(T const& src)` template function into `raw_ptr_traits, `shared_ptr_traits`,
to create a copy of `src` with a copy constructor of class T.

Using the added `class_::find_object(obj)` overloading in `convert<T>` specializations
for a wrapped class T references, both for `raw_ptr_traits and `shared_ptr_traits`.

Added a simple test case with a function returning an unwrapped C++ object, and
accessing it from JavaScript. The returned objects shall be valid in JavaScript,
since the `vpp8:class_.auto_wrap_objects(true)` for the test class.
pmed added a commit that referenced this issue Jul 21, 2019
Added `class_::auto_wrap_objects()` function to set an `auto_wrap_objects_`
flag in the `object_registry` for a wrapped class.

Added `class_::find_object(obj)` overloaded function for an object reference, to
create a clone of the `obj` with `Traits::clone()` and to wrap the cloned object
for the JavaScript side, if no such an instance was found.

Added `clone(T const& src)` template function into `raw_ptr_traits, `shared_ptr_traits`,
to create a copy of `src` with a copy constructor of class T.

Using the added `class_::find_object(obj)` overloading in `convert<T>` specializations
for a wrapped class T references, both for `raw_ptr_traits and `shared_ptr_traits`.

Added a simple test case with a function returning an unwrapped C++ object, and
accessing it from JavaScript. The returned objects shall be valid in JavaScript,
since the `vpp8:class_.auto_wrap_objects(true)` for the test class.
pmed added a commit that referenced this issue Jul 21, 2019
Added `class_::auto_wrap_objects()` function to set an `auto_wrap_objects_`
flag in the `object_registry` for a wrapped class.

Added `class_::find_object(obj)` overloaded function for an object reference, to
create a clone of the `obj` with `Traits::clone()` and to wrap the cloned object
for the JavaScript side, if no such an instance was found.

Added `clone(T const& src)` template function into `raw_ptr_traits, `shared_ptr_traits`,
to create a copy of `src` with a copy constructor of class T.

Using the added `class_::find_object(obj)` overloading in `convert<T>` specializations
for a wrapped class T references, both for `raw_ptr_traits and `shared_ptr_traits`.

Added a simple test case with a function returning an unwrapped C++ object, and
accessing it from JavaScript. The returned objects shall be valid in JavaScript,
since the `vpp8:class_.auto_wrap_objects(true)` for the test class.
pmed added a commit that referenced this issue Jul 21, 2019
Backported implementation of #113

Conflicts resolved:
#	v8pp/call_from_v8.hpp
#	v8pp/class.hpp
#	v8pp/function.hpp
pmed added a commit that referenced this issue Jul 21, 2019
Backported implementation of #113

Conflicts resolved:
#	v8pp/call_from_v8.hpp
#	v8pp/class.hpp
#	v8pp/function.hpp
pmed added a commit that referenced this issue Jul 21, 2019
...using it only in test_call_from_v8.cpp

Refine in context of #113
@pmed
Copy link
Owner

pmed commented Jul 21, 2019

Hi @tim-janik

I've added v8pp::class_::auto_wrap_objects() function to set a flag, that allows automatic wrapping of C++ objects returned from a C++ function. Actual copy and wrapping is performed in a class_::find_object(obj) function overloading for a C++ referenced to obj.

Please see the test_auto_wrap_objects() for a usage example. I would appreciate for a feedback, whether this feature is usable for you.

This implementation has also been backported from master to the recent c++17 branch. The issue is still open, because I also need to update the documentation.

Best regards,
Pavel

@tim-janik
Copy link
Contributor Author

Thanks @pmed.

One question, I was expecting auto_wrap_objects() to instantiate a template that calls the copy ctor. So that having a copy ctor only becomes a requirement for class_<> instances that call auto_wrap_objects() and not for others. Wouldn't the current implementation cause compiler errors when class_<> wraps a non-copyable type (e.g. a singleton) without calling auto_wrap_objects() ?

As an aside, I've run into major stability problems with my v8pp-based electron module (likely due to Electron instead of v8pp). But since debugging in Electron is exceptionally hard, we're probably moving to a JSON+IPC solution instead of using a v8pp based module. Our Jsonipc binding has taken lots of inspiration from the v8pp API, thank you for a great design. Here's the function implementing automatic copying/wrapping behavior via template instantiation as suggested above: https://github.com/tim-janik/beast/blob/a48588c8d838fc008c2c0651aa67b9f43c5c1162/jsonipc/jsonipc.hh#L891

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants