when v8 is embedded in a C program, can C be called from Javascript

1,994 views
Skip to first unread message

Jak Sprats

unread,
Jan 16, 2011, 6:43:25 AM1/16/11
to v8-users
Hi All,

I am looking to embed v8 into AlchemyDatabase
http://code.google.com/p/alchemydatabase/ - I am the author.

I have already embedded Lua and one very nice feature of Lua is lua
functions can be written in C and these functions can be called from
Lua.
In AlchemyDB, I have a lua function "client()" (written in C) and lua
scripts (run w/in the DB engine) can call "client()" to access the DB
directly/natively.

Does V8 embedding have something like this, so not only a way to call
Javascript from C, but also a way to call C from Javacript?

- Jak

Stephan Beal

unread,
Jan 16, 2011, 9:12:32 AM1/16/11
to v8-u...@googlegroups.com
On Sun, Jan 16, 2011 at 12:43 PM, Jak Sprats <jaks...@gmail.com> wrote:
Does V8 embedding have something like this, so not only a way to call
Javascript from C, but also a way to call C from Javacript?

There is, but only if you use C++ glue to bind your C API to v8's C++ API, which in turn binds to JS space.

If i may be so bold as to toot my own horn for a moment, i believe i've implemented the world's simplest-to-use binding mechanism for wrapping C functions (from C++) in v8. Here's an example of all the code one needs to bind sleep() to v8:

jsObj->Set( String::New("sleep"), FunctionTemplate::New(
      convert::FunctionForwarder<1>::Invocable<unsigned int,unsigned int,::sleep>
    )->GetFunction() ); 

About 50% of that code is required by v8 (i.e. unavoidable, regardless of the wrapping framework) and the other 50% is invoking one of my templates which creates a new v8::InvocationCallback function (with compile-time type safety and no dynamic memory costs) which acts a proxy for sleep().

More on this topic can be found here:


--
----- stephan beal
http://wanderinghorse.net/home/stephan/

Jak Sprats

unread,
Jan 17, 2011, 8:51:42 AM1/17/11
to v8-users

I dont care who's tooting the horn as long as it sounds good :)

This seems to be what I am looking for ... some questions:
1.) AlchemyDB is written in ANSI-C, what are the requirements for your
bindings (C++ at a minimum, any specifics on that)
2.) I just need one function wrapped, the function is called
"client()" and it can take between 1 and 6 arguments.

And on a long shot, do you know of any C programs that embedded V8 and
then the embedded v8 calls a C function via your bindings. This is
what I am trying to reproduce in AlchemyDB (the C function would be
"client()").

My intent w/ this is to open up Javascript routines w/in AlchemyDB
that can access AlchemyDB's data-structures and perform logic
datastore side. Pairing this w/ AlchemyDB's Node.js client could
provide a very interesting architecture where ALL logic (client,
server[Node.js], datastore[AlchemyDB) could be done in Javascript,
meaning high reusability of JS libs accross an entire system.

On Jan 16, 6:12 am, Stephan Beal <sgb...@googlemail.com> wrote:

Stephan Beal

unread,
Jan 17, 2011, 10:10:02 AM1/17/11
to v8-u...@googlegroups.com
On Mon, Jan 17, 2011 at 2:51 PM, Jak Sprats <jaks...@gmail.com> wrote:
This seems to be what I am looking for ... some questions:
1.) AlchemyDB is written in ANSI-C, what are the requirements for your
bindings (C++ at a minimum, any specifics on that)

Whatever requirements v8 has, basically. i don't remember v8-juice have any requirements above what v8 needs.
 
2.) I just need one function wrapped, the function is called
"client()" and it can take between 1 and 6 arguments.

The code demonstrated on that page accepts up to 10 arguments, and more can be generated via a script.
You don't need all of v8-juice for what you're doing: you can get by with only some of the header files:

Go to:

grab:

- convert.h
- forwarding.h
- forwarding-*.h (generated code)
- TypeList.h
- TypeList_*.h ( generated code)

And that should do it. The primary advantage, over using the whole v8-juice lib, is that you need only headers, not .cpp files. All of the type conversion/function-forwarding code is templates, and implemented in their header files.

