From 8b9847e0070290cf73c22565d0829514a463b94e Mon Sep 17 00:00:00 2001 From: Yves Date: Sun, 9 Nov 2014 15:16:00 +0000 Subject: [PATCH] Replace CScriptValRooted with JS::Heap and custom tracer for CNetClient Refs #2462 This was SVN commit r15946. --- source/gui/scripting/ScriptFunctions.cpp | 3 +- source/network/NetClient.cpp | 53 +++++++++++++++--------- source/network/NetClient.h | 21 ++++++++-- 3 files changed, 52 insertions(+), 25 deletions(-) diff --git a/source/gui/scripting/ScriptFunctions.cpp b/source/gui/scripting/ScriptFunctions.cpp index 904d89e1d8..64b230989d 100644 --- a/source/gui/scripting/ScriptFunctions.cpp +++ b/source/gui/scripting/ScriptFunctions.cpp @@ -395,7 +395,8 @@ CScriptVal PollNetworkClient(ScriptInterface::CxPrivate* pCxPrivate) // Convert from net client context to GUI script context JSContext* cxNet = g_NetClient->GetScriptInterface().GetContext(); JSAutoRequest rqNet(cxNet); - JS::RootedValue pollNet(cxNet, g_NetClient->GuiPoll().get()); + JS::RootedValue pollNet(cxNet); + g_NetClient->GuiPoll(&pollNet); return pCxPrivate->pScriptInterface->CloneValueFromOtherContext(g_NetClient->GetScriptInterface(), pollNet); } diff --git a/source/network/NetClient.cpp b/source/network/NetClient.cpp index 71b32a7f1a..8062cc8b24 100644 --- a/source/network/NetClient.cpp +++ b/source/network/NetClient.cpp @@ -74,6 +74,8 @@ CNetClient::CNetClient(CGame* game) : m_Game->SetTurnManager(NULL); // delete the old local turn manager so we don't accidentally use it void* context = this; + + JS_AddExtraGCRootsTracer(GetScriptInterface().GetJSRuntime(), CNetClient::Trace, this); // Set up transitions for session AddTransition(NCS_UNCONNECTED, (uint)NMT_CONNECT_COMPLETE, NCS_CONNECT, (void*)&OnConnect, context); @@ -120,6 +122,14 @@ CNetClient::CNetClient(CGame* game) : CNetClient::~CNetClient() { DestroyConnection(); + JS_RemoveExtraGCRootsTracer(GetScriptInterface().GetJSRuntime(), CNetClient::Trace, this); +} + +void CNetClient::TraceMember(JSTracer *trc) +{ + std::deque >::iterator itr; + for (itr=m_GuiMessageQueue.begin(); itr != m_GuiMessageQueue.end(); ++itr) + JS_CallHeapValueTracer(trc, &*itr, "m_GuiMessageQueue"); } void CNetClient::SetUserName(const CStrW& username) @@ -166,21 +176,23 @@ void CNetClient::Flush() m_Session->Flush(); } -CScriptValRooted CNetClient::GuiPoll() +void CNetClient::GuiPoll(JS::MutableHandleValue ret) { if (m_GuiMessageQueue.empty()) - return CScriptValRooted(); + { + ret.setUndefined(); + return; + } - CScriptValRooted r = m_GuiMessageQueue.front(); + ret.set(m_GuiMessageQueue.front()); m_GuiMessageQueue.pop_front(); - return r; } -void CNetClient::PushGuiMessage(const CScriptValRooted& message) -{ - ENSURE(!message.undefined()); +void CNetClient::PushGuiMessage(const JS::HandleValue message) +{ + ENSURE(!message.isUndefined()); - m_GuiMessageQueue.push_back(message); + m_GuiMessageQueue.push_back(JS::Heap(message)); } std::wstring CNetClient::TestReadGuiMessages() @@ -189,9 +201,10 @@ std::wstring CNetClient::TestReadGuiMessages() JSAutoRequest rq(cx); std::wstring r; + JS::RootedValue msg(cx); while (true) { - JS::RootedValue msg(cx, GuiPoll().get()); + GuiPoll(&msg); if (msg.isUndefined()) break; r += GetScriptInterface().ToString(&msg) + L"\n"; @@ -225,7 +238,7 @@ void CNetClient::PostPlayerAssignmentsToScript() GetScriptInterface().SetProperty(hosts, it->first.c_str(), host, false); } - PushGuiMessage(CScriptValRooted(cx, msg)); + PushGuiMessage(msg); } bool CNetClient::SendMessage(const CNetMessage* message) @@ -249,7 +262,7 @@ void CNetClient::HandleDisconnect(u32 reason) JS::RootedValue msg(cx); GetScriptInterface().Eval("({'type':'netstatus','status':'disconnected'})", &msg); GetScriptInterface().SetProperty(msg, "reason", (int)reason, false); - PushGuiMessage(CScriptValRooted(cx, msg)); + PushGuiMessage(msg); SAFE_DELETE(m_Session); @@ -343,14 +356,14 @@ void CNetClient::LoadFinished() JS::RootedValue msg(cx); GetScriptInterface().Eval("({'type':'netstatus','status':'join_syncing'})", &msg); - PushGuiMessage(CScriptValRooted(cx, msg)); + PushGuiMessage(msg); } else { // Connecting at the start of a game, so we'll wait for other players to finish loading JS::RootedValue msg(cx); GetScriptInterface().Eval("({'type':'netstatus','status':'waiting_for_players'})", &msg); - PushGuiMessage(CScriptValRooted(cx, msg)); + PushGuiMessage(msg); } CLoadedGameMessage loaded; @@ -369,7 +382,7 @@ bool CNetClient::OnConnect(void* context, CFsmEvent* event) JS::RootedValue msg(cx); client->GetScriptInterface().Eval("({'type':'netstatus','status':'connected'})", &msg); - client->PushGuiMessage(CScriptValRooted(cx, msg)); + client->PushGuiMessage(msg); return true; } @@ -424,7 +437,7 @@ bool CNetClient::OnAuthenticate(void* context, CFsmEvent* event) JS::RootedValue msg(cx); client->GetScriptInterface().Eval("({'type':'netstatus','status':'authenticated'})", &msg); client->GetScriptInterface().SetProperty(msg, "rejoining", isRejoining); - client->PushGuiMessage(CScriptValRooted(cx, msg)); + client->PushGuiMessage(msg); return true; } @@ -443,7 +456,7 @@ bool CNetClient::OnChat(void* context, CFsmEvent* event) client->GetScriptInterface().Eval("({'type':'chat'})", &msg); client->GetScriptInterface().SetProperty(msg, "guid", std::string(message->m_GUID), false); client->GetScriptInterface().SetProperty(msg, "text", std::wstring(message->m_Message), false); - client->PushGuiMessage(CScriptValRooted(cx, msg)); + client->PushGuiMessage(msg); return true; } @@ -462,7 +475,7 @@ bool CNetClient::OnReady(void* context, CFsmEvent* event) client->GetScriptInterface().Eval("({'type':'ready'})", &msg); client->GetScriptInterface().SetProperty(msg, "guid", std::string(message->m_GUID), false); client->GetScriptInterface().SetProperty(msg, "status", int (message->m_Status), false); - client->PushGuiMessage(CScriptValRooted(cx, msg)); + client->PushGuiMessage(msg); return true; } @@ -482,7 +495,7 @@ bool CNetClient::OnGameSetup(void* context, CFsmEvent* event) JS::RootedValue msg(cx); client->GetScriptInterface().Eval("({'type':'gamesetup'})", &msg); client->GetScriptInterface().SetProperty(msg, "data", message->m_Data, false); - client->PushGuiMessage(CScriptValRooted(cx, msg)); + client->PushGuiMessage(msg); return true; } @@ -535,7 +548,7 @@ bool CNetClient::OnGameStart(void* context, CFsmEvent* event) JS::RootedValue msg(cx); client->GetScriptInterface().Eval("({'type':'start'})", &msg); - client->PushGuiMessage(CScriptValRooted(cx, msg)); + client->PushGuiMessage(msg); return true; } @@ -584,7 +597,7 @@ bool CNetClient::OnLoadedGame(void* context, CFsmEvent* event) JS::RootedValue msg(cx); client->GetScriptInterface().Eval("({'type':'netstatus','status':'active'})", &msg); - client->PushGuiMessage(CScriptValRooted(cx, msg)); + client->PushGuiMessage(msg); return true; } diff --git a/source/network/NetClient.h b/source/network/NetClient.h index 35ea21ab42..5c1bb71fa6 100644 --- a/source/network/NetClient.h +++ b/source/network/NetClient.h @@ -68,7 +68,20 @@ public: CNetClient(CGame* game); virtual ~CNetClient(); - + + /** + * We assume that adding a tracing function that's only called + * during GC is better for performance than using a + * PersistentRooted where each value needs to be added to + * the root set. + */ + static void Trace(JSTracer *trc, void *data) + { + reinterpret_cast(data)->TraceMember(trc); + } + + void TraceMember(JSTracer *trc); + /** * Set the user's name that will be displayed to all players. * This must not be called after the connection setup. @@ -115,13 +128,13 @@ public: * * @return next message, or the value 'undefined' if the queue is empty */ - CScriptValRooted GuiPoll(); + void GuiPoll(JS::MutableHandleValue); /** * Add a message to the queue, to be read by GuiPoll. * The script value must be in the GetScriptInterface() JS context. */ - void PushGuiMessage(const CScriptValRooted& message); + void PushGuiMessage(const JS::HandleValue message); /** * Return a concatenation of all messages in the GUI queue, @@ -215,7 +228,7 @@ private: CStr m_GUID; /// Queue of messages for GuiPoll - std::deque m_GuiMessageQueue; + std::deque > m_GuiMessageQueue; /// Serialized game state received when joining an in-progress game std::string m_JoinSyncBuffer;