This article needs a technical review. How you can help.
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 building and running the sample below the code.
// This is an example for SpiderMonkey 31. // For SpiderMonkey 24, 38, or 45, see each comment. // following code might be needed in some case // #define __STDC_LIMIT_MACROS // #include <stdint.h> #include "jsapi.h" // [SpiderMonkey 45] // #include "js/Initialization.h" /* The class of the global object. */ static JSClass global_class = { "global", JSCLASS_GLOBAL_FLAGS, // [SpiderMonkey 38, 45] Replace all stubs but JS_GlobalObjectTraceHook with nullptr. JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, // [SpiderMonkey 24] doesn't need the bits after this; there is // no JS_GlobalObjectTraceHook there. nullptr, nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook }; int main(int argc, const char *argv[]) { // [SpiderMonkey 24] JS_Init does not exist. Remove this line. JS_Init(); // [SpiderMonkey 38, 45] useHelperThreads parameter is removed. // JSRuntime *rt = JS_NewRuntime(8L * 1024 * 1024); JSRuntime *rt = JS_NewRuntime(8L * 1024 * 1024, JS_USE_HELPER_THREADS); if (!rt) return 1; JSContext *cx = JS_NewContext(rt, 8192); if (!cx) return 1; { // Scope for our various stack objects (JSAutoRequest, RootedObject), so they all go // out of scope before we JS_DestroyContext. JSAutoRequest ar(cx); // In practice, you would want to exit this any // time you're spinning the event loop // [SpiderMonkey 24] hookOption parameter does not exist. // JS::RootedObject global(cx, JS_NewGlobalObject(cx, &global_class, nullptr)); JS::RootedObject global(cx, JS_NewGlobalObject(cx, &global_class, nullptr, JS::FireOnNewGlobalHook)); if (!global) return 1; JS::RootedValue rval(cx); { // Scope for JSAutoCompartment JSAutoCompartment ac(cx, global); JS_InitStandardClasses(cx, global); const char *script = "'hello'+'world, it is '+new Date()"; const char *filename = "noname"; int lineno = 1; // [SpiderMonkey 24] The type of rval parameter is 'jsval *'. // bool ok = JS_EvaluateScript(cx, global, script, strlen(script), filename, lineno, rval.address()); // [SpiderMonkey 38] JS_EvaluateScript is replaced with JS::Evaluate. // JS::CompileOptions opts(cx); // opts.setFileAndLine(filename, lineno); // bool ok = JS::Evaluate(cx, global, opts, script, strlen(script), &rval); // [SpiderMonkey 45] // JS::CompileOptions opts(cx); // opts.setFileAndLine(filename, lineno); // bool ok = JS::Evaluate(cx, opts, script, strlen(script), &rval); bool ok = JS_EvaluateScript(cx, global, script, strlen(script), filename, lineno, &rval); if (!ok) return 1; } JSString *str = rval.toString(); printf("%s\n", JS_EncodeString(cx, str)); } JS_DestroyContext(cx); JS_DestroyRuntime(rt); JS_ShutDown(); return 0; }
Build and run the Hello World example
Build command line depends on the OS and the tools. Here are sample Mac and Linux command lines (where <objdir>
is the directory where SpiderMonkey was built):
[Mac] clang++ -std=c++11 -I<objdir>/dist/include -L<objdir>/dist/lib helloworld.cpp -o helloworld -lmozjs-31 -lz [Linux] g++ -std=c++11 -I<objdir>/dist/include -L<objdir>/dist/lib helloworld.cpp -o helloworld -lmozjs-31 -lz -lpthread -ldl
It should print "helloworld, it is TIME"
(here TIME is the current time).
- 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.
- 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:\mozjs-31.2.0
- 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.
- Copy the code example above into a text editor and save the file as helloworld.cpp in the SpiderMonkey js\src directory. To get a copy of the code sample without line numbers, hover over the sample near the top until buttons appear. Then click the view source button, and copy the code from the window that appears.
- Compile the helloworld application and link to the SpiderMonkey library.
- Run the helloworld executable at the command line:
./helloworld
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 // [SpiderMonkey 24] Use JSBool instead of bool. static bool doit(JSContext *cx, unsigned argc, jsval *vp) { JS::CallArgs args = CallArgsFromVp(argc, vp); /* * Look in argv for argc actual parameters, set *rval to return a * value to the caller. * * ex. Add two arguments as integer. * args.rval().setInt32(args[0].toInt32() + args[1].toInt32()); */ return true; }
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[] = { JS_FN("doit", doit, DOIT_MINARGS, 0), /* etc... */ JS_FS_END };
JS_FS_END
terminates the table. And say:
ok = JS_DefineFunctions(cx, global, my_functions);
How to call JavaScript functions from C
First, create arguments for the call, here I create arguments with 2 items:
// [SpiderMonkey 24] JS::AutoValueArray is not defined. // JS::AutoValueVector argv(cx); // argv.resize(2); JS::AutoValueArray<2> argv(cx); argv[0].setInt32(1); argv[1].setInt32(2);
then call the function:
// [SpiderMonkey 24] Pass arguments length and the 'jsval *' pointer. // JS_CallFunctionName(cx, global, "func", 2, argv.begin(), rval.address()); JS_CallFunctionName(cx, global, "func", argv, &rval);
Example
Say the click event is for the top-most or focused UI element at position (x, y):
JSObject *target, *event; JS::AutoValueArray<1> argv(cx); /* * 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].setObjectOrNull(event); /* To emulate the DOM, you might want to try "onclick" too. */ ok = JS_CallFunctionName(cx, target, "onClick", argv, &rval); /* Now test rval to see whether we should cancel the event. */ if (rval.isBoolean() && !rval.toBoolean()) 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