Your code should include convert.h and/or forwarding.h, and the rest are implementation details. Those files assume an includes path of <v8/juice/foo.h>, and you will need to replace those if you plan to use a different structure.

 
And on a long shot, do you know of any C programs that embedded V8 and
then the embedded v8 calls a C function via your bindings. This is
what I am trying to reproduce in AlchemyDB (the C function would be
"client()").

i don't know of any programs which reach into v8 from C. i have implemented v8 add-ons on top of C libraries (like libcurl and libsqlite3), but that's going the other direction. C cannot call directly into JS because it can't use the objects needed by v8. It can, of course, use a C++ API which has been wrapped in (extern "C" {...}), which then can pass on the calls to v8. So the call chain would look like: C -> C++ -> JS

i hope this helps a bit,

James Pike

unread,
Jan 17, 2011, 10:52:16 AM1/17/11
to v8-u...@googlegroups.com
I like my version better than v8-juice. Takes advantage of boost to make the code neater and uses function pointer style template arguments to make the binding code smaller:

https://github.com/tsa/vu8

Cheers, James


Jak Sprats

unread,
Jan 18, 2011, 10:35:42 AM1/18/11
to v8-users
Hi Stephan,

this is very helpful, so thank you.

I am going to explain my use-case fully, because its pretty easy once
explained, (I am a bad explainer) and forgive me if my explanations
are overly simplistic, I am just a fanatic on clarity, so I write
things as dumbed down as possible.

A.) AlchemyDB has SQL commands
1.) SELECT * FROM tbl WHERE user_id = 33 AND name = 'sally'
2.) UPDATE tbl SET count = count + 1 WHERE id = 1234
B.) AlchemyDB has redis commands
1.) SET session_77 'name:bill;age:22'
2.) HGET user_77 name
C.) AlchemyDB currently has some commands to call the embedded LUA
This will add the file "functions.lua" to the embedded lua
environment (used to populate lua libraries)
1.) CONFIG ADD LUA functions.lua
This will pass the string 'return 1*2*3' to the embedded lua parser/
executor which will perform the action '1*2*3' and pass the results
back to AlchemyDB
2.) LUA 'return 1*2*3;'
This will call AlchemyDB's SQL and Redis commands from w/in LUA
First the session is checked for existence, and if it exists all
rows from the table 'user_data' are returned, otherwise return an
empty-string
3.) LUA 'sess = client('GET', 'session_77'); if (sess == nil)
return "" else return client('SELECT','*','FROM',;user_data', ' WHERE
id = 77'); end'

The lua function "client()" makes internal calls to AlchemyDB's SQL
and redis commands, and is VERY useful for avoiding network hops, and
placing trivial logic datastore side. Its like a sane stored
procedures implementation.

I want to have the exact same thing in Javascript, because Javascript
is really gaining in momentum, has 1000s of good libraries, and
Node.js's Alchemy users would backflip at the possiblity of
arbitrarily doing javascript logic at any point in their architecture.

So I need a very lightweight embedding of V8 and the single javascript
function "client()" that can call C to internally reach into
AlchemyDB.

I can have options to make AlchemyDB in C++ to be able to include V8,
that is acceptable.

I understand everything you wrote, I am just a little bit leery of how
much time it will take to figure out all the finer details of
embedding one language in another in another, it was actually tricky
to do w/ Lua, and lua is made for embedding ease. Any idea how many
man-days embedding V8 and then using v8-juice to implement the JS func
"client" would take? (just ballpark: is it a day, a week, a month?)

What would be REAL helpful is if there was a hello-world for embedding
v8 in C and then using v8-juice to define a hello-world JS-calling-C
function along w/ a how to compile and test for dummies, so I could
start playing around w/ it. This is my work style, if I can build
something, I can start glueing things together, but this initial
learning curve of libraries internals/peculiarities takes me a long
time.

thanks,
Jak

On Jan 17, 7:10 am, Stephan Beal <sgb...@googlemail.com> wrote:
> On Mon, Jan 17, 2011 at 2:51 PM, Jak Sprats <jakspr...@gmail.com> wrote:
> > This seems to be what I am looking for ... some questions:
> > 1.) AlchemyDB is written in ANSI-C, what are the requirements for your
> > bindings (C++ at a minimum, any specifics on that)
>
> Whatever requirements v8 has, basically. i don't remember v8-juice have any
> requirements above what v8 needs.
>
> > 2.) I just need one function wrapped, the function is called
> > "client()" and it can take between 1 and 6 arguments.
>
> The code demonstrated on that page accepts up to 10 arguments, and more can
> be generated via a script.
> You don't need all of v8-juice for what you're doing: you can get by with
> only some of the header files:
>
> Go to:http://code.google.com/p/v8-juice/source/browse/#svn/trunk/src/includ...

