mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
robustness improvements for -O gen-C++ generation of lambdas / "when"s
This commit is contained in:
parent
0ca2f9a8b2
commit
207b82ae4b
6 changed files with 66 additions and 35 deletions
|
@ -385,6 +385,10 @@ private:
|
|||
std::string LocalName(const ID* l) const;
|
||||
std::string LocalName(const IDPtr& l) const { return LocalName(l.get()); }
|
||||
|
||||
// The same, but for a capture.
|
||||
std::string CaptureName(const ID* l) const;
|
||||
std::string CaptureName(const IDPtr& l) const { return CaptureName(l.get()); }
|
||||
|
||||
// Returns a canonicalized name, with various non-alphanumeric
|
||||
// characters stripped or transformed, and guaranteed not to
|
||||
// conflict with C++ keywords.
|
||||
|
@ -585,8 +589,11 @@ private:
|
|||
// Maps function names to events relevant to them.
|
||||
std::unordered_map<std::string, std::vector<std::string>> body_events;
|
||||
|
||||
// Full type of the function we're currently compiling.
|
||||
FuncTypePtr func_type;
|
||||
|
||||
// Return type of the function we're currently compiling.
|
||||
TypePtr ret_type = nullptr;
|
||||
TypePtr ret_type;
|
||||
|
||||
// Internal name of the function we're currently compiling.
|
||||
std::string body_name;
|
||||
|
@ -697,6 +704,8 @@ private:
|
|||
void GenValueSwitchStmt(const Expr* e, const case_list* cases);
|
||||
|
||||
void GenWhenStmt(const WhenStmt* w);
|
||||
void GenWhenStmt(const WhenInfo* wi, const std::string& when_lambda, const Location* loc,
|
||||
std::vector<std::string> local_aggrs);
|
||||
void GenForStmt(const ForStmt* f);
|
||||
void GenForOverTable(const ExprPtr& tbl, const IDPtr& value_var, const IDPList* loop_vars);
|
||||
void GenForOverVector(const ExprPtr& tbl, const IDPtr& value_var, const IDPList* loop_vars);
|
||||
|
@ -771,6 +780,7 @@ private:
|
|||
std::string GenSizeExpr(const Expr* e, GenType gt);
|
||||
std::string GenScheduleExpr(const Expr* e);
|
||||
std::string GenLambdaExpr(const Expr* e);
|
||||
std::string GenLambdaExpr(const Expr* e, std::string capture_args);
|
||||
std::string GenIsExpr(const Expr* e, GenType gt);
|
||||
|
||||
std::string GenArithCoerceExpr(const Expr* e, GenType gt);
|
||||
|
|
|
@ -31,7 +31,7 @@ void CPPCompile::DeclareLambda(const LambdaExpr* l, const ProfileFunc* pf) {
|
|||
auto& ids = l->OuterIDs();
|
||||
|
||||
for ( auto id : ids )
|
||||
lambda_names[id] = LocalName(id);
|
||||
lambda_names[id] = CaptureName(id);
|
||||
|
||||
CreateFunction(l_id->GetType<FuncType>(), pf, lname, body, 0, l, FUNC_FLAVOR_FUNCTION);
|
||||
}
|
||||
|
@ -40,7 +40,12 @@ void CPPCompile::CreateFunction(const FuncTypePtr& ft, const ProfileFunc* pf, co
|
|||
int priority, const LambdaExpr* l, FunctionFlavor flavor) {
|
||||
const auto& yt = ft->Yield();
|
||||
in_hook = flavor == FUNC_FLAVOR_HOOK;
|
||||
const IDPList* lambda_ids = l ? &l->OuterIDs() : nullptr;
|
||||
|
||||
IDPList effective_lambda_ids;
|
||||
if ( l )
|
||||
effective_lambda_ids = l->OuterIDs();
|
||||
|
||||
const IDPList* lambda_ids = l ? &effective_lambda_ids : nullptr;
|
||||
|
||||
string args = BindArgs(ft, lambda_ids);
|
||||
|
||||
|
@ -313,7 +318,7 @@ void CPPCompile::GatherParamTypes(vector<string>& p_types, const FuncTypePtr& ft
|
|||
auto tn = FullTypeName(t);
|
||||
|
||||
// Allow the captures to be modified.
|
||||
p_types.emplace_back(string(tn) + "& ");
|
||||
p_types.emplace_back(string(tn) + "&");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -328,18 +333,16 @@ void CPPCompile::GatherParamNames(vector<string>& p_names, const FuncTypePtr& ft
|
|||
|
||||
if ( param_id ) {
|
||||
if ( t->Tag() == TYPE_ANY && param_id->GetType()->Tag() != TYPE_ANY )
|
||||
// We'll need to translate the parameter
|
||||
// from its current representation to
|
||||
// type "any".
|
||||
// We'll need to translate the parameter from its current
|
||||
// representation to type "any".
|
||||
p_names.emplace_back(string("any_param__CPP_") + Fmt(i));
|
||||
else
|
||||
p_names.emplace_back(LocalName(param_id));
|
||||
}
|
||||
else
|
||||
// Parameters that are unused don't wind up in the
|
||||
// ProfileFunc. Rather than dig their name out of
|
||||
// the function's declaration, we explicitly name
|
||||
// them to reflect that they're unused.
|
||||
// Parameters that are unused don't wind up in the ProfileFunc.
|
||||
// Rather than dig their name out of the function's declaration,
|
||||
// we explicitly name them to reflect that they're unused.
|
||||
p_names.emplace_back(string("unused_param__CPP_") + Fmt(i));
|
||||
}
|
||||
|
||||
|
|
|
@ -639,13 +639,15 @@ string CPPCompile::GenScheduleExpr(const Expr* e) {
|
|||
}
|
||||
|
||||
string CPPCompile::GenLambdaExpr(const Expr* e) {
|
||||
auto l = static_cast<const LambdaExpr*>(e);
|
||||
auto& body = l->Ingredients()->Body();
|
||||
return GenLambdaExpr(e, GenLambdaClone(l, false));
|
||||
}
|
||||
|
||||
string CPPCompile::GenLambdaExpr(const Expr* e, string capture_args) {
|
||||
auto l = static_cast<const LambdaExpr*>(e);
|
||||
auto name = Canonicalize(l->Name().c_str()) + "_lb_cl";
|
||||
auto cl_args = string("\"") + name + "\"";
|
||||
|
||||
if ( l->OuterIDs().size() > 0 )
|
||||
cl_args = cl_args + GenLambdaClone(l, false);
|
||||
|
||||
auto cl_args = string("\"") + name + "\"" + std::move(capture_args);
|
||||
auto body = string("make_intrusive<") + name + ">(" + cl_args + ")";
|
||||
auto func = string("make_intrusive<CPPLambdaFunc>(\"") + l->Name() + "\", cast_intrusive<FuncType>(" +
|
||||
GenTypeName(l->GetType()) + "), " + body + ")";
|
||||
|
@ -1175,7 +1177,7 @@ string CPPCompile::GenLambdaClone(const LambdaExpr* l, bool all_deep) {
|
|||
|
||||
for ( const auto& id : ids ) {
|
||||
const auto& id_t = id->GetType();
|
||||
auto arg = LocalName(id);
|
||||
auto arg = CaptureName(id);
|
||||
|
||||
if ( captures && ! IsNativeType(id_t) ) {
|
||||
for ( const auto& c : *captures )
|
||||
|
@ -1183,7 +1185,7 @@ string CPPCompile::GenLambdaClone(const LambdaExpr* l, bool all_deep) {
|
|||
arg = string("cast_intrusive<") + TypeName(id_t) + ">(" + arg + "->Clone())";
|
||||
}
|
||||
|
||||
cl_args = cl_args + ", " + arg;
|
||||
cl_args += ", " + arg;
|
||||
}
|
||||
|
||||
return cl_args;
|
||||
|
|
|
@ -77,6 +77,7 @@ protected:
|
|||
// Methods related to sending lambdas via Broker.
|
||||
std::optional<BrokerData> SerializeCaptures() const override;
|
||||
void SetCaptures(Frame* f) override;
|
||||
void SetCapturesVec(std::unique_ptr<std::vector<ZVal>> _captures_vec) { captures_vec = std::move(_captures_vec); }
|
||||
|
||||
FuncPtr DoClone() override;
|
||||
|
||||
|
|
|
@ -38,12 +38,18 @@ void CPPCompile::GenInvokeBody(const string& call, const TypePtr& t) {
|
|||
|
||||
void CPPCompile::DefineBody(const FuncTypePtr& ft, const ProfileFunc* pf, const string& fname, const StmtPtr& body,
|
||||
const IDPList* lambda_ids, FunctionFlavor flavor) {
|
||||
IDPList l_ids;
|
||||
if ( lambda_ids )
|
||||
l_ids = *lambda_ids;
|
||||
|
||||
locals.clear();
|
||||
params.clear();
|
||||
|
||||
body_name = fname;
|
||||
|
||||
func_type = ft;
|
||||
ret_type = ft->Yield();
|
||||
|
||||
in_hook = flavor == FUNC_FLAVOR_HOOK;
|
||||
auto ret_type_str = in_hook ? "bool" : FullTypeName(ret_type);
|
||||
|
||||
|
@ -52,7 +58,7 @@ void CPPCompile::DefineBody(const FuncTypePtr& ft, const ProfileFunc* pf, const
|
|||
|
||||
NL();
|
||||
|
||||
Emit("%s %s(%s)", ret_type_str, fname, ParamDecl(ft, lambda_ids, pf));
|
||||
Emit("%s %s(%s)", ret_type_str, fname, ParamDecl(ft, &l_ids, pf));
|
||||
|
||||
StartBlock();
|
||||
|
||||
|
@ -64,7 +70,7 @@ void CPPCompile::DefineBody(const FuncTypePtr& ft, const ProfileFunc* pf, const
|
|||
InitializeEvents(pf);
|
||||
|
||||
// Create the local variables.
|
||||
DeclareLocals(pf, lambda_ids);
|
||||
DeclareLocals(pf, &l_ids);
|
||||
|
||||
GenStmt(body);
|
||||
|
||||
|
@ -135,11 +141,12 @@ void CPPCompile::InitializeEvents(const ProfileFunc* pf) {
|
|||
}
|
||||
|
||||
void CPPCompile::DeclareLocals(const ProfileFunc* pf, const IDPList* lambda_ids) {
|
||||
// It's handy to have a set of the lambda captures rather than a list.
|
||||
IDSet lambda_set;
|
||||
// We track captures by their names rather than their ID*'s because the
|
||||
// latter can be inconsistent when inlining.
|
||||
set<string> capture_names;
|
||||
if ( lambda_ids )
|
||||
for ( auto li : *lambda_ids )
|
||||
lambda_set.insert(li);
|
||||
capture_names.insert(CaptureName(li));
|
||||
|
||||
const auto& ls = pf->Locals();
|
||||
|
||||
|
@ -149,11 +156,11 @@ void CPPCompile::DeclareLocals(const ProfileFunc* pf, const IDPList* lambda_ids)
|
|||
|
||||
for ( const auto& l : ls ) {
|
||||
auto ln = LocalName(l);
|
||||
auto cn = CaptureName(l);
|
||||
|
||||
if ( lambda_set.count(l) > 0 )
|
||||
// No need to declare these, they're passed in as
|
||||
// parameters.
|
||||
ln = lambda_names[l];
|
||||
if ( capture_names.count(cn) > 0 )
|
||||
// No need to declare these, they're passed in as parameters.
|
||||
ln = cn;
|
||||
|
||||
else if ( params.count(l) == 0 ) { // Not a parameter, so must be a local.
|
||||
Emit("%s %s;", FullTypeName(l->GetType()), ln);
|
||||
|
|
|
@ -305,15 +305,22 @@ void CPPCompile::GenValueSwitchStmt(const Expr* e, const case_list* cases) {
|
|||
|
||||
void CPPCompile::GenWhenStmt(const WhenStmt* w) {
|
||||
auto wi = w->Info();
|
||||
auto wl = wi->Lambda();
|
||||
|
||||
if ( ! wl )
|
||||
reporter->FatalError("cannot compile deprecated \"when\" statement");
|
||||
vector<string> local_aggrs;
|
||||
|
||||
for ( auto& l : wi->WhenExprLocals() )
|
||||
if ( IsAggr(l->GetType()) )
|
||||
local_aggrs.push_back(IDNameStr(l.get()));
|
||||
|
||||
auto when_lambda = GenExpr(wi->Lambda(), GEN_NATIVE);
|
||||
GenWhenStmt(wi.get(), when_lambda, w->GetLocationInfo(), std::move(local_aggrs));
|
||||
}
|
||||
|
||||
void CPPCompile::GenWhenStmt(const WhenInfo* wi, const std::string& when_lambda, const Location* loc,
|
||||
vector<string> local_aggrs) {
|
||||
auto is_return = wi->IsReturn() ? "true" : "false";
|
||||
auto timeout = wi->TimeoutExpr();
|
||||
auto timeout_val = timeout ? GenExpr(timeout, GEN_NATIVE) : "-1.0";
|
||||
auto loc = w->GetLocationInfo();
|
||||
|
||||
Emit("{ // begin a new scope for internal variables");
|
||||
|
||||
|
@ -331,17 +338,18 @@ void CPPCompile::GenWhenStmt(const WhenStmt* w) {
|
|||
NL();
|
||||
|
||||
Emit("std::vector<ValPtr> CPP__local_aggrs;");
|
||||
for ( auto& l : wi->WhenExprLocals() )
|
||||
if ( IsAggr(l->GetType()) )
|
||||
Emit("CPP__local_aggrs.emplace_back(%s);", IDNameStr(l.get()));
|
||||
for ( auto& la : local_aggrs )
|
||||
Emit("CPP__local_aggrs.emplace_back(%s);", la);
|
||||
|
||||
Emit("CPP__wi->Instantiate(%s);", GenExpr(wi->Lambda(), GEN_NATIVE));
|
||||
Emit("CPP__wi->Instantiate(%s);", when_lambda);
|
||||
|
||||
// We need a new frame for the trigger to unambiguously associate
|
||||
// with, in case we're called multiple times with our existing frame.
|
||||
Emit("auto new_frame = make_intrusive<Frame>(0, nullptr, nullptr);");
|
||||
Emit("auto curr_t = f__CPP->GetTrigger();");
|
||||
Emit("auto curr_assoc = f__CPP->GetTriggerAssoc();");
|
||||
if ( ! ret_type || ret_type->Tag() == TYPE_VOID )
|
||||
Emit("// Note, the following works even if curr_t is nil.");
|
||||
Emit("new_frame->SetTrigger({NewRef{}, curr_t});");
|
||||
Emit("new_frame->SetTriggerAssoc(curr_assoc);");
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue