mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-09-21 20:06:40 +00:00
[SM68 2/2] Update to Spidermonkey 68 APIs
No noteworthy API changes.
Details:
- Remove UTF16 script execution since UTF8 is supported in SM68 and
going forward
- Several new headers includes are required
- Realms replace Compartments as "global holders" (see meta-Bug 1357862)
- JSRequests are removed entirely (Bug 722345), see also aae417bd29
- Trivial API updates in ProxyHandlers, ArrayBuffer, Warnings, GC
reasons, Context options, ObjectIsFunction, ValueVectors and
JSCompartment
See also the migration guide:
https://github.com/mozilla-spidermonkey/spidermonkey-embedding-examples/blob/esr78/docs/Migration%20Guide.md
Tested by: Freagarach, Stan, Subitaneo
Fixes #5860
Differential Revision: https://code.wildfiregames.com/D3144
This was SVN commit r24297.
This commit is contained in:
@@ -161,14 +161,14 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
|
||||
#undef OVERLOADS
|
||||
|
||||
template<int i, typename T, typename... Ts>
|
||||
static void AssignOrToJSValHelper(const ScriptRequest& rq, JS::AutoValueVector& argv, const T& a, const Ts&... params)
|
||||
static void AssignOrToJSValHelper(const ScriptRequest& rq, JS::MutableHandleValueVector argv, const T& a, const Ts&... params)
|
||||
{
|
||||
ScriptInterface::AssignOrToJSVal(rq, argv[i], a);
|
||||
AssignOrToJSValHelper<i+1>(rq, argv, params...);
|
||||
}
|
||||
|
||||
template<int i, typename... Ts>
|
||||
static void AssignOrToJSValHelper(const ScriptRequest& UNUSED(rq), JS::AutoValueVector& UNUSED(argv))
|
||||
static void AssignOrToJSValHelper(const ScriptRequest& UNUSED(rq), JS::MutableHandleValueVector UNUSED(argv))
|
||||
{
|
||||
cassert(sizeof...(Ts) == 0);
|
||||
// Nop, for terminating the template recursion.
|
||||
@@ -179,9 +179,9 @@ bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, R& ret
|
||||
{
|
||||
ScriptRequest rq(this);
|
||||
JS::RootedValue jsRet(rq.cx);
|
||||
JS::AutoValueVector argv(rq.cx);
|
||||
JS::RootedValueVector argv(rq.cx);
|
||||
DISCARD argv.resize(sizeof...(Ts));
|
||||
AssignOrToJSValHelper<0>(rq, argv, params...);
|
||||
AssignOrToJSValHelper<0>(rq, &argv, params...);
|
||||
if (!CallFunction_(val, name, argv, &jsRet))
|
||||
return false;
|
||||
return FromJSVal(rq, jsRet, ret);
|
||||
@@ -192,9 +192,9 @@ bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, JS::Ro
|
||||
{
|
||||
ScriptRequest rq(this);
|
||||
JS::MutableHandle<R> jsRet(ret);
|
||||
JS::AutoValueVector argv(rq.cx);
|
||||
JS::RootedValueVector argv(rq.cx);
|
||||
DISCARD argv.resize(sizeof...(Ts));
|
||||
AssignOrToJSValHelper<0>(rq, argv, params...);
|
||||
AssignOrToJSValHelper<0>(rq, &argv, params...);
|
||||
return CallFunction_(val, name, argv, jsRet);
|
||||
}
|
||||
|
||||
@@ -202,9 +202,9 @@ template<typename R, typename... Ts>
|
||||
bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, JS::MutableHandle<R> ret, const Ts&... params) const
|
||||
{
|
||||
ScriptRequest rq(this);
|
||||
JS::AutoValueVector argv(rq.cx);
|
||||
JS::RootedValueVector argv(rq.cx);
|
||||
DISCARD argv.resize(sizeof...(Ts));
|
||||
AssignOrToJSValHelper<0>(rq, argv, params...);
|
||||
AssignOrToJSValHelper<0>(rq, &argv, params...);
|
||||
return CallFunction_(val, name, argv, ret);
|
||||
}
|
||||
|
||||
@@ -214,9 +214,9 @@ bool ScriptInterface::CallFunctionVoid(JS::HandleValue val, const char* name, co
|
||||
{
|
||||
ScriptRequest rq(this);
|
||||
JS::RootedValue jsRet(rq.cx);
|
||||
JS::AutoValueVector argv(rq.cx);
|
||||
JS::RootedValueVector argv(rq.cx);
|
||||
DISCARD argv.resize(sizeof...(Ts));
|
||||
AssignOrToJSValHelper<0>(rq, argv, params...);
|
||||
AssignOrToJSValHelper<0>(rq, &argv, params...);
|
||||
return CallFunction_(val, name, argv, &jsRet);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
|
||||
#include "ps/GameSetup/Config.h"
|
||||
#include "ps/Profile.h"
|
||||
#include "scriptinterface/ScriptExtraHeaders.h"
|
||||
#include "scriptinterface/ScriptEngine.h"
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
|
||||
|
||||
void GCSliceCallbackHook(JSContext* UNUSED(cx), JS::GCProgress progress, const JS::GCDescription& UNUSED(desc))
|
||||
{
|
||||
/**
|
||||
@@ -130,15 +130,15 @@ ScriptContext::~ScriptContext()
|
||||
ScriptEngine::GetSingleton().UnRegisterContext(m_cx);
|
||||
}
|
||||
|
||||
void ScriptContext::RegisterCompartment(JSCompartment* cmpt)
|
||||
void ScriptContext::RegisterRealm(JS::Realm* realm)
|
||||
{
|
||||
ENSURE(cmpt);
|
||||
m_Compartments.push_back(cmpt);
|
||||
ENSURE(realm);
|
||||
m_Realms.push_back(realm);
|
||||
}
|
||||
|
||||
void ScriptContext::UnRegisterCompartment(JSCompartment* cmpt)
|
||||
void ScriptContext::UnRegisterRealm(JS::Realm* realm)
|
||||
{
|
||||
m_Compartments.remove(cmpt);
|
||||
m_Realms.remove(realm);
|
||||
}
|
||||
|
||||
#define GC_DEBUG_PRINT 0
|
||||
@@ -204,8 +204,8 @@ void ScriptContext::MaybeIncrementalGC(double delay)
|
||||
#if GC_DEBUG_PRINT
|
||||
printf("Finishing incremental GC because gcBytes > m_ContextSize / 2. \n");
|
||||
#endif
|
||||
PrepareCompartmentsForIncrementalGC();
|
||||
JS::FinishIncrementalGC(m_cx, JS::gcreason::API);
|
||||
PrepareZonesForIncrementalGC();
|
||||
JS::FinishIncrementalGC(m_cx, JS::GCReason::API);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -233,11 +233,11 @@ void ScriptContext::MaybeIncrementalGC(double delay)
|
||||
else
|
||||
printf("Running incremental GC slice \n");
|
||||
#endif
|
||||
PrepareCompartmentsForIncrementalGC();
|
||||
PrepareZonesForIncrementalGC();
|
||||
if (!JS::IsIncrementalGCInProgress(m_cx))
|
||||
JS::StartIncrementalGC(m_cx, GC_NORMAL, JS::gcreason::API, GCSliceTimeBudget);
|
||||
JS::StartIncrementalGC(m_cx, GC_NORMAL, JS::GCReason::API, GCSliceTimeBudget);
|
||||
else
|
||||
JS::IncrementalGCSlice(m_cx, JS::gcreason::API, GCSliceTimeBudget);
|
||||
JS::IncrementalGCSlice(m_cx, JS::GCReason::API, GCSliceTimeBudget);
|
||||
}
|
||||
m_LastGCBytes = gcBytes;
|
||||
}
|
||||
@@ -248,12 +248,12 @@ void ScriptContext::ShrinkingGC()
|
||||
{
|
||||
JS_SetGCParameter(m_cx, JSGC_MODE, JSGC_MODE_ZONE);
|
||||
JS::PrepareForFullGC(m_cx);
|
||||
JS::GCForReason(m_cx, GC_SHRINK, JS::gcreason::API);
|
||||
JS::NonIncrementalGC(m_cx, GC_SHRINK, JS::GCReason::API);
|
||||
JS_SetGCParameter(m_cx, JSGC_MODE, JSGC_MODE_INCREMENTAL);
|
||||
}
|
||||
|
||||
void ScriptContext::PrepareCompartmentsForIncrementalGC() const
|
||||
void ScriptContext::PrepareZonesForIncrementalGC() const
|
||||
{
|
||||
for (JSCompartment* const& cmpt : m_Compartments)
|
||||
JS::PrepareZoneForGC(js::GetCompartmentZone(cmpt));
|
||||
for (JS::Realm* const& realm : m_Realms)
|
||||
JS::PrepareZoneForGC(js::GetRealmZone(realm));
|
||||
}
|
||||
|
||||
@@ -69,10 +69,10 @@ public:
|
||||
void ShrinkingGC();
|
||||
|
||||
/**
|
||||
* This is used to keep track of compartments which should be prepared for a GC.
|
||||
* This is used to keep track of realms which should be prepared for a GC.
|
||||
*/
|
||||
void RegisterCompartment(JSCompartment* cmpt);
|
||||
void UnRegisterCompartment(JSCompartment* cmpt);
|
||||
void RegisterRealm(JS::Realm* realm);
|
||||
void UnRegisterRealm(JS::Realm* realm);
|
||||
|
||||
/**
|
||||
* GetGeneralJSContext returns the context without starting a GC request and without
|
||||
@@ -87,8 +87,8 @@ private:
|
||||
|
||||
JSContext* m_cx;
|
||||
|
||||
void PrepareCompartmentsForIncrementalGC() const;
|
||||
std::list<JSCompartment*> m_Compartments;
|
||||
void PrepareZonesForIncrementalGC() const;
|
||||
std::list<JS::Realm*> m_Realms;
|
||||
|
||||
int m_ContextSize;
|
||||
int m_HeapGrowthBytesGCTrigger;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "ScriptConversions.h"
|
||||
#include "ScriptExtraHeaders.h"
|
||||
|
||||
#include "graphics/Entity.h"
|
||||
#include "maths/Vector2D.h"
|
||||
@@ -28,7 +29,7 @@
|
||||
#define FAIL(msg) STMT(LOGERROR(msg); return false)
|
||||
|
||||
// Implicit type conversions often hide bugs, so warn about them
|
||||
#define WARN_IF_NOT(c, v) STMT(if (!(c)) { JS_ReportWarningUTF8(rq.cx, "Script value conversion check failed: %s (got type %s)", #c, JS::InformalValueTypeName(v)); })
|
||||
#define WARN_IF_NOT(c, v) STMT(if (!(c)) { JS::WarnUTF8(rq.cx, "Script value conversion check failed: %s (got type %s)", #c, JS::InformalValueTypeName(v)); })
|
||||
|
||||
template<> bool ScriptInterface::FromJSVal<bool>(const ScriptRequest& rq, JS::HandleValue v, bool& out)
|
||||
{
|
||||
|
||||
@@ -46,10 +46,20 @@
|
||||
#endif
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
#include "js/ArrayBuffer.h"
|
||||
#include "js/Conversions.h"
|
||||
#include "js/ContextOptions.h"
|
||||
#include "js/ForOfIterator.h"
|
||||
#include "js/GCAPI.h"
|
||||
#include "js/JSON.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "js/Proxy.h"
|
||||
#include "js/Warnings.h"
|
||||
|
||||
// CompileFunction & Evaluate
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/SourceText.h"
|
||||
|
||||
#undef signbit
|
||||
|
||||
|
||||
@@ -18,9 +18,36 @@
|
||||
#ifndef INCLUDED_SCRIPTFORWARD
|
||||
#define INCLUDED_SCRIPTFORWARD
|
||||
|
||||
|
||||
// Ignore some harmless warnings
|
||||
#if GCC_VERSION
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
#endif
|
||||
#if CLANG_VERSION
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wunused-parameter"
|
||||
#endif
|
||||
#if MSC_VERSION
|
||||
# pragma warning(push, 1)
|
||||
# pragma warning(disable: 4100)
|
||||
#endif
|
||||
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
class ScriptInterface;
|
||||
class ScriptRequest;
|
||||
|
||||
#if GCC_VERSION
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
#if CLANG_VERSION
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
#if MSC_VERSION
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
#endif // INCLUDED_SCRIPTFORWARD
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "ScriptContext.h"
|
||||
#include "ScriptExtraHeaders.h"
|
||||
#include "ScriptInterface.h"
|
||||
#include "ScriptStats.h"
|
||||
|
||||
@@ -42,8 +43,6 @@
|
||||
|
||||
#include "valgrind.h"
|
||||
|
||||
#include "scriptinterface/ScriptExtraHeaders.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Abstractions of various SpiderMonkey features.
|
||||
@@ -75,8 +74,7 @@ struct ScriptInterface_impl
|
||||
ScriptRequest::ScriptRequest(const ScriptInterface& scriptInterface) :
|
||||
cx(scriptInterface.m->m_cx)
|
||||
{
|
||||
JS_BeginRequest(cx);
|
||||
m_formerCompartment = JS_EnterCompartment(cx, scriptInterface.m->m_glob);
|
||||
m_formerRealm = JS::EnterRealm(cx, scriptInterface.m->m_glob);
|
||||
glob = JS::CurrentGlobalOrNull(cx);
|
||||
}
|
||||
|
||||
@@ -87,8 +85,7 @@ JS::Value ScriptRequest::globalValue() const
|
||||
|
||||
ScriptRequest::~ScriptRequest()
|
||||
{
|
||||
JS_LeaveCompartment(cx, m_formerCompartment);
|
||||
JS_EndRequest(cx);
|
||||
JS::LeaveRealm(cx, m_formerRealm);
|
||||
}
|
||||
|
||||
namespace
|
||||
@@ -324,17 +321,16 @@ bool ScriptInterface::MathRandom(double& nbr)
|
||||
ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptContext>& context) :
|
||||
m_context(context), m_cx(context->GetGeneralJSContext()), m_glob(context->GetGeneralJSContext()), m_nativeScope(context->GetGeneralJSContext())
|
||||
{
|
||||
JS::CompartmentCreationOptions creationOpt;
|
||||
JS::RealmCreationOptions creationOpt;
|
||||
// Keep JIT code during non-shrinking GCs. This brings a quite big performance improvement.
|
||||
creationOpt.setPreserveJitCode(true);
|
||||
JS::CompartmentOptions opt(creationOpt, JS::CompartmentBehaviors{});
|
||||
JS::RealmOptions opt(creationOpt, JS::RealmBehaviors{});
|
||||
|
||||
JSAutoRequest rq(m_cx);
|
||||
m_glob = JS_NewGlobalObject(m_cx, &global_class, nullptr, JS::OnNewGlobalHookOption::FireOnNewGlobalHook, opt);
|
||||
|
||||
JSAutoCompartment autoCmpt(m_cx, m_glob);
|
||||
JSAutoRealm autoRealm(m_cx, m_glob);
|
||||
|
||||
ENSURE(JS_InitStandardClasses(m_cx, m_glob));
|
||||
ENSURE(JS::InitRealmStandardClasses(m_cx));
|
||||
|
||||
JS_DefineProperty(m_cx, m_glob, "global", m_glob, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
|
||||
|
||||
@@ -351,18 +347,17 @@ ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const sh
|
||||
Register("ProfileStop", ::ProfileStop, 0);
|
||||
Register("ProfileAttribute", ::ProfileAttribute, 1);
|
||||
|
||||
m_context->RegisterCompartment(js::GetObjectCompartment(m_glob));
|
||||
m_context->RegisterRealm(JS::GetObjectRealmOrNull(m_glob));
|
||||
}
|
||||
|
||||
ScriptInterface_impl::~ScriptInterface_impl()
|
||||
{
|
||||
m_context->UnRegisterCompartment(js::GetObjectCompartment(m_glob));
|
||||
m_context->UnRegisterRealm(JS::GetObjectRealmOrNull(m_glob));
|
||||
}
|
||||
|
||||
void ScriptInterface_impl::Register(const char* name, JSNative fptr, uint nargs) const
|
||||
{
|
||||
JSAutoRequest rq(m_cx);
|
||||
JSAutoCompartment autoCmpt(m_cx, m_glob);
|
||||
JSAutoRealm autoRealm(m_cx, m_glob);
|
||||
JS::RootedObject nativeScope(m_cx, m_nativeScope);
|
||||
JS::RootedFunction func(m_cx, JS_DefineFunction(m_cx, nativeScope, name, fptr, nargs, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT));
|
||||
}
|
||||
@@ -718,7 +713,7 @@ bool ScriptInterface::EnumeratePropertyNames(JS::HandleValue objVal, bool enumer
|
||||
}
|
||||
|
||||
JS::RootedObject obj(rq.cx, &objVal.toObject());
|
||||
JS::AutoIdVector props(rq.cx);
|
||||
JS::RootedIdVector props(rq.cx);
|
||||
// This recurses up the prototype chain on its own.
|
||||
if (!js::GetPropertyKeys(rq.cx, obj, enumerableOnly? 0 : JSITER_HIDDEN, &props))
|
||||
return false;
|
||||
@@ -774,20 +769,20 @@ bool ScriptInterface::LoadScript(const VfsPath& filename, const std::string& cod
|
||||
{
|
||||
ScriptRequest rq(this);
|
||||
JS::RootedObject global(rq.cx, rq.glob);
|
||||
utf16string codeUtf16(code.begin(), code.end());
|
||||
uint lineNo = 1;
|
||||
|
||||
// CompileOptions does not copy the contents of the filename string pointer.
|
||||
// Passing a temporary string there will cause undefined behaviour, so we create a separate string to avoid the temporary.
|
||||
std::string filenameStr = filename.string8();
|
||||
|
||||
JS::CompileOptions options(rq.cx);
|
||||
options.setFileAndLine(filenameStr.c_str(), lineNo);
|
||||
options.setFileAndLine(filenameStr.c_str(), 1);
|
||||
options.setIsRunOnce(false);
|
||||
|
||||
JS::RootedFunction func(rq.cx);
|
||||
JS::AutoObjectVector emptyScopeChain(rq.cx);
|
||||
if (!JS::CompileFunction(rq.cx, emptyScopeChain, options, NULL, 0, NULL,
|
||||
reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)(codeUtf16.length()), &func))
|
||||
JS::SourceText<mozilla::Utf8Unit> src;
|
||||
ENSURE(src.init(rq.cx, code.c_str(), code.length(), JS::SourceOwnership::Borrowed));
|
||||
JS::RootedObjectVector emptyScopeChain(rq.cx);
|
||||
JS::RootedFunction func(rq.cx, JS::CompileFunction(rq.cx, emptyScopeChain, options, NULL, 0, NULL, src));
|
||||
if (func == nullptr)
|
||||
{
|
||||
ScriptException::CatchPending(rq);
|
||||
return false;
|
||||
@@ -801,19 +796,20 @@ bool ScriptInterface::LoadScript(const VfsPath& filename, const std::string& cod
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScriptInterface::LoadGlobalScript(const VfsPath& filename, const std::wstring& code) const
|
||||
bool ScriptInterface::LoadGlobalScript(const VfsPath& filename, const std::string& code) const
|
||||
{
|
||||
ScriptRequest rq(this);
|
||||
utf16string codeUtf16(code.begin(), code.end());
|
||||
uint lineNo = 1;
|
||||
// CompileOptions does not copy the contents of the filename string pointer.
|
||||
// Passing a temporary string there will cause undefined behaviour, so we create a separate string to avoid the temporary.
|
||||
std::string filenameStr = filename.string8();
|
||||
|
||||
JS::RootedValue rval(rq.cx);
|
||||
JS::CompileOptions opts(rq.cx);
|
||||
opts.setFileAndLine(filenameStr.c_str(), lineNo);
|
||||
if (JS::Evaluate(rq.cx, opts, reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)(codeUtf16.length()), &rval))
|
||||
opts.setFileAndLine(filenameStr.c_str(), 1);
|
||||
|
||||
JS::SourceText<mozilla::Utf8Unit> src;
|
||||
ENSURE(src.init(rq.cx, code.c_str(), code.length(), JS::SourceOwnership::Borrowed));
|
||||
if (JS::Evaluate(rq.cx, opts, src, &rval))
|
||||
return true;
|
||||
|
||||
ScriptException::CatchPending(rq);
|
||||
@@ -839,9 +835,8 @@ bool ScriptInterface::LoadGlobalScriptFile(const VfsPath& path) const
|
||||
return false;
|
||||
}
|
||||
|
||||
std::wstring code = wstring_from_utf8(file.DecodeUTF8()); // assume it's UTF-8
|
||||
CStr code = file.DecodeUTF8(); // assume it's UTF-8
|
||||
|
||||
utf16string codeUtf16(code.begin(), code.end());
|
||||
uint lineNo = 1;
|
||||
// CompileOptions does not copy the contents of the filename string pointer.
|
||||
// Passing a temporary string there will cause undefined behaviour, so we create a separate string to avoid the temporary.
|
||||
@@ -850,7 +845,9 @@ bool ScriptInterface::LoadGlobalScriptFile(const VfsPath& path) const
|
||||
JS::RootedValue rval(rq.cx);
|
||||
JS::CompileOptions opts(rq.cx);
|
||||
opts.setFileAndLine(filenameStr.c_str(), lineNo);
|
||||
if (JS::Evaluate(rq.cx, opts, reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)(codeUtf16.length()), &rval))
|
||||
JS::SourceText<mozilla::Utf8Unit> src;
|
||||
ENSURE(src.init(rq.cx, code.c_str(), code.length(), JS::SourceOwnership::Borrowed));
|
||||
if (JS::Evaluate(rq.cx, opts, src, &rval))
|
||||
return true;
|
||||
|
||||
ScriptException::CatchPending(rq);
|
||||
@@ -861,31 +858,27 @@ bool ScriptInterface::Eval(const char* code) const
|
||||
{
|
||||
ScriptRequest rq(this);
|
||||
JS::RootedValue rval(rq.cx);
|
||||
return Eval_(code, &rval);
|
||||
}
|
||||
|
||||
bool ScriptInterface::Eval_(const char* code, JS::MutableHandleValue rval) const
|
||||
{
|
||||
ScriptRequest rq(this);
|
||||
utf16string codeUtf16(code, code+strlen(code));
|
||||
|
||||
JS::CompileOptions opts(rq.cx);
|
||||
opts.setFileAndLine("(eval)", 1);
|
||||
if (JS::Evaluate(rq.cx, opts, reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)codeUtf16.length(), rval))
|
||||
JS::SourceText<mozilla::Utf8Unit> src;
|
||||
ENSURE(src.init(rq.cx, code, strlen(code), JS::SourceOwnership::Borrowed));
|
||||
if (JS::Evaluate(rq.cx, opts, src, &rval))
|
||||
return true;
|
||||
|
||||
ScriptException::CatchPending(rq);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScriptInterface::Eval_(const wchar_t* code, JS::MutableHandleValue rval) const
|
||||
bool ScriptInterface::Eval(const char* code, JS::MutableHandleValue rval) const
|
||||
{
|
||||
ScriptRequest rq(this);
|
||||
utf16string codeUtf16(code, code+wcslen(code));
|
||||
|
||||
JS::CompileOptions opts(rq.cx);
|
||||
opts.setFileAndLine("(eval)", 1);
|
||||
if (JS::Evaluate(rq.cx, opts, reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)codeUtf16.length(), rval))
|
||||
JS::SourceText<mozilla::Utf8Unit> src;
|
||||
ENSURE(src.init(rq.cx, code, strlen(code), JS::SourceOwnership::Borrowed));
|
||||
if (JS::Evaluate(rq.cx, opts, src, rval))
|
||||
return true;
|
||||
|
||||
ScriptException::CatchPending(rq);
|
||||
|
||||
@@ -49,6 +49,8 @@ ERROR_TYPE(Scripting_DefineType, CreationFailed);
|
||||
// but as large as necessary for all wrapped functions)
|
||||
#define SCRIPT_INTERFACE_MAX_ARGS 8
|
||||
|
||||
class JSStructuredCloneData;
|
||||
|
||||
class ScriptInterface;
|
||||
struct ScriptInterface_impl;
|
||||
|
||||
@@ -61,7 +63,7 @@ extern thread_local shared_ptr<ScriptContext> g_ScriptContext;
|
||||
* RAII structure which encapsulates an access to the context and compartment of a ScriptInterface.
|
||||
* This struct provides:
|
||||
* - a pointer to the context, while acting like JSAutoRequest
|
||||
* - a pointer to the global object of the compartment, while acting like JSAutoCompartment
|
||||
* - a pointer to the global object of the compartment, while acting like JSAutoRealm
|
||||
*
|
||||
* This way, getting and using those pointers is safe with respect to the GC
|
||||
* and to the separation of compartments.
|
||||
@@ -81,11 +83,11 @@ public:
|
||||
JSContext* cx;
|
||||
JSObject* glob;
|
||||
private:
|
||||
JSCompartment* m_formerCompartment;
|
||||
JS::Realm* m_formerRealm;
|
||||
};
|
||||
|
||||
/**
|
||||
* Abstraction around a SpiderMonkey JSCompartment.
|
||||
* Abstraction around a SpiderMonkey JS::Realm.
|
||||
*
|
||||
* Thread-safety:
|
||||
* - May be used in non-main threads.
|
||||
@@ -244,11 +246,6 @@ public:
|
||||
|
||||
bool FreezeObject(JS::HandleValue objVal, bool deep) const;
|
||||
|
||||
bool Eval(const char* code) const;
|
||||
|
||||
template<typename CHAR> bool Eval(const CHAR* code, JS::MutableHandleValue out) const;
|
||||
template<typename T, typename CHAR> bool Eval(const CHAR* code, T& out) const;
|
||||
|
||||
/**
|
||||
* Convert an object to a UTF-8 encoded string, either with JSON
|
||||
* (if pretty == true and there is no JSON error) or with toSource().
|
||||
@@ -288,7 +285,7 @@ public:
|
||||
* @param code JS code to execute
|
||||
* @return true on successful compilation and execution; false otherwise
|
||||
*/
|
||||
bool LoadGlobalScript(const VfsPath& filename, const std::wstring& code) const;
|
||||
bool LoadGlobalScript(const VfsPath& filename, const std::string& code) const;
|
||||
|
||||
/**
|
||||
* Load and execute the given script in the global scope.
|
||||
@@ -296,6 +293,14 @@ public:
|
||||
*/
|
||||
bool LoadGlobalScriptFile(const VfsPath& path) const;
|
||||
|
||||
/**
|
||||
* Evaluate some JS code in the global scope.
|
||||
* @return true on successful compilation and execution; false otherwise
|
||||
*/
|
||||
bool Eval(const char* code) const;
|
||||
bool Eval(const char* code, JS::MutableHandleValue out) const;
|
||||
template<typename T> bool Eval(const char* code, T& out) const;
|
||||
|
||||
/**
|
||||
* Convert a JS::Value to a C++ type. (This might trigger GC.)
|
||||
*/
|
||||
@@ -425,8 +430,6 @@ private:
|
||||
}
|
||||
|
||||
bool CallFunction_(JS::HandleValue val, const char* name, JS::HandleValueArray argv, JS::MutableHandleValue ret) const;
|
||||
bool Eval_(const char* code, JS::MutableHandleValue ret) const;
|
||||
bool Eval_(const wchar_t* code, JS::MutableHandleValue ret) const;
|
||||
bool SetGlobal_(const char* name, JS::HandleValue value, bool replace, bool constant, bool enumerate);
|
||||
bool SetProperty_(JS::HandleValue obj, const char* name, JS::HandleValue value, bool constant, bool enumerate) const;
|
||||
bool SetProperty_(JS::HandleValue obj, const wchar_t* name, JS::HandleValue value, bool constant, bool enumerate) const;
|
||||
@@ -592,20 +595,13 @@ bool ScriptInterface::GetPropertyInt(JS::HandleValue obj, int name, T& out) cons
|
||||
return FromJSVal(rq, val, out);
|
||||
}
|
||||
|
||||
template<typename CHAR>
|
||||
bool ScriptInterface::Eval(const CHAR* code, JS::MutableHandleValue ret) const
|
||||
{
|
||||
if (!Eval_(code, ret))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T, typename CHAR>
|
||||
bool ScriptInterface::Eval(const CHAR* code, T& ret) const
|
||||
template<typename T>
|
||||
bool ScriptInterface::Eval(const char* code, T& ret) const
|
||||
{
|
||||
ScriptRequest rq(this);
|
||||
JS::RootedValue rval(rq.cx);
|
||||
if (!Eval_(code, &rval))
|
||||
if (!Eval(code, &rval))
|
||||
return false;
|
||||
return FromJSVal(rq, rval, ret);
|
||||
}
|
||||
|
||||
@@ -243,10 +243,10 @@ public:
|
||||
TS_ASSERT(script.Eval(input.c_str(), &val));
|
||||
|
||||
std::string stringified = script.StringifyJSON(&val);
|
||||
TS_ASSERT_STR_EQUALS(stringified, "{\n \"x\": 1,\n \"z\": [\n 2,\n \"3\xE2\x98\xBA\xEF\xBF\xBD\"\n ],\n \"y\": true\n}");
|
||||
TS_ASSERT_STR_EQUALS(stringified, "{\n \"x\": 1,\n \"z\": [\n 2,\n \"3\u263A\\ud800\"\n ],\n \"y\": true\n}");
|
||||
|
||||
TS_ASSERT(script.ParseJSON(stringified, &val));
|
||||
TS_ASSERT_STR_EQUALS(script.ToString(&val), "({x:1, z:[2, \"3\\u263A\\uFFFD\"], y:true})");
|
||||
TS_ASSERT_STR_EQUALS(script.ToString(&val), "({x:1, z:[2, \"3\\u263A\\uD800\"], y:true})");
|
||||
}
|
||||
|
||||
// This function tests a common way to mod functions, by crating a wrapper that
|
||||
|
||||
Reference in New Issue
Block a user