mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
reductions of expressions in ASTs - code compiles but doesn't yet link
This commit is contained in:
parent
6aa84087b0
commit
10e80dfcd3
8 changed files with 3264 additions and 164 deletions
294
src/Expr.cc
294
src/Expr.cc
|
@ -41,6 +41,10 @@ const char* expr_name(BroExprTag t)
|
||||||
"coerce", "record_coerce", "table_coerce", "vector_coerce",
|
"coerce", "record_coerce", "table_coerce", "vector_coerce",
|
||||||
"sizeof", "cast", "is", "[:]=",
|
"sizeof", "cast", "is", "[:]=",
|
||||||
"inline()",
|
"inline()",
|
||||||
|
"[]=", "$=",
|
||||||
|
"vec+=",
|
||||||
|
"to_any_coerce", "from_any_coerce",
|
||||||
|
"any[]",
|
||||||
"nop",
|
"nop",
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -95,12 +99,24 @@ NameExpr* Expr::AsNameExpr()
|
||||||
return (NameExpr*) this;
|
return (NameExpr*) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NameExprPtr Expr::AsNameExprPtr()
|
||||||
|
{
|
||||||
|
CHECK_TAG(tag, EXPR_NAME, "ExprVal::AsNameExpr", expr_name)
|
||||||
|
return {NewRef{}, (NameExpr*) this};
|
||||||
|
}
|
||||||
|
|
||||||
const ConstExpr* Expr::AsConstExpr() const
|
const ConstExpr* Expr::AsConstExpr() const
|
||||||
{
|
{
|
||||||
CHECK_TAG(tag, EXPR_CONST, "ExprVal::AsConstExpr", expr_name)
|
CHECK_TAG(tag, EXPR_CONST, "ExprVal::AsConstExpr", expr_name)
|
||||||
return (const ConstExpr*) this;
|
return (const ConstExpr*) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConstExprPtr Expr::AsConstExprPtr()
|
||||||
|
{
|
||||||
|
CHECK_TAG(tag, EXPR_CONST, "ExprVal::AsConstExpr", expr_name)
|
||||||
|
return {NewRef{}, (ConstExpr*) this};
|
||||||
|
}
|
||||||
|
|
||||||
const CallExpr* Expr::AsCallExpr() const
|
const CallExpr* Expr::AsCallExpr() const
|
||||||
{
|
{
|
||||||
CHECK_TAG(tag, EXPR_CALL, "ExprVal::AsCallExpr", expr_name)
|
CHECK_TAG(tag, EXPR_CALL, "ExprVal::AsCallExpr", expr_name)
|
||||||
|
@ -143,6 +159,12 @@ EventExprPtr Expr::AsEventExprPtr()
|
||||||
return {NewRef{}, (EventExpr*) this};
|
return {NewRef{}, (EventExpr*) this};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefExprPtr Expr::AsRefExprPtr()
|
||||||
|
{
|
||||||
|
CHECK_TAG(tag, EXPR_REF, "ExprVal::AsRefExpr", expr_name)
|
||||||
|
return {NewRef{}, (RefExpr*) this};
|
||||||
|
}
|
||||||
|
|
||||||
bool Expr::CanAdd() const
|
bool Expr::CanAdd() const
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -182,6 +204,132 @@ void Expr::Assign(Frame* /* f */, ValPtr /* v */)
|
||||||
Internal("Expr::Assign called");
|
Internal("Expr::Assign called");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Expr::AssignToIndex(ValPtr v1, ValPtr v2, ValPtr v3) const
|
||||||
|
{
|
||||||
|
bool iterators_invalidated;
|
||||||
|
|
||||||
|
auto error_msg = assign_to_index(v1, v2, v3, iterators_invalidated);
|
||||||
|
|
||||||
|
if ( iterators_invalidated )
|
||||||
|
{
|
||||||
|
ODesc d;
|
||||||
|
Describe(&d);
|
||||||
|
reporter->PushLocation(GetLocationInfo());
|
||||||
|
reporter->Warning("possible loop/iterator invalidation caused by expression: %s", d.Description());
|
||||||
|
reporter->PopLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( error_msg )
|
||||||
|
RuntimeErrorWithCallStack(error_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_slice_index(int idx, int len)
|
||||||
|
{
|
||||||
|
if ( abs(idx) > len )
|
||||||
|
idx = idx > 0 ? len : 0; // Clamp maximum positive/negative indices.
|
||||||
|
else if ( idx < 0 )
|
||||||
|
idx += len; // Map to a positive index.
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* assign_to_index(ValPtr v1, ValPtr v2, ValPtr v3,
|
||||||
|
bool& iterators_invalidated)
|
||||||
|
{
|
||||||
|
iterators_invalidated = false;
|
||||||
|
|
||||||
|
if ( ! v1 || ! v2 || ! v3 )
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Hold an extra reference to 'arg_v' in case the ownership transfer
|
||||||
|
// to the table/vector goes wrong and we still want to obtain
|
||||||
|
// diagnostic info from the original value after the assignment
|
||||||
|
// already unref'd.
|
||||||
|
auto v_extra = v3;
|
||||||
|
|
||||||
|
switch ( v1->GetType()->Tag() ) {
|
||||||
|
case TYPE_VECTOR:
|
||||||
|
{
|
||||||
|
const ListVal* lv = v2->AsListVal();
|
||||||
|
VectorVal* v1_vect = v1->AsVectorVal();
|
||||||
|
|
||||||
|
if ( lv->Length() > 1 )
|
||||||
|
{
|
||||||
|
auto len = v1_vect->Size();
|
||||||
|
bro_int_t first = get_slice_index(lv->Idx(0)->CoerceToInt(), len);
|
||||||
|
bro_int_t last = get_slice_index(lv->Idx(1)->CoerceToInt(), len);
|
||||||
|
|
||||||
|
// Remove the elements from the vector within the slice.
|
||||||
|
for ( auto idx = first; idx < last; idx++ )
|
||||||
|
v1_vect->Remove(first);
|
||||||
|
|
||||||
|
// Insert the new elements starting at the first
|
||||||
|
// position.
|
||||||
|
|
||||||
|
VectorVal* v_vect = v3->AsVectorVal();
|
||||||
|
|
||||||
|
for ( auto idx = 0u; idx < v_vect->Size();
|
||||||
|
idx++, first++ )
|
||||||
|
v1_vect->Insert(first, v_vect->At(idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ( ! v1_vect->Assign(lv->Idx(0)->CoerceToUnsigned(), std::move(v3)) )
|
||||||
|
{
|
||||||
|
v3 = std::move(v_extra);
|
||||||
|
|
||||||
|
if ( v3 )
|
||||||
|
{
|
||||||
|
ODesc d;
|
||||||
|
v3->Describe(&d);
|
||||||
|
const auto& vt = v3->GetType();
|
||||||
|
auto vtt = vt->Tag();
|
||||||
|
std::string tn = vtt == TYPE_RECORD ?
|
||||||
|
vt->GetName() : type_name(vtt);
|
||||||
|
return util::fmt("vector index assignment failed for invalid type '%s', value: %s",
|
||||||
|
tn.data(), d.Description());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return "assignment failed with null value";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TYPE_TABLE:
|
||||||
|
{
|
||||||
|
if ( ! v1->AsTableVal()->Assign(std::move(v2), std::move(v3), true, &iterators_invalidated) )
|
||||||
|
{
|
||||||
|
v3 = std::move(v_extra);
|
||||||
|
|
||||||
|
if ( v3 )
|
||||||
|
{
|
||||||
|
ODesc d;
|
||||||
|
v3->Describe(&d);
|
||||||
|
const auto& vt = v3->GetType();
|
||||||
|
auto vtt = vt->Tag();
|
||||||
|
std::string tn = vtt == TYPE_RECORD ?
|
||||||
|
vt->GetName() : type_name(vtt);
|
||||||
|
return util::fmt("table index assignment failed for invalid type '%s', value: %s",
|
||||||
|
tn.data(), d.Description());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return "assignment failed with null value";
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TYPE_STRING:
|
||||||
|
return "assignment via string index accessor not allowed";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "bad index expression type in assignment";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
TypePtr Expr::InitType() const
|
TypePtr Expr::InitType() const
|
||||||
{
|
{
|
||||||
return type;
|
return type;
|
||||||
|
@ -312,6 +460,12 @@ NameExpr::NameExpr(IDPtr arg_id, bool const_init)
|
||||||
h->SetUsed();
|
h->SetUsed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This isn't in-lined to avoid needing to pull in ID.h.
|
||||||
|
IDPtr NameExpr::IdPtr()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
ValPtr NameExpr::Eval(Frame* f) const
|
ValPtr NameExpr::Eval(Frame* f) const
|
||||||
{
|
{
|
||||||
ValPtr v;
|
ValPtr v;
|
||||||
|
@ -436,7 +590,14 @@ ValPtr UnaryExpr::Eval(Frame* f) const
|
||||||
if ( ! v )
|
if ( ! v )
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if ( is_vector(v) && Tag() != EXPR_IS && Tag() != EXPR_CAST )
|
if ( is_vector(v) && Tag() != EXPR_IS && Tag() != EXPR_CAST &&
|
||||||
|
// The following allows passing vectors-by-reference to
|
||||||
|
// functions that use vector-of-any for generic vector
|
||||||
|
// manipulation ...
|
||||||
|
Tag() != EXPR_TO_ANY_COERCE &&
|
||||||
|
// ... and the following to avoid vectorizing operations
|
||||||
|
// on vector-of-any's
|
||||||
|
Tag() != EXPR_FROM_ANY_COERCE )
|
||||||
{
|
{
|
||||||
VectorVal* v_op = v->AsVectorVal();
|
VectorVal* v_op = v->AsVectorVal();
|
||||||
VectorTypePtr out_t;
|
VectorTypePtr out_t;
|
||||||
|
@ -457,9 +618,7 @@ ValPtr UnaryExpr::Eval(Frame* f) const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
return Fold(v.get());
|
return Fold(v.get());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnaryExpr::IsPure() const
|
bool UnaryExpr::IsPure() const
|
||||||
|
@ -2129,7 +2288,8 @@ void RefExpr::Assign(Frame* f, ValPtr v)
|
||||||
AssignExpr::AssignExpr(ExprPtr arg_op1,
|
AssignExpr::AssignExpr(ExprPtr arg_op1,
|
||||||
ExprPtr arg_op2,
|
ExprPtr arg_op2,
|
||||||
bool arg_is_init, ValPtr arg_val,
|
bool arg_is_init, ValPtr arg_val,
|
||||||
const AttributesPtr& attrs)
|
const AttributesPtr& attrs,
|
||||||
|
bool typecheck)
|
||||||
: BinaryExpr(EXPR_ASSIGN, arg_is_init ?
|
: BinaryExpr(EXPR_ASSIGN, arg_is_init ?
|
||||||
std::move(arg_op1) : arg_op1->MakeLvalue(),
|
std::move(arg_op1) : arg_op1->MakeLvalue(),
|
||||||
std::move(arg_op2))
|
std::move(arg_op2))
|
||||||
|
@ -2152,9 +2312,10 @@ AssignExpr::AssignExpr(ExprPtr arg_op1,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We discard the status from TypeCheck since it has already
|
if ( typecheck )
|
||||||
// generated error messages.
|
// We discard the status from TypeCheck since it has already
|
||||||
(void) TypeCheck(attrs);
|
// generated error messages.
|
||||||
|
(void) TypeCheck(attrs);
|
||||||
|
|
||||||
val = std::move(arg_val);
|
val = std::move(arg_val);
|
||||||
|
|
||||||
|
@ -2754,16 +2915,6 @@ ValPtr IndexExpr::Eval(Frame* f) const
|
||||||
return Fold(v1.get(), v2.get());
|
return Fold(v1.get(), v2.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_slice_index(int idx, int len)
|
|
||||||
{
|
|
||||||
if ( abs(idx) > len )
|
|
||||||
idx = idx > 0 ? len : 0; // Clamp maximum positive/negative indices.
|
|
||||||
else if ( idx < 0 )
|
|
||||||
idx += len; // Map to a positive index.
|
|
||||||
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
ValPtr IndexExpr::Fold(Val* v1, Val* v2) const
|
ValPtr IndexExpr::Fold(Val* v1, Val* v2) const
|
||||||
{
|
{
|
||||||
if ( IsError() )
|
if ( IsError() )
|
||||||
|
@ -2855,105 +3006,9 @@ void IndexExpr::Assign(Frame* f, ValPtr v)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto v1 = op1->Eval(f);
|
auto v1 = op1->Eval(f);
|
||||||
|
|
||||||
if ( ! v1 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto v2 = op2->Eval(f);
|
auto v2 = op2->Eval(f);
|
||||||
|
|
||||||
if ( ! v1 || ! v2 )
|
AssignToIndex(v1, v2, v);
|
||||||
return;
|
|
||||||
|
|
||||||
// Hold an extra reference to 'arg_v' in case the ownership transfer to
|
|
||||||
// the table/vector goes wrong and we still want to obtain diagnostic info
|
|
||||||
// from the original value after the assignment already unref'd.
|
|
||||||
auto v_extra = v;
|
|
||||||
|
|
||||||
switch ( v1->GetType()->Tag() ) {
|
|
||||||
case TYPE_VECTOR:
|
|
||||||
{
|
|
||||||
const ListVal* lv = v2->AsListVal();
|
|
||||||
VectorVal* v1_vect = v1->AsVectorVal();
|
|
||||||
|
|
||||||
if ( lv->Length() > 1 )
|
|
||||||
{
|
|
||||||
auto len = v1_vect->Size();
|
|
||||||
bro_int_t first = get_slice_index(lv->Idx(0)->CoerceToInt(), len);
|
|
||||||
bro_int_t last = get_slice_index(lv->Idx(1)->CoerceToInt(), len);
|
|
||||||
|
|
||||||
// Remove the elements from the vector within the slice
|
|
||||||
for ( auto idx = first; idx < last; idx++ )
|
|
||||||
v1_vect->Remove(first);
|
|
||||||
|
|
||||||
// Insert the new elements starting at the first position
|
|
||||||
VectorVal* v_vect = v->AsVectorVal();
|
|
||||||
|
|
||||||
for ( auto idx = 0u; idx < v_vect->Size(); idx++, first++ )
|
|
||||||
v1_vect->Insert(first, v_vect->At(idx));
|
|
||||||
}
|
|
||||||
else if ( ! v1_vect->Assign(lv->Idx(0)->CoerceToUnsigned(), std::move(v)) )
|
|
||||||
{
|
|
||||||
v = std::move(v_extra);
|
|
||||||
|
|
||||||
if ( v )
|
|
||||||
{
|
|
||||||
ODesc d;
|
|
||||||
v->Describe(&d);
|
|
||||||
const auto& vt = v->GetType();
|
|
||||||
auto vtt = vt->Tag();
|
|
||||||
std::string tn = vtt == TYPE_RECORD ? vt->GetName() : type_name(vtt);
|
|
||||||
RuntimeErrorWithCallStack(util::fmt(
|
|
||||||
"vector index assignment failed for invalid type '%s', value: %s",
|
|
||||||
tn.data(), d.Description()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
RuntimeErrorWithCallStack("assignment failed with null value");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case TYPE_TABLE:
|
|
||||||
{
|
|
||||||
bool iterators_invalidated = false;
|
|
||||||
|
|
||||||
if ( ! v1->AsTableVal()->Assign(std::move(v2), std::move(v), true, &iterators_invalidated) )
|
|
||||||
{
|
|
||||||
v = std::move(v_extra);
|
|
||||||
|
|
||||||
if ( v )
|
|
||||||
{
|
|
||||||
ODesc d;
|
|
||||||
v->Describe(&d);
|
|
||||||
const auto& vt = v->GetType();
|
|
||||||
auto vtt = vt->Tag();
|
|
||||||
std::string tn = vtt == TYPE_RECORD ? vt->GetName() : type_name(vtt);
|
|
||||||
RuntimeErrorWithCallStack(util::fmt(
|
|
||||||
"table index assignment failed for invalid type '%s', value: %s",
|
|
||||||
tn.data(), d.Description()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
RuntimeErrorWithCallStack("assignment failed with null value");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( iterators_invalidated )
|
|
||||||
{
|
|
||||||
ODesc d;
|
|
||||||
Describe(&d);
|
|
||||||
reporter->PushLocation(GetLocationInfo());
|
|
||||||
reporter->Warning("possible loop/iterator invalidation caused by expression: %s", d.Description());
|
|
||||||
reporter->PopLocation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TYPE_STRING:
|
|
||||||
RuntimeErrorWithCallStack("assignment via string index accessor not allowed");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
RuntimeErrorWithCallStack("bad index expression type in assignment");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IndexExpr::ExprDescribe(ODesc* d) const
|
void IndexExpr::ExprDescribe(ODesc* d) const
|
||||||
|
@ -5168,7 +5223,16 @@ bool check_and_promote_args(ListExpr* const args, RecordType* types)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
def_elements.push_front(def_attr->GetExpr().get());
|
// Don't use the default expression directly, as
|
||||||
|
// doing so will wind up sharing its code across
|
||||||
|
// different invocations that use the default
|
||||||
|
// argument. That works okay for the interpreter,
|
||||||
|
// but if we transform the code we want that done
|
||||||
|
// separately for each instance, rather than
|
||||||
|
// one instance inheriting the transformed version
|
||||||
|
// from another.
|
||||||
|
auto e = def_attr->GetExpr();
|
||||||
|
def_elements.push_front(e->Duplicate().release());
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( const auto& elem : def_elements )
|
for ( const auto& elem : def_elements )
|
||||||
|
|
508
src/Expr.h
508
src/Expr.h
|
@ -68,6 +68,15 @@ enum BroExprTag : int {
|
||||||
EXPR_IS,
|
EXPR_IS,
|
||||||
EXPR_INDEX_SLICE_ASSIGN,
|
EXPR_INDEX_SLICE_ASSIGN,
|
||||||
EXPR_INLINE,
|
EXPR_INLINE,
|
||||||
|
|
||||||
|
// The following types of expressions are only created for
|
||||||
|
// ASTs transformed to reduced form; they aren't germane for
|
||||||
|
// ASTs produced by parsing .zeek script files.
|
||||||
|
EXPR_INDEX_ASSIGN, EXPR_FIELD_LHS_ASSIGN,
|
||||||
|
EXPR_APPEND_TO,
|
||||||
|
EXPR_TO_ANY_COERCE, EXPR_FROM_ANY_COERCE,
|
||||||
|
EXPR_ANY_INDEX,
|
||||||
|
|
||||||
EXPR_NOP,
|
EXPR_NOP,
|
||||||
|
|
||||||
#define NUM_EXPRS (int(EXPR_NOP) + 1)
|
#define NUM_EXPRS (int(EXPR_NOP) + 1)
|
||||||
|
@ -75,18 +84,27 @@ enum BroExprTag : int {
|
||||||
|
|
||||||
extern const char* expr_name(BroExprTag t);
|
extern const char* expr_name(BroExprTag t);
|
||||||
|
|
||||||
class ListExpr;
|
|
||||||
class NameExpr;
|
|
||||||
class ConstExpr;
|
|
||||||
class IndexExpr;
|
|
||||||
class AssignExpr;
|
class AssignExpr;
|
||||||
class CallExpr;
|
class CallExpr;
|
||||||
|
class ConstExpr;
|
||||||
class EventExpr;
|
class EventExpr;
|
||||||
class Stmt;
|
class FieldAssignExpr;
|
||||||
|
class FieldExpr;
|
||||||
|
class ForExpr;
|
||||||
|
class IndexExpr;
|
||||||
|
class ListExpr;
|
||||||
|
class NameExpr;
|
||||||
|
class RefExpr;
|
||||||
|
|
||||||
class Expr;
|
class Expr;
|
||||||
using ExprPtr = IntrusivePtr<Expr>;
|
using CallExprPtr = IntrusivePtr<CallExpr>;
|
||||||
|
using ConstExprPtr = IntrusivePtr<ConstExpr>;
|
||||||
using EventExprPtr = IntrusivePtr<EventExpr>;
|
using EventExprPtr = IntrusivePtr<EventExpr>;
|
||||||
|
using ExprPtr = IntrusivePtr<Expr>;
|
||||||
|
using NameExprPtr = IntrusivePtr<NameExpr>;
|
||||||
|
using RefExprPtr = IntrusivePtr<RefExpr>;
|
||||||
|
|
||||||
|
class Stmt;
|
||||||
using StmtPtr = IntrusivePtr<Stmt>;
|
using StmtPtr = IntrusivePtr<Stmt>;
|
||||||
|
|
||||||
class Expr : public Obj {
|
class Expr : public Obj {
|
||||||
|
@ -182,13 +200,17 @@ public:
|
||||||
ctype* As ## ctype (); \
|
ctype* As ## ctype (); \
|
||||||
IntrusivePtr<ctype> As ## ctype ## Ptr ();
|
IntrusivePtr<ctype> As ## ctype ## Ptr ();
|
||||||
|
|
||||||
|
ZEEK_EXPR_ACCESSOR_DECLS(AssignExpr)
|
||||||
|
ZEEK_EXPR_ACCESSOR_DECLS(CallExpr)
|
||||||
|
ZEEK_EXPR_ACCESSOR_DECLS(ConstExpr)
|
||||||
|
ZEEK_EXPR_ACCESSOR_DECLS(EventExpr)
|
||||||
|
ZEEK_EXPR_ACCESSOR_DECLS(FieldAssignExpr)
|
||||||
|
ZEEK_EXPR_ACCESSOR_DECLS(FieldExpr)
|
||||||
|
ZEEK_EXPR_ACCESSOR_DECLS(ForExpr)
|
||||||
|
ZEEK_EXPR_ACCESSOR_DECLS(IndexExpr)
|
||||||
ZEEK_EXPR_ACCESSOR_DECLS(ListExpr)
|
ZEEK_EXPR_ACCESSOR_DECLS(ListExpr)
|
||||||
ZEEK_EXPR_ACCESSOR_DECLS(NameExpr)
|
ZEEK_EXPR_ACCESSOR_DECLS(NameExpr)
|
||||||
ZEEK_EXPR_ACCESSOR_DECLS(ConstExpr)
|
ZEEK_EXPR_ACCESSOR_DECLS(RefExpr)
|
||||||
ZEEK_EXPR_ACCESSOR_DECLS(CallExpr)
|
|
||||||
ZEEK_EXPR_ACCESSOR_DECLS(AssignExpr)
|
|
||||||
ZEEK_EXPR_ACCESSOR_DECLS(IndexExpr)
|
|
||||||
ZEEK_EXPR_ACCESSOR_DECLS(EventExpr)
|
|
||||||
|
|
||||||
void Describe(ODesc* d) const override final;
|
void Describe(ODesc* d) const override final;
|
||||||
|
|
||||||
|
@ -200,6 +222,117 @@ public:
|
||||||
// Recursively traverses the AST to inline eligible function calls.
|
// Recursively traverses the AST to inline eligible function calls.
|
||||||
virtual ExprPtr Inline(Inliner* inl) { return ThisPtr(); }
|
virtual ExprPtr Inline(Inliner* inl) { return ThisPtr(); }
|
||||||
|
|
||||||
|
// True if the expression can serve as an operand to a reduced
|
||||||
|
// expression.
|
||||||
|
bool IsSingleton(Reducer* r) const
|
||||||
|
{
|
||||||
|
return (tag == EXPR_NAME && IsReduced(r)) || tag == EXPR_CONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
// True if the expression has no side effects, false otherwise.
|
||||||
|
virtual bool HasNoSideEffects() const { return IsPure(); }
|
||||||
|
|
||||||
|
// True if the expression is in fully reduced form: a singleton
|
||||||
|
// or an assignment to an operator with singleton operands.
|
||||||
|
virtual bool IsReduced(Reducer* c) const;
|
||||||
|
|
||||||
|
// True if the expression's operands are singletons.
|
||||||
|
virtual bool HasReducedOps(Reducer* c) const;
|
||||||
|
|
||||||
|
// True if (a) the expression has at least one operand, and (b) all
|
||||||
|
// of its operands are constant.
|
||||||
|
bool HasConstantOps() const
|
||||||
|
{
|
||||||
|
return GetOp1() && GetOp1()->IsConst() &&
|
||||||
|
(! GetOp2() ||
|
||||||
|
(GetOp2()->IsConst() &&
|
||||||
|
(! GetOp3() || GetOp3()->IsConst())));
|
||||||
|
}
|
||||||
|
|
||||||
|
// True if the expression is reduced to a form that can be
|
||||||
|
// used in a conditional.
|
||||||
|
bool IsReducedConditional(Reducer* c) const;
|
||||||
|
|
||||||
|
// True if the expression is reduced to a form that can be
|
||||||
|
// used in a field assignment.
|
||||||
|
bool IsReducedFieldAssignment(Reducer* c) const;
|
||||||
|
|
||||||
|
// True if this expression can be the RHS for a field assignment.
|
||||||
|
bool IsFieldAssignable(const Expr* e) const;
|
||||||
|
|
||||||
|
// True if the expression will transform to one of another type
|
||||||
|
// upon reduction, for non-constant operands. "Transform" means
|
||||||
|
// something beyond assignment to a temporary. Necessary so that
|
||||||
|
// we know to fully reduce such expressions if they're the RHS
|
||||||
|
// of an assignment.
|
||||||
|
virtual bool WillTransform(Reducer* c) const { return false; }
|
||||||
|
|
||||||
|
// The same, but for the expression when used in a conditional context.
|
||||||
|
virtual bool WillTransformInConditional(Reducer* c) const
|
||||||
|
{ return false; }
|
||||||
|
|
||||||
|
// Returns the current expression transformed into "new_me".
|
||||||
|
// Takes a bare pointer for "new_me" since often it's newly
|
||||||
|
// allocated.
|
||||||
|
ExprPtr TransformMe(Expr* new_me, Reducer* c, StmtPtr& red_stmt);
|
||||||
|
ExprPtr TransformMe(ExprPtr new_me, Reducer* c, StmtPtr& red_stmt)
|
||||||
|
{ return TransformMe(new_me.get(), c, red_stmt); }
|
||||||
|
|
||||||
|
// Returns a set of predecessor statements in red_stmt (which might
|
||||||
|
// be nil if no reduction necessary), and the reduced version of
|
||||||
|
// the expression, suitable for replacing previous uses. The
|
||||||
|
// second version always yields a singleton suitable for use
|
||||||
|
// as an operand. The first version does this too except
|
||||||
|
// for assignment statements; thus, its form is not guarantee
|
||||||
|
// suitable for use as an operand.
|
||||||
|
virtual ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt);
|
||||||
|
virtual ExprPtr ReduceToSingleton(Reducer* c, StmtPtr& red_stmt)
|
||||||
|
{ return Reduce(c, red_stmt); }
|
||||||
|
|
||||||
|
// Reduces the expression to one whose operands are singletons.
|
||||||
|
// Returns a predecessor statement (which might be a StmtList), if any.
|
||||||
|
virtual StmtPtr ReduceToSingletons(Reducer* c);
|
||||||
|
|
||||||
|
// Reduces the expression to one that can appear as a conditional.
|
||||||
|
ExprPtr ReduceToConditional(Reducer* c, StmtPtr& red_stmt);
|
||||||
|
|
||||||
|
// Reduces the expression to one that can appear as a field
|
||||||
|
// assignment.
|
||||||
|
ExprPtr ReduceToFieldAssignment(Reducer* c, StmtPtr& red_stmt);
|
||||||
|
|
||||||
|
// Helper function for factoring out complexities related to
|
||||||
|
// index-based assignment.
|
||||||
|
void AssignToIndex(ValPtr v1, ValPtr v2, ValPtr v3) const;
|
||||||
|
|
||||||
|
// Returns a new expression corresponding to a temporary
|
||||||
|
// that's been assigned to the given expression via red_stmt.
|
||||||
|
ExprPtr AssignToTemporary(ExprPtr e, Reducer* c, StmtPtr& red_stmt);
|
||||||
|
// Same but for this expression.
|
||||||
|
ExprPtr AssignToTemporary(Reducer* c, StmtPtr& red_stmt)
|
||||||
|
{ return AssignToTemporary(ThisPtr(), c, red_stmt); }
|
||||||
|
|
||||||
|
// If the expression always evaluates to the same value, returns
|
||||||
|
// that value. Otherwise, returns nullptr.
|
||||||
|
virtual ValPtr FoldVal() const { return nullptr; }
|
||||||
|
|
||||||
|
// Returns a Val or a constant Expr corresponding to zero.
|
||||||
|
ValPtr MakeZero(TypeTag t) const;
|
||||||
|
ConstExprPtr MakeZeroExpr(TypeTag t) const;
|
||||||
|
|
||||||
|
// Returns the expression's operands, or nil if it doesn't
|
||||||
|
// have the given operand.
|
||||||
|
virtual ExprPtr GetOp1() const;
|
||||||
|
virtual ExprPtr GetOp2() const;
|
||||||
|
virtual ExprPtr GetOp3() const;
|
||||||
|
|
||||||
|
// Sets the operands to new values.
|
||||||
|
virtual void SetOp1(ExprPtr new_op);
|
||||||
|
virtual void SetOp2(ExprPtr new_op);
|
||||||
|
virtual void SetOp3(ExprPtr new_op);
|
||||||
|
|
||||||
|
// Helper function to reduce boring code runs.
|
||||||
|
StmtPtr MergeStmts(StmtPtr s1, StmtPtr s2, StmtPtr s3 = nullptr) const;
|
||||||
|
|
||||||
// Access to the original expression from which this one is derived,
|
// Access to the original expression from which this one is derived,
|
||||||
// or this one if we don't have an original. Returns a bare pointer
|
// or this one if we don't have an original. Returns a bare pointer
|
||||||
// rather than an ExprPtr to emphasize that the access is read-only.
|
// rather than an ExprPtr to emphasize that the access is read-only.
|
||||||
|
@ -272,6 +405,7 @@ public:
|
||||||
explicit NameExpr(IDPtr id, bool const_init = false);
|
explicit NameExpr(IDPtr id, bool const_init = false);
|
||||||
|
|
||||||
ID* Id() const { return id.get(); }
|
ID* Id() const { return id.get(); }
|
||||||
|
IDPtr IdPtr();
|
||||||
|
|
||||||
ValPtr Eval(Frame* f) const override;
|
ValPtr Eval(Frame* f) const override;
|
||||||
void Assign(Frame* f, ValPtr v) override;
|
void Assign(Frame* f, ValPtr v) override;
|
||||||
|
@ -282,10 +416,20 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
bool HasNoSideEffects() const override { return true; }
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
bool HasReducedOps(Reducer* c) const override { return IsReduced(c); }
|
||||||
|
bool WillTransform(Reducer* c) const override { return ! IsReduced(c); }
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
ValPtr FoldVal() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void ExprDescribe(ODesc* d) const override;
|
void ExprDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
|
// Returns true if our identifier is a global with a constant value
|
||||||
|
// that can be propagated; used for optimization.
|
||||||
|
bool FoldableGlobal() const;
|
||||||
|
|
||||||
IDPtr id;
|
IDPtr id;
|
||||||
bool in_const_init;
|
bool in_const_init;
|
||||||
};
|
};
|
||||||
|
@ -303,6 +447,7 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
ValPtr FoldVal() const override { return val; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void ExprDescribe(ODesc* d) const override;
|
void ExprDescribe(ODesc* d) const override;
|
||||||
|
@ -325,6 +470,14 @@ public:
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Inline(Inliner* inl) override;
|
ExprPtr Inline(Inliner* inl) override;
|
||||||
|
|
||||||
|
bool HasNoSideEffects() const override;
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
bool HasReducedOps(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
|
ExprPtr GetOp1() const override final { return op; }
|
||||||
|
void SetOp1(ExprPtr _op) override final { op = std::move(_op); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
UnaryExpr(BroExprTag arg_tag, ExprPtr arg_op);
|
UnaryExpr(BroExprTag arg_tag, ExprPtr arg_op);
|
||||||
|
|
||||||
|
@ -353,6 +506,17 @@ public:
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Inline(Inliner* inl) override;
|
ExprPtr Inline(Inliner* inl) override;
|
||||||
|
|
||||||
|
bool HasNoSideEffects() const override;
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
bool HasReducedOps(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
|
ExprPtr GetOp1() const override final { return op1; }
|
||||||
|
ExprPtr GetOp2() const override final { return op2; }
|
||||||
|
|
||||||
|
void SetOp1(ExprPtr _op) override final { std::move(op1 = _op); }
|
||||||
|
void SetOp2(ExprPtr _op) override final { std::move(op2 = _op); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BinaryExpr(BroExprTag arg_tag,
|
BinaryExpr(BroExprTag arg_tag,
|
||||||
ExprPtr arg_op1, ExprPtr arg_op2)
|
ExprPtr arg_op1, ExprPtr arg_op2)
|
||||||
|
@ -425,6 +589,12 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
bool HasNoSideEffects() const override;
|
||||||
|
bool WillTransform(Reducer* c) const override { return true; }
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
bool HasReducedOps(Reducer* c) const override { return false; }
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
ExprPtr ReduceToSingleton(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ComplementExpr final : public UnaryExpr {
|
class ComplementExpr final : public UnaryExpr {
|
||||||
|
@ -433,6 +603,8 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
bool WillTransform(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr Fold(Val* v) const override;
|
ValPtr Fold(Val* v) const override;
|
||||||
|
@ -444,6 +616,8 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
bool WillTransform(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr Fold(Val* v) const override;
|
ValPtr Fold(Val* v) const override;
|
||||||
|
@ -455,6 +629,8 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
bool WillTransform(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr Fold(Val* v) const override;
|
ValPtr Fold(Val* v) const override;
|
||||||
|
@ -466,6 +642,8 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
bool WillTransform(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr Fold(Val* v) const override;
|
ValPtr Fold(Val* v) const override;
|
||||||
|
@ -490,6 +668,11 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
bool WillTransform(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ExprPtr BuildSub(const ExprPtr& op1, const ExprPtr& op2);
|
||||||
};
|
};
|
||||||
|
|
||||||
class AddToExpr final : public BinaryExpr {
|
class AddToExpr final : public BinaryExpr {
|
||||||
|
@ -499,6 +682,8 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
bool WillTransform(Reducer* c) const override { return true; }
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RemoveFromExpr final : public BinaryExpr {
|
class RemoveFromExpr final : public BinaryExpr {
|
||||||
|
@ -508,6 +693,8 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
bool WillTransform(Reducer* c) const override { return true; }
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SubExpr final : public BinaryExpr {
|
class SubExpr final : public BinaryExpr {
|
||||||
|
@ -516,6 +703,8 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
bool WillTransform(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TimesExpr final : public BinaryExpr {
|
class TimesExpr final : public BinaryExpr {
|
||||||
|
@ -525,6 +714,8 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
bool WillTransform(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DivideExpr final : public BinaryExpr {
|
class DivideExpr final : public BinaryExpr {
|
||||||
|
@ -533,6 +724,8 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
bool WillTransform(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr AddrFold(Val* v1, Val* v2) const override;
|
ValPtr AddrFold(Val* v1, Val* v2) const override;
|
||||||
|
@ -555,6 +748,13 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
bool WillTransform(Reducer* c) const override { return true; }
|
||||||
|
bool WillTransformInConditional(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool IsTrue(const ExprPtr& e) const;
|
||||||
|
bool IsFalse(const ExprPtr& e) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BitExpr final : public BinaryExpr {
|
class BitExpr final : public BinaryExpr {
|
||||||
|
@ -563,6 +763,8 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
bool WillTransform(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EqExpr final : public BinaryExpr {
|
class EqExpr final : public BinaryExpr {
|
||||||
|
@ -572,6 +774,8 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
bool WillTransform(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr Fold(Val* v1, Val* v2) const override;
|
ValPtr Fold(Val* v1, Val* v2) const override;
|
||||||
|
@ -584,6 +788,8 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
bool WillTransform(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CondExpr final : public Expr {
|
class CondExpr final : public Expr {
|
||||||
|
@ -603,6 +809,20 @@ public:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
ExprPtr Inline(Inliner* inl) override;
|
ExprPtr Inline(Inliner* inl) override;
|
||||||
|
|
||||||
|
bool WillTransform(Reducer* c) const override;
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
bool HasReducedOps(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
StmtPtr ReduceToSingletons(Reducer* c) override;
|
||||||
|
|
||||||
|
ExprPtr GetOp1() const override final { return op1; }
|
||||||
|
ExprPtr GetOp2() const override final { return op2; }
|
||||||
|
ExprPtr GetOp3() const override final { return op3; }
|
||||||
|
|
||||||
|
void SetOp1(ExprPtr _op) override final { op1 = std::move(_op); }
|
||||||
|
void SetOp2(ExprPtr _op) override final { op2 = std::move(_op); }
|
||||||
|
void SetOp3(ExprPtr _op) override final { op3 = std::move(_op); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void ExprDescribe(ODesc* d) const override;
|
void ExprDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
|
@ -620,6 +840,14 @@ public:
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
|
||||||
|
bool WillTransform(Reducer* c) const override;
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
bool HasReducedOps(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
|
// Reduce to simplifed LHS form, i.e., a reference to only a name.
|
||||||
|
StmtPtr ReduceToLHS(Reducer* c);
|
||||||
};
|
};
|
||||||
|
|
||||||
class AssignExpr : public BinaryExpr {
|
class AssignExpr : public BinaryExpr {
|
||||||
|
@ -628,7 +856,8 @@ public:
|
||||||
// yet still perform the assignment. Used for triggers.
|
// yet still perform the assignment. Used for triggers.
|
||||||
AssignExpr(ExprPtr op1, ExprPtr op2, bool is_init,
|
AssignExpr(ExprPtr op1, ExprPtr op2, bool is_init,
|
||||||
ValPtr val = nullptr,
|
ValPtr val = nullptr,
|
||||||
const AttributesPtr& attrs = nullptr);
|
const AttributesPtr& attrs = nullptr,
|
||||||
|
bool type_check = true);
|
||||||
|
|
||||||
ValPtr Eval(Frame* f) const override;
|
ValPtr Eval(Frame* f) const override;
|
||||||
void EvalIntoAggregate(const zeek::Type* t, Val* aggr, Frame* f) const override;
|
void EvalIntoAggregate(const zeek::Type* t, Val* aggr, Frame* f) const override;
|
||||||
|
@ -637,20 +866,29 @@ public:
|
||||||
ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override;
|
ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override;
|
||||||
bool IsPure() const override;
|
bool IsPure() const override;
|
||||||
|
|
||||||
void SetOp2(ExprPtr e)
|
|
||||||
{
|
|
||||||
op2 = std::move(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
|
||||||
|
bool HasNoSideEffects() const override;
|
||||||
|
bool WillTransform(Reducer* c) const override { return true; }
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
bool HasReducedOps(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
ExprPtr ReduceToSingleton(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
|
// Whether this is an assignment to a temporary.
|
||||||
|
bool IsTemp() const { return is_temp; }
|
||||||
|
void SetIsTemp() { is_temp = true; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool TypeCheck(const AttributesPtr& attrs = nullptr);
|
bool TypeCheck(const AttributesPtr& attrs = nullptr);
|
||||||
bool TypeCheckArithmetics(TypeTag bt1, TypeTag bt2);
|
bool TypeCheckArithmetics(TypeTag bt1, TypeTag bt2);
|
||||||
|
|
||||||
bool is_init;
|
bool is_init;
|
||||||
ValPtr val; // optional
|
ValPtr val; // optional
|
||||||
|
|
||||||
|
// Optimization-related:
|
||||||
|
bool is_temp = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IndexSliceAssignExpr final : public AssignExpr {
|
class IndexSliceAssignExpr final : public AssignExpr {
|
||||||
|
@ -688,6 +926,9 @@ public:
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
|
||||||
|
bool HasReducedOps(Reducer* c) const override;
|
||||||
|
StmtPtr ReduceToSingletons(Reducer* c) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr Fold(Val* v1, Val* v2) const override;
|
ValPtr Fold(Val* v1, Val* v2) const override;
|
||||||
|
|
||||||
|
@ -797,6 +1038,10 @@ public:
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
|
||||||
|
bool HasReducedOps(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
StmtPtr ReduceToSingletons(Reducer* c) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override;
|
ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override;
|
||||||
|
|
||||||
|
@ -823,6 +1068,10 @@ public:
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
|
||||||
|
bool HasReducedOps(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
StmtPtr ReduceToSingletons(Reducer* c) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override;
|
ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override;
|
||||||
|
|
||||||
|
@ -849,6 +1098,10 @@ public:
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
|
||||||
|
bool HasReducedOps(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
StmtPtr ReduceToSingletons(Reducer* c) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override;
|
ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override;
|
||||||
|
|
||||||
|
@ -867,6 +1120,8 @@ public:
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
|
||||||
|
bool HasReducedOps(Reducer* c) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override;
|
ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override;
|
||||||
|
|
||||||
|
@ -885,6 +1140,9 @@ public:
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
|
||||||
|
bool WillTransform(Reducer* c) const override { return true; }
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void ExprDescribe(ODesc* d) const override;
|
void ExprDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
|
@ -898,6 +1156,9 @@ public:
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
|
||||||
|
bool WillTransform(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr FoldSingleVal(Val* v, InternalTypeTag t) const;
|
ValPtr FoldSingleVal(Val* v, InternalTypeTag t) const;
|
||||||
ValPtr Fold(Val* v) const override;
|
ValPtr Fold(Val* v) const override;
|
||||||
|
@ -974,6 +1235,16 @@ public:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
ExprPtr Inline(Inliner* inl) override;
|
ExprPtr Inline(Inliner* inl) override;
|
||||||
|
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
bool HasReducedOps(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
|
ExprPtr GetOp1() const override final;
|
||||||
|
ExprPtr GetOp2() const override final;
|
||||||
|
|
||||||
|
void SetOp1(ExprPtr _op) override final;
|
||||||
|
void SetOp2(ExprPtr _op) override final;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void ExprDescribe(ODesc* d) const override;
|
void ExprDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
|
@ -988,6 +1259,8 @@ public:
|
||||||
// Optimization-related:
|
// Optimization-related:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
|
||||||
|
bool HasReducedOps(Reducer* c) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr Fold(Val* v1, Val* v2) const override;
|
ValPtr Fold(Val* v1, Val* v2) const override;
|
||||||
|
|
||||||
|
@ -1011,6 +1284,11 @@ public:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
ExprPtr Inline(Inliner* inl) override;
|
ExprPtr Inline(Inliner* inl) override;
|
||||||
|
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
bool HasReducedOps(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
StmtPtr ReduceToSingletons(Reducer* c) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void ExprDescribe(ODesc* d) const override;
|
void ExprDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
|
@ -1038,6 +1316,8 @@ public:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
ExprPtr Inline(Inliner* inl) override;
|
ExprPtr Inline(Inliner* inl) override;
|
||||||
|
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void ExprDescribe(ODesc* d) const override;
|
void ExprDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
|
@ -1048,30 +1328,8 @@ private:
|
||||||
std::string my_name;
|
std::string my_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EventExpr final : public Expr {
|
// This comes before EventExpr so that EventExpr::GetOp1 can return its
|
||||||
public:
|
// arguments as convertible to ExprPtr.
|
||||||
EventExpr(const char* name, ListExprPtr args);
|
|
||||||
|
|
||||||
const char* Name() const { return name.c_str(); }
|
|
||||||
ListExpr* Args() const { return args.get(); }
|
|
||||||
EventHandlerPtr Handler() const { return handler; }
|
|
||||||
|
|
||||||
ValPtr Eval(Frame* f) const override;
|
|
||||||
|
|
||||||
TraversalCode Traverse(TraversalCallback* cb) const override;
|
|
||||||
|
|
||||||
// Optimization-related:
|
|
||||||
ExprPtr Duplicate() override;
|
|
||||||
ExprPtr Inline(Inliner* inl) override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void ExprDescribe(ODesc* d) const override;
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
EventHandlerPtr handler;
|
|
||||||
ListExprPtr args;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ListExpr : public Expr {
|
class ListExpr : public Expr {
|
||||||
public:
|
public:
|
||||||
ListExpr();
|
ListExpr();
|
||||||
|
@ -1099,6 +1357,11 @@ public:
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
ExprPtr Inline(Inliner* inl) override;
|
ExprPtr Inline(Inliner* inl) override;
|
||||||
|
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
bool HasReducedOps(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
StmtPtr ReduceToSingletons(Reducer* c) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr AddSetInit(const zeek::Type* t, ValPtr aggr) const;
|
ValPtr AddSetInit(const zeek::Type* t, ValPtr aggr) const;
|
||||||
|
|
||||||
|
@ -1107,6 +1370,38 @@ protected:
|
||||||
ExprPList exprs;
|
ExprPList exprs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class EventExpr final : public Expr {
|
||||||
|
public:
|
||||||
|
EventExpr(const char* name, ListExprPtr args);
|
||||||
|
|
||||||
|
const char* Name() const { return name.c_str(); }
|
||||||
|
ListExpr* Args() const { return args.get(); }
|
||||||
|
EventHandlerPtr Handler() const { return handler; }
|
||||||
|
|
||||||
|
ValPtr Eval(Frame* f) const override;
|
||||||
|
|
||||||
|
TraversalCode Traverse(TraversalCallback* cb) const override;
|
||||||
|
|
||||||
|
// Optimization-related:
|
||||||
|
ExprPtr Duplicate() override;
|
||||||
|
ExprPtr Inline(Inliner* inl) override;
|
||||||
|
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
StmtPtr ReduceToSingletons(Reducer* c) override;
|
||||||
|
|
||||||
|
ExprPtr GetOp1() const override final { return args; }
|
||||||
|
void SetOp1(ExprPtr _op) override final
|
||||||
|
{ args = {NewRef{}, _op->AsListExpr()}; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void ExprDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
EventHandlerPtr handler;
|
||||||
|
ListExprPtr args;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class RecordAssignExpr final : public ListExpr {
|
class RecordAssignExpr final : public ListExpr {
|
||||||
public:
|
public:
|
||||||
|
@ -1155,6 +1450,9 @@ public:
|
||||||
|
|
||||||
ExprPtr Duplicate() override;
|
ExprPtr Duplicate() override;
|
||||||
|
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
TraversalCode Traverse(TraversalCallback* cb) const override;
|
TraversalCode Traverse(TraversalCallback* cb) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -1166,6 +1464,134 @@ protected:
|
||||||
StmtPtr body;
|
StmtPtr body;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A companion to AddToExpr that's for vector-append, instantiated during
|
||||||
|
// the reduction process.
|
||||||
|
class AppendToExpr : public BinaryExpr {
|
||||||
|
public:
|
||||||
|
AppendToExpr(ExprPtr op1, ExprPtr op2);
|
||||||
|
ValPtr Eval(Frame* f) const override;
|
||||||
|
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
|
ExprPtr Duplicate() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// An internal class for reduced form.
|
||||||
|
class IndexAssignExpr : public BinaryExpr {
|
||||||
|
public:
|
||||||
|
// "op1[op2] = op3", all reduced.
|
||||||
|
IndexAssignExpr(ExprPtr op1, ExprPtr op2, ExprPtr op3);
|
||||||
|
|
||||||
|
ValPtr Eval(Frame* f) const override;
|
||||||
|
|
||||||
|
ExprPtr Duplicate() override;
|
||||||
|
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
bool HasReducedOps(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
ExprPtr ReduceToSingleton(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
|
ExprPtr GetOp3() const override final { return op3; }
|
||||||
|
void SetOp3(ExprPtr _op) override final { op3 = _op; }
|
||||||
|
|
||||||
|
TraversalCode Traverse(TraversalCallback* cb) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void ExprDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
|
ExprPtr op3; // assignment RHS
|
||||||
|
};
|
||||||
|
|
||||||
|
// An internal class for reduced form.
|
||||||
|
class FieldLHSAssignExpr : public BinaryExpr {
|
||||||
|
public:
|
||||||
|
// "op1$field = RHS", where RHS is reduced with respect to
|
||||||
|
// ReduceToFieldAssignment().
|
||||||
|
FieldLHSAssignExpr(ExprPtr op1, ExprPtr op2, const char* field_name,
|
||||||
|
int field);
|
||||||
|
|
||||||
|
const char* FieldName() const { return field_name; }
|
||||||
|
int Field() const { return field; }
|
||||||
|
|
||||||
|
ValPtr Eval(Frame* f) const override;
|
||||||
|
|
||||||
|
ExprPtr Duplicate() override;
|
||||||
|
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
bool HasReducedOps(Reducer* c) const override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
ExprPtr ReduceToSingleton(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void ExprDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
|
const char* field_name;
|
||||||
|
int field;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Expression to explicitly capture conversion to an "any" type, rather
|
||||||
|
// than it occurring implicitly during script interpretation.
|
||||||
|
class CoerceToAnyExpr : public UnaryExpr {
|
||||||
|
public:
|
||||||
|
CoerceToAnyExpr(ExprPtr op);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ValPtr Fold(Val* v) const override;
|
||||||
|
|
||||||
|
ExprPtr Duplicate() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Same, but for conversion from an "any" type.
|
||||||
|
class CoerceFromAnyExpr : public UnaryExpr {
|
||||||
|
public:
|
||||||
|
CoerceFromAnyExpr(ExprPtr op, TypePtr to_type);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ValPtr Fold(Val* v) const override;
|
||||||
|
|
||||||
|
ExprPtr Duplicate() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Expression used to explicitly capture [a, b, c, ...] = x assignments.
|
||||||
|
class AnyIndexExpr : public UnaryExpr {
|
||||||
|
public:
|
||||||
|
AnyIndexExpr(ExprPtr op, int index);
|
||||||
|
|
||||||
|
int Index() const { return index; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ValPtr Fold(Val* v) const override;
|
||||||
|
|
||||||
|
void ExprDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
|
ExprPtr Duplicate() override;
|
||||||
|
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||||
|
|
||||||
|
int index;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Used internally for optimization, when a placeholder is needed.
|
||||||
|
class NopExpr : public Expr {
|
||||||
|
public:
|
||||||
|
explicit NopExpr() : Expr(EXPR_NOP) { }
|
||||||
|
|
||||||
|
ValPtr Eval(Frame* f) const override;
|
||||||
|
|
||||||
|
ExprPtr Duplicate() override;
|
||||||
|
|
||||||
|
TraversalCode Traverse(TraversalCallback* cb) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void ExprDescribe(ODesc* d) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Assigns v1[v2] = v3. Returns an error message, or nullptr on success.
|
||||||
|
// Factored out so that compiled code can call it as well as the interpreter.
|
||||||
|
extern const char* assign_to_index(ValPtr v1, ValPtr v2, ValPtr v3,
|
||||||
|
bool& iterators_invalidated);
|
||||||
|
|
||||||
|
|
||||||
inline Val* Expr::ExprVal() const
|
inline Val* Expr::ExprVal() const
|
||||||
{
|
{
|
||||||
|
|
76
src/Stmt.h
76
src/Stmt.h
|
@ -11,9 +11,12 @@
|
||||||
#include "zeek/ID.h"
|
#include "zeek/ID.h"
|
||||||
|
|
||||||
ZEEK_FORWARD_DECLARE_NAMESPACED(CompositeHash, zeek::detail);
|
ZEEK_FORWARD_DECLARE_NAMESPACED(CompositeHash, zeek::detail);
|
||||||
|
ZEEK_FORWARD_DECLARE_NAMESPACED(NameExpr, zeek::detail);
|
||||||
|
|
||||||
namespace zeek::detail {
|
namespace zeek::detail {
|
||||||
|
|
||||||
|
using NameExprPtr = IntrusivePtr<zeek::detail::NameExpr>;
|
||||||
|
|
||||||
class ExprListStmt : public Stmt {
|
class ExprListStmt : public Stmt {
|
||||||
public:
|
public:
|
||||||
const ListExpr* ExprList() const { return l.get(); }
|
const ListExpr* ExprList() const { return l.get(); }
|
||||||
|
@ -366,6 +369,11 @@ public:
|
||||||
StmtPtr Duplicate() override;
|
StmtPtr Duplicate() override;
|
||||||
void Inline(Inliner* inl) override;
|
void Inline(Inliner* inl) override;
|
||||||
|
|
||||||
|
// Idioms commonly used in reduction.
|
||||||
|
StmtList(StmtPtr s1, Stmt* s2);
|
||||||
|
StmtList(StmtPtr s1, StmtPtr s2);
|
||||||
|
StmtList(StmtPtr s1, StmtPtr s2, StmtPtr s3);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool IsPure() const override;
|
bool IsPure() const override;
|
||||||
|
|
||||||
|
@ -439,6 +447,74 @@ protected:
|
||||||
bool is_return;
|
bool is_return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Internal statement used for inlining. Executes a block and stops
|
||||||
|
// the propagation of any "return" inside the block. Generated in
|
||||||
|
// an already-reduced state.
|
||||||
|
class CatchReturnStmt : public Stmt {
|
||||||
|
public:
|
||||||
|
explicit CatchReturnStmt(StmtPtr block, NameExprPtr ret_var);
|
||||||
|
|
||||||
|
StmtPtr Block() const { return block; }
|
||||||
|
|
||||||
|
// This returns a bare pointer rather than a NameExprPtr only
|
||||||
|
// because we don't want to have to include Expr.h in this header.
|
||||||
|
const NameExpr* RetVar() const { return ret_var.get(); }
|
||||||
|
|
||||||
|
// The assignment statement this statement transformed into,
|
||||||
|
// or nil if it hasn't (the common case).
|
||||||
|
StmtPtr AssignStmt() const { return assign_stmt; }
|
||||||
|
|
||||||
|
ValPtr Exec(Frame* f, StmtFlowType& flow) const override;
|
||||||
|
|
||||||
|
bool IsPure() const override;
|
||||||
|
|
||||||
|
// Even though these objects are generated in reduced form, we still
|
||||||
|
// have a reduction method to support the subsequent optimizer pass.
|
||||||
|
StmtPtr DoReduce(Reducer* c) override;
|
||||||
|
|
||||||
|
// Note, no need for a NoFlowAfter() method because anything that
|
||||||
|
// has "NoFlowAfter" inside the body still gets caught and we
|
||||||
|
// continue afterwards.
|
||||||
|
|
||||||
|
StmtPtr Duplicate() override;
|
||||||
|
|
||||||
|
void StmtDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
|
TraversalCode Traverse(TraversalCallback* cb) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// The inlined function body.
|
||||||
|
StmtPtr block;
|
||||||
|
|
||||||
|
// Expression that holds the return value. Only used for compiling.
|
||||||
|
NameExprPtr ret_var;
|
||||||
|
|
||||||
|
// If this statement transformed into an assignment, that
|
||||||
|
// corresponding statement.
|
||||||
|
StmtPtr assign_stmt;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Statement that makes sure at run-time that an "any" type has the
|
||||||
|
// correct number of (list) entries to enable sub-assigning to it via
|
||||||
|
// statements like "[a, b, c] = x;". Generated in an already-reduced state.
|
||||||
|
class CheckAnyLenStmt : public ExprStmt {
|
||||||
|
public:
|
||||||
|
explicit CheckAnyLenStmt(ExprPtr e, int expected_len);
|
||||||
|
|
||||||
|
ValPtr Exec(Frame* f, StmtFlowType& flow) const override;
|
||||||
|
|
||||||
|
StmtPtr Duplicate() override;
|
||||||
|
|
||||||
|
bool IsReduced(Reducer* c) const override;
|
||||||
|
StmtPtr DoReduce(Reducer* c) override;
|
||||||
|
|
||||||
|
void StmtDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int expected_len;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace zeek::detail
|
} // namespace zeek::detail
|
||||||
|
|
||||||
using ExprListStmt [[deprecated("Remove in v4.1. Use zeek::detail::ExprListStmt instead.")]] = zeek::detail::ExprListStmt;
|
using ExprListStmt [[deprecated("Remove in v4.1. Use zeek::detail::ExprListStmt instead.")]] = zeek::detail::ExprListStmt;
|
||||||
|
|
|
@ -24,11 +24,13 @@ using ValPtr = IntrusivePtr<Val>;
|
||||||
|
|
||||||
namespace zeek::detail {
|
namespace zeek::detail {
|
||||||
|
|
||||||
class StmtList;
|
class ExprStmt;
|
||||||
class ForStmt;
|
class ForStmt;
|
||||||
class InitStmt;
|
class InitStmt;
|
||||||
class WhenStmt;
|
class ReturnStmt;
|
||||||
|
class StmtList;
|
||||||
class SwitchStmt;
|
class SwitchStmt;
|
||||||
|
class WhenStmt;
|
||||||
|
|
||||||
class EventExpr;
|
class EventExpr;
|
||||||
class ListExpr;
|
class ListExpr;
|
||||||
|
@ -37,6 +39,7 @@ using EventExprPtr = IntrusivePtr<EventExpr>;
|
||||||
using ListExprPtr = IntrusivePtr<ListExpr>;
|
using ListExprPtr = IntrusivePtr<ListExpr>;
|
||||||
|
|
||||||
class Inliner;
|
class Inliner;
|
||||||
|
class Reducer;
|
||||||
|
|
||||||
class Stmt;
|
class Stmt;
|
||||||
using StmtPtr = IntrusivePtr<Stmt>;
|
using StmtPtr = IntrusivePtr<Stmt>;
|
||||||
|
@ -50,6 +53,7 @@ public:
|
||||||
virtual ValPtr Exec(Frame* f, StmtFlowType& flow) const = 0;
|
virtual ValPtr Exec(Frame* f, StmtFlowType& flow) const = 0;
|
||||||
|
|
||||||
Stmt* Ref() { zeek::Ref(this); return this; }
|
Stmt* Ref() { zeek::Ref(this); return this; }
|
||||||
|
StmtPtr ThisPtr() { return {NewRef{}, this}; }
|
||||||
|
|
||||||
bool SetLocationInfo(const Location* loc) override
|
bool SetLocationInfo(const Location* loc) override
|
||||||
{ return Stmt::SetLocationInfo(loc, loc); }
|
{ return Stmt::SetLocationInfo(loc, loc); }
|
||||||
|
@ -64,7 +68,9 @@ public:
|
||||||
ForStmt* AsForStmt();
|
ForStmt* AsForStmt();
|
||||||
const ForStmt* AsForStmt() const;
|
const ForStmt* AsForStmt() const;
|
||||||
|
|
||||||
|
const ExprStmt* AsExprStmt() const;
|
||||||
const InitStmt* AsInitStmt() const;
|
const InitStmt* AsInitStmt() const;
|
||||||
|
const ReturnStmt* AsReturnStmt() const;
|
||||||
const WhenStmt* AsWhenStmt() const;
|
const WhenStmt* AsWhenStmt() const;
|
||||||
const SwitchStmt* AsSwitchStmt() const;
|
const SwitchStmt* AsSwitchStmt() const;
|
||||||
|
|
||||||
|
@ -81,12 +87,37 @@ public:
|
||||||
|
|
||||||
virtual TraversalCode Traverse(TraversalCallback* cb) const = 0;
|
virtual TraversalCode Traverse(TraversalCallback* cb) const = 0;
|
||||||
|
|
||||||
// Returns a duplicate of the statement.
|
// Returns a duplicate of the statement so that modifications
|
||||||
|
// can be made to statements from inlining function bodies - or
|
||||||
|
// to the originals - without affecting other instances.
|
||||||
|
//
|
||||||
|
// It's tempting to think that there are some statements that
|
||||||
|
// are safe to share across multiple functions and could just
|
||||||
|
// return references to themselves - but since we associate
|
||||||
|
// information for script optimization with individual statements
|
||||||
|
// nodes, even these need to be duplicated.
|
||||||
virtual StmtPtr Duplicate() = 0;
|
virtual StmtPtr Duplicate() = 0;
|
||||||
|
|
||||||
// Recursively traverses the AST to inline eligible function calls.
|
// Recursively traverses the AST to inline eligible function calls.
|
||||||
virtual void Inline(Inliner* inl) { }
|
virtual void Inline(Inliner* inl) { }
|
||||||
|
|
||||||
|
// True if the statement is in reduced form.
|
||||||
|
virtual bool IsReduced(Reducer* c) const;
|
||||||
|
|
||||||
|
// Returns a reduced version of the statement, as managed by
|
||||||
|
// the given Reducer.
|
||||||
|
StmtPtr Reduce(Reducer* c);
|
||||||
|
virtual StmtPtr DoReduce(Reducer* c) { return ThisPtr(); }
|
||||||
|
|
||||||
|
// True if there's definitely no control flow past the statement.
|
||||||
|
// The argument governs whether to ignore "break" statements, given
|
||||||
|
// they mean two different things depending on whether they're in
|
||||||
|
// a loop or a switch. Also, if we want to know whether flow reaches
|
||||||
|
// the *end* of a loop, then we also want to ignore break's, as
|
||||||
|
// in that case, they do lead to flow reaching the end.
|
||||||
|
virtual bool NoFlowAfter(bool ignore_break) const
|
||||||
|
{ return false; }
|
||||||
|
|
||||||
// Access to the original statement from which this one is derived,
|
// Access to the original statement from which this one is derived,
|
||||||
// or this one if we don't have an original. Returns a bare pointer
|
// or this one if we don't have an original. Returns a bare pointer
|
||||||
// rather than a StmtPtr to emphasize that the access is read-only.
|
// rather than a StmtPtr to emphasize that the access is read-only.
|
||||||
|
@ -124,6 +155,11 @@ public:
|
||||||
protected:
|
protected:
|
||||||
explicit Stmt(StmtTag arg_tag);
|
explicit Stmt(StmtTag arg_tag);
|
||||||
|
|
||||||
|
// Helper function called after reductions to perform canonical
|
||||||
|
// actions. Takes a bare pointer for new_me because usually
|
||||||
|
// it's been newly new'd, so this keeps down code clutter.
|
||||||
|
StmtPtr TransformMe(Stmt* new_me, Reducer* c);
|
||||||
|
|
||||||
void AddTag(ODesc* d) const;
|
void AddTag(ODesc* d) const;
|
||||||
virtual void StmtDescribe(ODesc* d) const;
|
virtual void StmtDescribe(ODesc* d) const;
|
||||||
void DescribeDone(ODesc* d) const;
|
void DescribeDone(ODesc* d) const;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
186
src/script_opt/Reduce.h
Normal file
186
src/script_opt/Reduce.h
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "zeek/IntrusivePtr.h"
|
||||||
|
|
||||||
|
namespace zeek::detail {
|
||||||
|
|
||||||
|
class Expr;
|
||||||
|
class TempVar;
|
||||||
|
class ProfileFunc;
|
||||||
|
|
||||||
|
class Reducer {
|
||||||
|
public:
|
||||||
|
Reducer(Scope* s);
|
||||||
|
~Reducer();
|
||||||
|
|
||||||
|
StmtPtr Reduce(StmtPtr s)
|
||||||
|
{
|
||||||
|
return s->Reduce(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExprPtr GenTemporaryExpr(const TypePtr& t, ExprPtr rhs);
|
||||||
|
|
||||||
|
NameExpr* UpdateName(NameExpr* n);
|
||||||
|
bool NameIsReduced(const NameExpr* n) const;
|
||||||
|
|
||||||
|
void UpdateIDs(IDPList* ids);
|
||||||
|
bool IDsAreReduced(const IDPList* ids) const;
|
||||||
|
|
||||||
|
void UpdateIDs(std::vector<IDPtr>& ids);
|
||||||
|
bool IDsAreReduced(const std::vector<IDPtr>& ids) const;
|
||||||
|
|
||||||
|
IDPtr UpdateID(IDPtr id);
|
||||||
|
bool ID_IsReduced(const IDPtr& id) const
|
||||||
|
{ return ID_IsReduced(id.get()); }
|
||||||
|
bool ID_IsReduced(const ID* id) const;
|
||||||
|
|
||||||
|
// This is called *prior* to pushing a new inline block, in
|
||||||
|
// order to generate the equivalent of function parameters.
|
||||||
|
NameExprPtr GenInlineBlockName(IDPtr id);
|
||||||
|
|
||||||
|
int NumNewLocals() const { return new_locals.size(); }
|
||||||
|
|
||||||
|
// Returns the name of a temporary for holding the return
|
||||||
|
// value of the block, or nil if the type indicates there's
|
||||||
|
// o return value.
|
||||||
|
NameExprPtr PushInlineBlock(TypePtr type);
|
||||||
|
void PopInlineBlock();
|
||||||
|
|
||||||
|
// Whether it's okay to split a statement into two copies for if-else
|
||||||
|
// expansion. We only allow this to a particular depth because
|
||||||
|
// beyond that a function body can get too large to analyze.
|
||||||
|
bool BifurcationOkay() const { return bifurcation_level <= 12; }
|
||||||
|
int BifurcationLevel() const { return bifurcation_level; }
|
||||||
|
|
||||||
|
void PushBifurcation() { ++bifurcation_level; }
|
||||||
|
void PopBifurcation() { --bifurcation_level; }
|
||||||
|
|
||||||
|
int NumTemps() const { return temps.length(); }
|
||||||
|
|
||||||
|
// True if this name already reflects the replacement.
|
||||||
|
bool IsNewLocal(const NameExpr* n) const
|
||||||
|
{ return IsNewLocal(n->Id()); }
|
||||||
|
bool IsNewLocal(const ID* id) const;
|
||||||
|
|
||||||
|
bool IsTemporary(const ID* id) const
|
||||||
|
{ return FindTemporary(id) != nullptr; }
|
||||||
|
|
||||||
|
// This is a stub for now, since it's not relevant for AST
|
||||||
|
// reduction by itself. However, many of the Reduce methods
|
||||||
|
// ultimately will call this predicate to control how they
|
||||||
|
// function during the second traversal used to optimize
|
||||||
|
// the reduced form, so we provide the hook now.
|
||||||
|
bool Optimizing() const { return false; }
|
||||||
|
|
||||||
|
// A stub for now, but ultimately a predicate that indicates whether
|
||||||
|
// a given reduction pass is being made to prune unused statements.
|
||||||
|
bool IsPruning() const { return false; }
|
||||||
|
|
||||||
|
// A stub for now, ultimately a predicate that returns true if
|
||||||
|
// the given statement should be removed due to AST optimization.
|
||||||
|
bool ShouldOmitStmt(const StmtPtr& s) const { return false; }
|
||||||
|
|
||||||
|
// A stub for now, ultimately provides a replacement for the
|
||||||
|
// given statement due to AST optimization, or nil if there's
|
||||||
|
// no replacement.
|
||||||
|
StmtPtr ReplacementStmt(const StmtPtr& s) const { return nullptr; }
|
||||||
|
|
||||||
|
// NOT YET IMPLEMENTED, SO CURRENTLY A STUB:
|
||||||
|
// Given the LHS and RHS of an assignment, returns true
|
||||||
|
// if the RHS is a common subexpression (meaning that the
|
||||||
|
// current assignment statement should be deleted). In
|
||||||
|
// that case, has the side effect of associating an alias
|
||||||
|
// for the LHS with the temporary holding the equivalent RHS.
|
||||||
|
//
|
||||||
|
// Assumes reduction (including alias propagation) has
|
||||||
|
// already been applied.
|
||||||
|
bool IsCSE(const AssignExpr* a, const NameExpr* lhs, const Expr* rhs)
|
||||||
|
{ return false; }
|
||||||
|
|
||||||
|
// Given an lhs=rhs statement followed by succ_stmt, returns
|
||||||
|
// a (new) merge of the two if they're of the form tmp=rhs, var=tmp;
|
||||||
|
// otherwise, nil.
|
||||||
|
Stmt* MergeStmts(const NameExpr* lhs, ExprPtr rhs, Stmt* succ_stmt);
|
||||||
|
|
||||||
|
// The following two methods will, in the future, update expressions
|
||||||
|
// with optimized versions. They are distinct because the first
|
||||||
|
// one (meant for calls in a Stmt reduction context) will also Reduce
|
||||||
|
// the expression, whereas the second one (meant for calls in an Expr
|
||||||
|
// context) does not, to avoid circularity.
|
||||||
|
//
|
||||||
|
// For now, they are stubs.
|
||||||
|
//
|
||||||
|
// These two are used for use in optimizing expressions that appear in
|
||||||
|
// a Stmt context.
|
||||||
|
ExprPtr OptExpr(Expr* e) { return {NewRef{}, e}; }
|
||||||
|
ExprPtr OptExpr(ExprPtr e) { return e; }
|
||||||
|
// This one for expressions appearing in an Expr context.
|
||||||
|
ExprPtr UpdateExpr(ExprPtr e) { return e; }
|
||||||
|
|
||||||
|
const Scope* FuncScope() const { return scope; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool SameVal(const Val* v1, const Val* v2) const;
|
||||||
|
|
||||||
|
IDPtr GenTemporary(const TypePtr& t, ExprPtr rhs);
|
||||||
|
TempVar* FindTemporary(const ID* id) const;
|
||||||
|
|
||||||
|
// Retrieve the identifier corresponding to the new local for
|
||||||
|
// the given expression. Creates the local if necessary.
|
||||||
|
IDPtr FindNewLocal(ID* id);
|
||||||
|
IDPtr FindNewLocal(const NameExpr* n)
|
||||||
|
{ return FindNewLocal(n->Id()); }
|
||||||
|
|
||||||
|
// Generate a new local to use in lieu of the original (seen
|
||||||
|
// in an inlined block). The difference is that the new
|
||||||
|
// version has a distinct name and has a correct frame offset
|
||||||
|
// for the current function.
|
||||||
|
IDPtr GenLocal(ID* orig);
|
||||||
|
|
||||||
|
// Track that we're replacing instances of "orig" with a new
|
||||||
|
// expression. This allows us to locate the RDs associated
|
||||||
|
// with "orig" in the context of the new expression, without
|
||||||
|
// requiring an additional RD propagation pass.
|
||||||
|
void TrackExprReplacement(const Expr* orig, const Expr* e);
|
||||||
|
|
||||||
|
Scope* scope;
|
||||||
|
PList<TempVar> temps;
|
||||||
|
|
||||||
|
// Temps for which we've processed their associated expression
|
||||||
|
// (and they didn't wind up being aliases).
|
||||||
|
PList<TempVar> expr_temps;
|
||||||
|
|
||||||
|
// Let's us go from an identifier to an associated temporary
|
||||||
|
// variable, if it corresponds to one.
|
||||||
|
std::unordered_map<const ID*, TempVar*> ids_to_temps;
|
||||||
|
|
||||||
|
std::unordered_set<ID*> new_locals;
|
||||||
|
std::unordered_map<const ID*, IDPtr> orig_to_new_locals;
|
||||||
|
|
||||||
|
// Tracks whether we're inside an inline block, and if so then
|
||||||
|
// how deeply.
|
||||||
|
int inline_block_level = 0;
|
||||||
|
|
||||||
|
// Tracks how deeply we are in "bifurcation", i.e., duplicating
|
||||||
|
// code for if-else cascades. We need to cap this at a certain
|
||||||
|
// depth or else we can get functions whose size blows up
|
||||||
|
// exponentially.
|
||||||
|
int bifurcation_level = 0;
|
||||||
|
|
||||||
|
// For a new expression we've created, map it to the expression
|
||||||
|
// it's replacing. This allows us to locate the RDs associated
|
||||||
|
// with the usage.
|
||||||
|
std::unordered_map<const Expr*, const Expr*> new_expr_to_orig;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Used for debugging, to communicate which expression wasn't
|
||||||
|
// reduced when we expected them all to be.
|
||||||
|
extern const Expr* non_reduced_perp;
|
||||||
|
extern bool checking_reduction;
|
||||||
|
|
||||||
|
// Used to report a non-reduced expression.
|
||||||
|
extern bool NonReduced(const Expr* perp);
|
||||||
|
|
||||||
|
} // zeek::detail
|
|
@ -1,7 +1,7 @@
|
||||||
// See the file "COPYING" in the main distribution directory for copyright.
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
#include "TempVar.h"
|
#include "zeek/script_opt/TempVar.h"
|
||||||
#include "Reporter.h"
|
#include "zeek/Reporter.h"
|
||||||
|
|
||||||
|
|
||||||
namespace zeek::detail {
|
namespace zeek::detail {
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
// Class for managing temporary variables created during statement reduction
|
// Class for managing temporary variables created during statement reduction
|
||||||
// for compilation.
|
// for compilation.
|
||||||
|
|
||||||
#include "ID.h"
|
#include "zeek/ID.h"
|
||||||
#include "Expr.h"
|
#include "zeek/Expr.h"
|
||||||
|
|
||||||
|
|
||||||
namespace zeek::detail {
|
namespace zeek::detail {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue