Keep v8 context alive for future reference

42 views
Skip to first unread message

Austin Einter

unread,
Jun 26, 2019, 11:05:49 PM6/26/19
to v8-users
Dear All
I am quite new to v8. I am a c developer, with limited c++ knowledge. Sorry if I ask very basic questions.

I have a C application, that interacts with web servers. Gets javascript. Need to execute javascript.
Imagine a situation, where I get total 2 javascript files from server.

js1.js
function js_add_elements(var1, var2) 
{ 
    var var3 = parseInt(var1) + parseInt(var2); 
    var result = 'Addition of ' + var1 + ' and ' + var2 + ' results ' + var3; 
    return result; 
}

js2.js
js_add_elements(2, 3);


I have my c code as below.

Header file
typedef struct
{
    std::unique_ptr<v8::Platform> platform;
    v8::Isolate::CreateParams create_params;
    v8::Isolate *isolate;
    v8::Isolate::Scope *isolate_scope;
}MJSEInstance;

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Create MJSE instance
*/
void *mjse_create_instance(char **argv);

/**
* @brief Destroy MJSE instance
* @param instance -> MJSE instance
*/
void mjse_destroy_instance(void *instance);

/**
* @brief Executes a script
* @param minstance - MJSE instance
* @param jscript - the javascript
* @param scriptlen - Length of script
*/
void mjse_execute_script(void *instance, char *jscript);

#ifdef __cplusplus
}
#endif

CPP File
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "include/libplatform/libplatform.h"
#include "include/v8.h"
#include "mjse.h"
#include "mjse_int.h"
#include <new>

extern "C"  {
using namespace v8;

void *mjse_create_instance(char **argv)
{
    MJSEInstance *instance = (MJSEInstance *)calloc(1, sizeof(MJSEInstance));
    
    v8::V8::InitializeICUDefaultLocation(argv[0]);
    v8::V8::InitializeExternalStartupData(argv[0]);
    instance->platform = v8::platform::NewDefaultPlatform();

    v8::V8::InitializePlatform(instance->platform.get());
    v8::V8::Initialize();
    
    instance->create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
    instance->isolate = v8::Isolate::New(instance->create_params);
    instance->isolate_scope  = new v8::Isolate::Scope(instance->isolate);
    
    return instance;
}

void mjse_destroy_instance(void *minstance)
{
    MJSEInstance *instance = (MJSEInstance *)minstance;
    
    if(instance == NULL)
        return;
    
    if(instance->isolate_scope)
    {
        delete instance->isolate_scope;
    }
    
    if(instance->isolate)
    {
        instance->isolate->Dispose();
    }

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

    if(instance->create_params.array_buffer_allocator)
    {
        delete instance->create_params.array_buffer_allocator;
    }
    
    instance->~MJSEInstance();
    free(instance);
}


void mjse_execute_script(void *minstance, char *jscript)
{
    MJSEInstance *instance = (MJSEInstance *)minstance;

    // Create a stack-allocated handle scope.
    v8::HandleScope handle_scope(instance->isolate);

    // Create a new context.
    v8::Local<v8::Context> context = v8::Context::New(instance->isolate);
    
    // Enter the context for compiling and running the hello world script.
    v8::Context::Scope context_scope(context);

    {

        // Create a string containing the JavaScript source code.
        v8::Local<v8::String> source =
          v8::String::NewFromUtf8(instance->isolate, jscript,
          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->isolate, result);
        printf("%s\n", *utf8);
    }
}
}

Main File
int main(int argc, char **argv)
{
    char *script;
    void *instance;

    instance = mjse_create_instance(argv);

    script =    "function js_add_elements(var1, var2) \
                { \
                    var var3 = parseInt(var1) + parseInt(var2); \
                    var result = 'Addition of ' + var1 + ' and ' + var2 + ' results ' + var3; \
                    return result; \
                };";
    mjse_execute_script(instance, script);

    script = "js_add_elements(2, 3);";
    mjse_execute_script(instance, script);

    mjse_destroy_instance(instance);
    return 0;
}

Now whats happening, while executing javascript first time it executes fine. But while trying to execute second time (letter in red), it gets exception.

