Index: source/gui/CGUI.cpp =================================================================== --- source/gui/CGUI.cpp +++ source/gui/CGUI.cpp @@ -441,7 +441,7 @@ return; } - if (!function.isObject() || !JS_ObjectIsFunction(rq.cx, &function.toObject())) + if (!function.isObject() || !JS_ObjectIsFunction(&function.toObject())) { ScriptException::Raise(rq, "Cannot assign non-function value to global hotkey '%s'", hotkeyTag.c_str()); return; @@ -923,7 +923,7 @@ CStr code(Element.GetText()); if (!code.empty()) - m_ScriptInterface->LoadGlobalScript(L"Some XML file", code.FromUTF8()); + m_ScriptInterface->LoadGlobalScript(L"Some XML file", code); } void CGUI::Xeromyces_ReadSprite(XMBElement Element, CXeromyces* pFile) Index: source/gui/GUIManager.cpp =================================================================== --- source/gui/GUIManager.cpp +++ source/gui/GUIManager.cpp @@ -226,7 +226,7 @@ ScriptRequest rq(scriptInterface); - if (!JS_ObjectIsFunction(rq.cx, &callbackFunc.toObject())) + if (!JS_ObjectIsFunction(&callbackFunc.toObject())) { LOGERROR("Given callback handler is not a function!"); return; @@ -254,7 +254,7 @@ if (args) scriptInterface->ReadStructuredClone(args, &argVal); - JS::AutoValueVector paramData(rq.cx); + JS::RootedValueVector paramData(rq.cx); DISCARD paramData.append(argVal); JS::RootedValue result(rq.cx); Index: source/gui/ObjectBases/IGUIObject.cpp =================================================================== --- source/gui/ObjectBases/IGUIObject.cpp +++ source/gui/ObjectBases/IGUIObject.cpp @@ -27,6 +27,7 @@ #include "ps/GameSetup/Config.h" #include "ps/Profile.h" #include "scriptinterface/ScriptContext.h" +#include "scriptinterface/ScriptExtraHeaders.h" #include "scriptinterface/ScriptInterface.h" #include "soundmanager/ISoundManager.h" @@ -320,13 +321,16 @@ char buf[64]; sprintf_s(buf, ARRAY_SIZE(buf), "__eventhandler%d (%s)", x++, eventName.c_str()); + // TODO: this is essentially the same code as ScriptInterface::LoadScript (with a tweak for the argument). JS::CompileOptions options(rq.cx); options.setFileAndLine(CodeName.c_str(), 0); options.setIsRunOnce(false); - JS::RootedFunction func(rq.cx); - JS::AutoObjectVector emptyScopeChain(rq.cx); - if (!JS::CompileFunction(rq.cx, emptyScopeChain, options, buf, paramCount, paramNames, Code.c_str(), Code.length(), &func)) + JS::SourceText 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, buf, paramCount, paramNames, src)); + if (func == nullptr) { LOGERROR("RegisterScriptHandler: Failed to compile the script for %s", eventName.c_str()); return; @@ -408,7 +412,7 @@ "x", mousePos.x, "y", mousePos.y, "buttons", m_pGUI.GetMouseButtons()); - JS::AutoValueVector paramData(rq.cx); + JS::RootedValueVector paramData(rq.cx); DISCARD paramData.append(mouse); ScriptEvent(eventName, paramData); @@ -426,7 +430,7 @@ return false; ScriptRequest rq(m_pGUI.GetScriptInterface()); - JS::AutoValueVector paramData(rq.cx); + JS::RootedValueVector paramData(rq.cx); return ScriptEventWithReturn(eventName, paramData); } Index: source/gui/ObjectTypes/CMiniMap.cpp =================================================================== --- source/gui/ObjectTypes/CMiniMap.cpp +++ source/gui/ObjectTypes/CMiniMap.cpp @@ -250,7 +250,7 @@ JS::RootedValue buttonJs(rq.cx); ScriptInterface::ToJSVal(rq, &buttonJs, button); - JS::AutoValueVector paramData(rq.cx); + JS::RootedValueVector paramData(rq.cx); DISCARD paramData.append(coords); DISCARD paramData.append(buttonJs); Index: source/gui/Scripting/JSInterface_GUIProxy.h =================================================================== --- source/gui/Scripting/JSInterface_GUIProxy.h +++ source/gui/Scripting/JSInterface_GUIProxy.h @@ -92,14 +92,14 @@ return false; } // Return nothing. - virtual bool ownPropertyKeys(JSContext* UNUSED(cx), JS::HandleObject UNUSED(proxy), JS::AutoIdVector& UNUSED(props)) const override + virtual bool ownPropertyKeys(JSContext* UNUSED(cx), JS::HandleObject UNUSED(proxy), JS::MutableHandleIdVector UNUSED(props)) const override { return true; } // Return nothing. - virtual JSObject* enumerate(JSContext* UNUSED(cx), JS::HandleObject UNUSED(proxy)) const override + virtual bool enumerate(JSContext* UNUSED(cx), JS::HandleObject UNUSED(proxy), JS::MutableHandleIdVector UNUSED(props)) const override { - return nullptr; + return true; } // Throw an exception is JS attempts to query the prototype. virtual bool getPrototypeIfOrdinary(JSContext* UNUSED(cx), JS::HandleObject UNUSED(proxy), bool* UNUSED(isOrdinary), JS::MutableHandleObject UNUSED(protop)) const override Index: source/gui/Scripting/JSInterface_GUIProxy_impl.h =================================================================== --- source/gui/Scripting/JSInterface_GUIProxy_impl.h +++ source/gui/Scripting/JSInterface_GUIProxy_impl.h @@ -151,7 +151,7 @@ // Use onWhatever to set event handlers if (propName.substr(0, 2) == "on") { - if (vp.isPrimitive() || vp.isNull() || !JS_ObjectIsFunction(rq.cx, &vp.toObject())) + if (vp.isPrimitive() || vp.isNull() || !JS_ObjectIsFunction(&vp.toObject())) { LOGERROR("on- event-handlers must be functions"); return result.fail(JSMSG_NOT_FUNCTION); Index: source/lobby/XmppClient.cpp =================================================================== --- source/lobby/XmppClient.cpp +++ source/lobby/XmppClient.cpp @@ -32,6 +32,7 @@ #include "ps/CLogger.h" #include "ps/ConfigDB.h" #include "ps/Pyrogenesis.h" +#include "scriptinterface/ScriptExtraHeaders.h" // StructuredClone #include "scriptinterface/ScriptInterface.h" #include Index: source/ps/CConsole.cpp =================================================================== --- source/ps/CConsole.cpp +++ source/ps/CConsole.cpp @@ -558,7 +558,7 @@ ScriptRequest rq(*pScriptInterface); JS::RootedValue rval(rq.cx); - pScriptInterface->Eval(szLine, &rval); + pScriptInterface->Eval(CStrW(szLine).ToUTF8().c_str(), &rval); if (!rval.isUndefined()) InsertMessage(pScriptInterface->ToString(&rval)); } Index: source/ps/GameSetup/GameSetup.cpp =================================================================== --- source/ps/GameSetup/GameSetup.cpp +++ source/ps/GameSetup/GameSetup.cpp @@ -186,7 +186,7 @@ const ScriptInterface& scriptInterface = *(g_GUI->GetActiveGUI()->GetScriptInterface()); ScriptRequest rq(scriptInterface); - JS::AutoValueVector paramData(rq.cx); + JS::RootedValueVector paramData(rq.cx); DISCARD paramData.append(JS::NumberValue(percent)); Index: source/scriptinterface/NativeWrapperDefns.h =================================================================== --- source/scriptinterface/NativeWrapperDefns.h +++ source/scriptinterface/NativeWrapperDefns.h @@ -161,14 +161,14 @@ #undef OVERLOADS template -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(rq, argv, params...); } template -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 @@ { 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 @@ { ScriptRequest rq(this); JS::MutableHandle 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 @@ bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, JS::MutableHandle 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 @@ { 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); } Index: source/scriptinterface/ScriptContext.h =================================================================== --- source/scriptinterface/ScriptContext.h +++ source/scriptinterface/ScriptContext.h @@ -69,10 +69,10 @@ 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 @@ JSContext* m_cx; - void PrepareCompartmentsForIncrementalGC() const; - std::list m_Compartments; + void PrepareZonesForIncrementalGC() const; + std::list m_Realms; int m_ContextSize; int m_HeapGrowthBytesGCTrigger; Index: source/scriptinterface/ScriptContext.cpp =================================================================== --- source/scriptinterface/ScriptContext.cpp +++ source/scriptinterface/ScriptContext.cpp @@ -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 @@ 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 @@ #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 @@ 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 @@ { 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)); } Index: source/scriptinterface/ScriptConversions.cpp =================================================================== --- source/scriptinterface/ScriptConversions.cpp +++ source/scriptinterface/ScriptConversions.cpp @@ -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(const ScriptRequest& rq, JS::HandleValue v, bool& out) { Index: source/scriptinterface/ScriptExtraHeaders.h =================================================================== --- source/scriptinterface/ScriptExtraHeaders.h +++ source/scriptinterface/ScriptExtraHeaders.h @@ -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 Index: source/scriptinterface/ScriptForward.h =================================================================== --- source/scriptinterface/ScriptForward.h +++ source/scriptinterface/ScriptForward.h @@ -18,9 +18,29 @@ #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 + + #include "js/TypeDecls.h" class ScriptInterface; class ScriptRequest; +#if GCC_VERSION +# pragma GCC diagnostic pop +#endif +#if CLANG_VERSION +# pragma clang diagnostic pop +#endif + + #endif // INCLUDED_SCRIPTFORWARD Index: source/scriptinterface/ScriptInterface.h =================================================================== --- source/scriptinterface/ScriptInterface.h +++ source/scriptinterface/ScriptInterface.h @@ -49,6 +49,8 @@ // 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 @@ * 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 @@ JSContext* cx; JSObject* glob; private: - JSCompartment* m_formerCompartment; + JS::Realm* m_formerRealm; }; /** - * Abstraction around a SpiderMonkey JSCompartment. + * Abstraction around a SpiderMonkey JS::Compartment. * * Thread-safety: * - May be used in non-main threads. @@ -244,11 +246,6 @@ bool FreezeObject(JS::HandleValue objVal, bool deep) const; - bool Eval(const char* code) const; - - template bool Eval(const CHAR* code, JS::MutableHandleValue out) const; - template 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 @@ * @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 @@ */ 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 bool Eval(const char* code, T& out) const; + /** * Convert a JS::Value to a C++ type. (This might trigger GC.) */ @@ -425,8 +430,6 @@ } 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 @@ return FromJSVal(rq, val, out); } -template -bool ScriptInterface::Eval(const CHAR* code, JS::MutableHandleValue ret) const -{ - if (!Eval_(code, ret)) - return false; - return true; -} -template -bool ScriptInterface::Eval(const CHAR* code, T& ret) const +template +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); } Index: source/scriptinterface/ScriptInterface.cpp =================================================================== --- source/scriptinterface/ScriptInterface.cpp +++ source/scriptinterface/ScriptInterface.cpp @@ -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 @@ 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 @@ ScriptRequest::~ScriptRequest() { - JS_LeaveCompartment(cx, m_formerCompartment); - JS_EndRequest(cx); + JS::LeaveRealm(cx, m_formerRealm); } namespace @@ -324,17 +321,16 @@ ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const shared_ptr& 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 @@ 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 @@ } 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 @@ { 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(codeUtf16.c_str()), (uint)(codeUtf16.length()), &func)) + JS::SourceText 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 @@ 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(codeUtf16.c_str()), (uint)(codeUtf16.length()), &rval)) + opts.setFileAndLine(filenameStr.c_str(), 1); + + JS::SourceText 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 @@ 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 @@ JS::RootedValue rval(rq.cx); JS::CompileOptions opts(rq.cx); opts.setFileAndLine(filenameStr.c_str(), lineNo); - if (JS::Evaluate(rq.cx, opts, reinterpret_cast(codeUtf16.c_str()), (uint)(codeUtf16.length()), &rval)) + JS::SourceText 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 @@ { 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(codeUtf16.c_str()), (uint)codeUtf16.length(), rval)) + JS::SourceText 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(codeUtf16.c_str()), (uint)codeUtf16.length(), rval)) + JS::SourceText 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); Index: source/scriptinterface/tests/test_ScriptInterface.h =================================================================== --- source/scriptinterface/tests/test_ScriptInterface.h +++ source/scriptinterface/tests/test_ScriptInterface.h @@ -243,10 +243,10 @@ 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 Index: source/simulation2/components/CCmpAIManager.cpp =================================================================== --- source/simulation2/components/CCmpAIManager.cpp +++ source/simulation2/components/CCmpAIManager.cpp @@ -158,7 +158,7 @@ m_ScriptInterface->SetProperty(settings, "templates", m_Worker.m_EntityTemplates, false); } - JS::AutoValueVector argv(rq.cx); + JS::RootedValueVector argv(rq.cx); DISCARD argv.append(settings.get()); m_ScriptInterface->CallConstructor(ctor, argv, &m_Obj); @@ -457,7 +457,7 @@ "players", playersID, "templates", m_EntityTemplates); - JS::AutoValueVector argv(rq.cx); + JS::RootedValueVector argv(rq.cx); DISCARD argv.append(settings); m_ScriptInterface->CallConstructor(ctor, argv, &m_SharedAIObj); Index: source/simulation2/serialization/BinarySerializer.cpp =================================================================== --- source/simulation2/serialization/BinarySerializer.cpp +++ source/simulation2/serialization/BinarySerializer.cpp @@ -129,7 +129,7 @@ HandleScriptVal(bufferVal); break; } - else if (JS_IsArrayBufferObject(obj)) + else if (JS::IsArrayBufferObject(obj)) { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_ARRAY_BUFFER); @@ -137,11 +137,11 @@ #error TODO: need to convert JS ArrayBuffer data to little-endian #endif - u32 length = JS_GetArrayBufferByteLength(obj); + u32 length = JS::GetArrayBufferByteLength(obj); m_Serializer.NumberU32_Unbounded("buffer length", length); JS::AutoCheckCannotGC nogc; bool sharedMemory; - m_Serializer.RawBytes("buffer data", (const u8*)JS_GetArrayBufferData(obj, &sharedMemory, nogc), length); + m_Serializer.RawBytes("buffer data", (const u8*)JS::GetArrayBufferData(obj, &sharedMemory, nogc), length); break; } Index: source/simulation2/serialization/StdDeserializer.cpp =================================================================== --- source/simulation2/serialization/StdDeserializer.cpp +++ source/simulation2/serialization/StdDeserializer.cpp @@ -23,7 +23,7 @@ #include "StdSerializer.h" // for DEBUG_SERIALIZER_ANNOTATE #include "scriptinterface/ScriptInterface.h" -#include "scriptinterface/ScriptExtraHeaders.h" // for typed arrays +#include "scriptinterface/ScriptExtraHeaders.h" // For typed arrays and ArrayBuffer #include "lib/byte_order.h" @@ -284,7 +284,7 @@ throw PSERROR_Deserialize_ScriptError(); JS::RootedObject bufferObj(rq.cx, &bufferVal.toObject()); - if (!JS_IsArrayBufferObject(bufferObj)) + if (!JS::IsArrayBufferObject(bufferObj)) throw PSERROR_Deserialize_ScriptError("js_IsArrayBuffer failed"); switch(arrayType) @@ -335,7 +335,7 @@ void* contents = malloc(length); ENSURE(contents); RawBytes("buffer data", (u8*)contents, length); - JS::RootedObject bufferObj(rq.cx, JS_NewArrayBufferWithContents(rq.cx, length, contents)); + JS::RootedObject bufferObj(rq.cx, JS::NewArrayBufferWithContents(rq.cx, length, contents)); AddScriptBackref(bufferObj); return JS::ObjectValue(*bufferObj); Index: source/simulation2/system/ReplayTurnManager.cpp =================================================================== --- source/simulation2/system/ReplayTurnManager.cpp +++ source/simulation2/system/ReplayTurnManager.cpp @@ -89,7 +89,7 @@ const ScriptInterface& scriptInterface = m_Simulation2.GetScriptInterface(); ScriptRequest rq(scriptInterface); - JS::AutoValueVector paramData(rq.cx); + JS::RootedValueVector paramData(rq.cx); DISCARD paramData.append(JS::NumberValue(turn)); Index: source/simulation2/system/TurnManager.cpp =================================================================== --- source/simulation2/system/TurnManager.cpp +++ source/simulation2/system/TurnManager.cpp @@ -26,6 +26,7 @@ #include "ps/CLogger.h" #include "ps/Replay.h" #include "ps/Util.h" +#include "scriptinterface/ScriptExtraHeaders.h" // StructuredClone #include "scriptinterface/ScriptInterface.h" #include "simulation2/Simulation2.h" Index: source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp =================================================================== --- source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp +++ source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp @@ -916,7 +916,7 @@ wxString cmd = ::wxGetTextFromUser(_T(""), _("JS command"), _T(""), this); if (cmd.IsEmpty()) return; - POST_MESSAGE(JavaScript, ((std::wstring)cmd.wc_str())); + POST_MESSAGE(JavaScript, (std::string(cmd.ToUTF8()))); } void ScenarioEditor::OnCameraReset(wxCommandEvent& WXUNUSED(event)) Index: source/tools/atlas/GameInterface/Messages.h =================================================================== --- source/tools/atlas/GameInterface/Messages.h +++ source/tools/atlas/GameInterface/Messages.h @@ -77,7 +77,7 @@ ); MESSAGE(JavaScript, - ((std::wstring, command)) + ((std::string, command)) ); //////////////////////////////////////////////////////////////////////////