1
// Copyright 2008, Google Inc.
3
// Redistribution and use in source and binary forms, with or without
4
// modification, are permitted provided that the following conditions are met:
6
// 1. Redistributions of source code must retain the above copyright notice,
7
// this list of conditions and the following disclaimer.
8
// 2. Redistributions in binary form must reproduce the above copyright notice,
9
// this list of conditions and the following disclaimer in the documentation
10
// and/or other materials provided with the distribution.
11
// 3. Neither the name of Google Inc. nor the names of its contributors may be
12
// used to endorse or promote products derived from this software without
13
// specific prior written permission.
15
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
// Create a SpiderMonkey instance and return an NPAPI wrapper for it.
28
#include "gears/base/common/js_standalone_engine.h"
29
#include "gears/base/common/js_runner.h"
30
#include "gears/base/common/mutex.h"
31
#include "gears/base/common/scoped_token.h"
33
#include "gears/base/safari/npapi_patches.h"
35
#include "third_party/spidermonkey/gears_include/mozjs_api.h"
36
#include "third_party/spidermonkey/gears_npapi_bindings/mozjs_npapi_storage.h"
37
#include "third_party/spidermonkey/gears_npapi_bindings/mozjs_npruntime.h"
39
// Mutex to guard JSCreateContext calls.
40
static Mutex engine_creation_mutex;
42
// Defined in js_runner_np.cc
43
void HandleJSError(const JsRunner *js_runner, JsErrorInfo &error_info);
45
typedef DECLARE_SCOPED_TRAITS(JSContext*, JS_DestroyContext, NULL)
47
typedef scoped_token<JSContext*, JSContextTraits> scoped_jscontext_ptr;
49
// Spidermonkey callback for error handling.
50
static void JS_DLL_CALLBACK JsErrorHandler(JSContext *cx, const char *message,
51
JSErrorReport *report) {
52
// Ugly hack, without this, if we call a JS error handler from here
53
// then Spidermonkey will bork.
54
JSBool old_val = cx->throwing;
55
cx->throwing = JS_FALSE;
57
JsRunner *js_runner = static_cast<JsRunner*>(JS_GetContextPrivate(cx));
58
if (js_runner && report) {
59
JsErrorInfo error_info;
60
error_info.line = report->lineno + 1; // Reported lines start at zero.
62
// The error message can either be in the separate *message param or in
63
// *report->ucmessage. For example, running the following JS in a worker
64
// causes the separate message param to get used:
65
// throw new Error("foo")
66
// Other errors cause the report->ucmessage property to get used.
68
// Mozilla also does this, see:
69
// http://lxr.mozilla.org/mozilla1.8.0/source/dom/src/base/nsJSEnvironment.cpp#163
70
if (report->ucmessage) {
71
error_info.message = reinterpret_cast<const char16 *>(report->ucmessage);
73
std::string16 message_str;
74
if (UTF8ToString16(message, &message_str)) {
75
error_info.message = message_str;
79
HandleJSError(js_runner, error_info);
82
cx->throwing = old_val;
87
static JSBool js_gc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
93
static JSBool js_print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
95
JSString *str = JS_ValueToString(cx, argv[0]);
96
printf("script result: %s\n", JS_GetStringBytes(str));
100
static JSBool js_break(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
107
// Create a JS context & Engine and return them.
108
static bool CreateJSEngine(JsRunner *js_runner, JSRuntime **runtime,
109
JSContext **context) {
110
// These are taken from js_runner_ff.cc, if changes are made you'll
111
// probably want to change the values there too.
113
const int kRuntimeMaxBytes = 1 * 1024 * 1024; // Somewhat more sensible.
115
const int kRuntimeMaxBytes = 64 * 1024 * 1024; // mozilla/.../js.c uses 64 MB
117
const int kContextStackChunkSize = 1024; // Firefox often uses 1024;
118
// also see js/src/readme.html
119
// Create a new JS Runtime.
122
MutexLock lock(&engine_creation_mutex);
123
rt = JS_NewRuntime(kRuntimeMaxBytes);
126
if (!rt) { return false; }
128
// Initialize a context.
129
scoped_jscontext_ptr cx(JS_NewContext(rt, kContextStackChunkSize));
135
// VAROBJFIX is recommended in /mozilla/js/src/jsapi.h
136
JS_SetOptions(cx.get(), JS_GetOptions(cx.get()) | JSOPTION_VAROBJFIX);
137
JS_SetErrorReporter(cx.get(), JsErrorHandler);
138
JS_SetContextPrivate(cx.get(), reinterpret_cast<void*>(js_runner));
140
// These structs are static because they must live for duration of JS engine.
141
// SpiderMonkey README also suggests using static for one-off objects.
142
static JSClass global_class = {
143
"Global", 0, // name, flags
144
JS_PropertyStub, JS_PropertyStub, // defineProperty, deleteProperty
145
JS_PropertyStub, JS_PropertyStub, // getProperty, setProperty
146
JS_EnumerateStub, JS_ResolveStub, // enum, resolve
147
JS_ConvertStub, JS_FinalizeStub // convert, finalize
150
JSAutoRequest context_lock(cx.get());
151
JSObject *global_obj = JS_NewObject(cx.get(), &global_class, 0, 0);
152
if (!global_obj) { return false; }
154
JSBool js_ok = JS_InitStandardClasses(cx.get(), global_obj);
155
if (!js_ok) { return false; }
158
JS_DefineFunction(cx.get(), global_obj, "print", js_print, 1, 0);
159
JS_DefineFunction(cx.get(), global_obj, "GearsInternalCollectGarbage", js_gc,
161
JS_DefineFunction(cx.get(), global_obj, "brk", js_break,
165
// Everything is setup, so pass out the JSContext.
167
*context = cx.release();
171
bool JSStandaloneEngine::InitEngine(JsRunner *js_runner,
172
NPP_t *np_instance) {
176
// Bootstrap the JS Engine instance.
179
if (!CreateJSEngine(js_runner, &runtime, &context)) {
183
// Setup the global object
184
// JsRunner is the browser side.
185
(np_instance)->ndata = static_cast<void *>(js_runner);
187
// for use by the plugin side.
188
(np_instance)->pdata = NULL;
190
SpiderMonkeyNPAPIBindings::NPAPI_Storage::CreateThreadLocals(runtime,
197
void JSStandaloneEngine::GetNPNEntryPoints(NPNetscapeFuncs *browser_funcs) {
198
assert(browser_funcs);
199
#ifdef BROWSER_WEBKIT
200
memset(browser_funcs, 0, sizeof(GearsNPNetscapeFuncs));
201
browser_funcs->size = sizeof(GearsNPNetscapeFuncs);
203
memset(browser_funcs, 0, sizeof(NPNetscapeFuncs));
204
browser_funcs->size = sizeof(browser_funcs);
206
browser_funcs->version = 1;
207
browser_funcs->memalloc = SpiderMonkeyNPAPIBindings::NPN_MemAlloc;
208
browser_funcs->memfree = SpiderMonkeyNPAPIBindings::NPN_MemFree;
209
browser_funcs->getvalue = SpiderMonkeyNPAPIBindings::NPN_GetValue;
210
browser_funcs->releasevariantvalue =
211
SpiderMonkeyNPAPIBindings::NPN_ReleaseVariantValue;
212
browser_funcs->getstringidentifier =
213
SpiderMonkeyNPAPIBindings::NPN_GetStringIdentifier;
214
browser_funcs->getstringidentifiers =
215
SpiderMonkeyNPAPIBindings::NPN_GetStringIdentifiers;
216
browser_funcs->getintidentifier =
217
SpiderMonkeyNPAPIBindings::NPN_GetIntIdentifier;
218
browser_funcs->identifierisstring =
219
SpiderMonkeyNPAPIBindings::NPN_IdentifierIsString;
220
browser_funcs->utf8fromidentifier =
221
SpiderMonkeyNPAPIBindings::NPN_UTF8FromIdentifier;
222
#ifdef BROWSER_WEBKIT
223
browser_funcs->intfromidentifier =
224
reinterpret_cast<void * (*)(void *)>(
225
SpiderMonkeyNPAPIBindings::NPN_IntFromIdentifier);
227
browser_funcs->intfromidentifier =
228
SpiderMonkeyNPAPIBindings::NPN_IntFromIdentifier;
230
browser_funcs->createobject = SpiderMonkeyNPAPIBindings::NPN_CreateObject;
231
browser_funcs->retainobject = SpiderMonkeyNPAPIBindings::NPN_RetainObject;
232
browser_funcs->releaseobject = SpiderMonkeyNPAPIBindings::NPN_ReleaseObject;
233
browser_funcs->invoke = SpiderMonkeyNPAPIBindings::NPN_Invoke;
234
browser_funcs->invokeDefault = SpiderMonkeyNPAPIBindings::NPN_InvokeDefault;
235
browser_funcs->evaluate = SpiderMonkeyNPAPIBindings::NPN_Evaluate;
236
browser_funcs->getproperty = SpiderMonkeyNPAPIBindings::NPN_GetProperty;
237
browser_funcs->setproperty = SpiderMonkeyNPAPIBindings::NPN_SetProperty;
238
browser_funcs->removeproperty = SpiderMonkeyNPAPIBindings::NPN_RemoveProperty;
239
browser_funcs->hasproperty = SpiderMonkeyNPAPIBindings::NPN_HasProperty;
240
browser_funcs->hasmethod = SpiderMonkeyNPAPIBindings::NPN_HasMethod;
241
browser_funcs->setexception = SpiderMonkeyNPAPIBindings::NPN_SetException;
242
#ifdef BROWSER_WEBKIT
243
((GearsNPNetscapeFuncs *)browser_funcs)->enumerate =
244
SpiderMonkeyNPAPIBindings::NPN_Enumerate;
246
browser_funcs->enumerate = SpiderMonkeyNPAPIBindings::NPN_Enumerate;
250
bool JSStandaloneEngine::TerminateEngine() {
251
JSContext * context =
252
SpiderMonkeyNPAPIBindings::NPAPI_Storage::GetCurrentJSContext();
254
SpiderMonkeyNPAPIBindings::NPAPI_Storage::GetsJSRuntime();
255
JS_DestroyContext(context);
256
JS_DestroyRuntime(runtime);
257
SpiderMonkeyNPAPIBindings::NPAPI_Storage::ClearJSContext();