Expression#GetReference(): ref, not copy, index if possible

to avoid malloc().
This commit is contained in:
Alexander A. Klimov 2022-11-10 11:52:55 +01:00
parent a65f2d6b41
commit 5933729590
2 changed files with 70 additions and 24 deletions

View File

@ -22,6 +22,15 @@ using namespace icinga;
boost::signals2::signal<void (ScriptFrame&, ScriptError *ex, const DebugInfo&)> Expression::OnBreakpoint;
boost::thread_specific_ptr<bool> l_InBreakpointHandler;
RefIndex::RefIndex() : m_Foreign(&m_Own)
{ }
void RefIndex::Set(String own)
{
m_Own = std::move(own);
m_Foreign = &m_Own;
}
Expression::~Expression()
{ }
@ -63,7 +72,7 @@ ExpressionResult Expression::Evaluate(ScriptFrame& frame, DebugHint *dhint) cons
}
}
bool Expression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const
bool Expression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, RefIndex *index, DebugHint **dhint) const
{
return false;
}
@ -122,9 +131,9 @@ ExpressionResult VariableExpression::DoEvaluate(ScriptFrame& frame, DebugHint *d
return ScriptGlobal::Get(m_Variable);
}
bool VariableExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const
bool VariableExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, RefIndex *index, DebugHint **dhint) const
{
*index = m_Variable;
index->Set(&m_Variable);
if (frame.Locals && frame.Locals->Contains(m_Variable)) {
*parent = frame.Locals;
@ -152,7 +161,7 @@ bool VariableExpression::GetReference(ScriptFrame& frame, bool init_dict, Value
ExpressionResult RefExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{
Value parent;
String index;
RefIndex index;
if (!m_Operand->GetReference(frame, false, &parent, &index, &dhint))
BOOST_THROW_EXCEPTION(ScriptError("Cannot obtain reference for expression.", m_DebugInfo));
@ -160,7 +169,7 @@ ExpressionResult RefExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint)
if (!parent.IsObject())
BOOST_THROW_EXCEPTION(ScriptError("Cannot obtain reference for expression because parent is not an object.", m_DebugInfo));
return new Reference(parent, index);
return new Reference(parent, index.Get());
}
ExpressionResult DerefExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
@ -177,7 +186,7 @@ ExpressionResult DerefExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhin
return ref->Get();
}
bool DerefExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const
bool DerefExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, RefIndex *index, DebugHint **dhint) const
{
ExpressionResult operand = m_Operand->Evaluate(frame);
if (operand.GetCode() != ResultOK)
@ -186,7 +195,7 @@ bool DerefExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *pa
Reference::Ptr ref = operand.GetValue();
*parent = ref->GetParent();
*index = ref->GetIndex();
index->Set(ref->GetIndex());
return true;
}
@ -449,10 +458,10 @@ ExpressionResult LogicalOrExpression::DoEvaluate(ScriptFrame& frame, DebugHint *
ExpressionResult FunctionCallExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{
Value self, vfunc;
String index;
RefIndex index;
if (m_FName->GetReference(frame, false, &self, &index))
vfunc = VMOps::GetField(self, index, frame.Sandboxed, m_DebugInfo);
vfunc = VMOps::GetField(self, index.Get(), frame.Sandboxed, m_DebugInfo);
else {
ExpressionResult vfuncres = m_FName->Evaluate(frame);
CHECK_RESULT(vfuncres);
@ -611,7 +620,7 @@ ExpressionResult SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint)
DebugHint *psdhint = dhint;
Value parent;
String index;
RefIndex index;
if (!m_Operand1->GetReference(frame, true, &parent, &index, &psdhint))
BOOST_THROW_EXCEPTION(ScriptError("Expression cannot be assigned to.", m_DebugInfo));
@ -620,7 +629,7 @@ ExpressionResult SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint)
CHECK_RESULT(operand2);
if (m_Op != OpSetLiteral) {
Value object = VMOps::GetField(parent, index, frame.Sandboxed, m_DebugInfo);
Value object = VMOps::GetField(parent, index.Get(), frame.Sandboxed, m_DebugInfo);
switch (m_Op) {
case OpSetAdd:
@ -652,7 +661,7 @@ ExpressionResult SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint)
}
}
VMOps::SetField(parent, index, operand2.GetValue(), m_OverrideFrozen, m_DebugInfo);
VMOps::SetField(parent, index.Get(), operand2.GetValue(), m_OverrideFrozen, m_DebugInfo);
if (psdhint) {
psdhint->AddMessage("=", m_DebugInfo);
@ -745,10 +754,10 @@ ExpressionResult IndexerExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dh
return VMOps::GetField(operand1.GetValue(), operand2.GetValue(), frame.Sandboxed, m_DebugInfo);
}
bool IndexerExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const
bool IndexerExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, RefIndex *index, DebugHint **dhint) const
{
Value vparent;
String vindex;
RefIndex vindex;
DebugHint *psdhint = nullptr;
bool free_psd = false;
@ -765,17 +774,17 @@ bool IndexerExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *
if (vparent.IsObject()) {
Object::Ptr oparent = vparent;
has_field = oparent->HasOwnField(vindex);
has_field = oparent->HasOwnField(vindex.Get());
}
if (has_field)
old_value = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_Operand1->GetDebugInfo());
old_value = VMOps::GetField(vparent, vindex.Get(), frame.Sandboxed, m_Operand1->GetDebugInfo());
if (old_value.IsEmpty() && !old_value.IsString())
VMOps::SetField(vparent, vindex, new Dictionary(), m_OverrideFrozen, m_Operand1->GetDebugInfo());
VMOps::SetField(vparent, vindex.Get(), new Dictionary(), m_OverrideFrozen, m_Operand1->GetDebugInfo());
}
*parent = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_DebugInfo);
*parent = VMOps::GetField(vparent, vindex.Get(), frame.Sandboxed, m_DebugInfo);
free_psd = true;
} else {
ExpressionResult operand1 = m_Operand1->Evaluate(frame);
@ -783,11 +792,11 @@ bool IndexerExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *
}
ExpressionResult operand2 = m_Operand2->Evaluate(frame);
*index = operand2.GetValue();
index->Set(operand2.GetValue());
if (dhint) {
if (psdhint)
*dhint = new DebugHint(psdhint->GetChild(*index));
*dhint = new DebugHint(psdhint->GetChild(index->Get()));
else
*dhint = nullptr;
}

