I work with embedded V8, not with node, so some of that is french to me :) I tried storing FunctionTemplate in a Value and encountered the same error. If you're keeping the persistent handles in a global collection in any case, you might consider taking a raw pointer to the Persistent, and storing that in a v8::External. Then you can static_cast it back to FunctionTemplate where you call "Inherit". It still means you're doing some deliberate garbage handling however.
On Friday, 23 October 2020 at 06:35:07 UTC+10:30 Rodrigo Hernandez wrote: > Hi Ben, > > Yes, however what I need to store is the v8::FunctionTemplate, > v8::Local<v8::FunctionTemplate> to be more specific, which does not inherit > from Value and there is a static_assert that checks for that. > > So perhaps, maybe if go to the real problem a different solution may arise. > > I have a Js wrapper C++ base class from which all C++-to-Js must inherit, > this is based on the code for Node.js, so when I write a new class that > inherits from this wrapper, I need to allocate a FunctionTemplate on the > isolate/context pair, like so: > > I removed some lines, but otherwise you can look at this code here: > https://github.com/AeonGames/AeonGUI/blob/master/core/dom/EventTarget.cpp#L23 > > void EventTarget::Initialize ( v8::Isolate* aIsolate ) > { > v8::Local<v8::Context> context = aIsolate->GetCurrentContext(); > //--------------------------------------- > // Store constructor on a callback data object > > v8::Local<v8::ObjectTemplate> constructor_data_template = > v8::ObjectTemplate::New ( aIsolate ); > constructor_data_template->SetInternalFieldCount ( 1 ); > v8::Local<v8::Object> constructor_data = > > constructor_data_template->NewInstance ( context > ).ToLocalChecked(); > > // Prepare EventTarget constructor template > v8::Local<v8::FunctionTemplate> constructor_template = > v8::FunctionTemplate::New ( aIsolate, JsObjectWrap::New<EventTarget>, > constructor_data ); > // <----- THIS IS THE FunctionTemplate I NEED TO STORE > > constructor_template->SetClassName ( v8::String::NewFromUtf8 ( > aIsolate, "EventTarget" ).ToLocalChecked() ); > > constructor_template->InstanceTemplate()->SetInternalFieldCount ( 1 ); > > > AddFunctionTemplate ( aIsolate, typeid ( EventTarget ), constructor_template > ); > // <---- THIS IS MY CURRENT SOLUTION > > //---------------------------------------------------------------- > > > v8::Local<v8::Function> event = event_template->GetFunction ( context > ).ToLocalChecked(); > context->Global()->Set ( context, v8::String::NewFromUtf8 ( > aIsolate, "Event" ).ToLocalChecked(), > event ).FromJust(); > > > v8::Local<v8::Function> constructor = > constructor_template->GetFunction ( context ).ToLocalChecked(); > constructor_data->SetInternalField ( 0, constructor ); > context->Global()->Set ( context, v8::String::NewFromUtf8 ( > > aIsolate, "EventTarget" > ).ToLocalChecked(), > constructor ).FromJust(); > } > > Then, when I want to have Node inherit from EventTarget I write a similar > static function (the previous one is also static) > https://github.com/AeonGames/AeonGUI/blob/master/core/dom/Node.cpp#L221 > > void Node::Initialize ( v8::Isolate* aIsolate ) > { > if ( HasFunctionTemplate ( aIsolate, typeid ( Node ) ) ) > { > throw std::runtime_error ( "Isolate already initialized." ); > } > > v8::Local<v8::Context> context = aIsolate->GetCurrentContext(); > > // Prepare Node constructor template > > v8::Local<v8::FunctionTemplate> constructor_template = > v8::FunctionTemplate::New ( aIsolate ); > > constructor_template->SetClassName ( v8::String::NewFromUtf8 ( > aIsolate, "Node" ).ToLocalChecked() ); > constructor_template->Inherit ( EventTarget::GetFunctionTemplate ( > aIsolate, typeid ( EventTarget ) ) ); > // <-- THIS IS WHAT I REALLY NEED > > > AddFunctionTemplate ( aIsolate, typeid ( Node ), constructor_template > ); > > > v8::Local<v8::Function> constructor = > constructor_template->GetFunction ( context ).ToLocalChecked(); > context->Global()->Set ( context, v8::String::NewFromUtf8 ( > aIsolate, "Node" ).ToLocalChecked(), > constructor ).FromJust(); > } > > As I said before, this works but I feel that makes the code too verbose > and prone to error, for example now I am now forced to have a trivial > Finalize function on all classes: > > void Node::Finalize ( v8::Isolate* aIsolate ) > { > RemoveFunctionTemplate ( aIsolate, typeid ( Node ) ); > } > > because the FunctionTemplate objects are stored as Persistent Handles in > this map: > > > static std::unordered_map<std::pair<v8::Isolate*, size_t>, > v8::Persistent<v8::FunctionTemplate, > v8::CopyablePersistentTraits<v8::FunctionTemplate>>> FunctionTemplates{}; > > So I need to free them all, unlike a Local. > > So, perhaps there is a way where I can either store the template in the > constructor, or maybe there is a way to have Node inherit from EventTarget > without requiring the FunctionTemplate, but instead require just the > function? > > Thanks for taking a look! > On Wednesday, October 21, 2020 at 5:39:59 PM UTC-6 boi...@gmail.com wrote: > >> Rodrigo, you should be able to trivially cast a v8::Function or >> v8::Object to v8::Value is that what you're trying to do? In that case you >> don't need to put them in a v8::External. You can pass those objects to >> data->SetInternalField safely I would think. >> Ben >> >> >> On Tuesday, 20 October 2020 at 15:10:00 UTC+10:30 Rodrigo Hernandez wrote: >> >>> So, coming back to this, is there a way to cast/convert/wrap a local >>> template (function or object) into a v8::Value? >>> I am thinking about hiding them inside an internal field so I could do: >>> >>> context->global()->GetFunction("constructor")->GetInternalField(X). >>> >>> how safe would it be to cast them to a void* and wrapping them inside a >>> v8::External? >>> >>> On Sunday, October 11, 2020 at 11:40:27 AM UTC-6 Rodrigo Hernandez wrote: >>> >>>> Thanks Ben, I see how those are less optimal, I was hoping for >>>> something along the lines of >>>> context->global()->GetFunctionTemplate("constructor"), or something along >>>> those lines. >>>> The only problem I have with my approach is that I need a Finalize >>>> function on each wrapped class that pretty much just resets the permanent >>>> handles. >>>> >>>> Thanks Again! >>>> On Sunday, October 11, 2020 at 1:49:10 AM UTC-6 Ben Noordhuis wrote: >>>> >>>>> On Sat, Oct 10, 2020 at 10:44 PM Rodrigo Hernandez >>>>> <kwizatz.ae...@gmail.com> wrote: >>>>> > >>>>> > Hello, >>>>> > >>>>> > So, suppose I am wrapping a C++ class around a JS constructor, I've >>>>> already created and initialized the isolate, created and initialized a >>>>> context, I have the FunctionTemplate for the constructor and I have >>>>> instantiated the function and I can call it from Js as x() or new X(), >>>>> > all this is fine, the function template context is finished and the >>>>> handle lost. >>>>> > >>>>> > But then I want to create another wrapped object for a class that >>>>> inherits from the first one. >>>>> > Is there a way to retrieve the base class FunctionTemplate so in the >>>>> child class I can call child->Inherit(base)? >>>>> > >>>>> > Is there another way of doing this? >>>>> > >>>>> > Right now I am keeping a C++ unordered_map of isolate to persistent >>>>> handle to function templates, and that works, but is that the only >>>>> option? >>>>> > >>>>> > Thanks! >>>>> >>>>> It's not the only option but it's a pretty good solution. Less optimal >>>>> solutions: >>>>> >>>>> - store them in the snapshot with SnapshotCreator::AddData() (but you >>>>> can only retrieve it once) >>>>> - scan the heap for them with Isolate::VisitHandlesWithClassIds(). >>>>> >>>>> No doubt there are more ways to stow them away somewhere. >>>>> >>>> -- -- v8-users mailing list v8-users@googlegroups.com http://groups.google.com/group/v8-users --- You received this message because you are subscribed to the Google Groups "v8-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to v8-users+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/v8-users/c6f2c0e0-128a-4f9a-81b1-5d75db9170afn%40googlegroups.com.