1
0
forked from mirrors/0ad

Exact stack rooting for structured cloning functions.

Refs #2415
Refs #2462

This was SVN commit r15597.
This commit is contained in:
Yves
2014-08-01 20:55:16 +00:00
parent 7dbbb4e419
commit 608c27fe10
8 changed files with 104 additions and 54 deletions
+8 -3
View File
@@ -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<ScriptInterface::StructuredClone> 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
+4 -4
View File
@@ -113,7 +113,7 @@ void CGUIManager::PopPageCB(shared_ptr<ScriptInterface::StructuredClone> 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<ScriptInterface::StructuredClone> 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(
+48 -22
View File
@@ -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<ICmpGuiInterface> 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<ICmpCommandQueue> 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<entity_id_t> 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);
}
/**
+2 -1
View File
@@ -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);
+8 -8
View File
@@ -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> structuredClone = otherContext.WriteStructuredClone(val);
jsval clone = ReadStructuredClone(structuredClone);
return clone;
JSAutoRequest rq(m->m_cx);
JS::RootedValue out(m->m_cx);
shared_ptr<StructuredClone> structuredClone = otherContext.WriteStructuredClone(val);
ReadStructuredClone(structuredClone, &out);
return out.get();
}
ScriptInterface::StructuredClone::StructuredClone() :
@@ -1487,10 +1489,8 @@ shared_ptr<ScriptInterface::StructuredClone> ScriptInterface::WriteStructuredClo
return ret;
}
jsval ScriptInterface::ReadStructuredClone(const shared_ptr<ScriptInterface::StructuredClone>& ptr)
void ScriptInterface::ReadStructuredClone(const shared_ptr<ScriptInterface::StructuredClone>& 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);
}
+2 -2
View File
@@ -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<StructuredClone> WriteStructuredClone(jsval v);
jsval ReadStructuredClone(const shared_ptr<StructuredClone>& ptr);
void ReadStructuredClone(const shared_ptr<StructuredClone>& ptr, JS::MutableHandleValue ret);
/**
* Converts |a| if needed and assigns it to |handle|.
+15 -5
View File
@@ -152,11 +152,14 @@ public:
static std::vector<SimulationCommand> CloneCommandsFromOtherContext(ScriptInterface& oldScript, ScriptInterface& newScript,
const std::vector<SimulationCommand>& commands)
{
JSContext* cxOld = oldScript.GetContext();
JSAutoRequest rqOld(cxOld);
std::vector<SimulationCommand> 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::vector<SimulationComman
// Load the trigger scripts after we have loaded the simulation.
{
JSContext* cx = secondaryComponentManager.GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
JS::RootedValue mapSettingsCloned(cx, secondaryComponentManager.GetScriptInterface().CloneValueFromOtherContext(m_ComponentManager.GetScriptInterface(), m_MapSettings.get()));
JSContext* cx1 = m_ComponentManager.GetScriptInterface().GetContext();
JSAutoRequest rq1(cx1);
// TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade
JS::RootedValue tmpMapSettings(cx1, m_MapSettings.get());
JSContext* cx2 = secondaryComponentManager.GetScriptInterface().GetContext();
JSAutoRequest rq2(cx2);
JS::RootedValue mapSettingsCloned(cx2,
secondaryComponentManager.GetScriptInterface().CloneValueFromOtherContext(
m_ComponentManager.GetScriptInterface(), tmpMapSettings));
ENSURE(LoadTriggerScripts(secondaryComponentManager, mapSettingsCloned));
}
@@ -468,7 +468,8 @@ public:
JSContext* cx = m_ScriptInterface->GetContext();
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<ScriptInterface::StructuredClone>& 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<std::pair<std::string, const CParamNode*> >& 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<CAIWorker::SCommandSets> commands;
m_Worker.GetCommands(commands);
CmpPtr<ICmpCommandQueue> 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));
}
}
}