node.js — Как вызвать обратный вызов javascript из переполнения стека

Я пытаюсь вызвать обратный вызов в V8 из другой точки моей функции. Итак, этот фрагмент кода регистрирует обратный вызов:

        if (args.Length())
{
String::Utf8Value event(args[0]->ToString());
if (event.length())
{
Isolate* isolate = V8Interface::getCurrent()->getIsolate();

Locker locker(isolate);
HandleScope scope(isolate);

callback cb = callback(isolate, Local<Function>::Cast(args[1]));

if(!events.count(*event))
{
events[*event] = callbacks({ cb });
}
else
{
events.find(*event)->second.push_back(cb);
}
}
}

И этот называет это:

 void trigger(std::string event)
{

Isolate* isolate = V8Interface::getCurrent()->getIsolate();

Locker locker(isolate);
HandleScope scope(isolate);

if(events.count(event))
{
for(callback cb : events.find(event)->second)
{
Local<Function> local = Local<Function>::New(isolate, cb);
local->Call(isolate->GetCurrentContext()->Global(), 0, {});
}
}
}

Триггерная функция может быть вызвана где угодно в любое время в моем коде C ++. Я попробовал простой пример (init v8, затем вызвать триггер), и я получаю:

#
# Fatal error in C:\OgreSDK\Projects\whitedrop\third_party\io.js\deps\v8\src/api.h, line 386
# CHECK(allow_empty_handle || that != 0) failed
#

Это мое главное

Scribe::V8Interface v8Interface = Scribe::V8Interface();
v8Interface.initialize();

for(Whitedrop::WorldEvent* event : Whitedrop::worldEvents)
{
event->onStart();
}

Вы можете получить весь источник здесь:

https://github.com/whitedrop/whitedrop/tree/feature/v8

Строка 386:

/**
* Create a local handle for the content of another handle.
* The referee is kept alive by the local handle even when
* the original handle is destroyed/disposed.
*/
V8_INLINE static Local<T> New(Isolate* isolate, Handle<T> that); // <<<<<<
V8_INLINE static Local<T> New(Isolate* isolate,
const PersistentBase<T>& that);

РЕДАКТИРОВАТЬ: Я пытался, благодаря Бен Noordhuis, как это:

Isolate* isolate = V8Interface::getCurrent()->getIsolate();

Locker locker(isolate);
HandleScope scope(isolate);

callback cb;
cb.Reset(isolate, Local<Function>::Cast(args[1]));

И позвонить:

Isolate* isolate = V8Interface::getCurrent()->getIsolate();

Locker locker(isolate);
HandleScope scope(isolate);

if(events.count(event))
{
for(callback cb : events.find(event)->second)
{
Local<Function> local = Local<Function>::New(isolate, cb);
local->Call(isolate->GetCurrentContext()->Global(), 0, {});
}
}

Но та же ошибка: ‘(

4

Решение

Не уверен, что автору вопроса все еще нужен ответ. Тем не мение.

В продолжение предыдущего ответа о преобразовании локальных обработчиков в постоянные.
На странице документации по аддонам Node.js C ++ есть несколько примеров:

https://nodejs.org/api/addons.html#addons_function_factory

Для постоянных объектов они используют метод статического конструктора как настойчивый<функция>.
Когда модуль инициализирован, конструктор может быть инициализирован Сброс метод
как это (на самом деле я не нашел его описание в документах V8 — http://izs.me/v8-docs/classv8_1_1Persistent.html):

// some where in external class or as global var
static Persistent<Function> persistentCallback;

// when need to init
persistentCallback.Reset(isolate, f_tmpl->GetFunction());

Чтобы вызвать этот метод, когда это необходимо, вы должны использовать Местный Ручка приведена вот так:

Local<Function> f = Local<Function>::New(isoloate,persistentCallback)

Знайте, что вы не можете использовать Справиться указатели, потому что его :: Новый Метод не подходит для таких аргументов.

КСТАТИ. Я понял, что мне не нужно использовать обработчик Persistent в моем коде для хранения метода обратного вызова в случае, если я уже связал его в контексте JS. Похоже, что в этом случае он правильно управляется GC. Но нет другого способа разделить переменные между вызовами функций c ++, например. когда вы храните некоторые защищенные данные внутри вашего модуля.

2

Другие решения

Я думаю, что вы должны бросить Local<T> в Persistent<T> прежде чем хранить их в events, Если вы этого не сделаете, GC из v8 может собирать функции в любое время.

Handle<Function> args0 = Handle<Function>::Cast(args[0]);
Persistent<Function> pfn(args0);
callback cb = callback(isolate, pfn); // use Persistent<T> instead of Local<T>
0

По вопросам рекламы [email protected]