the bulk of the compiler

This commit is contained in:
Vern Paxson 2021-04-19 16:32:04 -07:00
parent 158e82a2c1
commit 863be9436b
40 changed files with 7730 additions and 0 deletions

View file

@ -0,0 +1,247 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include "zeek/script_opt/CPP/Compile.h"
namespace zeek::detail {
void CPPCompile::CompileFunc(const FuncInfo& func)
{
if ( ! IsCompilable(func) )
return;
auto fname = Canonicalize(BodyName(func).c_str()) + "_zf";
auto pf = func.Profile();
auto f = func.Func();
auto body = func.Body();
DefineBody(f->GetType(), pf, fname, body, nullptr, f->Flavor());
}
void CPPCompile::CompileLambda(const LambdaExpr* l, const ProfileFunc* pf)
{
auto lname = Canonicalize(l->Name().c_str()) + "_lb";
auto body = l->Ingredients().body;
auto l_id = l->Ingredients().id;
auto& ids = l->OuterIDs();
DefineBody(l_id->GetType<FuncType>(), pf, lname, body, &ids,
FUNC_FLAVOR_FUNCTION);
}
void CPPCompile::GenInvokeBody(const std::string& fname, const TypePtr& t,
const std::string& args)
{
auto call = fname + "(" + args + ")";
if ( ! t || t->Tag() == TYPE_VOID )
{
Emit("%s;", call);
Emit("return nullptr;");
}
else
Emit("return %s;", NativeToGT(call, t, GEN_VAL_PTR));
}
void CPPCompile::DefineBody(const FuncTypePtr& ft, const ProfileFunc* pf,
const std::string& fname, const StmtPtr& body,
const IDPList* lambda_ids, FunctionFlavor flavor)
{
locals.clear();
params.clear();
body_name = fname;
ret_type = ft->Yield();
in_hook = flavor == FUNC_FLAVOR_HOOK;
auto ret_type_str = in_hook ? "bool" : FullTypeName(ret_type);
for ( const auto& p : pf->Params() )
params.emplace(p);
NL();
Emit("%s %s(%s)", ret_type_str, fname, ParamDecl(ft, lambda_ids, pf));
StartBlock();
// Deal with "any" parameters, if any.
TranslateAnyParams(ft, pf);
// Make sure that any events referred to in this function have
// been initialized.
InitializeEvents(pf);
// Create the local variables.
DeclareLocals(pf, lambda_ids);
GenStmt(body);
if ( in_hook )
{
Emit("return true;");
in_hook = false;
}
// Seatbelts for running off the end of a function that's supposed
// to return a non-native type.
if ( ! IsNativeType(ret_type) )
Emit("return nullptr;");
EndBlock();
}
void CPPCompile::TranslateAnyParams(const FuncTypePtr& ft, const ProfileFunc* pf)
{
const auto& formals = ft->Params();
int n = formals->NumFields();
for ( auto i = 0; i < n; ++i )
{
const auto& t = formals->GetFieldType(i);
if ( t->Tag() != TYPE_ANY )
// Not a relevant parameter.
continue;
auto param_id = FindParam(i, pf);
if ( ! param_id )
// Parameter isn't used, skip it.
continue;
const auto& pt = param_id->GetType();
if ( pt->Tag() == TYPE_ANY )
// It's already "any", nothing more to do.
continue;
auto any_i = std::string("any_param__CPP_") + Fmt(i);
Emit("%s %s = %s;", FullTypeName(pt), LocalName(param_id),
GenericValPtrToGT(any_i, pt, GEN_NATIVE));
}
}
void CPPCompile::InitializeEvents(const ProfileFunc* pf)
{
// Make sure that any events referred to in this function have
// been initialized. We have to do this dynamically because it
// depends on whether the final script using the compiled code
// happens to load the associated event handler
for ( const auto& e : pf->Events() )
{
auto ev_name = globals[e] + "_ev";
// Create a scope so we don't have to individualize the
// variables.
Emit("{");
Emit("static bool did_init = false;");
Emit("if ( ! did_init )");
StartBlock();
// We do both a Lookup and a Register because only the latter
// returns an EventHandlerPtr, sigh.
Emit("if ( event_registry->Lookup(\"%s\") )", e);
StartBlock();
Emit("%s = event_registry->Register(\"%s\");", ev_name.c_str(), e);
EndBlock();
Emit("did_init = true;");
EndBlock();
Emit("}");
}
}
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.
std::unordered_set<const ID*> lambda_set;
if ( lambda_ids )
for ( auto li : *lambda_ids )
lambda_set.insert(li);
const auto& ls = pf->Locals();
// Track whether we generated a declaration. This is just for
// tidiness in the output.
bool did_decl = false;
for ( const auto& l : ls )
{
auto ln = LocalName(l);
if ( lambda_set.count(l) > 0 )
// No need to declare these, they're passed in as
// parameters.
ln = lambda_names[l];
else if ( params.count(l) == 0 )
{ // Not a parameter, so must be a local.
Emit("%s %s;", FullTypeName(l->GetType()), ln);
did_decl = true;
}
locals.emplace(l, ln);
}
if ( did_decl )
NL();
}
std::string CPPCompile::BodyName(const FuncInfo& func)
{
const auto& f = func.Func();
const auto& bodies = f->GetBodies();
std::string fname = f->Name();
if ( bodies.size() == 1 )
return fname;
// Make the name distinct-per-body.
const auto& body = func.Body();
int i;
for ( i = 0; i < bodies.size(); ++i )
if ( bodies[i].stmts == body )
break;
if ( i >= bodies.size() )
reporter->InternalError("can't find body in CPPCompile::BodyName");
return fname + "__" + Fmt(i);
}
std::string CPPCompile::GenArgs(const RecordTypePtr& params, const Expr* e)
{
const auto& exprs = e->AsListExpr()->Exprs();
std::string gen;
int n = exprs.size();
for ( auto i = 0; i < n; ++i )
{
auto e_i = exprs[i];
auto gt = GEN_NATIVE;
const auto& param_t = params->GetFieldType(i);
bool param_any = param_t->Tag() == TYPE_ANY;
bool arg_any = e_i->GetType()->Tag() == TYPE_ANY;
if ( param_any && ! arg_any )
gt = GEN_VAL_PTR;
auto expr_gen = GenExpr(e_i, gt);
if ( ! param_any && arg_any )
expr_gen = GenericValPtrToGT(expr_gen, param_t, GEN_NATIVE);
gen = gen + expr_gen;
if ( i < n - 1 )
gen += ", ";
}
return gen;
}
} // zeek::detail