mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
extensive rewrite of generation & execution of run-time initialization
This commit is contained in:
parent
bc3bf4ea6c
commit
e1a760e674
26 changed files with 3459 additions and 1580 deletions
|
@ -22,7 +22,7 @@ void CPPCompile::DeclareFunc(const FuncInfo& func)
|
|||
const auto& body = func.Body();
|
||||
auto priority = func.Priority();
|
||||
|
||||
DeclareSubclass(f->GetType(), pf, fname, body, priority, nullptr, f->Flavor());
|
||||
CreateFunction(f->GetType(), pf, fname, body, priority, nullptr, f->Flavor());
|
||||
|
||||
if ( f->GetBodies().size() == 1 )
|
||||
compiled_simple_funcs[f->Name()] = fname;
|
||||
|
@ -40,17 +40,88 @@ void CPPCompile::DeclareLambda(const LambdaExpr* l, const ProfileFunc* pf)
|
|||
for ( auto id : ids )
|
||||
lambda_names[id] = LocalName(id);
|
||||
|
||||
DeclareSubclass(l_id->GetType<FuncType>(), pf, lname, body, 0, l, FUNC_FLAVOR_FUNCTION);
|
||||
CreateFunction(l_id->GetType<FuncType>(), pf, lname, body, 0, l, FUNC_FLAVOR_FUNCTION);
|
||||
}
|
||||
|
||||
void CPPCompile::DeclareSubclass(const FuncTypePtr& ft, const ProfileFunc* pf, const string& fname,
|
||||
const StmtPtr& body, int priority, const LambdaExpr* l,
|
||||
FunctionFlavor flavor)
|
||||
void CPPCompile::CreateFunction(const FuncTypePtr& ft, const ProfileFunc* pf, const string& fname,
|
||||
const StmtPtr& body, 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;
|
||||
|
||||
string args = BindArgs(ft, lambda_ids);
|
||||
|
||||
auto yt_decl = in_hook ? "bool" : FullTypeName(yt);
|
||||
|
||||
vector<string> p_types;
|
||||
GatherParamTypes(p_types, ft, lambda_ids, pf);
|
||||
|
||||
string cast = string(yt_decl) + "(*)(";
|
||||
for ( auto& pt : p_types )
|
||||
cast += pt + ", ";
|
||||
cast += string("Frame*)");
|
||||
|
||||
// We need to distinguish between hooks and non-hooks that happen
|
||||
// to have matching type signatures. They'll be equivalent if they
|
||||
// have identical cast's. To keep them separate, we cheat and
|
||||
// make hook casts different, string-wise, without altering their
|
||||
// semantics.
|
||||
if ( in_hook )
|
||||
cast += " ";
|
||||
|
||||
func_index[fname] = cast;
|
||||
|
||||
if ( casting_index.count(cast) == 0 )
|
||||
{
|
||||
casting_index[cast] = func_casting_glue.size();
|
||||
|
||||
DispatchInfo di;
|
||||
di.cast = cast;
|
||||
di.args = args;
|
||||
di.is_hook = in_hook;
|
||||
di.yield = yt;
|
||||
|
||||
func_casting_glue.emplace_back(di);
|
||||
}
|
||||
|
||||
if ( lambda_ids )
|
||||
{
|
||||
DeclareSubclass(ft, pf, fname, args, lambda_ids);
|
||||
BuildLambda(ft, pf, fname, body, l, lambda_ids);
|
||||
EndBlock(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Emit("static %s %s(%s);", yt_decl, fname, ParamDecl(ft, lambda_ids, pf));
|
||||
|
||||
// Track this function as known to have been compiled.
|
||||
// We don't track lambda bodies as compiled because they
|
||||
// can't be instantiated directly without also supplying
|
||||
// the captures. In principle we could make an exception
|
||||
// for lambdas that don't take any arguments, but that
|
||||
// seems potentially more confusing than beneficial.
|
||||
compiled_funcs.emplace(fname);
|
||||
|
||||
auto loc_f = script_specific_filename(body);
|
||||
cf_locs[fname] = loc_f;
|
||||
}
|
||||
|
||||
auto h = pf->HashVal();
|
||||
|
||||
body_hashes[fname] = h;
|
||||
body_priorities[fname] = priority;
|
||||
body_names.emplace(body.get(), fname);
|
||||
|
||||
total_hash = merge_p_hashes(total_hash, h);
|
||||
}
|
||||
|
||||
void CPPCompile::DeclareSubclass(const FuncTypePtr& ft, const ProfileFunc* pf, const string& fname,
|
||||
const string& args, const IDPList* lambda_ids)
|
||||
{
|
||||
const auto& yt = ft->Yield();
|
||||
|
||||
auto yt_decl = in_hook ? "bool" : FullTypeName(yt);
|
||||
|
||||
NL();
|
||||
|
@ -76,8 +147,7 @@ void CPPCompile::DeclareSubclass(const FuncTypePtr& ft, const ProfileFunc* pf, c
|
|||
}
|
||||
}
|
||||
|
||||
Emit("%s_cl(const char* name%s) : CPPStmt(name)%s { }", fname, addl_args.c_str(),
|
||||
inits.c_str());
|
||||
Emit("%s_cl(const char* name%s) : CPPStmt(name)%s { }", fname, addl_args, inits);
|
||||
|
||||
// An additional constructor just used to generate place-holder
|
||||
// instances, due to the mis-design that lambdas are identified
|
||||
|
@ -92,7 +162,7 @@ void CPPCompile::DeclareSubclass(const FuncTypePtr& ft, const ProfileFunc* pf, c
|
|||
|
||||
if ( in_hook )
|
||||
{
|
||||
Emit("if ( ! %s(%s) )", fname, BindArgs(ft, lambda_ids));
|
||||
Emit("if ( ! %s(%s) )", fname, args);
|
||||
StartBlock();
|
||||
Emit("flow = FLOW_BREAK;");
|
||||
EndBlock();
|
||||
|
@ -100,42 +170,36 @@ void CPPCompile::DeclareSubclass(const FuncTypePtr& ft, const ProfileFunc* pf, c
|
|||
}
|
||||
|
||||
else if ( IsNativeType(yt) )
|
||||
GenInvokeBody(fname, yt, BindArgs(ft, lambda_ids));
|
||||
GenInvokeBody(fname, yt, args);
|
||||
|
||||
else
|
||||
Emit("return %s(%s);", fname, BindArgs(ft, lambda_ids));
|
||||
Emit("return %s(%s);", fname, args);
|
||||
|
||||
EndBlock();
|
||||
}
|
||||
|
||||
if ( lambda_ids )
|
||||
BuildLambda(ft, pf, fname, body, l, lambda_ids);
|
||||
else
|
||||
{
|
||||
// Track this function as known to have been compiled.
|
||||
// We don't track lambda bodies as compiled because they
|
||||
// can't be instantiated directly without also supplying
|
||||
// the captures. In principle we could make an exception
|
||||
// for lambdas that don't take any arguments, but that
|
||||
// seems potentially more confusing than beneficial.
|
||||
compiled_funcs.emplace(fname);
|
||||
|
||||
auto loc_f = script_specific_filename(body);
|
||||
cf_locs[fname] = loc_f;
|
||||
|
||||
// Some guidance for those looking through the generated code.
|
||||
Emit("// compiled body for: %s", loc_f);
|
||||
}
|
||||
|
||||
EndBlock(true);
|
||||
|
||||
auto h = pf->HashVal();
|
||||
|
||||
body_hashes[fname] = h;
|
||||
body_priorities[fname] = priority;
|
||||
body_names.emplace(body.get(), fname);
|
||||
names_to_bodies.emplace(fname, body.get());
|
||||
|
||||
total_hash = merge_p_hashes(total_hash, h);
|
||||
void CPPCompile::DeclareDynCPPStmt()
|
||||
{
|
||||
Emit("// A version of CPPStmt that manages a function pointer and");
|
||||
Emit("// dynamically casts it to a given type to call it via Exec().");
|
||||
Emit("// We will later generate a custom Exec method to support this");
|
||||
Emit("// dispatch. All of this is ugly, and only needed because clang");
|
||||
Emit("// goes nuts (super slow) in the face of thousands of templates");
|
||||
Emit("// in a given context (initializers, or a function body).");
|
||||
Emit("class CPPDynStmt : public CPPStmt");
|
||||
Emit("\t{");
|
||||
Emit("public:");
|
||||
Emit("\tCPPDynStmt(const char* _name, void* _func, int _type_signature) : CPPStmt(_name), "
|
||||
"func(_func), type_signature(_type_signature) { }");
|
||||
Emit("\tValPtr Exec(Frame* f, StmtFlowType& flow) override final;");
|
||||
Emit("private:");
|
||||
Emit("\t// The function to call in Exec().");
|
||||
Emit("\tvoid* func;");
|
||||
Emit("\t// Used via a switch in the dynamically-generated Exec() method");
|
||||
Emit("\t// to cast func to the write type, and to call it with the");
|
||||
Emit("\t// right arguments pulled out of the frame.");
|
||||
Emit("\tint type_signature;");
|
||||
Emit("\t};");
|
||||
}
|
||||
|
||||
void CPPCompile::BuildLambda(const FuncTypePtr& ft, const ProfileFunc* pf, const string& fname,
|
||||
|
@ -146,28 +210,17 @@ void CPPCompile::BuildLambda(const FuncTypePtr& ft, const ProfileFunc* pf, const
|
|||
{
|
||||
auto name = lambda_names[id];
|
||||
auto tn = FullTypeName(id->GetType());
|
||||
Emit("%s %s;", tn, name.c_str());
|
||||
Emit("%s %s;", tn, name);
|
||||
}
|
||||
|
||||
// Generate initialization to create and register the lambda.
|
||||
auto literal_name = string("\"") + l->Name() + "\"";
|
||||
auto instantiate = string("make_intrusive<") + fname + "_cl>(" + literal_name + ")";
|
||||
auto h = pf->HashVal();
|
||||
auto nl = lambda_ids->length();
|
||||
bool has_captures = nl > 0;
|
||||
|
||||
int nl = lambda_ids->length();
|
||||
auto h = Fmt(pf->HashVal());
|
||||
auto has_captures = nl > 0 ? "true" : "false";
|
||||
auto l_init = string("register_lambda__CPP(") + instantiate + ", " + h + ", \"" + l->Name() +
|
||||
"\", " + GenTypeName(ft) + ", " + has_captures + ");";
|
||||
|
||||
AddInit(l, l_init);
|
||||
NoteInitDependency(l, TypeRep(ft));
|
||||
|
||||
// Make the lambda's body's initialization depend on the lambda's
|
||||
// initialization. That way GenFuncVarInits() can generate
|
||||
// initializations with the assurance that the associated body
|
||||
// hashes will have been registered.
|
||||
AddInit(body.get());
|
||||
NoteInitDependency(body.get(), l);
|
||||
auto gi = make_shared<LambdaRegistrationInfo>(this, l->Name(), ft, fname + "_cl", h,
|
||||
has_captures);
|
||||
lambda_reg_info->AddInstance(gi);
|
||||
|
||||
// Generate method to extract the lambda captures from a deserialized
|
||||
// Frame object.
|
||||
|
@ -237,17 +290,71 @@ string CPPCompile::BindArgs(const FuncTypePtr& ft, const IDPList* lambda_ids)
|
|||
string CPPCompile::ParamDecl(const FuncTypePtr& ft, const IDPList* lambda_ids,
|
||||
const ProfileFunc* pf)
|
||||
{
|
||||
const auto& params = ft->Params();
|
||||
int n = params->NumFields();
|
||||
vector<string> p_types;
|
||||
vector<string> p_names;
|
||||
|
||||
GatherParamTypes(p_types, ft, lambda_ids, pf);
|
||||
GatherParamNames(p_names, ft, lambda_ids, pf);
|
||||
|
||||
ASSERT(p_types.size() == p_names.size());
|
||||
|
||||
string decl;
|
||||
|
||||
for ( auto i = 0U; i < p_types.size(); ++i )
|
||||
decl += p_types[i] + " " + p_names[i] + ", ";
|
||||
|
||||
// Add in the declaration of the frame.
|
||||
return decl + "Frame* f__CPP";
|
||||
}
|
||||
|
||||
void CPPCompile::GatherParamTypes(vector<string>& p_types, const FuncTypePtr& ft,
|
||||
const IDPList* lambda_ids, const ProfileFunc* pf)
|
||||
{
|
||||
const auto& params = ft->Params();
|
||||
int n = params->NumFields();
|
||||
|
||||
for ( auto i = 0; i < n; ++i )
|
||||
{
|
||||
const auto& t = params->GetFieldType(i);
|
||||
auto tn = FullTypeName(t);
|
||||
auto param_id = FindParam(i, pf);
|
||||
string fn;
|
||||
|
||||
if ( IsNativeType(t) )
|
||||
// Native types are always pass-by-value.
|
||||
p_types.emplace_back(tn);
|
||||
else
|
||||
{
|
||||
if ( param_id && pf->Assignees().count(param_id) > 0 )
|
||||
// We modify the parameter.
|
||||
p_types.emplace_back(tn);
|
||||
else
|
||||
// Not modified, so pass by const reference.
|
||||
p_types.emplace_back(string("const ") + tn + "&");
|
||||
}
|
||||
}
|
||||
|
||||
if ( lambda_ids )
|
||||
// Add the captures as additional parameters.
|
||||
for ( auto& id : *lambda_ids )
|
||||
{
|
||||
const auto& t = id->GetType();
|
||||
auto tn = FullTypeName(t);
|
||||
|
||||
// Allow the captures to be modified.
|
||||
p_types.emplace_back(string(tn) + "& ");
|
||||
}
|
||||
}
|
||||
|
||||
void CPPCompile::GatherParamNames(vector<string>& p_names, const FuncTypePtr& ft,
|
||||
const IDPList* lambda_ids, const ProfileFunc* pf)
|
||||
{
|
||||
const auto& params = ft->Params();
|
||||
int n = params->NumFields();
|
||||
|
||||
for ( auto i = 0; i < n; ++i )
|
||||
{
|
||||
const auto& t = params->GetFieldType(i);
|
||||
auto param_id = FindParam(i, pf);
|
||||
|
||||
if ( param_id )
|
||||
{
|
||||
|
@ -255,50 +362,22 @@ string CPPCompile::ParamDecl(const FuncTypePtr& ft, const IDPList* lambda_ids,
|
|||
// We'll need to translate the parameter
|
||||
// from its current representation to
|
||||
// type "any".
|
||||
fn = string("any_param__CPP_") + Fmt(i);
|
||||
p_names.emplace_back(string("any_param__CPP_") + Fmt(i));
|
||||
else
|
||||
fn = LocalName(param_id);
|
||||
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.
|
||||
fn = string("unused_param__CPP_") + Fmt(i);
|
||||
|
||||
if ( IsNativeType(t) )
|
||||
// Native types are always pass-by-value.
|
||||
decl = decl + tn + " " + fn;
|
||||
else
|
||||
{
|
||||
if ( param_id && pf->Assignees().count(param_id) > 0 )
|
||||
// We modify the parameter.
|
||||
decl = decl + tn + " " + fn;
|
||||
else
|
||||
// Not modified, so pass by const reference.
|
||||
decl = decl + "const " + tn + "& " + fn;
|
||||
}
|
||||
|
||||
decl += ", ";
|
||||
// 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));
|
||||
}
|
||||
|
||||
if ( lambda_ids )
|
||||
{
|
||||
// Add the captures as additional parameters.
|
||||
for ( auto& id : *lambda_ids )
|
||||
{
|
||||
auto name = lambda_names[id];
|
||||
const auto& t = id->GetType();
|
||||
auto tn = FullTypeName(t);
|
||||
|
||||
// Allow the captures to be modified.
|
||||
decl = decl + tn + "& " + name + ", ";
|
||||
}
|
||||
}
|
||||
|
||||
// Add in the declaration of the frame.
|
||||
return decl + "Frame* f__CPP";
|
||||
p_names.emplace_back(lambda_names[id]);
|
||||
}
|
||||
|
||||
const ID* CPPCompile::FindParam(int i, const ProfileFunc* pf)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue