Embeddable JavaScript engine.
Website: https://www-archive.mozilla.org/js/spidermonkey/
Source:
Mozilla SpiderMonkey 1.6 archive
Platforms supported: Win32, Linux
Headers to include: spidermonkey/jsapi.bi
Header version: SpiderMonkey 1.6
Native SDK and values
Use the archived 1.6 C embedding API with these examples. Current SpiderMonkey SDKs have a different embedding API. The native Win32 build uses 32-bit JSWord and jsval values; its DLL and import library belong to a Win32 application. The SDK's CPU configuration cannot be carried unchanged into a Win64 build.
C int, JSBool, int32 and uint32 use 32-bit types. The low three bits of a jsval encode its type. Use the binding's conversion macros rather than dereferencing a tagged value directly. JS_TRUE and JS_FALSE use C's 1 and 0 boolean representation, including when encoded by BOOLEAN_TO_JSVAL.
The actual Win32 SDK from Mozilla's js-1.60.tar.gz archive has been checked with independent C layouts, both FreeBASIC backends, native callbacks, GC roots and all three examples. The same archived engine also passes on Linux i386 with both backends, C layouts, callbacks, GC roots and all three examples. On Linux amd64 use a 32-bit executable and matching runtime; native Win64 execution remains separate. Generate jsautocfg.h using the actual i386 CPU-configuration program. Apply build_scripts/patches/spidermonkey16-fdlibm-errno.patch privately: the global-errno workaround belongs to XP_WIN, while Unix must use <errno.h> to match glibc thread-local errno. The patch preserves the Windows workaround. The SDK was built without JS_THREADSAFE, so one application thread owns each runtime and its contexts.
Ownership and cleanup
Check every runtime, context, object, string and function creation result. JSClass is borrowed by its objects and must remain valid for their lifetime. Destroy contexts before their runtime, and call JS_ShutDown() after the application has finished with all SpiderMonkey runtimes.
JS_GetStringBytes() returns borrowed storage. Copy it before keeping it across an API call which may allocate or collect. JS_NewStringCopyN() copies a caller's buffer into SDK-owned storage. JS_NewString() instead accepts an owned buffer obtained through JS_malloc(); an ordinary FreeBASIC string buffer must not be passed to it.
Protect a jsval held outside the engine with JS_AddRoot(cx, @value) before a possible garbage collection, then remove that root with JS_RemoveRoot(cx, @value) before the context is destroyed. The root tracks the value's storage address, so keep that address valid. Native callbacks return JS_TRUE on success, set their result through rval, and return JS_FALSE on failure.
Example
'' examples/manual/libraries/spidermonkey1.bas
''
'' Example extracted from the FreeBASIC Manual
'' from topic 'SpiderMonkey'
'' Purpose: Evaluate JavaScript using the archived SpiderMonkey 1.6 API.
'' Responsibilities: Checked engine setup, borrowed strings and owned cleanup.
'' This example contains no JavaScript engine implementation or worker threads.
''
'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ExtLibspidermonkey
'' --------
'' Evaluating javascript code
#include Once "spidermonkey/jsapi.bi"
' The SDK borrows this class descriptor for every object's lifetime.
' A single application thread owns the runtime and its callbacks.
Dim Shared As JSClass global_class = _
( _
@"global", 0, _
@JS_PropertyStub, @JS_PropertyStub, @JS_PropertyStub, @JS_PropertyStub, _
@JS_EnumerateStub, @JS_ResolveStub, @JS_ConvertStub, @JS_FinalizeStub _
)
Const TEST_SCRIPT = _
!"function fact(n) \n" + _
!"{ \n" + _
!" if (n <= 1) \n" + _
!" return 1; \n" + _
!" \n" + _
!" return n * fact(n - 1);\n" + _
!"} \n" + _
!" \n" + _
!" fact(5) \n"
Function run_example() As Integer
Dim As JSRuntime Ptr rt
Dim As JSContext Ptr cx
Dim As Integer status = 1
Do
' One MiB GC budget; 4096 selects the context's stack chunk size.
rt = JS_NewRuntime(1048576)
If rt = 0 Then Exit Do
cx = JS_NewContext(rt, 4096)
If cx = 0 Then Exit Do
Dim As JSObject Ptr global = JS_NewObject(cx, @global_class, NULL, NULL)
If global = 0 Then Exit Do
JS_SetGlobalObject(cx, global)
If JS_InitStandardClasses(cx, global) = 0 Then Exit Do
Dim As jsval rval
If JS_EvaluateScript(cx, global, TEST_SCRIPT, Len(TEST_SCRIPT), "localhost", 1, @rval) = 0 Then Exit Do
Dim As JSString Ptr result_string = JS_ValueToString(cx, rval)
If result_string = 0 Then Exit Do
Dim As ZString Ptr result_bytes = JS_GetStringBytes(result_string)
If result_bytes = 0 Then Exit Do
Print "result: " & *result_bytes
status = 0
Loop While 0
' Destroy contexts before their runtime, then release process-wide state.
If cx <> 0 Then JS_DestroyContext(cx)
If rt <> 0 Then JS_DestroyRuntime(rt)
JS_ShutDown()
Return status
End Function
Dim As Integer status = run_example()
If status <> 0 Then Print "SpiderMonkey example failed"
End status
'' end of spidermonkey1.bas
'' examples/manual/libraries/spidermonkey2.bas
''
'' Example extracted from the FreeBASIC Manual
'' from topic 'SpiderMonkey'
'' Purpose: Evaluate JavaScript using the archived SpiderMonkey 1.6 API.
'' Responsibilities: Checked engine setup, borrowed strings and owned cleanup.
'' This example contains no JavaScript engine implementation or worker threads.
''
'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ExtLibspidermonkey
'' --------
'' Callback example: Functions that are used by the Javascript code,
'' but are implemented in FB.
#include Once "spidermonkey/jsapi.bi"
' The SDK borrows this class descriptor for every object's lifetime.
' A single application thread owns the runtime and its callbacks.
Dim Shared As JSClass global_class = _
( _
@"global", 0, _
@JS_PropertyStub, @JS_PropertyStub, @JS_PropertyStub, @JS_PropertyStub, _
@JS_EnumerateStub, @JS_ResolveStub, @JS_ConvertStub, @JS_FinalizeStub _
)
Private Function print_callback cdecl _
( _
ByVal cx As JSContext Ptr, _
ByVal obj As JSObject Ptr, _
ByVal argc As uintN, _
ByVal argv As jsval Ptr, _
ByVal rval As jsval Ptr _
) As JSBool
If (argc < 1 OrElse argv = 0 OrElse rval = 0) Then
Return 0
End If
Dim As JSString Ptr arg_string = JS_ValueToString(cx, argv[0])
If arg_string = 0 Then Return 0
Dim As ZString Ptr arg_bytes = JS_GetStringBytes(arg_string)
If arg_bytes = 0 Then Return 0
Print *arg_bytes
*rval = JSVAL_VOID
Return 1
End Function
Private Function ucase_callback cdecl _
( _
ByVal cx As JSContext Ptr, _
ByVal obj As JSObject Ptr, _
ByVal argc As uintN, _
ByVal argv As jsval Ptr, _
ByVal rval As jsval Ptr _
) As JSBool
If (argc < 1 OrElse argv = 0 OrElse rval = 0) Then
Return 0
End If
Dim As JSString Ptr arg_string = JS_ValueToString(cx, argv[0])
If arg_string = 0 Then Return 0
Dim As ZString Ptr arg_bytes = JS_GetStringBytes(arg_string)
If arg_bytes = 0 Then Return 0
' Copy borrowed bytes before calling an API which can allocate or collect.
Dim As String result = UCase(*arg_bytes)
Dim As JSString Ptr result_string = JS_NewStringCopyN(cx, StrPtr(result), Len(result))
If result_string = 0 Then Return 0
' The SDK owns the copy; the FreeBASIC string can leave scope safely.
*rval = STRING_TO_JSVAL(result_string)
Return 1
End Function
Const TEST_SCRIPT = "print(ucase('hello'));"
Function run_example() As Integer
Dim As JSRuntime Ptr rt
Dim As JSContext Ptr cx
Dim As Integer status = 1
Do
' One MiB GC budget; 4096 selects the context's stack chunk size.
rt = JS_NewRuntime(1048576)
If rt = 0 Then Exit Do
cx = JS_NewContext(rt, 4096)
If cx = 0 Then Exit Do
Dim As JSObject Ptr global = JS_NewObject(cx, @global_class, NULL, NULL)
If global = 0 Then Exit Do
JS_SetGlobalObject(cx, global)
If JS_InitStandardClasses(cx, global) = 0 Then Exit Do
If JS_DefineFunction(cx, global, "print", @print_callback, 1, 0) = 0 Then Exit Do
If JS_DefineFunction(cx, global, "ucase", @ucase_callback, 1, 0) = 0 Then Exit Do
Dim As jsval rval
If JS_EvaluateScript(cx, global, TEST_SCRIPT, Len(TEST_SCRIPT), "localhost", 1, @rval) = 0 Then Exit Do
status = 0
Loop While 0
' Destroy contexts before their runtime, then release process-wide state.
If cx <> 0 Then JS_DestroyContext(cx)
If rt <> 0 Then JS_DestroyRuntime(rt)
JS_ShutDown()
Return status
End Function
Dim As Integer status = run_example()
If status <> 0 Then Print "SpiderMonkey example failed"
End status
'' end of spidermonkey2.bas