Exact stack rooting for ScriptInterface::ToString.

I had to change a few other functions to take JS::MutableHandleValue
because JS::Stringify takes a JS::MutableHandleValue as input parameter.
That seems a bit strange because it should not change that value.
I assume it has historical reasons.

Refs #2415
Refs #2462

This was SVN commit r15605.
This commit is contained in:
Yves 2014-08-03 17:29:49 +00:00
parent 1561f55b27
commit 169174824f
16 changed files with 50 additions and 39 deletions

View File

@ -185,13 +185,16 @@ void CNetClient::PushGuiMessage(const CScriptValRooted& message)
std::wstring CNetClient::TestReadGuiMessages()
{
JSContext* cx = GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
std::wstring r;
while (true)
{
CScriptValRooted msg = GuiPoll();
if (msg.undefined())
JS::RootedValue msg(cx, GuiPoll().get());
if (msg.isUndefined())
break;
r += GetScriptInterface().ToString(msg.get()) + L"\n";
r += GetScriptInterface().ToString(&msg) + L"\n";
}
return r;
}

View File

@ -133,7 +133,7 @@ u8* CSimulationMessage::Serialize(u8* pBuffer) const
serializer.NumberU32_Unbounded("client", m_Client);
serializer.NumberI32_Unbounded("player", m_Player);
serializer.NumberU32_Unbounded("turn", m_Turn);
serializer.ScriptVal("command", tmpData);
serializer.ScriptVal("command", &tmpData);
return serializer.GetBuffer();
}
@ -168,13 +168,16 @@ size_t CSimulationMessage::GetSerializedLength() const
serializer.NumberU32_Unbounded("client", m_Client);
serializer.NumberI32_Unbounded("player", m_Player);
serializer.NumberU32_Unbounded("turn", m_Turn);
serializer.ScriptVal("command", tmpData);
serializer.ScriptVal("command", &tmpData);
return CNetMessage::GetSerializedLength() + serializer.GetLength();
}
CStr CSimulationMessage::ToString() const
{
std::string source = utf8_from_wstring(m_ScriptInterface->ToString(m_Data.get()));
JSContext* cx = m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue tmpData(cx, m_Data.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade
std::string source = utf8_from_wstring(m_ScriptInterface->ToString(&tmpData));
std::stringstream stream;
stream << "CSimulationMessage { m_Client: " << m_Client << ", m_Player: " << m_Player << ", m_Turn: " << m_Turn << ", m_Data: " << source << " }";
@ -202,7 +205,7 @@ u8* CGameSetupMessage::Serialize(u8* pBuffer) const
u8* pos = CNetMessage::Serialize(pBuffer);
CBufferBinarySerializer serializer(m_ScriptInterface, pos);
serializer.ScriptVal("command", tmpData);
serializer.ScriptVal("command", &tmpData);
return serializer.GetBuffer();
}
@ -228,13 +231,16 @@ size_t CGameSetupMessage::GetSerializedLength() const
JS::RootedValue tmpData(cx, m_Data.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade
CLengthBinarySerializer serializer(m_ScriptInterface);
serializer.ScriptVal("command", tmpData);
serializer.ScriptVal("command", &tmpData);
return CNetMessage::GetSerializedLength() + serializer.GetLength();
}
CStr CGameSetupMessage::ToString() const
{
std::string source = utf8_from_wstring(m_ScriptInterface.ToString(m_Data.get()));
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedValue tmpData(cx, m_Data.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade
std::string source = utf8_from_wstring(m_ScriptInterface.ToString(&tmpData));
std::stringstream stream;
stream << "CGameSetupMessage { m_Data: " << source << " }";

View File

@ -611,7 +611,7 @@ void CConsole::ProcessBuffer(const wchar_t* szLine)
JS::RootedValue rval(cx);
pScriptInterface->Eval(szLine, &rval);
if (!rval.isUndefined())
InsertMessageRaw(pScriptInterface->ToString(rval));
InsertMessageRaw(pScriptInterface->ToString(&rval));
}
void CConsole::LoadHistory()

View File

@ -1319,7 +1319,7 @@ std::string ScriptInterface::StringifyJSON(JS::MutableHandleValue obj, bool inde
}
std::wstring ScriptInterface::ToString(jsval obj, bool pretty)
std::wstring ScriptInterface::ToString(JS::MutableHandleValue obj, bool pretty)
{
JSAutoRequest rq(m->m_cx);
@ -1335,7 +1335,7 @@ std::wstring ScriptInterface::ToString(jsval obj, bool pretty)
// Temporary disable the error reporter, so we don't print complaints about cyclic values
JSErrorReporter er = JS_SetErrorReporter(m->m_cx, NULL);
JSBool ok = JS_Stringify(m->m_cx, &obj, NULL, JS::NumberValue(2), &StringifierW::callback, &str);
JSBool ok = JS_Stringify(m->m_cx, obj.address(), NULL, JS::NumberValue(2), &StringifierW::callback, &str);
// Restore error reporter
JS_SetErrorReporter(m->m_cx, er);
@ -1351,8 +1351,7 @@ std::wstring ScriptInterface::ToString(jsval obj, bool pretty)
// so fall back to obj.toSource()
std::wstring source = L"(error)";
JS::RootedValue tmpObj(m->m_cx, obj); // TODO: pass Handle as argument already
CallFunction(tmpObj, "toSource", source);
CallFunction(obj, "toSource", source);
return source;
}

View File

@ -265,7 +265,8 @@ public:
template<typename CHAR> bool Eval(const CHAR* code, JS::MutableHandleValue out);
template<typename T, typename CHAR> bool Eval(const CHAR* code, T& out);
std::wstring ToString(jsval obj, bool pretty = false);
// We have to use a mutable handle because JS_Stringify requires that for unknown reasons.
std::wstring ToString(JS::MutableHandleValue obj, bool pretty = false);
/**
* Parse a UTF-8-encoded JSON string. Returns the unmodified value on error and prints an error message.

View File

@ -252,6 +252,6 @@ public:
TS_ASSERT_STR_EQUALS(stringified, "{\n \"x\": 1,\n \"z\": [\n 2,\n \"3\xE2\x98\xBA\xEF\xBF\xBD\"\n ],\n \"y\": true\n}");
script.ParseJSON(stringified, &val);
TS_ASSERT_WSTR_EQUALS(script.ToString(val.get()), L"({x:1, z:[2, \"3\\u263A\\uFFFD\"], y:true})");
TS_ASSERT_WSTR_EQUALS(script.ToString(&val), L"({x:1, z:[2, \"3\\u263A\\uFFFD\"], y:true})");
}
};

View File

@ -608,7 +608,7 @@ public:
JS::RootedValue tmpSharedAIObj(cx, m_SharedAIObj.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade
if (!m_ScriptInterface->CallFunction(tmpSharedAIObj, "Serialize", &sharedData))
LOGERROR(L"AI shared script Serialize call failed");
serializer.ScriptVal("sharedData", sharedData);
serializer.ScriptVal("sharedData", &sharedData);
}
for (size_t i = 0; i < m_Players.size(); ++i)
{
@ -621,7 +621,7 @@ public:
{
JS::RootedValue val(cx);
m_ScriptInterface->ReadStructuredClone(m_Players[i]->m_Commands[j], &val);
serializer.ScriptVal("command", val);
serializer.ScriptVal("command", &val);
}
JS::RootedValue tmpPlayerObj(cx, m_Players[i]->m_Obj.get()); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade
@ -631,11 +631,11 @@ public:
JS::RootedValue scriptData(cx);
if (!m_ScriptInterface->CallFunction(tmpPlayerObj, "Serialize", &scriptData))
LOGERROR(L"AI script Serialize call failed");
serializer.ScriptVal("data", scriptData);
serializer.ScriptVal("data", &scriptData);
}
else
{
serializer.ScriptVal("data", tmpPlayerObj);
serializer.ScriptVal("data", &tmpPlayerObj);
}
}
}

View File

@ -59,7 +59,7 @@ public:
{
tmpRoot.set(m_LocalQueue[i].data.get());
serialize.NumberI32_Unbounded("player", m_LocalQueue[i].player);
serialize.ScriptVal("data", tmpRoot);
serialize.ScriptVal("data", &tmpRoot);
}
}

View File

@ -93,11 +93,11 @@ void CComponentTypeScript::Serialize(ISerializer& serialize)
JS::RootedValue val(cx);
if (!m_ScriptInterface.CallFunction(tmpInstance, "Serialize", &val))
LOGERROR(L"Script Serialize call failed");
serialize.ScriptVal("object", val);
serialize.ScriptVal("object", &val);
}
else
{
serialize.ScriptVal("object", tmpInstance);
serialize.ScriptVal("object", &tmpInstance);
}
}

View File

@ -185,7 +185,7 @@ protected:
m_Impl.Put(name, (u8*)value.data(), value.length());
}
virtual void PutScriptVal(const char* UNUSED(name), JS::HandleValue value)
virtual void PutScriptVal(const char* UNUSED(name), JS::MutableHandleValue value)
{
m_ScriptImpl->HandleScriptVal(value);
}

View File

@ -147,7 +147,7 @@ void CDebugSerializer::PutString(const char* name, const std::string& value)
m_Stream << INDENT << name << ": " << "\"" << escaped << "\"\n";
}
void CDebugSerializer::PutScriptVal(const char* name, JS::HandleValue value)
void CDebugSerializer::PutScriptVal(const char* name, JS::MutableHandleValue value)
{
std::wstring source = m_ScriptInterface.ToString(value, true);

View File

@ -54,7 +54,7 @@ protected:
virtual void PutNumber(const char* name, fixed value);
virtual void PutBool(const char* name, bool value);
virtual void PutString(const char* name, const std::string& value);
virtual void PutScriptVal(const char* name, JS::HandleValue value);
virtual void PutScriptVal(const char* name, JS::MutableHandleValue value);
virtual void PutRaw(const char* name, const u8* data, size_t len);
private:

View File

@ -92,7 +92,7 @@ void ISerializer::String(const char* name, const std::wstring& value, uint32_t m
PutString(name, str);
}
void ISerializer::ScriptVal(const char* name, JS::HandleValue value)
void ISerializer::ScriptVal(const char* name, JS::MutableHandleValue value)
{
PutScriptVal(name, value);
}

View File

@ -216,10 +216,11 @@ public:
void String(const char* name, const std::wstring& value, uint32_t minlength, uint32_t maxlength);
/**
* Serialize a jsval.
* Serialize a JS::MutableHandleValue.
* The value must not contain any unserializable values (like functions).
* NOTE: We have to use a mutable handle because JS_Stringify requires that for unknown reasons.
*/
void ScriptVal(const char* name, JS::HandleValue value);
void ScriptVal(const char* name, JS::MutableHandleValue value);
/**
* Serialize a stream of bytes.
@ -255,7 +256,8 @@ protected:
virtual void PutNumber(const char* name, fixed value) = 0;
virtual void PutBool(const char* name, bool value) = 0;
virtual void PutString(const char* name, const std::string& value) = 0;
virtual void PutScriptVal(const char* name, JS::HandleValue value) = 0;
// We have to use a mutable handle because JS_Stringify requires that for unknown reasons.
virtual void PutScriptVal(const char* name, JS::MutableHandleValue value) = 0;
virtual void PutRaw(const char* name, const u8* data, size_t len) = 0;
};

View File

@ -135,19 +135,19 @@ public:
const CParamNode* inherit1 = tempMan->LoadTemplate(ent2, "inherit1", -1);
JS::RootedValue val(cx);
ScriptInterface::ToJSVal(cx, &val, inherit1);
TS_ASSERT_WSTR_EQUALS(man.GetScriptInterface().ToString(val.get()), L"({Test1A:{'@a':\"a1\", '@b':\"b1\", '@c':\"c1\", d:\"d1\", e:\"e1\", f:\"f1\"}})");
TS_ASSERT_WSTR_EQUALS(man.GetScriptInterface().ToString(&val), L"({Test1A:{'@a':\"a1\", '@b':\"b1\", '@c':\"c1\", d:\"d1\", e:\"e1\", f:\"f1\"}})");
const CParamNode* inherit2 = tempMan->LoadTemplate(ent2, "inherit2", -1);
ScriptInterface::ToJSVal(cx, &val, inherit2);
TS_ASSERT_WSTR_EQUALS(man.GetScriptInterface().ToString(val.get()), L"({'@parent':\"inherit1\", Test1A:{'@a':\"a2\", '@b':\"b1\", '@c':\"c1\", d:\"d2\", e:\"e1\", f:\"f1\", g:\"g2\"}})");
TS_ASSERT_WSTR_EQUALS(man.GetScriptInterface().ToString(&val), L"({'@parent':\"inherit1\", Test1A:{'@a':\"a2\", '@b':\"b1\", '@c':\"c1\", d:\"d2\", e:\"e1\", f:\"f1\", g:\"g2\"}})");
const CParamNode* actor = tempMan->LoadTemplate(ent2, "actor|example1", -1);
ScriptInterface::ToJSVal(cx, &val, &actor->GetChild("VisualActor"));
TS_ASSERT_WSTR_EQUALS(man.GetScriptInterface().ToString(val.get()), L"({Actor:\"example1\", ActorOnly:(void 0), SilhouetteDisplay:\"false\", SilhouetteOccluder:\"false\", VisibleInAtlasOnly:\"false\"})");
TS_ASSERT_WSTR_EQUALS(man.GetScriptInterface().ToString(&val), L"({Actor:\"example1\", ActorOnly:(void 0), SilhouetteDisplay:\"false\", SilhouetteOccluder:\"false\", VisibleInAtlasOnly:\"false\"})");
const CParamNode* foundation = tempMan->LoadTemplate(ent2, "foundation|actor|example1", -1);
ScriptInterface::ToJSVal(cx, &val, &foundation->GetChild("VisualActor"));
TS_ASSERT_WSTR_EQUALS(man.GetScriptInterface().ToString(val.get()), L"({Actor:\"example1\", ActorOnly:(void 0), Foundation:(void 0), SilhouetteDisplay:\"false\", SilhouetteOccluder:\"false\", VisibleInAtlasOnly:\"false\"})");
TS_ASSERT_WSTR_EQUALS(man.GetScriptInterface().ToString(&val), L"({Actor:\"example1\", ActorOnly:(void 0), Foundation:(void 0), SilhouetteDisplay:\"false\", SilhouetteOccluder:\"false\", VisibleInAtlasOnly:\"false\"})");
}
void test_LoadTemplate_errors()

View File

@ -276,7 +276,7 @@ public:
{
std::stringstream stream;
CDebugSerializer serialize(script, stream);
serialize.ScriptVal("script", obj);
serialize.ScriptVal("script", &obj);
TS_ASSERT_STR_EQUALS(stream.str(),
"script: {\n"
" \"x\": 123,\n"
@ -297,7 +297,7 @@ public:
std::stringstream stream;
CStdSerializer serialize(script, stream);
serialize.ScriptVal("script", obj);
serialize.ScriptVal("script", &obj);
TS_ASSERT_STREAM(stream, 119,
"\x03" // SCRIPT_TYPE_OBJECT
@ -352,7 +352,7 @@ public:
std::stringstream stream;
CStdSerializer serialize(script, stream);
serialize.ScriptVal("script", obj);
serialize.ScriptVal("script", &obj);
if (expstream)
{
@ -584,7 +584,7 @@ public:
TestLogger logger;
TS_ASSERT(script.Eval("([1, 2, function () { }])", &obj));
TS_ASSERT_THROWS(serialize.ScriptVal("script", obj), PSERROR_Serialize_InvalidScriptValue);
TS_ASSERT_THROWS(serialize.ScriptVal("script", &obj), PSERROR_Serialize_InvalidScriptValue);
}
void test_script_splice()
@ -619,7 +619,7 @@ public:
std::stringstream stream;
CStdSerializer serialize(script, stream);
serialize.ScriptVal("script", obj);
serialize.ScriptVal("script", &obj);
CStdDeserializer deserialize(script, stream);