diff --git a/source/graphics/MapGenerator.cpp b/source/graphics/MapGenerator.cpp index 9c6b1e7ad0..82400cb55e 100644 --- a/source/graphics/MapGenerator.cpp +++ b/source/graphics/MapGenerator.cpp @@ -92,7 +92,7 @@ void* CMapGeneratorWorker::RunThread(CMapGeneratorWorker* self) shared_ptr 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 CMapGeneratorWorker::GetResults() +ScriptInterface::StructuredClone CMapGeneratorWorker::GetResults() { std::lock_guard lock(m_WorkerMutex); return m_MapData; @@ -232,7 +232,7 @@ void CMapGeneratorWorker::ExportMap(ScriptInterface::CmptPrivate* pCmptPrivate, // Copy results std::lock_guard 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 CMapGenerator::GetResults() +ScriptInterface::StructuredClone CMapGenerator::GetResults() { return m_Worker->GetResults(); } diff --git a/source/graphics/MapGenerator.h b/source/graphics/MapGenerator.h index d398f2810b..353f9ef1a9 100644 --- a/source/graphics/MapGenerator.h +++ b/source/graphics/MapGenerator.h @@ -67,7 +67,7 @@ public: * * @return StructuredClone containing map data */ - shared_ptr GetResults(); + ScriptInterface::StructuredClone GetResults(); private: CMapGeneratorWorker* m_Worker; @@ -110,7 +110,7 @@ public: * * @return StructuredClone containing map data */ - shared_ptr 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 m_MapData; + ScriptInterface::StructuredClone m_MapData; /** * Deterministic random number generator. diff --git a/source/graphics/MapReader.cpp b/source/graphics/MapReader.cpp index f616bd3a0d..65d7f5921f 100644 --- a/source/graphics/MapReader.cpp +++ b/source/graphics/MapReader.cpp @@ -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 results = m_MapGen->GetResults(); + ScriptInterface::StructuredClone results = m_MapGen->GetResults(); // Parse data into simulation context JS::RootedValue data(rq.cx); diff --git a/source/graphics/MapReader.h b/source/graphics/MapReader.h index 8c9f824b53..744c1da839 100644 --- a/source/graphics/MapReader.h +++ b/source/graphics/MapReader.h @@ -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 diff --git a/source/gui/GUIManager.cpp b/source/gui/GUIManager.cpp index e36d314d36..81b76dceed 100644 --- a/source/gui/GUIManager.cpp +++ b/source/gui/GUIManager.cpp @@ -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 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 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 args) +void CGUIManager::PopPage(ScriptInterface::StructuredClone args) { if (m_PageStack.size() < 2) { @@ -121,7 +121,7 @@ void CGUIManager::PopPage(shared_ptr args) m_PageStack.back().PerformCallbackFunction(args); } -CGUIManager::SGUIPage::SGUIPage(const CStrW& pageName, const shared_ptr 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 scriptContext) { // If we're hotloading then try to grab some data from the previous page - shared_ptr hotloadData; + ScriptInterface::StructuredClone hotloadData; if (gui) { shared_ptr scriptInterface = gui->GetScriptInterface(); @@ -138,7 +138,7 @@ void CGUIManager::SGUIPage::LoadPage(shared_ptr 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(scriptInterface.GetJSRuntime(), callbackFunc); + callbackFunction = std::make_shared(scriptInterface.GetGeneralJSContext(), callbackFunc); } -void CGUIManager::SGUIPage::PerformCallbackFunction(shared_ptr args) +void CGUIManager::SGUIPage::PerformCallbackFunction(ScriptInterface::StructuredClone args) { if (!callbackFunction) return; diff --git a/source/gui/GUIManager.h b/source/gui/GUIManager.h index 20e9e54efd..b226f23506 100644 --- a/source/gui/GUIManager.h +++ b/source/gui/GUIManager.h @@ -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 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 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 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 args); + void PerformCallbackFunction(ScriptInterface::StructuredClone args); CStrW name; std::unordered_set inputs; // for hotloading - shared_ptr initData; // data to be passed to the init() function + ScriptInterface::StructuredClone initData; // data to be passed to the init() function shared_ptr gui; // the actual GUI page /** diff --git a/source/gui/ObjectBases/IGUIObject.cpp b/source/gui/ObjectBases/IGUIObject.cpp index 21c6d8269a..b6e9455918 100644 --- a/source/gui/ObjectBases/IGUIObject.cpp +++ b/source/gui/ObjectBases/IGUIObject.cpp @@ -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(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; diff --git a/source/gui/Scripting/JSInterface_GUIManager.cpp b/source/gui/Scripting/JSInterface_GUIManager.cpp index 6055461a16..380b2d96e3 100644 --- a/source/gui/Scripting/JSInterface_GUIManager.cpp +++ b/source/gui/Scripting/JSInterface_GUIManager.cpp @@ -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) diff --git a/source/gui/Scripting/JSInterface_GUISize.cpp b/source/gui/Scripting/JSInterface_GUISize.cpp index 16c7291bcb..04212da81b 100644 --- a/source/gui/Scripting/JSInterface_GUISize.cpp +++ b/source/gui/Scripting/JSInterface_GUISize.cpp @@ -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, diff --git a/source/gui/Scripting/JSInterface_GUISize.h b/source/gui/Scripting/JSInterface_GUISize.h index bcf87e4f43..53050a863b 100644 --- a/source/gui/Scripting/JSInterface_GUISize.h +++ b/source/gui/Scripting/JSInterface_GUISize.h @@ -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[]; diff --git a/source/gui/Scripting/JSInterface_IGUIObject.cpp b/source/gui/Scripting/JSInterface_IGUIObject.cpp index 2fdae17ba9..0b2062c702 100644 --- a/source/gui/Scripting/JSInterface_IGUIObject.cpp +++ b/source/gui/Scripting/JSInterface_IGUIObject.cpp @@ -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); diff --git a/source/gui/Scripting/JSInterface_IGUIObject.h b/source/gui/Scripting/JSInterface_IGUIObject.h index a90f827701..4a13e69aea 100644 --- a/source/gui/Scripting/JSInterface_IGUIObject.h +++ b/source/gui/Scripting/JSInterface_IGUIObject.h @@ -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); diff --git a/source/gui/tests/test_GuiManager.h b/source/gui/tests/test_GuiManager.h index bfef132bf1..2957f6f575 100755 --- a/source/gui/tests/test_GuiManager.h +++ b/source/gui/tests/test_GuiManager.h @@ -66,7 +66,7 @@ public: JS::RootedValue val(rq.cx); scriptInterface.CreateObject(rq, &val); - std::shared_ptr 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'. diff --git a/source/lobby/XmppClient.cpp b/source/lobby/XmppClient.cpp index 7da3de41c6..98bf494933 100644 --- a/source/lobby/XmppClient.cpp +++ b/source/lobby/XmppClient.cpp @@ -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); } /** diff --git a/source/network/NetClient.cpp b/source/network/NetClient.cpp index 5f06bf2145..124b390d0d 100644 --- a/source/network/NetClient.cpp +++ b/source/network/NetClient.cpp @@ -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) diff --git a/source/network/NetMessageSim.cpp b/source/network/NetMessageSim.cpp index 9ea45678c1..0876a4e179 100644 --- a/source/network/NetMessageSim.cpp +++ b/source/network/NetMessageSim.cpp @@ -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) { } diff --git a/source/network/NetServer.cpp b/source/network/NetServer.cpp index a1abe071d7..8198a748aa 100644 --- a/source/network/NetServer.cpp +++ b/source/network/NetServer.cpp @@ -389,7 +389,7 @@ void CNetServerWorker::Run() // We create a new ScriptContext for this network thread, with a single ScriptInterface. shared_ptr 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) { diff --git a/source/network/scripting/JSInterface_Network.cpp b/source/network/scripting/JSInterface_Network.cpp index 7de7b1266c..cc198f2724 100644 --- a/source/network/scripting/JSInterface_Network.cpp +++ b/source/network/scripting/JSInterface_Network.cpp @@ -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) diff --git a/source/ps/Game.cpp b/source/ps/Game.cpp index 295663874a..c2f7afffa9 100644 --- a/source/ps/Game.cpp +++ b/source/ps/Game.cpp @@ -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); diff --git a/source/ps/Mod.cpp b/source/ps/Mod.cpp index 8ae3708ccc..0166282b31 100644 --- a/source/ps/Mod.cpp +++ b/source/ps/Mod.cpp @@ -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 g_modsLoaded; diff --git a/source/ps/ProfileViewer.cpp b/source/ps/ProfileViewer.cpp index 572963b0b3..1aa4c2acbb 100644 --- a/source/ps/ProfileViewer.cpp +++ b/source/ps/ProfileViewer.cpp @@ -488,7 +488,7 @@ namespace const ScriptInterface& m_ScriptInterface; JS::PersistentRooted 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()) { } diff --git a/source/ps/SavedGame.cpp b/source/ps/SavedGame.cpp index 5fe1a97f1e..0253e573fa 100644 --- a/source/ps/SavedGame.cpp +++ b/source/ps/SavedGame.cpp @@ -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& 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& 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) { } diff --git a/source/ps/SavedGame.h b/source/ps/SavedGame.h index d4489da307..507eb691a0 100644 --- a/source/ps/SavedGame.h +++ b/source/ps/SavedGame.h @@ -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& 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& guiMetadataClone); + Status SavePrefix(const CStrW& prefix, const CStrW& description, CSimulation2& simulation, const ScriptInterface::StructuredClone& guiMetadataClone); /** * Load saved game archive with the given name diff --git a/source/ps/World.cpp b/source/ps/World.cpp index 8c87b4e508..36ba3c828a 100644 --- a/source/ps/World.cpp +++ b/source/ps/World.cpp @@ -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(), diff --git a/source/ps/World.h b/source/ps/World.h index d563c809c3..2ad9feaa3e 100644 --- a/source/ps/World.h +++ b/source/ps/World.h @@ -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. diff --git a/source/ps/scripting/JSInterface_Game.cpp b/source/ps/scripting/JSInterface_Game.cpp index eb59a18d0b..6021ea6d45 100644 --- a/source/ps/scripting/JSInterface_Game.cpp +++ b/source/ps/scripting/JSInterface_Game.cpp @@ -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, ""); diff --git a/source/ps/scripting/JSInterface_SavedGame.cpp b/source/ps/scripting/JSInterface_SavedGame.cpp index 70d8efb5f9..8c11d004df 100644 --- a/source/ps/scripting/JSInterface_SavedGame.cpp +++ b/source/ps/scripting/JSInterface_SavedGame.cpp @@ -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 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 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); diff --git a/source/ps/scripting/JSInterface_VFS.cpp b/source/ps/scripting/JSInterface_VFS.cpp index b35ad36e9e..6cf516eeb0 100644 --- a/source/ps/scripting/JSInterface_VFS.cpp +++ b/source/ps/scripting/JSInterface_VFS.cpp @@ -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); diff --git a/source/scriptinterface/NativeWrapperDefns.h b/source/scriptinterface/NativeWrapperDefns.h index 462cb2c485..300643d7e1 100644 --- a/source/scriptinterface/NativeWrapperDefns.h +++ b/source/scriptinterface/NativeWrapperDefns.h @@ -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 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); } diff --git a/source/scriptinterface/ScriptContext.cpp b/source/scriptinterface/ScriptContext.cpp index 7bb4509ccd..ec73a12105 100644 --- a/source/scriptinterface/ScriptContext.cpp +++ b/source/scriptinterface/ScriptContext.cpp @@ -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 diff --git a/source/scriptinterface/ScriptContext.h b/source/scriptinterface/ScriptContext.h index 8002752b8d..032d7da909 100644 --- a/source/scriptinterface/ScriptContext.h +++ b/source/scriptinterface/ScriptContext.h @@ -23,16 +23,14 @@ #include -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; diff --git a/source/scriptinterface/ScriptConversions.cpp b/source/scriptinterface/ScriptConversions.cpp index 26c4ce0073..054d920235 100644 --- a/source/scriptinterface/ScriptConversions.cpp +++ b/source/scriptinterface/ScriptConversions.cpp @@ -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(const ScriptRequest& rq, JS::HandleValue v, bool& out) { diff --git a/source/scriptinterface/ScriptExceptions.cpp b/source/scriptinterface/ScriptExceptions.cpp index f15495d0fe..4a2fb5dd3d 100644 --- a/source/scriptinterface/ScriptExceptions.cpp +++ b/source/scriptinterface/ScriptExceptions.cpp @@ -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); } diff --git a/source/scriptinterface/ScriptExceptions.h b/source/scriptinterface/ScriptExceptions.h index d8fff7151d..d6bc7891c2 100644 --- a/source/scriptinterface/ScriptExceptions.h +++ b/source/scriptinterface/ScriptExceptions.h @@ -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, diff --git a/source/scriptinterface/ScriptInterface.cpp b/source/scriptinterface/ScriptInterface.cpp index 6a3a302985..5d7f7583d6 100644 --- a/source/scriptinterface/ScriptInterface.cpp +++ b/source/scriptinterface/ScriptInterface.cpp @@ -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& 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 ScriptInterface::GetContext() const @@ -560,7 +566,7 @@ bool ScriptInterface::SetGlobal_(const char* name, JS::HandleValue value, bool r return false; if (found) { - JS::Rooted desc(rq.cx); + JS::Rooted 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 = 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::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(); + return ScriptInterface::StructuredClone(); } - shared_ptr ret(new StructuredClone); - ret->m_Data = data; - ret->m_Size = nbytes; return ret; } -void ScriptInterface::ReadStructuredClone(const shared_ptr& 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); } diff --git a/source/scriptinterface/ScriptInterface.h b/source/scriptinterface/ScriptInterface.h index 76761c235a..3381aaeb27 100644 --- a/source/scriptinterface/ScriptInterface.h +++ b/source/scriptinterface/ScriptInterface.h @@ -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 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; - shared_ptr WriteStructuredClone(JS::HandleValue v) const; - void ReadStructuredClone(const shared_ptr& 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. diff --git a/source/scriptinterface/ScriptStats.cpp b/source/scriptinterface/ScriptStats.cpp index a680d00648..3304e72b8a 100644 --- a/source/scriptinterface/ScriptStats.cpp +++ b/source/scriptinterface/ScriptStats.cpp @@ -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: diff --git a/source/scriptinterface/ScriptTypes.h b/source/scriptinterface/ScriptTypes.h index 4aa195e352..78be5a8e2b 100644 --- a/source/scriptinterface/ScriptTypes.h +++ b/source/scriptinterface/ScriptTypes.h @@ -55,6 +55,8 @@ #if MSC_VERSION // reduce the warning level for the SpiderMonkey headers # pragma warning(push, 1) +// ignore C4291 in +# pragma warning(disable: 4291) #endif #include "jspubtd.h" diff --git a/source/scriptinterface/tests/test_ScriptInterface.h b/source/scriptinterface/tests/test_ScriptInterface.h index ac06e967c5..d8c0d3359a 100644 --- a/source/scriptinterface/tests/test_ScriptInterface.h +++ b/source/scriptinterface/tests/test_ScriptInterface.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()); } } diff --git a/source/simulation2/Simulation2.cpp b/source/simulation2/Simulation2.cpp index a81c26c4a8..4def32622e 100644 --- a/source/simulation2/Simulation2.cpp +++ b/source/simulation2/Simulation2.cpp @@ -49,11 +49,11 @@ class CSimulation2Impl { public: - CSimulation2Impl(CUnitManager* unitManager, shared_ptr rt, CTerrain* terrain) : - m_SimContext(), m_ComponentManager(m_SimContext, rt), + CSimulation2Impl(CUnitManager* unitManager, shared_ptr 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 CloneCommandsFromOtherContext(const ScriptInterface& oldScript, const ScriptInterface& newScript, + static std::vector CloneCommandsFromOtherCompartment(const ScriptInterface& oldScript, const ScriptInterface& newScript, const std::vector& commands) { std::vector 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::vectorGetScriptInterface()); 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::vectorLoadMap(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::vectorGetScriptInterface(), 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 rt, CTerrain* terrain) : - m(new CSimulation2Impl(unitManager, rt, terrain)) +CSimulation2::CSimulation2(CUnitManager* unitManager, shared_ptr cx, CTerrain* terrain) : + m(new CSimulation2Impl(unitManager, cx, terrain)) { } diff --git a/source/simulation2/Simulation2.h b/source/simulation2/Simulation2.h index 907cfa2af4..6bc526cbfc 100644 --- a/source/simulation2/Simulation2.h +++ b/source/simulation2/Simulation2.h @@ -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 rt, CTerrain* terrain); + CSimulation2(CUnitManager* unitManager, shared_ptr cx, CTerrain* terrain); ~CSimulation2(); void EnableSerializationTest(); diff --git a/source/simulation2/components/CCmpAIManager.cpp b/source/simulation2/components/CCmpAIManager.cpp index ee7599a50e..e0edc1e938 100644 --- a/source/simulation2/components/CCmpAIManager.cpp +++ b/source/simulation2/components/CCmpAIManager.cpp @@ -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) : 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 m_ScriptInterface; JS::PersistentRootedValue m_Obj; - std::vector > m_Commands; + std::vector m_Commands; }; public: struct SCommandSets { player_id_t player; - std::vector > commands; + std::vector 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 (this)); - JS_AddExtraGCRootsTracer(m_ScriptInterface->GetJSRuntime(), Trace, this); + JS_AddExtraGCRootsTracer(m_ScriptInterface->GetGeneralJSContext(), Trace, this); m_ScriptInterface->RegisterFunction("PostCommand"); m_ScriptInterface->RegisterFunction("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& gameState, const Grid& passabilityMap, const Grid& territoryMap, + bool RunGamestateInit(const ScriptInterface::StructuredClone& gameState, const Grid& passabilityMap, const Grid& territoryMap, const std::map& nonPathfindingPassClassMasks, const std::map& 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& 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 m_LoadedModules; - shared_ptr m_GameState; + ScriptInterface::StructuredClone m_GameState; Grid m_PassabilityMap; JS::PersistentRootedValue m_PassabilityMapVal; Grid 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 cmpPathfinder(GetSystemEntity()); diff --git a/source/simulation2/components/ICmpAIManager.cpp b/source/simulation2/components/ICmpAIManager.cpp index 9b1ba1a060..54ba0312ac 100644 --- a/source/simulation2/components/ICmpAIManager.cpp +++ b/source/simulation2/components/ICmpAIManager.cpp @@ -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); diff --git a/source/simulation2/components/tests/test_Pathfinder.h b/source/simulation2/components/tests/test_Pathfinder.h index 3cb0a3c692..7bd459f6d8 100644 --- a/source/simulation2/components/tests/test_Pathfinder.h +++ b/source/simulation2/components/tests/test_Pathfinder.h @@ -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(); diff --git a/source/simulation2/scripting/EngineScriptConversions.cpp b/source/simulation2/scripting/EngineScriptConversions.cpp index f75110b438..3c28a1d174 100644 --- a/source/simulation2/scripting/EngineScriptConversions.cpp +++ b/source/simulation2/scripting/EngineScriptConversions.cpp @@ -168,8 +168,11 @@ template<> void ScriptInterface::ToJSVal(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(const ScriptRequest& rq, JS::HandleValue v, CFixedVector2D& out) @@ -200,8 +203,11 @@ template<> void ScriptInterface::ToJSVal(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 >(const ScriptRequest& rq, JS::MutableHandleValue ret, const Grid& val) diff --git a/source/simulation2/scripting/JSInterface_Simulation.cpp b/source/simulation2/scripting/JSInterface_Simulation.cpp index b1dce48ce3..b006fceee9 100644 --- a/source/simulation2/scripting/JSInterface_Simulation.cpp +++ b/source/simulation2/scripting/JSInterface_Simulation.cpp @@ -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); } diff --git a/source/simulation2/scripting/MessageTypeConversions.cpp b/source/simulation2/scripting/MessageTypeConversions.cpp index 2eee3d6a8d..344e318c48 100644 --- a/source/simulation2/scripting/MessageTypeConversions.cpp +++ b/source/simulation2/scripting/MessageTypeConversions.cpp @@ -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(); } diff --git a/source/simulation2/scripting/ScriptComponent.cpp b/source/simulation2/scripting/ScriptComponent.cpp index b30340b4a8..17202a64af 100644 --- a/source/simulation2/scripting/ScriptComponent.cpp +++ b/source/simulation2/scripting/ScriptComponent.cpp @@ -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); diff --git a/source/simulation2/serialization/BinarySerializer.cpp b/source/simulation2/serialization/BinarySerializer.cpp index 7dff1e636f..c8909e725b 100644 --- a/source/simulation2/serialization/BinarySerializer.cpp +++ b/source/simulation2/serialization/BinarySerializer.cpp @@ -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 desc(rq.cx); + JS::Rooted desc(rq.cx); if (!JS_GetPropertyDescriptorById(rq.cx, obj, id, &desc)) throw PSERROR_Serialize_ScriptError("JS_GetPropertyDescriptorById failed"); if (desc.hasGetterObject()) diff --git a/source/simulation2/serialization/StdDeserializer.cpp b/source/simulation2/serialization/StdDeserializer.cpp index 9c4689a795..1635aa7427 100644 --- a/source/simulation2/serialization/StdDeserializer.cpp +++ b/source/simulation2/serialization/StdDeserializer.cpp @@ -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) diff --git a/source/simulation2/system/ComponentManager.cpp b/source/simulation2/system/ComponentManager.cpp index 8bba681c96..cfcfb390a9 100644 --- a/source/simulation2/system/ComponentManager.cpp +++ b/source/simulation2/system/ComponentManager.cpp @@ -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 rt, bool skipScriptFunctions) : +CComponentManager::CComponentManager(CSimContext& context, shared_ptr 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); diff --git a/source/simulation2/system/ComponentManager.h b/source/simulation2/system/ComponentManager.h index 07089d1b21..70fd7be5ad 100644 --- a/source/simulation2/system/ComponentManager.h +++ b/source/simulation2/system/ComponentManager.h @@ -74,7 +74,7 @@ private: }; public: - CComponentManager(CSimContext&, shared_ptr rt, bool skipScriptFunctions = false); + CComponentManager(CSimContext&, shared_ptr cx, bool skipScriptFunctions = false); ~CComponentManager(); void LoadComponentTypes(); diff --git a/source/simulation2/system/TurnManager.cpp b/source/simulation2/system/TurnManager.cpp index 80e946fccb..e78c54f06c 100644 --- a/source/simulation2/system/TurnManager.cpp +++ b/source/simulation2/system/TurnManager.cpp @@ -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::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). diff --git a/source/simulation2/tests/test_Serializer.h b/source/simulation2/tests/test_Serializer.h index 593c02d5d6..98005999cc 100644 --- a/source/simulation2/tests/test_Serializer.h +++ b/source/simulation2/tests/test_Serializer.h @@ -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();