как получить возвращаемое значение функции JS из V8?

В настоящее время я пытаюсь получить возвращаемое значение функции, которую я вызываю в JS. Следующий код может воспроизвести его (за исключением версии 8)

#include "v8.h"
#include "libplatform/libplatform.h"
#include <string>
#include <cassert>

int64_t repro() 
{
    auto isolate = v8::Isolate::New(initializer.create_params_);
    assert(isolate != nullptr);
    v8::Isolate::Scope isolate_scope(isolate);
    v8::HandleScope handle_scope(isolate);
    auto context = v8::Context::New(isolate);
    v8::Context::Scope context_scope(context);
    assert(context.IsEmpty() == false);
    auto global = context->Global();

    std::string script = "function foo() {\n"
                         "  return BigInt(1);\n"
                         "}";

    v8::Local<v8::String> sourceScript =
        v8::String::NewFromUtf8(isolate, script.c_str(),
                                v8::NewStringType::kNormal)
            .ToLocalChecked();
    v8::Local<v8::Script> s =
        v8::Script::Compile(context, sourceScript).ToLocalChecked();
    s->Run(context);

     v8::Local<v8::String> name =
        v8::String::NewFromUtf8(isolate, "foo",
                                v8::NewStringType::kInternalized)
            .ToLocalChecked();
    auto value = global->Get(context, name).ToLocalChecked();
    assert(value->IsFunction());
    auto func = v8::Handle<v8::Function>::Cast(value);

    auto result = func->Call(context, context->Global(), 0, nullptr)
                      .ToLocalChecked();
    assert(result->IsBigInt());
    auto bigint = result->IntegerValue(context);
    assert(bigint.IsNothing() == false);
    return bigint.ToChecked();
}

когда я теперь смотрю на bigint - тип сообщает как BigInt, но IsNothing () возвращает true. Что я делаю неправильно?

Спасибо

Тобиас


person Tobias Langner    schedule 05.05.2020    source источник


Ответы (1)


Как сказано в документации, v8::Value::IntegerValue() "возвращает эквивалент ToInteger()->Value()", что означает, что он генерирует исключение (т. Е. Возвращает Nothing) при вызове на BigInt, отражая тот факт, что в JavaScript, вызывая "абстрактную операцию" _ 5_ в BigInt выдает TypeError, или, другими словами: BigInt не просто неявно конвертируется в Number.

Чтобы извлечь значение BigInt из C ++, вы можете сделать это:

int64_t bigint = v8::Local<v8::BigInt>::cast(result)->Int64Value();

Конечно, это даст неверный результат, если значение BigInt больше, чем int64. Требуется необязательный bool*, чтобы указать, было ли преобразование в int64 без потерь или с усечением. Если вам нужно получить большие значения, вы можете использовать метод ToWordsArray(...).

как получить возвращаемое значение функции JS из V8?

Точно так же, как и вы:

v8::MaybeLocal<v8::Value> result = func->Call(...);

Обратите внимание, что использование .ToLocalChecked(); рискованно: если функция выдает исключение вместо возврата значения, .ToLocalChecked() выдает сбой. Если вы не контролируете код функции и, следовательно, не можете гарантировать, что она не сработает, тогда лучше проверить, является ли результат пустым, и аккуратно обработать исключения. См. Каталог samples/ V8 или документацию на v8.dev/docs/, где можно найти множество примеров и дополнительные объяснения.

(Примечание: я бы рекомендовал использовать auto гораздо меньше. Это помогает увидеть типы. Различия, скажем, между v8::Value, v8::Local<v8::Value>, v8::MaybeLocal<v8::Value> и v8::Local<v8::BigInt> значительны, и это помогает вам писать правильный код, когда вы не просто спрячьте их за auto.)

person jmrk    schedule 05.05.2020