Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the correct way to use v8::Locker, and why must I use it?

I'm trying to embed v8 in an Android application using NDK.

I have a JNI module that looks something like this (JNI mapping code not shown):

#include <jni.h>
#include <android/log.h>

#include <v8.h>
using namespace v8;

static jlong getMagicNumber() {
  HandleScope handle_scope;
  Persistent<Context> context = Context::New();
  Context::Scope context_scope(context);

  Handle<String> source = String::New("40 + 2");

  Handle<Script> script = Script::Compile(source);
  Handle<Value> result = script->Run();

  context.Dispose();

  return result->NumberValue();
}

The first time I run getMagicNumber, it correctly runs and returns 42. The second time I try to run it, it crashes.

Specifically, this ASSERT seen in v8's isolate.h fails:

// Returns the isolate inside which the current thread is running.
INLINE(static Isolate* Current()) {
  Isolate* isolate = reinterpret_cast<Isolate*>(
      Thread::GetExistingThreadLocal(isolate_key_));
  ASSERT(isolate != NULL);
  return isolate;
}

It sounds a lot like this problem, which suggests using v8::Locker to obtain "exclusive access to the isolate".

By adding a simple Locker l; to the top of getMagicNumber, the crash no longer occurs. Problems that fix themselves that easily tend to break themselves when I'm not paying attention.

I only have the most tenuous understanding of why this fixes my problem, and I'm getting compiler warnings that I'm using v8::Locker in a deprecated fashion. The recommended method is to provide it with a v8::Isolate as an argument to v8::Locker's constructor, but I have no idea how I'm supposed to "obtain" an isolate.

Ultimately: What is the proper way to solve this problem according to the current state of v8, and why?

like image 875
namuol Avatar asked Mar 24 '13 07:03

namuol


1 Answers

As I understand it, a V8 isolate is an instance of the V8 runtime, complete with a heap, a garbage collector, and zero or more V8 contexts. Isolates are not thread-safe and must be protected via v8::Locker.

In general, to use V8 you must first create an isolate:

v8::Isolate* isolate = v8::Isolate::New();

Then, to use the isolate from any thread:

v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);

At this point the thread owns the isolate and is free to create contexts, execute scripts, etc.

Now, for the benefit of very simple applications, V8 provides a default isolate and relaxes the locking requirement, but you can only use these crutches if you always access V8 from the same thread. My guess is that your application failed because the second call was made from a different thread.

like image 143
BitCortex Avatar answered Sep 18 '22 02:09

BitCortex