mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
script optimization tracking of functions called by event engine or indirectly
This commit is contained in:
parent
e9b990254a
commit
dd91790f1e
6 changed files with 640 additions and 490 deletions
|
@ -193,22 +193,21 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e) {
|
|||
all_globals.insert(id);
|
||||
|
||||
const auto& t = id->GetType();
|
||||
if ( t->Tag() == TYPE_FUNC && t->AsFuncType()->Flavor() == FUNC_FLAVOR_EVENT )
|
||||
events.insert(id->Name());
|
||||
if ( t->Tag() == TYPE_FUNC )
|
||||
if ( t->AsFuncType()->Flavor() == FUNC_FLAVOR_EVENT )
|
||||
events.insert(id->Name());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// This is a tad ugly. Unfortunately due to the
|
||||
// weird way that Zeek function *declarations* work,
|
||||
// there's no reliable way to get the list of
|
||||
// parameters for a function *definition*, since
|
||||
// they can have different names than what's present
|
||||
// in the declaration. So we identify them directly,
|
||||
// by knowing that they come at the beginning of the
|
||||
// frame ... and being careful to avoid misconfusing
|
||||
// a lambda capture with a low frame offset as a
|
||||
// parameter.
|
||||
// This is a tad ugly. Unfortunately due to the weird way
|
||||
// that Zeek function *declarations* work, there's no reliable
|
||||
// way to get the list of parameters for a function *definition*,
|
||||
// since they can have different names than what's present in the
|
||||
// declaration. So we identify them directly, by knowing that
|
||||
// they come at the beginning of the frame ... and being careful
|
||||
// to avoid misconfusing a lambda capture with a low frame offset
|
||||
// as a parameter.
|
||||
if ( captures.count(id) == 0 && id->Offset() < num_params )
|
||||
params.insert(id);
|
||||
|
||||
|
@ -251,11 +250,25 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e) {
|
|||
case EXPR_REMOVE_FROM:
|
||||
case EXPR_ASSIGN: {
|
||||
auto lhs = e->GetOp1();
|
||||
bool is_assign = e->Tag() == EXPR_ASSIGN;
|
||||
|
||||
if ( is_assign ) {
|
||||
// Check for this being an assignment to a function (as
|
||||
// opposed to a call). If so, then the function can be
|
||||
// used indirectly.
|
||||
auto rhs = e->GetOp2();
|
||||
if ( rhs->Tag() == EXPR_NAME ) {
|
||||
auto& rhs_id = rhs->AsNameExpr()->IdPtr();
|
||||
const auto& t = rhs_id->GetType();
|
||||
if ( t->Tag() == TYPE_FUNC && t->AsFuncType()->Flavor() == FUNC_FLAVOR_FUNCTION )
|
||||
indirect_funcs.insert(rhs_id.get());
|
||||
}
|
||||
}
|
||||
|
||||
if ( lhs->Tag() == EXPR_REF )
|
||||
lhs = lhs->GetOp1();
|
||||
|
||||
else if ( e->Tag() == EXPR_ASSIGN )
|
||||
else if ( is_assign )
|
||||
// This isn't a direct assignment, but instead an overloaded
|
||||
// use of "=" such as in a table constructor.
|
||||
break;
|
||||
|
@ -267,7 +280,7 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e) {
|
|||
auto id = lhs->AsNameExpr()->Id();
|
||||
TrackAssignment(id);
|
||||
|
||||
if ( e->Tag() == EXPR_ASSIGN ) {
|
||||
if ( is_assign ) {
|
||||
auto a_e = static_cast<const AssignExpr*>(e);
|
||||
auto& av = a_e->AssignVal();
|
||||
if ( av )
|
||||
|
@ -287,7 +300,7 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e) {
|
|||
// assignment "a[b] = aggr", it's not a[b]'s type but
|
||||
// rather a's type. However, for any of the others,
|
||||
// e.g. "a[b] -= aggr" it is a[b]'s type.
|
||||
if ( e->Tag() == EXPR_ASSIGN )
|
||||
if ( is_assign )
|
||||
aggr_mods.insert(lhs_aggr_t.get());
|
||||
else
|
||||
aggr_mods.insert(lhs_t.get());
|
||||
|
@ -325,20 +338,39 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e) {
|
|||
|
||||
case EXPR_CALL: {
|
||||
auto c = e->AsCallExpr();
|
||||
auto args = c->Args();
|
||||
auto f = c->Func();
|
||||
|
||||
if ( f->Tag() != EXPR_NAME ) {
|
||||
const NameExpr* n = nullptr;
|
||||
const ID* func = nullptr;
|
||||
|
||||
if ( f->Tag() == EXPR_NAME ) {
|
||||
n = f->AsNameExpr();
|
||||
func = n->Id();
|
||||
|
||||
if ( ! func->IsGlobal() )
|
||||
does_indirect_calls = true;
|
||||
}
|
||||
else
|
||||
does_indirect_calls = true;
|
||||
return TC_CONTINUE;
|
||||
|
||||
// Check for whether any of the arguments is a bare function.
|
||||
// If so, then note that that function may be used indirectly,
|
||||
// unless the function being called is known to be idempotent.
|
||||
if ( does_indirect_calls || ! is_idempotent(func->Name()) ) {
|
||||
for ( auto& arg : args->Exprs() )
|
||||
if ( arg->Tag() == EXPR_NAME ) {
|
||||
auto& arg_id = arg->AsNameExpr()->IdPtr();
|
||||
const auto& t = arg_id->GetType();
|
||||
if ( t->Tag() == TYPE_FUNC && t->AsFuncType()->Flavor() == FUNC_FLAVOR_FUNCTION )
|
||||
indirect_funcs.insert(arg_id.get());
|
||||
}
|
||||
}
|
||||
|
||||
auto n = f->AsNameExpr();
|
||||
auto func = n->Id();
|
||||
|
||||
if ( ! func->IsGlobal() ) {
|
||||
does_indirect_calls = true;
|
||||
if ( does_indirect_calls )
|
||||
// We waited on doing this until after checking for
|
||||
// indirect functions.
|
||||
return TC_CONTINUE;
|
||||
}
|
||||
|
||||
all_globals.insert(func);
|
||||
|
||||
|
@ -361,7 +393,6 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e) {
|
|||
}
|
||||
|
||||
// Recurse into the arguments.
|
||||
auto args = c->Args();
|
||||
args->Traverse(this);
|
||||
|
||||
// Do the following explicitly, since we won't be recursing
|
||||
|
@ -604,7 +635,7 @@ bool ProfileFuncs::GetCallSideEffects(const NameExpr* n, IDSet& non_local_ids, T
|
|||
|
||||
auto func = fv->AsFunc();
|
||||
if ( func->GetKind() == Func::BUILTIN_FUNC ) {
|
||||
if ( ! is_side_effect_free(func->Name()) )
|
||||
if ( ! has_no_script_side_effects(func->Name()) )
|
||||
is_unknown = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -1137,7 +1168,7 @@ bool ProfileFuncs::DefinitelyHasNoSideEffects(const ExprPtr& e) const {
|
|||
return false;
|
||||
|
||||
for ( auto& b : pf->BiFGlobals() )
|
||||
if ( ! is_side_effect_free(b->Name()) )
|
||||
if ( ! has_no_script_side_effects(b->Name()) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -1228,7 +1259,7 @@ bool ProfileFuncs::AssessSideEffects(const ProfileFunc* pf, IDSet& non_local_ids
|
|||
}
|
||||
|
||||
for ( auto& b : pf->BiFGlobals() )
|
||||
if ( ! is_side_effect_free(b->Name()) ) {
|
||||
if ( ! has_no_script_side_effects(b->Name()) ) {
|
||||
is_unknown = true;
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue