3

I would like to implement this functionality in an embedded JavaScript application that uses v8 engine.

function myFunction1() {
   //do stuff
}

function myFunction2() {
   //do other stuff
}

myAddon.addCallback(myFunction1);
myAddon.addCallback(myFunction2);
myAddon.removeCallback(myFunction1);

In order to do this I need to store these functions in a std::set like so

void addCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
   v8::HandleScope scope(args.GetIsolate());
   v8::Local<v8::Function> cb = v8::Local<v8::Function>::Cast(args[0]);
   std::set mySet = this->mySet;
   //now how do I insert a reference to this function into mySet so I can retrieve
   //it later
}

void removeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
   v8::HandleScope scope(args.GetIsolate());
   v8::Local<v8::Function> cb = v8::Local<v8::Function>::Cast(args[0]);
   std::set mySet = this->mySet;
   //now how do I remove the element in this set that refers to this function?
}

How does one go about doing this? I don't want to use v8::Object::GetIdentityHash() because the result is not guaranteed to be unique.

I also can't just store the Local in the std::set because the copy constructor is private and it would also get descoped once removeCallback or addCallback return.

Thanks for any help in advance.

Edit: I realize I could write some javascript to do the function hashing for me, and then call one C++ binded function to iteration through all the callbacks, but I'd rather not do this every time I need to store sets or hashes of JavaScript objects.

robot_guy
  • 31
  • 3

1 Answers1

4

This is correct that you can't safely store Local<T> handle, because when it gets out of scope, your function object may become available to garbage collection. What you need is a persistent handle. You can construct it out of local like:

v8::Local<v8::Function> cb = v8::Local<v8::Function>::Cast(args[0]);
v8::Persistent<v8::Function, v8::CopyablePersistentTraits<v8::Function>> value(isolate, cb);

Note CopyablePersistentTraits which allows handle copying. There is also NonCopyablePersistentTraits if you would like to prevent that.

Now you can put it in a vector:

std::vector<v8::Persistent<v8::Function, v8::CopyablePersistentTraits<v8::Function>>> v;
v.push_back(value);

Convert back to local:

v8::Local<v8::Function> local = v8::Local<v8::Function>::New(isolate, value);

For std::set you also need to provide comparison function for elements. It also might be a good idea to wrap v8::Persistent<T> into your own class like PersistentWrapper<T> (this is what I am doing in my project) to get the desired behavior.

iefserge
  • 1,136
  • 1
  • 10
  • 10
  • Yes, sorry you are correct, those would have to be persistent objects so they wouldn't lose scope. Can you provide an example of how you wrap Persistent? Thanks – robot_guy Jan 22 '14 at 18:39
  • For example https://gist.github.com/anonymous/8565705 (c++11). I don't need objects hashing though. Is the only reason for hashing that you can remove callback later? – iefserge Jan 22 '14 at 20:04