Jak Sprats

unread,
Jan 18, 2011, 10:40:37 AM1/18/11
to v8-users
Hi James,

does vu8 fulfill all the requirements I wrote in my last reply to
Stephan?

Can you (briefly) compare and contrast vu8's strengths and weaknesses
compared to v8-juice (e.g. lightweight is GOOD for my use-case).

Do you have a simple hello-world example w/ build instructions that
works on generic linux OSes, so I can do a quick evaluation?

thanks,
Jak

On Jan 17, 7:52 am, James Pike <ja...@chilon.net> wrote:
> I like my version better than v8-juice. Takes advantage of boost to make the
> code neater and uses function pointer style template arguments to make the
> binding code smaller:
>
> https://github.com/tsa/vu8
>
> Cheers, James
>
> On 16 January 2011 14:12, Stephan Beal <sgb...@googlemail.com> wrote:
>

Stephan Beal

unread,
Jan 18, 2011, 10:59:54 AM1/18/11
to v8-u...@googlegroups.com
On Tue, Jan 18, 2011 at 4:35 PM, Jak Sprats <jaks...@gmail.com> wrote:
<huge snip> 
...man-days embedding V8 and then using v8-juice to implement the JS func

"client" would take? (just ballpark: is it a day, a week, a month?)

i couldn't even guess. AlchemyDB and reddit are both foreign words to me, so i couldn't even venture a guess.
 
What would be REAL helpful is if there was a hello-world for embedding
v8 in C

There is a hello-world (the shell app) in the v8 source tree. Binding that with C requires a C++ middle-man API which has functions the C code can call (i.e. they use export "C"). Aside from that, there should be no magic involved.

If all you want to do is wrap a single function, an add-on library like v8-juice or vu8 is way overkill. i'd start by taking a look at shell.cc in the v8 source tree.

Stephan Beal

unread,
Jan 18, 2011, 11:03:34 AM1/18/11
to v8-u...@googlegroups.com
On Tue, Jan 18, 2011 at 4:40 PM, Jak Sprats <jaks...@gmail.com> wrote:
does vu8 fulfill all the requirements I wrote in my last reply to
Stephan?

Can you (briefly) compare and contrast vu8's strengths and weaknesses
compared to v8-juice (e.g. lightweight is GOOD for my use-case).

i have no experience with vu8. i only found out about it via the above post. From a brief glance, it seems provide more or less the same features as v8-juice, but vu8 uses of function-pointer-style template args to make the API more readable (if i had only known how to do that two years ago...).
 
Do you have a simple hello-world example w/ build instructions that
works on generic linux OSes, so I can do a quick evaluation?

The v8-juice tree comes with its own shell, which demonstrates most of its features, but from what you've described i think you only need plain old v8.

Vyacheslav Egorov

unread,
Jan 18, 2011, 11:08:55 AM1/18/11
to v8-u...@googlegroups.com
Jak,

I think it would be pretty easy to convert your Lua intergration into
V8 intergration line by line without relying on any third party
libraries.

Let me show you a mapping between Lua and V8 APIs

Lua:
// Lua API manipulates with stack. Anything on the stack will be kept
alive when GC happens.
int code = luaL_dostring(L, s);
if (code) {
// error is on top of the stack
const char *error_message = lua_tostring(L, -1);
report(error_message);
} else {
// return values are on top of the stack
}

