Connecting C++ To Javascript Via Google’s V8

I’ve been playing around with Google’s V8 JavaScript engine. One of the really cool things about V8 is that it was built to be embedded into a C++ application. Here at Bungee Labs I’ve been writing the infrastructure for our bungee connect platform for some time now. One thing that I’m always interested in is speed and V8 is very fast. I ran the benchmarks that Google posted in my browser (Firefox 3.03), and then I ran them using the new V8 engine. The new engine is faster by an order of magnitude.

Getting your head wrapped around the V8 API takes some time. There is a very brief overview page that you can read to get started writing V8 applications, but you will have to spend quite a bit of time scouring the source code to figure out how to do anything of note. Most of the documentation focuses on how your js files can call into C++. For our purposes, I also needed to call into JavaScript from C++ and get information back from the V8 engine. Here is some code that does that.

Let’s say you have some JavaScript file that defines a function foo (you can’t have a coding exercise without a foo) that looks like the following:

function foo() {
return 42;
}

If you’ve embedded V8 into your C++ application you could call foo by doing the following:

void myClass::myFunction()
{
HandleScope scope;
LocalContext context;

Script::Compile(String::New("function foo() { return 42; }"))->Run();

Local fun = Local::Cast(context->Global()->Get(String::New("foo")));

int argc = 0;
Handle argv[] = NULL;

Handle result = fun->Call(fun, argc, argv); // argc and argv are your standard arguments to a function
...
}

What this does is it sends the JavaScript that I wrote to the V8 engine via the Compile and Run functions. Now, I need access to the foo function and I do that by getting the Function from the Global namespace. If my function took any parameters I could fill out the argv array and then the function would have access to those values just like any normal JavaScript function would. When I make the Call function I give it an object to be the receiver, itself in this case, and I pass the argument length and array. The value that is returned from the function is stored in the result variable.

So, that wasn’t too bad. It all makes sense once you see it. The hard part always is trying to figure that stuff out when you don’t know where to look.

Another thing I had to figure out was how to make a function call on an object instance. This is a bit more difficult but it’s really just a variation on a theme. Let’s say our JavaScript looks like this:

function bar() {
this.x = 42;

this.foo = function() {
return x;
}
}

I need to get a handle to the function constructor first so I do that here:

Handle fun = Handle::Cast(env->Global()->Get(String::New("bar")));

Now I can create an instance of this function with:

Handle<Object> object = fun->NewInstance(argc, argv);

Again argc and argv are your arguments to your function which in this case is bar. If bar took more parameters you would pass those in so that bar would be setup correctly.

Once I have an object I can ask it for it’s function that I want to call:

Handle fun_to_call = Handle::Cast(object->Get(String::New("foo")));

And finally I can call that function:

fun_to_call->Call(object, argc, argv);

Since I am using the same API function Call, I can expect a return value just like in the first example.

I’ve found V8 to be an excellent JavaScript engine, and it has a fantastic API. I’ll be using it for some of my internal projects and I’ll keep posting cool ideas as I run across them.

Corey Olsen
Senior Platform Engineer
Bungee Labs

About these ads

2 Comments »

  1. Tom Hagman said

    Corey,

    I’ve been playing with the V8 engine for a few days.

    I’m builting a COM+ ATL server to expose the javascript engine functionality. I’m having some trouble getting the name of a object being returned by a function.

    Here’s JS sample:
    function CRV(pName1, pValue1)
    {
    this.Name = pName1;
    this.Value = pValue1;
    }

    function doit()
    {
    var crv = new CRValue(‘Col1′, ‘Val1′);
    return crv;
    }

    doit();

    When doit() returns a CRV, I need to know that the type is ‘CRV’.

    This compiles, but kills the engine on the GetName();
    Local jsfunc = result->ToFunction();
    Handle hFunctionName = jsfunc->GetName();

    where result is return from script->Run();

    Any suggestions would be appreciated.

    Thanks,
    Tom

    • olsenc said

      Whenever I get a value back from js into my c++ code I always check it’s type by casting it to the type I think it should be. I would try something along the lines of:
      v8::Handle result = function->Call(object, 0, NULL);
      v8::Handle resultAsAFunction = v8::Handle::Cast(result);

      now you can check to see if the variable is null or undefined:
      if (resultAsAFunction.IsEmpty() || resultAsAFunction->IsUndefined())
      { … }

      Try that and see if that gives you any clues as to whether or not you actually have a function or not. My first inclination was that what you actually have is an object not a function and the method GetName is not defined on a v8 Object.

      Corey

RSS feed for comments on this post · TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: