Skip to content
New issue

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

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

Already on GitHub? # 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

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

No branches or pull requests

2 participants