V8:
// V8 does not have implicit stack. Instead API is all about Handles.
// Handles keep what they reference alive during GC.
// There are two types of the Handles: Local and Persistent.
// Each Local handle is owned by a HandleScope --- when HandleScope
dies so do all Local handles it owns.
// In terms of Lua: creating HandleScope is like remembering height of
Lua stack, creating Local handle is like pushing
// value on the stack and destroying HandleScope is like poping
everything above remembered height.
v8::HandleScope handle_scope;
Local<String> v8_string = v8::String::New(s);
Local<Script> script = v8::Script::Compile(v8_string);
v8::TryCatch try_catch;
Local<Value> result = script->Run();
if (try_catch.HasCaught()) {
// exception is in try_catch.Exception()
v8::String::AsciiValue error_message(try_catch.Exception());
report(*error_message);
} else {
// returned value is in the result.
}

As you can see conversion is pretty much straighforward.

--
Vyacheslav Egorov

James Pike

unread,
Jan 19, 2011, 6:02:30 AM1/19/11
to v8-u...@googlegroups.com
> On Tue, Jan 18, 2011 at 4:40 PM, Jak Sprats <[1]jaks...@gmail.com>

> wrote:
>
> does vu8 fulfill all the requirements I wrote in my last reply to
> Stephan?
> Can you (briefly) compare and contrast vu8's strengths and
> weaknesses
> compared to v8-juice (e.g. lightweight is GOOD for my use-case).

vu8 is header only with nothing to link against, and should be
equivalent to hand-writing the code yourself as it uses template
meta-programming heavily to optimise (the same as v8-juice). The code
size of vu8 is much smaller than v8-juice in spite of it performing
the same tasks as it re-uses components from boost. Particularly boost
fusion, boost mpl and boost preprocessor were very helpful. v8-juice
replicates many features from boost.mpl and boost.fusion, which removes
the dependency on boost but increases the size of the source code.

Additionally vu8 will take advantage of C++0x variadic template
arguments, r-value references and perfect forwarding. These improve
compile times amongst other things.

> i have no experience with vu8. i only found out about it via the above
> post. From a brief glance, it seems provide more or less the same
> features as v8-juice, but vu8 uses of function-pointer-style template
> args to make the API more readable (if i had only known how to do that
> two years ago...).

I could commit the code to v8-juice to show you if you want. Function
pointer templates can be passed easily using any type-based template
parameters, but converting this function pointer into a template
argument that accepts a member-function pointer requires either C++0x or
some pre-processor programming. The only tricky bit really is:

template <class T, [dependant on T] Q>

[dependant on T] can be worked out using a meta-program on T to
determine the type of template parameter Q is (i.e. what kind of
member function pointer it is). The trouble is without C++0x variadic
template parameters you need one copy of the meta-function to
determine [dependant] for each N where N is the number of arguments
in the member function prototype. You'd need to use preprocessor
programming to do this without C++0x variadic template arguments, and
with them the problem is trivial.

If you look at detail/Proto.hpp and Class.hpp in vu8 you'll probably
get it right away.

--
+44 (0) 7974 159 643 | ja...@chilon.net | http://chilon.net

Jak Sprats

unread,
Jan 19, 2011, 9:58:19 AM1/19/11
to v8-users
hi

this is a very helpful metaphor, I can read your C-calling-Lua example
and then get the C-calling-Javascript like i was reading a tutorial,
thank you.

One question, and this is not about calling C-calling-JS, it is about
calling JS-calling-C

In AlchemyDB, in C, I have the following line
lua_register(Lua, "client", luaCall_client);
Which tells the Lua interpreter, that when a lua scripts makes a
"client()" call, it should be rerouted to my C function
"luaCall_client()".

Is there a similarly simple mechanism to register JS functions to call
defined C functions.

This is the part I am not yet fully grasping on how to code it :)

- Jak

Jak Sprats

unread,
Jan 19, 2011, 10:01:06 AM1/19/11
to v8-users
>> If all you want to do is wrap a single function, an add-on library like v8-juice or vu8 is way overkill. i'd start by taking a look at shell.cc inthe v8 source tree.

Hi Stephan,

