diff --git a/source/graphics/MapReader.cpp b/source/graphics/MapReader.cpp index dc1c2cf699..5464aaea6b 100644 --- a/source/graphics/MapReader.cpp +++ b/source/graphics/MapReader.cpp @@ -1256,6 +1256,9 @@ int CMapReader::LoadRMSettings() int CMapReader::GenerateMap() { + JSContext* cx = pSimulation2->GetScriptInterface().GetContext(); + JSAutoRequest rq(cx); + if (!m_MapGen) { // Initialize map generator @@ -1286,15 +1289,17 @@ int CMapReader::GenerateMap() shared_ptr results = m_MapGen->GetResults(); // Parse data into simulation context - CScriptValRooted data(pSimulation2->GetScriptInterface().GetContext(), pSimulation2->GetScriptInterface().ReadStructuredClone(results)); - if (data.undefined()) + JS::RootedValue data(cx); + pSimulation2->GetScriptInterface().ReadStructuredClone(results, &data); + + if (data.isUndefined()) { // RMS failed - return to main menu throw PSERROR_Game_World_MapLoadFailed("Error generating random map.\nCheck application log for details."); } else { - m_MapData = data; + m_MapData = CScriptValRooted(cx, data); } } else diff --git a/source/gui/GUIManager.cpp b/source/gui/GUIManager.cpp index 0365ca013f..6f707d0bd7 100644 --- a/source/gui/GUIManager.cpp +++ b/source/gui/GUIManager.cpp @@ -113,7 +113,7 @@ void CGUIManager::PopPageCB(shared_ptr args) JS::RootedValue initDataVal(cx); if (initDataClone) - initDataVal.set(scriptInterface->ReadStructuredClone(initDataClone)); + scriptInterface->ReadStructuredClone(initDataClone, &initDataVal); else { LOGERROR(L"Called PopPageCB when initData (which should contain the callback function name) isn't set!"); @@ -142,7 +142,7 @@ void CGUIManager::PopPageCB(shared_ptr args) JS::RootedValue argVal(cx); if (args) - argVal.set(scriptInterface->ReadStructuredClone(args)); + scriptInterface->ReadStructuredClone(args, &argVal); if (!scriptInterface->CallFunctionVoid(global, callback.c_str(), argVal)) { LOGERROR(L"Failed to call the callback function %hs in the page %ls", callback.c_str(), m_PageStack.back().name.c_str()); @@ -239,9 +239,9 @@ void CGUIManager::LoadPage(SGUIPage& page) JS::RootedValue hotloadDataVal(cx); JS::RootedValue global(cx, scriptInterface->GetGlobalObject()); if (page.initData) - initDataVal.set(scriptInterface->ReadStructuredClone(page.initData)); + scriptInterface->ReadStructuredClone(page.initData, &initDataVal); if (hotloadData) - hotloadDataVal.set(scriptInterface->ReadStructuredClone(hotloadData)); + scriptInterface->ReadStructuredClone(hotloadData, &hotloadDataVal); // Call the init() function if (!scriptInterface->CallFunctionVoid( diff --git a/source/gui/scripting/ScriptFunctions.cpp b/source/gui/scripting/ScriptFunctions.cpp index 62608b3ae0..1bf25ef7e1 100644 --- a/source/gui/scripting/ScriptFunctions.cpp +++ b/source/gui/scripting/ScriptFunctions.cpp @@ -109,27 +109,33 @@ void PopGuiPageCB(ScriptInterface::CxPrivate* pCxPrivate, CScriptVal args) g_GUI->PopPageCB(pCxPrivate->pScriptInterface->WriteStructuredClone(args.get())); } -CScriptVal GuiInterfaceCall(ScriptInterface::CxPrivate* pCxPrivate, std::wstring name, CScriptVal data) +CScriptVal GuiInterfaceCall(ScriptInterface::CxPrivate* pCxPrivate, std::wstring name, CScriptVal data1) { + // TODO: With ESR31 we should be able to take JS::HandleValue directly + JSContext* cx = pCxPrivate->pScriptInterface->GetContext(); + JSAutoRequest rq(cx); + JS::RootedValue data(cx, data1.get()); + if (!g_Game) - return JSVAL_VOID; + return JS::UndefinedValue(); CSimulation2* sim = g_Game->GetSimulation2(); ENSURE(sim); CmpPtr cmpGuiInterface(*sim, SYSTEM_ENTITY); if (!cmpGuiInterface) - return JSVAL_VOID; + return JS::UndefinedValue(); - int player = -1; - if (g_Game) - player = g_Game->GetPlayerID(); + int player = g_Game->GetPlayerID(); - CScriptValRooted arg (sim->GetScriptInterface().GetContext(), sim->GetScriptInterface().CloneValueFromOtherContext(*(pCxPrivate->pScriptInterface), data.get())); - CScriptVal ret (cmpGuiInterface->ScriptCall(player, name, arg.get())); - return pCxPrivate->pScriptInterface->CloneValueFromOtherContext(sim->GetScriptInterface(), ret.get()); + JSContext* cxSim = sim->GetScriptInterface().GetContext(); + JSAutoRequest rqSim(cxSim); + JS::RootedValue arg(cxSim, sim->GetScriptInterface().CloneValueFromOtherContext(*(pCxPrivate->pScriptInterface), data)); + JS::RootedValue ret(cxSim, cmpGuiInterface->ScriptCall(player, name, CScriptVal(arg)).get()); + + return pCxPrivate->pScriptInterface->CloneValueFromOtherContext(sim->GetScriptInterface(), ret); } -void PostNetworkCommand(ScriptInterface::CxPrivate* pCxPrivate, CScriptVal cmd) +void PostNetworkCommand(ScriptInterface::CxPrivate* pCxPrivate, CScriptVal cmd1) { if (!g_Game) return; @@ -139,10 +145,17 @@ void PostNetworkCommand(ScriptInterface::CxPrivate* pCxPrivate, CScriptVal cmd) CmpPtr cmpCommandQueue(*sim, SYSTEM_ENTITY); if (!cmpCommandQueue) return; + + // TODO: With ESR31 we should be able to take JS::HandleValue directly + JSContext* cx = pCxPrivate->pScriptInterface->GetContext(); + JSAutoRequest rq(cx); + JS::RootedValue cmd(cx, cmd1.get()); - jsval cmd2 = sim->GetScriptInterface().CloneValueFromOtherContext(*(pCxPrivate->pScriptInterface), cmd.get()); + JSContext* cxSim = sim->GetScriptInterface().GetContext(); + JSAutoRequest rqSim(cxSim); + JS::RootedValue cmd2(cxSim, sim->GetScriptInterface().CloneValueFromOtherContext(*(pCxPrivate->pScriptInterface), cmd)); - cmpCommandQueue->PostNetworkCommand(cmd2); + cmpCommandQueue->PostNetworkCommand(CScriptVal(cmd2)); } std::vector PickEntitiesAtPoint(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int x, int y, int range) @@ -202,21 +215,29 @@ void StartNetworkGame(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) g_NetServer->StartGame(); } -void StartGame(ScriptInterface::CxPrivate* pCxPrivate, CScriptVal attribs, int playerID) +void StartGame(ScriptInterface::CxPrivate* pCxPrivate, CScriptVal attribs1, int playerID) { ENSURE(!g_NetServer); ENSURE(!g_NetClient); ENSURE(!g_Game); g_Game = new CGame(); + + // TODO: With ESR31 we should be able to take JS::HandleValue directly + JSContext* cx = pCxPrivate->pScriptInterface->GetContext(); + JSAutoRequest rq(cx); + JS::RootedValue attribs(cx, attribs1.get()); // Convert from GUI script context to sim script context CSimulation2* sim = g_Game->GetSimulation2(); - CScriptValRooted gameAttribs (sim->GetScriptInterface().GetContext(), - sim->GetScriptInterface().CloneValueFromOtherContext(*(pCxPrivate->pScriptInterface), attribs.get())); + JSContext* cxSim = sim->GetScriptInterface().GetContext(); + JSAutoRequest rqSim(cxSim); + + JS::RootedValue gameAttribs(cxSim, + sim->GetScriptInterface().CloneValueFromOtherContext(*(pCxPrivate->pScriptInterface), attribs)); g_Game->SetPlayerID(playerID); - g_Game->StartGame(gameAttribs, ""); + g_Game->StartGame(CScriptValRooted(cxSim, gameAttribs), ""); } CScriptVal StartSavedGame(ScriptInterface::CxPrivate* pCxPrivate, std::wstring name) @@ -339,12 +360,13 @@ void DisconnectNetworkGame(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) CScriptVal PollNetworkClient(ScriptInterface::CxPrivate* pCxPrivate) { if (!g_NetClient) - return CScriptVal(); - - CScriptValRooted poll = g_NetClient->GuiPoll(); + return JS::UndefinedValue(); // Convert from net client context to GUI script context - return pCxPrivate->pScriptInterface->CloneValueFromOtherContext(g_NetClient->GetScriptInterface(), poll.get()); + JSContext* cxNet = g_NetClient->GetScriptInterface().GetContext(); + JSAutoRequest rqNet(cxNet); + JS::RootedValue pollNet(cxNet, g_NetClient->GuiPoll().get()); + return pCxPrivate->pScriptInterface->CloneValueFromOtherContext(g_NetClient->GetScriptInterface(), pollNet); } void AssignNetworkPlayer(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int playerID, std::string guid) @@ -435,11 +457,15 @@ CScriptVal LoadMapSettings(ScriptInterface::CxPrivate* pCxPrivate, VfsPath pathn CScriptVal GetMapSettings(ScriptInterface::CxPrivate* pCxPrivate) { if (!g_Game) - return CScriptVal(); + return JS::UndefinedValue(); + JSContext* cx = g_Game->GetSimulation2()->GetScriptInterface().GetContext(); + JSAutoRequest rq(cx); + + JS::RootedValue mapSettings(cx, g_Game->GetSimulation2()->GetMapSettings().get()); return pCxPrivate->pScriptInterface->CloneValueFromOtherContext( g_Game->GetSimulation2()->GetScriptInterface(), - g_Game->GetSimulation2()->GetMapSettings().get()); + mapSettings); } /** diff --git a/source/ps/SavedGame.cpp b/source/ps/SavedGame.cpp index 293cb7ac59..f863081432 100644 --- a/source/ps/SavedGame.cpp +++ b/source/ps/SavedGame.cpp @@ -89,7 +89,8 @@ Status SavedGames::Save(const std::wstring& name, const std::wstring& descriptio simulation.GetScriptInterface().SetProperty(metadata, "player", playerID); simulation.GetScriptInterface().SetProperty(metadata, "initAttributes", simulation.GetInitAttributes()); - JS::RootedValue guiMetadata(cx, simulation.GetScriptInterface().ReadStructuredClone(guiMetadataClone)); + JS::RootedValue guiMetadata(cx); + simulation.GetScriptInterface().ReadStructuredClone(guiMetadataClone, &guiMetadata); // get some camera data JS::RootedValue cameraMetadata(cx); diff --git a/source/scriptinterface/ScriptInterface.cpp b/source/scriptinterface/ScriptInterface.cpp index 017ed10f59..909dbfcdb0 100644 --- a/source/scriptinterface/ScriptInterface.cpp +++ b/source/scriptinterface/ScriptInterface.cpp @@ -1451,12 +1451,14 @@ void ScriptInterface::ForceGC() JS_GC(this->GetJSRuntime()); } -jsval ScriptInterface::CloneValueFromOtherContext(ScriptInterface& otherContext, jsval val) +JS::Value ScriptInterface::CloneValueFromOtherContext(ScriptInterface& otherContext, JS::HandleValue val) { PROFILE("CloneValueFromOtherContext"); - shared_ptr structuredClone = otherContext.WriteStructuredClone(val); - jsval clone = ReadStructuredClone(structuredClone); - return clone; + JSAutoRequest rq(m->m_cx); + JS::RootedValue out(m->m_cx); + shared_ptr structuredClone = otherContext.WriteStructuredClone(val); + ReadStructuredClone(structuredClone, &out); + return out.get(); } ScriptInterface::StructuredClone::StructuredClone() : @@ -1487,10 +1489,8 @@ shared_ptr ScriptInterface::WriteStructuredClo return ret; } -jsval ScriptInterface::ReadStructuredClone(const shared_ptr& ptr) +void ScriptInterface::ReadStructuredClone(const shared_ptr& ptr, JS::MutableHandleValue ret) { JSAutoRequest rq(m->m_cx); - jsval ret = JSVAL_VOID; - JS_ReadStructuredClone(m->m_cx, ptr->m_Data, ptr->m_Size, JS_STRUCTURED_CLONE_VERSION, &ret, NULL, NULL); - return ret; + JS_ReadStructuredClone(m->m_cx, ptr->m_Data, ptr->m_Size, JS_STRUCTURED_CLONE_VERSION, ret.address(), NULL, NULL); } diff --git a/source/scriptinterface/ScriptInterface.h b/source/scriptinterface/ScriptInterface.h index 19e2b57086..1a37bcb052 100644 --- a/source/scriptinterface/ScriptInterface.h +++ b/source/scriptinterface/ScriptInterface.h @@ -322,7 +322,7 @@ public: * Complex values (functions, XML, etc) won't be cloned correctly, but basic * types and cyclic references should be fine. */ - jsval CloneValueFromOtherContext(ScriptInterface& otherContext, jsval val); + JS::Value CloneValueFromOtherContext(ScriptInterface& otherContext, JS::HandleValue val); /** * Convert a jsval to a C++ type. (This might trigger GC.) @@ -393,7 +393,7 @@ public: }; shared_ptr WriteStructuredClone(jsval v); - jsval ReadStructuredClone(const shared_ptr& ptr); + void ReadStructuredClone(const shared_ptr& ptr, JS::MutableHandleValue ret); /** * Converts |a| if needed and assigns it to |handle|. diff --git a/source/simulation2/Simulation2.cpp b/source/simulation2/Simulation2.cpp index f6616a1faf..9ffcb2b38b 100644 --- a/source/simulation2/Simulation2.cpp +++ b/source/simulation2/Simulation2.cpp @@ -152,11 +152,14 @@ public: static std::vector CloneCommandsFromOtherContext(ScriptInterface& oldScript, ScriptInterface& newScript, const std::vector& commands) { + JSContext* cxOld = oldScript.GetContext(); + JSAutoRequest rqOld(cxOld); + std::vector newCommands = commands; for (size_t i = 0; i < newCommands.size(); ++i) { - newCommands[i].data = CScriptValRooted(newScript.GetContext(), - newScript.CloneValueFromOtherContext(oldScript, newCommands[i].data.get())); + JS::RootedValue tmpOldCommand(cxOld, newCommands[i].data.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade + newCommands[i].data = CScriptValRooted(newScript.GetContext(), newScript.CloneValueFromOtherContext(oldScript, tmpOldCommand)); } return newCommands; } @@ -356,9 +359,16 @@ void CSimulation2Impl::Update(int turnLength, const std::vectorGetContext(); JSAutoRequest rq(cx); - JS::RootedValue state(cx, m_ScriptInterface->ReadStructuredClone(gameState)); + JS::RootedValue state(cx); + m_ScriptInterface->ReadStructuredClone(gameState, &state); JS::RootedValue tmpVal(cx); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade ScriptInterface::ToJSVal(cx, &tmpVal, passabilityMap); @@ -547,7 +548,10 @@ public: void RegisterTechTemplates(const shared_ptr& techTemplates) { JSContext* cx = m_ScriptInterface->GetContext(); - m_TechTemplates = CScriptValRooted(cx, m_ScriptInterface->ReadStructuredClone(techTemplates)); + JSAutoRequest rq(cx); + JS::RootedValue ret(cx); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade + m_ScriptInterface->ReadStructuredClone(techTemplates, &ret); + m_TechTemplates = CScriptValRooted(cx, ret); } void LoadEntityTemplates(const std::vector >& templates) @@ -622,7 +626,8 @@ 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) { - JS::RootedValue val(cx, m_ScriptInterface->ReadStructuredClone(m_Players[i]->m_Commands[j])); + JS::RootedValue val(cx); + m_ScriptInterface->ReadStructuredClone(m_Players[i]->m_Commands[j], &val); serializer.ScriptVal("command", val); } @@ -763,7 +768,7 @@ private: JS::RootedValue state(cx); { PROFILE3("AI compute read state"); - state.set(m_ScriptInterface->ReadStructuredClone(m_GameState)); + m_ScriptInterface->ReadStructuredClone(m_GameState, &state); m_ScriptInterface->SetProperty(state, "passabilityMap", m_PassabilityMapVal, true); m_ScriptInterface->SetProperty(state, "territoryMap", m_TerritoryMapVal, true); } @@ -1012,21 +1017,24 @@ public: virtual void PushCommands() { - ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface(); - std::vector commands; m_Worker.GetCommands(commands); CmpPtr cmpCommandQueue(GetSystemEntity()); if (!cmpCommandQueue) return; - + + ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface(); + JSContext* cx = scriptInterface.GetContext(); + JSAutoRequest rq(cx); + JS::RootedValue clonedCommandVal(cx); + for (size_t i = 0; i < commands.size(); ++i) { for (size_t j = 0; j < commands[i].commands.size(); ++j) { - cmpCommandQueue->PushLocalCommand(commands[i].player, - scriptInterface.ReadStructuredClone(commands[i].commands[j])); + scriptInterface.ReadStructuredClone(commands[i].commands[j], &clonedCommandVal); + cmpCommandQueue->PushLocalCommand(commands[i].player, CScriptVal(clonedCommandVal)); } } }