support for discarding ASTs once compiled via ZAM script optimization

This commit is contained in:
Vern Paxson 2023-07-20 09:39:05 -07:00
parent 79c53c9ed6
commit 91d70e6dd4
13 changed files with 55 additions and 17 deletions

@ -1 +1 @@
Subproject commit 116be85c38f2f5dabd01f42b8b53e38004df41c0 Subproject commit cbba05dbaa58fdabe863f4e8a122ca92809b52d6

View file

@ -132,8 +132,8 @@ ID::ID(const char* arg_name, IDScope arg_scope, bool arg_is_export)
ID::~ID() ID::~ID()
{ {
ClearOptInfo();
delete[] name; delete[] name;
delete opt_info;
} }
std::string ID::ModuleName() const std::string ID::ModuleName() const
@ -687,6 +687,12 @@ std::vector<Func*> ID::GetOptionHandlers() const
return v; return v;
} }
void ID::ClearOptInfo()
{
delete opt_info;
opt_info = nullptr;
}
} // namespace detail } // namespace detail
} // namespace zeek } // namespace zeek

View file

@ -151,6 +151,7 @@ public:
std::vector<Func*> GetOptionHandlers() const; std::vector<Func*> GetOptionHandlers() const;
IDOptInfo* GetOptInfo() const { return opt_info; } IDOptInfo* GetOptInfo() const { return opt_info; }
void ClearOptInfo();
protected: protected:
void EvalFunc(ExprPtr ef, ExprPtr ev); void EvalFunc(ExprPtr ef, ExprPtr ev);

View file

@ -1770,7 +1770,7 @@ ExprPtr AssignExpr::Reduce(Reducer* c, StmtPtr& red_stmt)
red_stmt = MergeStmts(rhs_reduce, lhs_stmt, rhs_stmt); red_stmt = MergeStmts(rhs_reduce, lhs_stmt, rhs_stmt);
auto field_name = field_e->FieldName(); auto field_name = util::copy_string(field_e->FieldName());
auto field = field_e->Field(); auto field = field_e->Field();
auto field_assign = make_intrusive<FieldLHSAssignExpr>(lhs_e, rhs_e, field_name, field); auto field_assign = make_intrusive<FieldLHSAssignExpr>(lhs_e, rhs_e, field_name, field);
@ -1909,7 +1909,7 @@ ExprPtr IndexExprWhen::Duplicate()
ExprPtr FieldExpr::Duplicate() ExprPtr FieldExpr::Duplicate()
{ {
return SetSucc(new FieldExpr(op->Duplicate(), field_name)); return SetSucc(new FieldExpr(op->Duplicate(), util::copy_string(field_name)));
} }
ExprPtr HasFieldExpr::Duplicate() ExprPtr HasFieldExpr::Duplicate()

View file

@ -148,6 +148,7 @@ public:
// Returns a list of the initialization expressions seen for all // Returns a list of the initialization expressions seen for all
// globals, ordered by when they were processed. // globals, ordered by when they were processed.
static auto& GetGlobalInitExprs() { return global_init_exprs; } static auto& GetGlobalInitExprs() { return global_init_exprs; }
static void ClearGlobalInitExprs() { global_init_exprs.clear(); }
// Associated constant expression, if any. This is only set // Associated constant expression, if any. This is only set
// for identifiers that are aliases for a constant (i.e., there // for identifiers that are aliases for a constant (i.e., there

View file

