1 /**************************************************************************\
2 * Copyright (c) Kongsberg Oil & Gas Technologies AS
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif /* !HAVE_CONFIG_H */
36
37 #ifdef COIN_HAVE_JAVASCRIPT
38
39 #include <cassert>
40 #include <cstdlib>
41 #include <cstring>
42 #include <cstdio>
43
44 #if !defined(SPIDERMONKEY_RUNTIME_LINKING) && defined(HAVE_SPIDERMONKEY_VIA_LINKTIME_LINKING)
45 #ifdef _WIN32
46 #define XP_WIN
47 #ifdef HAVE_WINDOWS_H
48 #include <windows.h>
49 #else
50 #error Cannot compile SpiderMonkey support without windows.h available.
51 #endif /* !HAVE_WINDWOS_H */
52 #else /* For UNIX and Mac OS X */
53 #define XP_UNIX
54 #endif
55 #include <jsapi.h>
56 #endif /* !defined(SPIDERMONKEY_RUNTIME_LINKING) && defined(HAVE_SPIDERMONKEY_VIA_LINKTIME_LINKING) */
57
58 /*! \file spidermonkey.h */
59 #include <Inventor/C/glue/spidermonkey.h>
60
61 #include <Inventor/C/glue/dl.h>
62 #include <Inventor/C/errors/debugerror.h>
63 #include <Inventor/C/tidbits.h>
64
65 #include "threads/threadsutilp.h"
66 #include "tidbitsp.h"
67
68 /* ********************************************************************** */
69 #ifdef __cplusplus
70 extern "C" {
71 #endif /* __cplusplus */
72
73 /* ******************************************************************** */
74
75 static SpiderMonkey_t * spidermonkey_instance = NULL;
76 static cc_libhandle spidermonkey_libhandle = NULL;
77 static SbBool spidermonkey_failed_to_load = FALSE;
78 static int spidermonkey_is_initializing = 0;
79
80 /* ******************************************************************** */
81
82 static SbBool
spidermonkey_debug(void)83 spidermonkey_debug(void)
84 {
85 static int dbg = -1;
86 if (dbg == -1) {
87 const char * env = coin_getenv("COIN_DEBUG_SPIDERMONKEY_BINDING");
88 dbg = (env && (atoi(env) > 0)) ? 1 : 0;
89 }
90 return dbg;
91 }
92
93 /* ******************************************************************** */
94
95 /* Cleans up at exit. */
96 static void
spidermonkey_cleanup(void)97 spidermonkey_cleanup(void)
98 {
99 #ifdef SPIDERMONKEY_RUNTIME_LINKING
100 if (spidermonkey_libhandle) {
101 cc_dl_close(spidermonkey_libhandle);
102 spidermonkey_libhandle = NULL;
103 }
104 #endif /* SPIDERMONKEY_RUNTIME_LINKING */
105
106 assert(spidermonkey_instance);
107 free(spidermonkey_instance);
108 spidermonkey_instance = NULL;
109 spidermonkey_failed_to_load = FALSE;
110 spidermonkey_is_initializing = 0;
111 }
112
113 /* ******************************************************************** */
114
115 /* Implemented by using the singleton pattern. */
116 const SpiderMonkey_t *
spidermonkey(void)117 spidermonkey(void)
118 {
119 SpiderMonkey_t * sm;
120
121 CC_SYNC_BEGIN(spidermonkey);
122
123 if (spidermonkey_instance || spidermonkey_failed_to_load) { goto wrapperexit; }
124
125 /* Detect recursive calls. */
126 {
127 assert(spidermonkey_is_initializing == 0);
128 spidermonkey_is_initializing = 1;
129 }
130
131
132 /* First invocation, do initializations. */
133 spidermonkey_instance = sm = (SpiderMonkey_t *)malloc(sizeof(SpiderMonkey_t));
134 /* FIXME: handle out-of-memory on malloc(). 20000928 mortene. */
135 (void)coin_atexit((coin_atexit_f*) spidermonkey_cleanup, CC_ATEXIT_DYNLIBS);
136
137 /* Be optimistic. */
138 sm->available = 1;
139
140 #ifdef SPIDERMONKEY_RUNTIME_LINKING
141
142 {
143 unsigned int idx;
144
145 /* FIXME: there's a configure mortene. */
146 const char * possiblelibnames[] = {
147 NULL, /* is set below */
148 /* MSWindows DLL name */
149 "js32",
150
151 /* UNIX-style names (SpiderMonkey compiled from source) */
152 "js", "libjs", "libjs.so", "libjs.dylib",
153
154 /* Debian package 'spidermonkey-bin' (SpiderMonkey v1.5) */
155 "libsmjs.so.1",
156
157 /* terminator */
158 NULL
159 };
160 possiblelibnames[0] = coin_getenv("COIN_SPIDERMONKEY_LIBNAME");
161 idx = possiblelibnames[0] ? 0 : 1;
162
163 while (!spidermonkey_libhandle && possiblelibnames[idx]) {
164 if (spidermonkey_debug()) {
165 cc_debugerror_postinfo("spidermonkey", "Trying to dynamically load library '%s'",
166 possiblelibnames[idx]);
167 }
168 spidermonkey_libhandle = cc_dl_open(possiblelibnames[idx]);
169 idx++;
170 }
171
172 if (!spidermonkey_libhandle) {
173 sm->available = 0;
174 spidermonkey_failed_to_load = 1;
175 if (spidermonkey_debug()) {
176 cc_debugerror_postinfo("spidermonkey", "SpiderMonkey library failed to load.");
177 }
178 goto wrapperexit;
179 }
180
181 if (spidermonkey_debug()) {
182 if (spidermonkey_failed_to_load) {
183 /* FIXME: This message will never be reached, as far as I can see (20050906 handegar) */
184 cc_debugerror_postinfo("spidermonkey", "Found no SpiderMonkey library on system.");
185 }
186 else {
187 cc_debugerror_postinfo("spidermonkey",
188 "Dynamically loaded SpiderMonkey library as '%s'.",
189 possiblelibnames[idx-1]);
190 }
191 }
192 }
193
194
195 /* Define macro for grabbing function symbols. Casting the type is
196 necessary for this file to be compatible with C++ compilers. */
197 #define REGISTER_FUNC(_funcname_, _funcsig_) \
198 sm->_funcname_ = (_funcsig_)cc_dl_sym(spidermonkey_libhandle, SO__QUOTE(_funcname_)); \
199 assert(sm->_funcname_)
200
201 /* Some functions in SpiderMonkey may have a symbol name different
202 from the API name. */
203 #define REGISTER_FUNC_ALTERNATE(_funcname_, _altname_, _funcsig_) \
204 sm->_funcname_ = (_funcsig_)cc_dl_sym(spidermonkey_libhandle, SO__QUOTE(_funcname_)); \
205 if (sm->_funcname_ == NULL) { sm->_funcname_ = (_funcsig_)cc_dl_sym(spidermonkey_libhandle, SO__QUOTE(_altname_)); } \
206 assert(sm->_funcname_)
207
208 #elif defined(HAVE_SPIDERMONKEY_VIA_LINKTIME_LINKING) /* static linking */
209
210 #define REGISTER_FUNC(_funcname_, _funcsig_) \
211 sm->_funcname_ = (_funcsig_)_funcname_; \
212 assert(sm->_funcname_)
213
214 #define REGISTER_FUNC_ALTERNATE(_funcname_, _altname_, _funcsig_) \
215 REGISTER_FUNC(_funcname_, _funcsig_)
216
217 #else /* neither dynamic nor static linking */
218
219 sm->available = 0;
220
221 #define REGISTER_FUNC(_funcname_, _funcsig_) \
222 sm->_funcname_ = NULL
223
224 #define REGISTER_FUNC_ALTERNATE(_funcname_, _altname_, _funcsig_) \
225 REGISTER_FUNC(_funcname_, _funcsig_)
226
227 #endif /* done setting up REGISTER_FUNC */
228
229 REGISTER_FUNC(JS_GetImplementationVersion, JS_GetImplementationVersion_t);
230 if (spidermonkey_debug() && sm->JS_GetImplementationVersion) {
231 const char * version = sm->JS_GetImplementationVersion();
232 cc_debugerror_postinfo("spidermonkey", "%s", version);
233 }
234
235 REGISTER_FUNC(JS_EvaluateScript, JS_EvaluateScript_t);
236 REGISTER_FUNC(JS_ValueToString, JS_ValueToString_t);
237 REGISTER_FUNC(JS_GetStringBytes, JS_GetStringBytes_t);
238 REGISTER_FUNC(JS_SetProperty, JS_SetProperty_t);
239 REGISTER_FUNC(JS_GetProperty, JS_GetProperty_t);
240 REGISTER_FUNC(JS_CallFunctionName, JS_CallFunctionName_t);
241 REGISTER_FUNC(JS_CallFunctionValue, JS_CallFunctionValue_t);
242 REGISTER_FUNC(JS_ConstructObjectWithArguments, JS_ConstructObjectWithArguments_t);
243 REGISTER_FUNC_ALTERNATE(JS_NewRuntime, JS_Init, JS_NewRuntime_t);
244 REGISTER_FUNC_ALTERNATE(JS_DestroyRuntime, JS_Finish, JS_DestroyRuntime_t);
245 REGISTER_FUNC(JS_NewContext, JS_NewContext_t);
246 REGISTER_FUNC(JS_DestroyContext, JS_DestroyContext_t);
247 REGISTER_FUNC(JS_ShutDown, JS_ShutDown_t);
248 REGISTER_FUNC(JS_SetErrorReporter, JS_SetErrorReporter_t);
249 REGISTER_FUNC(JS_PropertyStub, JS_PropertyStub_t);
250 REGISTER_FUNC(JS_EnumerateStub, JS_EnumerateStub_t);
251 REGISTER_FUNC(JS_ResolveStub, JS_ResolveStub_t);
252 REGISTER_FUNC(JS_ConvertStub, JS_ConvertStub_t);
253 REGISTER_FUNC(JS_FinalizeStub, JS_FinalizeStub_t);
254 REGISTER_FUNC(JS_NewObject, JS_NewObject_t);
255 REGISTER_FUNC(JS_InitStandardClasses, JS_InitStandardClasses_t);
256 REGISTER_FUNC(JS_DefineObject, JS_DefineObject_t);
257 REGISTER_FUNC(JS_DefineProperties, JS_DefineProperties_t);
258 REGISTER_FUNC(JS_GetPrivate, JS_GetPrivate_t);
259 REGISTER_FUNC(JS_SetPrivate, JS_SetPrivate_t);
260 REGISTER_FUNC(JS_NewFunction, JS_NewFunction_t);
261 REGISTER_FUNC(JS_GetFunctionObject, JS_GetFunctionObject_t);
262 REGISTER_FUNC(JS_GetParent, JS_GetParent_t);
263 REGISTER_FUNC(JS_SetParent, JS_SetParent_t);
264 REGISTER_FUNC(JS_DefineFunctions, JS_DefineFunctions_t);
265 REGISTER_FUNC(JS_NewStringCopyZ, JS_NewStringCopyZ_t);
266 REGISTER_FUNC(JS_TypeOfValue, JS_TypeOfValue_t);
267 REGISTER_FUNC(JS_GetTypeName, JS_GetTypeName_t);
268 REGISTER_FUNC(JS_InstanceOf, JS_InstanceOf_t);
269 REGISTER_FUNC(JS_InitClass, JS_InitClass_t);
270 REGISTER_FUNC(JS_NewDoubleValue, JS_NewDoubleValue_t);
271 REGISTER_FUNC(JS_SetContextPrivate, JS_SetContextPrivate_t);
272 REGISTER_FUNC(JS_GetContextPrivate, JS_GetContextPrivate_t);
273 REGISTER_FUNC(JS_ValueToBoolean, JS_ValueToBoolean_t);
274 REGISTER_FUNC(JS_ValueToNumber, JS_ValueToNumber_t);
275 REGISTER_FUNC(JS_NewArrayObject, JS_NewArrayObject_t);
276 REGISTER_FUNC(JS_GetArrayLength, JS_GetArrayLength_t);
277 REGISTER_FUNC(JS_SetArrayLength, JS_SetArrayLength_t);
278 REGISTER_FUNC(JS_HasArrayLength, JS_HasArrayLength_t);
279 REGISTER_FUNC(JS_GetElement, JS_GetElement_t);
280 REGISTER_FUNC(JS_SetElement, JS_SetElement_t);
281 REGISTER_FUNC(JS_AddRoot, JS_AddRoot_t);
282 REGISTER_FUNC(JS_RemoveRoot, JS_RemoveRoot_t);
283 REGISTER_FUNC(JS_GetStringLength, JS_GetStringLength_t);
284 REGISTER_FUNC(JS_LookupProperty, JS_LookupProperty_t);
285 REGISTER_FUNC(JS_DefineProperty, JS_DefineProperty_t);
286 REGISTER_FUNC(JS_CompileFile, JS_CompileFile_t);
287 REGISTER_FUNC(JS_ValueToObject, JS_ValueToObject_t);
288 REGISTER_FUNC(JS_ExecuteScript, JS_ExecuteScript_t);
289 REGISTER_FUNC(JS_IsExceptionPending, JS_IsExceptionPending_t);
290 REGISTER_FUNC(JS_GetPendingException, JS_GetPendingException_t);
291 REGISTER_FUNC(JS_SetPendingException, JS_SetPendingException_t);
292 REGISTER_FUNC(JS_ClearPendingException, JS_ClearPendingException_t);
293 REGISTER_FUNC(JS_NewDouble, JS_NewDouble_t);
294 REGISTER_FUNC(JS_CallFunction, JS_CallFunction_t);
295 REGISTER_FUNC(JS_ValueToFunction, JS_ValueToFunction_t);
296 REGISTER_FUNC(JS_ReportError, JS_ReportError_t);
297 REGISTER_FUNC(JS_IsArrayObject, JS_IsArrayObject_t);
298 REGISTER_FUNC(JS_ObjectIsFunction, JS_ObjectIsFunction_t);
299 REGISTER_FUNC(JS_ValueToECMAInt32, JS_ValueToECMAInt32_t);
300 REGISTER_FUNC(JS_DefineFunction, JS_DefineFunction_t);
301 REGISTER_FUNC(JS_GetGlobalObject, JS_GetGlobalObject_t);
302 REGISTER_FUNC(JS_SetGCCallback, JS_SetGCCallback_t);
303 REGISTER_FUNC(JS_MaybeGC, JS_MaybeGC_t);
304 REGISTER_FUNC(JS_GC, JS_GC_t);
305 REGISTER_FUNC(JS_IsRunning, JS_IsRunning_t);
306 REGISTER_FUNC(JS_DeleteProperty, JS_DeleteProperty_t);
307 REGISTER_FUNC(JS_CompileScript, JS_CompileScript_t);
308 REGISTER_FUNC(JS_GetNaNValue, JS_GetNaNValue_t);
309 REGISTER_FUNC(JS_GetNegativeInfinityValue, JS_GetNegativeInfinityValue_t);
310 REGISTER_FUNC(JS_GetPositiveInfinityValue, JS_GetPositiveInfinityValue_t);
311 REGISTER_FUNC(JS_GetEmptyStringValue, JS_GetEmptyStringValue_t);
312 REGISTER_FUNC(JS_SetPropertyAttributes, JS_SetPropertyAttributes_t);
313 REGISTER_FUNC(JS_GetPropertyAttributes, JS_GetPropertyAttributes_t);
314 REGISTER_FUNC(JS_GetClass, JS_GetClass_t);
315 REGISTER_FUNC(JS_GetPrototype, JS_GetPrototype_t);
316 REGISTER_FUNC(JS_SetPrototype, JS_SetPrototype_t);
317 REGISTER_FUNC(JS_CompareStrings, JS_CompareStrings_t);
318 REGISTER_FUNC(JS_GetOptions, JS_GetOptions_t);
319 REGISTER_FUNC(JS_SetOptions, JS_SetOptions_t);
320 REGISTER_FUNC(JS_ToggleOptions, JS_ToggleOptions_t);
321 REGISTER_FUNC(JS_Enumerate, JS_Enumerate_t);
322 REGISTER_FUNC(JS_IdToValue, JS_IdToValue_t);
323 REGISTER_FUNC(JS_GetFunctionName, JS_GetFunctionName_t);
324 REGISTER_FUNC(JS_GetConstructor, JS_GetConstructor_t);
325 REGISTER_FUNC(JS_DestroyIdArray, JS_DestroyIdArray_t);
326
327 wrapperexit:
328 CC_SYNC_END(spidermonkey);
329 return spidermonkey_instance;
330 }
331
332 #undef REGISTER_FUNC
333
334 #ifdef __cplusplus
335 } /* extern "C" */
336 #endif /* __cplusplus */
337
338 #endif /* !COIN_HAVE_JAVASCRIPT */
339