1
0
forked from 0ad/0ad

Remove serializablePrototype code

The script interface has code to serialize/deserialize JS objects with a
user-defined prototype. That code is usable in the AI, but currently
unused (and there are no plans to use it in the long run).

Removing it allows removing more code down the line, which helps with
the SM45-52 migration.

Collaboration with itms.

Refs #4893

Differential Revision: https://code.wildfiregames.com/D2897
This was SVN commit r24157.
This commit is contained in:
wraitii 2020-11-11 08:43:13 +00:00
parent 9c46062319
commit f22449bf24
6 changed files with 11 additions and 188 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -216,7 +216,6 @@ public:
m_CommandsComputed(true),
m_HasLoadedEntityTemplates(false),
m_HasSharedComponent(false),
m_SerializablePrototypes(new ObjectIdCache<std::wstring>(g_ScriptRuntime)),
m_EntityTemplates(g_ScriptRuntime->m_rt),
m_SharedAIObj(g_ScriptRuntime->m_rt),
m_PassabilityMapVal(g_ScriptRuntime->m_rt),
@ -227,7 +226,6 @@ public:
m_ScriptInterface->SetCallbackData(static_cast<void*> (this));
m_SerializablePrototypes->init();
JS_AddExtraGCRootsTracer(m_ScriptInterface->GetJSRuntime(), Trace, this);
m_ScriptInterface->RegisterFunction<void, int, JS::HandleValue, CAIWorker::PostCommand>("PostCommand");
@ -660,8 +658,6 @@ public:
else
{
CStdSerializer serializer(*m_ScriptInterface, stream);
// TODO: see comment in Deserialize()
serializer.SetSerializablePrototypes(m_SerializablePrototypes);
SerializeState(serializer);
}
}
@ -782,12 +778,6 @@ public:
m_Players.back()->m_Commands.push_back(m_ScriptInterface->WriteStructuredClone(val));
}
// TODO: this is yucky but necessary while the AIs are sharing data between contexts;
// ideally a new (de)serializer instance would be created for each player
// so they would have a single, consistent script context to use and serializable
// prototypes could be stored in their ScriptInterface
deserializer.SetSerializablePrototypes(m_DeserializablePrototypes);
bool hasCustomDeserialize = m_ScriptInterface->HasProperty(m_Players.back()->m_Obj, "Deserialize");
if (hasCustomDeserialize)
{
@ -826,25 +816,6 @@ public:
return m_Players.size();
}
void RegisterSerializablePrototype(std::wstring name, JS::HandleValue proto)
{
// Require unique prototype and name (for reverse lookup)
// TODO: this is yucky - see comment in Deserialize()
ENSURE(proto.isObject() && "A serializable prototype has to be an object!");
JSContext* cx = m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS::RootedObject obj(cx, &proto.toObject());
if (m_SerializablePrototypes->has(obj) || m_DeserializablePrototypes.find(name) != m_DeserializablePrototypes.end())
{
LOGERROR("RegisterSerializablePrototype called with same prototype multiple times: p=%p n='%s'", (void *)obj.get(), utf8_from_wstring(name));
return;
}
m_SerializablePrototypes->add(cx, obj, name);
m_DeserializablePrototypes[name] = JS::Heap<JSObject*>(obj);
}
private:
static void Trace(JSTracer *trc, void *data)
{
@ -853,8 +824,6 @@ private:
void TraceMember(JSTracer *trc)
{
for (std::pair<const std::wstring, JS::Heap<JSObject*>>& prototype : m_DeserializablePrototypes)
JS_CallObjectTracer(trc, &prototype.second, "CAIWorker::m_DeserializablePrototypes");
for (std::pair<const VfsPath, JS::Heap<JS::Value>>& metadata : m_PlayerMetadata)
JS_CallValueTracer(trc, &metadata.second, "CAIWorker::m_PlayerMetadata");
}
@ -943,8 +912,6 @@ private:
bool m_CommandsComputed;
shared_ptr<ObjectIdCache<std::wstring> > m_SerializablePrototypes;
std::map<std::wstring, JS::Heap<JSObject*> > m_DeserializablePrototypes;
CTemplateLoader m_TemplateLoader;
};

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -56,10 +56,9 @@ static u8 GetArrayType(js::Scalar::Type arrayType)
CBinarySerializerScriptImpl::CBinarySerializerScriptImpl(const ScriptInterface& scriptInterface, ISerializer& serializer) :
m_ScriptInterface(scriptInterface), m_Serializer(serializer), m_ScriptBackrefs(scriptInterface.GetRuntime()),
m_SerializablePrototypes(new ObjectIdCache<std::wstring>(scriptInterface.GetRuntime())), m_ScriptBackrefsNext(1)
m_ScriptBackrefsNext(1)
{
m_ScriptBackrefs.init();
m_SerializablePrototypes->init();
}
void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
@ -152,52 +151,9 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
JSProtoKey protokey = JSCLASS_CACHED_PROTO_KEY(jsclass);
if (protokey == JSProto_Object)
{
// Object class - check for user-defined prototype
JS::RootedObject proto(cx);
JS_GetPrototype(cx, obj, &proto);
if (!proto)
throw PSERROR_Serialize_ScriptError("JS_GetPrototype failed");
if (m_SerializablePrototypes->empty() || !IsSerializablePrototype(proto))
{
// Standard Object prototype
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT);
// TODO: maybe we should throw an error for unrecognized non-Object prototypes?
// (requires fixing AI serialization first and excluding component scripts)
}
else
{
// User-defined custom prototype
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_PROTOTYPE);
const std::wstring prototypeName = GetPrototypeName(proto);
m_Serializer.String("proto name", prototypeName, 0, 256);
// Does it have custom Serialize function?
// if so, we serialize the data it returns, rather than the object's properties directly
bool hasCustomSerialize;
if (!JS_HasProperty(cx, obj, "Serialize", &hasCustomSerialize))
throw PSERROR_Serialize_ScriptError("JS_HasProperty failed");
if (hasCustomSerialize)
{
JS::RootedValue serialize(cx);
if (!JS_GetProperty(cx, obj, "Serialize", &serialize))
throw PSERROR_Serialize_ScriptError("JS_GetProperty failed");
// If serialize is null, so don't serialize anything more
if (!serialize.isNull())
{
JS::RootedValue data(cx);
if (!m_ScriptInterface.CallFunction(val, "Serialize", &data))
throw PSERROR_Serialize_ScriptError("Prototype Serialize function failed");
HandleScriptVal(data);
}
break;
}
}
}
else if (protokey == JSProto_Number)
{
@ -474,21 +430,3 @@ u32 CBinarySerializerScriptImpl::GetScriptBackrefTag(JS::HandleObject obj)
// Return a non-tag number so callers know they need to serialize the object
return 0;
}
bool CBinarySerializerScriptImpl::IsSerializablePrototype(JS::HandleObject prototype)
{
return m_SerializablePrototypes->has(prototype);
}
std::wstring CBinarySerializerScriptImpl::GetPrototypeName(JS::HandleObject prototype)
{
std::wstring ret;
bool found = m_SerializablePrototypes->find(prototype, ret);
ENSURE(found);
return ret;
}
void CBinarySerializerScriptImpl::SetSerializablePrototypes(shared_ptr<ObjectIdCache<std::wstring> > prototypes)
{
m_SerializablePrototypes = prototypes;
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2017 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -87,7 +87,6 @@ public:
void ScriptString(const char* name, JS::HandleString string);
void HandleScriptVal(JS::HandleValue val);
void SetSerializablePrototypes(shared_ptr<ObjectIdCache<std::wstring> > prototypes);
private:
const ScriptInterface& m_ScriptInterface;
ISerializer& m_Serializer;
@ -95,11 +94,6 @@ private:
ObjectIdCache<u32> m_ScriptBackrefs;
u32 m_ScriptBackrefsNext;
u32 GetScriptBackrefTag(JS::HandleObject obj);
shared_ptr<ObjectIdCache<std::wstring> > m_SerializablePrototypes;
bool IsSerializablePrototype(JS::HandleObject prototype);
std::wstring GetPrototypeName(JS::HandleObject prototype);
};
/**
@ -127,11 +121,6 @@ public:
{
}
virtual void SetSerializablePrototypes(shared_ptr<ObjectIdCache<std::wstring> >& prototypes)
{
m_ScriptImpl->SetSerializablePrototypes(prototypes);
}
protected:
/*
The Put* implementations here are designed for subclasses

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2015 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -31,7 +31,7 @@ enum
SCRIPT_TYPE_BACKREF = 8,
SCRIPT_TYPE_TYPED_ARRAY = 9, // ArrayBufferView subclasses - see below
SCRIPT_TYPE_ARRAY_BUFFER = 10, // ArrayBuffer containing actual typed array data (may be shared by multiple views)
SCRIPT_TYPE_OBJECT_PROTOTYPE = 11, // user-defined prototype
SCRIPT_TYPE_OBJECT_PROTOTYPE = 11, // user-defined prototype - currently unused
SCRIPT_TYPE_OBJECT_NUMBER = 12, // standard Number class
SCRIPT_TYPE_OBJECT_STRING = 13, // standard String class
SCRIPT_TYPE_OBJECT_BOOLEAN = 14, // standard Boolean class

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -56,9 +56,6 @@ void CStdDeserializer::TraceMember(JSTracer *trc)
{
for (size_t i=0; i<m_ScriptBackrefs.size(); ++i)
JS_CallObjectTracer(trc, &m_ScriptBackrefs[i], "StdDeserializer::m_ScriptBackrefs");
for (std::pair<const std::wstring, JS::Heap<JSObject*>>& proto : m_SerializablePrototypes)
JS_CallObjectTracer(trc, &proto.second, "StdDeserializer::m_SerializablePrototypes");
}
void CStdDeserializer::Get(const char* name, u8* data, size_t len)
@ -139,7 +136,6 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
case SCRIPT_TYPE_ARRAY:
case SCRIPT_TYPE_OBJECT:
case SCRIPT_TYPE_OBJECT_PROTOTYPE:
{
JS::RootedObject obj(cx);
if (appendParent)
@ -152,51 +148,10 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
NumberU32_Unbounded("array length", length);
obj.set(JS_NewArrayObject(cx, length));
}
else if (type == SCRIPT_TYPE_OBJECT)
else // SCRIPT_TYPE_OBJECT
{
obj.set(JS_NewPlainObject(cx));
}
else // SCRIPT_TYPE_OBJECT_PROTOTYPE
{
std::wstring prototypeName;
String("proto name", prototypeName, 0, 256);
// Get constructor object
JS::RootedObject proto(cx);
GetSerializablePrototype(prototypeName, &proto);
if (!proto)
throw PSERROR_Deserialize_ScriptError("Failed to find serializable prototype for object");
obj.set(JS_NewObjectWithGivenProto(cx, nullptr, proto));
if (!obj)
throw PSERROR_Deserialize_ScriptError("JS_NewObject failed");
// Does it have custom Deserialize function?
// if so, we let it handle the deserialized data, rather than adding properties directly
bool hasCustomDeserialize, hasCustomSerialize;
if (!JS_HasProperty(cx, obj, "Serialize", &hasCustomSerialize) || !JS_HasProperty(cx, obj, "Deserialize", &hasCustomDeserialize))
throw PSERROR_Serialize_ScriptError("JS_HasProperty failed");
if (hasCustomDeserialize)
{
AddScriptBackref(obj);
JS::RootedValue serialize(cx);
if (!JS_GetProperty(cx, obj, "Serialize", &serialize))
throw PSERROR_Serialize_ScriptError("JS_GetProperty failed");
bool hasNullSerialize = hasCustomSerialize && serialize.isNull();
// If Serialize is null, we'll still call Deserialize but with undefined argument
JS::RootedValue data(cx);
if (!hasNullSerialize)
ScriptVal("data", &data);
JS::RootedValue objVal(cx, JS::ObjectValue(*obj));
m_ScriptInterface.CallFunctionVoid(objVal, "Deserialize", data);
return JS::ObjectValue(*obj);
}
}
if (!obj)
throw PSERROR_Deserialize_ScriptError("Deserializer failed to create new object");
@ -501,22 +456,3 @@ void CStdDeserializer::ScriptObjectAppend(const char* name, JS::HandleValue objV
JS::RootedObject obj(cx, &objVal.toObject());
ReadScriptVal(name, obj);
}
void CStdDeserializer::SetSerializablePrototypes(std::map<std::wstring, JS::Heap<JSObject*> >& prototypes)
{
m_SerializablePrototypes = prototypes;
}
bool CStdDeserializer::IsSerializablePrototype(const std::wstring& name)
{
return m_SerializablePrototypes.find(name) != m_SerializablePrototypes.end();
}
void CStdDeserializer::GetSerializablePrototype(const std::wstring& name, JS::MutableHandleObject ret)
{
std::map<std::wstring, JS::Heap<JSObject*> >::iterator it = m_SerializablePrototypes.find(name);
if (it != m_SerializablePrototypes.end())
ret.set(it->second);
else
ret.set(NULL);
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2017 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -38,8 +38,6 @@ public:
virtual std::istream& GetStream();
virtual void RequireBytesInStream(size_t numBytes);
virtual void SetSerializablePrototypes(std::map<std::wstring, JS::Heap<JSObject*> >& prototypes);
static void Trace(JSTracer *trc, void *data);
void TraceMember(JSTracer *trc);
@ -60,11 +58,6 @@ private:
const ScriptInterface& m_ScriptInterface;
std::istream& m_Stream;
std::map<std::wstring, JS::Heap<JSObject*> > m_SerializablePrototypes;
bool IsSerializablePrototype(const std::wstring& name);
void GetSerializablePrototype(const std::wstring& name, JS::MutableHandleObject ret);
};
#endif // INCLUDED_STDDESERIALIZER