mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
reduction of Stmt subclasses - compiles but does not yet link
This commit is contained in:
parent
10e80dfcd3
commit
7a9694a2a4
4 changed files with 1059 additions and 66 deletions
109
src/Stmt.cc
109
src/Stmt.cc
|
@ -32,6 +32,8 @@ const char* stmt_name(StmtTag t)
|
||||||
"for", "next", "break", "return", "add", "delete",
|
"for", "next", "break", "return", "add", "delete",
|
||||||
"list", "bodylist",
|
"list", "bodylist",
|
||||||
"<init>", "fallthrough", "while",
|
"<init>", "fallthrough", "while",
|
||||||
|
"catch-return",
|
||||||
|
"check-any-length",
|
||||||
"null",
|
"null",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -94,6 +96,18 @@ const SwitchStmt* Stmt::AsSwitchStmt() const
|
||||||
return (const SwitchStmt*) this;
|
return (const SwitchStmt*) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ExprStmt* Stmt::AsExprStmt() const
|
||||||
|
{
|
||||||
|
CHECK_TAG(tag, STMT_EXPR, "Stmt::AsExprStmt", stmt_name)
|
||||||
|
return (const ExprStmt*) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ReturnStmt* Stmt::AsReturnStmt() const
|
||||||
|
{
|
||||||
|
CHECK_TAG(tag, STMT_RETURN, "Stmt::AsReturnStmt", stmt_name)
|
||||||
|
return (const ReturnStmt*) this;
|
||||||
|
}
|
||||||
|
|
||||||
bool Stmt::SetLocationInfo(const Location* start, const Location* end)
|
bool Stmt::SetLocationInfo(const Location* start, const Location* end)
|
||||||
{
|
{
|
||||||
if ( ! Obj::SetLocationInfo(start, end) )
|
if ( ! Obj::SetLocationInfo(start, end) )
|
||||||
|
@ -354,6 +368,11 @@ ExprStmt::ExprStmt(StmtTag t, ExprPtr arg_e) : Stmt(t), e(std::move(arg_e))
|
||||||
|
|
||||||
ExprStmt::~ExprStmt() = default;
|
ExprStmt::~ExprStmt() = default;
|
||||||
|
|
||||||
|
ExprPtr ExprStmt::StmtExprPtr() const
|
||||||
|
{
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
ValPtr ExprStmt::Exec(Frame* f, StmtFlowType& flow) const
|
ValPtr ExprStmt::Exec(Frame* f, StmtFlowType& flow) const
|
||||||
{
|
{
|
||||||
RegisterAccess();
|
RegisterAccess();
|
||||||
|
@ -961,17 +980,37 @@ TraversalCode SwitchStmt::Traverse(TraversalCallback* cb) const
|
||||||
HANDLE_TC_STMT_POST(tc);
|
HANDLE_TC_STMT_POST(tc);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddStmt::AddStmt(ExprPtr arg_e) : ExprStmt(STMT_ADD, std::move(arg_e))
|
|
||||||
|
AddDelStmt::AddDelStmt(StmtTag t, ExprPtr arg_e)
|
||||||
|
: ExprStmt(t, std::move(arg_e))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AddDelStmt::IsPure() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TraversalCode AddDelStmt::Traverse(TraversalCallback* cb) const
|
||||||
|
{
|
||||||
|
TraversalCode tc = cb->PreStmt(this);
|
||||||
|
HANDLE_TC_STMT_PRE(tc);
|
||||||
|
|
||||||
|
// Argument is stored in base class's "e" field.
|
||||||
|
tc = e->Traverse(cb);
|
||||||
|
HANDLE_TC_STMT_PRE(tc);
|
||||||
|
|
||||||
|
tc = cb->PostStmt(this);
|
||||||
|
HANDLE_TC_STMT_POST(tc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AddStmt::AddStmt(ExprPtr arg_e) : AddDelStmt(STMT_ADD, std::move(arg_e))
|
||||||
{
|
{
|
||||||
if ( ! e->CanAdd() )
|
if ( ! e->CanAdd() )
|
||||||
Error("illegal add statement");
|
Error("illegal add statement");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AddStmt::IsPure() const
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ValPtr AddStmt::Exec(Frame* f, StmtFlowType& flow) const
|
ValPtr AddStmt::Exec(Frame* f, StmtFlowType& flow) const
|
||||||
{
|
{
|
||||||
RegisterAccess();
|
RegisterAccess();
|
||||||
|
@ -981,20 +1020,7 @@ ValPtr AddStmt::Exec(Frame* f, StmtFlowType& flow) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TraversalCode AddStmt::Traverse(TraversalCallback* cb) const
|
DelStmt::DelStmt(ExprPtr arg_e) : AddDelStmt(STMT_DELETE, std::move(arg_e))
|
||||||
{
|
|
||||||
TraversalCode tc = cb->PreStmt(this);
|
|
||||||
HANDLE_TC_STMT_PRE(tc);
|
|
||||||
|
|
||||||
// Argument is stored in base class's "e" field.
|
|
||||||
tc = e->Traverse(cb);
|
|
||||||
HANDLE_TC_STMT_PRE(tc);
|
|
||||||
|
|
||||||
tc = cb->PostStmt(this);
|
|
||||||
HANDLE_TC_STMT_POST(tc);
|
|
||||||
}
|
|
||||||
|
|
||||||
DelStmt::DelStmt(ExprPtr arg_e) : ExprStmt(STMT_DELETE, std::move(arg_e))
|
|
||||||
{
|
{
|
||||||
if ( e->IsError() )
|
if ( e->IsError() )
|
||||||
return;
|
return;
|
||||||
|
@ -1003,11 +1029,6 @@ DelStmt::DelStmt(ExprPtr arg_e) : ExprStmt(STMT_DELETE, std::move(arg_e))
|
||||||
Error("illegal delete statement");
|
Error("illegal delete statement");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DelStmt::IsPure() const
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ValPtr DelStmt::Exec(Frame* f, StmtFlowType& flow) const
|
ValPtr DelStmt::Exec(Frame* f, StmtFlowType& flow) const
|
||||||
{
|
{
|
||||||
RegisterAccess();
|
RegisterAccess();
|
||||||
|
@ -1016,18 +1037,6 @@ ValPtr DelStmt::Exec(Frame* f, StmtFlowType& flow) const
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
TraversalCode DelStmt::Traverse(TraversalCallback* cb) const
|
|
||||||
{
|
|
||||||
TraversalCode tc = cb->PreStmt(this);
|
|
||||||
HANDLE_TC_STMT_PRE(tc);
|
|
||||||
|
|
||||||
// Argument is stored in base class's "e" field.
|
|
||||||
tc = e->Traverse(cb);
|
|
||||||
HANDLE_TC_STMT_PRE(tc);
|
|
||||||
|
|
||||||
tc = cb->PostStmt(this);
|
|
||||||
HANDLE_TC_STMT_POST(tc);
|
|
||||||
}
|
|
||||||
|
|
||||||
EventStmt::EventStmt(EventExprPtr arg_e)
|
EventStmt::EventStmt(EventExprPtr arg_e)
|
||||||
: ExprStmt(STMT_EVENT, arg_e), event_expr(std::move(arg_e))
|
: ExprStmt(STMT_EVENT, arg_e), event_expr(std::move(arg_e))
|
||||||
|
@ -1060,10 +1069,10 @@ TraversalCode EventStmt::Traverse(TraversalCallback* cb) const
|
||||||
HANDLE_TC_STMT_POST(tc);
|
HANDLE_TC_STMT_POST(tc);
|
||||||
}
|
}
|
||||||
|
|
||||||
WhileStmt::WhileStmt(ExprPtr arg_loop_condition,
|
WhileStmt::WhileStmt(ExprPtr arg_loop_condition, StmtPtr arg_body)
|
||||||
StmtPtr arg_body)
|
|
||||||
: Stmt(STMT_WHILE),
|
: Stmt(STMT_WHILE),
|
||||||
loop_condition(std::move(arg_loop_condition)), body(std::move(arg_body))
|
loop_condition(std::move(arg_loop_condition)),
|
||||||
|
body(std::move(arg_body))
|
||||||
{
|
{
|
||||||
if ( ! loop_condition->IsError() &&
|
if ( ! loop_condition->IsError() &&
|
||||||
! IsBool(loop_condition->GetType()->Tag()) )
|
! IsBool(loop_condition->GetType()->Tag()) )
|
||||||
|
@ -1119,6 +1128,9 @@ ValPtr WhileStmt::Exec(Frame* f, StmtFlowType& flow) const
|
||||||
|
|
||||||
for ( ; ; )
|
for ( ; ; )
|
||||||
{
|
{
|
||||||
|
if ( loop_cond_pred_stmt )
|
||||||
|
loop_cond_pred_stmt->Exec(f, flow);
|
||||||
|
|
||||||
auto cond = loop_condition->Eval(f);
|
auto cond = loop_condition->Eval(f);
|
||||||
|
|
||||||
if ( ! cond )
|
if ( ! cond )
|
||||||
|
@ -1568,12 +1580,15 @@ void ReturnStmt::StmtDescribe(ODesc* d) const
|
||||||
|
|
||||||
StmtList::StmtList() : Stmt(STMT_LIST)
|
StmtList::StmtList() : Stmt(STMT_LIST)
|
||||||
{
|
{
|
||||||
|
stmts = new StmtPList;
|
||||||
}
|
}
|
||||||
|
|
||||||
StmtList::~StmtList()
|
StmtList::~StmtList()
|
||||||
{
|
{
|
||||||
for ( const auto& stmt : stmts )
|
for ( const auto& stmt : Stmts() )
|
||||||
Unref(stmt);
|
Unref(stmt);
|
||||||
|
|
||||||
|
delete stmts;
|
||||||
}
|
}
|
||||||
|
|
||||||
ValPtr StmtList::Exec(Frame* f, StmtFlowType& flow) const
|
ValPtr StmtList::Exec(Frame* f, StmtFlowType& flow) const
|
||||||
|
@ -1581,7 +1596,7 @@ ValPtr StmtList::Exec(Frame* f, StmtFlowType& flow) const
|
||||||
RegisterAccess();
|
RegisterAccess();
|
||||||
flow = FLOW_NEXT;
|
flow = FLOW_NEXT;
|
||||||
|
|
||||||
for ( const auto& stmt : stmts )
|
for ( const auto& stmt : Stmts() )
|
||||||
{
|
{
|
||||||
f->SetNextStmt(stmt);
|
f->SetNextStmt(stmt);
|
||||||
|
|
||||||
|
@ -1604,7 +1619,7 @@ ValPtr StmtList::Exec(Frame* f, StmtFlowType& flow) const
|
||||||
|
|
||||||
bool StmtList::IsPure() const
|
bool StmtList::IsPure() const
|
||||||
{
|
{
|
||||||
for ( const auto& stmt : stmts )
|
for ( const auto& stmt : Stmts() )
|
||||||
if ( ! stmt->IsPure() )
|
if ( ! stmt->IsPure() )
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
@ -1615,10 +1630,10 @@ void StmtList::StmtDescribe(ODesc* d) const
|
||||||
if ( ! d->IsReadable() )
|
if ( ! d->IsReadable() )
|
||||||
{
|
{
|
||||||
AddTag(d);
|
AddTag(d);
|
||||||
d->AddCount(stmts.length());
|
d->AddCount(stmts->length());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( stmts.length() == 0 )
|
if ( stmts->length() == 0 )
|
||||||
DescribeDone(d);
|
DescribeDone(d);
|
||||||
|
|
||||||
else
|
else
|
||||||
|
@ -1629,7 +1644,7 @@ void StmtList::StmtDescribe(ODesc* d) const
|
||||||
d->NL();
|
d->NL();
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( const auto& stmt : stmts )
|
for ( const auto& stmt : Stmts() )
|
||||||
{
|
{
|
||||||
stmt->Describe(d);
|
stmt->Describe(d);
|
||||||
d->NL();
|
d->NL();
|
||||||
|
@ -1645,7 +1660,7 @@ TraversalCode StmtList::Traverse(TraversalCallback* cb) const
|
||||||
TraversalCode tc = cb->PreStmt(this);
|
TraversalCode tc = cb->PreStmt(this);
|
||||||
HANDLE_TC_STMT_PRE(tc);
|
HANDLE_TC_STMT_PRE(tc);
|
||||||
|
|
||||||
for ( const auto& stmt : stmts )
|
for ( const auto& stmt : Stmts() )
|
||||||
{
|
{
|
||||||
tc = stmt->Traverse(cb);
|
tc = stmt->Traverse(cb);
|
||||||
HANDLE_TC_STMT_PRE(tc);
|
HANDLE_TC_STMT_PRE(tc);
|
||||||
|
|
129
src/Stmt.h
129
src/Stmt.h
|
@ -26,6 +26,9 @@ public:
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
void Inline(Inliner* inl) override;
|
void Inline(Inliner* inl) override;
|
||||||
|
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
StmtPtr DoReduce(Reducer* c) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ExprListStmt(StmtTag t, ListExprPtr arg_l);
|
ExprListStmt(StmtTag t, ListExprPtr arg_l);
|
||||||
|
|
||||||
|
@ -38,6 +41,12 @@ protected:
|
||||||
void StmtDescribe(ODesc* d) const override;
|
void StmtDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
ListExprPtr l;
|
ListExprPtr l;
|
||||||
|
|
||||||
|
// Optimization-related:
|
||||||
|
|
||||||
|
// Returns a new version of the original derived object
|
||||||
|
// based on the given list of singleton expressions.
|
||||||
|
virtual StmtPtr DoSubclassReduce(ListExprPtr singletons, Reducer* c) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PrintStmt final : public ExprListStmt {
|
class PrintStmt final : public ExprListStmt {
|
||||||
|
@ -51,6 +60,9 @@ public:
|
||||||
protected:
|
protected:
|
||||||
ValPtr DoExec(std::vector<ValPtr> vals,
|
ValPtr DoExec(std::vector<ValPtr> vals,
|
||||||
StmtFlowType& flow) const override;
|
StmtFlowType& flow) const override;
|
||||||
|
|
||||||
|
// Optimization-related:
|
||||||
|
StmtPtr DoSubclassReduce(ListExprPtr singletons, Reducer* c) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExprStmt : public Stmt {
|
class ExprStmt : public Stmt {
|
||||||
|
@ -58,9 +70,15 @@ public:
|
||||||
explicit ExprStmt(ExprPtr e);
|
explicit ExprStmt(ExprPtr e);
|
||||||
~ExprStmt() override;
|
~ExprStmt() override;
|
||||||
|
|
||||||
|
// This constructor is only meant for internal use, but it's
|
||||||
|
// not protected since ExprPtr's mask the actual caller,
|
||||||
|
// not allowing us to use "friend" for protected access.
|
||||||
|
ExprStmt(StmtTag t, ExprPtr e);
|
||||||
|
|
||||||
ValPtr Exec(Frame* f, StmtFlowType& flow) const override;
|
ValPtr Exec(Frame* f, StmtFlowType& flow) const override;
|
||||||
|
|
||||||
const Expr* StmtExpr() const { return e.get(); }
|
const Expr* StmtExpr() const { return e.get(); }
|
||||||
|
ExprPtr StmtExprPtr() const;
|
||||||
|
|
||||||
void StmtDescribe(ODesc* d) const override;
|
void StmtDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
|
@ -70,9 +88,10 @@ public:
|
||||||
StmtPtr Duplicate() override;
|
StmtPtr Duplicate() override;
|
||||||
void Inline(Inliner* inl) override;
|
void Inline(Inliner* inl) override;
|
||||||
|
|
||||||
protected:
|
bool IsReduced(Reducer* c) const override;
|
||||||
ExprStmt(StmtTag t, ExprPtr e);
|
StmtPtr DoReduce(Reducer* c) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
virtual ValPtr DoExec(Frame* f, Val* v, StmtFlowType& flow) const;
|
virtual ValPtr DoExec(Frame* f, Val* v, StmtFlowType& flow) const;
|
||||||
|
|
||||||
bool IsPure() const override;
|
bool IsPure() const override;
|
||||||
|
@ -96,6 +115,11 @@ public:
|
||||||
StmtPtr Duplicate() override;
|
StmtPtr Duplicate() override;
|
||||||
void Inline(Inliner* inl) override;
|
void Inline(Inliner* inl) override;
|
||||||
|
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
StmtPtr DoReduce(Reducer* c) override;
|
||||||
|
|
||||||
|
bool NoFlowAfter(bool ignore_break) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr DoExec(Frame* f, Val* v, StmtFlowType& flow) const override;
|
ValPtr DoExec(Frame* f, Val* v, StmtFlowType& flow) const override;
|
||||||
bool IsPure() const override;
|
bool IsPure() const override;
|
||||||
|
@ -118,6 +142,8 @@ public:
|
||||||
const Stmt* Body() const { return s.get(); }
|
const Stmt* Body() const { return s.get(); }
|
||||||
Stmt* Body() { return s.get(); }
|
Stmt* Body() { return s.get(); }
|
||||||
|
|
||||||
|
void UpdateBody(StmtPtr new_body) { s = new_body; }
|
||||||
|
|
||||||
void Describe(ODesc* d) const override;
|
void Describe(ODesc* d) const override;
|
||||||
|
|
||||||
TraversalCode Traverse(TraversalCallback* cb) const;
|
TraversalCode Traverse(TraversalCallback* cb) const;
|
||||||
|
@ -148,6 +174,11 @@ public:
|
||||||
StmtPtr Duplicate() override;
|
StmtPtr Duplicate() override;
|
||||||
void Inline(Inliner* inl) override;
|
void Inline(Inliner* inl) override;
|
||||||
|
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
StmtPtr DoReduce(Reducer* c) override;
|
||||||
|
|
||||||
|
bool NoFlowAfter(bool ignore_break) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr DoExec(Frame* f, Val* v, StmtFlowType& flow) const override;
|
ValPtr DoExec(Frame* f, Val* v, StmtFlowType& flow) const override;
|
||||||
bool IsPure() const override;
|
bool IsPure() const override;
|
||||||
|
@ -178,28 +209,38 @@ protected:
|
||||||
std::vector<std::pair<ID*, int>> case_label_type_list;
|
std::vector<std::pair<ID*, int>> case_label_type_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AddStmt final : public ExprStmt {
|
// Helper class. Added for script optimization, but it makes sense
|
||||||
|
// in terms of factoring even without.
|
||||||
|
class AddDelStmt : public ExprStmt {
|
||||||
|
public:
|
||||||
|
TraversalCode Traverse(TraversalCallback* cb) const override;
|
||||||
|
|
||||||
|
bool IsPure() const override;
|
||||||
|
|
||||||
|
// Optimization-related:
|
||||||
|
StmtPtr DoReduce(Reducer* c) override;
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AddDelStmt(StmtTag t, ExprPtr arg_e);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AddStmt final : public AddDelStmt {
|
||||||
public:
|
public:
|
||||||
explicit AddStmt(ExprPtr e);
|
explicit AddStmt(ExprPtr e);
|
||||||
|
|
||||||
bool IsPure() const override;
|
|
||||||
ValPtr Exec(Frame* f, StmtFlowType& flow) const override;
|
ValPtr Exec(Frame* f, StmtFlowType& flow) const override;
|
||||||
|
|
||||||
TraversalCode Traverse(TraversalCallback* cb) const override;
|
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
StmtPtr Duplicate() override;
|
StmtPtr Duplicate() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DelStmt final : public ExprStmt {
|
class DelStmt final : public AddDelStmt {
|
||||||
public:
|
public:
|
||||||
explicit DelStmt(ExprPtr e);
|
explicit DelStmt(ExprPtr e);
|
||||||
|
|
||||||
bool IsPure() const override;
|
|
||||||
ValPtr Exec(Frame* f, StmtFlowType& flow) const override;
|
ValPtr Exec(Frame* f, StmtFlowType& flow) const override;
|
||||||
|
|
||||||
TraversalCode Traverse(TraversalCallback* cb) const override;
|
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
StmtPtr Duplicate() override;
|
StmtPtr Duplicate() override;
|
||||||
};
|
};
|
||||||
|
@ -215,6 +256,8 @@ public:
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
StmtPtr Duplicate() override;
|
StmtPtr Duplicate() override;
|
||||||
|
|
||||||
|
StmtPtr DoReduce(Reducer* c) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
EventExprPtr event_expr;
|
EventExprPtr event_expr;
|
||||||
};
|
};
|
||||||
|
@ -232,11 +275,20 @@ public:
|
||||||
TraversalCode Traverse(TraversalCallback* cb) const override;
|
TraversalCode Traverse(TraversalCallback* cb) const override;
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
const Stmt* CondStmt() const
|
StmtPtr CondPredStmt() const
|
||||||
{ return loop_cond_stmt ? loop_cond_stmt.get() : nullptr; }
|
{ return loop_cond_pred_stmt ? loop_cond_pred_stmt : nullptr; }
|
||||||
StmtPtr Duplicate() override;
|
StmtPtr Duplicate() override;
|
||||||
void Inline(Inliner* inl) override;
|
void Inline(Inliner* inl) override;
|
||||||
|
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
StmtPtr DoReduce(Reducer* c) override;
|
||||||
|
|
||||||
|
// Note, no need for a NoFlowAfter method because the loop might
|
||||||
|
// execute zero times, so it's always the default of "false".
|
||||||
|
|
||||||
|
const StmtPtr ConditionAsStmt() const
|
||||||
|
{ return stmt_loop_condition; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr Exec(Frame* f, StmtFlowType& flow) const override;
|
ValPtr Exec(Frame* f, StmtFlowType& flow) const override;
|
||||||
|
|
||||||
|
@ -246,8 +298,14 @@ protected:
|
||||||
// Optimization-related member variables.
|
// Optimization-related member variables.
|
||||||
|
|
||||||
// When in reduced form, the following holds a statement (which
|
// When in reduced form, the following holds a statement (which
|
||||||
// might be a block) for evaluating the loop's conditional.
|
// might be a block) that's a *predecessor* necessary for evaluating
|
||||||
StmtPtr loop_cond_stmt = nullptr;
|
// the loop's conditional.
|
||||||
|
StmtPtr loop_cond_pred_stmt = nullptr;
|
||||||
|
|
||||||
|
// When reducing, we create a *statement* associated with
|
||||||
|
// evaluating the reduced conditional, as well as the reduced
|
||||||
|
// expression. This turns out to be useful in propagating RDs/UDs.
|
||||||
|
StmtPtr stmt_loop_condition = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ForStmt final : public ExprStmt {
|
class ForStmt final : public ExprStmt {
|
||||||
|
@ -274,6 +332,12 @@ public:
|
||||||
StmtPtr Duplicate() override;
|
StmtPtr Duplicate() override;
|
||||||
void Inline(Inliner* inl) override;
|
void Inline(Inliner* inl) override;
|
||||||
|
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
StmtPtr DoReduce(Reducer* c) override;
|
||||||
|
|
||||||
|
// Note, no need for a NoFlowAfter method because the loop might
|
||||||
|
// execute zero times, so it's always the default of "false".
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr DoExec(Frame* f, Val* v, StmtFlowType& flow) const override;
|
ValPtr DoExec(Frame* f, Val* v, StmtFlowType& flow) const override;
|
||||||
|
|
||||||
|
@ -297,6 +361,9 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
StmtPtr Duplicate() override { return SetSucc(new NextStmt()); }
|
StmtPtr Duplicate() override { return SetSucc(new NextStmt()); }
|
||||||
|
|
||||||
|
bool NoFlowAfter(bool ignore_break) const override
|
||||||
|
{ return true; }
|
||||||
protected:
|
protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -314,6 +381,9 @@ public:
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
StmtPtr Duplicate() override { return SetSucc(new BreakStmt()); }
|
StmtPtr Duplicate() override { return SetSucc(new BreakStmt()); }
|
||||||
|
|
||||||
|
bool NoFlowAfter(bool ignore_break) const override
|
||||||
|
{ return ! ignore_break; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -349,6 +419,12 @@ public:
|
||||||
// Constructor used for duplication, when we've already done
|
// Constructor used for duplication, when we've already done
|
||||||
// all of the type-checking.
|
// all of the type-checking.
|
||||||
ReturnStmt(ExprPtr e, bool ignored);
|
ReturnStmt(ExprPtr e, bool ignored);
|
||||||
|
|
||||||
|
// Optimization-related:
|
||||||
|
StmtPtr DoReduce(Reducer* c) override;
|
||||||
|
|
||||||
|
bool NoFlowAfter(bool ignore_break) const override
|
||||||
|
{ return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class StmtList : public Stmt {
|
class StmtList : public Stmt {
|
||||||
|
@ -358,8 +434,8 @@ public:
|
||||||
|
|
||||||
ValPtr Exec(Frame* f, StmtFlowType& flow) const override;
|
ValPtr Exec(Frame* f, StmtFlowType& flow) const override;
|
||||||
|
|
||||||
const StmtPList& Stmts() const { return stmts; }
|
const StmtPList& Stmts() const { return *stmts; }
|
||||||
StmtPList& Stmts() { return stmts; }
|
StmtPList& Stmts() { return *stmts; }
|
||||||
|
|
||||||
void StmtDescribe(ODesc* d) const override;
|
void StmtDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
|
@ -369,6 +445,11 @@ public:
|
||||||
StmtPtr Duplicate() override;
|
StmtPtr Duplicate() override;
|
||||||
void Inline(Inliner* inl) override;
|
void Inline(Inliner* inl) override;
|
||||||
|
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
StmtPtr DoReduce(Reducer* c) override;
|
||||||
|
|
||||||
|
bool NoFlowAfter(bool ignore_break) const override;
|
||||||
|
|
||||||
// Idioms commonly used in reduction.
|
// Idioms commonly used in reduction.
|
||||||
StmtList(StmtPtr s1, Stmt* s2);
|
StmtList(StmtPtr s1, Stmt* s2);
|
||||||
StmtList(StmtPtr s1, StmtPtr s2);
|
StmtList(StmtPtr s1, StmtPtr s2);
|
||||||
|
@ -377,7 +458,16 @@ public:
|
||||||
protected:
|
protected:
|
||||||
bool IsPure() const override;
|
bool IsPure() const override;
|
||||||
|
|
||||||
StmtPList stmts;
|
StmtPList* stmts;
|
||||||
|
|
||||||
|
// Optimization-related:
|
||||||
|
bool ReduceStmt(int& s_i, StmtPList* f_stmts, Reducer* c);
|
||||||
|
|
||||||
|
void ResetStmts(StmtPList* new_stmts)
|
||||||
|
{
|
||||||
|
delete stmts;
|
||||||
|
stmts = new_stmts;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class InitStmt final : public Stmt {
|
class InitStmt final : public Stmt {
|
||||||
|
@ -396,6 +486,9 @@ public:
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
StmtPtr Duplicate() override;
|
StmtPtr Duplicate() override;
|
||||||
|
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
StmtPtr DoReduce(Reducer* c) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::vector<IDPtr> inits;
|
std::vector<IDPtr> inits;
|
||||||
};
|
};
|
||||||
|
@ -439,6 +532,8 @@ public:
|
||||||
StmtPtr Duplicate() override;
|
StmtPtr Duplicate() override;
|
||||||
void Inline(Inliner* inl) override;
|
void Inline(Inliner* inl) override;
|
||||||
|
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ExprPtr cond;
|
ExprPtr cond;
|
||||||
StmtPtr s1;
|
StmtPtr s1;
|
||||||
|
|
|
@ -18,6 +18,8 @@ enum StmtTag {
|
||||||
STMT_INIT,
|
STMT_INIT,
|
||||||
STMT_FALLTHROUGH,
|
STMT_FALLTHROUGH,
|
||||||
STMT_WHILE,
|
STMT_WHILE,
|
||||||
|
STMT_CATCH_RETURN, // for reduced InlineExpr's
|
||||||
|
STMT_CHECK_ANY_LEN, // internal reduced statement
|
||||||
STMT_NULL
|
STMT_NULL
|
||||||
#define NUM_STMTS (int(STMT_NULL) + 1)
|
#define NUM_STMTS (int(STMT_NULL) + 1)
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,11 +4,50 @@
|
||||||
|
|
||||||
#include "zeek/Stmt.h"
|
#include "zeek/Stmt.h"
|
||||||
#include "zeek/Expr.h"
|
#include "zeek/Expr.h"
|
||||||
|
#include "zeek/Frame.h"
|
||||||
|
#include "zeek/Reporter.h"
|
||||||
|
#include "zeek/Desc.h"
|
||||||
|
#include "zeek/Traverse.h"
|
||||||
|
#include "zeek/script_opt/Reduce.h"
|
||||||
|
|
||||||
|
|
||||||
namespace zeek::detail {
|
namespace zeek::detail {
|
||||||
|
|
||||||
|
|
||||||
|
bool Stmt::IsReduced(Reducer* c) const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
StmtPtr Stmt::Reduce(Reducer* c)
|
||||||
|
{
|
||||||
|
auto this_ptr = ThisPtr();
|
||||||
|
|
||||||
|
auto repl = c->ReplacementStmt(this_ptr);
|
||||||
|
if ( repl )
|
||||||
|
return repl;
|
||||||
|
|
||||||
|
if ( c->ShouldOmitStmt(this_ptr) )
|
||||||
|
{
|
||||||
|
auto null = make_intrusive<NullStmt>();
|
||||||
|
null->SetOriginal(this_ptr);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DoReduce(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
StmtPtr Stmt::TransformMe(Stmt* new_me, Reducer* c)
|
||||||
|
{
|
||||||
|
ASSERT(new_me != this);
|
||||||
|
|
||||||
|
// Set the original prior to reduction, to support "original chains"
|
||||||
|
// to ultimately resolve back to the source statement.
|
||||||
|
new_me->SetOriginal(ThisPtr());
|
||||||
|
return new_me->Reduce(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ExprListStmt::Inline(Inliner* inl)
|
void ExprListStmt::Inline(Inliner* inl)
|
||||||
{
|
{
|
||||||
auto& e = l->Exprs();
|
auto& e = l->Exprs();
|
||||||
|
@ -16,12 +55,70 @@ void ExprListStmt::Inline(Inliner* inl)
|
||||||
e.replace(i, e[i]->Inline(inl).release());
|
e.replace(i, e[i]->Inline(inl).release());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ExprListStmt::IsReduced(Reducer* c) const
|
||||||
|
{
|
||||||
|
const ExprPList& e = l->Exprs();
|
||||||
|
for ( const auto& expr : e )
|
||||||
|
if ( ! expr->IsSingleton(c) )
|
||||||
|
return NonReduced(expr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
StmtPtr ExprListStmt::DoReduce(Reducer* c)
|
||||||
|
{
|
||||||
|
if ( ! c->Optimizing() && IsReduced(c) )
|
||||||
|
return ThisPtr();
|
||||||
|
|
||||||
|
auto new_l = make_intrusive<ListExpr>();
|
||||||
|
auto s = new StmtList;
|
||||||
|
|
||||||
|
ExprPList& e = l->Exprs();
|
||||||
|
for ( auto& expr : e )
|
||||||
|
{
|
||||||
|
if ( c->Optimizing() )
|
||||||
|
new_l->Append(c->OptExpr(expr));
|
||||||
|
|
||||||
|
else if ( expr->IsSingleton(c) )
|
||||||
|
new_l->Append({NewRef{}, expr});
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StmtPtr red_e_stmt;
|
||||||
|
auto red_e = expr->ReduceToSingleton(c, red_e_stmt);
|
||||||
|
new_l->Append(red_e);
|
||||||
|
|
||||||
|
if ( red_e_stmt )
|
||||||
|
s->Stmts().push_back(red_e_stmt.release());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( c->Optimizing() )
|
||||||
|
{
|
||||||
|
l = new_l;
|
||||||
|
return ThisPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s->Stmts().push_back(DoSubclassReduce(new_l, c).release());
|
||||||
|
return s->Reduce(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
StmtPtr PrintStmt::Duplicate()
|
StmtPtr PrintStmt::Duplicate()
|
||||||
{
|
{
|
||||||
return SetSucc(new PrintStmt(l->Duplicate()->AsListExprPtr()));
|
return SetSucc(new PrintStmt(l->Duplicate()->AsListExprPtr()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StmtPtr PrintStmt::DoSubclassReduce(ListExprPtr singletons, Reducer* c)
|
||||||
|
{
|
||||||
|
auto new_me = make_intrusive<PrintStmt>(singletons);
|
||||||
|
new_me->SetOriginal(ThisPtr());
|
||||||
|
return new_me;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
StmtPtr ExprStmt::Duplicate()
|
StmtPtr ExprStmt::Duplicate()
|
||||||
{
|
{
|
||||||
|
@ -34,6 +131,61 @@ void ExprStmt::Inline(Inliner* inl)
|
||||||
e = e->Inline(inl);
|
e = e->Inline(inl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ExprStmt::IsReduced(Reducer* c) const
|
||||||
|
{
|
||||||
|
if ( ! e || e->IsReduced(c) )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return NonReduced(e.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
StmtPtr ExprStmt::DoReduce(Reducer* c)
|
||||||
|
{
|
||||||
|
if ( ! e )
|
||||||
|
// e can be nil for our derived classes (like ReturnStmt).
|
||||||
|
return TransformMe(new NullStmt, c);
|
||||||
|
|
||||||
|
auto t = e->Tag();
|
||||||
|
|
||||||
|
if ( t == EXPR_NOP )
|
||||||
|
return TransformMe(new NullStmt, c);
|
||||||
|
|
||||||
|
if ( c->Optimizing() )
|
||||||
|
{
|
||||||
|
e = c->OptExpr(e);
|
||||||
|
return ThisPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( e->IsSingleton(c) )
|
||||||
|
// No point evaluating.
|
||||||
|
return TransformMe(new NullStmt, c);
|
||||||
|
|
||||||
|
if ( (t == EXPR_ASSIGN || t == EXPR_CALL ||
|
||||||
|
t == EXPR_INDEX_ASSIGN || t == EXPR_FIELD_LHS_ASSIGN ||
|
||||||
|
t == EXPR_APPEND_TO) &&
|
||||||
|
e->IsReduced(c) )
|
||||||
|
return ThisPtr();
|
||||||
|
|
||||||
|
StmtPtr red_e_stmt;
|
||||||
|
|
||||||
|
if ( t == EXPR_CALL )
|
||||||
|
// A bare call. If we reduce it regularly, if
|
||||||
|
// it has a non-void type it'll generate an
|
||||||
|
// assignment to a temporary.
|
||||||
|
red_e_stmt = e->ReduceToSingletons(c);
|
||||||
|
else
|
||||||
|
e = e->Reduce(c, red_e_stmt);
|
||||||
|
|
||||||
|
if ( red_e_stmt )
|
||||||
|
{
|
||||||
|
auto s = new StmtList(red_e_stmt, ThisPtr());
|
||||||
|
return TransformMe(s, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
return ThisPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
StmtPtr IfStmt::Duplicate()
|
StmtPtr IfStmt::Duplicate()
|
||||||
{
|
{
|
||||||
|
@ -51,6 +203,119 @@ void IfStmt::Inline(Inliner* inl)
|
||||||
s2->Inline(inl);
|
s2->Inline(inl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IfStmt::IsReduced(Reducer* c) const
|
||||||
|
{
|
||||||
|
if ( ! e->IsReducedConditional(c) )
|
||||||
|
return NonReduced(e.get());
|
||||||
|
|
||||||
|
return s1->IsReduced(c) && s2->IsReduced(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
StmtPtr IfStmt::DoReduce(Reducer* c)
|
||||||
|
{
|
||||||
|
StmtPtr red_e_stmt;
|
||||||
|
|
||||||
|
if ( e->WillTransformInConditional(c) )
|
||||||
|
e = e->ReduceToConditional(c, red_e_stmt);
|
||||||
|
|
||||||
|
// First, assess some fundamental transformations.
|
||||||
|
if ( e->Tag() == EXPR_NOT )
|
||||||
|
{ // Change "if ( ! x ) s1 else s2" to "if ( x ) s2 else s1".
|
||||||
|
auto s1_orig = s1;
|
||||||
|
s1 = s2;
|
||||||
|
s2 = s1_orig;
|
||||||
|
|
||||||
|
e = e->GetOp1();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( e->Tag() == EXPR_OR_OR && c->BifurcationOkay() )
|
||||||
|
{
|
||||||
|
c->PushBifurcation();
|
||||||
|
|
||||||
|
// Expand "if ( a || b ) s1 else s2" to
|
||||||
|
// "if ( a ) s1 else { if ( b ) s1 else s2 }"
|
||||||
|
auto a = e->GetOp1();
|
||||||
|
auto b = e->GetOp2();
|
||||||
|
|
||||||
|
auto s1_dup = s1 ? s1->Duplicate() : nullptr;
|
||||||
|
s2 = make_intrusive<IfStmt>(b, s1_dup, s2);
|
||||||
|
e = a;
|
||||||
|
|
||||||
|
auto res = DoReduce(c);
|
||||||
|
c->PopBifurcation();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( e->Tag() == EXPR_AND_AND && c->BifurcationOkay() )
|
||||||
|
{
|
||||||
|
c->PushBifurcation();
|
||||||
|
|
||||||
|
// Expand "if ( a && b ) s1 else s2" to
|
||||||
|
// "if ( a ) { if ( b ) s1 else s2 } else s2"
|
||||||
|
auto a = e->GetOp1();
|
||||||
|
auto b = e->GetOp2();
|
||||||
|
|
||||||
|
auto s2_dup = s2 ? s2->Duplicate() : nullptr;
|
||||||
|
s1 = make_intrusive<IfStmt>(b, s1, s2_dup);
|
||||||
|
e = a;
|
||||||
|
|
||||||
|
auto res = DoReduce(c);
|
||||||
|
c->PopBifurcation();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
s1 = s1->Reduce(c);
|
||||||
|
s2 = s2->Reduce(c);
|
||||||
|
|
||||||
|
if ( s1->Tag() == STMT_NULL && s2->Tag() == STMT_NULL )
|
||||||
|
return TransformMe(new NullStmt, c);
|
||||||
|
|
||||||
|
if ( c->Optimizing() )
|
||||||
|
e = c->OptExpr(e);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StmtPtr cond_red_stmt;
|
||||||
|
e = e->ReduceToConditional(c, cond_red_stmt);
|
||||||
|
|
||||||
|
if ( red_e_stmt && cond_red_stmt )
|
||||||
|
red_e_stmt = make_intrusive<StmtList>(red_e_stmt,
|
||||||
|
cond_red_stmt);
|
||||||
|
else if ( cond_red_stmt )
|
||||||
|
red_e_stmt = cond_red_stmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( e->IsConst() )
|
||||||
|
{
|
||||||
|
auto c_e = e->AsConstExprPtr();
|
||||||
|
auto t = c_e->Value()->AsBool();
|
||||||
|
|
||||||
|
if ( c->Optimizing() )
|
||||||
|
return t ? s1 : s2;
|
||||||
|
|
||||||
|
if ( t )
|
||||||
|
return TransformMe(new StmtList(red_e_stmt, s1), c);
|
||||||
|
else
|
||||||
|
return TransformMe(new StmtList(red_e_stmt, s2), c);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( red_e_stmt )
|
||||||
|
return TransformMe(new StmtList(red_e_stmt, this), c);
|
||||||
|
|
||||||
|
return ThisPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IfStmt::NoFlowAfter(bool ignore_break) const
|
||||||
|
{
|
||||||
|
if ( s1 && s2 )
|
||||||
|
return s1->NoFlowAfter(ignore_break) &&
|
||||||
|
s2->NoFlowAfter(ignore_break);
|
||||||
|
|
||||||
|
// Assuming the test isn't constant, the non-existent branch
|
||||||
|
// could be picked, so flow definitely continues afterwards.
|
||||||
|
// (Constant branches will be pruned during reduciton.)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
IntrusivePtr<Case> Case::Duplicate()
|
IntrusivePtr<Case> Case::Duplicate()
|
||||||
{
|
{
|
||||||
|
@ -86,6 +351,128 @@ void SwitchStmt::Inline(Inliner* inl)
|
||||||
c->Body()->Inline(inl);
|
c->Body()->Inline(inl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SwitchStmt::IsReduced(Reducer* r) const
|
||||||
|
{
|
||||||
|
if ( ! e->IsReduced(r) )
|
||||||
|
return NonReduced(e.get());
|
||||||
|
|
||||||
|
for ( const auto& c : *cases )
|
||||||
|
{
|
||||||
|
if ( c->ExprCases() && ! c->ExprCases()->IsReduced(r) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( c->TypeCases() && ! r->IDsAreReduced(c->TypeCases()) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( ! c->Body()->IsReduced(r) )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
StmtPtr SwitchStmt::DoReduce(Reducer* rc)
|
||||||
|
{
|
||||||
|
auto s = make_intrusive<StmtList>();
|
||||||
|
StmtPtr red_e_stmt;
|
||||||
|
|
||||||
|
if ( rc->Optimizing() )
|
||||||
|
e = rc->OptExpr(e);
|
||||||
|
else
|
||||||
|
e = e->Reduce(rc, red_e_stmt);
|
||||||
|
|
||||||
|
// Note, the compiler checks for constant switch expressions.
|
||||||
|
|
||||||
|
if ( red_e_stmt )
|
||||||
|
s->Stmts().push_back(red_e_stmt.release());
|
||||||
|
|
||||||
|
for ( const auto& c : *cases )
|
||||||
|
{
|
||||||
|
auto c_e = c->ExprCases();
|
||||||
|
if ( c_e )
|
||||||
|
{
|
||||||
|
StmtPtr c_e_stmt;
|
||||||
|
auto red_cases = c_e->Reduce(rc, c_e_stmt);
|
||||||
|
|
||||||
|
if ( c_e_stmt )
|
||||||
|
s->Stmts().push_back(c_e_stmt.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto c_t = c->TypeCases();
|
||||||
|
if ( c_t )
|
||||||
|
rc->UpdateIDs(c_t);
|
||||||
|
|
||||||
|
c->UpdateBody(c->Body()->Reduce(rc));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upate type cases.
|
||||||
|
for ( auto& i : case_label_type_list )
|
||||||
|
{
|
||||||
|
IDPtr idp = {NewRef{}, i.first};
|
||||||
|
i.first = rc->UpdateID(idp).release();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( s->Stmts().length() > 0 )
|
||||||
|
{
|
||||||
|
StmtPtr me = ThisPtr();
|
||||||
|
auto pre_and_me = new StmtList(s, me);
|
||||||
|
return TransformMe(pre_and_me, rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ThisPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SwitchStmt::NoFlowAfter(bool ignore_break) const
|
||||||
|
{
|
||||||
|
bool control_reaches_end = false;
|
||||||
|
bool default_seen_with_no_flow_after = false;
|
||||||
|
|
||||||
|
for ( const auto& c : *Cases() )
|
||||||
|
{
|
||||||
|
if ( ! c->Body()->NoFlowAfter(true) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( (! c->ExprCases() ||
|
||||||
|
c->ExprCases()->Exprs().length() == 0) &&
|
||||||
|
(! c->TypeCases() ||
|
||||||
|
c->TypeCases()->length() == 0) )
|
||||||
|
// We saw the default, and the test before this
|
||||||
|
// one established that it has no flow after it.
|
||||||
|
default_seen_with_no_flow_after = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return default_seen_with_no_flow_after;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool AddDelStmt::IsReduced(Reducer* c) const
|
||||||
|
{
|
||||||
|
return e->HasReducedOps(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
StmtPtr AddDelStmt::DoReduce(Reducer* c)
|
||||||
|
{
|
||||||
|
if ( c->Optimizing() )
|
||||||
|
{
|
||||||
|
e = c->OptExpr(e);
|
||||||
|
return ThisPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( e->Tag() != EXPR_INDEX && e->Tag() != EXPR_FIELD )
|
||||||
|
Internal("bad \"add\"/\"delete\"");
|
||||||
|
|
||||||
|
auto red_e_stmt = e->ReduceToSingletons(c);
|
||||||
|
|
||||||
|
if ( red_e_stmt )
|
||||||
|
{
|
||||||
|
auto s = new StmtList(red_e_stmt, ThisPtr());
|
||||||
|
return TransformMe(s, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
return ThisPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
StmtPtr AddStmt::Duplicate()
|
StmtPtr AddStmt::Duplicate()
|
||||||
{
|
{
|
||||||
|
@ -104,6 +491,32 @@ StmtPtr EventStmt::Duplicate()
|
||||||
return SetSucc(new EventStmt(e->Duplicate()->AsEventExprPtr()));
|
return SetSucc(new EventStmt(e->Duplicate()->AsEventExprPtr()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StmtPtr EventStmt::DoReduce(Reducer* c)
|
||||||
|
{
|
||||||
|
if ( c->Optimizing() )
|
||||||
|
{
|
||||||
|
e = c->OptExpr(e);
|
||||||
|
event_expr = e->AsEventExprPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ( ! event_expr->IsSingleton(c) )
|
||||||
|
{
|
||||||
|
StmtPtr red_e_stmt;
|
||||||
|
auto ee_red = event_expr->Reduce(c, red_e_stmt);
|
||||||
|
|
||||||
|
event_expr = ee_red->AsEventExprPtr();
|
||||||
|
e = event_expr;
|
||||||
|
|
||||||
|
if ( red_e_stmt )
|
||||||
|
{
|
||||||
|
auto s = new StmtList(red_e_stmt, ThisPtr());
|
||||||
|
return TransformMe(s, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ThisPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
StmtPtr WhileStmt::Duplicate()
|
StmtPtr WhileStmt::Duplicate()
|
||||||
{
|
{
|
||||||
|
@ -115,12 +528,55 @@ void WhileStmt::Inline(Inliner* inl)
|
||||||
{
|
{
|
||||||
loop_condition = loop_condition->Inline(inl);
|
loop_condition = loop_condition->Inline(inl);
|
||||||
|
|
||||||
if ( loop_cond_stmt )
|
if ( loop_cond_pred_stmt )
|
||||||
loop_cond_stmt->Inline(inl);
|
loop_cond_pred_stmt->Inline(inl);
|
||||||
if ( body )
|
if ( body )
|
||||||
body->Inline(inl);
|
body->Inline(inl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WhileStmt::IsReduced(Reducer* c) const
|
||||||
|
{
|
||||||
|
// No need to check loop_cond_pred_stmt, as we create it reduced.
|
||||||
|
return loop_condition->IsReducedConditional(c) && body->IsReduced(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
StmtPtr WhileStmt::DoReduce(Reducer* c)
|
||||||
|
{
|
||||||
|
if ( c->Optimizing() )
|
||||||
|
loop_condition = c->OptExpr(loop_condition);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( IsReduced(c) )
|
||||||
|
{
|
||||||
|
if ( ! c->IsPruning() )
|
||||||
|
{
|
||||||
|
// See comment below for the particulars
|
||||||
|
// of this constructor.
|
||||||
|
stmt_loop_condition =
|
||||||
|
make_intrusive<ExprStmt>(STMT_EXPR,
|
||||||
|
loop_condition);
|
||||||
|
return ThisPtr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
loop_condition = loop_condition->ReduceToConditional(c,
|
||||||
|
loop_cond_pred_stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
body = body->Reduce(c);
|
||||||
|
|
||||||
|
// We use the more involved ExprStmt constructor here to bypass
|
||||||
|
// its check for whether the expression is being ignored, since
|
||||||
|
// we're not actually creating an ExprStmt for execution.
|
||||||
|
stmt_loop_condition =
|
||||||
|
make_intrusive<ExprStmt>(STMT_EXPR, loop_condition);
|
||||||
|
|
||||||
|
if ( loop_cond_pred_stmt )
|
||||||
|
loop_cond_pred_stmt = loop_cond_pred_stmt->Reduce(c);
|
||||||
|
|
||||||
|
return ThisPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
StmtPtr ForStmt::Duplicate()
|
StmtPtr ForStmt::Duplicate()
|
||||||
{
|
{
|
||||||
|
@ -151,6 +607,46 @@ void ForStmt::Inline(Inliner* inl)
|
||||||
body->Inline(inl);
|
body->Inline(inl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ForStmt::IsReduced(Reducer* c) const
|
||||||
|
{
|
||||||
|
if ( ! e->IsReduced(c) )
|
||||||
|
return NonReduced(e.get());
|
||||||
|
|
||||||
|
if ( ! c->IDsAreReduced(loop_vars) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( value_var && ! c->ID_IsReduced(value_var) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return body->IsReduced(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
StmtPtr ForStmt::DoReduce(Reducer* c)
|
||||||
|
{
|
||||||
|
StmtPtr red_e_stmt;
|
||||||
|
|
||||||
|
if ( c->Optimizing() )
|
||||||
|
e = c->OptExpr(e);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
e = e->Reduce(c, red_e_stmt);
|
||||||
|
c->UpdateIDs(loop_vars);
|
||||||
|
|
||||||
|
if ( value_var )
|
||||||
|
value_var = c->UpdateID(value_var);
|
||||||
|
}
|
||||||
|
|
||||||
|
body = body->Reduce(c);
|
||||||
|
|
||||||
|
if ( body->Tag() == STMT_NULL )
|
||||||
|
Error("empty \"for\" body leaves loop variables in indeterminant state");
|
||||||
|
|
||||||
|
if ( red_e_stmt )
|
||||||
|
return TransformMe(new StmtList(red_e_stmt, this), c);
|
||||||
|
|
||||||
|
return ThisPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
StmtPtr ReturnStmt::Duplicate()
|
StmtPtr ReturnStmt::Duplicate()
|
||||||
{
|
{
|
||||||
|
@ -162,6 +658,61 @@ ReturnStmt::ReturnStmt(ExprPtr arg_e, bool ignored)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StmtPtr ReturnStmt::DoReduce(Reducer* c)
|
||||||
|
{
|
||||||
|
if ( ! e )
|
||||||
|
return ThisPtr();
|
||||||
|
|
||||||
|
if ( c->Optimizing() )
|
||||||
|
{
|
||||||
|
e = c->OptExpr(e);
|
||||||
|
return ThisPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! e->IsSingleton(c) )
|
||||||
|
{
|
||||||
|
StmtPtr red_e_stmt;
|
||||||
|
e = e->Reduce(c, red_e_stmt);
|
||||||
|
|
||||||
|
if ( red_e_stmt )
|
||||||
|
{
|
||||||
|
auto s = new StmtList(red_e_stmt, ThisPtr());
|
||||||
|
return TransformMe(s, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ThisPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
StmtList::StmtList(StmtPtr s1, Stmt* s2) : Stmt(STMT_LIST)
|
||||||
|
{
|
||||||
|
stmts = new StmtPList;
|
||||||
|
if ( s1 )
|
||||||
|
stmts->append(s1.release());
|
||||||
|
if ( s2 )
|
||||||
|
stmts->append(s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
StmtList::StmtList(StmtPtr s1, StmtPtr s2) : Stmt(STMT_LIST)
|
||||||
|
{
|
||||||
|
stmts = new StmtPList;
|
||||||
|
if ( s1 )
|
||||||
|
stmts->append(s1.release());
|
||||||
|
if ( s2 )
|
||||||
|
stmts->append(s2.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
StmtList::StmtList(StmtPtr s1, StmtPtr s2, StmtPtr s3) : Stmt(STMT_LIST)
|
||||||
|
{
|
||||||
|
stmts = new StmtPList;
|
||||||
|
if ( s1 )
|
||||||
|
stmts->append(s1.release());
|
||||||
|
if ( s2 )
|
||||||
|
stmts->append(s2.release());
|
||||||
|
if ( s3 )
|
||||||
|
stmts->append(s3.release());
|
||||||
|
}
|
||||||
|
|
||||||
StmtPtr StmtList::Duplicate()
|
StmtPtr StmtList::Duplicate()
|
||||||
{
|
{
|
||||||
|
@ -179,6 +730,181 @@ void StmtList::Inline(Inliner* inl)
|
||||||
stmt->Inline(inl);
|
stmt->Inline(inl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StmtList::IsReduced(Reducer* c) const
|
||||||
|
{
|
||||||
|
int n = Stmts().length();
|
||||||
|
|
||||||
|
for ( auto i = 0; i < n; ++i )
|
||||||
|
{
|
||||||
|
auto& s_i = Stmts()[i];
|
||||||
|
if ( ! s_i->IsReduced(c) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( s_i->NoFlowAfter(false) && i < n - 1 )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
StmtPtr StmtList::DoReduce(Reducer* c)
|
||||||
|
{
|
||||||
|
StmtPList* f_stmts = new StmtPList;
|
||||||
|
bool did_change = false;
|
||||||
|
|
||||||
|
int n = Stmts().length();
|
||||||
|
|
||||||
|
for ( auto i = 0; i < n; ++i )
|
||||||
|
{
|
||||||
|
if ( ReduceStmt(i, f_stmts, c) )
|
||||||
|
did_change = true;
|
||||||
|
|
||||||
|
if ( i < n - 1 && Stmts()[i]->NoFlowAfter(false) )
|
||||||
|
{
|
||||||
|
did_change = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( reporter->Errors() > 0 )
|
||||||
|
return ThisPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( f_stmts->length() == 0 )
|
||||||
|
return TransformMe(new NullStmt, c);
|
||||||
|
|
||||||
|
if ( f_stmts->length() == 1 )
|
||||||
|
return (*f_stmts)[0]->Reduce(c);
|
||||||
|
|
||||||
|
if ( did_change )
|
||||||
|
{
|
||||||
|
ResetStmts(f_stmts);
|
||||||
|
return Reduce(c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
delete f_stmts;
|
||||||
|
|
||||||
|
return ThisPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StmtList::ReduceStmt(int& s_i, StmtPList* f_stmts, Reducer* c)
|
||||||
|
{
|
||||||
|
bool did_change = false;
|
||||||
|
auto stmt = Stmts()[s_i]->ThisPtr();
|
||||||
|
|
||||||
|
auto old_stmt = stmt;
|
||||||
|
|
||||||
|
stmt = stmt->Reduce(c);
|
||||||
|
|
||||||
|
if ( stmt != old_stmt )
|
||||||
|
did_change = true;
|
||||||
|
|
||||||
|
if ( c->Optimizing() && stmt->Tag() == STMT_EXPR )
|
||||||
|
{
|
||||||
|
// There are two potential optimizations that affect
|
||||||
|
// whether we keep assignment statements. The first is
|
||||||
|
// for potential assignment chains like
|
||||||
|
//
|
||||||
|
// tmp1 = x;
|
||||||
|
// tmp2 = tmp1;
|
||||||
|
//
|
||||||
|
// where we can change this pair to simply "tmp2 = x", assuming
|
||||||
|
// no later use of tmp1.
|
||||||
|
//
|
||||||
|
// In addition, if we have "tmp1 = e" and "e" is an expression
|
||||||
|
// already computed into another temporary (say tmp0) that's
|
||||||
|
// safely usable at this point, then we can elide the tmp1
|
||||||
|
// assignment entirely.
|
||||||
|
auto s_e = stmt->AsExprStmt();
|
||||||
|
auto e = s_e->StmtExpr();
|
||||||
|
|
||||||
|
if ( e->Tag() != EXPR_ASSIGN )
|
||||||
|
{
|
||||||
|
f_stmts->append(stmt.release());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto a = e->AsAssignExpr();
|
||||||
|
auto lhs = a->Op1()->AsRefExprPtr()->Op();
|
||||||
|
|
||||||
|
if ( lhs->Tag() != EXPR_NAME )
|
||||||
|
{
|
||||||
|
f_stmts->append(stmt.release());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto var = lhs->AsNameExpr();
|
||||||
|
auto rhs = a->GetOp2();
|
||||||
|
|
||||||
|
if ( s_i < Stmts().length() - 1 )
|
||||||
|
{
|
||||||
|
// See if we can compress an assignment chain.
|
||||||
|
auto& s_i_succ = Stmts()[s_i + 1];
|
||||||
|
|
||||||
|
// Don't reduce s_i_succ. If it's what we're
|
||||||
|
// looking for, it's already reduced.
|
||||||
|
auto merge = c->MergeStmts(var, rhs, s_i_succ);
|
||||||
|
if ( merge )
|
||||||
|
{
|
||||||
|
f_stmts->append(merge);
|
||||||
|
|
||||||
|
// Skip both this statement and the next,
|
||||||
|
// now that we've substituted the merge.
|
||||||
|
++s_i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( c->IsCSE(a, var, rhs.get()) )
|
||||||
|
{
|
||||||
|
// printf("discarding %s as unnecessary\n", obj_desc(a));
|
||||||
|
// Skip this now unnecessary statement.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( stmt->Tag() == STMT_LIST )
|
||||||
|
{ // inline the list
|
||||||
|
auto sl = stmt->AsStmtList();
|
||||||
|
|
||||||
|
for ( auto& sub_stmt : sl->Stmts() )
|
||||||
|
f_stmts->append(sub_stmt->Ref());
|
||||||
|
|
||||||
|
did_change = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ( stmt->Tag() == STMT_NULL )
|
||||||
|
// skip it
|
||||||
|
did_change = true;
|
||||||
|
|
||||||
|
else
|
||||||
|
// No need to Ref() because the StmtPList destructor
|
||||||
|
// doesn't Unref(), only the explict list-walking
|
||||||
|
// in the ~StmtList destructor.
|
||||||
|
f_stmts->append(stmt.release());
|
||||||
|
|
||||||
|
return did_change;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StmtList::NoFlowAfter(bool ignore_break) const
|
||||||
|
{
|
||||||
|
for ( auto& s : Stmts() )
|
||||||
|
{
|
||||||
|
// For "break" statements, if ignore_break is set then
|
||||||
|
// by construction flow *does* go to after this statement
|
||||||
|
// list. If we just used the second test below, then
|
||||||
|
// while the "break" would indicate there's flow after it,
|
||||||
|
// if there's dead code following that includes a "return",
|
||||||
|
// this would in fact be incorrect.
|
||||||
|
if ( ignore_break && s->Tag() == STMT_BREAK )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( s->NoFlowAfter(ignore_break) )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
StmtPtr InitStmt::Duplicate()
|
StmtPtr InitStmt::Duplicate()
|
||||||
{
|
{
|
||||||
|
@ -191,6 +917,17 @@ StmtPtr InitStmt::Duplicate()
|
||||||
return SetSucc(new InitStmt(new_inits));
|
return SetSucc(new InitStmt(new_inits));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InitStmt::IsReduced(Reducer* c) const
|
||||||
|
{
|
||||||
|
return c->IDsAreReduced(inits);
|
||||||
|
}
|
||||||
|
|
||||||
|
StmtPtr InitStmt::DoReduce(Reducer* c)
|
||||||
|
{
|
||||||
|
c->UpdateIDs(inits);
|
||||||
|
return ThisPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
StmtPtr WhenStmt::Duplicate()
|
StmtPtr WhenStmt::Duplicate()
|
||||||
{
|
{
|
||||||
|
@ -208,5 +945,149 @@ void WhenStmt::Inline(Inliner* inl)
|
||||||
// the frames of closures.
|
// the frames of closures.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WhenStmt::IsReduced(Reducer* c) const
|
||||||
|
{
|
||||||
|
// We consider these always reduced because they're not
|
||||||
|
// candidates for any further optimization.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CatchReturnStmt::CatchReturnStmt(StmtPtr _block, NameExprPtr _ret_var)
|
||||||
|
: Stmt(STMT_CATCH_RETURN)
|
||||||
|
{
|
||||||
|
block = _block;
|
||||||
|
ret_var = _ret_var;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValPtr CatchReturnStmt::Exec(Frame* f, StmtFlowType& flow) const
|
||||||
|
{
|
||||||
|
RegisterAccess();
|
||||||
|
|
||||||
|
auto val = block->Exec(f, flow);
|
||||||
|
|
||||||
|
if ( flow == FLOW_RETURN )
|
||||||
|
flow = FLOW_NEXT;
|
||||||
|
|
||||||
|
if ( ret_var )
|
||||||
|
f->SetElement(ret_var->Id()->Offset(), val);
|
||||||
|
|
||||||
|
// Note, do *not* return the value! That's taken as a signal
|
||||||
|
// that a full return executed.
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CatchReturnStmt::IsPure() const
|
||||||
|
{
|
||||||
|
// The ret_var is pure by construction.
|
||||||
|
return block->IsPure();
|
||||||
|
}
|
||||||
|
|
||||||
|
StmtPtr CatchReturnStmt::Duplicate()
|
||||||
|
{
|
||||||
|
auto rv_dup = ret_var->Duplicate();
|
||||||
|
auto rv_dup_ptr = rv_dup->AsNameExprPtr();
|
||||||
|
return SetSucc(new CatchReturnStmt(block->Duplicate(), rv_dup_ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
StmtPtr CatchReturnStmt::DoReduce(Reducer* c)
|
||||||
|
{
|
||||||
|
block = block->Reduce(c);
|
||||||
|
|
||||||
|
if ( block->Tag() == STMT_RETURN )
|
||||||
|
{
|
||||||
|
// The whole thing reduced to a bare return. This can
|
||||||
|
// happen due to constant propagation.
|
||||||
|
auto ret = block->AsReturnStmt();
|
||||||
|
auto ret_e = ret->StmtExprPtr();
|
||||||
|
|
||||||
|
if ( ! ret_e )
|
||||||
|
{
|
||||||
|
if ( ret_var )
|
||||||
|
reporter->InternalError("inlining inconsistency: no return value");
|
||||||
|
|
||||||
|
return make_intrusive<NullStmt>();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto assign = make_intrusive<AssignExpr>(ret_var->Duplicate(),
|
||||||
|
ret_e->Duplicate(),
|
||||||
|
false);
|
||||||
|
assign_stmt = make_intrusive<ExprStmt>(assign);
|
||||||
|
return assign_stmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ThisPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CatchReturnStmt::StmtDescribe(ODesc* d) const
|
||||||
|
{
|
||||||
|
Stmt::StmtDescribe(d);
|
||||||
|
block->Describe(d);
|
||||||
|
DescribeDone(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
TraversalCode CatchReturnStmt::Traverse(TraversalCallback* cb) const
|
||||||
|
{
|
||||||
|
TraversalCode tc = cb->PreStmt(this);
|
||||||
|
HANDLE_TC_STMT_PRE(tc);
|
||||||
|
|
||||||
|
block->Traverse(cb);
|
||||||
|
|
||||||
|
if ( ret_var )
|
||||||
|
ret_var->Traverse(cb);
|
||||||
|
|
||||||
|
tc = cb->PostStmt(this);
|
||||||
|
HANDLE_TC_STMT_POST(tc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CheckAnyLenStmt::CheckAnyLenStmt(ExprPtr arg_e, int _expected_len)
|
||||||
|
: ExprStmt(STMT_CHECK_ANY_LEN, std::move(arg_e))
|
||||||
|
{
|
||||||
|
expected_len = _expected_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValPtr CheckAnyLenStmt::Exec(Frame* f, StmtFlowType& flow) const
|
||||||
|
{
|
||||||
|
RegisterAccess();
|
||||||
|
flow = FLOW_NEXT;
|
||||||
|
|
||||||
|
auto& v = e->Eval(f)->AsListVal()->Vals();
|
||||||
|
|
||||||
|
if ( v.size() != expected_len )
|
||||||
|
reporter->ExprRuntimeError(e.get(), "mismatch in list lengths");
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
StmtPtr CheckAnyLenStmt::Duplicate()
|
||||||
|
{
|
||||||
|
return SetSucc(new CheckAnyLenStmt(e->Duplicate(), expected_len));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckAnyLenStmt::IsReduced(Reducer* c) const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
StmtPtr CheckAnyLenStmt::DoReduce(Reducer* c)
|
||||||
|
{
|
||||||
|
// These are created in reduced form.
|
||||||
|
return ThisPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckAnyLenStmt::StmtDescribe(ODesc* d) const
|
||||||
|
{
|
||||||
|
Stmt::StmtDescribe(d);
|
||||||
|
|
||||||
|
e->Describe(d);
|
||||||
|
if ( ! d->IsBinary() )
|
||||||
|
d->Add(".length == ");
|
||||||
|
|
||||||
|
d->Add(expected_len);
|
||||||
|
|
||||||
|
DescribeDone(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace zeek::detail
|
} // namespace zeek::detail
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue