How to embed the JavaScript engine

  • Revision slug: How_to_embed_the_JavaScript_engine
  • Revision title: How to embed the JavaScript engine
  • Revision id: 49815
  • Created:
  • Creator: MarkGiffin
  • Is current revision? No
  • Comment one or more formatting changes

Revision Content

 

See also JSAPI User Guide. In particular, it has more and better code examples!

A Bare Bones Tutorial

Hello World sample embedding application

The following code is a very simple application that shows how to embed SpiderMonkey and run a simple JavaScript script. See the instructions for running it below the code.

/*
 * This define is for Windows only, it is a work-around for bug 661663.
 */
#ifdef _MSC_VER
# define XP_WIN
#endif

/* Include the JSAPI header file to get access to SpiderMonkey. */
#include "jsapi.h"

/* The class of the global object. */
static JSClass global_class = {
    "global", JSCLASS_GLOBAL_FLAGS,
    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
    JSCLASS_NO_OPTIONAL_MEMBERS
};

/* The error reporter callback. */
void reportError(JSContext *cx, const char *message, JSErrorReport *report)
{
    fprintf(stderr, "%s:%u:%s\n",
            report->filename ? report->filename : "<no filename="filename">",
            (unsigned int) report->lineno,
            message);
}

int main(int argc, const char *argv[])
{
    /* JSAPI variables. */
    JSRuntime *rt;
    JSContext *cx;
    JSObject  *global;

    /* Create a JS runtime. You always need at least one runtime per process. */
    rt = JS_NewRuntime(8 * 1024 * 1024);
    if (rt == NULL)
        return 1;

    /* Create a context. You always need a context per thread. */
    cx = JS_NewContext(rt, 8192);
    if (cx == NULL)
        return 1;
    JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT | JSOPTION_METHODJIT);
    JS_SetVersion(cx, JSVERSION_LATEST);
    JS_SetErrorReporter(cx, reportError);

    /*
     * Create the global object in a new compartment.
     * You always need a global object per context.
     */
    global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
    if (global == NULL)
        return 1;

    /*
     * Populate the global object with the standard JavaScript
     * function and object classes, such as Object, Array, Date.
     */
    if (!JS_InitStandardClasses(cx, global))
        return 1;

    /* Your application code here. This may include JSAPI calls
     * to create your own custom JavaScript objects and to run scripts.
     *
     * The following example code creates a literal JavaScript script,
     * evaluates it, and prints the result to stdout.
     *
     * Errors are conventionally saved in a JSBool variable named ok.
     */
    char *script = "'Hello ' + 'World!'";
    jsval rval;
    JSString *str;
    JSBool ok;
    const char *filename = "noname";
    uintN lineno = 0;

    ok = JS_EvaluateScript(cx, global, script, strlen(script),
                           filename, lineno, &rval);
    if (rval == NULL | rval == JS_FALSE)
        return 1;

    str = JS_ValueToString(cx, rval);
    printf("%s\n", JS_EncodeString(cx, str));

    /* End of your application code */

    /* Clean things up and shut down SpiderMonkey. */
    JS_DestroyContext(cx);
    JS_DestroyRuntime(rt);
    JS_ShutDown();
    return 0;
}

Run the Hello World example

  1. Make sure the build computer has the prerequisites for building SpiderMonkey: Linux, Windows, Mac OS X, others. For Windows, the following steps will assume that you have installed the MozillaBuild package.
  2. Get the SpiderMonkey source code. You can download a source archive or use Mercurial (hg) to pull the SpiderMonkey repository. On Windows, do not install the SpiderMonkey source code under the msys root directory (which is usually c:\mozilla-build\msys). Instead use something like C:\js-1.8.5.
  3. Compile SpiderMonkey using the build instructions at SpiderMonkey Build Documentation. By default this will build a SpiderMonkey shared library that you will link into your application in a later step.
  4. Copy the code example above into a text editor and save the file as helloworld.cpp in the SpiderMonkey js\src directory.
  5. Compile the helloworld application and link to the SpiderMonkey library.
  6. Here is a sample Linux command line (where <objdir> is the directory where SpiderMonkey was built):
        g++ -I<objdir>/dist/include -L<objdir>/dist/bin -ljs  helloworld.cpp
    Here is a sample Windows command line from the MozillaBuild shell:
        cl helloworld.cpp -link dist/lib/mozjs185-1.0.lib
  7. Run the helloworld executable at the command line:
  8.     ./helloworld
    It should print Hello World!

