簡體   English   中英

從V8中的C ++回調調用Javascript函數

[英]Calling Javascript function from a C++ callback in V8

我正在嘗試在調用c ++回調時調用已注冊的JS函數,但由於我認為是范圍界定問題,因此我遇到了段錯誤。

 Handle<Value> addEventListener( const Arguments& args ) {
    HandleScope scope;
    if (!args[0]->IsFunction()) {
        return ThrowException(Exception::TypeError(String::New("Wrong arguments")));
    }

    Persistent<Function> fn = Persistent<Function>::New(Handle<Function>::Cast(args[0]));
    Local<Number> num = Number::New(registerListener(&callback, &fn));
    scope.Close(num);
}

發生事件時,將調用以下方法。 我假設這可能發生在V8正在執行JS的另一個線程上。

void callback(int event, void* context ) {
    HandleScope scope;
    Local<Value> args[] = { Local<Value>::New(Number::New(event)) };
    Persistent<Function> *func = static_cast<Persistent<Function> *>(context);
    (* func)->Call((* func), 1, args);

    scope.Close(Undefined());
}

這會導致分段錯誤:11.請注意,如果我直接通過addEventListener()對Persistent的引用來調用回調函數,它將正確執行該函數。

我假設我需要一個儲物櫃或隔離櫃? 看起來libuv的uv_queue_work()也許可以解決這個問題,但是由於我沒有啟動線程,所以我看不到如何使用它。

當您在代碼中聲明Persistent<Function> fn時, fn是堆棧分配的變量。

fn是一個Persistent<Function> ,它是一個句柄類,它將包含一個指向一些類型為Function堆分配值的指針,但fn本身在堆棧上。

這意味着,當您調用registerListener(&callback, &fn)&fn將使用句柄的地址(類型Persistent<Function> ),而不是堆上Function的地址。 當函數退出時,句柄將被銷毀,但Function本身將保留在堆中。

因此,作為修復,我建議傳遞Function的地址而不是句柄的地址,如下所示:

Persistent<Function> fn = Persistent<Function>::New(Handle<Function>::Cast(args[0]));
Local<Number> num = Number::New(registerListener(&callback, *fn));

(請注意, Persistent<T>上的operator*返回的是T*而不是更常規的T& ,請參見http://bespin.cz/~ondras/html/classv8_1_1Handle.html

您還必須調整callback以解決以下事實: context現在是指向Function的原始指針,如下所示:

Persistent<Function> func = static_cast<Function*>(context);
func->Call((* func), 1, args);

在這里從原始Function指針創建Persistent<Function>是可以的,因為我們知道context實際上是一個持久對象。

為了簡潔起見,我還將(*func)->Call(...)更改為func->Call(...) 對於V8手柄,它們執行相同的操作。

我知道這個問題有點老了,但是nodejs v0.10到v0.12進行了相當大的更新。 V8更改了v8 :: Persistent的行為。 v8 :: Persistent不再繼承自v8 :: Handle。 我正在更新一些代碼,發現以下方法有效...

  void resize(const v8::FunctionCallbackInfo<Value> &args) {
    Isolate *isolate = Isolate::GetCurrent();
    HandleScope scope(isolate);
    Persistent<Function> callback;
    callback.Reset(isolate, args[0].As<Function>())
    const unsigned argc = 2;
    Local<Value> argv[argc] = { Null(isolate), String::NewFromUtf8(isolate, "success") };
    Local<Function>::New(isolate, work->callback)->Call(isolate->GetCurrentContext()->Global(), argc, argv);
    callback.Reset();
  }

我相信此更新的目的是使暴露內存泄漏變得更加困難。 在節點v0.10中,您將執行以下操作...

  v8::Local<v8::Value> value = /* ... */;
  v8::Persistent<v8::Value> persistent = v8::Persistent<v8::Value>::New(value);
  // ...
  v8::Local<v8::Value> value_again = *persistent;
  // ...
  persistent.Dispose();
  persistent.Clear();

問題在於,在addEventListener中, Persistent<Function> fn在堆棧上分配,然后您將指向該指針的指針用作回調的上下文。

但是,因為fn是在堆棧上分配的,所以當addEventListener退出時,它會消失。 因此,有了回調context現在指向一些虛假值。

您應該分配一些堆空間,並將所需的所有數據放在那里的callback中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM