Reusing v8 context

107 views
Skip to first unread message

Marco Bambini

unread,
Nov 2, 2020, 4:36:33 AM11/2/20
to v8-users
Dear All,
I am a C developer quite new to v8 (I have limited c++ knowledge).
Sorry if I ask very basic questions.

I have a C application that need to execute some js code in different times preserving the same context.

My code looks like:
Header file
=========
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>

typedef struct V8Engine V8Engine;
typedef struct V8Context V8Context;
typedef struct V8Value V8Value;

V8Engine* V8EngineInit (const char *path);
void  V8EngineFree (V8Engine *engine);
V8Context* V8ContextCreate (V8Engine *engine);
void V8ContextFree (V8Context *context);
V8Value* V8ExecuteScript (V8Context *context, const char *script);
bool V8ValueIsError (V8Value *value);

#ifdef __cplusplus

}

#endif

#endif



C++ file
======
#include "libplatform/libplatform.h"
#include "v8.h"
#include "c8.h"

struct V8Engine {
    std::unique_ptr<v8::Platform> platform;
    v8::Isolate::CreateParams create_params;
    v8::Isolate *isolate;
    v8::Isolate::Scope *isolate_scope;

};

struct V8Context {
     V8Engine *engine;
     v8::Global<v8::Context> *context;
};

struct V8Value {

};



// MARK: -

extern "C" {

V8Engine* V8EngineInit (const char *path) {
    V8Engine *engine = (V8Engine *)calloc(1, sizeof(V8Engine));
    if (!engine) return nullptr;

    // Initialize V8
    v8::V8::InitializeICUDefaultLocation(path);
    v8::V8::InitializeExternalStartupData(path);
    engine->platform = v8::platform::NewDefaultPlatform();

    v8::V8::InitializePlatform(engine->platform.get());
    v8::V8::Initialize();

    engine->create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
    engine->isolate = v8::Isolate::New(engine->create_params);
    engine->isolate_scope = new v8::Isolate::Scope(engine->isolate);

    return engine;
}


void V8EngineFree (V8Engine *engine) {
    if (engine == NULL) return;

    if (engine->isolate_scope) {
        delete engine->isolate_scope;
    }

    if (engine->isolate) {
        engine->isolate->Dispose();
    }

    v8::V8::Dispose();
    v8::V8::ShutdownPlatform();

    if (engine->create_params.array_buffer_allocator) {
        delete engine->create_params.array_buffer_allocator;
    }

    engine->~V8Engine();
    free(engine);
}



V8Context* V8ContextCreate (V8Engine *engine) {
    V8Context *instance = (V8Context *)calloc(1, sizeof(V8Context));
    if (!instance) return nullptr;

    instance->engine = engine;
    v8::Local<v8::Context> local_context = v8::Context::New(engine->isolate);
    instance->context = new v8::Global<v8::Context>(engine->isolate, local_context);

    return instance;
}

void V8ContextFree (V8Context *context) {
    delete context->context;
    context->~V8Context();
    free(context);
}



V8Value* V8ExecuteScript (V8Context *instance, const char *script) {
    // Create a stack-allocated handle scope
    v8::HandleScope handle_scope(instance->engine->isolate);

    // Enter the context for compiling and running the script
    v8::Local<v8::Context> context(instance->context->Get(instance->engine->isolate));
    v8::Context::Scope context_scope(context);

    {
        // Create a string containing the JavaScript source code
        v8::Local<v8::String> source = v8::String::NewFromUtf8(instance->engine->isolate, script, v8::NewStringType::kNormal).ToLocalChecked();

        // Compile the source code
        v8::Local<v8::Script> script = v8::Script::Compile(context, source).ToLocalChecked();

        // Run the script to get the result
        v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();

        // Convert the result to an UTF8 string and print it
        v8::String::Utf8Value utf8(instance->engine->isolate, result);
        printf("%s\n", *utf8);
    }

    return nullptr;
}



bool V8ValueIsError (V8Value *value) {
    return false;
}

}

// main C file
==========
int main (int argc, char* argv[]) {
    V8Engine *vm = V8EngineInit(argv[0]);
    V8Context *context = V8ContextCreate(vm);

    const char *script1 = " function js_add_elements(var1, var2) { \
                                var var3 = parseInt(var1) + parseInt(var2); \
                                var result = 'Addition of ' + var1 + ' and ' + var2 + ' results ' + var3; \
                                return result; \
                        };";
    const char *script2 = "js_add_elements(2, 3);";
    const char *script3 = "js_add_elements(4, 5);";

    V8ExecuteScript(context, script1);
    V8ExecuteScript(context, script2);
    V8ExecuteScript(context, script3);

    V8ContextFree(context);
    V8EngineFree(vm);
}

When I run this code this error is printed on console:

#
# Fatal error in v8::HandleScope::CreateHandle()
# Cannot create a handle without a HandleScope
#

on the line
v8::Local<v8::Context> local_context = v8::Context::New(engine->isolate);

in
V8Context* V8ContextCreate (V8Engine *engine)

Please let me know what I am doing wrong (a fixed sample code would be extremely useful).

Thanks a lot,
Marco Bambini

Simon Zünd

unread,
Nov 2, 2020, 5:17:32 AM11/2/20
to v8-users
My guess is that in your V8ContextCreate function you also need a temporary HandleScope before you can make a global out of the context:

v8::HandleScope handle_scope(engine->isolate);

--
--
v8-users mailing list
v8-u...@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+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/v8-users/9da40893-5c6c-402b-89a8-d9a3ce617555n%40googlegroups.com.

Marco Bambini

unread,
Nov 2, 2020, 5:58:22 AM11/2/20
to v8-users
Not sure to understand, a temporary HandleScope already exists in my code:

// Create a stack-allocated handle scope

v8::HandleScope handle_scope(instance->engine->isolate);


// Enter the context for compiling and running the script

v8::Local<v8::Context> context(instance->context->Get(instance->engine->isolate));

v8::Context::Scope context_scope(context);


Marco Bambini

unread,
Nov 2, 2020, 6:11:46 AM11/2/20
to v8-users
Sorry I misread the function name. Now it works thanks a lot!

On Monday, November 2, 2020 at 11:17:32 AM UTC+1 szu...@google.com wrote:
Reply all
Reply to author
Forward
0 new messages