How to call C functions from JavaScript

Say the C function is named doit and it would like at least two actual parameters when called (if the caller supplies fewer, the JS engine should ensure that undefined is passed for the missing ones):

#define DOIT_MINARGS 2

static JSBool
doit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    /*
     * Look in argv for argc actual parameters, set *rval to return a
     * value to the caller.
     */
    ...
}

Then to wire it up to JS, you could write:

ok = JS_DefineFunction(cx, global, "doit", doit, DOIT_MINARGS, 0);

Or, if you had a bunch of native functions to define, you would probably put them in a table:

static JSFunctionSpec my_functions[] = {
    {"doit", doit, DOIT_MINARGS, 0, 0},
    etc...
    {0,0,0,0,0},
};

(the final, all-zeroes function specifier terminates the table) and say:

ok = JS_DefineFunctions(cx, global, my_functions);

How to call JavaScript functions from C

Say the click event is for the top-most or focused UI element at position (x, y):

JSObject *target, *event;
jsval argv[1], rval;

/*
 * Find event target and make event object to represent this click.
 * Pass cx to NewEventObject so JS_NewObject can be called.
 */
target = FindEventTargetAt(cx, global, x, y);
event = NewEventObject(cx, "click", x, y);
argv[0] = OBJECT_TO_JSVAL(event);

/* To emulate the DOM, you might want to try "onclick" too. */
ok = JS_CallFunctionName(cx, target, "onClick", 1, argv, &rval);

/* Now test rval to see whether we should cancel the event. */
if (JSVAL_IS_BOOLEAN(rval) && !JSVAL_TO_BOOLEAN(rval))
    CancelEvent(event);

Again, I've elided error checking (such as testing for !ok after the call), and I've faked up some C event management routines that emulate the DOM's convention of canceling an event if its handler returns false.

Original Document Information

  • Author: Brendan Eich
  • Last Updated Date: 21 February, 2000

Revision Source

<p> </p>
<p>See also <a href="/En/SpiderMonkey/JSAPI_User_Guide" title="En/SpiderMonkey/JSAPI_User_Guide">JSAPI User Guide</a>. In particular, it has more and better code examples!</p>
<h2 name="A_Bare_Bones_Tutorial">A Bare Bones Tutorial</h2>
<h3>Hello World sample embedding application</h3>
<p>The following code is a very simple application that shows how to embed SpiderMonkey and run a simple JavaScript script. See the instructions for running it below the code.</p>
<pre>/*
 * This define is for Windows only, it is a work-around for bug 661663.
 */
#ifdef _MSC_VER
# define XP_WIN
#endif

/* Include the JSAPI header file to get access to SpiderMonkey. */
#include "jsapi.h"

/* The class of the global object. */
static JSClass global_class = {
    "global", JSCLASS_GLOBAL_FLAGS,
    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
    JSCLASS_NO_OPTIONAL_MEMBERS
};

/* The error reporter callback. */
void reportError(JSContext *cx, const char *message, JSErrorReport *report)
{
    fprintf(stderr, "%s:%u:%s\n",
            report-&gt;filename ? report-&gt;filename : "&lt;no filename="filename"&gt;",
            (unsigned int) report-&gt;lineno,
            message);
}

int main(int argc, const char *argv[])
{
    /* JSAPI variables. */
    JSRuntime *rt;
    JSContext *cx;
    JSObject  *global;

    /* Create a JS runtime. You always need at least one runtime per process. */
    rt = JS_NewRuntime(8 * 1024 * 1024);
    if (rt == NULL)
        return 1;

    /* Create a context. You always need a context per thread. */
    cx = JS_NewContext(rt, 8192);
    if (cx == NULL)
        return 1;
    JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT | JSOPTION_METHODJIT);
    JS_SetVersion(cx, JSVERSION_LATEST);
    JS_SetErrorReporter(cx, reportError);

    /*
     * Create the global object in a new compartment.
     * You always need a global object per context.
     */
    global = JS_NewCompartmentAndGlobalObject(cx, &amp;global_class, NULL);
    if (global == NULL)
        return 1;

    /*
     * Populate the global object with the standard JavaScript
     * function and object classes, such as Object, Array, Date.
     */
    if (!JS_InitStandardClasses(cx, global))
        return 1;

    /* Your application code here. This may include JSAPI calls
     * to create your own custom JavaScript objects and to run scripts.
     *
     * The following example code creates a literal JavaScript script,
     * evaluates it, and prints the result to stdout.
     *
     * Errors are conventionally saved in a JSBool variable named ok.
     */
    char *script = "'Hello ' + 'World!'";
    jsval rval;
    JSString *str;
    JSBool ok;
    const char *filename = "noname";
    uintN lineno = 0;

    ok = JS_EvaluateScript(cx, global, script, strlen(script),
                           filename, lineno, &amp;rval);
    if (rval == NULL | rval == JS_FALSE)
        return 1;

    str = JS_ValueToString(cx, rval);
    printf("%s\n", JS_EncodeString(cx, str));

    /* End of your application code */

    /* Clean things up and shut down SpiderMonkey. */
    JS_DestroyContext(cx);
    JS_DestroyRuntime(rt);
    JS_ShutDown();
    return 0;
}</pre>
<h3>Run the Hello World example</h3>
<ol style="margin-top: 0px; margin-right: 0px; margin-bottom: 1.286em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 22px; color: rgb(51, 51, 51); font-family: 'Lucida Grande', 'Lucida Sans Unicode', Lucida, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 22px; "> <li>Make sure the build computer has the prerequisites for building SpiderMonkey: <a href="/En/Developer_Guide/Build_Instructions/Linux_Prerequisites" title="https://developer.mozilla.org/En/Developer_Guide/Build_Instructions/Linux_Prerequisites">Linux</a>, <a href="/En/Developer_Guide/Build_Instructions/Windows_Prerequisites" title="https://developer.mozilla.org/En/Developer_Guide/Build_Instructions/Windows_Prerequisites">Windows</a>, <a href="/En/Developer_Guide/Build_Instructions/Mac_OS_X_Prerequisites" title="https://developer.mozilla.org/En/Developer_Guide/Build_Instructions/Mac_OS_X_Prerequisites">Mac OS X</a>, <a href="/En/Developer_Guide/Build_Instructions" title="https://developer.mozilla.org/En/Developer_Guide/Build_Instructions">others</a>. For Windows, the following steps will assume that you have installed the <a href="/En/Developer_Guide/Build_Instructions/Windows_Prerequisites#mozillabuild" title="https://developer.mozilla.org/En/Developer_Guide/Build_Instructions/Windows_Prerequisites#mozillabuild">MozillaBuild</a> package.</li> <li>Get the SpiderMonkey source code. You can <a class=" external" href="http://ftp.mozilla.org/pub/mozilla.org/js/" title="http://ftp.mozilla.org/pub/mozilla.org/js/">download a source archive</a> or use Mercurial (hg) to <a title="https://developer.mozilla.org/En/SpiderMonkey/Getting_SpiderMonkey_source_code#Getting_the_latest_SpiderMonkey_source_code">pull the SpiderMonkey repository</a>. On Windows, do not install the SpiderMonkey source code under the msys root directory (which is usually c:\mozilla-build\msys). Instead use something like C:\js-1.8.5.</li> <li>Compile SpiderMonkey using the build instructions at <a href="/En/SpiderMonkey/Build_Documentation" title="https://developer.mozilla.org/En/SpiderMonkey/Build_Documentation">SpiderMonkey Build Documentation</a>. By default this will build a SpiderMonkey shared library that you will link into your application in a later step.</li> <li>Copy the code example above into a text editor and save the file as <code style="font: normal normal normal 100%/normal 'Courier New', 'Andale Mono', monospace; color: inherit; font-weight: inherit; ">helloworld.cpp</code> in the SpiderMonkey <code style="font: normal normal normal 100%/normal 'Courier New', 'Andale Mono', monospace; color: inherit; font-weight: inherit; ">js\src</code> directory.</li> <li>Compile the helloworld application and link to the SpiderMonkey library.</li> <div>Here is a sample Linux command line (where <code style="font: normal normal normal 100%/normal 'Courier New', 'Andale Mono', monospace; color: inherit; font-weight: inherit; ">&lt;objdir&gt;</code> is the directory where SpiderMonkey was built):</div> <div><code style="font: normal normal normal 100%/normal 'Courier New', 'Andale Mono', monospace; color: inherit; font-weight: inherit; ">    g++ -I&lt;objdir&gt;/dist/include -L&lt;objdir&gt;/dist/bin -ljs  helloworld.cpp</code></div> <div>Here is a sample Windows command line from the MozillaBuild shell:</div> <code style="font: normal normal normal 100%/normal 'Courier New', 'Andale Mono', monospace; color: inherit; font-weight: inherit; ">    cl helloworld.cpp -link dist/lib/mozjs185-1.0.lib</code> <li>Run the <code style="font: normal normal normal 100%/normal 'Courier New', 'Andale Mono', monospace; color: inherit; font-weight: inherit; ">helloworld</code> executable at the command line:</li> <div><code style="font: normal normal normal 100%/normal 'Courier New', 'Andale Mono', monospace; color: inherit; font-weight: inherit; ">    ./helloworld</code></div> <div>It should print <code style="font: normal normal normal 100%/normal 'Courier New', 'Andale Mono', monospace; color: inherit; font-weight: inherit; ">Hello World!</code><code style="font: normal normal normal 100%/normal 'Courier New', 'Andale Mono', monospace; color: inherit; font-weight: inherit; "><br> </code></div>
</ol>
<h3>How to call C functions from JavaScript</h3>
<p>Say the C function is named <code>doit</code> and it would like at least two actual parameters when called (if the caller supplies fewer, the JS engine should ensure that undefined is passed for the missing ones):</p>
<pre class="eval">#define DOIT_MINARGS 2

