I am trying to use v8 in C++, I want to compile the js code in main thread and then I pass the compiled_script
to the executor(child Thread). the Run
execution process will run in threads.
Story: compile process is expensive and I need performance, therefore I will cache all compiled script at the beginning and will pass them to different threads for execution.
for testing this scenario I just create only one thread and passed the compiled script to it, after 1500 iteration in for
loop, the program exited with Segmentation Fault Error.
The problem is related to thread, if I move the execution to outside the thread, it will successfully ended.
I investigate more but can not find any solutions.
Complete Code :
#include "include/libplatform/libplatform.h"
#include "include/v8.h"
#include <future>
#include <iostream>
#include <string>
#include <thread>
bool ExecuteScript(v8::Isolate *isolate,
v8::MaybeLocal<v8::Script> compiled_script) {
v8::HandleScope handle_scope(isolate);
v8::TryCatch try_catch(isolate);
v8::Local<v8::Context> context(isolate->GetCurrentContext());
v8::Local<v8::Value> result;
v8::Local<v8::Script> c = compiled_script.FromMaybe(v8::Local<v8::Script>());
if (c.IsEmpty())
std::cout << "Compile Script is Empty" << std::endl;
if (context.IsEmpty())
std::cout << "Conetxt is Empty" << std::endl;
auto x = c->Run(context);
if (!x.ToLocal(&result)) {
v8::String::Utf8Value error(isolate, try_catch.Exception());
std::cout << *error << std::endl;
return false;
}
return true;
}
v8::MaybeLocal<v8::Script> CompileScript(v8::Isolate *isolate,
v8::Local<v8::String> raw_source) {
v8::ScriptCompiler::Source source(raw_source);
auto unboundedScript =
v8::ScriptCompiler::CompileUnboundScript(
isolate, &source,
v8::ScriptCompiler::CompileOptions::kNoCompileOptions)
.ToLocalChecked();
return unboundedScript->BindToCurrentContext();
}
int main() {
v8::Isolate::CreateParams create_params;
v8::Isolate *isolate;
std::unique_ptr<v8::Platform> platform;
v8::Global<v8::Context> context_;
v8::V8::InitializeICUDefaultLocation(".");
v8::V8::InitializeExternalStartupData(".");
platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
create_params.array_buffer_allocator =
v8::ArrayBuffer::Allocator::NewDefaultAllocator();
isolate = v8::Isolate::New(create_params);
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope scope(isolate);
v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
context_.Reset(isolate, context);
{
auto tt = std::async(std::launch::async, [&]() {
v8::Locker locker(isolate);
v8::HandleScope thread_scope(isolate);
v8::Context::Scope context_scope(context);
v8::MaybeLocal<v8::Script> compliedScript = CompileScript(
isolate,
v8::String::NewFromUtf8Literal(isolate, "var j=0; while(j<5) j++; "));
for (int i = 0; i < 1000000; i++) {
std::cout << i << std::endl;
if (!ExecuteScript(isolate, compliedScript)) {
std::cout << "Execution Error" << std::endl;
return;
}
}
});
tt.wait();
}
v8::V8::Dispose();
v8::V8::ShutdownPlatform();
delete create_params.array_buffer_allocator;
std::cout << "Exit Normal" << std::endl;
return 0;
}
How can I fix this ?
Edit1:
- Code Cleanup
- valgrind memory leak result :
==2588106== Warning: set address range perms: large range [0x2bf200000000, 0x2bf400000000) (noaccess)
==2588106== Warning: set address range perms: large range [0x2bf200000000, 0x2bf400000000) (noaccess)
==2588106== Warning: set address range perms: large range [0x2bf200000000, 0x2bf300000000) (noaccess)==2588106== Thread 9:
==2588106== Invalid read of size 8
==2588106== at 0x2D7B24: v8::internal::Isolate::main_thread_local_heap() (in /home/linux/v8)
==2588106== by 0x3F07EA: v8::internal::interpreter::BytecodeArrayIterator::BytecodeArrayIterator(v8::internal::Handle<v8::internal::BytecodeArray>, int) (in /home/linux/v8)
==2588106== by 0xD7EC2B: v8::internal::compiler::BytecodeGraphBuilder::BytecodeGraphBuilder(v8::internal::compiler::JSHeapBroker*, v8::internal::Zone*, v8::internal::compiler::NativeContextRef const&, v8::internal::compiler::SharedFunctionInfoRef const&, v8::internal::compiler::FeedbackCellRef const&, v8::internal::BytecodeOffset, v8::internal::compiler::JSGraph*, v8::internal::compiler::CallFrequency const&, v8::internal::compiler::SourcePositionTable*, int, v8::internal::CodeKind, v8::base::Flags<v8::internal::compiler::BytecodeGraphBuilderFlag, int>, v8::internal::TickCounter*, v8::internal::compiler::ObserveNodeInfo const&) (in /home/linux/v8)
==2588106== by 0xD92621: v8::internal::compiler::BuildGraphFromBytecode(v8::internal::compiler::JSHeapBroker*, v8::internal::Zone*, v8::internal::compiler::SharedFunctionInfoRef const&, v8::internal::compiler::FeedbackCellRef const&, v8::internal::BytecodeOffset, v8::internal::compiler::JSGraph*, v8::internal::compiler::CallFrequency const&, v8::internal::compiler::SourcePositionTable*, int, v8::internal::CodeKind, v8::base::Flags<v8::internal::compiler::BytecodeGraphBuilderFlag, int>, v8::internal::TickCounter*, v8::internal::compiler::ObserveNodeInfo const&) (in /home/linux/v8)
==2588106== by 0x80E6FD: v8::internal::compiler::GraphBuilderPhase::Run(v8::internal::compiler::PipelineData*, v8::internal::Zone*) (in /home/linux/v8)
==2588106== by 0x7FFE81: void v8::internal::compiler::PipelineImpl::Run<v8::internal::compiler::GraphBuilderPhase>() (in /home/linux/v8)
==2588106== by 0x7FC747: v8::internal::compiler::PipelineImpl::CreateGraph() (in /home/linux/v8)
==2588106== by 0x7FC10F: v8::internal::compiler::PipelineCompilationJob::PrepareJobImpl(v8::internal::Isolate*) (in /home/linux/v8)
==2588106== by 0x253924: v8::internal::OptimizedCompilationJob::PrepareJob(v8::internal::Isolate*) (in /home/linux/v8)
==2588106== by 0x25F4E5: v8::internal::(anonymous namespace)::GetOptimizedCodeLater(std::unique_ptr<v8::internal::OptimizedCompilationJob, std::default_delete<v8::internal::OptimizedCompilationJob> >, v8::internal::Isolate*, v8::internal::OptimizedCompilationInfo*, v8::internal::CodeKind, v8::internal::Handle<v8::internal::JSFunction>) (in /home/linux/v8)
==2588106== by 0x25862D: v8::internal::(anonymous namespace)::GetOptimizedCode(v8::internal::Handle<v8::internal::JSFunction>, v8::internal::ConcurrencyMode, v8::internal::CodeKind, v8::internal::BytecodeOffset, v8::internal::JavaScriptFrame*) (in /home/linux/v8)
==2588106== by 0x259905: v8::internal::Compiler::CompileOptimized(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::ConcurrencyMode, v8::internal::CodeKind) (in /home/linux/v8)
==2588106== Address 0xc1f8 is not stack'd, malloc'd or (recently) free'd
==2588106==
==2588106==
==2588106== Access not within mapped region at address 0xC1F8
==2588106== at 0x2D7B24: v8::internal::Isolate::main_thread_local_heap() (in /home/linux/v8)
==2588106== by 0x3F07EA: v8::internal::interpreter::BytecodeArrayIterator::BytecodeArrayIterator(v8::internal::Handle<v8::internal::BytecodeArray>, int) (in /home/linux/v8)
==2588106== by 0xD7EC2B: v8::internal::compiler::BytecodeGraphBuilder::BytecodeGraphBuilder(v8::internal::compiler::JSHeapBroker*, v8::internal::Zone*, v8::internal::compiler::NativeContextRef const&, v8::internal::compiler::SharedFunctionInfoRef const&, v8::internal::compiler::FeedbackCellRef const&, v8::internal::BytecodeOffset, v8::internal::compiler::JSGraph*, v8::internal::compiler::CallFrequency const&, v8::internal::compiler::SourcePositionTable*, int, v8::internal::CodeKind, v8::base::Flags<v8::internal::compiler::BytecodeGraphBuilderFlag, int>, v8::internal::TickCounter*, v8::internal::compiler::ObserveNodeInfo const&) (in /home/linux/v8)
==2588106== by 0xD92621: v8::internal::compiler::BuildGraphFromBytecode(v8::internal::compiler::JSHeapBroker*, v8::internal::Zone*, v8::internal::compiler::SharedFunctionInfoRef const&, v8::internal::compiler::FeedbackCellRef const&, v8::internal::BytecodeOffset, v8::internal::compiler::JSGraph*, v8::internal::compiler::CallFrequency const&, v8::internal::compiler::SourcePositionTable*, int, v8::internal::CodeKind, v8::base::Flags<v8::internal::compiler::BytecodeGraphBuilderFlag, int>, v8::internal::TickCounter*, v8::internal::compiler::ObserveNodeInfo const&) (in /home/linux/v8)
==2588106== by 0x80E6FD: v8::internal::compiler::GraphBuilderPhase::Run(v8::internal::compiler::PipelineData*, v8::internal::Zone*) (in /home/linux/v8)
==2588106== by 0x7FFE81: void v8::internal::compiler::PipelineImpl::Run<v8::internal::compiler::GraphBuilderPhase>() (in /home/linux/v8)
==2588106== by 0x7FC747: v8::internal::compiler::PipelineImpl::CreateGraph() (in /home/linux/v8)
==2588106== by 0x7FC10F: v8::internal::compiler::PipelineCompilationJob::PrepareJobImpl(v8::internal::Isolate*) (in /home/linux/v8)
==2588106== by 0x253924: v8::internal::OptimizedCompilationJob::PrepareJob(v8::internal::Isolate*) (in /home/linux/v8)
==2588106== by 0x25F4E5: v8::internal::(anonymous namespace)::GetOptimizedCodeLater(std::unique_ptr<v8::internal::OptimizedCompilationJob, std::default_delete<v8::internal::OptimizedCompilationJob> >, v8::internal::Isolate*, v8::internal::OptimizedCompilationInfo*, v8::internal::CodeKind, v8::internal::Handle<v8::internal::JSFunction>) (in /home/linux/v8)
==2588106== by 0x25862D: v8::internal::(anonymous namespace)::GetOptimizedCode(v8::internal::Handle<v8::internal::JSFunction>, v8::internal::ConcurrencyMode, v8::internal::CodeKind, v8::internal::BytecodeOffset, v8::internal::JavaScriptFrame*) (in /home/linux/v8)
==2588106== by 0x259905: v8::internal::Compiler::CompileOptimized(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::ConcurrencyMode, v8::internal::CodeKind) (in /home/linux/v8)
==2588106== If you believe this happened as a result of a stack
==2588106== overflow in your program's main thread (unlikely but
==2588106== possible), you can try to increase the size of the
==2588106== main thread stack using the --main-stacksize= flag.
==2588106== The main thread stack size used in this run was 8388608.
==2588106==
==2588106== HEAP SUMMARY:
==2588106== in use at exit: 541,595 bytes in 1,411 blocks
==2588106== total heap usage: 2,072 allocs, 661 frees, 1,155,883 bytes allocated
==2588106==
==2588106== Thread 1:
==2588106== 1 bytes in 1 blocks are still reachable in loss record 1 of 1,252
==2588106== at 0x483CFE3: operator new(unsigned long) (vg_replace_malloc.c:417)
==2588106== by 0x330BFC: v8::internal::Heap::SetUpSpaces() (in /home/linux/v8)
==2588106== by 0x2D60B7: v8::internal::Isolate::Init(v8::internal::SnapshotData*, v8::internal::SnapshotData*, bool) (in /home/linux/v8)
==2588106== by 0x2D6C88: v8::internal::Isolate::InitWithSnapshot(v8::internal::SnapshotData*, v8::internal::SnapshotData*, bool) (in /home/linux/v8)
==2588106== by 0x5F789D: v8::internal::Snapshot::Initialize(v8::internal::Isolate*) (in /home/linux/v8)
==2588106== by 0x245612: v8::Isolate::Initialize(v8::Isolate*, v8::Isolate::CreateParams const&) (in /home/linux/v8)
==2588106== by 0x24581C: v8::Isolate::New(v8::Isolate::CreateParams const&) (in /home/linux/v8)
==2588106== by 0x2074BB: main (in /home/linux/v8)
==2588106==
==2588106== 1 bytes in 1 blocks are still reachable in loss record 2 of 1,252
==2588106== at 0x483CFE3: operator new(unsigned long) (vg_replace_malloc.c:417)
==2588106== by 0x330F6A: v8::internal::Heap::SetUpSpaces() (in /home/linux/v8)
==2588106== by 0x2D60B7: v8::internal::Isolate::Init(v8::internal::SnapshotData*, v8::internal::SnapshotData*, bool) (in /home/linux/v8)
==2588106== by 0x2D6C88: v8::internal::Isolate::InitWithSnapshot(v8::internal::SnapshotData*, v8::internal::SnapshotData*, bool) (in /home/linux/v8)
==2588106== by 0x5F789D: v8::internal::Snapshot::Initialize(v8::internal::Isolate*) (in /home/linux/v8)
==2588106== by 0x245612: v8::Isolate::Initialize(v8::Isolate*, v8::Isolate::CreateParams const&) (in /home/linux/v8)
==2588106== by 0x24581C: v8::Isolate::New(v8::Isolate::CreateParams const&) (in /home/linux/v8)
==2588106== by 0x2074BB: main (in /home/linux/v8)
==2588106==
==2588106== 1 bytes in 1 blocks are still reachable in loss record 3 of 1,252
==2588106== at 0x483EA5D: operator new[](unsigned long, std::nothrow_t const&) (vg_replace_malloc.c:658)
==2588106== by 0x53082E: v8::internal::String::ToCString(v8::internal::AllowNullsFlag, v8::internal::RobustnessFlag, int, int, int*) (in /home/linux/v8)
==2588106== by 0x530C0A: v8::internal::String::ToCString(v8::internal::AllowNullsFlag, v8::internal::RobustnessFlag, int*) (in /home/linux/v8)
==2588106== by 0x51AE2F: v8::internal::SharedFunctionInfo::DebugNameCStr() (in /home/linux/v8)
==2588106== by 0x27839C: v8::internal::OptimizedCompilationInfo::GetDebugName() const (in /home/linux/v8)
==2588106== by 0x7FB419: v8::internal::compiler::PipelineData::PipelineData(v8::internal::compiler::ZoneStats*, v8::internal::Isolate*, v8::internal::OptimizedCompilationInfo*, v8::internal::compiler::PipelineStatistics*, bool) (in /home/linux/v8)
==2588106== by 0x7FB1FF: v8::internal::compiler::PipelineCompilationJob::PipelineCompilationJob(v8::internal::Isolate*, v8::internal::Handle<v8::internal::SharedFunctionInfo>, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::BytecodeOffset, v8::internal::JavaScriptFrame*, v8::internal::CodeKind) (in /home/linux/v8)
==2588106== by 0x807EDA: v8::internal::compiler::Pipeline::NewCompilationJob(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::CodeKind, bool, v8::internal::BytecodeOffset, v8::internal::JavaScriptFrame*) (in /home/linux/v8)
==2588106== by 0x2585F8: v8::internal::(anonymous namespace)::GetOptimizedCode(v8::internal::Handle<v8::internal::JSFunction>, v8::internal::ConcurrencyMode, v8::internal::CodeKind, v8::internal::BytecodeOffset, v8::internal::JavaScriptFrame*) (in /home/linux/v8)
==2588106== by 0x259905: v8::internal::Compiler::CompileOptimized(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::ConcurrencyMode, v8::internal::CodeKind) (in /home/linux/v8)
==2588106== by 0xB2C785: v8::internal::(anonymous namespace)::CompileOptimized(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::ConcurrencyMode) (in /home/linux/v8)
==2588106== by 0xB28ACB: v8::internal::Runtime_CompileOptimized_Concurrent(int, unsigned long*, v8::internal::Isolate*) (in /home/linux/v8)
==2588106==
==2588106== 2 bytes in 1 blocks are still reachable in loss record 4 of 1,252
==2588106== at 0x483EA5D: operator new[](unsigned long, std::nothrow_t const&) (vg_replace_malloc.c:658)
==2588106== by 0x261383: v8::internal::CallDescriptors::InitializeOncePerProcess() (in /home/linux/v8)
==2588106== by 0x3F0386: v8::internal::V8::InitializeOncePerProcessImpl() (in /home/linux/v8)
==2588106== by 0x9ED455: v8::base::CallOnceImpl(std::atomic<unsigned char>*, std::function<void ()>) (in /home/linux/v8)
==2588106== by 0x3EFFFD: v8::internal::V8::Initialize() (in /home/linux/v8)
==2588106== by 0x23634A: v8::V8::Initialize(int) (in /home/linux/v8)
==2588106== by 0x2074A2: main (in /home/linux/v8)
==2588106==
==2588106== 2 bytes in 1 blocks are still reachable in loss record 5 of 1,252
==2588106== at 0x483EA5D: operator new[](unsigned long, std::nothrow_t const&) (vg_replace_malloc.c:658)
==2588106== by 0x2620B0: v8::internal::CallDescriptors::InitializeOncePerProcess() (in /home/linux/v8)
==2588106== by 0x3F0386: v8::internal::V8::InitializeOncePerProcessImpl() (in /home/linux/v8)
==2588106== by 0x9ED455: v8::base::CallOnceImpl(std::atomic<unsigned char>*, std::function<void ()>) (in /home/linux/v8)
==2588106== by 0x3EFFFD: v8::internal::V8::Initialize() (in /home/linux/v8)
==2588106== by 0x23634A: v8::V8::Initialize(int) (in /home/linux/v8)
==2588106== by 0x2074A2: main (in /home/linux/v8)
Edit 2: Compiling command :
g++ sample.cpp libv8_monolith.a -I/usr/local/include/v8/ -I/usr/local/include/v8/include/ -lpthread -o v8 -DV8_COMPRESS_POINTERS