@ -31,8 +31,6 @@ void (*CPP_activation_hook)() = nullptr;
// Tracks all of the loaded functions (including event handlers and hooks). // Tracks all of the loaded functions (including event handlers and hooks).
static std::vector<FuncInfo> funcs; static std::vector<FuncInfo> funcs;
static ZAMCompiler* ZAM = nullptr;
static bool generating_CPP = false; static bool generating_CPP = false;
static std::string CPP_dir; // where to generate C++ code static std::string CPP_dir; // where to generate C++ code
@ -78,12 +76,10 @@ const FuncInfo* analyze_global_stmts(Stmt* stmts)
auto sc = current_scope(); auto sc = current_scope();
std::vector<IDPtr> empty_inits; std::vector<IDPtr> empty_inits;
StmtPtr stmts_p{NewRef{}, stmts};
global_stmts = make_intrusive<ScriptFunc>(id); global_stmts = make_intrusive<ScriptFunc>(id);
global_stmts->AddBody(stmts_p, empty_inits, sc->Length()); global_stmts->AddBody(stmts->ThisPtr(), empty_inits, sc->Length());
funcs.emplace_back(global_stmts, sc, stmts_p, 0);
funcs.emplace_back(global_stmts, sc, stmts->ThisPtr(), 0);
return &funcs.back(); return &funcs.back();
} }
@ -253,15 +249,15 @@ static void optimize_func(ScriptFunc* f, std::shared_ptr<ProfileFunc> pf, ScopeP
if ( analysis_options.gen_ZAM_code ) if ( analysis_options.gen_ZAM_code )
{ {
ZAM = new ZAMCompiler(f, pf, scope, new_body, ud, rc); ZAMCompiler ZAM(f, pf, scope, new_body, ud, rc);
new_body = ZAM->CompileBody(); new_body = ZAM.CompileBody();
if ( reporter->Errors() > 0 ) if ( reporter->Errors() > 0 )
return; return;
if ( analysis_options.dump_ZAM ) if ( analysis_options.dump_ZAM )
ZAM->Dump(); ZAM.Dump();
f->ReplaceBody(body, new_body); f->ReplaceBody(body, new_body);
body = new_body; body = new_body;
@ -544,6 +540,25 @@ static void analyze_scripts_for_ZAM(std::unique_ptr<ProfileFuncs>& pfs)
finalize_functions(funcs); finalize_functions(funcs);
} }
void clear_script_analysis()
{
IDOptInfo::ClearGlobalInitExprs();
// We need to explicitly clear out the optimization information
// associated with identifiers. They have reference loops with
// the parent identifier that will prevent reclamation of the
// identifiers (and the optimization information) upon Unref'ing
// when discarding the scopes and ASTs.
for ( auto& f : funcs )
for ( auto& id : f.Scope()->OrderedVars() )
id->ClearOptInfo();
funcs.clear();
non_recursive_funcs.clear();
lambdas.clear();
when_lambdas.clear();
}
void analyze_scripts(bool no_unused_warnings) void analyze_scripts(bool no_unused_warnings)
{ {
init_options(); init_options();

View file

@ -196,6 +196,10 @@ extern bool should_analyze(const ScriptFuncPtr& f, const StmtPtr& body);
// suppressed by the flag) and optimization. // suppressed by the flag) and optimization.
extern void analyze_scripts(bool no_unused_warnings); extern void analyze_scripts(bool no_unused_warnings);
// Called when all script processing is complete and we can discard
// unused ASTs and associated state.
extern void clear_script_analysis();
// Called when Zeek is terminating. // Called when Zeek is terminating.
extern void finish_script_execution(); extern void finish_script_execution();

View file

@ -60,6 +60,7 @@ class ZAMCompiler
public: public:
ZAMCompiler(ScriptFunc* f, std::shared_ptr<ProfileFunc> pf, ScopePtr scope, StmtPtr body, ZAMCompiler(ScriptFunc* f, std::shared_ptr<ProfileFunc> pf, ScopePtr scope, StmtPtr body,
std::shared_ptr<UseDefs> ud, std::shared_ptr<Reducer> rd); std::shared_ptr<UseDefs> ud, std::shared_ptr<Reducer> rd);
~ZAMCompiler();
StmtPtr CompileBody(); StmtPtr CompileBody();

View file

@ -29,6 +29,14 @@ ZAMCompiler::ZAMCompiler(ScriptFunc* f, std::shared_ptr<ProfileFunc> _pf, ScopeP
Init(); Init();
} }
ZAMCompiler::~ZAMCompiler()
{
curr_stmt = nullptr;
for ( auto i : insts1 )
delete i;
}
void ZAMCompiler::Init() void ZAMCompiler::Init()
{ {
InitGlobals(); InitGlobals();

View file

@ -1096,7 +1096,7 @@ const ZAMStmt ZAMCompiler::DoCall(const CallExpr* c, const NameExpr* n)
z.aux->can_change_non_locals = true; z.aux->can_change_non_locals = true;
z.call_expr = c; z.call_expr = {NewRef{}, const_cast<CallExpr*>(c)};
if ( in_when ) if ( in_when )
z.SetType(n->GetType()); z.SetType(n->GetType());

View file

@ -1581,7 +1581,7 @@ macro WhenCall(func)
throw ZAMDelayedCallException(); throw ZAMDelayedCallException();
auto& lhs = frame[z.v1]; auto& lhs = frame[z.v1];
auto trigger = f->GetTrigger(); auto trigger = f->GetTrigger();
Val* v = trigger ? trigger->Lookup(z.call_expr) : nullptr; Val* v = trigger ? trigger->Lookup(z.call_expr.get()) : nullptr;
ValPtr vp; ValPtr vp;
if ( v ) if ( v )
vp = {NewRef{}, v}; vp = {NewRef{}, v};
@ -1593,7 +1593,7 @@ macro WhenCall(func)
std::vector<ValPtr> args; std::vector<ValPtr> args;
for ( auto i = 0; i < n; ++i ) for ( auto i = 0; i < n; ++i )
args.push_back(aux->ToVal(frame, i)); args.push_back(aux->ToVal(frame, i));
f->SetCall(z.call_expr); f->SetCall(z.call_expr.get());
/* It's possible that this function will call another that /* It's possible that this function will call another that
* itself returns null because *it* is the actual blocker. * itself returns null because *it* is the actual blocker.
* That will set ZAM_error, which we need to ignore. * That will set ZAM_error, which we need to ignore.

View file

@ -130,7 +130,7 @@ public:
// Interpreter call expression associated with this instruction, // Interpreter call expression associated with this instruction,
// for error reporting and stack backtraces. // for error reporting and stack backtraces.
const CallExpr* call_expr = nullptr; CallExprPtr call_expr = nullptr;
// Whether v1 represents a frame slot type for which we // Whether v1 represents a frame slot type for which we
// explicitly manage the memory. // explicitly manage the memory.

View file

@ -1114,6 +1114,8 @@ SetupResult setup(int argc, char** argv, Options* zopts)
g_frame_stack.pop_back(); g_frame_stack.pop_back();
} }
clear_script_analysis();
if ( zeek_script_loaded ) if ( zeek_script_loaded )
{ {
// Queue events reporting loaded scripts. // Queue events reporting loaded scripts.