Library/V8/Tutorial

 ''PLEASE provide feedback or questions on the associated blog entry for this page so that improvements that can be made to this page.

I'd like it to be as helpful as possible for future readers, but only want to invest the time on what on information I specifically know is wanted!''

Overview
This isn't precisely a tutorial, but rather a look at example code of using Google V8. The motivation for this page is largely that, while the Google V8 documentation provides all the information necessary to embed V8 in a C++ application, a bit more example code likely would get the concepts across more quickly.

In short, this article attempts (using mostly pseudo-code) to expose a HTML-like Document Object Model (DOM) to the hosted Javascript code. In the pseudo-code below, the "document" variable as well as an created Elements would be native C++ objects in the hosted app - which are exposed to Google V8 via wrapper objects:

This will more or less show how to:


 * Add wrappers on existing native C++ objects and expose them to the V8 engine
 * Allocate native C++ objects and wrap them as Javascript variables
 * ...and, though not in the example above, add a free function to the global namespace

Building V8
I'll assume there's no need to add any text to this section here until I get feedback otherwise...

Engine::runJavascript
This article is about Google's V8 Javascript interpreter, not LxEngine. However, to give some context of how V8 is being used, some very brief and superficial description of LxEngine is needed - namely, one of the main functions that invokes Javascript code within the engine:

Engine::runJavascript is the entry-point for running a series of scripts on a single, specific LxEngine Document object (i.e. scripts on one object affect only that Document and no others, similar to webpages). What an LxEngine Document actually represents is not terribly important for the purposes of this article (think of it as more or less an XML or HTML document, if that helps). What is important is simply that it's a native C++ object.

One point worth noting: the method takes a vector of scripts, not a single script. This is done so that every script in the vector shares the same execution context. In other words, the first script does affect the second script. This is useful if the first script, for example, is loading a set of utility functions which are then used by the subsequent scripts. This is worth mentioning since the notions of context and scope are intrinsic to using V8 correctly and effectively.

The basics
The Google V8 docs covers in-depth what's described in this section, so we'll run through it only very quickly:

First create a HandleScope. This is a scoped C++ object that informs V8 that all Handle object created within the HandleScope go out of scope when the HandleScope goes out of the scope. This is the standard way of dealing with Handle lifetimes in V8: it's done for efficiency - see the V8 docs for more information about why.

Then a ObjectTemplate is created for the "global" Javascript object. A "template" is a confusing word here if your gut reaction is to think "C++ template". It's essentially a template in the sense of "the basic information used to describe the object before it is actually created". Think of it as a "descriptor" which will be used to create the object, if that is helpful. When the Context object is later passed this template, it will create the global object (accessible via context->Global) from this template descriptor object. Therefore, if there are multiple V8 Contexts, this single template can be used to create multiple global objects, one per Context. In this barebones code, nothing is done with this object, but this template is where free functions will be added to the global context (e.g. think of a free standing function like HTML's Javascript alert function).

The Context is next created. Note this needs to be explicitly Disposed at the end since it is a Persistent object, not a regular Handle or Local which would be disposed of automatically when the HandleScope went out of scope.

The String, Script, Run code should be somewhat self-explanatory.

Adding a free function
First, let's add a free standing function. This is simple and provides a nice printf-debugging tool. For now, it will be a simple print implementation that takes one string argument and echoes it to the console (i.e. not multi-argument, formatted types like a real printf implementation).

Adding the function involves "Set"ing a property on the global template. When the Javascript global object is created by the Context, it will inherit these properties from the template. Add the property as a FunctionTemplate. Again, this is creating a FunctionTemplate that tells V8 what to create when it actually needs to create the Function rather than creating a Function directly.

A FunctionTemplate needs to match the fixed function signature of all Function objects: return a Handle and take an Arguments object. If the function doesn't return a value, then just return Undefined. Note: the C++ implementation uses the name print and the function is exposed as __lx_print to Javascript; obviously, any names can be used as desired.

(Note: technically this function is not a pure 'free-standing' function. The function is actually a method on the implicit global object.  In most cases, this does not particularly matter, but is worth remembering if you encounter a situation where it may matter.)

We'll get to the  in the next section: this is basically just a helper in the LxEngine code to convert V8's Handle to native C++ types. Also, we'll ignore the fact that this implementation doesn't check that the number of arguments is correct or other validation necessary in production-quality code. Again, this is intended to a barebones example.

Data Marshaling
The  code referenced above is actually a LxEngine helper class (not part of the V8 API!) with overloaded constructors that can convert from many simple native C++ data types to V8 Handle types and vice-versa via an overloaded implicit cast operator. The details of the class don't fully fit in with the intent of this tutorial (it's about V8, not LxEngine), so let's just look at how a Handle gets converted to a std::string. Handling other types essentially simply requires taking a look at the V8 documentation (or maybe glancing at the current code for _marshal in the hpp and cpp files over in the LxEngine github repository?).

Adding a global object
In other words, how to add the "document" object...

This is a section adds a global variable "document" to the global V8 context. This object wraps a native C++ object (an LxEngine Document, in this case) and exposes it to Javascript. Note: there is no associated named "type" exposed to Javascript so that the user cannot directly create new Document objects; the "type" of the object is defined only implicitly, not explicitly, to the user.

Setting up the class

 * 1) Create a FunctionTemplate.  Remember, a "class" in Javascript is a function, so to create a wrapper of a C++ class, we need a JS function to represent it.  Also note that we're creating a FunctionTemplate object.  This describes the Function before it is actually created by V8.
 * 2) Next, modify the InstanceTemplate on the FunctionTemplate.  We need to describe what kind of C++ object is created when "new" is called on our Javascript function (calling "new" on a JS function is essentially the equivalent of making a C++ constructor call).  We need to do this so that we can tell V8 to allocate an "internal field" on the object where we can store the native C++ pointer to the object (thus a connection between the JS object and C++ object is maintained).  Phrasing this differently: fill in the template for when a new instance of the function is created.  Note: since we're creating a single global object, the object creation will only be called internally and never exposed to the user - but we still need to tell V8 how to create the new object whether it's invoked natively or from JS.
 * 3) Then we have to fill out the PrototypeTemplate for the function.  This is essentially the C++ equivalent of accessing the Javascript "prototype" property on a function.  If this doesn't make sense, a quick refresher on object-oriented Javascript might be helpful.   We then add two need functions to the prototype.  Note this is very much like the free function added previously, but in this case there are added to the prototype object of the function - rather than the global object (but in Javascript, functions are a type of object, so that's why there's a close similarity).

Adding a method
In short, a method is just like a function, but it needs a  pointer. The  pointer is accessible as the   in the Arguments object during the invokation of a method.

LxEngine uses a  helper to grab the   object. Note, the code for returning the value from  will be covered later.

And the listing for _nativeThis is below. Note: LxEngine assumes there will always be exactly 1 internal field on any natively wrapped object. Your code might decide to use multiple internal fields. There's no reason only 1 has to be used and this is merely an LxEngine convention.

Creating the object
Essentially we now need to write the C++ equivalent of...

First note that the 'class' created earlier in the tutorial is not really called "Document" - it was never assigned a name as far as the Javascript client code is concerned. It's essentially an anonymous class. This is good since we don't want the user creating their own "Document" objects - we're just exposing one singleton object under the "document" variable name. However, for conceptual purposes let's think of that Function created above as the "Document" class, even though we never expose it to the JS client code with any name,


 * 1) GetFunction is called on the FunctionTemplate to actually instantiate the real Function from the template descriptor.  This represents the Javascript object for the function.  (Note the code comment: some code must be set on the template before the Function is every created.  Note also: only one instantiation of a template can occur per context.).
 * 2) Now that we have the function we can call it.  But we actually want to call "new" on it, not directly invoke it.  That's precisely what NewInstance does.
 * 3) At this point we now have an anonymous Javascript object of the "Document" type...
 * 4) Next, bind it to the native C++ object by setting that internal field we allocated
 * 5) Next, assign it a name in the global object so that it can be accessed from Javascript using the name "document"

Note in the last line of code we are accessing the context global object, the global object template. The free function __lx_print was added to the object template prior to the object being created. Here the "document" object is added to the global object itself. In V8, it's usually important to understand what needs to be added to templates versus the actual objects.

Adding JS allocated native C++ objects
When the javascript code calls "document.createElement", a native Element object needs to be created and wrapped in a Javascript object. Let's cover how to do that.

Setting up the class
This is similar to creating the document object


 * 1) Create the FunctionTemplate representing the "class"
 * 2) Allocate an internal field to store the native pointer on the InstanceTemplate
 * 3) Add the methods to the prototype

...but then there's one more thing done here


 * 1) Store a Persistent handle for the function

Why the last step? We need to hang on to the Function so that Function::NewInstance can be called from our createElement implementation. In the code below, the LxEngine uses a static s_pActiveContext object to store that Function for duration of the script invokation.

Allocating a new object
Let's go back to document.createElement:


 * 1) Grab the native Document*
 * 2) Marshal the JS arguments to native C++ types
 * 3) Call the native method

...now, how to expose that newly allocated C++ Element object?

Two things happen:
 * 1) Store a reference to the newly allocated object
 * 2) Call the _wrapObject helper to create the JS wrapper

We'll examine both those steps after the code listing:

Storing a reference to the allocated object
This is a bit of a LxEngine idiosyncrasy, but it exposes something good to understand about V8.

Reference Counting

LxEngine uses std::shared_ptr<> on all its major objects to provide 'automatic' memory management of its resources. This is generally very helpful as it keeps things simple and straightforward. But here's the problem: V8 exposes that C++ variable as a void*, not as a std::shared_ptr<>. In other words, we have no way of knowing when a JS variable is potentially referencing the native C++ object or not. This invalidates the reference counting: in general, if any code using an object is using reference coding, then all code using those objects has to use reference counting.

The 'right' way of handling this may be to use a V8 PersistentHandle, which can be made into a weak pointer - which V8 allows a callback to be registered on when that handle goes out of scope...but that's not what the code in this article does. At least in this revision of the article, that is.

The code in this article simply keeps a list of all native objects allocated during the run of the script. It clears this list at the end of the script run. What this means is: (a) it's very simple and straightforward - all allocated native objects are guaranteed to exist as long as the script, (b) an allocated native object will still be in memory for the duration of the script, even if the JS code is no longer referencing it.

Again, it's not necessarily an ideal solution, but it's keeping things simple for the purposes of this article. For the purposes of learning to embed Google V8, suffice to say, that (a) V8 does not try to manage the memory of your native objects and (b) there is a way to use PersistentHandle to get notification on a garbage collected object but this articles does not cover that.

Wrapping the object
This is pretty simple, as it's very similar to the "document" object but we don't have to assign the created object a name.


 * 1) Call NewInstance on the Function (i.e. equivalent to new my_function)
 * 2) Set the internal field to the value of the native C++ object
 * 3) Return a Handle to the object

Synchronizing Native Object Reference Counts with the V8 Garbage Collector
I'll try to update the wiki with a direct description, but for now see the post Synchronizing Native Reference Counts with V8 on the blog.

In short, look into the Persistent::MakeWeak method.

Wrapping a Javascript function as a std::function<>
See this blog post, or send leave feedback if you'd like more information in this section.

Adding the Javascript Math library
Please leave some feedback and I'll add this section.

Conclusion
This article was put together hastily - but given my own difficulty in find more examples of V8 embedding, I thought posting a hasty article would be more helpful than not posting anything.

If you have feedback, questions, or suggestions, please post them to the corresponding blog entry for this article:

http://athile.net/library/blog/?p=159

Hearing from others would be motivation to spend some time polishing this article up.