I understand, it is creating new v8 Local context each time, and does not have js1.js details, hence getting exception. I also found in web we can have v8 Global context and refer the context while executing for second time.

However I have not been able to find, how to declare v8 global context and store / move v8 local context there and refer it during second time execution. Please let me know with a sample/example code.

Thanks
Austin 

Ben Noordhuis

unread,
Jun 27, 2019, 4:39:04 AM6/27/19
to v8-users
You can make the context persistent like this:

if (instance->context == nullptr) {
v8::Local<v8::Context> context = v8::Context::New(instance->isolate);
instance->context = new v8::Global<v8::Context>(instance->isolate, context);
}

v8::Local<v8::Context> context(instance->isolate, instance->context);
v8::Context::Scope context_scope(context);

Austin Einter

unread,
Jun 27, 2019, 8:05:10 AM6/27/19
to v8-u...@googlegroups.com
Thanks Ben. I followed your suggestion.
I added v8::Global<v8::Context> *context; member in instance structure.

I put the code as below.

    if(instance->context == nullptr)

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

 For last line (in red) I am getting below compilation error.

error: no matching function for call to ‘v8::Local<v8::Context>::Local(v8::Isolate*&, v8::Global<v8::Context>*&)’

Please let me know what I need to do to avoid this error.

Thanks
Austin


--
--
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/CAHQurc8H1d8Stfhw7rAGac9ZSL3pS5mOmrR-9%3DjGLtW2ZtMunQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Austin Einter

unread,
Jun 27, 2019, 8:27:46 AM6/27/19
to v8-u...@googlegroups.com
I changed the line to
v8::Local<v8::Context> context(instance->context->Get(instance->isolate));

It is compiling also working fine.

However when I execute this executable with valgrind, I get lot of "Conditional jump or move depends on uninitialised value(s)"

One such conditional jump is given below.

==5158== Conditional jump or move depends on uninitialised value(s)
==5158==    at 0x8F0868: v8::internal::DeclarationScope::CheckConflictingVarDeclarations() (in /home/user/mjse)
==5158==    by 0x4D8F68: v8::internal::PreParser::PreParseFunction(v8::internal::AstRawString const*, v8::internal::FunctionKind, v8::internal::FunctionLiteral::FunctionType, v8::internal::DeclarationScope*, int*, v8::internal::ProducedPreparseData**, int) (in /home/user/mjse)
==5158==    by 0x4B7935: v8::internal::Parser::SkipFunction(v8::internal::AstRawString const*, v8::internal::FunctionKind, v8::internal::FunctionLiteral::FunctionType, v8::internal::DeclarationScope*, int*, int*, v8::internal::ProducedPreparseData**) (in /home/user/mjse)
==5158==    by 0x4AB715: v8::internal::Parser::ParseFunctionLiteral(v8::internal::AstRawString const*, v8::internal::Scanner::Location, v8::internal::FunctionNameValidity, v8::internal::FunctionKind, int, v8::internal::FunctionLiteral::FunctionType, v8::internal::LanguageMode, v8::internal::ZoneList<v8::internal::AstRawString const*>*) (in /home/user/mjse)
==5158==    by 0x4D1EFA: v8::internal::ParserBase<v8::internal::Parser>::ParseHoistableDeclaration(int, v8::base::Flags<v8::internal::ParseFunctionFlag, int>, v8::internal::ZoneList<v8::internal::AstRawString const*>*, bool) (in /home/user/mjse)
==5158==    by 0x4AA266: v8::internal::Parser::DoParseProgram(v8::internal::Isolate*, v8::internal::ParseInfo*) (in /home/user/mjse)
==5158==    by 0x4A9958: v8::internal::Parser::ParseProgram(v8::internal::Isolate*, v8::internal::ParseInfo*) (in /home/user/mjse)
==5158==    by 0x4D5759: v8::internal::parsing::ParseProgram(v8::internal::ParseInfo*, v8::internal::Isolate*) (in /home/user/mjse)
==5158==    by 0x22A835: v8::internal::(anonymous namespace)::CompileToplevel(v8::internal::ParseInfo*, v8::internal::Isolate*, v8::internal::IsCompiledScope*) (in /home/user/mjse)
==5158==    by 0x22C128: v8::internal::Compiler::GetSharedFunctionInfoForScript(v8::internal::Isolate*, v8::internal::Handle<v8::internal::String>, v8::internal::Compiler::ScriptDetails const&, v8::ScriptOriginOptions, v8::Extension*, v8::internal::ScriptData*, v8::ScriptCompiler::CompileOptions, v8::ScriptCompiler::NoCacheReason, v8::internal::NativesFlag) (in /home/user/mjse)
==5158==    by 0x1F0EE4: v8::ScriptCompiler::CompileUnboundInternal(v8::Isolate*, v8::ScriptCompiler::Source*, v8::ScriptCompiler::CompileOptions, v8::ScriptCompiler::NoCacheReason) (in /home/user/mjse)
==5158==    by 0x1F15D6: v8::ScriptCompiler::Compile(v8::Local<v8::Context>, v8::ScriptCompiler::Source*, v8::ScriptCompiler::CompileOptions, v8::ScriptCompiler::NoCacheReason) (in /home/user/mjse)
==5158== 


