diff --git a/CHANGES b/CHANGES index 3b30918f12..8bac101433 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,16 @@ +4.1.0-dev.51 | 2021-01-07 17:02:28 -0800 + + * Virtualize Obj::GetLocationInfo() (Vern Paxson, Corelight) + + Cleaner approach for localizing errors associated with duplicated ASTs. + + * Add support for inlining of Zeek script functions (Vern Paxson, Corelight) + + * Add support for duplicating Zeek ASTS (Vern Paxson, Corelight) + + * Update COPYING to 2021 (Johanna Amann, Corelight) + 4.1.0-dev.27 | 2021-01-06 20:42:35 -0800 * GH-1347: Update cmake module to fix ZeekPluginDynamic's find_package(CAF) (Jon Siwek, Corelight) diff --git a/VERSION b/VERSION index 4f59ac3edd..a73fc06403 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.1.0-dev.27 +4.1.0-dev.51 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 53591ca348..ca7736485f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -322,6 +322,12 @@ set(MAIN_SRCS plugin/Manager.cc plugin/Plugin.cc + script_opt/Expr.cc + script_opt/Inline.cc + script_opt/ProfileFunc.cc + script_opt/ScriptOpt.cc + script_opt/Stmt.cc + nb_dns.c digest.h ) diff --git a/src/Expr.cc b/src/Expr.cc index b11f382a33..c9cbd10e34 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -39,7 +39,10 @@ const char* expr_name(BroExprTag t) "$=", "in", "<<>>", "()", "function()", "event", "schedule", "coerce", "record_coerce", "table_coerce", "vector_coerce", - "sizeof", "cast", "is", "[:]=" + "sizeof", "cast", "is", "[:]=", + "inline()", + "nop", + }; if ( int(t) >= NUM_EXPRS ) @@ -74,6 +77,12 @@ ListExpr* Expr::AsListExpr() return (ListExpr*) this; } +ListExprPtr Expr::AsListExprPtr() + { + CHECK_TAG(tag, EXPR_LIST, "ExprVal::AsListExpr", expr_name) + return {NewRef{}, (ListExpr*) this}; + } + const NameExpr* Expr::AsNameExpr() const { CHECK_TAG(tag, EXPR_NAME, "ExprVal::AsNameExpr", expr_name) @@ -86,6 +95,18 @@ NameExpr* Expr::AsNameExpr() return (NameExpr*) this; } +const ConstExpr* Expr::AsConstExpr() const + { + CHECK_TAG(tag, EXPR_CONST, "ExprVal::AsConstExpr", expr_name) + return (const ConstExpr*) this; + } + +const CallExpr* Expr::AsCallExpr() const + { + CHECK_TAG(tag, EXPR_CALL, "ExprVal::AsCallExpr", expr_name) + return (const CallExpr*) this; + } + const AssignExpr* Expr::AsAssignExpr() const { CHECK_TAG(tag, EXPR_ASSIGN, "ExprVal::AsAssignExpr", expr_name) @@ -110,6 +131,18 @@ IndexExpr* Expr::AsIndexExpr() return (IndexExpr*) this; } +const EventExpr* Expr::AsEventExpr() const + { + CHECK_TAG(tag, EXPR_EVENT, "ExprVal::AsEventExpr", expr_name) + return (const EventExpr*) this; + } + +EventExprPtr Expr::AsEventExprPtr() + { + CHECK_TAG(tag, EXPR_EVENT, "ExprVal::AsEventExpr", expr_name) + return {NewRef{}, (EventExpr*) this}; + } + bool Expr::CanAdd() const { return false; @@ -258,8 +291,9 @@ void Expr::RuntimeErrorWithCallStack(const std::string& msg) const ODesc d; d.SetShort(); Describe(&d); - reporter->RuntimeError(GetLocationInfo(), "%s, expression: %s, call stack: %s", - msg.data(), d.Description(), rcs.data()); + reporter->RuntimeError(GetLocationInfo(), + "%s, expression: %s, call stack: %s", + msg.data(), d.Description(), rcs.data()); } } @@ -928,12 +962,23 @@ void BinaryExpr::PromoteType(TypeTag t, bool is_vector) { PromoteOps(t); - if ( is_vector) + if ( is_vector ) SetType(make_intrusive(base_type(t))); else SetType(base_type(t)); } +void BinaryExpr::PromoteForInterval(ExprPtr& op) + { + if ( is_vector(op1) || is_vector(op2) ) + SetType(make_intrusive(base_type(TYPE_INTERVAL))); + else + SetType(base_type(TYPE_INTERVAL)); + + if ( op->GetType()->Tag() != TYPE_DOUBLE ) + op = make_intrusive(op, TYPE_DOUBLE); + } + CloneExpr::CloneExpr(ExprPtr arg_op) : UnaryExpr(EXPR_CLONE, std::move(arg_op)) { @@ -1416,12 +1461,7 @@ TimesExpr::TimesExpr(ExprPtr arg_op1, ExprPtr arg_op2) if ( bt1 == TYPE_INTERVAL || bt2 == TYPE_INTERVAL ) { if ( IsArithmetic(bt1) || IsArithmetic(bt2) ) - { - if ( is_vector(op1) && is_vector(op2) ) - SetType(make_intrusive(base_type(TYPE_INTERVAL))); - else - PromoteType(TYPE_INTERVAL, is_vector(op1) || is_vector(op2) ); - } + PromoteForInterval(IsArithmetic(bt1) ? op1 : op2); else ExprError("multiplication with interval requires arithmetic operand"); } @@ -1457,12 +1497,7 @@ DivideExpr::DivideExpr(ExprPtr arg_op1, ExprPtr arg_op2) if ( bt1 == TYPE_INTERVAL || bt2 == TYPE_INTERVAL ) { if ( IsArithmetic(bt1) || IsArithmetic(bt2) ) - { - if ( is_vector(op1) && is_vector(op2) ) - SetType(make_intrusive(base_type(TYPE_INTERVAL))); - else - PromoteType(TYPE_INTERVAL, is_vector(op1) || is_vector(op2)); - } + PromoteForInterval(IsArithmetic(bt1) ? op1 : op2); else if ( bt1 == TYPE_INTERVAL && bt2 == TYPE_INTERVAL ) { if ( is_vector(op1) || is_vector(op2) ) @@ -3186,7 +3221,8 @@ TraversalCode RecordConstructorExpr::Traverse(TraversalCallback* cb) const TableConstructorExpr::TableConstructorExpr(ListExprPtr constructor_list, std::unique_ptr> arg_attrs, - TypePtr arg_type) + TypePtr arg_type, + AttributesPtr arg_attrs2) : UnaryExpr(EXPR_TABLE_CONSTRUCTOR, std::move(constructor_list)) { if ( IsError() ) @@ -3222,6 +3258,8 @@ TableConstructorExpr::TableConstructorExpr(ListExprPtr constructor_list, if ( arg_attrs ) attrs = make_intrusive(std::move(*arg_attrs), type, false, false); + else + attrs = arg_attrs2; const auto& indices = type->AsTableType()->GetIndices()->GetTypes(); const ExprPList& cle = op->AsListExpr()->Exprs(); @@ -3321,7 +3359,8 @@ void TableConstructorExpr::ExprDescribe(ODesc* d) const SetConstructorExpr::SetConstructorExpr(ListExprPtr constructor_list, std::unique_ptr> arg_attrs, - TypePtr arg_type) + TypePtr arg_type, + AttributesPtr arg_attrs2) : UnaryExpr(EXPR_SET_CONSTRUCTOR, std::move(constructor_list)) { if ( IsError() ) @@ -3354,6 +3393,8 @@ SetConstructorExpr::SetConstructorExpr(ListExprPtr constructor_list, if ( arg_attrs ) attrs = make_intrusive(std::move(*arg_attrs), type, false, false); + else + attrs = arg_attrs2; const auto& indices = type->AsTableType()->GetIndices()->GetTypes(); ExprPList& cle = op->AsListExpr()->Exprs(); diff --git a/src/Expr.h b/src/Expr.h index 87aa2e0dd6..396b1107a4 100644 --- a/src/Expr.h +++ b/src/Expr.h @@ -10,6 +10,7 @@ #include "zeek/ZeekList.h" #include "zeek/IntrusivePtr.h" +#include "zeek/StmtBase.h" #include "zeek/Timer.h" #include "zeek/Type.h" #include "zeek/EventHandler.h" @@ -66,13 +67,17 @@ enum BroExprTag : int { EXPR_CAST, EXPR_IS, EXPR_INDEX_SLICE_ASSIGN, -#define NUM_EXPRS (int(EXPR_INDEX_SLICE_ASSIGN) + 1) + EXPR_INLINE, + EXPR_NOP, + +#define NUM_EXPRS (int(EXPR_NOP) + 1) }; extern const char* expr_name(BroExprTag t); class ListExpr; class NameExpr; +class ConstExpr; class IndexExpr; class AssignExpr; class CallExpr; @@ -82,7 +87,7 @@ class Stmt; class Expr; using ExprPtr = IntrusivePtr; using EventExprPtr = IntrusivePtr; -using ListExprPtr = IntrusivePtr; +using StmtPtr = IntrusivePtr; class Expr : public Obj { public: @@ -99,6 +104,7 @@ public: BroExprTag Tag() const { return tag; } Expr* Ref() { zeek::Ref(this); return this; } + ExprPtr ThisPtr() { return {NewRef{}, this}; } // Evaluates the expression and returns a corresponding Val*, // or nil if the expression's value isn't fixed. @@ -171,22 +177,65 @@ public: void MarkParen() { paren = true; } bool IsParen() const { return paren; } - const ListExpr* AsListExpr() const; - ListExpr* AsListExpr(); +#define ZEEK_EXPR_ACCESSOR_DECLS(ctype) \ + const ctype* As ## ctype () const; \ + ctype* As ## ctype (); \ + IntrusivePtr As ## ctype ## Ptr (); - const NameExpr* AsNameExpr() const; - NameExpr* AsNameExpr(); - - const AssignExpr* AsAssignExpr() const; - AssignExpr* AsAssignExpr(); - - const IndexExpr* AsIndexExpr() const; - IndexExpr* AsIndexExpr(); + ZEEK_EXPR_ACCESSOR_DECLS(ListExpr) + ZEEK_EXPR_ACCESSOR_DECLS(NameExpr) + ZEEK_EXPR_ACCESSOR_DECLS(ConstExpr) + 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; virtual TraversalCode Traverse(TraversalCallback* cb) const = 0; + // Returns a duplicate of the expression. + virtual ExprPtr Duplicate() = 0; + + // Recursively traverses the AST to inline eligible function calls. + virtual ExprPtr Inline(Inliner* inl) { return ThisPtr(); } + + // 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 + // rather than an ExprPtr to emphasize that the access is read-only. + const Expr* Original() const + { return original ? original->Original() : this; } + + // Designate the given Expr node as the original for this one. + void SetOriginal(ExprPtr _orig) + { + if ( ! original ) + original = std::move(_orig); + } + + // A convenience function for taking a newly-created Expr, + // making it point to us as the successor, and returning it. + // + // Takes an Expr* rather than a ExprPtr to de-clutter the calling + // code, which is always passing in "new XyzExpr(...)". This + // call, as a convenient side effect, transforms that bare pointer + // into an ExprPtr. + virtual ExprPtr SetSucc(Expr* succ) + { + succ->SetOriginal(ThisPtr()); + if ( IsParen() ) + succ->MarkParen(); + return {AdoptRef{}, succ}; + } + + const detail::Location* GetLocationInfo() const override + { + if ( original ) + return original->GetLocationInfo(); + else + return Obj::GetLocationInfo(); + } + protected: Expr() = default; explicit Expr(BroExprTag arg_tag); @@ -211,6 +260,11 @@ protected: BroExprTag tag; TypePtr type; bool paren; + + // The original expression from which this statement was + // derived, if any. Used as an aid for generating meaningful + // and correctly-localized error messages. + ExprPtr original = nullptr; }; class NameExpr final : public Expr { @@ -226,6 +280,9 @@ public: TraversalCode Traverse(TraversalCallback* cb) const override; + // Optimization-related: + ExprPtr Duplicate() override; + protected: void ExprDescribe(ODesc* d) const override; @@ -238,11 +295,15 @@ public: explicit ConstExpr(ValPtr val); Val* Value() const { return val.get(); } + ValPtr ValuePtr() const { return val; } ValPtr Eval(Frame* f) const override; TraversalCode Traverse(TraversalCallback* cb) const override; + // Optimization-related: + ExprPtr Duplicate() override; + protected: void ExprDescribe(ODesc* d) const override; ValPtr val; @@ -261,6 +322,9 @@ public: TraversalCode Traverse(TraversalCallback* cb) const override; + // Optimization-related: + ExprPtr Inline(Inliner* inl) override; + protected: UnaryExpr(BroExprTag arg_tag, ExprPtr arg_op); @@ -286,6 +350,9 @@ public: TraversalCode Traverse(TraversalCallback* cb) const override; + // Optimization-related: + ExprPtr Inline(Inliner* inl) override; + protected: BinaryExpr(BroExprTag arg_tag, ExprPtr arg_op1, ExprPtr arg_op2) @@ -325,6 +392,11 @@ protected: // operands and also set expression's type). void PromoteType(TypeTag t, bool is_vector); + // Promote one of the operands to be "double" (if not already), + // to make it suitable for combining with the other "interval" + // operand, yielding an "interval" type. + void PromoteForInterval(ExprPtr& op); + void ExprDescribe(ODesc* d) const override; ExprPtr op1; @@ -336,6 +408,9 @@ public: explicit CloneExpr(ExprPtr op); ValPtr Eval(Frame* f) const override; + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr Fold(Val* v) const override; }; @@ -347,12 +422,18 @@ public: ValPtr Eval(Frame* f) const override; ValPtr DoSingleEval(Frame* f, Val* v) const; bool IsPure() const override; + + // Optimization-related: + ExprPtr Duplicate() override; }; class ComplementExpr final : public UnaryExpr { public: explicit ComplementExpr(ExprPtr op); + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr Fold(Val* v) const override; }; @@ -361,6 +442,9 @@ class NotExpr final : public UnaryExpr { public: explicit NotExpr(ExprPtr op); + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr Fold(Val* v) const override; }; @@ -369,6 +453,9 @@ class PosExpr final : public UnaryExpr { public: explicit PosExpr(ExprPtr op); + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr Fold(Val* v) const override; }; @@ -377,6 +464,9 @@ class NegExpr final : public UnaryExpr { public: explicit NegExpr(ExprPtr op); + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr Fold(Val* v) const override; }; @@ -386,6 +476,9 @@ public: explicit SizeExpr(ExprPtr op); ValPtr Eval(Frame* f) const override; + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr Fold(Val* v) const override; }; @@ -394,35 +487,53 @@ class AddExpr final : public BinaryExpr { public: AddExpr(ExprPtr op1, ExprPtr op2); void Canonicize() override; + + // Optimization-related: + ExprPtr Duplicate() override; }; class AddToExpr final : public BinaryExpr { public: AddToExpr(ExprPtr op1, ExprPtr op2); ValPtr Eval(Frame* f) const override; + + // Optimization-related: + ExprPtr Duplicate() override; }; class RemoveFromExpr final : public BinaryExpr { public: RemoveFromExpr(ExprPtr op1, ExprPtr op2); ValPtr Eval(Frame* f) const override; + + // Optimization-related: + ExprPtr Duplicate() override; }; class SubExpr final : public BinaryExpr { public: SubExpr(ExprPtr op1, ExprPtr op2); + + // Optimization-related: + ExprPtr Duplicate() override; }; class TimesExpr final : public BinaryExpr { public: TimesExpr(ExprPtr op1, ExprPtr op2); void Canonicize() override; + + // Optimization-related: + ExprPtr Duplicate() override; }; class DivideExpr final : public BinaryExpr { public: DivideExpr(ExprPtr op1, ExprPtr op2); + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr AddrFold(Val* v1, Val* v2) const override; }; @@ -430,6 +541,9 @@ protected: class ModExpr final : public BinaryExpr { public: ModExpr(ExprPtr op1, ExprPtr op2); + + // Optimization-related: + ExprPtr Duplicate() override; }; class BoolExpr final : public BinaryExpr { @@ -438,11 +552,17 @@ public: ValPtr Eval(Frame* f) const override; ValPtr DoSingleEval(Frame* f, ValPtr v1, Expr* op2) const; + + // Optimization-related: + ExprPtr Duplicate() override; }; class BitExpr final : public BinaryExpr { public: BitExpr(BroExprTag tag, ExprPtr op1, ExprPtr op2); + + // Optimization-related: + ExprPtr Duplicate() override; }; class EqExpr final : public BinaryExpr { @@ -450,6 +570,9 @@ public: EqExpr(BroExprTag tag, ExprPtr op1, ExprPtr op2); void Canonicize() override; + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr Fold(Val* v1, Val* v2) const override; }; @@ -458,6 +581,9 @@ class RelExpr final : public BinaryExpr { public: RelExpr(BroExprTag tag, ExprPtr op1, ExprPtr op2); void Canonicize() override; + + // Optimization-related: + ExprPtr Duplicate() override; }; class CondExpr final : public Expr { @@ -473,6 +599,10 @@ public: TraversalCode Traverse(TraversalCallback* cb) const override; + // Optimization-related: + ExprPtr Duplicate() override; + ExprPtr Inline(Inliner* inl) override; + protected: void ExprDescribe(ODesc* d) const override; @@ -487,6 +617,9 @@ public: void Assign(Frame* f, ValPtr v) override; ExprPtr MakeLvalue() override; + + // Optimization-related: + ExprPtr Duplicate() override; }; class AssignExpr : public BinaryExpr { @@ -509,6 +642,9 @@ public: op2 = std::move(e); } + // Optimization-related: + ExprPtr Duplicate() override; + protected: bool TypeCheck(const AttributesPtr& attrs = nullptr); bool TypeCheckArithmetics(TypeTag bt1, TypeTag bt2); @@ -522,6 +658,9 @@ public: IndexSliceAssignExpr(ExprPtr op1, ExprPtr op2, bool is_init); ValPtr Eval(Frame* f) const override; + + // Optimization-related: + ExprPtr Duplicate() override; }; class IndexExpr : public BinaryExpr { @@ -546,6 +685,9 @@ public: bool IsSlice() const { return is_slice; } + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr Fold(Val* v1, Val* v2) const override; @@ -585,6 +727,9 @@ public: return v; } + + // Optimization-related: + ExprPtr Duplicate() override; }; class FieldExpr final : public UnaryExpr { @@ -602,6 +747,9 @@ public: ExprPtr MakeLvalue() override; + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr Fold(Val* v) const override; @@ -621,6 +769,9 @@ public: const char* FieldName() const { return field_name; } + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr Fold(Val* v) const override; @@ -643,6 +794,9 @@ public: TraversalCode Traverse(TraversalCallback* cb) const override; + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override; @@ -655,7 +809,8 @@ class TableConstructorExpr final : public UnaryExpr { public: TableConstructorExpr(ListExprPtr constructor_list, std::unique_ptr> attrs, - TypePtr arg_type = nullptr); + TypePtr arg_type = nullptr, + AttributesPtr arg_attrs = nullptr); [[deprecated("Remove in v4.1. Use GetAttrs().")]] Attributes* Attrs() { return attrs.get(); } @@ -665,6 +820,9 @@ public: ValPtr Eval(Frame* f) const override; + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override; @@ -677,7 +835,8 @@ class SetConstructorExpr final : public UnaryExpr { public: SetConstructorExpr(ListExprPtr constructor_list, std::unique_ptr> attrs, - TypePtr arg_type = nullptr); + TypePtr arg_type = nullptr, + AttributesPtr arg_attrs = nullptr); [[deprecated("Remove in v4.1. Use GetAttrs().")]] Attributes* Attrs() { return attrs.get(); } @@ -687,6 +846,9 @@ public: ValPtr Eval(Frame* f) const override; + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override; @@ -702,6 +864,9 @@ public: ValPtr Eval(Frame* f) const override; + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override; @@ -717,6 +882,9 @@ public: void EvalIntoAggregate(const zeek::Type* t, Val* aggr, Frame* f) const override; bool IsRecordElement(TypeDecl* td) const override; + // Optimization-related: + ExprPtr Duplicate() override; + protected: void ExprDescribe(ODesc* d) const override; @@ -727,6 +895,9 @@ class ArithCoerceExpr final : public UnaryExpr { public: ArithCoerceExpr(ExprPtr op, TypeTag t); + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr FoldSingleVal(Val* v, InternalTypeTag t) const; ValPtr Fold(Val* v) const override; @@ -737,6 +908,9 @@ public: RecordCoerceExpr(ExprPtr op, RecordTypePtr r); ~RecordCoerceExpr() override; + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override; ValPtr Fold(Val* v) const override; @@ -752,6 +926,9 @@ public: TableCoerceExpr(ExprPtr op, TableTypePtr r); ~TableCoerceExpr() override; + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr Fold(Val* v) const override; }; @@ -761,6 +938,9 @@ public: VectorCoerceExpr(ExprPtr op, VectorTypePtr v); ~VectorCoerceExpr() override; + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr Fold(Val* v) const override; }; @@ -790,6 +970,10 @@ public: TraversalCode Traverse(TraversalCallback* cb) const override; + // Optimization-related: + ExprPtr Duplicate() override; + ExprPtr Inline(Inliner* inl) override; + protected: void ExprDescribe(ODesc* d) const override; @@ -801,6 +985,9 @@ class InExpr final : public BinaryExpr { public: InExpr(ExprPtr op1, ExprPtr op2); + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr Fold(Val* v1, Val* v2) const override; @@ -820,6 +1007,10 @@ public: TraversalCode Traverse(TraversalCallback* cb) const override; + // Optimization-related: + ExprPtr Duplicate() override; + ExprPtr Inline(Inliner* inl) override; + protected: void ExprDescribe(ODesc* d) const override; @@ -843,6 +1034,10 @@ public: Scope* GetScope() const; + // Optimization-related: + ExprPtr Duplicate() override; + ExprPtr Inline(Inliner* inl) override; + protected: void ExprDescribe(ODesc* d) const override; @@ -865,6 +1060,10 @@ public: TraversalCode Traverse(TraversalCallback* cb) const override; + // Optimization-related: + ExprPtr Duplicate() override; + ExprPtr Inline(Inliner* inl) override; + protected: void ExprDescribe(ODesc* d) const override; @@ -896,6 +1095,10 @@ public: TraversalCode Traverse(TraversalCallback* cb) const override; + // Optimization-related: + ExprPtr Duplicate() override; + ExprPtr Inline(Inliner* inl) override; + protected: ValPtr AddSetInit(const zeek::Type* t, ValPtr aggr) const; @@ -914,6 +1117,9 @@ class CastExpr final : public UnaryExpr { public: CastExpr(ExprPtr op, TypePtr t); + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr Eval(Frame* f) const override; void ExprDescribe(ODesc* d) const override; @@ -923,6 +1129,9 @@ class IsExpr final : public UnaryExpr { public: IsExpr(ExprPtr op, TypePtr t); + // Optimization-related: + ExprPtr Duplicate() override; + protected: ValPtr Fold(Val* v) const override; void ExprDescribe(ODesc* d) const override; @@ -931,6 +1140,33 @@ private: TypePtr t; }; + +class InlineExpr : public Expr { +public: + InlineExpr(ListExprPtr arg_args, std::vector params, StmtPtr body, + int frame_offset, TypePtr ret_type); + + bool IsPure() const override; + + ListExprPtr Args() const { return args; } + StmtPtr Body() const { return body; } + + ValPtr Eval(Frame* f) const override; + + ExprPtr Duplicate() override; + + TraversalCode Traverse(TraversalCallback* cb) const override; + +protected: + void ExprDescribe(ODesc* d) const override; + + std::vector params; + int frame_offset; + ListExprPtr args; + StmtPtr body; +}; + + inline Val* Expr::ExprVal() const { if ( ! IsConst() ) diff --git a/src/Frame.cc b/src/Frame.cc index 6694b507fe..b0a106f54f 100644 --- a/src/Frame.cc +++ b/src/Frame.cc @@ -30,6 +30,8 @@ Frame::Frame(int arg_size, const ScriptFunc* func, const zeek::Args* fn_args) delayed = false; closure = nullptr; + + current_offset = 0; } Frame::~Frame() @@ -68,12 +70,16 @@ void Frame::SetElement(int n, Val* v) void Frame::SetElement(int n, ValPtr v) { + n += current_offset; + ClearElement(n); frame[n] = {std::move(v), false}; } void Frame::SetElementWeak(int n, Val* v) { + n += current_offset; + ClearElement(n); frame[n] = {{AdoptRef{}, v}, true}; } @@ -120,10 +126,10 @@ const ValPtr& Frame::GetElementByID(const ID* id) const { auto where = offset_map->find(std::string(id->Name())); if ( where != offset_map->end() ) - return frame[where->second].val; + return frame[where->second + current_offset].val; } - return frame[id->Offset()].val; + return frame[id->Offset() + current_offset].val; } void Frame::Reset(int startIdx) @@ -142,7 +148,7 @@ void Frame::Reset(int startIdx) functions_with_closure_frame_reference.reset(); } - for ( int i = startIdx; i < size; ++i ) + for ( int i = startIdx + current_offset; i < size; ++i ) ClearElement(i); } @@ -244,7 +250,7 @@ Frame* Frame::SelectiveClone(const IDPList& selection, ScriptFunc* func) const } } - if ( ! frame[id->Offset()].val ) + if ( ! frame[id->Offset() + current_offset].val ) reporter->InternalError("Attempted to clone an id ('%s') with no associated value.", id->Name()); CloneNonFuncElement(id->Offset(), func, other); diff --git a/src/Frame.h b/src/Frame.h index e78bdcf492..64f496b6b6 100644 --- a/src/Frame.h +++ b/src/Frame.h @@ -58,7 +58,12 @@ public: * @return the value at index *n* of the underlying array. */ const ValPtr& GetElement(int n) const - { return frame[n].val; } + { + // Note: technically this may want to adjust by current_offset, but + // in practice, this method is never called from anywhere other than + // function call invocation, where current_offset should be zero. + return frame[n].val; + } [[deprecated("Remove in v4.1. Use GetElement(int).")]] Val* NthElement(int n) const { return frame[n].val.get(); } @@ -98,6 +103,15 @@ public: Val* GetElement(const ID* id) const { return GetElementByID(id).get(); } + /** + * Adjusts the current offset being used for frame accesses. + * This is in support of inlined functions. + * + * @param incr Amount by which to increase the frame offset. + * Use a negative value to shrink the offset. + */ + void AdjustOffset(int incr) { current_offset += incr; } + /** * Resets all of the indexes from [*startIdx, frame_size) in * the Frame. @@ -316,6 +330,13 @@ private: /** Associates ID's offsets with values. */ std::unique_ptr frame; + /** + * The offset we're currently using for references into the frame. + * This is how we support inlined functions without having to + * alter the offsets associated with their local variables. + */ + int current_offset; + /** The enclosing frame of this frame. */ Frame* closure; diff --git a/src/Func.cc b/src/Func.cc index 0062dab5ad..7a120e0538 100644 --- a/src/Func.cc +++ b/src/Func.cc @@ -310,6 +310,7 @@ ScriptFunc::ScriptFunc(const IDPtr& arg_id, StmtPtr arg_body, { Body b; b.stmts = AddInits(std::move(arg_body), aggr_inits); + current_body = b.stmts; b.priority = priority; bodies.push_back(b); } @@ -384,8 +385,7 @@ ValPtr ScriptFunc::Invoke(zeek::Args* args, Frame* parent) const for ( const auto& body : bodies ) { if ( sample_logger ) - sample_logger->LocationSeen( - body.stmts->GetLocationInfo()); + sample_logger->LocationSeen(body.stmts->GetLocationInfo()); // Fill in the rest of the frame with the function's arguments. for ( auto j = 0u; j < args->size(); ++j ) @@ -497,6 +497,8 @@ void ScriptFunc::AddBody(StmtPtr new_body, b.stmts = new_body; b.priority = priority; + current_body = new_body; + bodies.push_back(b); sort(bodies.begin(), bodies.end()); } @@ -627,6 +629,7 @@ BuiltinFunc::BuiltinFunc(built_in_func arg_func, const char* arg_name, type = id->GetType(); id->SetVal(make_intrusive(IntrusivePtr{NewRef{}, this})); + id->SetConst(); } BuiltinFunc::~BuiltinFunc() diff --git a/src/Func.h b/src/Func.h index 72c529942e..191a766218 100644 --- a/src/Func.h +++ b/src/Func.h @@ -10,6 +10,7 @@ #include #include "zeek/ZeekList.h" +#include "zeek/Stmt.h" #include "zeek/Obj.h" #include "zeek/IntrusivePtr.h" #include "zeek/Type.h" /* for function_flavor */ @@ -43,6 +44,8 @@ using ScopePtr = IntrusivePtr; using IDPtr = IntrusivePtr; using StmtPtr = IntrusivePtr; +class ScriptFunc; + } // namespace detail class Func; @@ -193,6 +196,22 @@ public: const std::vector& new_inits, size_t new_frame_size, int priority) override; + StmtPtr CurrentBody() const { return current_body; } + + /** + * Returns the function's frame size. + * @return The number of ValPtr slots in the function's frame. + */ + int FrameSize() const { return frame_size; } + + /** + * Changes the function's frame size to a new size - used for + * script optimization/compilation. + * + * @param new_size The frame size the function should use. + */ + void SetFrameSize(int new_size) { frame_size = new_size; } + /** Sets this function's outer_id list. */ void SetOuterIDs(IDPList ids) { outer_ids = std::move(ids); } @@ -226,6 +245,9 @@ private: // The frame the ScriptFunc was initialized in. Frame* closure = nullptr; bool weak_closure_ref = false; + + // The most recently added/updated body. + StmtPtr current_body; }; using built_in_func = BifReturnVal (*)(Frame* frame, const Args* args); diff --git a/src/Obj.h b/src/Obj.h index 7a393e09bc..6039621944 100644 --- a/src/Obj.h +++ b/src/Obj.h @@ -110,7 +110,7 @@ public: void AddLocation(ODesc* d) const; // Get location info for debugging. - const detail::Location* GetLocationInfo() const + virtual const detail::Location* GetLocationInfo() const { return location ? location : &detail::no_location; } virtual bool SetLocationInfo(const detail::Location* loc) diff --git a/src/Options.cc b/src/Options.cc index a81e2a8754..b3ce952ac5 100644 --- a/src/Options.cc +++ b/src/Options.cc @@ -3,6 +3,7 @@ #include "zeek-config.h" #include "zeek/Options.h" +#include "zeek/script_opt/ScriptOpt.h" #include @@ -104,6 +105,7 @@ void usage(const char* prog, int code) fprintf(stderr, " -H|--save-seeds | save seeds to given file\n"); fprintf(stderr, " -I|--print-id | print out given ID\n"); fprintf(stderr, " -N|--print-plugins | print available plugins and exit (-NN for verbose)\n"); + fprintf(stderr, " -O|--optimize[=