advice like this is golden. I am trying to not to add bloat, but I
have no idea where to start, so the answer, "your use case is simple
enough to go directly into the internals" is one I hear very gladly.

So in shell.cc, it looks like ExecuteString() would be a pretty good
embedding point ... this is pretty much the code Vyacheslav is
describing below. So this is half of the puzzle, I can embed v8 now
(this looks like a very clean embedding implementation for
javascript) ... now the other half, calling C from JS... I am not
finding an example of that in shell.cc

I have the feeling, I am very close to getting this, but I still dont
fully get how to register a C function to be called when a JS function
is called.

- Jak


On Jan 18, 7:59 am, Stephan Beal <sgb...@googlemail.com> wrote:

Ondřej Žára

unread,
Jan 19, 2011, 10:05:09 AM1/19/11
to v8-u...@googlegroups.com
>
> I have the feeling, I am very close to getting this, but I still dont
> fully get how to register a C function to be called when a JS function
> is called.
>
> - Jak

From shell.cc:

v8::Handle<v8::Value> Version(const v8::Arguments& args) {
return v8::String::New(v8::V8::GetVersion());
}

// Create a template for the global object.
v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();

// Bind the 'version' function
global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version));

O.

>
>
> On Jan 18, 7:59 am, Stephan Beal <sgb...@googlemail.com> wrote:
>> On Tue, Jan 18, 2011 at 4:35 PM, Jak Sprats <jakspr...@gmail.com> wrote:
>> > <huge snip>
>>
>> ...man-days embedding V8 and then using v8-juice to implement the JS func
>>
>> > "client" would take? (just ballpark: is it a day, a week, a month?)
>>
>> i couldn't even guess. AlchemyDB and reddit are both foreign words to me, so
>> i couldn't even venture a guess.
>>
>> > What would be REAL helpful is if there was a hello-world for embedding
>> > v8 in C
>>
>> There is a hello-world (the shell app) in the v8 source tree. Binding that
>> with C requires a C++ middle-man API which has functions the C code can call
>> (i.e. they use export "C"). Aside from that, there should be no magic
>> involved.
>>
>> If all you want to do is wrap a single function, an add-on library like
>> v8-juice or vu8 is way overkill. i'd start by taking a look at shell.cc in
>> the v8 source tree.
>>
>> --
>> ----- stephan bealhttp://wanderinghorse.net/home/stephan/
>

Jak Sprats

unread,
Jan 19, 2011, 10:07:09 AM1/19/11
to v8-users
Hi James,

i am a big fan of boost, especially when it is present in lieu of
someone writing-their-own-boost :)

do you have any examples of a C++ program that has a single C function
{in my case jsCall_client()} that can be called in javascript by
calling "client()"

w/ a simple example, I can figure out the rest and hopefully this
already exists or can somehow be incorporated into vu8's examples/
howtos

- Jak

On Jan 19, 3:02 am, James Pike <ja...@chilon.net> wrote:
> >    On Tue, Jan 18, 2011 at 4:40 PM, Jak Sprats <[1]jakspr...@gmail.com>

James Pike

unread,
Jan 19, 2011, 10:16:03 AM1/19/11
to v8-u...@googlegroups.com
On Wed, Jan 19, 2011 at 07:07:09AM -0800, Jak Sprats wrote:
> Hi James,
>
> i am a big fan of boost, especially when it is present in lieu of
> someone writing-their-own-boost :)
>
> do you have any examples of a C++ program that has a single C function
> {in my case jsCall_client()} that can be called in javascript by
> calling "client()"

#include <vu8/Module.hpp>

void jsCall_client() {
...
}

void makeModule(v8::Handle<v8::Context> ctxt) {
vu8::Module module;
module.Set<void (), &jsCall_client>("js_name")

ctxt.Set(v8::String::New("mod_name"), module.NewInstance());
// now any v8 calls in this context can use mod_name.js_name

James Pike

unread,
Jan 19, 2011, 10:17:52 AM1/19/11
to v8-u...@googlegroups.com
Oops should have been context_->Global()->Set(...), fixed inline.

On Wed, Jan 19, 2011 at 07:07:09AM -0800, Jak Sprats wrote:
> Hi James,
>
> i am a big fan of boost, especially when it is present in lieu of
> someone writing-their-own-boost :)
>
> do you have any examples of a C++ program that has a single C function
> {in my case jsCall_client()} that can be called in javascript by
> calling "client()"

