The correct way to run the same code twice in v8 (due to the lack of an array on the second run - deoptimizer)

The following program is based on the example on page v8 Getting Started . I made three changes to demonstrate the problem I am facing:

  • I create an empty array by putting it in a global context.
  • Running the script refers to the null element in the array, which should return undefined.
  • I run the compiled script twice.

The first run works fine. Second crash: v8 calls V8_Fatal () in Deoptimizer :: DoComputeCompiledStubFrame (), because descriptor-> register_param_count_ == -1.

Am I doing something wrong here? How can i fix this?

Isolate* isolate = Isolate::New(); Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); Local<Context> context = Context::New(isolate); Context::Scope context_scope(context); Local<Array> a = Array::New(isolate); context->Global()->Set(String::NewFromUtf8(isolate, "a"), a); Local<String> source = String::NewFromUtf8(isolate, "a[0];"); Local<Script> script = Script::Compile(source); Local<Value> result = script->Run(); Local<Value> result2 = script->Run(); return 0; 

NOTES:

  • This is the entire main () array.
  • Other pieces of JavaScript code run twice without problems. Somehow, this refers to a face reference that possibly causes deoptimization.
  • I do not want to recompile the script from scratch every time, because I usually run these scripts thousands of times, and sometimes millions of times.
  • I tried to compile the script as UnboundScript and then bind it for each execution, but the result is the same.
  • I reported this as a v8 issue , but no one answered, so I hope the StackOverflow community can help.
  • I see this on VS2012 Update 4, but I also see it on VS2008, both in x64 and x86, and in the Debug and Release assemblies.
+8
v8
source share
1 answer

OK, I found it. The problem is the uninitialized code stub for loading the dictionary - your use case starts it as a failure, since the stub is not initialized by other means, for example, compilation.

Below is a patch against v8 trunk version 22629, which fixes the problem for me, tested on Windows with VS 2010 and Linux with g ++ 4.9. Please let me know how you do this:

 Index: src/code-stubs.cc =================================================================== --- src/code-stubs.cc (revision 22629) +++ src/code-stubs.cc (working copy) @@ -236,6 +236,8 @@ CODE_STUB_LIST(DEF_CASE) #undef DEF_CASE case UninitializedMajorKey: return "<UninitializedMajorKey>Stub"; + case NoCache: + return "<NoCache>Stub"; default: if (!allow_unknown_keys) { UNREACHABLE(); @@ -939,6 +941,13 @@ // static +void KeyedLoadDictionaryElementStub::InstallDescriptors(Isolate* isolate) { + KeyedLoadDictionaryElementStub stub(isolate); + InstallDescriptor(isolate, &stub); +} + + +// static void KeyedLoadGenericElementStub::InstallDescriptors(Isolate* isolate) { KeyedLoadGenericElementStub stub(isolate); InstallDescriptor(isolate, &stub); Index: src/code-stubs.h =================================================================== --- src/code-stubs.h (revision 22629) +++ src/code-stubs.h (working copy) @@ -1862,6 +1862,8 @@ virtual void InitializeInterfaceDescriptor( CodeStubInterfaceDescriptor* descriptor) V8_OVERRIDE; + static void InstallDescriptors(Isolate* isolate); + private: Major MajorKey() const { return KeyedLoadElement; } int NotMissMinorKey() const { return DICTIONARY_ELEMENTS; } Index: src/isolate.cc =================================================================== --- src/isolate.cc (revision 22629) +++ src/isolate.cc (working copy) @@ -2000,6 +2000,7 @@ NumberToStringStub::InstallDescriptors(this); StringAddStub::InstallDescriptors(this); RegExpConstructResultStub::InstallDescriptors(this); + KeyedLoadDictionaryElementStub::InstallDescriptors(this); KeyedLoadGenericElementStub::InstallDescriptors(this); } 

As a workaround, if you don’t want to compile your own V8 now, you can execute the code on each Isolate that uses the KeyedLoadDictionaryElementStub directly, before your code runs --- this should initialize the stubs. For me, something similar to the following works:

 Isolate* isolate = Isolate::New(); Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); Local<Context> context = Context::New(isolate); Context::Scope context_scope(context); Local<Array> a = Array::New(isolate); context->Global()->Set(String::NewFromUtf8(isolate, "a"), a); // Workaround code for initializing KeyedLoadDictionaryElementStub Local<String> workaround_source = String::NewFromUtf8(isolate, "Math.random()"); Local<Script> workaround_script = Script::Compile(workaround_source); Local<Value> workaround_value = workaround_script->Run(); // End workaround Local<String> source = String::NewFromUtf8(isolate, "a[0]"); Local<Script> script = Script::Compile(source); // ...and so on 
+4
source share

All Articles