1
0
forked from mirrors/0ad

Upgrade to SpiderMonkey 1.8.5 (fixes #734)

This was SVN commit r9852.
This commit is contained in:
Ykkrosh
2011-07-16 23:24:14 +00:00
parent c7ba150c40
commit 2f0bd8d8b0
28 changed files with 267 additions and 93 deletions
+9 -2
View File
@@ -72,11 +72,18 @@ struct ScriptInterface_NativeMethodWrapper<void, TC> {
};
// Fast natives don't trigger the hook we use for profiling, so explicitly
// notify the profiler when these functions are being called
// notify the profiler when these functions are being called.
// ScriptInterface_impl::Register stores the name in a reserved slot.
// (TODO: this doesn't work for functions registered via InterfaceScripted.h.
// Maybe we should do some interned JS_GetFunctionId thing.)
#if ENABLE_SCRIPT_PROFILING
#define SCRIPT_PROFILE \
ENSURE(JSVAL_IS_OBJECT(JS_CALLEE(cx, vp)) && JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)))); \
const char* name = JS_GetFunctionName(JS_ValueToFunction(cx, JS_CALLEE(cx, vp))); /* native function so ValueToFunction is safe; this makes unsafe lifetime assumptions */ \
const char* name = "(unknown)"; \
jsval nameval; \
if (JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)), 0, &nameval) \
&& !JSVAL_IS_VOID(nameval)) \
name = static_cast<const char*>(JSVAL_TO_PRIVATE(nameval)); \
CProfileSampleScript profile(name);
#else
#define SCRIPT_PROFILE
+6 -8
View File
@@ -23,12 +23,7 @@
#include "ps/utf16string.h"
#include "ps/CLogger.h"
#include "ps/CStr.h"
#include "js/jsapi.h"
#define signbit std::signbit
#include "js/jstypedarray.h"
#undef signbit
#include "scriptinterface/ScriptExtraHeaders.h" // for typed arrays
#define FAIL(msg) STMT(JS_ReportError(cx, msg); return false)
@@ -114,8 +109,11 @@ template<> bool ScriptInterface::FromJSVal<std::wstring>(JSContext* cx, jsval v,
JSString* ret = JS_ValueToString(cx, v);
if (!ret)
FAIL("Argument must be convertible to a string");
jschar* ch = JS_GetStringChars(ret);
out = std::wstring(ch, ch + JS_GetStringLength(ret));
size_t length;
const jschar* ch = JS_GetStringCharsAndLength(cx, ret, &length);
if (!ch)
FAIL("JS_GetStringsCharsAndLength failed"); // out of memory
out = std::wstring(ch, ch + length);
return true;
}
@@ -0,0 +1,53 @@
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_SCRIPTEXTRAHEADERS
#define INCLUDED_SCRIPTEXTRAHEADERS
// Includes occasionally-used SpiderMonkey headers for typed arrays and debug API,
// with appropriate tweaks to fix warnings and build errors. (Most code should
// just include ScriptTypes.h directly to get the standard jsapi.h.)
#include "scriptinterface/ScriptTypes.h"
// Ignore some harmless warnings
#if GCC_VERSION >= 402 // (older GCCs don't support this pragma)
# pragma GCC diagnostic ignored "-Wunused-parameter"
# pragma GCC diagnostic ignored "-Wredundant-decls"
#endif
#if MSC_VERSION
# pragma warning(push)
# pragma warning(disable:4800) // "forcing value to bool 'true' or 'false' (performance warning)"
#endif
// Redefine signbit to fix build error in GCC
#define signbit std::signbit
#include "js/jstypedarray.h"
#include "js/jsdbgapi.h"
#undef signbit
#if MSC_VERSION
# pragma warning(pop)
#endif
#if GCC_VERSION >= 402
# pragma GCC diagnostic ignored "-Wunused-parameter"
# pragma GCC diagnostic warning "-Wredundant-decls"
#endif
#endif // INCLUDED_SCRIPTEXTRAHEADERS
+73 -17
View File
@@ -45,11 +45,7 @@
#define STACK_CHUNK_SIZE 8192
#if ENABLE_SCRIPT_PROFILING
# define signbit std::signbit
# include "js/jsdbgapi.h"
# undef signbit
#endif
#include "scriptinterface/ScriptExtraHeaders.h"
////////////////////////////////////////////////////////////////
@@ -57,7 +53,7 @@ class ScriptRuntime
{
public:
ScriptRuntime(int runtimeSize) :
m_rooter(NULL)
m_rooter(NULL), m_compartmentGlobal(NULL)
{
m_rt = JS_NewRuntime(runtimeSize);
ENSURE(m_rt); // TODO: error handling
@@ -85,6 +81,8 @@ public:
JSRuntime* m_rt;
AutoGCRooter* m_rooter;
JSObject* m_compartmentGlobal;
private:
#if ENABLE_SCRIPT_PROFILING
@@ -227,6 +225,7 @@ struct ScriptInterface_impl
JSContext* m_cx;
JSObject* m_glob; // global scope object
JSObject* m_nativeScope; // native function scope object
JSCrossCompartmentCall* m_call;
};
namespace
@@ -234,7 +233,7 @@ namespace
JSClass global_class = {
"global", JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL
@@ -265,6 +264,10 @@ void ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report)
{
// TODO: this violates the docs ("The error reporter callback must not reenter the JSAPI.")
// Hide the exception from EvaluateScript
JSExceptionState* excnState = JS_SaveExceptionState(cx);
JS_ClearPendingException(cx);
jsval rval;
const char dumpStack[] = "this.stack.trimRight().replace(/^/mg, ' ')"; // indent each line
if (JS_EvaluateScript(cx, JSVAL_TO_OBJECT(excn), dumpStack, ARRAY_SIZE(dumpStack)-1, "(eval)", 1, &rval))
@@ -272,6 +275,13 @@ void ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report)
std::string stackTrace;
if (ScriptInterface::FromJSVal(cx, rval, stackTrace))
msg << "\n" << stackTrace;
JS_RestoreExceptionState(cx, excnState);
}
else
{
// Error got replaced by new exception from EvaluateScript
JS_DropExceptionState(cx, excnState);
}
}
@@ -357,7 +367,15 @@ JSBool deepcopy(JSContext* cx, uintN argc, jsval* vp)
}
jsval ret;
if (!JS_StructuredClone(cx, JS_ARGV(cx, vp)[0], &ret))
// We'd usually do:
// if (!JS_StructuredClone(cx, JS_ARGV(cx, vp)[0], &ret, NULL, NULL))
// return JS_FALSE;
// but that function is broken in the 1.8.5 release
// (https://bugzilla.mozilla.org/show_bug.cgi?id=651510)
// so do an equivalent operation with a different API:
JSAutoStructuredCloneBuffer buf;
if (!buf.write(cx, JS_ARGV(cx, vp)[0]) || !buf.read(&ret, cx))
return JS_FALSE;
JS_SET_RVAL(cx, vp, ret);
@@ -463,7 +481,19 @@ ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const sh
// Threadsafe SpiderMonkey requires that we have a request before doing anything much
JS_BeginRequest(m_cx);
m_glob = JS_NewGlobalObject(m_cx, &global_class);
// We only want a single compartment per runtime
if (m_runtime->m_compartmentGlobal)
{
m_call = JS_EnterCrossCompartmentCall(m_cx, m_runtime->m_compartmentGlobal);
m_glob = JS_NewGlobalObject(m_cx, &global_class);
}
else
{
m_call = NULL;
m_glob = JS_NewCompartmentAndGlobalObject(m_cx, &global_class, NULL);
m_runtime->m_compartmentGlobal = m_glob;
}
ok = JS_InitStandardClasses(m_cx, m_glob);
ENSURE(ok);
@@ -485,13 +515,33 @@ ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const sh
ScriptInterface_impl::~ScriptInterface_impl()
{
if (m_call)
JS_LeaveCrossCompartmentCall(m_call);
JS_EndRequest(m_cx);
JS_DestroyContext(m_cx);
}
void ScriptInterface_impl::Register(const char* name, JSNative fptr, uintN nargs)
{
JS_DefineFunction(m_cx, m_nativeScope, name, fptr, nargs, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
JSFunction* func = JS_DefineFunction(m_cx, m_nativeScope, name, fptr, nargs, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
if (!func)
return;
#if ENABLE_SCRIPT_PROFILING
// Store the function name in a slot, so we can pass it to the profiler.
// Use a flyweight std::string because we can't assume the caller has
// a correctly-aligned string and that its lifetime is long enough
typedef boost::flyweight<
std::string,
boost::flyweights::no_tracking
// can't use no_locking; Register might be called in threads
> LockedStringFlyweight;
LockedStringFlyweight fw(name);
JS_SetReservedSlot(m_cx, JS_GetFunctionObject(func), 0, PRIVATE_TO_JSVAL((void*)fw.get().c_str()));
#endif
}
ScriptInterface::ScriptInterface(const char* nativeScopeName, const char* debugName, const shared_ptr<ScriptRuntime>& runtime) :
@@ -762,9 +812,9 @@ bool ScriptInterface::EnumeratePropertyNamesWithPrefix(jsval obj, const char* pr
continue; // ignore integer properties
JSString* name = JSVAL_TO_STRING(val);
size_t len = JS_GetStringLength(name);
jschar* chars = JS_GetStringChars(name);
if (len >= prefix16.size() && memcmp(chars, prefix16.c_str(), prefix16.size()*2) == 0)
size_t len;
const jschar* chars = JS_GetStringCharsAndLength(m->m_cx, name, &len);
if (chars && len >= prefix16.size() && memcmp(chars, prefix16.c_str(), prefix16.size()*2) == 0)
out.push_back(std::string(chars, chars+len)); // handles Unicode poorly
}
@@ -1102,7 +1152,10 @@ private:
if (JSVAL_IS_STRING(val))
{
JSString* str = JS_NewUCStringCopyN(cxTo, JS_GetStringChars(JSVAL_TO_STRING(val)), JS_GetStringLength(JSVAL_TO_STRING(val)));
size_t len;
const jschar* chars = JS_GetStringCharsAndLength(cxFrom, JSVAL_TO_STRING(val), &len);
CLONE_REQUIRE(chars, L"JS_GetStringCharsAndLength");
JSString* str = JS_NewUCStringCopyN(cxTo, chars, len);
CLONE_REQUIRE(str, L"JS_NewUCStringCopyN");
jsval rval = STRING_TO_JSVAL(str);
m_Mapping[JSVAL_TO_GCTHING(val)] = rval;
@@ -1153,7 +1206,10 @@ private:
// string jsids are runtime-specific, so we need to copy the string content
JSString* idstr = JS_ValueToString(cxFrom, idval);
CLONE_REQUIRE(idstr, L"JS_ValueToString (id)");
CLONE_REQUIRE(JS_SetUCProperty(cxTo, newObj, JS_GetStringChars(idstr), JS_GetStringLength(idstr), &newPropval), L"JS_SetUCProperty");
size_t len;
const jschar* chars = JS_GetStringCharsAndLength(cxFrom, idstr, &len);
CLONE_REQUIRE(idstr, L"JS_GetStringCharsAndLength (id)");
CLONE_REQUIRE(JS_SetUCProperty(cxTo, newObj, chars, len, &newPropval), L"JS_SetUCProperty");
}
else
{
@@ -1195,7 +1251,7 @@ shared_ptr<ScriptInterface::StructuredClone> ScriptInterface::WriteStructuredClo
{
uint64* data = NULL;
size_t nbytes = 0;
if (!JS_WriteStructuredClone(m->m_cx, v, &data, &nbytes))
if (!JS_WriteStructuredClone(m->m_cx, v, &data, &nbytes, NULL, NULL))
return shared_ptr<StructuredClone>();
// TODO: should we have better error handling?
// Currently we'll probably continue and then crash in ReadStructuredClone
@@ -1210,6 +1266,6 @@ shared_ptr<ScriptInterface::StructuredClone> ScriptInterface::WriteStructuredClo
jsval ScriptInterface::ReadStructuredClone(const shared_ptr<ScriptInterface::StructuredClone>& ptr)
{
jsval ret = JSVAL_VOID;
JS_ReadStructuredClone(m->m_cx, ptr->m_Data, ptr->m_Size, &ret);
JS_ReadStructuredClone(m->m_cx, ptr->m_Data, ptr->m_Size, JS_STRUCTURED_CLONE_VERSION, &ret, NULL, NULL);
return ret;
}
+20 -1
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -47,8 +47,27 @@
# endif
#endif
// Ignore some harmless warnings triggered by jsapi.h
#if GCC_VERSION >= 402 // (older GCCs don't support this pragma)
# pragma GCC diagnostic ignored "-Wunused-parameter"
# pragma GCC diagnostic ignored "-Wredundant-decls"
#endif
#if MSC_VERSION
# pragma warning(push)
# pragma warning(disable:4480) // "nonstandard extension used: specifying underlying type for enum"
# pragma warning(disable:4100) // "unreferenced formal parameter"
#endif
#include "js/jsapi.h"
#if MSC_VERSION
# pragma warning(pop)
#endif
#if GCC_VERSION >= 402
# pragma GCC diagnostic warning "-Wunused-parameter"
# pragma GCC diagnostic warning "-Wredundant-decls"
#endif
#if JS_VERSION != 185
#error Your compiler is trying to use an incorrect version of the SpiderMonkey library.
#error The only version that works is the one in the libraries/spidermonkey-tip/ directory,