diff --git a/src/ID.cc b/src/ID.cc index acd4597e80..2df52b2520 100644 --- a/src/ID.cc +++ b/src/ID.cc @@ -680,11 +680,6 @@ std::vector ID::GetOptionHandlers() const return v; } -void IDOptInfo::AddInitExpr(ExprPtr init_expr) - { - init_exprs.emplace_back(std::move(init_expr)); - } - } // namespace detail } // namespace zeek diff --git a/src/Var.cc b/src/Var.cc index 9a3b9bd9ac..c4e13c7d74 100644 --- a/src/Var.cc +++ b/src/Var.cc @@ -17,6 +17,7 @@ #include "zeek/Traverse.h" #include "zeek/Val.h" #include "zeek/module_util.h" +#include "zeek/script_opt/IDOptInfo.h" #include "zeek/script_opt/StmtOptInfo.h" #include "zeek/script_opt/UsageAnalyzer.h" @@ -117,12 +118,12 @@ static bool add_prototype(const IDPtr& id, Type* t, std::vector* attrs, return true; } -static void initialize_var(const IDPtr& id, InitClass c, ExprPtr init) +static ExprPtr initialize_var(const IDPtr& id, InitClass c, ExprPtr init) { if ( ! id->HasVal() ) { if ( c == INIT_REMOVE ) - return; + return nullptr; bool no_init = ! init; @@ -134,7 +135,7 @@ static void initialize_var(const IDPtr& id, InitClass c, ExprPtr init) auto& t = id->GetType(); if ( ! IsAggr(t) ) - return; + return nullptr; ValPtr init_val; @@ -147,7 +148,7 @@ static void initialize_var(const IDPtr& id, InitClass c, ExprPtr init) catch ( InterpreterException& ) { id->Error("initialization failed"); - return; + return nullptr; } } @@ -157,11 +158,11 @@ static void initialize_var(const IDPtr& id, InitClass c, ExprPtr init) else if ( t->Tag() == TYPE_VECTOR ) init_val = make_intrusive(cast_intrusive(t)); - id->SetVal(init_val); - return; + init = make_intrusive(init_val); + c = INIT_FULL; } - if ( c == INIT_EXTRA ) + else if ( c == INIT_EXTRA ) c = INIT_FULL; } @@ -177,19 +178,12 @@ static void initialize_var(const IDPtr& id, InitClass c, ExprPtr init) assignment = make_intrusive(lhs, init); else // This can happen due to error propagation. - return; + return nullptr; if ( assignment->IsError() ) - return; + return nullptr; - try - { - (void)assignment->Eval(nullptr); - } - catch ( InterpreterException& ) - { - id->Error("initialization failed"); - } + return assignment; } static void make_var(const IDPtr& id, TypePtr t, InitClass c, ExprPtr init, @@ -347,11 +341,29 @@ static void make_var(const IDPtr& id, TypePtr t, InitClass c, ExprPtr init, if ( init && ((c == INIT_EXTRA && id->GetAttr(ATTR_ADD_FUNC)) || (c == INIT_REMOVE && id->GetAttr(ATTR_DEL_FUNC))) ) + { // Just apply the function. id->SetVal(init, c); + id->GetOptInfo()->AddInitExpr(init, c); + } else if ( dt != VAR_REDEF || init || ! attr ) - initialize_var(id, c, init); + { + auto init_expr = initialize_var(id, c, init); + if ( init_expr ) + { + id->GetOptInfo()->AddInitExpr(init_expr); + + try + { + (void)init_expr->Eval(nullptr); + } + catch ( InterpreterException& ) + { + id->Error("initialization failed"); + } + } + } } if ( dt == VAR_CONST ) diff --git a/src/parse.y b/src/parse.y index 3e98d60944..5735c7beaf 100644 --- a/src/parse.y +++ b/src/parse.y @@ -102,7 +102,6 @@ #include "zeek/zeekygen/Manager.h" #include "zeek/module_util.h" #include "zeek/IntrusivePtr.h" -#include "zeek/script_opt/IDOptInfo.h" extern const char* filename; // Absolute path of file currently being parsed. extern const char* last_filename; // Absolute path of last file parsed. @@ -321,8 +320,6 @@ static void build_global(ID* id, Type* t, InitClass ic, Expr* e, add_global(id_ptr, std::move(t_ptr), ic, e_ptr, std::move(attrs_ptr), dt); - id->GetOptInfo()->AddInitExpr(e_ptr); - if ( dt == VAR_REDEF ) zeekygen_mgr->Redef(id, ::filename, ic, std::move(e_ptr)); else @@ -342,8 +339,6 @@ static StmtPtr build_local(ID* id, Type* t, InitClass ic, Expr* e, auto init = add_local(std::move(id_ptr), std::move(t_ptr), ic, e_ptr, std::move(attrs_ptr), dt); - id->GetOptInfo()->AddInitExpr(std::move(e_ptr)); - if ( do_coverage ) script_coverage_mgr.AddStmt(init.get()); diff --git a/src/script_opt/IDOptInfo.cc b/src/script_opt/IDOptInfo.cc index 69718683ab..bf100cf784 100644 --- a/src/script_opt/IDOptInfo.cc +++ b/src/script_opt/IDOptInfo.cc @@ -51,6 +51,8 @@ void IDDefRegion::Dump() const printf("\n"); } +std::vector IDOptInfo::global_init_exprs; + void IDOptInfo::Clear() { static bool did_init = false; @@ -69,6 +71,17 @@ void IDOptInfo::Clear() tracing = trace_ID && util::streq(trace_ID, my_id->Name()); } +void IDOptInfo::AddInitExpr(ExprPtr init_expr, InitClass ic) + { + if ( ! init_expr ) + return; + + if ( my_id->IsGlobal() ) + global_init_exprs.emplace_back(IDInitInfo(my_id, init_expr, ic)); + + init_exprs.emplace_back(std::move(init_expr)); + } + void IDOptInfo::DefinedAfter(const Stmt* s, const ExprPtr& e, const std::vector& conf_blocks, zeek_uint_t conf_start) { diff --git a/src/script_opt/IDOptInfo.h b/src/script_opt/IDOptInfo.h index 6bf8718a68..a55f5791a8 100644 --- a/src/script_opt/IDOptInfo.h +++ b/src/script_opt/IDOptInfo.h @@ -105,6 +105,24 @@ protected: ExprPtr def_expr; }; +// Class tracking information associated with a (global) identifier's +// (re-)initialization. + +class IDInitInfo + { +public: + IDInitInfo(const ID* _id, ExprPtr _init, InitClass _ic) : id(_id), init(_init), ic(_ic) { } + + const ID* Id() const { return id; } + const ExprPtr& Init() const { return init; } + InitClass IC() const { return ic; } + +private: + const ID* id; + ExprPtr init; + InitClass ic; + }; + // Class tracking optimization information associated with identifiers. class IDOptInfo @@ -118,11 +136,19 @@ public: void Clear(); // Used to track expressions employed when explicitly initializing - // the identifier. These are needed by compile-to-C++ script - // optimization. They're not used by ZAM optimization. - void AddInitExpr(ExprPtr init_expr); + // the (global) identifier. These are needed by compile-to-C++ script + // optimization, and for tracking variable usage. An initialization + // class other than INIT_NONE indicates that initialization should + // be done with the ExprPtr form of ID::SetVal. + void AddInitExpr(ExprPtr init_expr, InitClass ic = INIT_NONE); + + // Returns the initialization expressions for this identifier. const std::vector& GetInitExprs() const { return init_exprs; } + // Returns a list of the initialization expressions seen for all + // globals, ordered by when they were processed. + static auto& GetGlobalInitExprs() { return global_init_exprs; } + // Associated constant expression, if any. This is only set // for identifiers that are aliases for a constant (i.e., there // are no other assignments to them). @@ -224,6 +250,9 @@ private: // one of the earlier instances rather than the last one. std::vector init_exprs; + // Tracks initializations of globals in the order they're seen. + static std::vector global_init_exprs; + // If non-nil, a constant that this identifier always holds // once initially defined. const ConstExpr* const_expr = nullptr; @@ -256,8 +285,12 @@ private: // Whether the identifier is a temporary variable. bool is_temp = false; - // Only needed for debugging purposes. + // Associated identifier, to enable tracking of initialization + // expressions for globals (for C++ compilation), and for debugging + // output. const ID* my_id; + + // Only needed for debugging purposes. bool tracing = false; // Track whether we've already generated usage errors.