[SM52 2/2] Update to Spidermonkey 52 APIs.

No particularly noteworthy changes, as most complex API changes were
already supported in SM45 and done.
The addition of JSStructuredCloneData allows to remove our custom class.

Changes:
- InformalValueTypeName is back in the API, so remove our
implementation.
- Stop using JSRuntime entirely in favour of JSContext*
- JSPropertyDescriptor is renamed.
- CompartmentOptions are tweaked slightly (no functional changes)
- JS::Construct - API update.
- JSClass split - API update.
- A js.msg error message was removed, so we had to use a different one.
- Tests fix: fix comparison of union instances
- Disable warning in spidermonkey Vector.h
- Update error reporting to SM52 (minor API updates)
- Ignore warnings about unused return values (would come from OOM, which
isn't recoverable)

Most of the patching was done by Itms.

Tested by: Stan, Freagarach
Fixes #4893

Differential Revision: https://code.wildfiregames.com/D3095
This was SVN commit r24203.
This commit is contained in:
wraitii
2020-11-18 14:39:04 +00:00
parent 6bb08fb424
commit fd8f5abd2e
54 changed files with 251 additions and 324 deletions
+4 -4
View File
@@ -92,7 +92,7 @@ void* CMapGeneratorWorker::RunThread(CMapGeneratorWorker* self)
shared_ptr<ScriptContext> mapgenContext = ScriptContext::CreateContext(RMS_CONTEXT_SIZE);
// Enable the script to be aborted
JS_SetInterruptCallback(mapgenContext->GetJSRuntime(), MapGeneratorInterruptCallback);
JS_AddInterruptCallback(mapgenContext->GetGeneralJSContext(), MapGeneratorInterruptCallback);
self->m_ScriptInterface = new ScriptInterface("Engine", "MapGenerator", mapgenContext);
@@ -214,7 +214,7 @@ double CMapGeneratorWorker::GetMicroseconds(ScriptInterface::CmptPrivate* UNUSED
return JS_Now();
}
shared_ptr<ScriptInterface::StructuredClone> CMapGeneratorWorker::GetResults()
ScriptInterface::StructuredClone CMapGeneratorWorker::GetResults()
{
std::lock_guard<std::mutex> lock(m_WorkerMutex);
return m_MapData;
@@ -232,7 +232,7 @@ void CMapGeneratorWorker::ExportMap(ScriptInterface::CmptPrivate* pCmptPrivate,
// Copy results
std::lock_guard<std::mutex> lock(self->m_WorkerMutex);
self->m_MapData = self->m_ScriptInterface->WriteStructuredClone(data);
self->m_MapData = self->m_ScriptInterface->WriteStructuredClone(data, false);
self->m_Progress = 0;
}
@@ -427,7 +427,7 @@ int CMapGenerator::GetProgress()
return m_Worker->GetProgress();
}
shared_ptr<ScriptInterface::StructuredClone> CMapGenerator::GetResults()
ScriptInterface::StructuredClone CMapGenerator::GetResults()
{
return m_Worker->GetResults();
}
+3 -3
View File
@@ -67,7 +67,7 @@ public:
*
* @return StructuredClone containing map data
*/
shared_ptr<ScriptInterface::StructuredClone> GetResults();
ScriptInterface::StructuredClone GetResults();
private:
CMapGeneratorWorker* m_Worker;
@@ -110,7 +110,7 @@ public:
*
* @return StructuredClone containing map data
*/
shared_ptr<ScriptInterface::StructuredClone> GetResults();
ScriptInterface::StructuredClone GetResults();
/**
* Set initial seed, callback data.
@@ -201,7 +201,7 @@ private:
/**
* Result of the mapscript generation including terrain, entities and environment settings.
*/
shared_ptr<ScriptInterface::StructuredClone> m_MapData;
ScriptInterface::StructuredClone m_MapData;
/**
* Deterministic random number generator.
+6 -5
View File
@@ -39,6 +39,7 @@
#include "renderer/PostprocManager.h"
#include "renderer/SkyManager.h"
#include "renderer/WaterManager.h"
#include "scriptinterface/ScriptContext.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpCinemaManager.h"
#include "simulation2/components/ICmpGarrisonHolder.h"
@@ -62,7 +63,7 @@ CMapReader::CMapReader()
}
// LoadMap: try to load the map from given file; reinitialise the scene to new data if successful
void CMapReader::LoadMap(const VfsPath& pathname, JSRuntime* rt, JS::HandleValue settings, CTerrain *pTerrain_,
void CMapReader::LoadMap(const VfsPath& pathname, const ScriptContext& cx, JS::HandleValue settings, CTerrain *pTerrain_,
WaterManager* pWaterMan_, SkyManager* pSkyMan_,
CLightEnv *pLightEnv_, CGameView *pGameView_, CCinemaManager* pCinema_, CTriggerManager* pTrigMan_, CPostprocManager* pPostproc_,
CSimulation2 *pSimulation2_, const CSimContext* pSimContext_, int playerID_, bool skipEntities)
@@ -80,7 +81,7 @@ void CMapReader::LoadMap(const VfsPath& pathname, JSRuntime* rt, JS::HandleValu
m_PlayerID = playerID_;
m_SkipEntities = skipEntities;
m_StartingCameraTarget = INVALID_ENTITY;
m_ScriptSettings.init(rt, settings);
m_ScriptSettings.init(cx.GetGeneralJSContext(), settings);
filename_xml = pathname.ChangeExtension(L".xml");
@@ -144,7 +145,7 @@ void CMapReader::LoadMap(const VfsPath& pathname, JSRuntime* rt, JS::HandleValu
}
// LoadRandomMap: try to load the map data; reinitialise the scene to new data if successful
void CMapReader::LoadRandomMap(const CStrW& scriptFile, JSRuntime* rt, JS::HandleValue settings, CTerrain *pTerrain_,
void CMapReader::LoadRandomMap(const CStrW& scriptFile, const ScriptContext& cx, JS::HandleValue settings, CTerrain *pTerrain_,
WaterManager* pWaterMan_, SkyManager* pSkyMan_,
CLightEnv *pLightEnv_, CGameView *pGameView_, CCinemaManager* pCinema_, CTriggerManager* pTrigMan_, CPostprocManager* pPostproc_,
CSimulation2 *pSimulation2_, int playerID_)
@@ -152,7 +153,7 @@ void CMapReader::LoadRandomMap(const CStrW& scriptFile, JSRuntime* rt, JS::Handl
m_ScriptFile = scriptFile;
pSimulation2 = pSimulation2_;
pSimContext = pSimulation2 ? &pSimulation2->GetSimContext() : NULL;
m_ScriptSettings.init(rt, settings);
m_ScriptSettings.init(cx.GetGeneralJSContext(), settings);
pTerrain = pTerrain_;
pLightEnv = pLightEnv_;
pGameView = pGameView_;
@@ -1295,7 +1296,7 @@ int CMapReader::GenerateMap()
else if (progress == 0)
{
// Finished, get results as StructuredClone object, which must be read to obtain the JS::Value
shared_ptr<ScriptInterface::StructuredClone> results = m_MapGen->GetResults();
ScriptInterface::StructuredClone results = m_MapGen->GetResults();
// Parse data into simulation context
JS::RootedValue data(rq.cx);
+3 -3
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2017 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -52,11 +52,11 @@ public:
~CMapReader();
// LoadMap: try to load the map from given file; reinitialise the scene to new data if successful
void LoadMap(const VfsPath& pathname, JSRuntime* rt, JS::HandleValue settings, CTerrain*, WaterManager*, SkyManager*, CLightEnv*, CGameView*,
void LoadMap(const VfsPath& pathname, const ScriptContext& cx, JS::HandleValue settings, CTerrain*, WaterManager*, SkyManager*, CLightEnv*, CGameView*,
CCinemaManager*, CTriggerManager*, CPostprocManager* pPostproc, CSimulation2*, const CSimContext*,
int playerID, bool skipEntities);
void LoadRandomMap(const CStrW& scriptFile, JSRuntime* rt, JS::HandleValue settings, CTerrain*, WaterManager*, SkyManager*, CLightEnv*, CGameView*, CCinemaManager*, CTriggerManager*, CPostprocManager* pPostproc_, CSimulation2*, int playerID);
void LoadRandomMap(const CStrW& scriptFile, const ScriptContext& cx, JS::HandleValue settings, CTerrain*, WaterManager*, SkyManager*, CLightEnv*, CGameView*, CCinemaManager*, CTriggerManager*, CPostprocManager* pPostproc_, CSimulation2*, int playerID);
private:
// Load script settings for use by scripts
+9 -9
View File
@@ -88,16 +88,16 @@ void CGUIManager::SwitchPage(const CStrW& pageName, ScriptInterface* srcScriptIn
// The page stack is cleared (including the script context where initData came from),
// therefore we have to clone initData.
shared_ptr<ScriptInterface::StructuredClone> initDataClone;
ScriptInterface::StructuredClone initDataClone;
if (!initData.isUndefined())
initDataClone = srcScriptInterface->WriteStructuredClone(initData);
initDataClone = srcScriptInterface->WriteStructuredClone(initData, true);
m_PageStack.clear();
PushPage(pageName, initDataClone, JS::UndefinedHandleValue);
}
void CGUIManager::PushPage(const CStrW& pageName, shared_ptr<ScriptInterface::StructuredClone> initData, JS::HandleValue callbackFunction)
void CGUIManager::PushPage(const CStrW& pageName, ScriptInterface::StructuredClone initData, JS::HandleValue callbackFunction)
{
// Store the callback handler in the current GUI page before opening the new one
if (!m_PageStack.empty() && !callbackFunction.isUndefined())
@@ -109,7 +109,7 @@ void CGUIManager::PushPage(const CStrW& pageName, shared_ptr<ScriptInterface::St
m_PageStack.back().LoadPage(m_ScriptContext);
}
void CGUIManager::PopPage(shared_ptr<ScriptInterface::StructuredClone> args)
void CGUIManager::PopPage(ScriptInterface::StructuredClone args)
{
if (m_PageStack.size() < 2)
{
@@ -121,7 +121,7 @@ void CGUIManager::PopPage(shared_ptr<ScriptInterface::StructuredClone> args)
m_PageStack.back().PerformCallbackFunction(args);
}
CGUIManager::SGUIPage::SGUIPage(const CStrW& pageName, const shared_ptr<ScriptInterface::StructuredClone> initData)
CGUIManager::SGUIPage::SGUIPage(const CStrW& pageName, const ScriptInterface::StructuredClone initData)
: name(pageName), initData(initData), inputs(), gui(), callbackFunction()
{
}
@@ -129,7 +129,7 @@ CGUIManager::SGUIPage::SGUIPage(const CStrW& pageName, const shared_ptr<ScriptIn
void CGUIManager::SGUIPage::LoadPage(shared_ptr<ScriptContext> scriptContext)
{
// If we're hotloading then try to grab some data from the previous page
shared_ptr<ScriptInterface::StructuredClone> hotloadData;
ScriptInterface::StructuredClone hotloadData;
if (gui)
{
shared_ptr<ScriptInterface> scriptInterface = gui->GetScriptInterface();
@@ -138,7 +138,7 @@ void CGUIManager::SGUIPage::LoadPage(shared_ptr<ScriptContext> scriptContext)
JS::RootedValue global(rq.cx, rq.globalValue());
JS::RootedValue hotloadDataVal(rq.cx);
scriptInterface->CallFunction(global, "getHotloadData", &hotloadDataVal);
hotloadData = scriptInterface->WriteStructuredClone(hotloadDataVal);
hotloadData = scriptInterface->WriteStructuredClone(hotloadDataVal, true);
}
g_CursorName = g_DefaultCursor;
@@ -232,10 +232,10 @@ void CGUIManager::SGUIPage::SetCallbackFunction(ScriptInterface& scriptInterface
return;
}
callbackFunction = std::make_shared<JS::PersistentRootedValue>(scriptInterface.GetJSRuntime(), callbackFunc);
callbackFunction = std::make_shared<JS::PersistentRootedValue>(scriptInterface.GetGeneralJSContext(), callbackFunc);
}
void CGUIManager::SGUIPage::PerformCallbackFunction(shared_ptr<ScriptInterface::StructuredClone> args)
void CGUIManager::SGUIPage::PerformCallbackFunction(ScriptInterface::StructuredClone args)
{
if (!callbackFunction)
return;
+6 -6
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -69,13 +69,13 @@ public:
* user inputs.
* If given, the callbackHandler function will be executed once this page is closed.
*/
void PushPage(const CStrW& pageName, shared_ptr<ScriptInterface::StructuredClone> initData, JS::HandleValue callbackFunc);
void PushPage(const CStrW& pageName, ScriptInterface::StructuredClone initData, JS::HandleValue callbackFunc);
/**
* Unload the currently active GUI page, and make the previous page active.
* (There must be at least two pages when you call this.)
*/
void PopPage(shared_ptr<ScriptInterface::StructuredClone> args);
void PopPage(ScriptInterface::StructuredClone args);
/**
* Called when a file has been modified, to hotload changes.
@@ -132,7 +132,7 @@ private:
/**
* Initializes the data that will be used to create the CGUI page one or multiple times (hotloading).
*/
SGUIPage(const CStrW& pageName, const shared_ptr<ScriptInterface::StructuredClone> initData);
SGUIPage(const CStrW& pageName, const ScriptInterface::StructuredClone initData);
/**
* Create the CGUI with it's own ScriptInterface. Deletes the previous CGUI if it existed.
@@ -147,11 +147,11 @@ private:
/**
* Execute the stored callback function with the given arguments.
*/
void PerformCallbackFunction(shared_ptr<ScriptInterface::StructuredClone> args);
void PerformCallbackFunction(ScriptInterface::StructuredClone args);
CStrW name;
std::unordered_set<VfsPath> inputs; // for hotloading
shared_ptr<ScriptInterface::StructuredClone> initData; // data to be passed to the init() function
ScriptInterface::StructuredClone initData; // data to be passed to the init() function
shared_ptr<CGUI> gui; // the actual GUI page
/**
+4 -4
View File
@@ -76,7 +76,7 @@ IGUIObject::~IGUIObject()
delete p.second;
if (!m_ScriptHandlers.empty())
JS_RemoveExtraGCRootsTracer(m_pGUI.GetScriptInterface()->GetJSRuntime(), Trace, this);
JS_RemoveExtraGCRootsTracer(m_pGUI.GetScriptInterface()->GetGeneralJSContext(), Trace, this);
// m_Children is deleted along all other GUI Objects in the CGUI destructor
}
@@ -332,7 +332,7 @@ void IGUIObject::RegisterScriptHandler(const CStr& eventName, const CStr& Code,
void IGUIObject::SetScriptHandler(const CStr& eventName, JS::HandleObject Function)
{
if (m_ScriptHandlers.empty())
JS_AddExtraGCRootsTracer(m_pGUI.GetScriptInterface()->GetJSRuntime(), Trace, this);
JS_AddExtraGCRootsTracer(m_pGUI.GetScriptInterface()->GetGeneralJSContext(), Trace, this);
m_ScriptHandlers[eventName] = JS::Heap<JSObject*>(Function);
@@ -353,7 +353,7 @@ void IGUIObject::UnsetScriptHandler(const CStr& eventName)
m_ScriptHandlers.erase(it);
if (m_ScriptHandlers.empty())
JS_RemoveExtraGCRootsTracer(m_pGUI.GetScriptInterface()->GetJSRuntime(), Trace, this);
JS_RemoveExtraGCRootsTracer(m_pGUI.GetScriptInterface()->GetGeneralJSContext(), Trace, this);
{
auto it = m_pGUI.m_EventIGUIObjects.find(eventName);
if (it != m_pGUI.m_EventIGUIObjects.end())
@@ -402,7 +402,7 @@ InReaction IGUIObject::SendMouseEvent(EGUIMessageType type, const CStr& eventNam
"y", mousePos.y,
"buttons", m_pGUI.GetMouseButtons());
JS::AutoValueVector paramData(rq.cx);
paramData.append(mouse);
(void)paramData.append(mouse);
ScriptEvent(eventName, paramData);
return msg.skipped ? IN_PASS : IN_HANDLED;
@@ -29,7 +29,7 @@
// Functions aren't supported for example!
void JSI_GUIManager::PushGuiPage(ScriptInterface::CmptPrivate* pCmptPrivate, const std::wstring& name, JS::HandleValue initData, JS::HandleValue callbackFunction)
{
g_GUI->PushPage(name, pCmptPrivate->pScriptInterface->WriteStructuredClone(initData), callbackFunction);
g_GUI->PushPage(name, pCmptPrivate->pScriptInterface->WriteStructuredClone(initData, true), callbackFunction);
}
void JSI_GUIManager::SwitchGuiPage(ScriptInterface::CmptPrivate* pCmptPrivate, const std::wstring& name, JS::HandleValue initData)
@@ -46,7 +46,7 @@ void JSI_GUIManager::PopGuiPage(ScriptInterface::CmptPrivate* pCmptPrivate, JS::
return;
}
g_GUI->PopPage(pCmptPrivate->pScriptInterface->WriteStructuredClone(args));
g_GUI->PopPage(pCmptPrivate->pScriptInterface->WriteStructuredClone(args, true));
}
JS::Value JSI_GUIManager::GetGUIObjectByName(ScriptInterface::CmptPrivate* pCmptPrivate, const std::string& name)
+5 -2
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -23,7 +23,10 @@
#include "scriptinterface/ScriptInterface.h"
JSClass JSI_GUISize::JSI_class = {
"GUISize", 0,
"GUISize", 0, &JSI_GUISize::JSI_classops
};
JSClassOps JSI_GUISize::JSI_classops = {
nullptr, nullptr,
nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
+2 -1
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -24,6 +24,7 @@
namespace JSI_GUISize
{
extern JSClass JSI_class;
extern JSClassOps JSI_classops;
extern JSPropertySpec JSI_props[];
extern JSFunctionSpec JSI_methods[];
@@ -27,7 +27,10 @@
#include "scriptinterface/ScriptInterface.h"
JSClass JSI_IGUIObject::JSI_class = {
"GUIObject", JSCLASS_HAS_PRIVATE,
"GUIObject", JSCLASS_HAS_PRIVATE, &JSI_IGUIObject::JSI_classops
};
JSClassOps JSI_IGUIObject::JSI_classops = {
nullptr,
JSI_IGUIObject::deleteProperty,
JSI_IGUIObject::getProperty,
@@ -172,7 +175,7 @@ bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::Handle
}
if (e->SettingExists(propName))
return e->m_Settings[propName]->FromJSVal(rq, vp, true) ? result.succeed() : result.fail(JSMSG_TYPE_ERR_BAD_ARGS);
return e->m_Settings[propName]->FromJSVal(rq, vp, true) ? result.succeed() : result.fail(JSMSG_USER_DEFINED_ERROR);
LOGERROR("Property '%s' does not exist!", propName.c_str());
return result.fail(JSMSG_UNDEFINED_PROP);
@@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -23,6 +23,7 @@
namespace JSI_IGUIObject
{
extern JSClass JSI_class;
extern JSClassOps JSI_classops;
extern JSFunctionSpec JSI_methods[];
void RegisterScriptClass(ScriptInterface& scriptInterface);
+1 -1
View File
@@ -66,7 +66,7 @@ public:
JS::RootedValue val(rq.cx);
scriptInterface.CreateObject(rq, &val);
std::shared_ptr<ScriptInterface::StructuredClone> data = scriptInterface.WriteStructuredClone(JS::NullHandleValue);
ScriptInterface::StructuredClone data = scriptInterface.WriteStructuredClone(JS::NullHandleValue, true);
g_GUI->PushPage(L"hotkey/page_hotkey.xml", data, JS::UndefinedHandleValue);
// Press 'a'.
+4 -4
View File
@@ -94,7 +94,7 @@ XmppClient::XmppClient(const ScriptInterface* scriptInterface, const std::string
m_PlayerMapUpdate(false)
{
if (m_ScriptInterface)
JS_AddExtraGCRootsTracer(m_ScriptInterface->GetJSRuntime(), XmppClient::Trace, this);
JS_AddExtraGCRootsTracer(m_ScriptInterface->GetGeneralJSContext(), XmppClient::Trace, this);
// Read lobby configuration from default.cfg
std::string sXpartamupp;
@@ -192,7 +192,7 @@ XmppClient::~XmppClient()
glooxwrapper::Tag::free(t);
if (m_ScriptInterface)
JS_RemoveExtraGCRootsTracer(m_ScriptInterface->GetJSRuntime(), XmppClient::Trace, this);
JS_RemoveExtraGCRootsTracer(m_ScriptInterface->GetGeneralJSContext(), XmppClient::Trace, this);
}
void XmppClient::TraceMember(JSTracer* trc)
@@ -736,7 +736,7 @@ JS::Value XmppClient::GuiPollNewMessages(const ScriptInterface& scriptInterface)
m_GuiMessageQueue.clear();
// Copy the messages over to the caller script interface.
return scriptInterface.CloneValueFromOtherCompartment(*m_ScriptInterface, messages);
return scriptInterface.CloneValueFromOtherCompartment(*m_ScriptInterface, messages, false);
}
JS::Value XmppClient::GuiPollHistoricMessages(const ScriptInterface& scriptInterface)
@@ -754,7 +754,7 @@ JS::Value XmppClient::GuiPollHistoricMessages(const ScriptInterface& scriptInter
m_ScriptInterface->SetPropertyInt(messages, j++, message);
// Copy the messages over to the caller script interface.
return scriptInterface.CloneValueFromOtherCompartment(*m_ScriptInterface, messages);
return scriptInterface.CloneValueFromOtherCompartment(*m_ScriptInterface, messages, false);
}
/**
+3 -3
View File
@@ -71,7 +71,7 @@ CNetClient::CNetClient(CGame* game, bool isLocalClient) :
m_Session(NULL),
m_UserName(L"anonymous"),
m_HostID((u32)-1), m_ClientTurnManager(NULL), m_Game(game),
m_GameAttributes(game->GetSimulation2()->GetScriptInterface().GetJSRuntime()),
m_GameAttributes(game->GetSimulation2()->GetScriptInterface().GetGeneralJSContext()),
m_IsLocalClient(isLocalClient),
m_LastConnectionCheck(0),
m_Rejoin(false)
@@ -80,7 +80,7 @@ CNetClient::CNetClient(CGame* game, bool isLocalClient) :
void* context = this;
JS_AddExtraGCRootsTracer(GetScriptInterface().GetJSRuntime(), CNetClient::Trace, this);
JS_AddExtraGCRootsTracer(GetScriptInterface().GetGeneralJSContext(), CNetClient::Trace, this);
// Set up transitions for session
AddTransition(NCS_UNCONNECTED, (uint)NMT_CONNECT_COMPLETE, NCS_CONNECT, (void*)&OnConnect, context);
@@ -144,7 +144,7 @@ CNetClient::CNetClient(CGame* game, bool isLocalClient) :
CNetClient::~CNetClient()
{
DestroyConnection();
JS_RemoveExtraGCRootsTracer(GetScriptInterface().GetJSRuntime(), CNetClient::Trace, this);
JS_RemoveExtraGCRootsTracer(GetScriptInterface().GetGeneralJSContext(), CNetClient::Trace, this);
}
void CNetClient::TraceMember(JSTracer *trc)
+6 -6
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2017 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -110,18 +110,18 @@ public:
};
CSimulationMessage::CSimulationMessage(const ScriptInterface& scriptInterface) :
CNetMessage(NMT_SIMULATION_COMMAND), m_ScriptInterface(scriptInterface), m_Data(scriptInterface.GetJSRuntime())
CNetMessage(NMT_SIMULATION_COMMAND), m_ScriptInterface(scriptInterface), m_Data(scriptInterface.GetGeneralJSContext())
{
}
CSimulationMessage::CSimulationMessage(const ScriptInterface& scriptInterface, u32 client, i32 player, u32 turn, JS::HandleValue data) :
CNetMessage(NMT_SIMULATION_COMMAND), m_ScriptInterface(scriptInterface),
m_Client(client), m_Player(player), m_Turn(turn), m_Data(scriptInterface.GetJSRuntime(), data)
m_Client(client), m_Player(player), m_Turn(turn), m_Data(scriptInterface.GetGeneralJSContext(), data)
{
}
CSimulationMessage::CSimulationMessage(const CSimulationMessage& orig) :
m_Data(orig.m_ScriptInterface.GetJSRuntime()),
m_Data(orig.m_ScriptInterface.GetGeneralJSContext()),
m_Client(orig.m_Client),
m_Player(orig.m_Player),
m_ScriptInterface(orig.m_ScriptInterface),
@@ -185,13 +185,13 @@ CStr CSimulationMessage::ToString() const
CGameSetupMessage::CGameSetupMessage(const ScriptInterface& scriptInterface) :
CNetMessage(NMT_GAME_SETUP), m_ScriptInterface(scriptInterface), m_Data(scriptInterface.GetJSRuntime())
CNetMessage(NMT_GAME_SETUP), m_ScriptInterface(scriptInterface), m_Data(scriptInterface.GetGeneralJSContext())
{
}
CGameSetupMessage::CGameSetupMessage(const ScriptInterface& scriptInterface, JS::HandleValue data) :
CNetMessage(NMT_GAME_SETUP), m_ScriptInterface(scriptInterface),
m_Data(scriptInterface.GetJSRuntime(), data)
m_Data(scriptInterface.GetGeneralJSContext(), data)
{
}
+1 -1
View File
@@ -389,7 +389,7 @@ void CNetServerWorker::Run()
// We create a new ScriptContext for this network thread, with a single ScriptInterface.
shared_ptr<ScriptContext> netServerContext = ScriptContext::CreateContext();
m_ScriptInterface = new ScriptInterface("Engine", "Net server", netServerContext);
m_GameAttributes.init(m_ScriptInterface->GetJSRuntime(), JS::UndefinedValue());
m_GameAttributes.init(m_ScriptInterface->GetGeneralJSContext(), JS::UndefinedValue());
while (true)
{
@@ -163,7 +163,7 @@ JS::Value JSI_Network::PollNetworkClient(ScriptInterface::CmptPrivate* pCmptPriv
ScriptRequest rqNet(g_NetClient->GetScriptInterface());
JS::RootedValue pollNet(rqNet.cx);
g_NetClient->GuiPoll(&pollNet);
return pCmptPrivate->pScriptInterface->CloneValueFromOtherCompartment(g_NetClient->GetScriptInterface(), pollNet);
return pCmptPrivate->pScriptInterface->CloneValueFromOtherCompartment(g_NetClient->GetScriptInterface(), pollNet, false);
}
void JSI_Network::SetNetworkGameAttributes(ScriptInterface::CmptPrivate* pCmptPrivate, JS::HandleValue attribs1)
+2 -2
View File
@@ -243,7 +243,7 @@ void CGame::RegisterInit(const JS::HandleValue attribs, const std::string& saved
scriptInterface.GetProperty(attribs, "script", scriptFile);
scriptInterface.GetProperty(attribs, "settings", &settings);
m_World->RegisterInitRMS(scriptFile, scriptInterface.GetJSRuntime(), settings, m_PlayerID);
m_World->RegisterInitRMS(scriptFile, *scriptInterface.GetContext(), settings, m_PlayerID);
}
else
{
@@ -252,7 +252,7 @@ void CGame::RegisterInit(const JS::HandleValue attribs, const std::string& saved
scriptInterface.GetProperty(attribs, "map", mapFile);
scriptInterface.GetProperty(attribs, "settings", &settings);
m_World->RegisterInit(mapFile, scriptInterface.GetJSRuntime(), settings, m_PlayerID);
m_World->RegisterInit(mapFile, *scriptInterface.GetContext(), settings, m_PlayerID);
}
if (m_GameView)
RegMemFun(g_Renderer.GetSingletonPtr()->GetWaterManager(), &WaterManager::LoadWaterTextures, L"LoadWaterTextures", 80);
-1
View File
@@ -28,7 +28,6 @@
#include "ps/GameSetup/GameSetup.h"
#include "ps/GameSetup/Paths.h"
#include "ps/Pyrogenesis.h"
#include "scriptinterface/ScriptContext.h"
#include "scriptinterface/ScriptInterface.h"
std::vector<CStr> g_modsLoaded;
+2 -2
View File
@@ -488,7 +488,7 @@ namespace
const ScriptInterface& m_ScriptInterface;
JS::PersistentRooted<JS::Value> m_Root;
DumpTable(const ScriptInterface& scriptInterface, JS::HandleValue root) :
m_ScriptInterface(scriptInterface), m_Root(scriptInterface.GetJSRuntime(), root)
m_ScriptInterface(scriptInterface), m_Root(scriptInterface.GetGeneralJSContext(), root)
{
}
@@ -496,7 +496,7 @@ namespace
// automatic move constructor
DumpTable(DumpTable && original) :
m_ScriptInterface(original.m_ScriptInterface),
m_Root(original.m_ScriptInterface.GetJSRuntime(), original.m_Root.get())
m_Root(original.m_ScriptInterface.GetGeneralJSContext(), original.m_Root.get())
{
}
+3 -3
View File
@@ -35,7 +35,7 @@
// TODO: we ought to check version numbers when loading files
Status SavedGames::SavePrefix(const CStrW& prefix, const CStrW& description, CSimulation2& simulation, const shared_ptr<ScriptInterface::StructuredClone>& guiMetadataClone)
Status SavedGames::SavePrefix(const CStrW& prefix, const CStrW& description, CSimulation2& simulation, const ScriptInterface::StructuredClone& guiMetadataClone)
{
// Determine the filename to save under
const VfsPath basenameFormat(L"saves/" + prefix + L"-%04d");
@@ -50,7 +50,7 @@ Status SavedGames::SavePrefix(const CStrW& prefix, const CStrW& description, CSi
return Save(filename.Filename().string(), description, simulation, guiMetadataClone);
}
Status SavedGames::Save(const CStrW& name, const CStrW& description, CSimulation2& simulation, const shared_ptr<ScriptInterface::StructuredClone>& guiMetadataClone)
Status SavedGames::Save(const CStrW& name, const CStrW& description, CSimulation2& simulation, const ScriptInterface::StructuredClone& guiMetadataClone)
{
ScriptRequest rq(simulation.GetScriptInterface());
@@ -161,7 +161,7 @@ public:
*/
CGameLoader(const ScriptInterface& scriptInterface, std::string* savedState) :
m_ScriptInterface(scriptInterface),
m_Metadata(scriptInterface.GetJSRuntime()),
m_Metadata(scriptInterface.GetGeneralJSContext()),
m_SavedState(savedState)
{
}
+3 -3
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2018 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -45,7 +45,7 @@ namespace SavedGames
* @param guiMetadataClone if not NULL, store some UI-related data with the saved game
* @return INFO::OK if successfully saved, else an error Status
*/
Status Save(const CStrW& name, const CStrW& description, CSimulation2& simulation, const shared_ptr<ScriptInterface::StructuredClone>& guiMetadataClone);
Status Save(const CStrW& name, const CStrW& description, CSimulation2& simulation, const ScriptInterface::StructuredClone& guiMetadataClone);
/**
* Create new saved game archive with given prefix and simulation data
@@ -56,7 +56,7 @@ namespace SavedGames
* @param guiMetadataClone if not NULL, store some UI-related data with the saved game
* @return INFO::OK if successfully saved, else an error Status
*/
Status SavePrefix(const CStrW& prefix, const CStrW& description, CSimulation2& simulation, const shared_ptr<ScriptInterface::StructuredClone>& guiMetadataClone);
Status SavePrefix(const CStrW& prefix, const CStrW& description, CSimulation2& simulation, const ScriptInterface::StructuredClone& guiMetadataClone);
/**
* Load saved game archive with the given name
+5 -5
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2017 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -65,7 +65,7 @@ CWorld::CWorld(CGame *pGame):
/**
* Initializes the game world with the attributes provided.
**/
void CWorld::RegisterInit(const CStrW& mapFile, JSRuntime* rt, JS::HandleValue settings, int playerID)
void CWorld::RegisterInit(const CStrW& mapFile, const ScriptContext& cx, JS::HandleValue settings, int playerID)
{
// Load the map, if one was specified
if (mapFile.length())
@@ -75,7 +75,7 @@ void CWorld::RegisterInit(const CStrW& mapFile, JSRuntime* rt, JS::HandleValue s
try
{
CTriggerManager* pTriggerManager = NULL;
m_MapReader->LoadMap(mapfilename, rt, settings, m_Terrain,
m_MapReader->LoadMap(mapfilename, cx, settings, m_Terrain,
CRenderer::IsInitialised() ? g_Renderer.GetWaterManager() : NULL,
CRenderer::IsInitialised() ? g_Renderer.GetSkyManager() : NULL,
&g_LightEnv, m_pGame->GetView(),
@@ -94,11 +94,11 @@ void CWorld::RegisterInit(const CStrW& mapFile, JSRuntime* rt, JS::HandleValue s
}
}
void CWorld::RegisterInitRMS(const CStrW& scriptFile, JSRuntime* rt, JS::HandleValue settings, int playerID)
void CWorld::RegisterInitRMS(const CStrW& scriptFile, const ScriptContext& cx, JS::HandleValue settings, int playerID)
{
// If scriptFile is empty, a blank map will be generated using settings (no RMS run)
CTriggerManager* pTriggerManager = NULL;
m_MapReader->LoadRandomMap(scriptFile, rt, settings, m_Terrain,
m_MapReader->LoadRandomMap(scriptFile, cx, settings, m_Terrain,
CRenderer::IsInitialised() ? g_Renderer.GetWaterManager() : NULL,
CRenderer::IsInitialised() ? g_Renderer.GetSkyManager() : NULL,
&g_LightEnv, m_pGame->GetView(),
+3 -3
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2017 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -71,12 +71,12 @@ public:
/*
Initialize the World - load the map and all objects
*/
void RegisterInit(const CStrW& mapFile, JSRuntime* rt, JS::HandleValue settings, int playerID);
void RegisterInit(const CStrW& mapFile, const ScriptContext& cx, JS::HandleValue settings, int playerID);
/*
Initialize the World - generate and load the random map
*/
void RegisterInitRMS(const CStrW& scriptFile, JSRuntime* rt, JS::HandleValue settings, int playerID);
void RegisterInitRMS(const CStrW& scriptFile, const ScriptContext& cx, JS::HandleValue settings, int playerID);
/**
* Explicitly delete m_MapReader once the map has finished loading.
+1 -1
View File
@@ -51,7 +51,7 @@ void JSI_Game::StartGame(ScriptInterface::CmptPrivate* pCmptPrivate, JS::HandleV
ScriptRequest rqSim(sim->GetScriptInterface());
JS::RootedValue gameAttribs(rqSim.cx,
sim->GetScriptInterface().CloneValueFromOtherCompartment(*(pCmptPrivate->pScriptInterface), attribs));
sim->GetScriptInterface().CloneValueFromOtherCompartment(*(pCmptPrivate->pScriptInterface), attribs, false));
g_Game->SetPlayerID(playerID);
g_Game->StartGame(&gameAttribs, "");
@@ -40,14 +40,14 @@ bool JSI_SavedGame::DeleteSavedGame(ScriptInterface::CmptPrivate* UNUSED(pCmptPr
void JSI_SavedGame::SaveGame(ScriptInterface::CmptPrivate* pCmptPrivate, const std::wstring& filename, const std::wstring& description, JS::HandleValue GUIMetadata)
{
shared_ptr<ScriptInterface::StructuredClone> GUIMetadataClone = pCmptPrivate->pScriptInterface->WriteStructuredClone(GUIMetadata);
ScriptInterface::StructuredClone GUIMetadataClone = pCmptPrivate->pScriptInterface->WriteStructuredClone(GUIMetadata, false);
if (SavedGames::Save(filename, description, *g_Game->GetSimulation2(), GUIMetadataClone) < 0)
LOGERROR("Failed to save game");
}
void JSI_SavedGame::SaveGamePrefix(ScriptInterface::CmptPrivate* pCmptPrivate, const std::wstring& prefix, const std::wstring& description, JS::HandleValue GUIMetadata)
{
shared_ptr<ScriptInterface::StructuredClone> GUIMetadataClone = pCmptPrivate->pScriptInterface->WriteStructuredClone(GUIMetadata);
ScriptInterface::StructuredClone GUIMetadataClone = pCmptPrivate->pScriptInterface->WriteStructuredClone(GUIMetadata, false);
if (SavedGames::SavePrefix(prefix, description, *g_Game->GetSimulation2(), GUIMetadataClone) < 0)
LOGERROR("Failed to save game");
}
@@ -99,7 +99,7 @@ JS::Value JSI_SavedGame::StartSavedGame(ScriptInterface::CmptPrivate* pCmptPriva
ScriptRequest rqGame(sim->GetScriptInterface());
JS::RootedValue gameContextMetadata(rqGame.cx,
sim->GetScriptInterface().CloneValueFromOtherCompartment(*(pCmptPrivate->pScriptInterface), guiContextMetadata));
sim->GetScriptInterface().CloneValueFromOtherCompartment(*(pCmptPrivate->pScriptInterface), guiContextMetadata, false));
JS::RootedValue gameInitAttributes(rqGame.cx);
sim->GetScriptInterface().GetProperty(gameContextMetadata, "initAttributes", &gameInitAttributes);
+1 -1
View File
@@ -54,7 +54,7 @@ struct BuildDirEntListState
BuildDirEntListState(ScriptInterface* scriptInterface)
: pScriptInterface(scriptInterface),
filename_array(scriptInterface->GetJSRuntime()),
filename_array(scriptInterface->GetGeneralJSContext()),
cur_idx(0)
{
ScriptRequest rq(pScriptInterface);
+4 -4
View File
@@ -180,7 +180,7 @@ bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, R& ret
ScriptRequest rq(this);
JS::RootedValue jsRet(rq.cx);
JS::AutoValueVector argv(rq.cx);
argv.resize(sizeof...(Ts));
(void)argv.resize(sizeof...(Ts));
AssignOrToJSValHelper<0>(rq, argv, params...);
if (!CallFunction_(val, name, argv, &jsRet))
return false;
@@ -193,7 +193,7 @@ bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, JS::Ro
ScriptRequest rq(this);
JS::MutableHandle<R> jsRet(ret);
JS::AutoValueVector argv(rq.cx);
argv.resize(sizeof...(Ts));
(void)argv.resize(sizeof...(Ts));
AssignOrToJSValHelper<0>(rq, argv, params...);
return CallFunction_(val, name, argv, jsRet);
}
@@ -203,7 +203,7 @@ bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, JS::Mu
{
ScriptRequest rq(this);
JS::AutoValueVector argv(rq.cx);
argv.resize(sizeof...(Ts));
(void)argv.resize(sizeof...(Ts));
AssignOrToJSValHelper<0>(rq, argv, params...);
return CallFunction_(val, name, argv, ret);
}
@@ -215,7 +215,7 @@ bool ScriptInterface::CallFunctionVoid(JS::HandleValue val, const char* name, co
ScriptRequest rq(this);
JS::RootedValue jsRet(rq.cx);
JS::AutoValueVector argv(rq.cx);
argv.resize(sizeof...(Ts));
(void)argv.resize(sizeof...(Ts));
AssignOrToJSValHelper<0>(rq, argv, params...);
return CallFunction_(val, name, argv, &jsRet);
}
+30 -35
View File
@@ -25,7 +25,7 @@
#include "scriptinterface/ScriptInterface.h"
void GCSliceCallbackHook(JSRuntime* UNUSED(rt), JS::GCProgress progress, const JS::GCDescription& UNUSED(desc))
void GCSliceCallbackHook(JSContext* UNUSED(cx), JS::GCProgress progress, const JS::GCDescription& UNUSED(desc))
{
/*
* During non-incremental GC, the GC is bracketed by JSGC_CYCLE_BEGIN/END
@@ -69,7 +69,7 @@ void GCSliceCallbackHook(JSRuntime* UNUSED(rt), JS::GCProgress progress, const J
if (progress == JS::GCProgress::GC_CYCLE_BEGIN)
printf("starting cycle ===========================================\n");
const char16_t* str = desc.formatMessage(rt);
const char16_t* str = desc.formatMessage(cx);
int len = 0;
for(int i = 0; i < 10000; i++)
@@ -103,35 +103,32 @@ ScriptContext::ScriptContext(int contextSize, int heapGrowthBytesGCTrigger):
{
ENSURE(ScriptEngine::IsInitialised() && "The ScriptEngine must be initialized before constructing any ScriptContexts!");
m_rt = JS_NewRuntime(contextSize, JS::DefaultNurseryBytes, nullptr);
ENSURE(m_rt); // TODO: error handling
m_cx = JS_NewContext(contextSize, JS::DefaultNurseryBytes, nullptr);
ENSURE(m_cx); // TODO: error handling
JS::SetGCSliceCallback(m_rt, GCSliceCallbackHook);
ENSURE(JS::InitSelfHostedCode(m_cx));
JS_SetGCParameter(m_rt, JSGC_MAX_MALLOC_BYTES, m_ContextSize);
JS_SetGCParameter(m_rt, JSGC_MAX_BYTES, m_ContextSize);
JS_SetGCParameter(m_rt, JSGC_MODE, JSGC_MODE_INCREMENTAL);
JS::SetGCSliceCallback(m_cx, GCSliceCallbackHook);
JS_SetGCParameter(m_cx, JSGC_MAX_MALLOC_BYTES, m_ContextSize);
JS_SetGCParameter(m_cx, JSGC_MAX_BYTES, m_ContextSize);
JS_SetGCParameter(m_cx, JSGC_MODE, JSGC_MODE_INCREMENTAL);
// The whole heap-growth mechanism seems to work only for non-incremental GCs.
// We disable it to make it more clear if full GCs happen triggered by this JSAPI internal mechanism.
JS_SetGCParameter(m_rt, JSGC_DYNAMIC_HEAP_GROWTH, false);
JS_SetGCParameter(m_cx, JSGC_DYNAMIC_HEAP_GROWTH, false);
JS_SetErrorReporter(m_rt, ScriptException::ErrorReporter);
m_cx = JS_NewContext(m_rt, STACK_CHUNK_SIZE);
ENSURE(m_cx); // TODO: error handling
JS_SetOffthreadIonCompilationEnabled(m_rt, true);
JS_SetOffthreadIonCompilationEnabled(m_cx, true);
// For GC debugging:
// JS_SetGCZeal(m_cx, 2, JS_DEFAULT_ZEAL_FREQ);
JS_SetContextPrivate(m_cx, nullptr);
JS_SetGlobalJitCompilerOption(m_rt, JSJITCOMPILER_ION_ENABLE, 1);
JS_SetGlobalJitCompilerOption(m_rt, JSJITCOMPILER_BASELINE_ENABLE, 1);
JS_SetGlobalJitCompilerOption(m_cx, JSJITCOMPILER_ION_ENABLE, 1);
JS_SetGlobalJitCompilerOption(m_cx, JSJITCOMPILER_BASELINE_ENABLE, 1);
JS::RuntimeOptionsRef(m_cx)
JS::ContextOptionsRef(m_cx)
.setExtraWarnings(true)
.setWerror(false)
.setStrictMode(true);
@@ -144,8 +141,6 @@ ScriptContext::~ScriptContext()
ENSURE(ScriptEngine::IsInitialised() && "The ScriptEngine must be active (initialized and not yet shut down) when destroying a ScriptContext!");
JS_DestroyContext(m_cx);
JS_DestroyRuntime(m_rt);
ScriptEngine::GetSingleton().UnRegisterContext(m_cx);
}
@@ -165,7 +160,7 @@ void ScriptContext::MaybeIncrementalGC(double delay)
{
PROFILE2("MaybeIncrementalGC");
if (JS::IsIncrementalGCEnabled(m_rt))
if (JS::IsIncrementalGCEnabled(m_cx))
{
// The idea is to get the heap size after a completed GC and trigger the next GC when the heap size has
// reached m_LastGCBytes + X.
@@ -184,7 +179,7 @@ void ScriptContext::MaybeIncrementalGC(double delay)
m_LastGCCheck = timer_Time();
int gcBytes = JS_GetGCParameter(m_rt, JSGC_BYTES);
int gcBytes = JS_GetGCParameter(m_cx, JSGC_BYTES);
#if GC_DEBUG_PRINT
std::cout << "gcBytes: " << gcBytes / 1024 << " KB" << std::endl;
@@ -201,10 +196,10 @@ void ScriptContext::MaybeIncrementalGC(double delay)
// Run an additional incremental GC slice if the currently running incremental GC isn't over yet
// ... or
// start a new incremental GC if the JS heap size has grown enough for a GC to make sense
if (JS::IsIncrementalGCInProgress(m_rt) || (gcBytes - m_LastGCBytes > m_HeapGrowthBytesGCTrigger))
if (JS::IsIncrementalGCInProgress(m_cx) || (gcBytes - m_LastGCBytes > m_HeapGrowthBytesGCTrigger))
{
#if GC_DEBUG_PRINT
if (JS::IsIncrementalGCInProgress(m_rt))
if (JS::IsIncrementalGCInProgress(m_cx))
printf("An incremental GC cycle is in progress. \n");
else
printf("GC needed because JSGC_BYTES - m_LastGCBytes > m_HeapGrowthBytesGCTrigger \n"
@@ -218,13 +213,13 @@ void ScriptContext::MaybeIncrementalGC(double delay)
// fast enough.
if (gcBytes > m_ContextSize / 2)
{
if (JS::IsIncrementalGCInProgress(m_rt))
if (JS::IsIncrementalGCInProgress(m_cx))
{
#if GC_DEBUG_PRINT
printf("Finishing incremental GC because gcBytes > m_ContextSize / 2. \n");
#endif
PrepareCompartmentsForIncrementalGC();
JS::FinishIncrementalGC(m_rt, JS::gcreason::REFRESH_FRAME);
JS::FinishIncrementalGC(m_cx, JS::gcreason::REFRESH_FRAME);
}
else
{
@@ -240,23 +235,23 @@ void ScriptContext::MaybeIncrementalGC(double delay)
#if GC_DEBUG_PRINT
printf("Running full GC because gcBytes > m_ContextSize / 2. \n");
#endif
JS_GC(m_rt);
JS_GC(m_cx);
}
}
}
else
{
#if GC_DEBUG_PRINT
if (!JS::IsIncrementalGCInProgress(m_rt))
if (!JS::IsIncrementalGCInProgress(m_cx))
printf("Starting incremental GC \n");
else
printf("Running incremental GC slice \n");
#endif
PrepareCompartmentsForIncrementalGC();
if (!JS::IsIncrementalGCInProgress(m_rt))
JS::StartIncrementalGC(m_rt, GC_NORMAL, JS::gcreason::REFRESH_FRAME, GCSliceTimeBudget);
if (!JS::IsIncrementalGCInProgress(m_cx))
JS::StartIncrementalGC(m_cx, GC_NORMAL, JS::gcreason::REFRESH_FRAME, GCSliceTimeBudget);
else
JS::IncrementalGCSlice(m_rt, JS::gcreason::REFRESH_FRAME, GCSliceTimeBudget);
JS::IncrementalGCSlice(m_cx, JS::gcreason::REFRESH_FRAME, GCSliceTimeBudget);
}
m_LastGCBytes = gcBytes;
}
@@ -265,10 +260,10 @@ void ScriptContext::MaybeIncrementalGC(double delay)
void ScriptContext::ShrinkingGC()
{
JS_SetGCParameter(m_rt, JSGC_MODE, JSGC_MODE_COMPARTMENT);
JS::PrepareForFullGC(m_rt);
JS::GCForReason(m_rt, GC_SHRINK, JS::gcreason::REFRESH_FRAME);
JS_SetGCParameter(m_rt, JSGC_MODE, JSGC_MODE_INCREMENTAL);
JS_SetGCParameter(m_cx, JSGC_MODE, JSGC_MODE_ZONE);
JS::PrepareForFullGC(m_cx);
JS::GCForReason(m_cx, GC_SHRINK, JS::gcreason::REFRESH_FRAME);
JS_SetGCParameter(m_cx, JSGC_MODE, JSGC_MODE_INCREMENTAL);
}
void ScriptContext::PrepareCompartmentsForIncrementalGC() const
+3 -8
View File
@@ -23,16 +23,14 @@
#include <sstream>
constexpr int STACK_CHUNK_SIZE = 8192;
// Those are minimal defaults. The runtime for the main game is larger and GCs upon a larger growth.
constexpr int DEFAULT_CONTEXT_SIZE = 16 * 1024 * 1024;
constexpr int DEFAULT_HEAP_GROWTH_BYTES_GCTRIGGER = 2 * 1024 * 1024;
/**
* Abstraction around a SpiderMonkey JSRuntime/JSContext.
* Abstraction around a SpiderMonkey JSContext.
*
* A single ScriptContext, with the associated runtime and context,
* A single ScriptContext, with the associated context,
* should only be used on a single thread.
*
* (One means to share data between threads and contexts is to create
@@ -76,12 +74,10 @@ public:
void RegisterCompartment(JSCompartment* cmpt);
void UnRegisterCompartment(JSCompartment* cmpt);
JSRuntime* GetJSRuntime() const { return m_rt; }
/**
* GetGeneralJSContext returns the context without starting a GC request and without
* entering any compartment. It should only be used in specific situations, such as
* creating a new compartment, or as an unsafe alternative to GetJSRuntime.
* creating a new compartment, or when initializing a persistent rooted.
* If you need the compartmented context of a ScriptInterface, you should create a
* ScriptRequest and use the context from that.
*/
@@ -89,7 +85,6 @@ public:
private:
JSRuntime* m_rt;
JSContext* m_cx;
void PrepareCompartmentsForIncrementalGC() const;
+1 -22
View File
@@ -28,28 +28,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_ReportWarning(rq.cx, "Script value conversion check failed: %s (got type %s)", #c, InformalValueTypeName(v)); })
// TODO: SpiderMonkey: Follow upstream progresses about JS_InformalValueTypeName in the API
// https://bugzilla.mozilla.org/show_bug.cgi?id=1285917
static const char* InformalValueTypeName(const JS::Value& v)
{
if (v.isObject())
return "object";
if (v.isString())
return "string";
if (v.isSymbol())
return "symbol";
if (v.isNumber())
return "number";
if (v.isBoolean())
return "boolean";
if (v.isNull())
return "null";
if (v.isUndefined())
return "undefined";
return "value";
}
#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)); })
template<> bool ScriptInterface::FromJSVal<bool>(const ScriptRequest& rq, JS::HandleValue v, bool& out)
{
+3 -49
View File
@@ -73,10 +73,9 @@ bool ScriptException::CatchPending(const ScriptRequest& rq)
msg << " line " << report->lineno << "\n";
}
// TODO SM52:
// msg << report->message();
msg << report->message().c_str();
JS::RootedObject stackObj(rq.cx, ExceptionStackOrNull(rq.cx, excnObj));
JS::RootedObject stackObj(rq.cx, ExceptionStackOrNull(excnObj));
JS::RootedValue stackVal(rq.cx, JS::ObjectOrNullValue(stackObj));
if (!stackVal.isNull())
{
@@ -97,55 +96,10 @@ bool ScriptException::CatchPending(const ScriptRequest& rq)
return true;
}
void ScriptException::ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report)
{
if (!ScriptInterface::GetScriptInterfaceAndCBData(cx))
{
LOGERROR("Javascript - Out of Memory error");
return;
}
ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface);
std::stringstream msg;
bool isWarning = JSREPORT_IS_WARNING(report->flags);
msg << (isWarning ? "JavaScript warning: " : "JavaScript error: ");
if (report->filename)
{
msg << report->filename;
msg << " line " << report->lineno << "\n";
}
msg << message;
// If there is an exception, then print its stack trace
JS::RootedValue excn(rq.cx);
if (JS_GetPendingException(rq.cx, &excn) && excn.isObject())
{
JS::RootedValue stackVal(rq.cx);
JS::RootedObject excnObj(rq.cx, &excn.toObject());
JS_GetProperty(rq.cx, excnObj, "stack", &stackVal);
std::string stackText;
ScriptInterface::FromJSVal(rq, stackVal, stackText);
std::istringstream stream(stackText);
for (std::string line; std::getline(stream, line);)
msg << "\n " << line;
}
if (isWarning)
LOGWARNING("%s", msg.str().c_str());
else
LOGERROR("%s", msg.str().c_str());
// When running under Valgrind, print more information in the error message
// VALGRIND_PRINTF_BACKTRACE("->");
}
void ScriptException::Raise(const ScriptRequest& rq, const char* format, ...)
{
va_list ap;
va_start(ap, format);
JS_ReportError(rq.cx, format, ap);
JS_ReportErrorUTF8(rq.cx, format, ap);
va_end(ap);
}
@@ -39,8 +39,6 @@ bool IsPending(const ScriptRequest& rq);
*/
bool CatchPending(const ScriptRequest& rq);
void ErrorReporter(JSContext* rt, const char* message, JSErrorReport* report);
/**
* Raise a JS exception from C++ code.
* This is only really relevant in JSNative functions that don't use ObjectOpResult,
+28 -41
View File
@@ -94,8 +94,7 @@ ScriptRequest::~ScriptRequest()
namespace
{
JSClass global_class = {
"global", JSCLASS_GLOBAL_FLAGS,
JSClassOps global_classops = {
nullptr, nullptr,
nullptr, nullptr,
nullptr, nullptr, nullptr,
@@ -103,6 +102,10 @@ JSClass global_class = {
JS_GlobalObjectTraceHook
};
JSClass global_class = {
"global", JSCLASS_GLOBAL_FLAGS, &global_classops
};
// Functions in the global namespace:
bool print(JSContext* cx, uint argc, JS::Value* vp)
@@ -319,12 +322,15 @@ bool ScriptInterface::MathRandom(double& nbr)
}
ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptContext>& context) :
m_context(context), m_cx(context->GetGeneralJSContext()), m_glob(context->GetJSRuntime()), m_nativeScope(context->GetJSRuntime())
m_context(context), m_cx(context->GetGeneralJSContext()), m_glob(context->GetGeneralJSContext()), m_nativeScope(context->GetGeneralJSContext())
{
JS::CompartmentOptions opt;
opt.setVersion(JSVERSION_LATEST);
JS::CompartmentCreationOptions creationOpt;
// Keep JIT code during non-shrinking GCs. This brings a quite big performance improvement.
opt.setPreserveJitCode(true);
creationOpt.setPreserveJitCode(true);
JS::CompartmentBehaviors behaviors;
behaviors.setVersion(JSVERSION_LATEST);
JS::CompartmentOptions opt(creationOpt, behaviors);
JSAutoRequest rq(m_cx);
m_glob = JS_NewGlobalObject(m_cx, &global_class, nullptr, JS::OnNewGlobalHookOption::FireOnNewGlobalHook, opt);
@@ -446,9 +452,9 @@ void ScriptInterface::Register(const char* name, JSNative fptr, size_t nargs) co
m->Register(name, fptr, (uint)nargs);
}
JSRuntime* ScriptInterface::GetJSRuntime() const
JSContext* ScriptInterface::GetGeneralJSContext() const
{
return m->m_context->GetJSRuntime();
return m->m_context->GetGeneralJSContext();
}
shared_ptr<ScriptContext> ScriptInterface::GetContext() const
@@ -560,7 +566,7 @@ bool ScriptInterface::SetGlobal_(const char* name, JS::HandleValue value, bool r
return false;
if (found)
{
JS::Rooted<JSPropertyDescriptor> desc(rq.cx);
JS::Rooted<JS::PropertyDescriptor> desc(rq.cx);
if (!JS_GetOwnPropertyDescriptor(rq.cx, global, name, &desc))
return false;
@@ -971,15 +977,7 @@ std::string ScriptInterface::ToString(JS::MutableHandleValue obj, bool pretty) c
Stringifier str;
JS::RootedValue indentVal(rq.cx, JS::Int32Value(2));
// Temporary disable the error reporter, so we don't print complaints about cyclic values
JSErrorReporter er = JS_SetErrorReporter(GetJSRuntime(), nullptr);
bool ok = JS_Stringify(rq.cx, obj, nullptr, indentVal, &Stringifier::callback, &str);
// Restore error reporter
JS_SetErrorReporter(GetJSRuntime(), er);
if (ok)
if (JS_Stringify(rq.cx, obj, nullptr, indentVal, &Stringifier::callback, &str))
return str.stream.str();
// Drop exceptions raised by cyclic values before trying something else
@@ -994,48 +992,37 @@ std::string ScriptInterface::ToString(JS::MutableHandleValue obj, bool pretty) c
return utf8_from_wstring(source);
}
JS::Value ScriptInterface::CloneValueFromOtherCompartment(const ScriptInterface& otherCompartment, JS::HandleValue val) const
JS::Value ScriptInterface::CloneValueFromOtherCompartment(const ScriptInterface& otherCompartment, JS::HandleValue val, bool sameThread) const
{
PROFILE("CloneValueFromOtherCompartment");
ScriptRequest rq(this);
JS::RootedValue out(rq.cx);
shared_ptr<StructuredClone> structuredClone = otherCompartment.WriteStructuredClone(val);
ScriptInterface::StructuredClone structuredClone = otherCompartment.WriteStructuredClone(val, sameThread);
ReadStructuredClone(structuredClone, &out);
return out.get();
}
ScriptInterface::StructuredClone::StructuredClone() :
m_Data(NULL), m_Size(0)
{
}
ScriptInterface::StructuredClone::~StructuredClone()
{
if (m_Data)
JS_ClearStructuredClone(m_Data, m_Size, NULL, NULL);
}
shared_ptr<ScriptInterface::StructuredClone> ScriptInterface::WriteStructuredClone(JS::HandleValue v) const
ScriptInterface::StructuredClone ScriptInterface::WriteStructuredClone(JS::HandleValue v, bool sameThread) const
{
ScriptRequest rq(this);
u64* data = NULL;
size_t nbytes = 0;
if (!JS_WriteStructuredClone(rq.cx, v, &data, &nbytes, NULL, NULL, JS::UndefinedHandleValue))
JS::StructuredCloneScope scope = sameThread ? JS::StructuredCloneScope::SameProcessSameThread : JS::StructuredCloneScope::SameProcessDifferentThread;
ScriptInterface::StructuredClone ret(new JSStructuredCloneData(scope));
JS::CloneDataPolicy policy;
if (!JS_WriteStructuredClone(rq.cx, v, ret.get(), scope, policy, nullptr, nullptr, JS::UndefinedHandleValue))
{
debug_warn(L"Writing a structured clone with JS_WriteStructuredClone failed!");
ScriptException::CatchPending(rq);
return shared_ptr<StructuredClone>();
return ScriptInterface::StructuredClone();
}
shared_ptr<StructuredClone> ret(new StructuredClone);
ret->m_Data = data;
ret->m_Size = nbytes;
return ret;
}
void ScriptInterface::ReadStructuredClone(const shared_ptr<ScriptInterface::StructuredClone>& ptr, JS::MutableHandleValue ret) const
void ScriptInterface::ReadStructuredClone(const ScriptInterface::StructuredClone& ptr, JS::MutableHandleValue ret) const
{
ScriptRequest rq(this);
if (!JS_ReadStructuredClone(rq.cx, ptr->m_Data, ptr->m_Size, JS_STRUCTURED_CLONE_VERSION, ret, NULL, NULL))
if (!JS_ReadStructuredClone(rq.cx, *ptr, JS_STRUCTURED_CLONE_VERSION, ptr->scope(), ret, nullptr, nullptr))
ScriptException::CatchPending(rq);
}
+19 -20
View File
@@ -119,7 +119,14 @@ public:
void SetCallbackData(void* pCBData);
static CmptPrivate* GetScriptInterfaceAndCBData(JSContext* cx);
JSRuntime* GetJSRuntime() const;
/**
* GetGeneralJSContext returns the context without starting a GC request and without
* entering the ScriptInterface compartment. It should only be used in specific situations,
* for instance when initializing a persistent rooted.
* If you need the compartmented context of the ScriptInterface, you should create a
* ScriptInterface::Request and use the context from that.
*/
JSContext* GetGeneralJSContext() const;
shared_ptr<ScriptContext> GetContext() const;
/**
@@ -289,14 +296,6 @@ public:
*/
bool LoadGlobalScriptFile(const VfsPath& path) const;
/**
* Construct a new value (usable in this ScriptInterface's compartment) by cloning
* a value from a different compartment.
* Complex values (functions, XML, etc) won't be cloned correctly, but basic
* types and cyclic references should be fine.
*/
JS::Value CloneValueFromOtherCompartment(const ScriptInterface& otherCompartment, JS::HandleValue val) const;
/**
* Convert a JS::Value to a C++ type. (This might trigger GC.)
*/
@@ -331,18 +330,18 @@ public:
* We wrap them in shared_ptr so memory management is automatic and
* thread-safe.
*/
class StructuredClone
{
NONCOPYABLE(StructuredClone);
public:
StructuredClone();
~StructuredClone();
u64* m_Data;
size_t m_Size;
};
using StructuredClone = shared_ptr<JSStructuredCloneData>;
shared_ptr<StructuredClone> WriteStructuredClone(JS::HandleValue v) const;
void ReadStructuredClone(const shared_ptr<StructuredClone>& ptr, JS::MutableHandleValue ret) const;
StructuredClone WriteStructuredClone(JS::HandleValue v, bool sameThread) const;
void ReadStructuredClone(const StructuredClone& ptr, JS::MutableHandleValue ret) const;
/**
* Construct a new value (usable in this ScriptInterface's compartment) by cloning
* a value from a different compartment.
* Complex values (functions, XML, etc) won't be cloned correctly, but basic
* types and cyclic references should be fine.
*/
JS::Value CloneValueFromOtherCompartment(const ScriptInterface& otherCompartment, JS::HandleValue val, bool sameThread) const;
/**
* Retrieve the private data field of a JSObject that is an instance of the given JSClass.
+5 -5
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2015 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -84,28 +84,28 @@ CStr CScriptStatsTable::GetCellText(size_t row, size_t col)
{
if (col == 0)
return "max nominal heap bytes";
uint32_t n = JS_GetGCParameter(m_ScriptInterfaces.at(col-1).first->GetJSRuntime(), JSGC_MAX_BYTES);
uint32_t n = JS_GetGCParameter(m_ScriptInterfaces.at(col-1).first->GetGeneralJSContext(), JSGC_MAX_BYTES);
return CStr::FromUInt(n);
}
case Row_MaxMallocBytes:
{
if (col == 0)
return "max JS_malloc bytes";
uint32_t n = JS_GetGCParameter(m_ScriptInterfaces.at(col-1).first->GetJSRuntime(), JSGC_MAX_MALLOC_BYTES);
uint32_t n = JS_GetGCParameter(m_ScriptInterfaces.at(col-1).first->GetGeneralJSContext(), JSGC_MAX_MALLOC_BYTES);
return CStr::FromUInt(n);
}
case Row_Bytes:
{
if (col == 0)
return "allocated bytes";
uint32_t n = JS_GetGCParameter(m_ScriptInterfaces.at(col-1).first->GetJSRuntime(), JSGC_BYTES);
uint32_t n = JS_GetGCParameter(m_ScriptInterfaces.at(col-1).first->GetGeneralJSContext(), JSGC_BYTES);
return CStr::FromUInt(n);
}
case Row_NumberGC:
{
if (col == 0)
return "number of GCs";
uint32_t n = JS_GetGCParameter(m_ScriptInterfaces.at(col-1).first->GetJSRuntime(), JSGC_NUMBER);
uint32_t n = JS_GetGCParameter(m_ScriptInterfaces.at(col-1).first->GetGeneralJSContext(), JSGC_NUMBER);
return CStr::FromUInt(n);
}
default:
+2
View File
@@ -55,6 +55,8 @@
#if MSC_VERSION
// reduce the warning level for the SpiderMonkey headers
# pragma warning(push, 1)
// ignore C4291 in <mozilla/Vector.h>
# pragma warning(disable: 4291)
#endif
#include "jspubtd.h"
@@ -40,7 +40,7 @@ public:
ScriptInterface script("Test", "Test", g_ScriptContext);
TestLogger logger;
TS_ASSERT(!script.LoadScript(L"test.js", "1+"));
TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "ERROR: JavaScript error: test.js line 1\nSyntaxError: expected expression, got end of script");
TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "ERROR: JavaScript error: test.js line 1\nexpected expression, got end of script");
}
void test_loadscript_strict_warning()
@@ -57,7 +57,7 @@ public:
ScriptInterface script("Test", "Test", g_ScriptContext);
TestLogger logger;
TS_ASSERT(!script.LoadScript(L"test.js", "with(1){}"));
TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "ERROR: JavaScript error: test.js line 1\nSyntaxError: strict mode code may not contain \'with\' statements");
TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "ERROR: JavaScript error: test.js line 1\nstrict mode code may not contain \'with\' statements");
}
void test_clone_basic()
@@ -72,7 +72,7 @@ public:
{
ScriptRequest rq2(script2);
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1));
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1, true));
std::string source;
TS_ASSERT(script2.CallFunction(obj2, "toSource", source));
@@ -94,7 +94,7 @@ public:
{
ScriptRequest rq2(script2);
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1));
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1, true));
std::string source;
TS_ASSERT(script2.CallFunction(obj2, "toSource", source));
@@ -114,7 +114,7 @@ public:
{
ScriptRequest rq2(script2);
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1));
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1, true));
// Use JSAPI function to check if the values of the properties "a", "b" are equals a.x[0]
JS::RootedValue prop_a(rq2.cx);
@@ -125,8 +125,8 @@ public:
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());
TS_ASSERT(prop_x1.get() == prop_a.get());
TS_ASSERT(prop_x1.get() == prop_b.get());
}
}
+10 -10
View File
@@ -49,11 +49,11 @@
class CSimulation2Impl
{
public:
CSimulation2Impl(CUnitManager* unitManager, shared_ptr<ScriptContext> rt, CTerrain* terrain) :
m_SimContext(), m_ComponentManager(m_SimContext, rt),
CSimulation2Impl(CUnitManager* unitManager, shared_ptr<ScriptContext> cx, CTerrain* terrain) :
m_SimContext(), m_ComponentManager(m_SimContext, cx),
m_EnableOOSLog(false), m_EnableSerializationTest(false), m_RejoinTestTurn(-1), m_TestingRejoin(false),
m_SecondaryTerrain(nullptr), m_SecondaryContext(nullptr), m_SecondaryComponentManager(nullptr), m_SecondaryLoadedScripts(nullptr),
m_MapSettings(rt->GetJSRuntime()), m_InitAttributes(rt->GetJSRuntime())
m_MapSettings(cx->GetGeneralJSContext()), m_InitAttributes(cx->GetGeneralJSContext())
{
m_SimContext.m_UnitManager = unitManager;
m_SimContext.m_Terrain = terrain;
@@ -164,7 +164,7 @@ public:
void InitRNGSeedSimulation();
void InitRNGSeedAI();
static std::vector<SimulationCommand> CloneCommandsFromOtherContext(const ScriptInterface& oldScript, const ScriptInterface& newScript,
static std::vector<SimulationCommand> CloneCommandsFromOtherCompartment(const ScriptInterface& oldScript, const ScriptInterface& newScript,
const std::vector<SimulationCommand>& commands)
{
std::vector<SimulationCommand> newCommands;
@@ -173,7 +173,7 @@ public:
ScriptRequest rqNew(newScript);
for (const SimulationCommand& command : commands)
{
JS::RootedValue tmpCommand(rqNew.cx, newScript.CloneValueFromOtherCompartment(oldScript, command.data));
JS::RootedValue tmpCommand(rqNew.cx, newScript.CloneValueFromOtherCompartment(oldScript, command.data, true));
newScript.FreezeObject(tmpCommand, true);
SimulationCommand cmd(command.player, rqNew.cx, tmpCommand);
newCommands.emplace_back(std::move(cmd));
@@ -424,7 +424,7 @@ void CSimulation2Impl::Update(int turnLength, const std::vector<SimulationComman
ScriptRequest rq2(m_SecondaryComponentManager->GetScriptInterface());
JS::RootedValue mapSettingsCloned(rq2.cx,
m_SecondaryComponentManager->GetScriptInterface().CloneValueFromOtherCompartment(
scriptInterface, m_MapSettings));
scriptInterface, m_MapSettings, true));
ENSURE(LoadTriggerScripts(*m_SecondaryComponentManager, mapSettingsCloned, m_SecondaryLoadedScripts));
}
@@ -446,7 +446,7 @@ void CSimulation2Impl::Update(int turnLength, const std::vector<SimulationComman
scriptInterface.GetProperty(m_InitAttributes, "map", mapFile);
VfsPath mapfilename = VfsPath(mapFile).ChangeExtension(L".pmp");
mapReader->LoadMap(mapfilename, scriptInterface.GetJSRuntime(), JS::UndefinedHandleValue,
mapReader->LoadMap(mapfilename, *scriptInterface.GetContext(), JS::UndefinedHandleValue,
m_SecondaryTerrain, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, m_SecondaryContext, INVALID_PLAYER, true); // throws exception on failure
}
@@ -477,7 +477,7 @@ void CSimulation2Impl::Update(int turnLength, const std::vector<SimulationComman
ENSURE(m_ComponentManager.ComputeStateHash(primaryStateAfter.hash, false));
UpdateComponents(*m_SecondaryContext, turnLengthFixed,
CloneCommandsFromOtherContext(scriptInterface, m_SecondaryComponentManager->GetScriptInterface(), commands));
CloneCommandsFromOtherCompartment(scriptInterface, m_SecondaryComponentManager->GetScriptInterface(), commands));
SerializationTestState secondaryStateAfter;
ENSURE(m_SecondaryComponentManager->SerializeState(secondaryStateAfter.state));
if (serializationTestHash)
@@ -638,8 +638,8 @@ void CSimulation2Impl::DumpState()
////////////////////////////////////////////////////////////////
CSimulation2::CSimulation2(CUnitManager* unitManager, shared_ptr<ScriptContext> rt, CTerrain* terrain) :
m(new CSimulation2Impl(unitManager, rt, terrain))
CSimulation2::CSimulation2(CUnitManager* unitManager, shared_ptr<ScriptContext> cx, CTerrain* terrain) :
m(new CSimulation2Impl(unitManager, cx, terrain))
{
}
+1 -1
View File
@@ -48,7 +48,7 @@ class CSimulation2
public:
// TODO: CUnitManager should probably be handled automatically by this
// module, but for now we'll have it passed in externally instead
CSimulation2(CUnitManager* unitManager, shared_ptr<ScriptContext> rt, CTerrain* terrain);
CSimulation2(CUnitManager* unitManager, shared_ptr<ScriptContext> cx, CTerrain* terrain);
~CSimulation2();
void EnableSerializationTest();
+17 -16
View File
@@ -86,7 +86,7 @@ private:
CAIPlayer(CAIWorker& worker, const std::wstring& aiName, player_id_t player, u8 difficulty, const std::wstring& behavior,
shared_ptr<ScriptInterface> scriptInterface) :
m_Worker(worker), m_AIName(aiName), m_Player(player), m_Difficulty(difficulty), m_Behavior(behavior),
m_ScriptInterface(scriptInterface), m_Obj(scriptInterface->GetJSRuntime())
m_ScriptInterface(scriptInterface), m_Obj(scriptInterface->GetGeneralJSContext())
{
}
@@ -200,14 +200,14 @@ private:
shared_ptr<ScriptInterface> m_ScriptInterface;
JS::PersistentRootedValue m_Obj;
std::vector<shared_ptr<ScriptInterface::StructuredClone> > m_Commands;
std::vector<ScriptInterface::StructuredClone > m_Commands;
};
public:
struct SCommandSets
{
player_id_t player;
std::vector<shared_ptr<ScriptInterface::StructuredClone> > commands;
std::vector<ScriptInterface::StructuredClone > commands;
};
CAIWorker() :
@@ -216,17 +216,17 @@ public:
m_CommandsComputed(true),
m_HasLoadedEntityTemplates(false),
m_HasSharedComponent(false),
m_EntityTemplates(g_ScriptContext->GetJSRuntime()),
m_SharedAIObj(g_ScriptContext->GetJSRuntime()),
m_PassabilityMapVal(g_ScriptContext->GetJSRuntime()),
m_TerritoryMapVal(g_ScriptContext->GetJSRuntime())
m_EntityTemplates(g_ScriptContext->GetGeneralJSContext()),
m_SharedAIObj(g_ScriptContext->GetGeneralJSContext()),
m_PassabilityMapVal(g_ScriptContext->GetGeneralJSContext()),
m_TerritoryMapVal(g_ScriptContext->GetGeneralJSContext())
{
m_ScriptInterface->ReplaceNondeterministicRNG(m_RNG);
m_ScriptInterface->SetCallbackData(static_cast<void*> (this));
JS_AddExtraGCRootsTracer(m_ScriptInterface->GetJSRuntime(), Trace, this);
JS_AddExtraGCRootsTracer(m_ScriptInterface->GetGeneralJSContext(), Trace, this);
m_ScriptInterface->RegisterFunction<void, int, JS::HandleValue, CAIWorker::PostCommand>("PostCommand");
m_ScriptInterface->RegisterFunction<void, std::wstring, CAIWorker::IncludeModule>("IncludeModule");
@@ -245,7 +245,7 @@ public:
~CAIWorker()
{
JS_RemoveExtraGCRootsTracer(m_ScriptInterface->GetJSRuntime(), Trace, this);
JS_RemoveExtraGCRootsTracer(m_ScriptInterface->GetGeneralJSContext(), Trace, this);
}
bool HasLoadedEntityTemplates() const { return m_HasLoadedEntityTemplates; }
@@ -299,7 +299,7 @@ public:
{
if (m_Players[i]->m_Player == playerid)
{
m_Players[i]->m_Commands.push_back(m_ScriptInterface->WriteStructuredClone(cmd));
m_Players[i]->m_Commands.push_back(m_ScriptInterface->WriteStructuredClone(cmd, false));
return;
}
}
@@ -485,7 +485,7 @@ public:
return true;
}
bool RunGamestateInit(const shared_ptr<ScriptInterface::StructuredClone>& gameState, const Grid<NavcellData>& passabilityMap, const Grid<u8>& territoryMap,
bool RunGamestateInit(const ScriptInterface::StructuredClone& gameState, const Grid<NavcellData>& passabilityMap, const Grid<u8>& territoryMap,
const std::map<std::string, pass_class_t>& nonPathfindingPassClassMasks, const std::map<std::string, pass_class_t>& pathfindingPassClassMasks)
{
// this will be run last by InitGame.js, passing the full game representation.
@@ -521,7 +521,7 @@ public:
return true;
}
void UpdateGameState(const shared_ptr<ScriptInterface::StructuredClone>& gameState)
void UpdateGameState(const ScriptInterface::StructuredClone& gameState)
{
ENSURE(m_CommandsComputed);
m_GameState = gameState;
@@ -765,7 +765,7 @@ public:
{
JS::RootedValue val(rq.cx);
deserializer.ScriptVal("command", &val);
m_Players.back()->m_Commands.push_back(m_ScriptInterface->WriteStructuredClone(val));
m_Players.back()->m_Commands.push_back(m_ScriptInterface->WriteStructuredClone(val, false));
}
bool hasCustomDeserialize = m_ScriptInterface->HasProperty(m_Players.back()->m_Obj, "Deserialize");
@@ -888,7 +888,7 @@ private:
std::set<std::wstring> m_LoadedModules;
shared_ptr<ScriptInterface::StructuredClone> m_GameState;
ScriptInterface::StructuredClone m_GameState;
Grid<NavcellData> m_PassabilityMap;
JS::PersistentRootedValue m_PassabilityMapVal;
Grid<u8> m_TerritoryMap;
@@ -1016,7 +1016,8 @@ public:
if (cmpPathfinder)
cmpPathfinder->GetPassabilityClasses(nonPathfindingPassClassMasks, pathfindingPassClassMasks);
m_Worker.RunGamestateInit(scriptInterface.WriteStructuredClone(state), *passabilityMap, *territoryMap, nonPathfindingPassClassMasks, pathfindingPassClassMasks);
m_Worker.RunGamestateInit(scriptInterface.WriteStructuredClone(state, false),
*passabilityMap, *territoryMap, nonPathfindingPassClassMasks, pathfindingPassClassMasks);
}
virtual void StartComputation()
@@ -1041,7 +1042,7 @@ public:
LoadPathfinderClasses(state); // add the pathfinding classes to it
// Update the game state
m_Worker.UpdateGameState(scriptInterface.WriteStructuredClone(state));
m_Worker.UpdateGameState(scriptInterface.WriteStructuredClone(state, false));
// Update the pathfinding data
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity());
@@ -39,7 +39,7 @@ struct GetAIsHelper
public:
GetAIsHelper(const ScriptInterface& scriptInterface) :
m_ScriptInterface(scriptInterface),
m_AIs(scriptInterface.GetJSRuntime())
m_AIs(scriptInterface.GetGeneralJSContext())
{
ScriptRequest rq(m_ScriptInterface);
m_AIs = JS_NewArrayObject(rq.cx, 0);
@@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -28,6 +28,7 @@
#include "lib/tex/tex.h"
#include "ps/Loader.h"
#include "ps/Pyrogenesis.h"
#include "scriptinterface/ScriptContext.h"
#include "simulation2/Simulation2.h"
class TestCmpPathfinder : public CxxTest::TestSuite
@@ -147,7 +148,7 @@ public:
LDR_BeginRegistering();
mapReader->LoadMap(L"maps/skirmishes/Median Oasis (2).pmp",
sim2.GetScriptInterface().GetJSRuntime(), JS::UndefinedHandleValue,
*sim2.GetScriptInterface().GetContext(), JS::UndefinedHandleValue,
&terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
&sim2, &sim2.GetSimContext(), -1, false);
LDR_EndRegistering();
@@ -258,7 +259,7 @@ public:
LDR_BeginRegistering();
mapReader->LoadMap(L"maps/scenarios/Peloponnese.pmp",
sim2.GetScriptInterface().GetJSRuntime(), JS::UndefinedHandleValue,
*sim2.GetScriptInterface().GetContext(), JS::UndefinedHandleValue,
&terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
&sim2, &sim2.GetSimContext(), -1, false);
LDR_EndRegistering();
@@ -315,7 +316,7 @@ public:
LDR_BeginRegistering();
mapReader->LoadMap(L"maps/scenarios/Peloponnese.pmp",
sim2.GetScriptInterface().GetJSRuntime(), JS::UndefinedHandleValue,
*sim2.GetScriptInterface().GetContext(), JS::UndefinedHandleValue,
&terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
&sim2, &sim2.GetSimContext(), -1, false);
LDR_EndRegistering();
@@ -168,8 +168,11 @@ template<> void ScriptInterface::ToJSVal<CFixedVector3D>(const ScriptRequest& rq
args[1].setNumber(val.Y.ToDouble());
args[2].setNumber(val.Z.ToDouble());
if (!JS::Construct(rq.cx, valueVector3D, args, ret))
JS::RootedObject objVec(rq.cx);
if (!JS::Construct(rq.cx, valueVector3D, args, &objVec))
FAIL_VOID("Failed to construct Vector3D object");
ret.setObject(*objVec);
}
template<> bool ScriptInterface::FromJSVal<CFixedVector2D>(const ScriptRequest& rq, JS::HandleValue v, CFixedVector2D& out)
@@ -200,8 +203,11 @@ template<> void ScriptInterface::ToJSVal<CFixedVector2D>(const ScriptRequest& rq
args[0].setNumber(val.X.ToDouble());
args[1].setNumber(val.Y.ToDouble());
if (!JS::Construct(rq.cx, valueVector2D, args, ret))
JS::RootedObject objVec(rq.cx);
if (!JS::Construct(rq.cx, valueVector2D, args, &objVec))
FAIL_VOID("Failed to construct Vector2D object");
ret.setObject(*objVec);
}
template<> void ScriptInterface::ToJSVal<Grid<u8> >(const ScriptRequest& rq, JS::MutableHandleValue ret, const Grid<u8>& val)
@@ -51,11 +51,11 @@ JS::Value JSI_Simulation::GuiInterfaceCall(ScriptInterface::CmptPrivate* pCmptPr
return JS::UndefinedValue();
ScriptRequest rqSim(sim->GetScriptInterface());
JS::RootedValue arg(rqSim.cx, sim->GetScriptInterface().CloneValueFromOtherCompartment(*(pCmptPrivate->pScriptInterface), data));
JS::RootedValue arg(rqSim.cx, sim->GetScriptInterface().CloneValueFromOtherCompartment(*(pCmptPrivate->pScriptInterface), data, false));
JS::RootedValue ret(rqSim.cx);
cmpGuiInterface->ScriptCall(g_Game->GetViewedPlayerID(), name, arg, &ret);
return pCmptPrivate->pScriptInterface->CloneValueFromOtherCompartment(sim->GetScriptInterface(), ret);
return pCmptPrivate->pScriptInterface->CloneValueFromOtherCompartment(sim->GetScriptInterface(), ret, false);
}
void JSI_Simulation::PostNetworkCommand(ScriptInterface::CmptPrivate* pCmptPrivate, JS::HandleValue cmd)
@@ -71,7 +71,8 @@ void JSI_Simulation::PostNetworkCommand(ScriptInterface::CmptPrivate* pCmptPriva
return;
ScriptRequest rqSim(sim->GetScriptInterface());
JS::RootedValue cmd2(rqSim.cx, sim->GetScriptInterface().CloneValueFromOtherCompartment(*(pCmptPrivate->pScriptInterface), cmd));
JS::RootedValue cmd2(rqSim.cx,
sim->GetScriptInterface().CloneValueFromOtherCompartment(*(pCmptPrivate->pScriptInterface), cmd, false));
cmpCommandQueue->PostNetworkCommand(cmd2);
}
@@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -53,7 +53,7 @@
JS::Value CMessage::ToJSValCached(const ScriptInterface& scriptInterface) const
{
if (!m_Cached)
m_Cached.reset(new JS::PersistentRootedValue(scriptInterface.GetJSRuntime(), ToJSVal(scriptInterface)));
m_Cached.reset(new JS::PersistentRootedValue(scriptInterface.GetGeneralJSContext(), ToJSVal(scriptInterface)));
return m_Cached->get();
}
@@ -23,7 +23,7 @@
#include "simulation2/serialization/IDeserializer.h"
CComponentTypeScript::CComponentTypeScript(const ScriptInterface& scriptInterface, JS::HandleValue instance) :
m_ScriptInterface(scriptInterface), m_Instance(scriptInterface.GetJSRuntime(), instance)
m_ScriptInterface(scriptInterface), m_Instance(scriptInterface.GetGeneralJSContext(), instance)
{
// Cache the property detection for efficiency
ScriptRequest rq(m_ScriptInterface);
@@ -272,7 +272,7 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
JS::RootedValue propval(rq.cx);
// Forbid getters, which might delete values and mess things up.
JS::Rooted<JSPropertyDescriptor> desc(rq.cx);
JS::Rooted<JS::PropertyDescriptor> desc(rq.cx);
if (!JS_GetPropertyDescriptorById(rq.cx, obj, id, &desc))
throw PSERROR_Serialize_ScriptError("JS_GetPropertyDescriptorById failed");
if (desc.hasGetterObject())
@@ -30,12 +30,12 @@
CStdDeserializer::CStdDeserializer(const ScriptInterface& scriptInterface, std::istream& stream) :
m_ScriptInterface(scriptInterface), m_Stream(stream)
{
JS_AddExtraGCRootsTracer(m_ScriptInterface.GetJSRuntime(), CStdDeserializer::Trace, this);
JS_AddExtraGCRootsTracer(m_ScriptInterface.GetGeneralJSContext(), CStdDeserializer::Trace, this);
}
CStdDeserializer::~CStdDeserializer()
{
JS_RemoveExtraGCRootsTracer(m_ScriptInterface.GetJSRuntime(), CStdDeserializer::Trace, this);
JS_RemoveExtraGCRootsTracer(m_ScriptInterface.GetGeneralJSContext(), CStdDeserializer::Trace, this);
}
void CStdDeserializer::Trace(JSTracer *trc, void *data)
@@ -43,7 +43,7 @@ public:
virtual JS::Value ToJSVal(const ScriptInterface& UNUSED(scriptInterface)) const { return msg.get(); }
CMessageScripted(const ScriptInterface& scriptInterface, int mtid, const std::string& name, JS::HandleValue msg) :
mtid(mtid), handlerName("On" + name), globalHandlerName("OnGlobal" + name), msg(scriptInterface.GetJSRuntime(), msg)
mtid(mtid), handlerName("On" + name), globalHandlerName("OnGlobal" + name), msg(scriptInterface.GetGeneralJSContext(), msg)
{
}
@@ -53,9 +53,9 @@ public:
JS::PersistentRootedValue msg;
};
CComponentManager::CComponentManager(CSimContext& context, shared_ptr<ScriptContext> rt, bool skipScriptFunctions) :
CComponentManager::CComponentManager(CSimContext& context, shared_ptr<ScriptContext> cx, bool skipScriptFunctions) :
m_NextScriptComponentTypeId(CID__LastNative),
m_ScriptInterface("Engine", "Simulation", rt),
m_ScriptInterface("Engine", "Simulation", cx),
m_SimContext(context), m_CurrentlyHotloading(false)
{
context.SetComponentManager(this);
+1 -1
View File
@@ -74,7 +74,7 @@ private:
};
public:
CComponentManager(CSimContext&, shared_ptr<ScriptContext> rt, bool skipScriptFunctions = false);
CComponentManager(CSimContext&, shared_ptr<ScriptContext> cx, bool skipScriptFunctions = false);
~CComponentManager();
void LoadComponentTypes();
+1 -1
View File
@@ -46,7 +46,7 @@ CTurnManager::CTurnManager(CSimulation2& simulation, u32 defaultTurnLength, int
: m_Simulation2(simulation), m_CurrentTurn(0), m_ReadyTurn(1), m_TurnLength(defaultTurnLength),
m_PlayerId(-1), m_ClientId(clientId), m_DeltaSimTime(0), m_HasSyncError(false), m_Replay(replay),
m_FinalTurn(std::numeric_limits<u32>::max()), m_TimeWarpNumTurns(0),
m_QuickSaveMetadata(m_Simulation2.GetScriptInterface().GetJSRuntime())
m_QuickSaveMetadata(m_Simulation2.GetScriptInterface().GetGeneralJSContext())
{
// When we are on turn n, we schedule new commands for n+2.
// We know that all other clients have finished scheduling commands for n (else we couldn't have got here).
+2 -1
View File
@@ -21,6 +21,7 @@
#include "simulation2/serialization/HashSerializer.h"
#include "simulation2/serialization/StdSerializer.h"
#include "simulation2/serialization/StdDeserializer.h"
#include "scriptinterface/ScriptContext.h"
#include "scriptinterface/ScriptInterface.h"
#include "graphics/MapReader.h"
@@ -841,7 +842,7 @@ public:
LDR_BeginRegistering();
mapReader->LoadMap(L"maps/skirmishes/Greek Acropolis (2).pmp",
sim2.GetScriptInterface().GetJSRuntime(), JS::UndefinedHandleValue,
*sim2.GetScriptInterface().GetContext(), JS::UndefinedHandleValue,
&terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
&sim2, &sim2.GetSimContext(), -1, false);
LDR_EndRegistering();