#include <vu8/Module.hpp>

void jsCall_client() {
...
}

void makeModule(v8::Handle<v8::Context> ctxt) {
vu8::Module module;
module.Set<void (), &jsCall_client>("js_name")

ctxt->Global()->Set(v8::String::New("mod_name"), module.NewInstance());

Vyacheslav Egorov

unread,
Jan 19, 2011, 10:28:02 AM1/19/11
to v8-u...@googlegroups.com
Yes there is. Let me show you the mapping :-)

1) In Lua you have lua_CFunction :

typedef int (*lua_CFunction) (lua_State *L);

it gets arguments on the stack, pushes results on the stack and
returns number of results.

In V8 you have v8::InvocationCallback:

typedef Handle<Value> (*InvocationCallback)(const Arguments& args);

it gets Arguments object which provides access to arguments and returns result.

2) In Lua if you want to create function value from lua_CFunction foo you do

lua_pushcfunction(L, foo);
// function object is now on top of the stack

In V8 to create function from InvocationCallback foo you do:

Local<Function> f = FunctionTemplate::New(foo)->GetFunction();

3) To set global variable bar in Lua you push the value on the stack
and then call

lua_setglobal(L, "bar"); // pop value from the stack and assign it to
global called bar

In V8 you just do:

Context::GetCurrent()->Global()->Set(v8::String::New("bar"), val); //
where val is something you want to assign to global

4) In Lua lua_register(L, name, func) is just

lua_pushcfunction(L, func); // push function on the stack
lua_setglobal(L, name); // pop function from the stack and assign it
to global called name.

This translates to V8 as:

Context::GetCurrent()->Global()->Set(v8::String::New(name),
FunctionTemplate::New(func)->GetFunction());

// Concept of global object in V8/JavaScript is a bit more complicated
than in Lua so instead of using Context::GetCurrent()->Global() you
can access it in a different ways.

--
Vyacheslav Egorov

Stephan Beal

unread,
Jan 19, 2011, 12:32:34 PM1/19/11
to v8-u...@googlegroups.com
On Wed, Jan 19, 2011 at 3:58 PM, Jak Sprats <jaks...@gmail.com> wrote:
Is there a similarly simple mechanism to register JS functions to call
defined C functions.

This is the part I am not yet fully grasping on how to code it :)

That's the easy part. Here's an (untested/skeleton) example:

using namespace v8;
Handle<Value> my_func( Arguments const & argv )
{
    if( argv.Length() < 1 ) {
        return ThrowException("Requires 1 argument!");
    }
    
    unsigned int sleepTime = static_cast<unsigned int>(argv[0]->Int32Value);
    unsigned int rc;
    {
        v8::Unlocker unlock; // allows other threads to work while sleep()ing
        rc = ::sleep(sleepTime);
    }
    return Integer::New( static_cast<int32_t>(rc) );
}

(remember to do more range checking on the arguments, and remember that JS has no unsigned integer type, so a user passing a negative number would sleep very, very long in the above code.)

my_func() simply implements the v8::InvocationCallback interface (the standard callback type), and can be bound directly to v8.

That glue is basically what v8-juice/vu8 provide for you, but if you just want to wrap a small handful of functions then such helpers are probably overkill.

Jak Sprats

unread,
Jan 21, 2011, 10:38:22 AM1/21/11
to v8-users
Hi All,

this is enough information for me to give this a shot next week (maybe
the next as time allows).

I am going to schedule in 2 non-consecutive days, just to try it out
and report back (each day) to this very helpful group if/when i
encounter problems.

so thanks for the good info, and next time i check in on this thread
will either be in a triumphant or frustrated tone :)

- Jak

On Jan 19, 9:32 am, Stephan Beal <sgb...@googlemail.com> wrote:
Reply all
Reply to author
Forward
0 new messages