diff --git a/source/gui/GUIManager.cpp b/source/gui/GUIManager.cpp index 5cb796eadb..0365ca013f 100644 --- a/source/gui/GUIManager.cpp +++ b/source/gui/GUIManager.cpp @@ -172,11 +172,15 @@ void CGUIManager::LoadPage(SGUIPage& page) // If we're hotloading then try to grab some data from the previous page shared_ptr hotloadData; if (page.gui) - { - CScriptVal hotloadDataVal; - shared_ptr scriptInterface = page.gui->GetScriptInterface(); - scriptInterface->CallFunction(scriptInterface->GetGlobalObject(), "getHotloadData", hotloadDataVal); - hotloadData = scriptInterface->WriteStructuredClone(hotloadDataVal.get()); + { + shared_ptr scriptInterface = page.gui->GetScriptInterface(); + JSContext* cx = scriptInterface->GetContext(); + JSAutoRequest rq(cx); + + JS::RootedValue global(cx, scriptInterface->GetGlobalObject()); + JS::RootedValue hotloadDataVal(cx); + scriptInterface->CallFunction(global, "getHotloadData", &hotloadDataVal); + hotloadData = scriptInterface->WriteStructuredClone(hotloadDataVal); } page.inputs.clear(); @@ -228,16 +232,20 @@ void CGUIManager::LoadPage(SGUIPage& page) page.gui->SendEventToAll("load"); shared_ptr scriptInterface = page.gui->GetScriptInterface(); - CScriptVal initDataVal; - CScriptVal hotloadDataVal; + JSContext* cx = scriptInterface->GetContext(); + JSAutoRequest rq(cx); + + JS::RootedValue initDataVal(cx); + JS::RootedValue hotloadDataVal(cx); + JS::RootedValue global(cx, scriptInterface->GetGlobalObject()); if (page.initData) - initDataVal = scriptInterface->ReadStructuredClone(page.initData); + initDataVal.set(scriptInterface->ReadStructuredClone(page.initData)); if (hotloadData) - hotloadDataVal = scriptInterface->ReadStructuredClone(hotloadData); + hotloadDataVal.set(scriptInterface->ReadStructuredClone(hotloadData)); // Call the init() function if (!scriptInterface->CallFunctionVoid( - scriptInterface->GetGlobalObject(), + global, "init", initDataVal, hotloadDataVal) @@ -269,8 +277,9 @@ CScriptVal CGUIManager::GetSavedGameData(ScriptInterface*& pPageScriptInterface) JSContext* cx = top()->GetScriptInterface()->GetContext(); JSAutoRequest rq(cx); + JS::RootedValue global(cx, top()->GetGlobalObject()); JS::RootedValue data(cx); - if (!top()->GetScriptInterface()->CallFunction(top()->GetGlobalObject(), "getSavedGameData", &data)) + if (!top()->GetScriptInterface()->CallFunction(global, "getSavedGameData", &data)) LOGERROR(L"Failed to call getSavedGameData() on the current GUI page"); pPageScriptInterface = GetScriptInterface().get(); return CScriptVal(data); @@ -278,15 +287,24 @@ CScriptVal CGUIManager::GetSavedGameData(ScriptInterface*& pPageScriptInterface) std::string CGUIManager::GetSavedGameData() { - CScriptVal data; - top()->GetScriptInterface()->CallFunction(top()->GetGlobalObject(), "getSavedGameData", data); - return top()->GetScriptInterface()->StringifyJSON(data.get(), false); + shared_ptr scriptInterface = top()->GetScriptInterface(); + JSContext* cx = scriptInterface->GetContext(); + JSAutoRequest rq(cx); + + JS::RootedValue data(cx); + JS::RootedValue global(cx, top()->GetGlobalObject()); + scriptInterface->CallFunction(global, "getSavedGameData", &data); + return scriptInterface->StringifyJSON(data, false); } void CGUIManager::RestoreSavedGameData(std::string jsonData) { - top()->GetScriptInterface()->CallFunctionVoid(top()->GetGlobalObject(), "restoreSavedGameData", - top()->GetScriptInterface()->ParseJSON(jsonData)); + shared_ptr scriptInterface = top()->GetScriptInterface(); + JSContext* cx = scriptInterface->GetContext(); + JSAutoRequest rq(cx); + + JS::RootedValue global(cx, top()->GetGlobalObject()); + scriptInterface->CallFunctionVoid(global, "restoreSavedGameData", scriptInterface->ParseJSON(jsonData)); } InReaction CGUIManager::HandleEvent(const SDL_Event_* ev) @@ -297,12 +315,17 @@ InReaction CGUIManager::HandleEvent(const SDL_Event_* ev) // visible game area), sometimes they'll want to intercepts events before the GUI (e.g. // to capture all mouse events until a mouseup after dragging). // So we call two separate handler functions: + + shared_ptr scriptInterface = top()->GetScriptInterface(); + JSContext* cx = scriptInterface->GetContext(); + JSAutoRequest rq(cx); + JS::RootedValue global(cx, top()->GetGlobalObject()); bool handled; { PROFILE("handleInputBeforeGui"); - if (top()->GetScriptInterface()->CallFunction(top()->GetGlobalObject(), "handleInputBeforeGui", *ev, top()->FindObjectUnderMouse(), handled)) + if (scriptInterface->CallFunction(global, "handleInputBeforeGui", *ev, top()->FindObjectUnderMouse(), handled)) if (handled) return IN_HANDLED; } @@ -316,7 +339,8 @@ InReaction CGUIManager::HandleEvent(const SDL_Event_* ev) { PROFILE("handleInputAfterGui"); - if (top()->GetScriptInterface()->CallFunction(top()->GetGlobalObject(), "handleInputAfterGui", *ev, handled)) if (handled) + if (scriptInterface->CallFunction(global, "handleInputAfterGui", *ev, handled)) + if (handled) return IN_HANDLED; } diff --git a/source/network/NetMessageSim.cpp b/source/network/NetMessageSim.cpp index ef71c659a7..c21fdfffa6 100644 --- a/source/network/NetMessageSim.cpp +++ b/source/network/NetMessageSim.cpp @@ -124,13 +124,16 @@ u8* CSimulationMessage::Serialize(u8* pBuffer) const { // TODO: ought to handle serialization exceptions // TODO: ought to represent common commands more efficiently - + JSContext* cx = m_ScriptInterface->GetContext(); + JSAutoRequest rq(cx); + JS::RootedValue tmpData(cx, m_Data.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade + u8* pos = CNetMessage::Serialize(pBuffer); CBufferBinarySerializer serializer(*m_ScriptInterface, pos); serializer.NumberU32_Unbounded("client", m_Client); serializer.NumberI32_Unbounded("player", m_Player); serializer.NumberU32_Unbounded("turn", m_Turn); - serializer.ScriptVal("command", m_Data); + serializer.ScriptVal("command", tmpData); return serializer.GetBuffer(); } @@ -138,14 +141,18 @@ const u8* CSimulationMessage::Deserialize(const u8* pStart, const u8* pEnd) { // TODO: ought to handle serialization exceptions // TODO: ought to represent common commands more efficiently - + JSContext* cx = m_ScriptInterface->GetContext(); + JSAutoRequest rq(cx); + + JS::RootedValue tmpData(cx); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade const u8* pos = CNetMessage::Deserialize(pStart, pEnd); std::istringstream stream(std::string(pos, pEnd)); CStdDeserializer deserializer(*m_ScriptInterface, stream); deserializer.NumberU32_Unbounded("client", m_Client); deserializer.NumberI32_Unbounded("player", m_Player); deserializer.NumberU32_Unbounded("turn", m_Turn); - deserializer.ScriptVal("command", m_Data); + deserializer.ScriptVal("command", &tmpData); + m_Data = CScriptValRooted(cx, tmpData); return pEnd; } @@ -153,12 +160,15 @@ size_t CSimulationMessage::GetSerializedLength() const { // TODO: serializing twice is stupidly inefficient - we should just // do it once, store the result, and use it here and in Serialize - + JSContext* cx = m_ScriptInterface->GetContext(); + JSAutoRequest rq(cx); + JS::RootedValue tmpData(cx, m_Data.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade + CLengthBinarySerializer serializer(*m_ScriptInterface); serializer.NumberU32_Unbounded("client", m_Client); serializer.NumberI32_Unbounded("player", m_Player); serializer.NumberU32_Unbounded("turn", m_Turn); - serializer.ScriptVal("command", m_Data); + serializer.ScriptVal("command", tmpData); return CNetMessage::GetSerializedLength() + serializer.GetLength(); } @@ -186,28 +196,39 @@ CGameSetupMessage::CGameSetupMessage(ScriptInterface& scriptInterface, jsval dat u8* CGameSetupMessage::Serialize(u8* pBuffer) const { // TODO: ought to handle serialization exceptions - + JSContext* cx = m_ScriptInterface.GetContext(); + JSAutoRequest rq(cx); + JS::RootedValue tmpData(cx, m_Data.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade + u8* pos = CNetMessage::Serialize(pBuffer); CBufferBinarySerializer serializer(m_ScriptInterface, pos); - serializer.ScriptVal("command", m_Data); + serializer.ScriptVal("command", tmpData); return serializer.GetBuffer(); } const u8* CGameSetupMessage::Deserialize(const u8* pStart, const u8* pEnd) { // TODO: ought to handle serialization exceptions - + JSContext* cx = m_ScriptInterface.GetContext(); + JSAutoRequest rq(cx); + JS::RootedValue tmpData(cx); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade + const u8* pos = CNetMessage::Deserialize(pStart, pEnd); std::istringstream stream(std::string(pos, pEnd)); CStdDeserializer deserializer(m_ScriptInterface, stream); - deserializer.ScriptVal("command", m_Data); + deserializer.ScriptVal("command", &tmpData); + m_Data = CScriptValRooted(cx, tmpData); return pEnd; } size_t CGameSetupMessage::GetSerializedLength() const { + JSContext* cx = m_ScriptInterface.GetContext(); + JSAutoRequest rq(cx); + JS::RootedValue tmpData(cx, m_Data.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade + CLengthBinarySerializer serializer(m_ScriptInterface); - serializer.ScriptVal("command", m_Data); + serializer.ScriptVal("command", tmpData); return CNetMessage::GetSerializedLength() + serializer.GetLength(); } diff --git a/source/network/tests/test_NetMessage.h b/source/network/tests/test_NetMessage.h index 494eaa9fe8..5fdb7b47b7 100644 --- a/source/network/tests/test_NetMessage.h +++ b/source/network/tests/test_NetMessage.h @@ -27,9 +27,12 @@ public: void test_sim() { ScriptInterface script("Test", "Test", g_ScriptRuntime); - CScriptValRooted val; - script.Eval("[4]", val); - CSimulationMessage msg(script, 1, 2, 3, val.get()); + JSContext* cx = script.GetContext(); + JSAutoRequest rq(cx); + + JS::RootedValue val(cx); + script.Eval("[4]", &val); + CSimulationMessage msg(script, 1, 2, 3, val); TS_ASSERT_STR_EQUALS(msg.ToString(), "CSimulationMessage { m_Client: 1, m_Player: 2, m_Turn: 3, m_Data: [4] }"); size_t len = msg.GetSerializedLength(); diff --git a/source/ps/GameSetup/HWDetect.cpp b/source/ps/GameSetup/HWDetect.cpp index 4628125115..c2f5a3b35e 100644 --- a/source/ps/GameSetup/HWDetect.cpp +++ b/source/ps/GameSetup/HWDetect.cpp @@ -323,8 +323,8 @@ void RunHardwareDetection() g_UserReporter.SubmitReport("hwdetect", 11, scriptInterface.StringifyJSON(settings, false)); // Run the detection script: - - scriptInterface.CallFunctionVoid(scriptInterface.GetGlobalObject(), "RunHardwareDetection", settings); + JS::RootedValue global(cx, scriptInterface.GetGlobalObject()); + scriptInterface.CallFunctionVoid(global, "RunHardwareDetection", settings); } static void ReportGLLimits(ScriptInterface& scriptInterface, JS::HandleValue settings) diff --git a/source/scriptinterface/NativeWrapperDecls.h b/source/scriptinterface/NativeWrapperDecls.h index 047e5baf6d..64179e13c5 100644 --- a/source/scriptinterface/NativeWrapperDecls.h +++ b/source/scriptinterface/NativeWrapperDecls.h @@ -74,7 +74,7 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) // Call the named property on the given object #define OVERLOADS(z, i, data) \ template \ - bool CallFunction(jsval val, const char* name, T0_A0_CONST_REF(z,i) R& ret); + bool CallFunction(JS::HandleValue val, const char* name, T0_A0_CONST_REF(z,i) R& ret); BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #undef OVERLOADS @@ -83,7 +83,7 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) // (as people would expect it to work based on the SpiderMonkey rooting guide). #define OVERLOADS(z, i, data) \ template \ - bool CallFunction(jsval val, const char* name, T0_A0_CONST_REF(z,i) JS::Rooted* ret); + bool CallFunction(JS::HandleValue val, const char* name, T0_A0_CONST_REF(z,i) JS::Rooted* ret); BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #undef OVERLOADS @@ -91,7 +91,7 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) // without requiring implicit conversion. #define OVERLOADS(z, i, data) \ template \ - bool CallFunction(jsval val, const char* name, T0_A0_CONST_REF(z,i) JS::MutableHandle ret); + bool CallFunction(JS::HandleValue val, const char* name, T0_A0_CONST_REF(z,i) JS::MutableHandle ret); BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #undef OVERLOADS diff --git a/source/scriptinterface/NativeWrapperDefns.h b/source/scriptinterface/NativeWrapperDefns.h index b70338afee..6bbd84764f 100644 --- a/source/scriptinterface/NativeWrapperDefns.h +++ b/source/scriptinterface/NativeWrapperDefns.h @@ -129,16 +129,15 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #define OVERLOADS(z, i, data) \ template \ -bool ScriptInterface::CallFunction(jsval val, const char* name, T0_A0_CONST_REF(z,i) R& ret) \ +bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, T0_A0_CONST_REF(z,i) R& ret) \ { \ JSContext* cx = GetContext(); \ JSAutoRequest rq(cx); \ JS::RootedValue jsRet(cx); \ - JS::RootedValue val1(cx, val); \ JS::AutoValueVector argv(cx); \ argv.resize(i); \ BOOST_PP_REPEAT_##z (i, ASSIGN_OR_TO_JS_VAL, ~) \ - bool ok = CallFunction_(val1, name, argv.length(), argv.begin(), &jsRet); \ + bool ok = CallFunction_(val, name, argv.length(), argv.begin(), &jsRet); \ if (!ok) \ return false; \ return FromJSVal(cx, jsRet, ret); \ @@ -148,16 +147,15 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #define OVERLOADS(z, i, data) \ template \ -bool ScriptInterface::CallFunction(jsval val, const char* name, T0_A0_CONST_REF(z,i) JS::Rooted* ret) \ +bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, T0_A0_CONST_REF(z,i) JS::Rooted* ret) \ { \ JSContext* cx = GetContext(); \ JSAutoRequest rq(cx); \ JS::MutableHandle jsRet(ret); \ - JS::RootedValue val1(cx, val); \ JS::AutoValueVector argv(cx); \ argv.resize(i); \ BOOST_PP_REPEAT_##z (i, ASSIGN_OR_TO_JS_VAL, ~) \ - bool ok = CallFunction_(val1, name, argv.length(), argv.begin(), jsRet); \ + bool ok = CallFunction_(val, name, argv.length(), argv.begin(), jsRet); \ if (!ok) \ return false; \ return true; \ @@ -167,15 +165,14 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #define OVERLOADS(z, i, data) \ template \ -bool ScriptInterface::CallFunction(jsval val, const char* name, T0_A0_CONST_REF(z,i) JS::MutableHandle ret) \ +bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, T0_A0_CONST_REF(z,i) JS::MutableHandle ret) \ { \ JSContext* cx = GetContext(); \ JSAutoRequest rq(cx); \ - JS::RootedValue val1(cx, val); \ JS::AutoValueVector argv(cx); \ argv.resize(i); \ BOOST_PP_REPEAT_##z (i, ASSIGN_OR_TO_JS_VAL, ~) \ - bool ok = CallFunction_(val1, name, argv.length(), argv.begin(), ret); \ + bool ok = CallFunction_(val, name, argv.length(), argv.begin(), ret); \ if (!ok) \ return false; \ return true; \ diff --git a/source/scriptinterface/ScriptInterface.cpp b/source/scriptinterface/ScriptInterface.cpp index c51128f274..017ed10f59 100644 --- a/source/scriptinterface/ScriptInterface.cpp +++ b/source/scriptinterface/ScriptInterface.cpp @@ -964,12 +964,11 @@ JSObject* ScriptInterface::CreateCustomObject(const std::string & typeName) return JS_NewObject(m->m_cx, (*it).second.m_Class, prototype, NULL); } -bool ScriptInterface::CallFunctionVoid(jsval val, const char* name) +bool ScriptInterface::CallFunctionVoid(JS::HandleValue val, const char* name) { JSAutoRequest rq(m->m_cx); JS::RootedValue jsRet(m->m_cx); - JS::RootedValue val1(m->m_cx, val); - return CallFunction_(val1, name, 0, NULL, &jsRet); + return CallFunction_(val, name, 0, NULL, &jsRet); } bool ScriptInterface::CallFunction_(JS::HandleValue val, const char* name, uint argc, jsval* argv, JS::MutableHandleValue ret) @@ -1361,7 +1360,8 @@ std::string ScriptInterface::StringifyJSON(jsval obj, bool indent) std::wstring ScriptInterface::ToString(jsval obj, bool pretty) { JSAutoRequest rq(m->m_cx); - if (JSVAL_IS_VOID(obj)) + + if (obj.isUndefined()) return L"(void 0)"; // Try to stringify as JSON if possible @@ -1373,7 +1373,7 @@ std::wstring ScriptInterface::ToString(jsval obj, bool pretty) // Temporary disable the error reporter, so we don't print complaints about cyclic values JSErrorReporter er = JS_SetErrorReporter(m->m_cx, NULL); - JSBool ok = JS_Stringify(m->m_cx, &obj, NULL, INT_TO_JSVAL(2), &StringifierW::callback, &str); + JSBool ok = JS_Stringify(m->m_cx, &obj, NULL, JS::NumberValue(2), &StringifierW::callback, &str); // Restore error reporter JS_SetErrorReporter(m->m_cx, er); @@ -1389,7 +1389,8 @@ std::wstring ScriptInterface::ToString(jsval obj, bool pretty) // so fall back to obj.toSource() std::wstring source = L"(error)"; - CallFunction(obj, "toSource", source); + JS::RootedValue tmpObj(m->m_cx, obj); // TODO: pass Handle as argument already + CallFunction(tmpObj, "toSource", source); return source; } diff --git a/source/scriptinterface/ScriptInterface.h b/source/scriptinterface/ScriptInterface.h index 5c5ffea31e..19e2b57086 100644 --- a/source/scriptinterface/ScriptInterface.h +++ b/source/scriptinterface/ScriptInterface.h @@ -150,25 +150,25 @@ public: /** * Call the named property on the given object, with void return type and 0 arguments */ - bool CallFunctionVoid(jsval val, const char* name); + bool CallFunctionVoid(JS::HandleValue val, const char* name); /** * Call the named property on the given object, with void return type and 1 argument */ template - bool CallFunctionVoid(jsval val, const char* name, const T0& a0); + bool CallFunctionVoid(JS::HandleValue val, const char* name, const T0& a0); /** * Call the named property on the given object, with void return type and 2 arguments */ template - bool CallFunctionVoid(jsval val, const char* name, const T0& a0, const T1& a1); + bool CallFunctionVoid(JS::HandleValue val, const char* name, const T0& a0, const T1& a1); /** * Call the named property on the given object, with void return type and 3 arguments */ template - bool CallFunctionVoid(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2); + bool CallFunctionVoid(JS::HandleValue val, const char* name, const T0& a0, const T1& a1, const T2& a2); JSObject* CreateCustomObject(const std::string & typeName); void DefineCustomObjectType(JSClass *clasp, JSNative constructor, uint minArgs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs); @@ -480,45 +480,42 @@ inline void ScriptInterface::AssignOrToJSVal(JS::MutableHandleValue h } template -bool ScriptInterface::CallFunctionVoid(jsval val, const char* name, const T0& a0) +bool ScriptInterface::CallFunctionVoid(JS::HandleValue val, const char* name, const T0& a0) { JSContext* cx = GetContext(); JSAutoRequest rq(cx); JS::RootedValue jsRet(cx); - JS::RootedValue val1(cx, val); JS::AutoValueVector argv(cx); argv.resize(1); AssignOrToJSVal(argv.handleAt(0), a0); - return CallFunction_(val1, name, 1, argv.begin(), &jsRet); + return CallFunction_(val, name, 1, argv.begin(), &jsRet); } template -bool ScriptInterface::CallFunctionVoid(jsval val, const char* name, const T0& a0, const T1& a1) +bool ScriptInterface::CallFunctionVoid(JS::HandleValue val, const char* name, const T0& a0, const T1& a1) { JSContext* cx = GetContext(); JSAutoRequest rq(cx); JS::RootedValue jsRet(cx); - JS::RootedValue val1(cx, val); JS::AutoValueVector argv(cx); argv.resize(2); AssignOrToJSVal(argv.handleAt(0), a0); AssignOrToJSVal(argv.handleAt(1), a1); - return CallFunction_(val1, name, 2, argv.begin(), &jsRet); + return CallFunction_(val, name, 2, argv.begin(), &jsRet); } template -bool ScriptInterface::CallFunctionVoid(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2) +bool ScriptInterface::CallFunctionVoid(JS::HandleValue val, const char* name, const T0& a0, const T1& a1, const T2& a2) { JSContext* cx = GetContext(); JSAutoRequest rq(cx); JS::RootedValue jsRet(cx); - JS::RootedValue val1(cx, val); JS::AutoValueVector argv(cx); argv.resize(3); AssignOrToJSVal(argv.handleAt(0), a0); AssignOrToJSVal(argv.handleAt(1), a1); AssignOrToJSVal(argv.handleAt(2), a2); - return CallFunction_(val1, name, 3, argv.begin(), &jsRet); + return CallFunction_(val, name, 3, argv.begin(), &jsRet); } template diff --git a/source/scriptinterface/tests/test_ScriptConversions.h b/source/scriptinterface/tests/test_ScriptConversions.h index 643c6f4077..2bfdcb99fd 100644 --- a/source/scriptinterface/tests/test_ScriptConversions.h +++ b/source/scriptinterface/tests/test_ScriptConversions.h @@ -40,7 +40,8 @@ class TestScriptConversions : public CxxTest::TestSuite // We want to convert values to strings, but can't just call toSource() on them // since they might not be objects. So just use uneval. std::string source; - TS_ASSERT(script.CallFunction(JS::ObjectValue(*JS_GetGlobalForScopeChain(cx)), "uneval", CScriptVal(v1), source)); + JS::RootedValue global(cx, script.GetGlobalObject()); + TS_ASSERT(script.CallFunction(global, "uneval", v1, source)); TS_ASSERT_STR_EQUALS(source, expected); } @@ -56,7 +57,8 @@ class TestScriptConversions : public CxxTest::TestSuite ScriptInterface::ToJSVal(cx, &v1, value); std::string source; - TS_ASSERT(script.CallFunction(JS::ObjectValue(*JS_GetGlobalForScopeChain(cx)), "uneval", CScriptVal(v1), source)); + JS::RootedValue global(cx, script.GetGlobalObject()); + TS_ASSERT(script.CallFunction(global, "uneval", v1, source)); if (expected) TS_ASSERT_STR_EQUALS(source, expected); diff --git a/source/scriptinterface/tests/test_ScriptInterface.h b/source/scriptinterface/tests/test_ScriptInterface.h index 0ae54eec71..9ff367a5bd 100644 --- a/source/scriptinterface/tests/test_ScriptInterface.h +++ b/source/scriptinterface/tests/test_ScriptInterface.h @@ -65,14 +65,21 @@ public: ScriptInterface script1("Test", "Test", g_ScriptRuntime); ScriptInterface script2("Test", "Test", g_ScriptRuntime); - CScriptVal obj1; - TS_ASSERT(script1.Eval("({'x': 123, 'y': [1, 1.5, '2', 'test', undefined, null, true, false]})", obj1)); + JSContext* cx1 = script1.GetContext(); + JSAutoRequest rq1(cx1); + JS::RootedValue obj1(cx1); + TS_ASSERT(script1.Eval("({'x': 123, 'y': [1, 1.5, '2', 'test', undefined, null, true, false]})", &obj1)); - CScriptVal obj2 = script2.CloneValueFromOtherContext(script1, obj1.get()); + { + JSContext* cx2 = script2.GetContext(); + JSAutoRequest rq2(cx2); + + JS::RootedValue obj2(cx2, script2.CloneValueFromOtherContext(script1, obj1)); - std::string source; - TS_ASSERT(script2.CallFunction(obj2.get(), "toSource", source)); - TS_ASSERT_STR_EQUALS(source, "({x:123, y:[1, 1.5, \"2\", \"test\", (void 0), null, true, false]})"); + std::string source; + TS_ASSERT(script2.CallFunction(obj2, "toSource", source)); + TS_ASSERT_STR_EQUALS(source, "({x:123, y:[1, 1.5, \"2\", \"test\", (void 0), null, true, false]})"); + } } void test_clone_getters() @@ -81,14 +88,22 @@ public: ScriptInterface script1("Test", "Test", g_ScriptRuntime); ScriptInterface script2("Test", "Test", g_ScriptRuntime); - CScriptVal obj1; - TS_ASSERT(script1.Eval("var s = '?'; var v = ({get x() { return 123 }, 'y': {'w':{get z() { delete v.y; delete v.n; v = null; s += s; return 4 }}}, 'n': 100}); v", obj1)); + JSContext* cx1 = script1.GetContext(); + JSAutoRequest rq1(cx1); + + JS::RootedValue obj1(cx1); + TS_ASSERT(script1.Eval("var s = '?'; var v = ({get x() { return 123 }, 'y': {'w':{get z() { delete v.y; delete v.n; v = null; s += s; return 4 }}}, 'n': 100}); v", &obj1)); - CScriptVal obj2 = script2.CloneValueFromOtherContext(script1, obj1.get()); + { + JSContext* cx2 = script2.GetContext(); + JSAutoRequest rq2(cx2); + + JS::RootedValue obj2(cx2, script2.CloneValueFromOtherContext(script1, obj1)); - std::string source; - TS_ASSERT(script2.CallFunction(obj2.get(), "toSource", source)); - TS_ASSERT_STR_EQUALS(source, "({x:123, y:{w:{z:4}}})"); + std::string source; + TS_ASSERT(script2.CallFunction(obj2, "toSource", source)); + TS_ASSERT_STR_EQUALS(source, "({x:123, y:{w:{z:4}}})"); + } } void test_clone_cyclic() @@ -96,24 +111,29 @@ public: ScriptInterface script1("Test", "Test", g_ScriptRuntime); ScriptInterface script2("Test", "Test", g_ScriptRuntime); - CScriptVal obj1; - TS_ASSERT(script1.Eval("var x = []; x[0] = x; ({'a': x, 'b': x})", obj1)); + JSContext* cx1 = script1.GetContext(); + JSAutoRequest rq1(cx1); + + JS::RootedValue obj1(cx1); + TS_ASSERT(script1.Eval("var x = []; x[0] = x; ({'a': x, 'b': x})", &obj1)); - CScriptVal obj2 = script2.CloneValueFromOtherContext(script1, obj1.get()); + { + JSContext* cx2 = script2.GetContext(); + JSAutoRequest rq(cx2); + JS::RootedValue obj2(cx2, script2.CloneValueFromOtherContext(script1, obj1)); - // Use JSAPI function to check if the values of the properties "a", "b" are equals a.x[0] - JSContext* cx2 = script2.GetContext(); - JSAutoRequest rq(cx2); - JS::RootedValue prop_a(cx2); - JS::RootedValue prop_b(cx2); - JS::RootedValue prop_x1(cx2); - TS_ASSERT(JS_GetProperty(cx2, &(obj2.get().toObject()), "a", prop_a.address())); - TS_ASSERT(JS_GetProperty(cx2, &(obj2.get().toObject()), "b", prop_b.address())); - TS_ASSERT(prop_a.get().isObject()); - TS_ASSERT(prop_b.get().isObject()); - TS_ASSERT(JS_GetProperty(cx2, &(prop_a.get().toObject()), "0", prop_x1.address())); - TS_ASSERT_EQUALS(prop_x1.get(), prop_a.get()); - TS_ASSERT_EQUALS(prop_x1.get(), prop_b.get()); + // Use JSAPI function to check if the values of the properties "a", "b" are equals a.x[0] + JS::RootedValue prop_a(cx2); + JS::RootedValue prop_b(cx2); + JS::RootedValue prop_x1(cx2); + TS_ASSERT(script2.GetProperty(obj2, "a", &prop_a)); + TS_ASSERT(script2.GetProperty(obj2, "b", &prop_b)); + TS_ASSERT(prop_a.isObject()); + TS_ASSERT(prop_b.isObject()); + TS_ASSERT(script2.GetProperty(prop_a, "0", &prop_x1)); + TS_ASSERT_EQUALS(prop_x1.get(), prop_a.get()); + TS_ASSERT_EQUALS(prop_x1.get(), prop_b.get()); + } } /** diff --git a/source/simulation2/Simulation2.cpp b/source/simulation2/Simulation2.cpp index 6cd04cc167..f6616a1faf 100644 --- a/source/simulation2/Simulation2.cpp +++ b/source/simulation2/Simulation2.cpp @@ -639,12 +639,18 @@ ScriptInterface& CSimulation2::GetScriptInterface() const void CSimulation2::ReplaceSkirmishGlobals() { - GetScriptInterface().CallFunctionVoid(GetScriptInterface().GetGlobalObject(), "ReplaceSkirmishGlobals"); + JSContext* cx = GetScriptInterface().GetContext(); + JSAutoRequest rq(cx); + JS::RootedValue global(cx, GetScriptInterface().GetGlobalObject()); + GetScriptInterface().CallFunctionVoid(global, "ReplaceSkirmishGlobals"); } void CSimulation2::InitGame(const CScriptVal& data) { - GetScriptInterface().CallFunctionVoid(GetScriptInterface().GetGlobalObject(), "InitGame", data); + JSContext* cx = GetScriptInterface().GetContext(); + JSAutoRequest rq(cx); + JS::RootedValue global(cx, GetScriptInterface().GetGlobalObject()); + GetScriptInterface().CallFunctionVoid(global, "InitGame", data); } void CSimulation2::Update(int turnLength) @@ -728,7 +734,10 @@ CScriptVal CSimulation2::GetMapSettings() void CSimulation2::LoadPlayerSettings(bool newPlayers) { - GetScriptInterface().CallFunctionVoid(GetScriptInterface().GetGlobalObject(), "LoadPlayerSettings", m->m_MapSettings, newPlayers); + JSContext* cx = GetScriptInterface().GetContext(); + JSAutoRequest rq(cx); + JS::RootedValue global(cx, GetScriptInterface().GetGlobalObject()); + GetScriptInterface().CallFunctionVoid(global, "LoadPlayerSettings", m->m_MapSettings, newPlayers); } void CSimulation2::LoadMapSettings() @@ -736,10 +745,11 @@ void CSimulation2::LoadMapSettings() JSContext* cx = GetScriptInterface().GetContext(); JSAutoRequest rq(cx); + JS::RootedValue global(cx, GetScriptInterface().GetGlobalObject()); JS::RootedValue tmpMapSettings(cx, m->m_MapSettings.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade // Initialize here instead of in Update() - GetScriptInterface().CallFunctionVoid(GetScriptInterface().GetGlobalObject(), "LoadMapSettings", tmpMapSettings); + GetScriptInterface().CallFunctionVoid(global, "LoadMapSettings", tmpMapSettings); if (!m->m_StartupScript.empty()) GetScriptInterface().LoadScript(L"map startup script", m->m_StartupScript); diff --git a/source/simulation2/components/CCmpAIManager.cpp b/source/simulation2/components/CCmpAIManager.cpp index 40b63416d6..5ea6f571c0 100644 --- a/source/simulation2/components/CCmpAIManager.cpp +++ b/source/simulation2/components/CCmpAIManager.cpp @@ -180,20 +180,32 @@ private: void Run(JS::HandleValue state, int playerID) { + JSContext* cx = m_ScriptInterface->GetContext(); + JSAutoRequest rq(cx); + JS::RootedValue tmpObj(cx, m_Obj.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade + m_Commands.clear(); - m_ScriptInterface->CallFunctionVoid(m_Obj.get(), "HandleMessage", state, playerID); + m_ScriptInterface->CallFunctionVoid(tmpObj, "HandleMessage", state, playerID); } // overloaded with a sharedAI part. // javascript can handle both natively on the same function. void Run(JS::HandleValue state, int playerID, CScriptValRooted SharedAI) { + JSContext* cx = m_ScriptInterface->GetContext(); + JSAutoRequest rq(cx); + JS::RootedValue tmpObj(cx, m_Obj.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade + m_Commands.clear(); - m_ScriptInterface->CallFunctionVoid(m_Obj.get(), "HandleMessage", state, playerID, SharedAI); + m_ScriptInterface->CallFunctionVoid(tmpObj, "HandleMessage", state, playerID, SharedAI); } void InitAI(JS::HandleValue state, CScriptValRooted SharedAI) { + JSContext* cx = m_ScriptInterface->GetContext(); + JSAutoRequest rq(cx); + JS::RootedValue tmpObj(cx, m_Obj.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade + m_Commands.clear(); - m_ScriptInterface->CallFunctionVoid(m_Obj.get(), "Init", state, m_Player, SharedAI); + m_ScriptInterface->CallFunctionVoid(tmpObj, "Init", state, m_Player, SharedAI); } CAIWorker& m_Worker; @@ -470,7 +482,9 @@ public: m_ScriptInterface->SetProperty(state, "passabilityMap", m_PassabilityMapVal, true); m_ScriptInterface->SetProperty(state, "territoryMap", m_TerritoryMapVal, true); - m_ScriptInterface->CallFunctionVoid(m_SharedAIObj.get(), "init", state); + JS::RootedValue tmpSharedAIObj(cx, m_SharedAIObj.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade + + m_ScriptInterface->CallFunctionVoid(tmpSharedAIObj, "init", state); for (size_t i = 0; i < m_Players.size(); ++i) { @@ -593,8 +607,9 @@ public: serializer.Bool("useSharedScript", m_HasSharedComponent); if (m_HasSharedComponent) { - CScriptVal sharedData; - if (!m_ScriptInterface->CallFunction(m_SharedAIObj.get(), "Serialize", sharedData)) + JS::RootedValue sharedData(cx); + JS::RootedValue tmpSharedAIObj(cx, m_SharedAIObj.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade + if (!m_ScriptInterface->CallFunction(tmpSharedAIObj, "Serialize", &sharedData)) LOGERROR(L"AI shared script Serialize call failed"); serializer.ScriptVal("sharedData", sharedData); } @@ -607,7 +622,7 @@ public: serializer.NumberU32_Unbounded("num commands", (u32)m_Players[i]->m_Commands.size()); for (size_t j = 0; j < m_Players[i]->m_Commands.size(); ++j) { - CScriptVal val = m_ScriptInterface->ReadStructuredClone(m_Players[i]->m_Commands[j]); + JS::RootedValue val(cx, m_ScriptInterface->ReadStructuredClone(m_Players[i]->m_Commands[j])); serializer.ScriptVal("command", val); } @@ -654,9 +669,10 @@ public: TryLoadSharedComponent(false); if (m_HasSharedComponent) { - CScriptVal sharedData; - deserializer.ScriptVal("sharedData", sharedData); - if (!m_ScriptInterface->CallFunctionVoid(m_SharedAIObj.get(), "Deserialize", sharedData)) + JS::RootedValue sharedData(cx); + JS::RootedValue tmpSharedAIObj(cx, m_SharedAIObj.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 + deserializer.ScriptVal("sharedData", &sharedData); + if (!m_ScriptInterface->CallFunctionVoid(tmpSharedAIObj, "Deserialize", sharedData)) LOGERROR(L"AI shared script Deserialize call failed"); } @@ -676,9 +692,9 @@ public: m_Players.back()->m_Commands.reserve(numCommands); for (size_t j = 0; j < numCommands; ++j) { - CScriptVal val; - deserializer.ScriptVal("command", val); - m_Players.back()->m_Commands.push_back(m_ScriptInterface->WriteStructuredClone(val.get())); + JS::RootedValue val(cx); + deserializer.ScriptVal("command", &val); + m_Players.back()->m_Commands.push_back(m_ScriptInterface->WriteStructuredClone(val)); } // TODO: this is yucky but necessary while the AIs are sharing data between contexts; @@ -691,8 +707,8 @@ public: bool hasCustomDeserialize = m_ScriptInterface->HasProperty(tmpPlayerObj, "Deserialize"); if (hasCustomDeserialize) { - CScriptVal scriptData; - deserializer.ScriptVal("data", scriptData); + JS::RootedValue scriptData(cx); + deserializer.ScriptVal("data", &scriptData); if (m_Players[i]->m_UseSharedComponent) { if (!m_ScriptInterface->CallFunctionVoid(tmpPlayerObj, "Deserialize", scriptData, m_SharedAIObj)) @@ -705,7 +721,8 @@ public: } else { - deserializer.ScriptVal("data", tmpPlayerObj.get()); + deserializer.ScriptVal("data", &tmpPlayerObj); + m_Players.back()->m_Obj = CScriptValRooted(cx, tmpPlayerObj); } } } @@ -761,7 +778,8 @@ private: if (m_HasSharedComponent) { PROFILE3("AI run shared component"); - m_ScriptInterface->CallFunctionVoid(m_SharedAIObj.get(), "onUpdate", state); + JS::RootedValue tmpSharedAIObj(cx, m_SharedAIObj.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 + m_ScriptInterface->CallFunctionVoid(tmpSharedAIObj, "onUpdate", state); } for (size_t i = 0; i < m_Players.size(); ++i) diff --git a/source/simulation2/components/CCmpCommandQueue.cpp b/source/simulation2/components/CCmpCommandQueue.cpp index 2e2ce4a094..e0206e18a5 100644 --- a/source/simulation2/components/CCmpCommandQueue.cpp +++ b/source/simulation2/components/CCmpCommandQueue.cpp @@ -50,25 +50,33 @@ public: virtual void Serialize(ISerializer& serialize) { + JSContext* cx = GetSimContext().GetScriptInterface().GetContext(); + JSAutoRequest rq(cx); + + JS::RootedValue tmpRoot(cx); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade serialize.NumberU32_Unbounded("num commands", (u32)m_LocalQueue.size()); for (size_t i = 0; i < m_LocalQueue.size(); ++i) { + tmpRoot.set(m_LocalQueue[i].data.get()); serialize.NumberI32_Unbounded("player", m_LocalQueue[i].player); - serialize.ScriptVal("data", m_LocalQueue[i].data.get()); + serialize.ScriptVal("data", tmpRoot); } } virtual void Deserialize(const CParamNode& UNUSED(paramNode), IDeserializer& deserialize) { + JSContext* cx = GetSimContext().GetScriptInterface().GetContext(); + JSAutoRequest rq(cx); + u32 numCmds; deserialize.NumberU32_Unbounded("num commands", numCmds); for (size_t i = 0; i < numCmds; ++i) { i32 player; - CScriptValRooted data; + JS::RootedValue data(cx); deserialize.NumberI32_Unbounded("player", player); - deserialize.ScriptVal("data", data); - SimulationCommand c = { player, data }; + deserialize.ScriptVal("data", &data); + SimulationCommand c = { player, CScriptValRooted(cx, data) }; m_LocalQueue.push_back(c); } } @@ -96,20 +104,23 @@ public: virtual void FlushTurn(const std::vector& commands) { ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface(); - + JSContext* cx = scriptInterface.GetContext(); + JSAutoRequest rq(cx); + + JS::RootedValue global(cx, scriptInterface.GetGlobalObject()); std::vector localCommands; m_LocalQueue.swap(localCommands); for (size_t i = 0; i < localCommands.size(); ++i) { - bool ok = scriptInterface.CallFunctionVoid(scriptInterface.GetGlobalObject(), "ProcessCommand", localCommands[i].player, localCommands[i].data); + bool ok = scriptInterface.CallFunctionVoid(global, "ProcessCommand", localCommands[i].player, localCommands[i].data); if (!ok) LOGERROR(L"Failed to call ProcessCommand() global script function"); } for (size_t i = 0; i < commands.size(); ++i) { - bool ok = scriptInterface.CallFunctionVoid(scriptInterface.GetGlobalObject(), "ProcessCommand", commands[i].player, commands[i].data); + bool ok = scriptInterface.CallFunctionVoid(global, "ProcessCommand", commands[i].player, commands[i].data); if (!ok) LOGERROR(L"Failed to call ProcessCommand() global script function"); } diff --git a/source/simulation2/scripting/ScriptComponent.cpp b/source/simulation2/scripting/ScriptComponent.cpp index 8ea8f6bb70..5562ab4013 100644 --- a/source/simulation2/scripting/ScriptComponent.cpp +++ b/source/simulation2/scripting/ScriptComponent.cpp @@ -64,11 +64,15 @@ void CComponentTypeScript::Deinit() void CComponentTypeScript::HandleMessage(const CMessage& msg, bool global) { + JSContext* cx = m_ScriptInterface.GetContext(); + JSAutoRequest rq(cx); + const char* name = global ? msg.GetScriptGlobalHandlerName() : msg.GetScriptHandlerName(); - CScriptVal msgVal = msg.ToJSValCached(m_ScriptInterface); + JS::RootedValue msgVal(cx, msg.ToJSValCached(m_ScriptInterface)); - if (!m_ScriptInterface.CallFunctionVoid(m_Instance.get(), name, msgVal)) + JS::RootedValue tmpInstance(cx, m_Instance.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade + if (!m_ScriptInterface.CallFunctionVoid(tmpInstance, name, msgVal)) LOGERROR(L"Script message handler %hs failed", name); } @@ -77,19 +81,23 @@ void CComponentTypeScript::Serialize(ISerializer& serialize) // If the component set Serialize = null, then do no work here if (m_HasNullSerialize) return; + + JSContext* cx = m_ScriptInterface.GetContext(); + JSAutoRequest rq(cx); + JS::RootedValue tmpInstance(cx, m_Instance.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade // Support a custom "Serialize" function, which returns a new object that will be // serialized instead of the component itself if (m_HasCustomSerialize) { - CScriptVal val; - if (!m_ScriptInterface.CallFunction(m_Instance.get(), "Serialize", val)) + JS::RootedValue val(cx); + if (!m_ScriptInterface.CallFunction(tmpInstance, "Serialize", &val)) LOGERROR(L"Script Serialize call failed"); serialize.ScriptVal("object", val); } else { - serialize.ScriptVal("object", m_Instance.get()); + serialize.ScriptVal("object", tmpInstance); } } @@ -107,7 +115,7 @@ void CComponentTypeScript::Deserialize(const CParamNode& paramNode, IDeserialize // If Serialize = null, we'll still call Deserialize but with undefined argument if (!m_HasNullSerialize) - deserialize.ScriptVal("object", val.get()); + deserialize.ScriptVal("object", &val); if (!m_ScriptInterface.CallFunctionVoid(tmpInstance, "Deserialize", val)) LOGERROR(L"Script Deserialize call failed"); @@ -118,7 +126,7 @@ void CComponentTypeScript::Deserialize(const CParamNode& paramNode, IDeserialize { // Use ScriptObjectAppend so we don't lose the carefully-constructed // prototype/parent of this object - deserialize.ScriptObjectAppend("object", m_Instance.getRef()); + deserialize.ScriptObjectAppend("object", tmpInstance); } } diff --git a/source/simulation2/scripting/ScriptComponent.h b/source/simulation2/scripting/ScriptComponent.h index 96ef20566b..035013c514 100644 --- a/source/simulation2/scripting/ScriptComponent.h +++ b/source/simulation2/scripting/ScriptComponent.h @@ -52,12 +52,17 @@ public: // void CallVoid(const char* funcname); // template void CallVoid(const char* funcname, const T0& a0); // ... + +// TODO: Check if these temporary roots can be removed after SpiderMonkey 31 upgrade #define OVERLOADS(z, i, data) \ template \ R Call(const char* funcname BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(i, const T, &a)) \ { \ + JSContext* cx = m_ScriptInterface.GetContext(); \ + JSAutoRequest rq(cx); \ + JS::RootedValue tmpInstance(cx, m_Instance.get()); \ R ret; \ - if (m_ScriptInterface.CallFunction(m_Instance.get(), funcname BOOST_PP_ENUM_TRAILING_PARAMS(i, a), ret)) \ + if (m_ScriptInterface.CallFunction(tmpInstance, funcname BOOST_PP_ENUM_TRAILING_PARAMS(i, a), ret)) \ return ret; \ LOGERROR(L"Error calling component script function %hs", funcname); \ return R(); \ @@ -65,7 +70,10 @@ public: BOOST_PP_IF(i, template<, ) BOOST_PP_ENUM_PARAMS(i, typename T) BOOST_PP_IF(i, >, ) \ void CallVoid(const char* funcname BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(i, const T, &a)) \ { \ - if (m_ScriptInterface.CallFunctionVoid(m_Instance.get(), funcname BOOST_PP_ENUM_TRAILING_PARAMS(i, a))) \ + JSContext* cx = m_ScriptInterface.GetContext(); \ + JSAutoRequest rq(cx); \ + JS::RootedValue tmpInstance(cx, m_Instance.get()); \ + if (m_ScriptInterface.CallFunctionVoid(tmpInstance, funcname BOOST_PP_ENUM_TRAILING_PARAMS(i, a))) \ return; \ LOGERROR(L"Error calling component script function %hs", funcname); \ } diff --git a/source/simulation2/serialization/BinarySerializer.cpp b/source/simulation2/serialization/BinarySerializer.cpp index 994ac5b84a..b173bb902d 100644 --- a/source/simulation2/serialization/BinarySerializer.cpp +++ b/source/simulation2/serialization/BinarySerializer.cpp @@ -60,7 +60,7 @@ CBinarySerializerScriptImpl::CBinarySerializerScriptImpl(ScriptInterface& script { } -void CBinarySerializerScriptImpl::HandleScriptVal(jsval val) +void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val) { JSContext* cx = m_ScriptInterface.GetContext(); JSAutoRequest rq(cx); @@ -119,7 +119,8 @@ void CBinarySerializerScriptImpl::HandleScriptVal(jsval val) // Now handle its array buffer // this may be a backref, since ArrayBuffers can be shared by multiple views - HandleScriptVal(JS::ObjectValue(*JS_GetArrayBufferViewBuffer(obj))); + JS::RootedValue bufferVal(cx, JS::ObjectValue(*JS_GetArrayBufferViewBuffer(obj))); + HandleScriptVal(bufferVal); break; } else if (JS_IsArrayBufferObject(obj)) @@ -182,10 +183,10 @@ void CBinarySerializerScriptImpl::HandleScriptVal(jsval val) // If serialize is null, so don't serialize anything more if (!serialize.isNull()) { - CScriptValRooted data; - if (!m_ScriptInterface.CallFunction(val, "Serialize", data)) + JS::RootedValue data(cx); + if (!m_ScriptInterface.CallFunction(val, "Serialize", &data)) throw PSERROR_Serialize_ScriptError("Prototype Serialize function failed"); - HandleScriptVal(data.get()); + HandleScriptVal(data); } break; } diff --git a/source/simulation2/serialization/BinarySerializer.h b/source/simulation2/serialization/BinarySerializer.h index 9953995a64..9cf2ab0f6c 100644 --- a/source/simulation2/serialization/BinarySerializer.h +++ b/source/simulation2/serialization/BinarySerializer.h @@ -58,7 +58,7 @@ public: CBinarySerializerScriptImpl(ScriptInterface& scriptInterface, ISerializer& serializer); void ScriptString(const char* name, JSString* string); - void HandleScriptVal(jsval val); + void HandleScriptVal(JS::HandleValue val); void SetSerializablePrototypes(std::map& prototypes); private: ScriptInterface& m_ScriptInterface; @@ -185,7 +185,7 @@ protected: m_Impl.Put(name, (u8*)value.data(), value.length()); } - virtual void PutScriptVal(const char* UNUSED(name), jsval value) + virtual void PutScriptVal(const char* UNUSED(name), JS::HandleValue value) { m_ScriptImpl->HandleScriptVal(value); } diff --git a/source/simulation2/serialization/DebugSerializer.cpp b/source/simulation2/serialization/DebugSerializer.cpp index 5936033002..53fa058a5d 100644 --- a/source/simulation2/serialization/DebugSerializer.cpp +++ b/source/simulation2/serialization/DebugSerializer.cpp @@ -147,7 +147,7 @@ void CDebugSerializer::PutString(const char* name, const std::string& value) m_Stream << INDENT << name << ": " << "\"" << escaped << "\"\n"; } -void CDebugSerializer::PutScriptVal(const char* name, jsval value) +void CDebugSerializer::PutScriptVal(const char* name, JS::HandleValue value) { std::wstring source = m_ScriptInterface.ToString(value, true); diff --git a/source/simulation2/serialization/DebugSerializer.h b/source/simulation2/serialization/DebugSerializer.h index f8e4506e27..2f2638a061 100644 --- a/source/simulation2/serialization/DebugSerializer.h +++ b/source/simulation2/serialization/DebugSerializer.h @@ -54,7 +54,7 @@ protected: virtual void PutNumber(const char* name, fixed value); virtual void PutBool(const char* name, bool value); virtual void PutString(const char* name, const std::string& value); - virtual void PutScriptVal(const char* name, jsval value); + virtual void PutScriptVal(const char* name, JS::HandleValue value); virtual void PutRaw(const char* name, const u8* data, size_t len); private: diff --git a/source/simulation2/serialization/IDeserializer.h b/source/simulation2/serialization/IDeserializer.h index 3d986df49c..01a2c561d0 100644 --- a/source/simulation2/serialization/IDeserializer.h +++ b/source/simulation2/serialization/IDeserializer.h @@ -56,12 +56,10 @@ public: virtual void String(const char* name, std::wstring& out, uint32_t minlength, uint32_t maxlength); /// Deserialize a jsval, replacing 'out' - virtual void ScriptVal(const char* name, jsval& out) = 0; - virtual void ScriptVal(const char* name, CScriptVal& out) = 0; - virtual void ScriptVal(const char* name, CScriptValRooted& out) = 0; + virtual void ScriptVal(const char* name, JS::MutableHandleValue out) = 0; - /// Deserialize an object jsval, appending properties to object 'obj' - virtual void ScriptObjectAppend(const char* name, jsval& obj) = 0; + /// Deserialize an object value, appending properties to object 'objVal' + virtual void ScriptObjectAppend(const char* name, JS::HandleValue objVal) = 0; /// Deserialize a JSString virtual void ScriptString(const char* name, JSString*& out) = 0; diff --git a/source/simulation2/serialization/ISerializer.cpp b/source/simulation2/serialization/ISerializer.cpp index 8c4b429062..24140cad75 100644 --- a/source/simulation2/serialization/ISerializer.cpp +++ b/source/simulation2/serialization/ISerializer.cpp @@ -92,21 +92,11 @@ void ISerializer::String(const char* name, const std::wstring& value, uint32_t m PutString(name, str); } -void ISerializer::ScriptVal(const char* name, jsval value) +void ISerializer::ScriptVal(const char* name, JS::HandleValue value) { PutScriptVal(name, value); } -void ISerializer::ScriptVal(const char* name, CScriptVal value) -{ - PutScriptVal(name, value.get()); -} - -void ISerializer::ScriptVal(const char* name, CScriptValRooted value) -{ - PutScriptVal(name, value.get()); -} - void ISerializer::RawBytes(const char* name, const u8* data, size_t len) { PutRaw(name, data, len); diff --git a/source/simulation2/serialization/ISerializer.h b/source/simulation2/serialization/ISerializer.h index d742c27608..81d11f151a 100644 --- a/source/simulation2/serialization/ISerializer.h +++ b/source/simulation2/serialization/ISerializer.h @@ -218,22 +218,8 @@ public: /** * Serialize a jsval. * The value must not contain any unserializable values (like functions). - * Likely to trigger GC, so value must be rooted. */ - void ScriptVal(const char* name, jsval value); - - /** - * Serialize a CScriptVal. - * The value must not contain any unserializable values (like functions). - * Likely to trigger GC, so value must be rooted. - */ - void ScriptVal(const char* name, CScriptVal value); - - /** - * Serialize a CScriptValRooted. - * The value must not contain any unserializable values (like functions). - */ - void ScriptVal(const char* name, CScriptValRooted value); + void ScriptVal(const char* name, JS::HandleValue value); /** * Serialize a stream of bytes. @@ -269,7 +255,7 @@ protected: virtual void PutNumber(const char* name, fixed value) = 0; virtual void PutBool(const char* name, bool value) = 0; virtual void PutString(const char* name, const std::string& value) = 0; - virtual void PutScriptVal(const char* name, jsval value) = 0; + virtual void PutScriptVal(const char* name, JS::HandleValue value) = 0; virtual void PutRaw(const char* name, const u8* data, size_t len) = 0; }; diff --git a/source/simulation2/serialization/SerializeTemplates.h b/source/simulation2/serialization/SerializeTemplates.h index fcef0acfa8..ad71744482 100644 --- a/source/simulation2/serialization/SerializeTemplates.h +++ b/source/simulation2/serialization/SerializeTemplates.h @@ -190,19 +190,6 @@ struct SerializeBool } }; -struct SerializeScriptVal -{ - void operator()(ISerializer& serialize, const char* name, CScriptValRooted value) - { - serialize.ScriptVal(name, value); - } - - void operator()(IDeserializer& deserialize, const char* name, CScriptValRooted& value) - { - deserialize.ScriptVal(name, value); - } -}; - struct SerializeWaypoint { void operator()(ISerializer& serialize, const char* UNUSED(name), const ICmpPathfinder::Waypoint& value) diff --git a/source/simulation2/serialization/StdDeserializer.cpp b/source/simulation2/serialization/StdDeserializer.cpp index 928a9121eb..fb8bee4d6c 100644 --- a/source/simulation2/serialization/StdDeserializer.cpp +++ b/source/simulation2/serialization/StdDeserializer.cpp @@ -122,10 +122,9 @@ void CStdDeserializer::FreeScriptBackrefs() //////////////////////////////////////////////////////////////// -jsval CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JSObject* appendParent) +jsval CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleObject appendParent) { JSContext* cx = m_ScriptInterface.GetContext(); - JSAutoRequest rq(cx); uint8_t type; @@ -142,20 +141,20 @@ jsval CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JSObject* append case SCRIPT_TYPE_OBJECT: case SCRIPT_TYPE_OBJECT_PROTOTYPE: { - JSObject* obj; + JS::RootedObject obj(cx); if (appendParent) { - obj = appendParent; + obj.set(appendParent); } else if (type == SCRIPT_TYPE_ARRAY) { u32 length; NumberU32_Unbounded("array length", length); - obj = JS_NewArrayObject(cx, length, NULL); + obj.set(JS_NewArrayObject(cx, length, NULL)); } else if (type == SCRIPT_TYPE_OBJECT) { - obj = JS_NewObject(cx, NULL, NULL, NULL); + obj.set(JS_NewObject(cx, NULL, NULL, NULL)); } else // SCRIPT_TYPE_OBJECT_PROTOTYPE { @@ -163,18 +162,17 @@ jsval CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JSObject* append String("proto name", prototypeName, 0, 256); // Get constructor object - JSObject* proto = GetSerializablePrototype(prototypeName); + JS::RootedObject proto(cx, GetSerializablePrototype(prototypeName)); if (!proto) throw PSERROR_Deserialize_ScriptError("Failed to find serializable prototype for object"); - JSObject* parent = JS_GetParent(proto); + JS::RootedObject parent(cx, JS_GetParent(proto)); if (!proto || !parent) throw PSERROR_Deserialize_ScriptError(); - obj = JS_NewObject(cx, NULL, proto, parent); + obj.set(JS_NewObject(cx, NULL, proto, parent)); if (!obj) throw PSERROR_Deserialize_ScriptError("JS_NewObject failed"); - CScriptValRooted objRoot(cx, JS::ObjectValue(*obj)); // Does it have custom Deserialize function? // if so, we let it handle the deserialized data, rather than adding properties directly @@ -190,11 +188,12 @@ jsval CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JSObject* append bool hasNullSerialize = hasCustomSerialize && JSVAL_IS_NULL(serialize); // If Serialize is null, we'll still call Deserialize but with undefined argument - CScriptValRooted data; + JS::RootedValue data(cx); if (!hasNullSerialize) - ScriptVal("data", data); + ScriptVal("data", &data); - m_ScriptInterface.CallFunctionVoid(JS::ObjectValue(*obj), "Deserialize", data); + JS::RootedValue objVal(cx, JS::ObjectValue(*obj)); + m_ScriptInterface.CallFunctionVoid(objVal, "Deserialize", data); AddScriptBackref(obj); @@ -215,9 +214,7 @@ jsval CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JSObject* append { utf16string propname; ReadStringUTF16("prop name", propname); - - JS::RootedValue propval(cx, ReadScriptVal("prop value", NULL)); - CScriptValRooted propvalRoot(cx, propval); + JS::RootedValue propval(cx, ReadScriptVal("prop value", JS::NullPtr())); if (!JS_SetUCProperty(cx, obj, (const jschar*)propname.data(), propname.length(), propval.address())) throw PSERROR_Deserialize_ScriptError(); @@ -325,7 +322,7 @@ jsval CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JSObject* append u32 arrayTag = ReserveScriptBackref(); // Get buffer object - jsval bufferVal = ReadScriptVal("buffer", NULL); + jsval bufferVal = ReadScriptVal("buffer", JS::NullPtr()); if (!bufferVal.isObject()) throw PSERROR_Deserialize_ScriptError(); @@ -420,27 +417,21 @@ void CStdDeserializer::ScriptString(const char* name, JSString*& out) throw PSERROR_Deserialize_ScriptError("JS_NewUCStringCopyN failed"); } -void CStdDeserializer::ScriptVal(const char* name, jsval& out) +void CStdDeserializer::ScriptVal(const char* name, JS::MutableHandleValue out) { - out = ReadScriptVal(name, NULL); + out.set(ReadScriptVal(name, JS::NullPtr())); } -void CStdDeserializer::ScriptVal(const char* name, CScriptVal& out) +void CStdDeserializer::ScriptObjectAppend(const char* name, JS::HandleValue objVal) { - out = ReadScriptVal(name, NULL); -} - -void CStdDeserializer::ScriptVal(const char* name, CScriptValRooted& out) -{ - out = CScriptValRooted(m_ScriptInterface.GetContext(), ReadScriptVal(name, NULL)); -} - -void CStdDeserializer::ScriptObjectAppend(const char* name, jsval& obj) -{ - if (!obj.isObject()) + JSContext* cx = m_ScriptInterface.GetContext(); + JSAutoRequest rq(cx); + + if (!objVal.isObject()) throw PSERROR_Deserialize_ScriptError(); - ReadScriptVal(name, JSVAL_TO_OBJECT(obj)); + JS::RootedObject obj(cx, &objVal.toObject()); + ReadScriptVal(name, obj); } void CStdDeserializer::SetSerializablePrototypes(std::map& prototypes) diff --git a/source/simulation2/serialization/StdDeserializer.h b/source/simulation2/serialization/StdDeserializer.h index 681e8bd061..185b9f4d44 100644 --- a/source/simulation2/serialization/StdDeserializer.h +++ b/source/simulation2/serialization/StdDeserializer.h @@ -31,10 +31,8 @@ public: CStdDeserializer(ScriptInterface& scriptInterface, std::istream& stream); virtual ~CStdDeserializer(); - virtual void ScriptVal(const char* name, jsval& out); - virtual void ScriptVal(const char* name, CScriptVal& out); - virtual void ScriptVal(const char* name, CScriptValRooted& out); - virtual void ScriptObjectAppend(const char* name, jsval& obj); + virtual void ScriptVal(const char* name, JS::MutableHandleValue out); + virtual void ScriptObjectAppend(const char* name, JS::HandleValue objVal); virtual void ScriptString(const char* name, JSString*& out); virtual std::istream& GetStream(); @@ -46,7 +44,7 @@ protected: virtual void Get(const char* name, u8* data, size_t len); private: - jsval ReadScriptVal(const char* name, JSObject* appendParent); + jsval ReadScriptVal(const char* name, JS::HandleObject appendParent); void ReadStringUTF16(const char* name, utf16string& str); virtual void AddScriptBackref(JSObject* obj); diff --git a/source/simulation2/tests/test_Serializer.h b/source/simulation2/tests/test_Serializer.h index 91cff56a13..e8d8a724a3 100644 --- a/source/simulation2/tests/test_Serializer.h +++ b/source/simulation2/tests/test_Serializer.h @@ -267,8 +267,11 @@ public: void test_script_basic() { ScriptInterface script("Test", "Test", g_ScriptRuntime); - CScriptVal obj; - TS_ASSERT(script.Eval("({'x': 123, 'y': [1, 1.5, '2', 'test', undefined, null, true, false]})", obj)); + JSContext* cx = script.GetContext(); + JSAutoRequest rq(cx); + + JS::RootedValue obj(cx); + TS_ASSERT(script.Eval("({'x': 123, 'y': [1, 1.5, '2', 'test', undefined, null, true, false]})", &obj)); { std::stringstream stream; @@ -326,8 +329,8 @@ public: CStdDeserializer deserialize(script, stream); - jsval newobj; - deserialize.ScriptVal("script", newobj); + JS::RootedValue newobj(cx); + deserialize.ScriptVal("script", &newobj); TS_ASSERT(stream.good()); TS_ASSERT_EQUALS(stream.peek(), EOF); @@ -340,8 +343,11 @@ public: void helper_script_roundtrip(const char* msg, const char* input, const char* expected, size_t expstreamlen = 0, const char* expstream = NULL) { ScriptInterface script("Test", "Test", g_ScriptRuntime); - CScriptVal obj; - TSM_ASSERT(msg, script.Eval(input, obj)); + JSContext* cx = script.GetContext(); + JSAutoRequest rq(cx); + + JS::RootedValue obj(cx); + TSM_ASSERT(msg, script.Eval(input, &obj)); std::stringstream stream; CStdSerializer serialize(script, stream); @@ -355,8 +361,8 @@ public: CStdDeserializer deserialize(script, stream); - jsval newobj; - deserialize.ScriptVal("script", newobj); + JS::RootedValue newobj(cx); + deserialize.ScriptVal("script", &newobj); TSM_ASSERT(msg, stream.good()); TSM_ASSERT_EQUALS(msg, stream.peek(), EOF); @@ -567,14 +573,17 @@ public: void test_script_exceptions() { ScriptInterface script("Test", "Test", g_ScriptRuntime); - CScriptVal obj; + JSContext* cx = script.GetContext(); + JSAutoRequest rq(cx); + + JS::RootedValue obj(cx); std::stringstream stream; CStdSerializer serialize(script, stream); TestLogger logger; - TS_ASSERT(script.Eval("([1, 2, function () { }])", obj)); + TS_ASSERT(script.Eval("([1, 2, function () { }])", &obj)); TS_ASSERT_THROWS(serialize.ScriptVal("script", obj), PSERROR_Serialize_InvalidScriptValue); } @@ -599,8 +608,11 @@ public: const char* input = "var x = {}; for (var i=0;i<256;++i) x[i]=Math.pow(i, 2); x"; ScriptInterface script("Test", "Test", g_ScriptRuntime); - CScriptVal obj; - TS_ASSERT(script.Eval(input, obj)); + JSContext* cx = script.GetContext(); + JSAutoRequest rq(cx); + + JS::RootedValue obj(cx); + TS_ASSERT(script.Eval(input, &obj)); for (size_t i = 0; i < 256; ++i) { @@ -611,8 +623,8 @@ public: CStdDeserializer deserialize(script, stream); - jsval newobj; - deserialize.ScriptVal("script", newobj); + JS::RootedValue newobj(cx); + deserialize.ScriptVal("script", &newobj); TS_ASSERT(stream.good()); TS_ASSERT_EQUALS(stream.peek(), EOF);