static JSBool
doit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    /*
     * Look in argv for argc actual parameters, set *rval to return a
     * value to the caller.
     */
    ...
}
</pre>
<p>Then to wire it up to JS, you could write:</p>
<pre class="eval">ok = <a href="/en/SpiderMonkey/JSAPI_Reference/JS_DefineFunction" title="en/SpiderMonkey/JSAPI_Reference/JS_DefineFunction">JS_DefineFunction</a>(cx, global, "doit", doit, DOIT_MINARGS, 0);
</pre>
<p>Or, if you had a bunch of native functions to define, you would probably put them in a table:</p>
<pre class="eval">static <a href="/En/SpiderMonkey/JSAPI_Reference/JSFunctionSpec" title="En/SpiderMonkey/JSAPI_Reference/JSFunctionSpec">JSFunctionSpec</a> my_functions[] = {
    {"doit", doit, DOIT_MINARGS, 0, 0},
    etc...
    {0,0,0,0,0},
};
</pre>
<p>(the final, all-zeroes function specifier terminates the table) and say:</p>
<pre class="eval">ok = <a href="/en/SpiderMonkey/JSAPI_Reference/JS_DefineFunctions" title="en/SpiderMonkey/JSAPI_Reference/JS_DefineFunctions">JS_DefineFunctions</a>(cx, global, my_functions);
</pre>
<h3>How to call JavaScript functions from C</h3>
<p>Say the click event is for the top-most or focused UI element at position (x, y):</p>
<pre class="eval">JSObject *target, *event;
jsval argv[1], rval;

/*
 * Find event target and make event object to represent this click.
 * Pass cx to NewEventObject so JS_NewObject can be called.
 */
target = FindEventTargetAt(cx, global, x, y);
event = NewEventObject(cx, "click", x, y);
argv[0] = <a href="/en/SpiderMonkey/JSAPI_Reference/OBJECT_TO_JSVAL" title="en/SpiderMonkey/JSAPI_Reference/OBJECT_TO_JSVAL">OBJECT_TO_JSVAL</a>(event);

/* To emulate the DOM, you might want to try "onclick" too. */
ok = <a href="/en/SpiderMonkey/JSAPI_Reference/JS_CallFunctionName" title="en/SpiderMonkey/JSAPI_Reference/JS_CallFunctionName">JS_CallFunctionName</a>(cx, target, "onClick", 1, argv, &amp;rval);

/* Now test rval to see whether we should cancel the event. */
if (<a href="/en/SpiderMonkey/JSAPI_Reference/JSVAL_IS_BOOLEAN" title="en/SpiderMonkey/JSAPI_Reference/JSVAL_IS_BOOLEAN">JSVAL_IS_BOOLEAN</a>(rval) &amp;&amp; !<a href="/en/SpiderMonkey/JSAPI_Reference/JSVAL_TO_BOOLEAN" title="en/SpiderMonkey/JSAPI_Reference/JSVAL_TO_BOOLEAN">JSVAL_TO_BOOLEAN</a>(rval))
    CancelEvent(event);
</pre>
<p>Again, I've elided error checking (such as testing for <code>!ok</code> after the call), and I've faked up some C event management routines that emulate the DOM's convention of canceling an event if its handler returns false.</p>
<div class="originaldocinfo">
<h2 name="Original_Document_Information">Original Document Information</h2>
<ul> <li>Author: Brendan Eich</li> <li>Last Updated Date: 21 February, 2000</li>
</ul>
</div>
Revert to this revision