View File

@ -176,6 +176,37 @@ private:
if (res.GetCode() == ResultBreak) \
break; \
/**
* Abstracts a maybe owned String
*
* @ingroup config
*/
class RefIndex
{
public:
RefIndex();
RefIndex(const RefIndex&) = delete;
RefIndex(RefIndex&&) = delete;
RefIndex& operator=(const RefIndex&) = delete;
RefIndex& operator=(RefIndex&&) = delete;
inline const String& Get() const noexcept
{
return *m_Foreign;
}
inline void Set(const String* foreign) noexcept
{
m_Foreign = foreign;
}
void Set(String own);
private:
const String* m_Foreign;
String m_Own;
};
/**
* @ingroup config
*/
@ -191,7 +222,13 @@ public:
Expression& operator=(const Expression&) = delete;
ExpressionResult Evaluate(ScriptFrame& frame, DebugHint *dhint = nullptr) const;
virtual bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint = nullptr) const;
/**
* Caution! On return `*index` may point to a String somewhere in `this` (or subAST).
* Keep `this` alive while using `*index`!
*/
virtual bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, RefIndex *index, DebugHint **dhint = nullptr) const;
virtual const DebugInfo& GetDebugInfo() const;
virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const = 0;
@ -310,7 +347,7 @@ public:
protected:
ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override;
bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const override;
bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, RefIndex *index, DebugHint **dhint) const override;
private:
String m_Variable;
@ -328,7 +365,7 @@ public:
protected:
ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override;
bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const override;
bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, RefIndex *index, DebugHint **dhint) const override;
};
class RefExpression final : public UnaryExpression
@ -761,7 +798,7 @@ protected:
bool m_OverrideFrozen{false};
ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override;
bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const override;
bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, RefIndex *index, DebugHint **dhint) const override;
friend void BindToScope(std::unique_ptr<Expression>& expr, ScopeSpecifier scopeSpec);
};