952, 954: Add spidermonkey_empty_context
[elinks.git] / src / ecmascript / spidermonkey-shared.c
blobc4cc60c29e63c2f6d8e5c40dfb4abc6d6d5bab1e
1 /** SpiderMonkey support for both user scripts and web scripts.
2 * @file */
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
8 #include "elinks.h"
10 #include "ecmascript/spidermonkey-shared.h"
12 /** A shared runtime used for both user scripts (scripting/smjs/) and
13 * scripts on web pages (ecmascript/spidermonkey/).
15 * SpiderMonkey has bugs that corrupt memory when multiple JSRuntimes
16 * are used: https://bugzilla.mozilla.org/show_bug.cgi?id=378918 and
17 * perhaps others. */
18 JSRuntime *spidermonkey_runtime;
20 /** A JSContext that can be used in JS_SetPrivate and JS_GetPrivate
21 * when no better one is available. This context has no global
22 * object, so scripts cannot be evaluated in it.
24 * XXX: This also works around a crash on exit. SMJS will crash on
25 * JS_DestroyRuntime if the given runtime has never had any context
26 * created, which will be the case if one closes ELinks without having
27 * loaded any documents. */
28 JSContext *spidermonkey_empty_context;
30 /** A reference count for ::spidermonkey_runtime so that modules using
31 * it can be initialized and shut down in arbitrary order. */
32 static int spidermonkey_runtime_refcount;
34 /** Initialize ::spidermonkey_runtime and ::spidermonkey_empty_context.
35 * If already initialized, just increment the reference count.
37 * @return 1 if successful or 0 on error. If this succeeds, the
38 * caller must eventually call spidermonkey_runtime_release(). */
39 int
40 spidermonkey_runtime_addref(void)
42 if (spidermonkey_runtime_refcount == 0) {
43 assert(spidermonkey_runtime == NULL);
44 assert(spidermonkey_empty_context == NULL);
45 if_assert_failed return 0;
47 spidermonkey_runtime = JS_NewRuntime(4L * 1024L * 1024L);
48 if (!spidermonkey_runtime) return 0;
50 spidermonkey_empty_context = JS_NewContext(spidermonkey_runtime,
51 0);
52 if (!spidermonkey_empty_context) {
53 /* Perhaps JS_DestroyRuntime will now crash
54 * because no context was created, but there's
55 * not much else to do. */
56 JS_DestroyRuntime(spidermonkey_runtime);
57 spidermonkey_runtime = NULL;
58 JS_ShutDown();
62 assert(spidermonkey_runtime);
63 assert(spidermonkey_empty_context);
64 spidermonkey_runtime_refcount++;
65 assert(spidermonkey_runtime_refcount > 0);
66 if_assert_failed { spidermonkey_runtime_refcount--; return 0; }
67 return 1;
70 /** Release a reference to ::spidermonkey_runtime, and destroy it if
71 * that was the last reference. If spidermonkey_runtime_addref()
72 * failed, then this must not be called. */
73 void
74 spidermonkey_runtime_release(void)
76 assert(spidermonkey_runtime_refcount > 0);
77 assert(spidermonkey_runtime);
78 assert(spidermonkey_empty_context);
79 if_assert_failed return;
81 --spidermonkey_runtime_refcount;
82 if (spidermonkey_runtime_refcount == 0) {
83 JS_DestroyContext(spidermonkey_empty_context);
84 spidermonkey_empty_context = NULL;
85 JS_DestroyRuntime(spidermonkey_runtime);
86 spidermonkey_runtime = NULL;
87 JS_ShutDown();
91 /** An ELinks-specific replacement for JS_DefineFunctions().
93 * @relates spidermonkeyFunctionSpec */
94 JSBool
95 spidermonkey_DefineFunctions(JSContext *cx, JSObject *obj,
96 const spidermonkeyFunctionSpec *fs)
98 for (; fs->name; fs++) {
99 if (!JS_DefineFunction(cx, obj, fs->name, fs->call,
100 fs->nargs, 0))
101 return JS_FALSE;
103 return JS_TRUE;
106 /** An ELinks-specific replacement for JS_InitClass().
108 * @relates spidermonkeyFunctionSpec */
109 JSObject *
110 spidermonkey_InitClass(JSContext *cx, JSObject *obj,
111 JSObject *parent_proto, JSClass *clasp,
112 JSNative constructor, uintN nargs,
113 JSPropertySpec *ps,
114 const spidermonkeyFunctionSpec *fs,
115 JSPropertySpec *static_ps,
116 const spidermonkeyFunctionSpec *static_fs)
118 JSObject *proto = JS_InitClass(cx, obj, parent_proto, clasp,
119 constructor, nargs,
120 ps, NULL, static_ps, NULL);
122 if (proto == NULL)
123 return NULL;
125 if (fs) {
126 if (!spidermonkey_DefineFunctions(cx, proto, fs))
127 return NULL;
130 if (static_fs) {
131 JSObject *cons_obj = JS_GetConstructor(cx, proto);
133 if (cons_obj == NULL)
134 return NULL;
135 if (!spidermonkey_DefineFunctions(cx, cons_obj, static_fs))
136 return NULL;
139 return proto;