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