Cache property keys during component serialization

(cherry picked from commit ab6a420f78)
(fixed build on this commit by moving a change to commit originally ea34960249)
Signed-off-by: Itms <itms@wildfiregames.com>
This commit is contained in:
Lancelot de Ferrière 2025-05-08 14:52:28 +02:00 committed by Itms
parent 0fdd6005b8
commit 520c489b68
No known key found for this signature in database
GPG key ID: C7E52BD14CE14E09
5 changed files with 32 additions and 22 deletions

View file

@ -62,6 +62,8 @@ CBinarySerializerScriptImpl::CBinarySerializerScriptImpl(const ScriptInterface&
{
ScriptRequest rq(m_ScriptInterface);
JS_AddExtraGCRootsTracer(rq.cx, Trace, this);
m_SerializePropId = JS::PropertyKey::fromPinnedString(JS_AtomizeAndPinString(rq.cx, "Serialize"));
m_DeserializePropId = JS::PropertyKey::fromPinnedString(JS_AtomizeAndPinString(rq.cx, "Deserialize"));
}
CBinarySerializerScriptImpl::~CBinarySerializerScriptImpl()
@ -227,7 +229,7 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
if (!JS_GetPrototype(rq.cx, obj, &proto))
throw PSERROR_Serialize_ScriptError("JS_GetPrototype failed");
SPrototypeSerialization protoInfo = GetPrototypeInfo(rq, proto);
SPrototypeSerialization protoInfo = GetPrototypeInfo(rq, proto, m_SerializePropId, m_DeserializePropId);
if (protoInfo.name == "Object")
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT);

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2024 Wildfire Games.
/* Copyright (C) 2025 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -98,6 +98,10 @@ private:
ObjectTagMap m_ScriptBackrefTags;
u32 m_ScriptBackrefsNext;
u32 GetScriptBackrefTag(JS::HandleObject obj);
JS::PropertyKey m_SerializePropId;
JS::PropertyKey m_DeserializePropId;
};
/**

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2023 Wildfire Games.
/* Copyright (C) 2025 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -63,7 +63,7 @@ struct SPrototypeSerialization
bool hasNullSerialize = false;
};
inline SPrototypeSerialization GetPrototypeInfo(const ScriptRequest& rq, JS::HandleObject prototype)
inline SPrototypeSerialization GetPrototypeInfo(const ScriptRequest& rq, JS::HandleObject prototype, JS::PropertyKey ser, JS::PropertyKey deser)
{
SPrototypeSerialization ret;
@ -74,24 +74,23 @@ inline SPrototypeSerialization GetPrototypeInfo(const ScriptRequest& rq, JS::Han
if (ret.name == "Object")
return ret;
if (!JS_HasProperty(rq.cx, prototype, "Serialize", &ret.hasCustomSerialize) ||
!JS_HasProperty(rq.cx, prototype, "Deserialize", &ret.hasCustomDeserialize))
throw PSERROR_Serialize_ScriptError("JS_HasProperty failed");
JS::RootedValue serialize(rq.cx);
if (!JS_GetPropertyById(rq.cx, prototype, JS::Handle<jsid>::fromMarkedLocation(&ser), &serialize))
throw PSERROR_Serialize_ScriptError("JS_GetProperty failed");
if (ret.hasCustomSerialize)
if (serialize.isUndefined())
return ret;
ret.hasCustomSerialize = true;
if (serialize.isNull())
ret.hasNullSerialize = true;
if (!JS_HasPropertyById(rq.cx, prototype, JS::Handle<jsid>::fromMarkedLocation(&deser), &ret.hasCustomDeserialize) ||
(!ret.hasNullSerialize && !ret.hasCustomDeserialize))
{
JS::RootedValue serialize(rq.cx);
if (!JS_GetProperty(rq.cx, prototype, "Serialize", &serialize))
throw PSERROR_Serialize_ScriptError("JS_GetProperty failed");
if (serialize.isNull())
ret.hasNullSerialize = true;
else if (!ret.hasCustomDeserialize)
{
// Don't throw for this error: mods might need updating and this crashes as exceptions are not correctly handled.
LOGERROR("Error serializing object '%s': non-null Serialize() but no matching Deserialize().", ret.name);
}
// Don't throw for this error: mods might need updating and this crashes as exceptions are not correctly handled.
LOGERROR("Error serializing object '%s': non-null Serialize() but no matching Deserialize().", ret.name);
}
return ret;
}

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2022 Wildfire Games.
/* Copyright (C) 2025 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -36,6 +36,9 @@ CStdDeserializer::CStdDeserializer(const ScriptInterface& scriptInterface, std::
m_ScriptInterface(scriptInterface), m_Stream(stream)
{
JS_AddExtraGCRootsTracer(ScriptRequest(scriptInterface).cx, CStdDeserializer::Trace, this);
m_SerializePropId = JS::PropertyKey::fromPinnedString(JS_AtomizeAndPinString(rq.cx, "Serialize"));
m_DeserializePropId = JS::PropertyKey::fromPinnedString(JS_AtomizeAndPinString(rq.cx, "Deserialize"));
// Insert a dummy object in front, as valid tags start at 1.
m_ScriptBackrefs.emplace_back(nullptr);
}
@ -168,7 +171,7 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
JS::RootedObject prototype(rq.cx);
JS_GetPrototype(rq.cx, obj, &prototype);
SPrototypeSerialization info = GetPrototypeInfo(rq, prototype);
SPrototypeSerialization info = GetPrototypeInfo(rq, prototype, m_SerializePropId, m_DeserializePropId);
if (preexistingObject != nullptr && prototypeName != wstring_from_utf8(info.name))
throw PSERROR_Deserialize_ScriptError("Deserializer failed: incorrect pre-existing object");

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2021 Wildfire Games.
/* Copyright (C) 2025 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -52,6 +52,8 @@ private:
virtual void AddScriptBackref(JS::HandleObject obj);
virtual void GetScriptBackref(size_t tag, JS::MutableHandleObject ret);
std::vector<JS::Heap<JSObject*> > m_ScriptBackrefs;
JS::PropertyKey m_SerializePropId;
JS::PropertyKey m_DeserializePropId;
const ScriptInterface& m_ScriptInterface;