What could be the issue?

Thanks
Austin



Jakob Kummerow

unread,
Jun 27, 2019, 8:41:09 AM6/27/19
to v8-users
Could be a bug in valgrind, or a bug in V8. Getting a line number would be helpful, along with the exact version of V8. At a quick glance, I don't see any uninitialized variables in DeclarationScope::CheckConflictingVarDeclarations.

Austin Einter

unread,
Jun 27, 2019, 8:55:46 AM6/27/19
to v8-u...@googlegroups.com
One more observation, if I do not keep any argument in my javascript then I do not see conditional jump. I changed my first javascript to as given below, with this the conditional jump is not shown in valgrind report.

js1.js
function js_add_elements() 
{ 
    return 10; 
}

Austin Einter

unread,
Jun 27, 2019, 9:33:53 AM6/27/19
to v8-u...@googlegroups.com
Hi Jakob
Thanks for response.

Version: 7.7.0 (candidate)
(Got the version with printf("Version: %s", v8::V8::GetVersion());)

Line number, valgrind output does not show. Probably I need to rebuild v8 in debug mode.
I enabled --track-origin option in valgrind while executing. With this I get below report. Please see the text in red. The uninitialised value originates from those functions.



==7113==
==7113== Conditional jump or move depends on uninitialised value(s)
==7113==    at 0x8F0868: v8::internal::DeclarationScope::CheckConflictingVarDeclarations() (in /home/user/mjse)
==7113==    by 0x4D8F68: v8::internal::PreParser::PreParseFunction(v8::internal::AstRawString const*, v8::internal::FunctionKind, v8::internal::FunctionLiteral::FunctionType, v8::internal::DeclarationScope*, int*, v8::internal::ProducedPreparseData**, int) (in /home/user/mjse)
==7113==    by 0x4B7935: v8::internal::Parser::SkipFunction(v8::internal::AstRawString const*, v8::internal::FunctionKind, v8::internal::FunctionLiteral::FunctionType, v8::internal::DeclarationScope*, int*, int*, v8::internal::ProducedPreparseData**) (in /home/user/mjse)
==7113==    by 0x4AB715: v8::internal::Parser::ParseFunctionLiteral(v8::internal::AstRawString const*, v8::internal::Scanner::Location, v8::internal::FunctionNameValidity, v8::internal::FunctionKind, int, v8::internal::FunctionLiteral::FunctionType, v8::internal::LanguageMode, v8::internal::ZoneList<v8::internal::AstRawString const*>*) (in /home/user/mjse)
==7113==    by 0x4D1EFA: v8::internal::ParserBase<v8::internal::Parser>::ParseHoistableDeclaration(int, v8::base::Flags<v8::internal::ParseFunctionFlag, int>, v8::internal::ZoneList<v8::internal::AstRawString const*>*, bool) (in /home/user/mjse)
==7113==    by 0x4AA266: v8::internal::Parser::DoParseProgram(v8::internal::Isolate*, v8::internal::ParseInfo*) (in /home/user/mjse)
==7113==    by 0x4A9958: v8::internal::Parser::ParseProgram(v8::internal::Isolate*, v8::internal::ParseInfo*) (in /home/user/mjse)
==7113==    by 0x4D5759: v8::internal::parsing::ParseProgram(v8::internal::ParseInfo*, v8::internal::Isolate*) (in /home/user/mjse)
==7113==    by 0x22A835: v8::internal::(anonymous namespace)::CompileToplevel(v8::internal::ParseInfo*, v8::internal::Isolate*, v8::internal::IsCompiledScope*) (in /home/user/mjse)
==7113==    by 0x22C128: v8::internal::Compiler::GetSharedFunctionInfoForScript(v8::internal::Isolate*, v8::internal::Handle<v8::internal::String>, v8::internal::Compiler::ScriptDetails const&, v8::ScriptOriginOptions, v8::Extension*, v8::internal::ScriptData*, v8::ScriptCompiler::CompileOptions, v8::ScriptCompiler::NoCacheReason, v8::internal::NativesFlag) (in /home/user/mjse)
==7113==    by 0x1F0EE4: v8::ScriptCompiler::CompileUnboundInternal(v8::Isolate*, v8::ScriptCompiler::Source*, v8::ScriptCompiler::CompileOptions, v8::ScriptCompiler::NoCacheReason) (in /home/user/mjse)
==7113==    by 0x1F15D6: v8::ScriptCompiler::Compile(v8::Local<v8::Context>, v8::ScriptCompiler::Source*, v8::ScriptCompiler::CompileOptions, v8::ScriptCompiler::NoCacheReason) (in /home/user/mjse)


