Skip to content

Commit

Permalink
18652: Improves performance by reducing lock contention via immediate…
Browse files Browse the repository at this point in the history
… return values, fixes rare bugs (#47)

Adds ability for opcodes to return immediate types directly on the stack
instead of having to allocate memory, reducing lock contention,
improving performance.
Fixes some rare bugs, especially around calling concat or substr with
only a single parameter which needed to be interpreted, and incorrectly
was not.
Improves code consistency for opcodes to reduce likelihood of errors.
  • Loading branch information
howsohazard authored Dec 29, 2023
1 parent b2a8842 commit c9cd021
Show file tree
Hide file tree
Showing 20 changed files with 1,168 additions and 969 deletions.
2 changes: 1 addition & 1 deletion src/Amalgam/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ EvaluableNode *Parser::GetCodeForPathFromAToB(UnparseData &upd, EvaluableNode *a

//build code to get the reference
EvaluableNode *refpath = upd.enm->AllocNode(ENT_TARGET);
refpath->AppendOrderedChildNode(upd.enm->AllocNode(a_ancestor_depth));
refpath->AppendOrderedChildNode(upd.enm->AllocNode(static_cast<double>(a_ancestor_depth)));

//combine together
while(b_path_nodes.size() > 0)
Expand Down
4 changes: 2 additions & 2 deletions src/Amalgam/entity/Entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,7 @@ void Entity::SetRoot(EvaluableNode *_code, bool allocated_with_entity_enm, Evalu
else
{
auto code_copy = evaluableNodeManager.DeepAllocCopy(_code, metadata_modifier);
evaluableNodeManager.SetRootNode(code_copy.reference);
evaluableNodeManager.SetRootNode(code_copy);
}

//keep reference for current root
Expand Down Expand Up @@ -919,7 +919,7 @@ void Entity::SetRoot(EvaluableNode *_code, bool allocated_with_entity_enm, Evalu
void Entity::SetRoot(std::string &code_string, EvaluableNodeManager::EvaluableNodeMetadataModifier metadata_modifier, std::vector<EntityWriteListener *> *write_listeners)
{
EvaluableNodeReference new_code = Parser::Parse(code_string, &evaluableNodeManager);
SetRoot(new_code.reference, true, metadata_modifier, write_listeners);
SetRoot(new_code, true, metadata_modifier, write_listeners);
}

void Entity::AccumRoot(EvaluableNodeReference accum_code, bool allocated_with_entity_enm, EvaluableNodeManager::EvaluableNodeMetadataModifier metadata_modifier, std::vector<EntityWriteListener *> *write_listeners)
Expand Down
12 changes: 6 additions & 6 deletions src/Amalgam/entity/EntityManipulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ Entity *EntityManipulation::EntitiesMergeMethod::MergeValues(Entity *a, Entity *
merged_entity->SetRandomStream(b->GetRandomStream());

//merge entitys' code
EvaluableNode *code_a = (a != nullptr ? a->GetRoot().reference : nullptr);
EvaluableNode *code_b = (b != nullptr ? b->GetRoot().reference : nullptr);
EvaluableNodeReference code_a = (a != nullptr ? a->GetRoot() : EvaluableNodeReference::Null());
EvaluableNodeReference code_b = (b != nullptr ? b->GetRoot() : EvaluableNodeReference::Null());

EvaluableNodeTreeManipulation::NodesMergeMethod mm(&merged_entity->evaluableNodeManager, keepAllOfBoth, true);
EvaluableNode *result = mm.MergeValues(code_a, code_b);
Expand All @@ -44,8 +44,8 @@ Entity *EntityManipulation::EntitiesMergeForDifferenceMethod::MergeValues(Entity
Entity *result = new Entity();

//compare entitys' code
EvaluableNode *code_a = (a != nullptr ? a->GetRoot().reference : nullptr);
EvaluableNode *code_b = (b != nullptr ? b->GetRoot().reference : nullptr);
EvaluableNodeReference code_a = (a != nullptr ? a->GetRoot() : EvaluableNodeReference::Null());
EvaluableNodeReference code_b = (b != nullptr ? b->GetRoot() : EvaluableNodeReference::Null());

if(a != nullptr)
aEntitiesIncludedFromB[b] = a;
Expand Down Expand Up @@ -125,8 +125,8 @@ Entity *EntityManipulation::EntitiesMixMethod::MergeValues(Entity *a, Entity *b,
merged_entity->SetRandomStream(b->GetRandomStream());

//merge entity's code
EvaluableNode *code_a = (a != nullptr ? a->GetRoot().reference : nullptr);
EvaluableNode *code_b = (b != nullptr ? b->GetRoot().reference : nullptr);
EvaluableNodeReference code_a = (a != nullptr ? a->GetRoot() : EvaluableNodeReference::Null());
EvaluableNodeReference code_b = (b != nullptr ? b->GetRoot() : EvaluableNodeReference::Null());

EvaluableNodeTreeManipulation::NodesMixMethod mm(interpreter->randomStream.CreateOtherStreamViaRand(),
&merged_entity->evaluableNodeManager, fractionA, fractionB, similarMixChance);
Expand Down
128 changes: 128 additions & 0 deletions src/Amalgam/evaluablenode/EvaluableNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,15 @@ class EvaluableNodeImmediateValueWithType
: nodeType(ENIVT_NULL)
{ }

__forceinline EvaluableNodeImmediateValueWithType(bool value)
{
nodeType = ENIVT_NUMBER;
if(value)
nodeValue.number = 1.0;
else
nodeValue.number = 0.0;
}

constexpr EvaluableNodeImmediateValueWithType(double number)
: nodeType(ENIVT_NUMBER), nodeValue(number)
{ }
Expand Down Expand Up @@ -1091,6 +1100,125 @@ class EvaluableNodeImmediateValueWithType
nodeValue = EvaluableNodeImmediateValue(en);
}

bool GetValueAsBoolean()
{
if(nodeType == ENIVT_NUMBER)
{
if(nodeValue.number == 0.0)
return false;
if(FastIsNaN(nodeValue.number))
return false;
return true;
}

if(nodeType == ENIVT_STRING_ID)
{
if(nodeValue.stringID <= StringInternPool::EMPTY_STRING_ID)
return false;
return true;
}

if(nodeType == ENIVT_CODE)
return EvaluableNode::IsTrue(nodeValue.code);

//nodeType is one of ENIVT_NOT_EXIST, ENIVT_NULL, ENIVT_NUMBER_INDIRECTION_INDEX
return false;
}

double GetValueAsNumber(double value_if_null = std::numeric_limits<double>::quiet_NaN())
{
if(nodeType == ENIVT_NUMBER)
return nodeValue.number;

if(nodeType == ENIVT_STRING_ID)
{
if(nodeValue.stringID == string_intern_pool.NOT_A_STRING_ID)
return value_if_null;

const auto &str = string_intern_pool.GetStringFromID(nodeValue.stringID);
auto [value, success] = Platform_StringToNumber(str);
if(success)
return value;
return value_if_null;
}

if(nodeType == ENIVT_CODE)
return EvaluableNode::ToNumber(nodeValue.code);

//nodeType is one of ENIVT_NOT_EXIST, ENIVT_NULL, ENIVT_NUMBER_INDIRECTION_INDEX
return value_if_null;
}

std::pair<bool, std::string> GetValueAsString()
{
if(nodeType == ENIVT_NUMBER)
{
if(FastIsNaN(nodeValue.number))
return std::make_pair(false, "");

return std::make_pair(true, EvaluableNode::NumberToString(nodeValue.number));
}

if(nodeType == ENIVT_STRING_ID)
{
if(nodeValue.stringID == string_intern_pool.NOT_A_STRING_ID)
return std::make_pair(false, "");

const auto &str = string_intern_pool.GetStringFromID(nodeValue.stringID);
return std::make_pair(true, str);
}

if(nodeType == ENIVT_CODE)
return std::make_pair(true, EvaluableNode::ToStringPreservingOpcodeType(nodeValue.code));

//nodeType is one of ENIVT_NOT_EXIST, ENIVT_NULL, ENIVT_NUMBER_INDIRECTION_INDEX
return std::make_pair(false, "");
}

StringInternPool::StringID GetValueAsStringIDIfExists()
{
if(nodeType == ENIVT_NUMBER)
{
if(FastIsNaN(nodeValue.number))
return StringInternPool::NOT_A_STRING_ID;

const std::string str_value = EvaluableNode::NumberToString(nodeValue.number);
//will return empty string if not found
return string_intern_pool.GetIDFromString(str_value);
}

if(nodeType == ENIVT_STRING_ID)
return nodeValue.stringID;

if(nodeType == ENIVT_CODE)
return EvaluableNode::ToStringIDIfExists(nodeValue.code);

//nodeType is one of ENIVT_NOT_EXIST, ENIVT_NULL, ENIVT_NUMBER_INDIRECTION_INDEX
return string_intern_pool.NOT_A_STRING_ID;
}

StringInternPool::StringID GetValueAsStringIDWithReference()
{
if(nodeType == ENIVT_NUMBER)
{
if(FastIsNaN(nodeValue.number))
return StringInternPool::NOT_A_STRING_ID;

const std::string str_value = EvaluableNode::NumberToString(nodeValue.number);
//will return empty string if not found
return string_intern_pool.CreateStringReference(str_value);
}

if(nodeType == ENIVT_STRING_ID)
return string_intern_pool.CreateStringReference(nodeValue.stringID);

if(nodeType == ENIVT_CODE)
return EvaluableNode::ToStringIDWithReference(nodeValue.code);

//nodeType is one of ENIVT_NOT_EXIST, ENIVT_NULL, ENIVT_NUMBER_INDIRECTION_INDEX
return string_intern_pool.NOT_A_STRING_ID;
}

static inline bool AreEqual(EvaluableNodeImmediateValueWithType &a, EvaluableNodeImmediateValueWithType &b)
{
return EvaluableNodeImmediateValue::AreEqual(a.nodeType, a.nodeValue, b.nodeType, b.nodeValue);
Expand Down
Loading

0 comments on commit c9cd021

Please sign in to comment.