Skip to content

Commit

Permalink
Avoid unncessary copy of objects lists for last event of events lists
Browse files Browse the repository at this point in the history
  • Loading branch information
4ian committed Dec 31, 2016
1 parent 4825313 commit a81170d
Show file tree
Hide file tree
Showing 8 changed files with 533 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ void EventsCodeGenerationContext::InheritsFrom(const EventsCodeGenerationContext
}
}

void EventsCodeGenerationContext::Reuse(const EventsCodeGenerationContext & parent_)
{
InheritsFrom(parent_);
if (parent_.CanReuse())
contextDepth = parent_.GetContextDepth(); // Keep same context depth
}

void EventsCodeGenerationContext::ObjectsListNeeded(const gd::String & objectName)
{
if ( emptyObjectsListsToBeDeclared.find(objectName) == emptyObjectsListsToBeDeclared.end() )
Expand Down
31 changes: 30 additions & 1 deletion Core/GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@ class GD_CORE_API EventsCodeGenerationContext
* Default constructor. You may want to call InheritsFrom just after.
* \param maxDepthLevel Optional pointer to an unsigned integer that will be updated to contain the maximal scope depth reached.
*/
EventsCodeGenerationContext(unsigned int * maxDepthLevel_ = nullptr) : contextDepth(0), customConditionDepth(0), maxDepthLevel(maxDepthLevel_), parent(NULL) {};
EventsCodeGenerationContext(unsigned int * maxDepthLevel_ = nullptr) :
contextDepth(0),
customConditionDepth(0),
maxDepthLevel(maxDepthLevel_),
parent(NULL),
reuseExplicitlyForbidden(false)
{};
virtual ~EventsCodeGenerationContext() {};

/**
Expand All @@ -41,6 +47,28 @@ class GD_CORE_API EventsCodeGenerationContext
*/
void InheritsFrom(const EventsCodeGenerationContext & parent);

/**
* \brief As InheritsFrom, mark the context as being the child of another one, but enabling
* the child context to use the same object lists.
*
* Used for example for optimizing the last event of a list.
*/
void Reuse(const EventsCodeGenerationContext & parent);

/**
* \brief Forbid any optimization that would reuse and modify the object list from this context
* in children context.
*
* Used in while/for each/repeat or any event that have a loop and must ensure that
* the list of objects stay clean.
*/
void ForbidReuse() { reuseExplicitlyForbidden = true; }

/**
* \brief Return false if the object lists of the context can not be reused in a child context.
*/
bool CanReuse() const { return !reuseExplicitlyForbidden && parent != nullptr; }

/**
* \brief Returns the depth of the inheritance of the context.
*
Expand Down Expand Up @@ -150,6 +178,7 @@ class GD_CORE_API EventsCodeGenerationContext
unsigned int customConditionDepth; ///< The depth of the conditions being generated.
unsigned int * maxDepthLevel; ///< A pointer to a unsigned int updated with the maximum depth reached.
const EventsCodeGenerationContext * parent; ///< The parent of the current context. Can be NULL.
bool reuseExplicitlyForbidden; ///< If set to true, forbid children context to reuse this one without inheriting.
};

}
Expand Down
13 changes: 11 additions & 2 deletions Core/GDCore/Events/CodeGeneration/EventsCodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -675,8 +675,17 @@ gd::String EventsCodeGenerator::GenerateEventsListCode(gd::EventsList & events,
for ( std::size_t eId = 0; eId < events.size();++eId )
{
//Each event has its own context : Objects picked in an event are totally different than the one picked in another.
gd::EventsCodeGenerationContext context;
context.InheritsFrom(parentContext); //Events in the same "level" share the same context as their parent.
gd::EventsCodeGenerationContext newContext;
newContext.InheritsFrom(parentContext); //Events in the same "level" share the same context as their parent.

//*Optimization*: when the event is the last of a list, we can use the
//same lists of objects as the parent (as they will be discarded just after).
//This avoids a copy of the lists of objects which is an expensive operation.
bool reuseParentContext = parentContext.CanReuse() && eId == events.size()-1;
gd::EventsCodeGenerationContext reusedContext;
reusedContext.Reuse(parentContext);

auto & context = reuseParentContext ? reusedContext : newContext;

gd::String eventCoreCode = events[eId].GenerateEventCode(*this, context);
gd::String scopeBegin = GenerateScopeBegin(context);
Expand Down
4 changes: 2 additions & 2 deletions Core/GDCore/Events/CodeGeneration/EventsCodeGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class GD_CORE_API EventsCodeGenerator
virtual ~EventsCodeGenerator() {};

/**
* \brief Preprocess an events list ( Replacing for example links with the linked event ).
* \brief Preprocess an events list (replacing for example links with the linked events).
*
* This should be called before any code generation.
*/
Expand All @@ -57,7 +57,7 @@ class GD_CORE_API EventsCodeGenerator
*
* \param events std::vector of events
* \param context Context used for generation
* \return C++ code
* \return Code
*/
gd::String GenerateEventsListCode(gd::EventsList & events, const EventsCodeGenerationContext & context);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ CommonInstructionsExtension::CommonInstructionsExtension()
//For example, two sub conditions using an object called "MyObject" will both have to declare a "MyObject" object list.
gd::EventsCodeGenerationContext context;
context.InheritsFrom(parentContext);
context.ForbidReuse(); //TODO: This may not be necessary

gd::String conditionCode = codeGenerator.GenerateConditionCode(conditions[cId], "condition"+gd::String::From(cId)+"IsTrue", context);

Expand Down Expand Up @@ -244,6 +245,7 @@ CommonInstructionsExtension::CommonInstructionsExtension()
//Context is "reset" each time the event is repeated ( i.e. objects are picked again )
gd::EventsCodeGenerationContext context;
context.InheritsFrom(parentContext);
context.ForbidReuse();
if ( event.HasInfiniteLoopWarning() && !codeGenerator.GenerateCodeForRuntime() ) codeGenerator.AddIncludeFile("GDCpp/Extensions/Builtin/RuntimeSceneTools.h");

//Prepare codes
Expand Down Expand Up @@ -300,6 +302,7 @@ CommonInstructionsExtension::CommonInstructionsExtension()
//Context is "reset" each time the event is repeated ( i.e. objects are picked again )
gd::EventsCodeGenerationContext context;
context.InheritsFrom(parentContext);
context.ForbidReuse();

//Prepare conditions/actions codes
gd::String conditionsCode = codeGenerator.GenerateConditionsListCode(event.GetConditions(), context);
Expand Down Expand Up @@ -347,6 +350,7 @@ CommonInstructionsExtension::CommonInstructionsExtension()
//Context is "reset" each time the event is repeated ( i.e. objects are picked again )
gd::EventsCodeGenerationContext context;
context.InheritsFrom(parentContext);
context.ForbidReuse();

//Prepare conditions/actions codes
gd::String conditionsCode = codeGenerator.GenerateConditionsListCode(event.GetConditions(), context);
Expand Down
57 changes: 34 additions & 23 deletions GDJS/GDJS/Events/CodeGeneration/EventsCodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -391,41 +391,52 @@ gd::String EventsCodeGenerator::GetObjectListName(const gd::String & name, const

gd::String EventsCodeGenerator::GenerateObjectsDeclarationCode(gd::EventsCodeGenerationContext & context)
{
auto declareObjectList = [this](gd::String object, gd::EventsCodeGenerationContext & context) {
gd::String newListName = GetObjectListName(object, context);
if (!context.GetParentContext())
{
std::cout << "ERROR: During code generation, a context tried to use an already declared object list without having a parent" << std::endl;
return "/* Could not declare " + newListName + " */";
}

//*Optimization*: Avoid expensive copy of the object list if we're using
//the same list as the one from the parent context.
gd::String copiedListName = GetObjectListName(object, *context.GetParentContext());
if (newListName == copiedListName)
return "/* Reuse " + copiedListName + " */";

return newListName + ".createFrom("+copiedListName+");\n";
};

gd::String declarationsCode;
for ( set<gd::String>::iterator it = context.GetObjectsListsToBeDeclared().begin() ; it != context.GetObjectsListsToBeDeclared().end(); ++it )
for (auto object : context.GetObjectsListsToBeDeclared())
{
declarationsCode += GetObjectListName(*it, context);
if ( !context.ObjectAlreadyDeclared(*it) )
gd::String objectListDeclaration = "";
if ( !context.ObjectAlreadyDeclared(object) )
{
declarationsCode += ".createFrom(runtimeScene.getObjects(\""+ConvertToString(*it)+"\"));\n";
context.SetObjectDeclared(*it);
objectListDeclaration += GetObjectListName(object, context) + ".createFrom(runtimeScene.getObjects(\"" + ConvertToString(object) + "\"));";
context.SetObjectDeclared(object);
}
else
{
if (context.GetParentContext())
declarationsCode += ".createFrom("+GetObjectListName(*it, *context.GetParentContext())+");\n";
else
std::cout << "ERROR: During code generation, a context tried tried to use an already declared object list without having a parent" << std::endl;
}
objectListDeclaration = declareObjectList(object, context);

declarationsCode += objectListDeclaration + "\n";
}
for ( set<gd::String>::iterator it = context.GetObjectsListsToBeDeclaredEmpty().begin() ; it != context.GetObjectsListsToBeDeclaredEmpty().end(); ++it )
for (auto object : context.GetObjectsListsToBeDeclaredEmpty())
{
declarationsCode += GetObjectListName(*it, context);
if ( !context.ObjectAlreadyDeclared(*it) )
gd::String objectListDeclaration = "";
if ( !context.ObjectAlreadyDeclared(object) )
{
declarationsCode +=".length = 0;\n";
context.SetObjectDeclared(*it);
objectListDeclaration = GetObjectListName(object, context) + ".length = 0;\n";
context.SetObjectDeclared(object);
}
else
{
if (context.GetParentContext())
declarationsCode += ".createFrom("+GetObjectListName(*it, *context.GetParentContext())+");\n";
else
std::cout << "ERROR: During code generation, a context tried tried to use an already declared object list without having a parent" << std::endl;
}
objectListDeclaration = declareObjectList(object, context);

declarationsCode += objectListDeclaration + "\n";
}

return declarationsCode ;
return declarationsCode;
}

gd::String EventsCodeGenerator::GenerateConditionsListCode(gd::InstructionsList & conditions, gd::EventsCodeGenerationContext & context)
Expand Down
4 changes: 4 additions & 0 deletions GDJS/GDJS/Extensions/Builtin/CommonInstructionsExtension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ CommonInstructionsExtension::CommonInstructionsExtension()
//For example, two sub conditions using an object called "MyObject" will both have to declare a "MyObject" object list.
gd::EventsCodeGenerationContext context;
context.InheritsFrom(parentContext);
context.ForbidReuse(); //TODO: This may not be necessary

gd::String conditionCode = codeGenerator.GenerateConditionCode(conditions[cId], "condition"+gd::String::From(cId)+"IsTrue", context);

Expand Down Expand Up @@ -231,6 +232,7 @@ CommonInstructionsExtension::CommonInstructionsExtension()
//Context is "reset" each time the event is repeated ( i.e. objects are picked again )
gd::EventsCodeGenerationContext context;
context.InheritsFrom(parentContext);
context.ForbidReuse();

//Prepare codes
gd::String whileConditionsStr = codeGenerator.GenerateConditionsListCode(event.GetWhileConditions(), context);
Expand Down Expand Up @@ -285,6 +287,7 @@ CommonInstructionsExtension::CommonInstructionsExtension()
//Context is "reset" each time the event is repeated ( i.e. objects are picked again )
gd::EventsCodeGenerationContext context;
context.InheritsFrom(parentContext);
context.ForbidReuse();

//Prepare conditions/actions codes
gd::String conditionsCode = codeGenerator.GenerateConditionsListCode(event.GetConditions(), context);
Expand Down Expand Up @@ -339,6 +342,7 @@ CommonInstructionsExtension::CommonInstructionsExtension()
//Context is "reset" each time the event is repeated ( i.e. objects are picked again )
gd::EventsCodeGenerationContext context;
context.InheritsFrom(parentContext);
context.ForbidReuse();

for (unsigned int i = 0;i<realObjects.size();++i)
context.ObjectsListNeeded(realObjects[i]);
Expand Down
Loading

0 comments on commit a81170d

Please sign in to comment.