==7113==  Uninitialised value was created by a heap allocation
==7113==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7113==    by 0x555D7D: v8::internal::AllocWithRetry(unsigned long) (in /home/user/mjse)
==7113==    by 0x5A2C14: v8::internal::AccountingAllocator::AllocateSegment(unsigned long) (in /home/user/mjse)
==7113==    by 0x5A2EAA: v8::internal::Zone::NewExpand(unsigned long) (in /home/user/mjse)
==7113==    by 0x8E6E32: v8::internal::AstValueFactory::NewConsString() (in /home/user/mjse)
==7113==    by 0x4A624B: v8::internal::ParseInfo::GetOrCreateAstValueFactory() (in /home/user/mjse)
==7113==    by 0x4A91C8: v8::internal::Parser::Parser(v8::internal::ParseInfo*) (in /home/user/mjse)

==7113==    by 0x4D574B: v8::internal::parsing::ParseProgram(v8::internal::ParseInfo*, v8::internal::Isolate*) (in /home/user/mjse)
==7113==    by 0x22A835: v8::internal::(anonymous namespace)::CompileToplevel(v8::internal::ParseInfo*, v8::internal::Isolate*, v8::internal::IsCompiledScope*) (in /home/user/mjse)
==7113==    by 0x22C128: v8::internal::Compiler::GetSharedFunctionInfoForScript(v8::internal::Isolate*, v8::internal::Handle<v8::internal::String>, v8::internal::Compiler::ScriptDetails const&, v8::ScriptOriginOptions, v8::Extension*, v8::internal::ScriptData*, v8::ScriptCompiler::CompileOptions, v8::ScriptCompiler::NoCacheReason, v8::internal::NativesFlag) (in /home/user/mjse)
==7113==    by 0x1F0EE4: v8::ScriptCompiler::CompileUnboundInternal(v8::Isolate*, v8::ScriptCompiler::Source*, v8::ScriptCompiler::CompileOptions, v8::ScriptCompiler::NoCacheReason) (in /home/user/mjse)
==7113==    by 0x1F15D6: v8::ScriptCompiler::Compile(v8::Local<v8::Context>, v8::ScriptCompiler::Source*, v8::ScriptCompiler::CompileOptions, v8::ScriptCompiler::NoCacheReason) (in /home/user/mjse)
==7113== 

On Thu, Jun 27, 2019 at 6:11 PM Jakob Kummerow <jkum...@chromium.org> wrote:
Reply all
Reply to author
Forward
0 new messages