Reformat Zeek in Spicy style

This largely copies over Spicy's `.clang-format` configuration file. The
one place where we deviate is header include order since Zeek depends on
headers being included in a certain order.
This commit is contained in:
Benjamin Bannier 2023-10-10 21:13:34 +02:00
parent 7b8e7ed72c
commit f5a76c1aed
786 changed files with 131714 additions and 153609 deletions

View file

@ -2,151 +2,116 @@
#include "zeek/script_opt/CPP/Compile.h"
namespace zeek::detail
{
namespace zeek::detail {
using namespace std;
shared_ptr<CPP_InitInfo> CPPCompile::RegisterAttributes(const AttributesPtr& attrs)
{
if ( ! attrs )
return nullptr;
shared_ptr<CPP_InitInfo> CPPCompile::RegisterAttributes(const AttributesPtr& attrs) {
if ( ! attrs )
return nullptr;
auto a = attrs.get();
auto pa = processed_attrs.find(a);
auto a = attrs.get();
auto pa = processed_attrs.find(a);
if ( pa != processed_attrs.end() )
return pa->second;
if ( pa != processed_attrs.end() )
return pa->second;
attributes.AddKey(attrs, pfs.HashAttrs(attrs));
attributes.AddKey(attrs, pfs.HashAttrs(attrs));
// The cast is just so we can make an IntrusivePtr.
auto a_rep = const_cast<Attributes*>(attributes.GetRep(attrs));
if ( a_rep != a )
{
AttributesPtr a_rep_ptr = {NewRef{}, a_rep};
processed_attrs[a] = RegisterAttributes(a_rep_ptr);
return processed_attrs[a];
}
// The cast is just so we can make an IntrusivePtr.
auto a_rep = const_cast<Attributes*>(attributes.GetRep(attrs));
if ( a_rep != a ) {
AttributesPtr a_rep_ptr = {NewRef{}, a_rep};
processed_attrs[a] = RegisterAttributes(a_rep_ptr);
return processed_attrs[a];
}
for ( const auto& a : attrs->GetAttrs() )
(void)RegisterAttr(a);
for ( const auto& a : attrs->GetAttrs() )
(void)RegisterAttr(a);
shared_ptr<CPP_InitInfo> gi = make_shared<AttrsInfo>(this, attrs);
attrs_info->AddInstance(gi);
processed_attrs[a] = gi;
shared_ptr<CPP_InitInfo> gi = make_shared<AttrsInfo>(this, attrs);
attrs_info->AddInstance(gi);
processed_attrs[a] = gi;
return gi;
}
return gi;
}
shared_ptr<CPP_InitInfo> CPPCompile::RegisterAttr(const AttrPtr& attr)
{
auto a = attr.get();
auto pa = processed_attr.find(a);
shared_ptr<CPP_InitInfo> CPPCompile::RegisterAttr(const AttrPtr& attr) {
auto a = attr.get();
auto pa = processed_attr.find(a);
if ( pa != processed_attr.end() )
return pa->second;
if ( pa != processed_attr.end() )
return pa->second;
const auto& e = a->GetExpr();
if ( e && ! IsSimpleInitExpr(e) )
{
auto h = p_hash(e);
const auto& e = a->GetExpr();
if ( e && ! IsSimpleInitExpr(e) ) {
auto h = p_hash(e);
// Include the type in the hash, otherwise expressions
// like "vector()" are ambiguous.
h = merge_p_hashes(h, p_hash(e->GetType()));
// Include the type in the hash, otherwise expressions
// like "vector()" are ambiguous.
h = merge_p_hashes(h, p_hash(e->GetType()));
init_exprs.AddKey(e, h);
}
init_exprs.AddKey(e, h);
}
auto gi = make_shared<AttrInfo>(this, attr);
attr_info->AddInstance(gi);
processed_attr[a] = gi;
auto gi = make_shared<AttrInfo>(this, attr);
attr_info->AddInstance(gi);
processed_attr[a] = gi;
return gi;
}
return gi;
}
void CPPCompile::BuildAttrs(const AttributesPtr& attrs, string& attr_tags, string& attr_vals)
{
if ( attrs )
{
for ( const auto& a : attrs->GetAttrs() )
{
if ( attr_tags.size() > 0 )
{
attr_tags += ", ";
attr_vals += ", ";
}
void CPPCompile::BuildAttrs(const AttributesPtr& attrs, string& attr_tags, string& attr_vals) {
if ( attrs ) {
for ( const auto& a : attrs->GetAttrs() ) {
if ( attr_tags.size() > 0 ) {
attr_tags += ", ";
attr_vals += ", ";
}
attr_tags += Fmt(int(a->Tag()));
attr_tags += Fmt(int(a->Tag()));
const auto& e = a->GetExpr();
const auto& e = a->GetExpr();
if ( e )
attr_vals += GenExpr(e, GEN_VAL_PTR, false);
else
attr_vals += "nullptr";
}
}
if ( e )
attr_vals += GenExpr(e, GEN_VAL_PTR, false);
else
attr_vals += "nullptr";
}
}
attr_tags = string("{") + attr_tags + "}";
attr_vals = string("{") + attr_vals + "}";
}
attr_tags = string("{") + attr_tags + "}";
attr_vals = string("{") + attr_vals + "}";
}
const char* CPPCompile::AttrName(AttrTag t)
{
switch ( t )
{
case ATTR_OPTIONAL:
return "ATTR_OPTIONAL";
case ATTR_DEFAULT:
return "ATTR_DEFAULT";
case ATTR_REDEF:
return "ATTR_REDEF";
case ATTR_ADD_FUNC:
return "ATTR_ADD_FUNC";
case ATTR_DEL_FUNC:
return "ATTR_DEL_FUNC";
case ATTR_EXPIRE_FUNC:
return "ATTR_EXPIRE_FUNC";
case ATTR_EXPIRE_READ:
return "ATTR_EXPIRE_READ";
case ATTR_EXPIRE_WRITE:
return "ATTR_EXPIRE_WRITE";
case ATTR_EXPIRE_CREATE:
return "ATTR_EXPIRE_CREATE";
case ATTR_RAW_OUTPUT:
return "ATTR_RAW_OUTPUT";
case ATTR_PRIORITY:
return "ATTR_PRIORITY";
case ATTR_GROUP:
return "ATTR_GROUP";
case ATTR_LOG:
return "ATTR_LOG";
case ATTR_ERROR_HANDLER:
return "ATTR_ERROR_HANDLER";
case ATTR_TYPE_COLUMN:
return "ATTR_TYPE_COLUMN";
case ATTR_TRACKED:
return "ATTR_TRACKED";
case ATTR_ON_CHANGE:
return "ATTR_ON_CHANGE";
case ATTR_BROKER_STORE:
return "ATTR_BROKER_STORE";
case ATTR_BROKER_STORE_ALLOW_COMPLEX:
return "ATTR_BROKER_STORE_ALLOW_COMPLEX";
case ATTR_BACKEND:
return "ATTR_BACKEND";
case ATTR_DEPRECATED:
return "ATTR_DEPRECATED";
case ATTR_IS_ASSIGNED:
return "ATTR_IS_ASSIGNED";
case ATTR_IS_USED:
return "ATTR_IS_USED";
const char* CPPCompile::AttrName(AttrTag t) {
switch ( t ) {
case ATTR_OPTIONAL: return "ATTR_OPTIONAL";
case ATTR_DEFAULT: return "ATTR_DEFAULT";
case ATTR_REDEF: return "ATTR_REDEF";
case ATTR_ADD_FUNC: return "ATTR_ADD_FUNC";
case ATTR_DEL_FUNC: return "ATTR_DEL_FUNC";
case ATTR_EXPIRE_FUNC: return "ATTR_EXPIRE_FUNC";
case ATTR_EXPIRE_READ: return "ATTR_EXPIRE_READ";
case ATTR_EXPIRE_WRITE: return "ATTR_EXPIRE_WRITE";
case ATTR_EXPIRE_CREATE: return "ATTR_EXPIRE_CREATE";
case ATTR_RAW_OUTPUT: return "ATTR_RAW_OUTPUT";
case ATTR_PRIORITY: return "ATTR_PRIORITY";
case ATTR_GROUP: return "ATTR_GROUP";
case ATTR_LOG: return "ATTR_LOG";
case ATTR_ERROR_HANDLER: return "ATTR_ERROR_HANDLER";
case ATTR_TYPE_COLUMN: return "ATTR_TYPE_COLUMN";
case ATTR_TRACKED: return "ATTR_TRACKED";
case ATTR_ON_CHANGE: return "ATTR_ON_CHANGE";
case ATTR_BROKER_STORE: return "ATTR_BROKER_STORE";
case ATTR_BROKER_STORE_ALLOW_COMPLEX: return "ATTR_BROKER_STORE_ALLOW_COMPLEX";
case ATTR_BACKEND: return "ATTR_BACKEND";
case ATTR_DEPRECATED: return "ATTR_DEPRECATED";
case ATTR_IS_ASSIGNED: return "ATTR_IS_ASSIGNED";
case ATTR_IS_USED: return "ATTR_IS_USED";
default:
return "<busted>";
}
}
default: return "<busted>";
}
}
} // zeek::detail
} // namespace zeek::detail

View file

@ -4,16 +4,14 @@
#pragma once
namespace zeek::detail
{
namespace zeek::detail {
enum AttrExprType
{
AE_NONE, // attribute doesn't have an expression
AE_CONST, // easy expression - a constant (ConstExpr)
AE_NAME, // easy - a global (NameExpr)
AE_RECORD, // an empty record cast to a given type
AE_CALL, // everything else - requires a lambda, essentially
};
enum AttrExprType {
AE_NONE, // attribute doesn't have an expression
AE_CONST, // easy expression - a constant (ConstExpr)
AE_NAME, // easy - a global (NameExpr)
AE_RECORD, // an empty record cast to a given type
AE_CALL, // everything else - requires a lambda, essentially
};
} // zeek::detail
} // namespace zeek::detail

File diff suppressed because it is too large Load diff

View file

@ -6,159 +6,113 @@
using namespace std;
namespace zeek::detail
{
namespace zeek::detail {
shared_ptr<CPP_InitInfo> CPPCompile::RegisterConstant(const ValPtr& vp, int& consts_offset)
{
// Make sure the value pointer, which might be transient
// in construction, sticks around so we can track its
// value.
cv_indices.push_back(vp);
shared_ptr<CPP_InitInfo> CPPCompile::RegisterConstant(const ValPtr& vp, int& consts_offset) {
// Make sure the value pointer, which might be transient
// in construction, sticks around so we can track its
// value.
cv_indices.push_back(vp);
auto v = vp.get();
auto cv = const_vals.find(v);
auto v = vp.get();
auto cv = const_vals.find(v);
if ( cv != const_vals.end() )
{
// Already did this one.
consts_offset = const_offsets[v];
return cv->second;
}
if ( cv != const_vals.end() ) {
// Already did this one.
consts_offset = const_offsets[v];
return cv->second;
}
// Formulate a key that's unique per distinct constant.
// Formulate a key that's unique per distinct constant.
const auto& t = v->GetType();
string c_desc;
const auto& t = v->GetType();
string c_desc;
if ( t->Tag() == TYPE_STRING )
{
// We can't rely on these to render with consistent
// escaping, sigh. Just use the raw string.
auto s = v->AsString();
auto b = (const char*)(s->Bytes());
c_desc = string(b, s->Len()) + "string";
}
else
{
ODesc d;
v->Describe(&d);
if ( t->Tag() == TYPE_STRING ) {
// We can't rely on these to render with consistent
// escaping, sigh. Just use the raw string.
auto s = v->AsString();
auto b = (const char*)(s->Bytes());
c_desc = string(b, s->Len()) + "string";
}
else {
ODesc d;
v->Describe(&d);
// Don't confuse constants of different types that happen to
// render the same.
t->Describe(&d);
// Don't confuse constants of different types that happen to
// render the same.
t->Describe(&d);
// Likewise, tables that have attributes.
if ( t->Tag() == TYPE_TABLE )
{
const auto& attrs = v->AsTableVal()->GetAttrs();
if ( attrs )
attrs->Describe(&d);
else
d.Add("<no-attrs>");
}
// Likewise, tables that have attributes.
if ( t->Tag() == TYPE_TABLE ) {
const auto& attrs = v->AsTableVal()->GetAttrs();
if ( attrs )
attrs->Describe(&d);
else
d.Add("<no-attrs>");
}
c_desc = d.Description();
}
c_desc = d.Description();
}
auto c = constants.find(c_desc);
if ( c != constants.end() )
{
const_vals[v] = c->second;
consts_offset = const_offsets[v] = constants_offsets[c_desc];
return c->second;
}
auto c = constants.find(c_desc);
if ( c != constants.end() ) {
const_vals[v] = c->second;
consts_offset = const_offsets[v] = constants_offsets[c_desc];
return c->second;
}
auto tag = t->Tag();
auto const_name = const_info[tag]->NextName();
shared_ptr<CPP_InitInfo> gi;
auto tag = t->Tag();
auto const_name = const_info[tag]->NextName();
shared_ptr<CPP_InitInfo> gi;
switch ( tag )
{
case TYPE_BOOL:
gi = make_shared<BasicConstInfo>(vp->AsBool() ? "true" : "false");
break;
switch ( tag ) {
case TYPE_BOOL: gi = make_shared<BasicConstInfo>(vp->AsBool() ? "true" : "false"); break;
case TYPE_INT:
gi = make_shared<BasicConstInfo>(to_string(vp->AsInt()));
break;
case TYPE_INT: gi = make_shared<BasicConstInfo>(to_string(vp->AsInt())); break;
case TYPE_COUNT:
gi = make_shared<BasicConstInfo>(to_string(vp->AsCount()) + "ULL");
break;
case TYPE_COUNT: gi = make_shared<BasicConstInfo>(to_string(vp->AsCount()) + "ULL"); break;
case TYPE_DOUBLE:
gi = make_shared<BasicConstInfo>(to_string(vp->AsDouble()));
break;
case TYPE_DOUBLE: gi = make_shared<BasicConstInfo>(to_string(vp->AsDouble())); break;
case TYPE_TIME:
gi = make_shared<BasicConstInfo>(to_string(vp->AsDouble()));
break;
case TYPE_TIME: gi = make_shared<BasicConstInfo>(to_string(vp->AsDouble())); break;
case TYPE_INTERVAL:
gi = make_shared<BasicConstInfo>(to_string(vp->AsDouble()));
break;
case TYPE_INTERVAL: gi = make_shared<BasicConstInfo>(to_string(vp->AsDouble())); break;
case TYPE_ADDR:
gi = make_shared<DescConstInfo>(this, vp);
break;
case TYPE_ADDR: gi = make_shared<DescConstInfo>(this, vp); break;
case TYPE_SUBNET:
gi = make_shared<DescConstInfo>(this, vp);
break;
case TYPE_SUBNET: gi = make_shared<DescConstInfo>(this, vp); break;
case TYPE_ENUM:
gi = make_shared<EnumConstInfo>(this, vp);
break;
case TYPE_ENUM: gi = make_shared<EnumConstInfo>(this, vp); break;
case TYPE_STRING:
gi = make_shared<StringConstInfo>(this, vp);
break;
case TYPE_STRING: gi = make_shared<StringConstInfo>(this, vp); break;
case TYPE_PATTERN:
gi = make_shared<PatternConstInfo>(this, vp);
break;
case TYPE_PATTERN: gi = make_shared<PatternConstInfo>(this, vp); break;
case TYPE_PORT:
gi = make_shared<PortConstInfo>(vp);
break;
case TYPE_PORT: gi = make_shared<PortConstInfo>(vp); break;
case TYPE_LIST:
gi = make_shared<ListConstInfo>(this, vp);
break;
case TYPE_LIST: gi = make_shared<ListConstInfo>(this, vp); break;
case TYPE_VECTOR:
gi = make_shared<VectorConstInfo>(this, vp);
break;
case TYPE_VECTOR: gi = make_shared<VectorConstInfo>(this, vp); break;
case TYPE_RECORD:
gi = make_shared<RecordConstInfo>(this, vp);
break;
case TYPE_RECORD: gi = make_shared<RecordConstInfo>(this, vp); break;
case TYPE_TABLE:
gi = make_shared<TableConstInfo>(this, vp);
break;
case TYPE_TABLE: gi = make_shared<TableConstInfo>(this, vp); break;
case TYPE_FILE:
gi = make_shared<FileConstInfo>(this, vp);
break;
case TYPE_FILE: gi = make_shared<FileConstInfo>(this, vp); break;
case TYPE_FUNC:
gi = make_shared<FuncConstInfo>(this, vp);
break;
case TYPE_FUNC: gi = make_shared<FuncConstInfo>(this, vp); break;
default:
reporter->InternalError("bad constant type in CPPCompile::AddConstant");
break;
}
default: reporter->InternalError("bad constant type in CPPCompile::AddConstant"); break;
}
const_info[tag]->AddInstance(gi);
const_vals[v] = constants[c_desc] = gi;
const_info[tag]->AddInstance(gi);
const_vals[v] = constants[c_desc] = gi;
consts_offset = const_offsets[v] = constants_offsets[c_desc] = consts.size();
consts.emplace_back(tag, gi->Offset());
consts_offset = const_offsets[v] = constants_offsets[c_desc] = consts.size();
consts.emplace_back(tag, gi->Offset());
return gi;
}
return gi;
}
} // zeek::detail
} // namespace zeek::detail

View file

@ -2,390 +2,360 @@
#include "zeek/script_opt/CPP/Compile.h"
namespace zeek::detail
{
namespace zeek::detail {
using namespace std;
void CPPCompile::DeclareFunc(const FuncInfo& func)
{
if ( ! IsCompilable(func) )
return;
auto fname = Canonicalize(BodyName(func).c_str()) + "_zf";
auto pf = func.Profile();
auto f = func.Func();
const auto& body = func.Body();
auto priority = func.Priority();
CreateFunction(f->GetType(), pf, fname, body, priority, nullptr, f->Flavor());
if ( f->GetBodies().size() == 1 )
compiled_simple_funcs[f->Name()] = fname;
}
void CPPCompile::DeclareLambda(const LambdaExpr* l, const ProfileFunc* pf)
{
ASSERT(is_CPP_compilable(pf));
auto lname = Canonicalize(l->Name().c_str()) + "_lb";
auto body = l->Ingredients()->Body();
auto l_id = l->Ingredients()->GetID();
auto& ids = l->OuterIDs();
for ( auto id : ids )
lambda_names[id] = LocalName(id);
CreateFunction(l_id->GetType<FuncType>(), pf, lname, body, 0, l, FUNC_FLAVOR_FUNCTION);
}
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 ( ! l && 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);
}
body_hashes[fname] = pf->HashVal();
body_priorities[fname] = priority;
body_locs[fname] = body->GetLocationInfo();
body_names.emplace(body.get(), fname);
}
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();
Emit("static %s %s(%s);", yt_decl, fname, ParamDecl(ft, lambda_ids, pf));
Emit("class %s_cl final : public CPPStmt", fname);
StartBlock();
Emit("public:");
string addl_args; // captures passed in on construction
string inits; // initializers for corresponding member vars
if ( lambda_ids )
{
for ( auto& id : *lambda_ids )
{
auto name = lambda_names[id];
auto tn = FullTypeName(id->GetType());
addl_args = addl_args + ", " + tn + " _" + name;
inits = inits + ", " + name + "(std::move(_" + name + "))";
}
}
const Obj* stmts = pf->ProfiledBody();
if ( ! stmts )
stmts = pf->ProfiledExpr();
auto loc = stmts->GetLocationInfo();
auto loc_info = string("\"") + loc->filename + "\", " + Fmt(loc->first_line);
Emit("%s_cl(const char* name%s) : CPPStmt(name, %s)%s { }", fname, addl_args, loc_info, inits);
// An additional constructor just used to generate place-holder
// instances, due to the misdesign that lambdas are identified
// by their Func objects rather than their FuncVal objects.
if ( lambda_ids && lambda_ids->length() > 0 )
Emit("%s_cl(const char* name) : CPPStmt(name, %s) { }", fname, loc_info);
Emit("ValPtr Exec(Frame* f, StmtFlowType& flow) override");
StartBlock();
Emit("flow = FLOW_RETURN;");
if ( in_hook )
{
Emit("if ( ! %s(%s) )", fname, args);
StartBlock();
Emit("flow = FLOW_BREAK;");
EndBlock();
Emit("return nullptr;");
}
else if ( IsNativeType(yt) )
GenInvokeBody(fname, yt, args);
else
Emit("return %s(%s);", fname, args);
EndBlock();
}
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 final : public CPPStmt");
Emit("\t{");
Emit("public:");
Emit("\tCPPDynStmt(const char* _name, void* _func, int _type_signature, const char* filename, "
"int line_num) : CPPStmt(_name, filename, line_num), "
"func(_func), type_signature(_type_signature) { }");
Emit("\tValPtr Exec(Frame* f, StmtFlowType& flow) override;");
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,
const StmtPtr& body, const LambdaExpr* l, const IDPList* lambda_ids)
{
// Declare the member variables for holding the captures.
for ( auto& id : *lambda_ids )
{
auto name = lambda_names[id];
auto tn = FullTypeName(id->GetType());
Emit("%s %s;", tn, name);
}
// Generate initialization to create and register the lambda.
auto h = pf->HashVal();
auto nl = lambda_ids->length();
bool has_captures = nl > 0;
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.
Emit("void SetLambdaCaptures(Frame* f) override");
StartBlock();
for ( int i = 0; i < nl; ++i )
{
auto l_i = (*lambda_ids)[i];
const auto& t_i = l_i->GetType();
auto cap_i = string("f->GetElement(") + Fmt(i) + ")";
Emit("%s = %s;", lambda_names[l_i], GenericValPtrToGT(cap_i, t_i, GEN_NATIVE));
}
EndBlock();
// Generate the method for serializing the captures.
Emit("std::vector<ValPtr> SerializeLambdaCaptures() const override");
StartBlock();
Emit("std::vector<ValPtr> vals;");
for ( int i = 0; i < nl; ++i )
{
auto l_i = (*lambda_ids)[i];
const auto& t_i = l_i->GetType();
Emit("vals.emplace_back(%s);", NativeToGT(lambda_names[l_i], t_i, GEN_VAL_PTR));
}
Emit("return vals;");
EndBlock();
// Generate the Clone() method.
Emit("CPPStmtPtr Clone() override");
StartBlock();
auto arg_clones = GenLambdaClone(l, true);
Emit("return make_intrusive<%s_cl>(name.c_str()%s);", fname, arg_clones);
EndBlock();
}
string CPPCompile::BindArgs(const FuncTypePtr& ft, const IDPList* lambda_ids)
{
const auto& params = ft->Params();
auto t = params->Types();
string res;
int n = t ? t->size() : 0;
for ( auto i = 0; i < n; ++i )
{
auto arg_i = string("f->GetElement(") + Fmt(i) + ")";
const auto& pt = params->GetFieldType(i);
if ( IsNativeType(pt) )
res += arg_i + NativeAccessor(pt);
else
res += GenericValPtrToGT(arg_i, pt, GEN_VAL_PTR);
res += ", ";
}
if ( lambda_ids )
{
for ( auto& id : *lambda_ids )
res += lambda_names[id] + ", ";
}
// Add the final frame argument.
return res + "f";
}
string CPPCompile::ParamDecl(const FuncTypePtr& ft, const IDPList* lambda_ids,
const ProfileFunc* pf)
{
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);
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 )
{
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".
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.
p_names.emplace_back(string("unused_param__CPP_") + Fmt(i));
}
if ( lambda_ids )
// Add the captures as additional parameters.
for ( auto& id : *lambda_ids )
p_names.emplace_back(lambda_names[id]);
}
const ID* CPPCompile::FindParam(int i, const ProfileFunc* pf)
{
const auto& params = pf->Params();
for ( const auto& p : params )
if ( p->Offset() == i )
return p;
return nullptr;
}
} // zeek::detail
void CPPCompile::DeclareFunc(const FuncInfo& func) {
if ( ! IsCompilable(func) )
return;
auto fname = Canonicalize(BodyName(func).c_str()) + "_zf";
auto pf = func.Profile();
auto f = func.Func();
const auto& body = func.Body();
auto priority = func.Priority();
CreateFunction(f->GetType(), pf, fname, body, priority, nullptr, f->Flavor());
if ( f->GetBodies().size() == 1 )
compiled_simple_funcs[f->Name()] = fname;
}
void CPPCompile::DeclareLambda(const LambdaExpr* l, const ProfileFunc* pf) {
ASSERT(is_CPP_compilable(pf));
auto lname = Canonicalize(l->Name().c_str()) + "_lb";
auto body = l->Ingredients()->Body();
auto l_id = l->Ingredients()->GetID();
auto& ids = l->OuterIDs();
for ( auto id : ids )
lambda_names[id] = LocalName(id);
CreateFunction(l_id->GetType<FuncType>(), pf, lname, body, 0, l, FUNC_FLAVOR_FUNCTION);
}
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 ( ! l && 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);
}
body_hashes[fname] = pf->HashVal();
body_priorities[fname] = priority;
body_locs[fname] = body->GetLocationInfo();
body_names.emplace(body.get(), fname);
}
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();
Emit("static %s %s(%s);", yt_decl, fname, ParamDecl(ft, lambda_ids, pf));
Emit("class %s_cl final : public CPPStmt", fname);
StartBlock();
Emit("public:");
string addl_args; // captures passed in on construction
string inits; // initializers for corresponding member vars
if ( lambda_ids ) {
for ( auto& id : *lambda_ids ) {
auto name = lambda_names[id];
auto tn = FullTypeName(id->GetType());
addl_args = addl_args + ", " + tn + " _" + name;
inits = inits + ", " + name + "(std::move(_" + name + "))";
}
}
const Obj* stmts = pf->ProfiledBody();
if ( ! stmts )
stmts = pf->ProfiledExpr();
auto loc = stmts->GetLocationInfo();
auto loc_info = string("\"") + loc->filename + "\", " + Fmt(loc->first_line);
Emit("%s_cl(const char* name%s) : CPPStmt(name, %s)%s { }", fname, addl_args, loc_info, inits);
// An additional constructor just used to generate place-holder
// instances, due to the misdesign that lambdas are identified
// by their Func objects rather than their FuncVal objects.
if ( lambda_ids && lambda_ids->length() > 0 )
Emit("%s_cl(const char* name) : CPPStmt(name, %s) { }", fname, loc_info);
Emit("ValPtr Exec(Frame* f, StmtFlowType& flow) override");
StartBlock();
Emit("flow = FLOW_RETURN;");
if ( in_hook ) {
Emit("if ( ! %s(%s) )", fname, args);
StartBlock();
Emit("flow = FLOW_BREAK;");
EndBlock();
Emit("return nullptr;");
}
else if ( IsNativeType(yt) )
GenInvokeBody(fname, yt, args);
else
Emit("return %s(%s);", fname, args);
EndBlock();
}
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 final : public CPPStmt");
Emit("\t{");
Emit("public:");
Emit(
"\tCPPDynStmt(const char* _name, void* _func, int _type_signature, const char* filename, "
"int line_num) : CPPStmt(_name, filename, line_num), "
"func(_func), type_signature(_type_signature) { }");
Emit("\tValPtr Exec(Frame* f, StmtFlowType& flow) override;");
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, const StmtPtr& body,
const LambdaExpr* l, const IDPList* lambda_ids) {
// Declare the member variables for holding the captures.
for ( auto& id : *lambda_ids ) {
auto name = lambda_names[id];
auto tn = FullTypeName(id->GetType());
Emit("%s %s;", tn, name);
}
// Generate initialization to create and register the lambda.
auto h = pf->HashVal();
auto nl = lambda_ids->length();
bool has_captures = nl > 0;
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.
Emit("void SetLambdaCaptures(Frame* f) override");
StartBlock();
for ( int i = 0; i < nl; ++i ) {
auto l_i = (*lambda_ids)[i];
const auto& t_i = l_i->GetType();
auto cap_i = string("f->GetElement(") + Fmt(i) + ")";
Emit("%s = %s;", lambda_names[l_i], GenericValPtrToGT(cap_i, t_i, GEN_NATIVE));
}
EndBlock();
// Generate the method for serializing the captures.
Emit("std::vector<ValPtr> SerializeLambdaCaptures() const override");
StartBlock();
Emit("std::vector<ValPtr> vals;");
for ( int i = 0; i < nl; ++i ) {
auto l_i = (*lambda_ids)[i];
const auto& t_i = l_i->GetType();
Emit("vals.emplace_back(%s);", NativeToGT(lambda_names[l_i], t_i, GEN_VAL_PTR));
}
Emit("return vals;");
EndBlock();
// Generate the Clone() method.
Emit("CPPStmtPtr Clone() override");
StartBlock();
auto arg_clones = GenLambdaClone(l, true);
Emit("return make_intrusive<%s_cl>(name.c_str()%s);", fname, arg_clones);
EndBlock();
}
string CPPCompile::BindArgs(const FuncTypePtr& ft, const IDPList* lambda_ids) {
const auto& params = ft->Params();
auto t = params->Types();
string res;
int n = t ? t->size() : 0;
for ( auto i = 0; i < n; ++i ) {
auto arg_i = string("f->GetElement(") + Fmt(i) + ")";
const auto& pt = params->GetFieldType(i);
if ( IsNativeType(pt) )
res += arg_i + NativeAccessor(pt);
else
res += GenericValPtrToGT(arg_i, pt, GEN_VAL_PTR);
res += ", ";
}
if ( lambda_ids ) {
for ( auto& id : *lambda_ids )
res += lambda_names[id] + ", ";
}
// Add the final frame argument.
return res + "f";
}
string CPPCompile::ParamDecl(const FuncTypePtr& ft, const IDPList* lambda_ids, const ProfileFunc* pf) {
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);
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 ) {
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".
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.
p_names.emplace_back(string("unused_param__CPP_") + Fmt(i));
}
if ( lambda_ids )
// Add the captures as additional parameters.
for ( auto& id : *lambda_ids )
p_names.emplace_back(lambda_names[id]);
}
const ID* CPPCompile::FindParam(int i, const ProfileFunc* pf) {
const auto& params = pf->Params();
for ( const auto& p : params )
if ( p->Offset() == i )
return p;
return nullptr;
}
} // namespace zeek::detail

View file

@ -9,512 +9,471 @@
extern std::unordered_set<std::string> files_with_conditionals;
namespace zeek::detail
{
namespace zeek::detail {
using namespace std;
CPPCompile::CPPCompile(vector<FuncInfo>& _funcs, ProfileFuncs& _pfs, const string& gen_name,
bool _standalone, bool report_uncompilable)
: funcs(_funcs), pfs(_pfs), standalone(_standalone)
{
auto target_name = gen_name.c_str();
CPPCompile::CPPCompile(vector<FuncInfo>& _funcs, ProfileFuncs& _pfs, const string& gen_name, bool _standalone,
bool report_uncompilable)
: funcs(_funcs), pfs(_pfs), standalone(_standalone) {
auto target_name = gen_name.c_str();
write_file = fopen(target_name, "w");
if ( ! write_file )
{
reporter->Error("can't open C++ target file %s", target_name);
exit(1);
}
write_file = fopen(target_name, "w");
if ( ! write_file ) {
reporter->Error("can't open C++ target file %s", target_name);
exit(1);
}
Compile(report_uncompilable);
}
Compile(report_uncompilable);
}
CPPCompile::~CPPCompile()
{
fclose(write_file);
}
CPPCompile::~CPPCompile() { fclose(write_file); }
void CPPCompile::Compile(bool report_uncompilable)
{
unordered_set<string> filenames_reported_as_skipped;
bool had_to_skip = false;
void CPPCompile::Compile(bool report_uncompilable) {
unordered_set<string> filenames_reported_as_skipped;
bool had_to_skip = false;
// Determine which functions we can call directly, and reuse
// previously compiled instances of those if present.
for ( auto& func : funcs )
{
const auto& f = func.Func();
// Determine which functions we can call directly, and reuse
// previously compiled instances of those if present.
for ( auto& func : funcs ) {
const auto& f = func.Func();
auto& ofiles = analysis_options.only_files;
auto allow_cond = analysis_options.allow_cond;
auto& ofiles = analysis_options.only_files;
auto allow_cond = analysis_options.allow_cond;
string fn = func.Body()->GetLocationInfo()->filename;
string fn = func.Body()->GetLocationInfo()->filename;
if ( ! allow_cond && ! func.ShouldSkip() && ! ofiles.empty() &&
files_with_conditionals.count(fn) > 0 )
{
if ( report_uncompilable )
reporter->Warning(
"%s cannot be compiled to C++ due to source file %s having conditional code",
f->Name(), fn.c_str());
if ( ! allow_cond && ! func.ShouldSkip() && ! ofiles.empty() && files_with_conditionals.count(fn) > 0 ) {
if ( report_uncompilable )
reporter->Warning("%s cannot be compiled to C++ due to source file %s having conditional code",
f->Name(), fn.c_str());
else if ( filenames_reported_as_skipped.count(fn) == 0 )
{
reporter->Warning(
"skipping compilation of files in %s due to presence of conditional code",
fn.c_str());
filenames_reported_as_skipped.insert(fn);
}
else if ( filenames_reported_as_skipped.count(fn) == 0 ) {
reporter->Warning("skipping compilation of files in %s due to presence of conditional code",
fn.c_str());
filenames_reported_as_skipped.insert(fn);
}
had_to_skip = true;
func.SetSkip(true);
}
had_to_skip = true;
func.SetSkip(true);
}
if ( func.ShouldSkip() )
{
not_fully_compilable.insert(f->Name());
continue;
}
if ( func.ShouldSkip() ) {
not_fully_compilable.insert(f->Name());
continue;
}
if ( is_lambda(f) || is_when_lambda(f) )
{
// We deal with these separately.
func.SetSkip(true);
continue;
}
if ( is_lambda(f) || is_when_lambda(f) ) {
// We deal with these separately.
func.SetSkip(true);
continue;
}
const char* reason;
if ( IsCompilable(func, &reason) )
{
if ( f->Flavor() == FUNC_FLAVOR_FUNCTION )
// Note this as a callable compiled function.
compilable_funcs.insert(BodyName(func));
}
else
{
if ( reason && report_uncompilable )
{
had_to_skip = true;
reporter->Warning("%s cannot be compiled to C++ due to %s", f->Name(), reason);
}
const char* reason;
if ( IsCompilable(func, &reason) ) {
if ( f->Flavor() == FUNC_FLAVOR_FUNCTION )
// Note this as a callable compiled function.
compilable_funcs.insert(BodyName(func));
}
else {
if ( reason && report_uncompilable ) {
had_to_skip = true;
reporter->Warning("%s cannot be compiled to C++ due to %s", f->Name(), reason);
}
not_fully_compilable.insert(f->Name());
}
}
not_fully_compilable.insert(f->Name());
}
}
if ( standalone && had_to_skip )
reporter->FatalError(
"aborting standalone compilation to C++ due to having to skip some functions");
if ( standalone && had_to_skip )
reporter->FatalError("aborting standalone compilation to C++ due to having to skip some functions");
// Generate a hash unique for this compilation.
for ( const auto& func : funcs )
if ( ! func.ShouldSkip() )
total_hash = merge_p_hashes(total_hash, func.Profile()->HashVal());
// Generate a hash unique for this compilation.
for ( const auto& func : funcs )
if ( ! func.ShouldSkip() )
total_hash = merge_p_hashes(total_hash, func.Profile()->HashVal());
auto t = util::current_time();
total_hash = merge_p_hashes(total_hash, hash<double>{}(t));
auto t = util::current_time();
total_hash = merge_p_hashes(total_hash, hash<double>{}(t));
GenProlog();
GenProlog();
// Track all of the types we'll be using.
for ( const auto& t : pfs.RepTypes() )
{
TypePtr tp{NewRef{}, (Type*)(t)};
types.AddKey(tp, pfs.HashType(t));
}
// Track all of the types we'll be using.
for ( const auto& t : pfs.RepTypes() ) {
TypePtr tp{NewRef{}, (Type*)(t)};
types.AddKey(tp, pfs.HashType(t));
}
NL();
NL();
for ( auto& g : pfs.AllGlobals() )
CreateGlobal(g);
for ( auto& g : pfs.AllGlobals() )
CreateGlobal(g);
for ( const auto& e : pfs.Events() )
if ( AddGlobal(e, "gl") )
Emit("EventHandlerPtr %s_ev;", globals[string(e)]);
for ( const auto& e : pfs.Events() )
if ( AddGlobal(e, "gl") )
Emit("EventHandlerPtr %s_ev;", globals[string(e)]);
for ( const auto& t : pfs.RepTypes() )
{
ASSERT(types.HasKey(t));
TypePtr tp{NewRef{}, (Type*)(t)};
RegisterType(tp);
}
for ( const auto& t : pfs.RepTypes() ) {
ASSERT(types.HasKey(t));
TypePtr tp{NewRef{}, (Type*)(t)};
RegisterType(tp);
}
// The scaffolding is now in place to go ahead and generate
// the functions & lambdas. First declare them ...
for ( const auto& func : funcs )
if ( ! func.ShouldSkip() )
DeclareFunc(func);
// The scaffolding is now in place to go ahead and generate
// the functions & lambdas. First declare them ...
for ( const auto& func : funcs )
if ( ! func.ShouldSkip() )
DeclareFunc(func);
// We track lambdas by their internal names, and associate those
// with their AST bodies. Two different LambdaExpr's can wind up
// referring to the same underlying lambda if the bodies happen to
// be identical. In that case, we don't want to generate the lambda
// twice, but we do want to map the second one to the same body name.
unordered_map<string, const Stmt*> lambda_ASTs;
for ( const auto& l : pfs.Lambdas() )
{
const auto& n = l->Name();
const auto body = l->Ingredients()->Body().get();
if ( lambda_ASTs.count(n) > 0 )
// Reuse previous body.
body_names[body] = body_names[lambda_ASTs[n]];
else
{
DeclareLambda(l, pfs.ExprProf(l).get());
lambda_ASTs[n] = body;
}
}
// We track lambdas by their internal names, and associate those
// with their AST bodies. Two different LambdaExpr's can wind up
// referring to the same underlying lambda if the bodies happen to
// be identical. In that case, we don't want to generate the lambda
// twice, but we do want to map the second one to the same body name.
unordered_map<string, const Stmt*> lambda_ASTs;
for ( const auto& l : pfs.Lambdas() ) {
const auto& n = l->Name();
const auto body = l->Ingredients()->Body().get();
if ( lambda_ASTs.count(n) > 0 )
// Reuse previous body.
body_names[body] = body_names[lambda_ASTs[n]];
else {
DeclareLambda(l, pfs.ExprProf(l).get());
lambda_ASTs[n] = body;
}
}
NL();
NL();
// ... and now generate their bodies.
for ( const auto& func : funcs )
if ( ! func.ShouldSkip() )
CompileFunc(func);
// ... and now generate their bodies.
for ( const auto& func : funcs )
if ( ! func.ShouldSkip() )
CompileFunc(func);
lambda_ASTs.clear();
for ( const auto& l : pfs.Lambdas() )
{
const auto& n = l->Name();
if ( lambda_ASTs.count(n) > 0 )
continue;
lambda_ASTs.clear();
for ( const auto& l : pfs.Lambdas() ) {
const auto& n = l->Name();
if ( lambda_ASTs.count(n) > 0 )
continue;
CompileLambda(l, pfs.ExprProf(l).get());
lambda_ASTs[n] = l->Ingredients()->Body().get();
}
CompileLambda(l, pfs.ExprProf(l).get());
lambda_ASTs[n] = l->Ingredients()->Body().get();
}
NL();
Emit("std::vector<CPP_RegisterBody> CPP__bodies_to_register = {");
NL();
Emit("std::vector<CPP_RegisterBody> CPP__bodies_to_register = {");
for ( const auto& f : compiled_funcs )
RegisterCompiledBody(f);
for ( const auto& f : compiled_funcs )
RegisterCompiledBody(f);
Emit("};");
Emit("};");
GenEpilog();
}
GenEpilog();
}
void CPPCompile::GenProlog()
{
Emit("#include \"zeek/script_opt/CPP/Runtime.h\"\n");
void CPPCompile::GenProlog() {
Emit("#include \"zeek/script_opt/CPP/Runtime.h\"\n");
// Get the working directory for annotating the output to help
// with debugging.
char working_dir[8192];
if ( ! getcwd(working_dir, sizeof working_dir) )
reporter->FatalError("getcwd failed: %s", strerror(errno));
// Get the working directory for annotating the output to help
// with debugging.
char working_dir[8192];
if ( ! getcwd(working_dir, sizeof working_dir) )
reporter->FatalError("getcwd failed: %s", strerror(errno));
Emit("namespace zeek::detail { //\n");
Emit("namespace CPP_%s { // %s\n", Fmt(total_hash), string(working_dir));
Emit("namespace zeek::detail { //\n");
Emit("namespace CPP_%s { // %s\n", Fmt(total_hash), string(working_dir));
// The following might-or-might-not wind up being populated/used.
Emit("std::vector<int> field_mapping;");
Emit("std::vector<int> enum_mapping;");
NL();
// The following might-or-might-not wind up being populated/used.
Emit("std::vector<int> field_mapping;");
Emit("std::vector<int> enum_mapping;");
NL();
const_info[TYPE_BOOL] = CreateConstInitInfo("Bool", "ValPtr", "bool");
const_info[TYPE_INT] = CreateConstInitInfo("Int", "ValPtr", "zeek_int_t");
const_info[TYPE_COUNT] = CreateConstInitInfo("Count", "ValPtr", "zeek_uint_t");
const_info[TYPE_DOUBLE] = CreateConstInitInfo("Double", "ValPtr", "double");
const_info[TYPE_TIME] = CreateConstInitInfo("Time", "ValPtr", "double");
const_info[TYPE_INTERVAL] = CreateConstInitInfo("Interval", "ValPtr", "double");
const_info[TYPE_ADDR] = CreateConstInitInfo("Addr", "ValPtr", "");
const_info[TYPE_SUBNET] = CreateConstInitInfo("SubNet", "ValPtr", "");
const_info[TYPE_PORT] = CreateConstInitInfo("Port", "ValPtr", "uint32_t");
const_info[TYPE_BOOL] = CreateConstInitInfo("Bool", "ValPtr", "bool");
const_info[TYPE_INT] = CreateConstInitInfo("Int", "ValPtr", "zeek_int_t");
const_info[TYPE_COUNT] = CreateConstInitInfo("Count", "ValPtr", "zeek_uint_t");
const_info[TYPE_DOUBLE] = CreateConstInitInfo("Double", "ValPtr", "double");
const_info[TYPE_TIME] = CreateConstInitInfo("Time", "ValPtr", "double");
const_info[TYPE_INTERVAL] = CreateConstInitInfo("Interval", "ValPtr", "double");
const_info[TYPE_ADDR] = CreateConstInitInfo("Addr", "ValPtr", "");
const_info[TYPE_SUBNET] = CreateConstInitInfo("SubNet", "ValPtr", "");
const_info[TYPE_PORT] = CreateConstInitInfo("Port", "ValPtr", "uint32_t");
const_info[TYPE_ENUM] = CreateCompoundInitInfo("Enum", "ValPtr");
const_info[TYPE_STRING] = CreateCompoundInitInfo("String", "ValPtr");
const_info[TYPE_LIST] = CreateCompoundInitInfo("List", "ValPtr");
const_info[TYPE_PATTERN] = CreateCompoundInitInfo("Pattern", "ValPtr");
const_info[TYPE_VECTOR] = CreateCompoundInitInfo("Vector", "ValPtr");
const_info[TYPE_RECORD] = CreateCompoundInitInfo("Record", "ValPtr");
const_info[TYPE_TABLE] = CreateCompoundInitInfo("Table", "ValPtr");
const_info[TYPE_FUNC] = CreateCompoundInitInfo("Func", "ValPtr");
const_info[TYPE_FILE] = CreateCompoundInitInfo("File", "ValPtr");
const_info[TYPE_ENUM] = CreateCompoundInitInfo("Enum", "ValPtr");
const_info[TYPE_STRING] = CreateCompoundInitInfo("String", "ValPtr");
const_info[TYPE_LIST] = CreateCompoundInitInfo("List", "ValPtr");
const_info[TYPE_PATTERN] = CreateCompoundInitInfo("Pattern", "ValPtr");
const_info[TYPE_VECTOR] = CreateCompoundInitInfo("Vector", "ValPtr");
const_info[TYPE_RECORD] = CreateCompoundInitInfo("Record", "ValPtr");
const_info[TYPE_TABLE] = CreateCompoundInitInfo("Table", "ValPtr");
const_info[TYPE_FUNC] = CreateCompoundInitInfo("Func", "ValPtr");
const_info[TYPE_FILE] = CreateCompoundInitInfo("File", "ValPtr");
type_info = CreateCompoundInitInfo("Type", "Ptr");
attr_info = CreateCompoundInitInfo("Attr", "Ptr");
attrs_info = CreateCompoundInitInfo("Attributes", "Ptr");
type_info = CreateCompoundInitInfo("Type", "Ptr");
attr_info = CreateCompoundInitInfo("Attr", "Ptr");
attrs_info = CreateCompoundInitInfo("Attributes", "Ptr");
call_exprs_info = CreateCustomInitInfo("CallExpr", "Ptr");
lambda_reg_info = CreateCustomInitInfo("LambdaRegistration", "");
global_id_info = CreateCustomInitInfo("GlobalID", "");
call_exprs_info = CreateCustomInitInfo("CallExpr", "Ptr");
lambda_reg_info = CreateCustomInitInfo("LambdaRegistration", "");
global_id_info = CreateCustomInitInfo("GlobalID", "");
NL();
DeclareDynCPPStmt();
NL();
}
NL();
DeclareDynCPPStmt();
NL();
}
shared_ptr<CPP_InitsInfo> CPPCompile::CreateConstInitInfo(const char* tag, const char* type,
const char* c_type)
{
auto gi = make_shared<CPP_BasicConstInitsInfo>(tag, type, c_type);
return RegisterInitInfo(tag, type, gi);
}
shared_ptr<CPP_InitsInfo> CPPCompile::CreateConstInitInfo(const char* tag, const char* type, const char* c_type) {
auto gi = make_shared<CPP_BasicConstInitsInfo>(tag, type, c_type);
return RegisterInitInfo(tag, type, gi);
}
shared_ptr<CPP_InitsInfo> CPPCompile::CreateCompoundInitInfo(const char* tag, const char* type)
{
auto gi = make_shared<CPP_CompoundInitsInfo>(tag, type);
return RegisterInitInfo(tag, type, gi);
}
shared_ptr<CPP_InitsInfo> CPPCompile::CreateCompoundInitInfo(const char* tag, const char* type) {
auto gi = make_shared<CPP_CompoundInitsInfo>(tag, type);
return RegisterInitInfo(tag, type, gi);
}
shared_ptr<CPP_InitsInfo> CPPCompile::CreateCustomInitInfo(const char* tag, const char* type)
{
auto gi = make_shared<CPP_CustomInitsInfo>(tag, type);
if ( type[0] == '\0' )
gi->SetCPPType("void*");
shared_ptr<CPP_InitsInfo> CPPCompile::CreateCustomInitInfo(const char* tag, const char* type) {
auto gi = make_shared<CPP_CustomInitsInfo>(tag, type);
if ( type[0] == '\0' )
gi->SetCPPType("void*");
return RegisterInitInfo(tag, type, gi);
}
return RegisterInitInfo(tag, type, gi);
}
shared_ptr<CPP_InitsInfo> CPPCompile::RegisterInitInfo(const char* tag, const char* type,
shared_ptr<CPP_InitsInfo> gi)
{
string v_type = type[0] ? (string(tag) + type) : "void*";
Emit("std::vector<%s> CPP__%s__;", v_type, string(tag));
all_global_info.insert(gi);
return gi;
}
shared_ptr<CPP_InitsInfo> gi) {
string v_type = type[0] ? (string(tag) + type) : "void*";
Emit("std::vector<%s> CPP__%s__;", v_type, string(tag));
all_global_info.insert(gi);
return gi;
}
void CPPCompile::RegisterCompiledBody(const string& f)
{
// Build up an initializer of the events relevant to the function.
string events;
auto be = body_events.find(f);
if ( be != body_events.end() )
for ( const auto& e : be->second )
{
if ( events.size() > 0 )
events += ", ";
events = events + "\"" + e + "\"";
}
void CPPCompile::RegisterCompiledBody(const string& f) {
// Build up an initializer of the events relevant to the function.
string events;
auto be = body_events.find(f);
if ( be != body_events.end() )
for ( const auto& e : be->second ) {
if ( events.size() > 0 )
events += ", ";
events = events + "\"" + e + "\"";
}
events = string("{") + events + "}";
events = string("{") + events + "}";
auto fi = func_index.find(f);
ASSERT(fi != func_index.end());
auto type_signature = casting_index[fi->second];
auto fi = func_index.find(f);
ASSERT(fi != func_index.end());
auto type_signature = casting_index[fi->second];
auto h = body_hashes[f];
auto p = body_priorities[f];
auto loc = body_locs[f];
auto body_info = Fmt(p) + ", " + Fmt(h) + ", \"" + loc->filename + " (C++)\", " +
Fmt(loc->first_line);
auto h = body_hashes[f];
auto p = body_priorities[f];
auto loc = body_locs[f];
auto body_info = Fmt(p) + ", " + Fmt(h) + ", \"" + loc->filename + " (C++)\", " + Fmt(loc->first_line);
Emit("\tCPP_RegisterBody(\"%s\", (void*) %s, %s, %s, std::vector<std::string>(%s)),", f, f,
Fmt(type_signature), body_info, events);
}
Emit("\tCPP_RegisterBody(\"%s\", (void*) %s, %s, %s, std::vector<std::string>(%s)),", f, f, Fmt(type_signature),
body_info, events);
}
void CPPCompile::GenEpilog()
{
if ( standalone )
{
NL();
InitializeGlobals();
}
void CPPCompile::GenEpilog() {
if ( standalone ) {
NL();
InitializeGlobals();
}
NL();
for ( const auto& ii : init_infos )
GenInitExpr(ii.second);
NL();
for ( const auto& ii : init_infos )
GenInitExpr(ii.second);
NL();
GenCPPDynStmt();
NL();
GenCPPDynStmt();
NL();
for ( const auto& gi : all_global_info )
gi->GenerateInitializers(this);
NL();
for ( const auto& gi : all_global_info )
gi->GenerateInitializers(this);
NL();
InitializeEnumMappings();
NL();
InitializeEnumMappings();
NL();
InitializeFieldMappings();
NL();
InitializeFieldMappings();
NL();
InitializeBiFs();
NL();
InitializeBiFs();
NL();
indices_mgr.Generate(this);
NL();
indices_mgr.Generate(this);
NL();
InitializeStrings();
NL();
InitializeStrings();
NL();
InitializeHashes();
NL();
InitializeHashes();
NL();
InitializeConsts();
NL();
InitializeConsts();
NL();
GenLoadBiFs();
NL();
GenLoadBiFs();
NL();
GenFinishInit();
NL();
GenFinishInit();
NL();
GenRegisterBodies();
NL();
GenRegisterBodies();
NL();
Emit("void init__CPP()");
StartBlock();
Emit("register_bodies__CPP();");
EndBlock();
NL();
Emit("void init__CPP()");
StartBlock();
Emit("register_bodies__CPP();");
EndBlock();
if ( standalone )
GenStandaloneActivation();
if ( standalone )
GenStandaloneActivation();
GenInitHook();
GenInitHook();
Emit("} //\n\n");
Emit("} // zeek::detail");
}
Emit("} //\n\n");
Emit("} // zeek::detail");
}
void CPPCompile::GenCPPDynStmt()
{
Emit("ValPtr CPPDynStmt::Exec(Frame* f, StmtFlowType& flow)");
void CPPCompile::GenCPPDynStmt() {
Emit("ValPtr CPPDynStmt::Exec(Frame* f, StmtFlowType& flow)");
StartBlock();
StartBlock();
Emit("flow = FLOW_RETURN;");
Emit("f->SetOnlyCall(ce.get());");
Emit("flow = FLOW_RETURN;");
Emit("f->SetOnlyCall(ce.get());");
Emit("switch ( type_signature )");
StartBlock();
for ( auto i = 0U; i < func_casting_glue.size(); ++i )
{
Emit("case %s:", to_string(i));
StartBlock();
auto& glue = func_casting_glue[i];
Emit("switch ( type_signature )");
StartBlock();
for ( auto i = 0U; i < func_casting_glue.size(); ++i ) {
Emit("case %s:", to_string(i));
StartBlock();
auto& glue = func_casting_glue[i];
auto invoke = string("(*(") + glue.cast + ")(func))(" + glue.args + ")";
auto invoke = string("(*(") + glue.cast + ")(func))(" + glue.args + ")";
if ( glue.is_hook )
{
Emit("if ( ! %s )", invoke);
StartBlock();
Emit("flow = FLOW_BREAK;");
EndBlock();
Emit("return nullptr;");
}
if ( glue.is_hook ) {
Emit("if ( ! %s )", invoke);
StartBlock();
Emit("flow = FLOW_BREAK;");
EndBlock();
Emit("return nullptr;");
}
else if ( IsNativeType(glue.yield) )
GenInvokeBody(invoke, glue.yield);
else if ( IsNativeType(glue.yield) )
GenInvokeBody(invoke, glue.yield);
else
Emit("return %s;", invoke);
else
Emit("return %s;", invoke);
EndBlock();
}
EndBlock();
}
Emit("default:");
Emit("\treporter->InternalError(\"invalid type in CPPDynStmt::Exec\");");
Emit("\treturn nullptr;");
Emit("default:");
Emit("\treporter->InternalError(\"invalid type in CPPDynStmt::Exec\");");
Emit("\treturn nullptr;");
EndBlock();
EndBlock();
}
EndBlock();
EndBlock();
}
void CPPCompile::GenLoadBiFs()
{
Emit("void load_BiFs__CPP()");
StartBlock();
Emit("for ( auto& b : CPP__BiF_lookups__ )");
Emit("\tb.ResolveBiF();");
EndBlock();
}
void CPPCompile::GenLoadBiFs() {
Emit("void load_BiFs__CPP()");
StartBlock();
Emit("for ( auto& b : CPP__BiF_lookups__ )");
Emit("\tb.ResolveBiF();");
EndBlock();
}
void CPPCompile::GenFinishInit()
{
Emit("void finish_init__CPP()");
void CPPCompile::GenFinishInit() {
Emit("void finish_init__CPP()");
StartBlock();
StartBlock();
Emit("static bool did_init = false;");
Emit("if ( did_init )");
Emit("\treturn;");
Emit("did_init = true;");
Emit("static bool did_init = false;");
Emit("if ( did_init )");
Emit("\treturn;");
Emit("did_init = true;");
NL();
Emit("std::vector<std::vector<int>> InitIndices;");
Emit("generate_indices_set(CPP__Indices__init, InitIndices);");
NL();
Emit("std::vector<std::vector<int>> InitIndices;");
Emit("generate_indices_set(CPP__Indices__init, InitIndices);");
Emit("std::map<TypeTag, std::shared_ptr<CPP_AbstractInitAccessor>> InitConsts;");
Emit("std::map<TypeTag, std::shared_ptr<CPP_AbstractInitAccessor>> InitConsts;");
NL();
for ( const auto& ci : const_info )
{
auto& gi = ci.second;
Emit("InitConsts.emplace(%s, std::make_shared<CPP_InitAccessor<%s>>(%s));",
TypeTagName(ci.first), gi->CPPType(), gi->InitsName());
}
NL();
for ( const auto& ci : const_info ) {
auto& gi = ci.second;
Emit("InitConsts.emplace(%s, std::make_shared<CPP_InitAccessor<%s>>(%s));", TypeTagName(ci.first),
gi->CPPType(), gi->InitsName());
}
Emit("InitsManager im(CPP__ConstVals, InitConsts, InitIndices, CPP__Strings, CPP__Hashes, "
"CPP__Type__, CPP__Attributes__, CPP__Attr__, CPP__CallExpr__);");
Emit(
"InitsManager im(CPP__ConstVals, InitConsts, InitIndices, CPP__Strings, CPP__Hashes, "
"CPP__Type__, CPP__Attributes__, CPP__Attr__, CPP__CallExpr__);");
NL();
int max_cohort = 0;
for ( const auto& gi : all_global_info )
max_cohort = std::max(max_cohort, gi->MaxCohort());
NL();
int max_cohort = 0;
for ( const auto& gi : all_global_info )
max_cohort = std::max(max_cohort, gi->MaxCohort());
for ( auto c = 0; c <= max_cohort; ++c )
for ( const auto& gi : all_global_info )
if ( gi->CohortSize(c) > 0 )
Emit("%s.InitializeCohort(&im, %s);", gi->InitializersName(), Fmt(c));
for ( auto c = 0; c <= max_cohort; ++c )
for ( const auto& gi : all_global_info )
if ( gi->CohortSize(c) > 0 )
Emit("%s.InitializeCohort(&im, %s);", gi->InitializersName(), Fmt(c));
// Populate mappings for dynamic offsets.
NL();
Emit("for ( auto& em : CPP__enum_mappings__ )");
Emit("\tenum_mapping.push_back(em.ComputeOffset(&im));");
NL();
Emit("for ( auto& fm : CPP__field_mappings__ )");
Emit("\tfield_mapping.push_back(fm.ComputeOffset(&im));");
// Populate mappings for dynamic offsets.
NL();
Emit("for ( auto& em : CPP__enum_mappings__ )");
Emit("\tenum_mapping.push_back(em.ComputeOffset(&im));");
NL();
Emit("for ( auto& fm : CPP__field_mappings__ )");
Emit("\tfield_mapping.push_back(fm.ComputeOffset(&im));");
NL();
NL();
Emit("load_BiFs__CPP();");
Emit("load_BiFs__CPP();");
if ( standalone )
// Note, BiFs will also be loaded again later, because the
// main initialization finishes upon loading of the activation
// script, rather than after all scripts have been parsed
// and plugins (with BiFs) have been loaded.
Emit("init_globals__CPP();");
if ( standalone )
// Note, BiFs will also be loaded again later, because the
// main initialization finishes upon loading of the activation
// script, rather than after all scripts have been parsed
// and plugins (with BiFs) have been loaded.
Emit("init_globals__CPP();");
EndBlock();
}
EndBlock();
}
void CPPCompile::GenRegisterBodies()
{
Emit("void register_bodies__CPP()");
StartBlock();
void CPPCompile::GenRegisterBodies() {
Emit("void register_bodies__CPP()");
StartBlock();
Emit("for ( auto& b : CPP__bodies_to_register )");
StartBlock();
Emit("auto f = make_intrusive<CPPDynStmt>(b.func_name.c_str(), b.func, b.type_signature, "
"b.filename, b.line_num);");
Emit("for ( auto& b : CPP__bodies_to_register )");
StartBlock();
Emit(
"auto f = make_intrusive<CPPDynStmt>(b.func_name.c_str(), b.func, b.type_signature, "
"b.filename, b.line_num);");
auto reg = standalone ? "register_standalone_body" : "register_body";
Emit("%s__CPP(f, b.priority, b.h, b.events, finish_init__CPP);", reg);
EndBlock();
auto reg = standalone ? "register_standalone_body" : "register_body";
Emit("%s__CPP(f, b.priority, b.h, b.events, finish_init__CPP);", reg);
EndBlock();
EndBlock();
}
EndBlock();
}
bool CPPCompile::IsCompilable(const FuncInfo& func, const char** reason)
{
if ( ! is_CPP_compilable(func.Profile(), reason) )
return false;
bool CPPCompile::IsCompilable(const FuncInfo& func, const char** reason) {
if ( ! is_CPP_compilable(func.Profile(), reason) )
return false;
if ( reason )
// Indicate that there's no fundamental reason it can't be
// compiled.
*reason = nullptr;
if ( reason )
// Indicate that there's no fundamental reason it can't be
// compiled.
*reason = nullptr;
if ( func.ShouldSkip() )
return false;
if ( func.ShouldSkip() )
return false;
return true;
}
return true;
}
} // zeek::detail
} // namespace zeek::detail

View file

@ -2,27 +2,23 @@
#include "zeek/script_opt/CPP/Compile.h"
namespace zeek::detail
{
namespace zeek::detail {
using namespace std;
void CPPCompile::StartBlock()
{
IndentUp();
Emit("{");
}
void CPPCompile::StartBlock() {
IndentUp();
Emit("{");
}
void CPPCompile::EndBlock(bool needs_semi)
{
Emit("}%s", needs_semi ? ";" : "");
IndentDown();
}
void CPPCompile::EndBlock(bool needs_semi) {
Emit("}%s", needs_semi ? ";" : "");
IndentDown();
}
void CPPCompile::Indent() const
{
for ( auto i = 0; i < block_level; ++i )
fprintf(write_file, "%s", "\t");
}
void CPPCompile::Indent() const {
for ( auto i = 0; i < block_level; ++i )
fprintf(write_file, "%s", "\t");
}
} // zeek::detail
} // namespace zeek::detail

File diff suppressed because it is too large Load diff

View file

@ -7,8 +7,7 @@
#include "zeek/Desc.h"
#include "zeek/broker/Data.h"
namespace zeek::detail
{
namespace zeek::detail {
using namespace std;
@ -17,73 +16,61 @@ unordered_map<string, unordered_set<p_hash_type>> added_bodies;
unordered_map<p_hash_type, void (*)()> standalone_callbacks;
vector<void (*)()> standalone_finalizations;
void CPPFunc::Describe(ODesc* d) const
{
d->AddSP("compiled function");
d->Add(name);
}
void CPPFunc::Describe(ODesc* d) const {
d->AddSP("compiled function");
d->Add(name);
}
CPPStmt::CPPStmt(const char* _name, const char* filename, int line_num)
: Stmt(STMT_CPP), name(_name)
{
// We build a fake CallExpr node to be used for error-reporting.
// It doesn't matter that it matches the actual function/event/hook
// type-checking-wise, but it *does* need to type-check.
auto no_args = make_intrusive<RecordType>(nullptr);
auto no_yield = base_type(TYPE_VOID);
auto ft = make_intrusive<FuncType>(no_args, no_yield, FUNC_FLAVOR_FUNCTION);
CPPStmt::CPPStmt(const char* _name, const char* filename, int line_num) : Stmt(STMT_CPP), name(_name) {
// We build a fake CallExpr node to be used for error-reporting.
// It doesn't matter that it matches the actual function/event/hook
// type-checking-wise, but it *does* need to type-check.
auto no_args = make_intrusive<RecordType>(nullptr);
auto no_yield = base_type(TYPE_VOID);
auto ft = make_intrusive<FuncType>(no_args, no_yield, FUNC_FLAVOR_FUNCTION);
vector<StmtPtr> no_bodies;
vector<int> no_priorities;
vector<StmtPtr> no_bodies;
vector<int> no_priorities;
auto sf = make_intrusive<ScriptFunc>(name, ft, no_bodies, no_priorities);
auto fv = make_intrusive<FuncVal>(sf);
auto empty_args = make_intrusive<ListExpr>();
auto sf = make_intrusive<ScriptFunc>(name, ft, no_bodies, no_priorities);
auto fv = make_intrusive<FuncVal>(sf);
auto empty_args = make_intrusive<ListExpr>();
ce = make_intrusive<CallExpr>(make_intrusive<ConstExpr>(fv), empty_args);
Location loc(filename, line_num, line_num, 1, 1);
ce->SetLocationInfo(&loc);
}
ce = make_intrusive<CallExpr>(make_intrusive<ConstExpr>(fv), empty_args);
Location loc(filename, line_num, line_num, 1, 1);
ce->SetLocationInfo(&loc);
}
CPPLambdaFunc::CPPLambdaFunc(string _name, FuncTypePtr ft, CPPStmtPtr _l_body)
: ScriptFunc(std::move(_name), std::move(ft), {_l_body}, {0})
{
l_body = std::move(_l_body);
}
: ScriptFunc(std::move(_name), std::move(ft), {_l_body}, {0}) {
l_body = std::move(_l_body);
}
broker::expected<broker::data> CPPLambdaFunc::SerializeCaptures() const
{
auto vals = l_body->SerializeLambdaCaptures();
broker::expected<broker::data> CPPLambdaFunc::SerializeCaptures() const {
auto vals = l_body->SerializeLambdaCaptures();
broker::vector rval;
rval.emplace_back(string("CopyFrame"));
broker::vector rval;
rval.emplace_back(string("CopyFrame"));
broker::vector body;
broker::vector body;
for ( const auto& val : vals )
{
auto expected = Broker::detail::val_to_data(val.get());
if ( ! expected )
return broker::ec::invalid_data;
for ( const auto& val : vals ) {
auto expected = Broker::detail::val_to_data(val.get());
if ( ! expected )
return broker::ec::invalid_data;
TypeTag tag = val->GetType()->Tag();
broker::vector val_tuple{std::move(*expected), static_cast<broker::integer>(tag)};
body.emplace_back(std::move(val_tuple));
}
TypeTag tag = val->GetType()->Tag();
broker::vector val_tuple{std::move(*expected), static_cast<broker::integer>(tag)};
body.emplace_back(std::move(val_tuple));
}
rval.emplace_back(std::move(body));
rval.emplace_back(std::move(body));
return {std::move(rval)};
}
return {std::move(rval)};
}
void CPPLambdaFunc::SetCaptures(Frame* f)
{
l_body->SetLambdaCaptures(f);
}
void CPPLambdaFunc::SetCaptures(Frame* f) { l_body->SetLambdaCaptures(f); }
FuncPtr CPPLambdaFunc::DoClone()
{
return make_intrusive<CPPLambdaFunc>(name, type, l_body->Clone());
}
FuncPtr CPPLambdaFunc::DoClone() { return make_intrusive<CPPLambdaFunc>(name, type, l_body->Clone()); }
} // zeek::detail
} // namespace zeek::detail

View file

@ -8,73 +8,67 @@
#include "zeek/Func.h"
#include "zeek/script_opt/ProfileFunc.h"
namespace zeek
{
namespace zeek {
namespace detail
{
namespace detail {
// A subclass of Func used for lambdas that the compiler creates for
// complex initializations (expressions used in type attributes).
// The usage is via derivation from this class, rather than direct
// use of it.
class CPPFunc : public Func
{
class CPPFunc : public Func {
public:
bool IsPure() const override { return is_pure; }
bool IsPure() const override { return is_pure; }
void Describe(ODesc* d) const override;
void Describe(ODesc* d) const override;
protected:
// Constructor used when deriving subclasses.
CPPFunc(const char* _name, bool _is_pure)
{
name = _name;
is_pure = _is_pure;
}
// Constructor used when deriving subclasses.
CPPFunc(const char* _name, bool _is_pure) {
name = _name;
is_pure = _is_pure;
}
std::string name;
bool is_pure;
};
std::string name;
bool is_pure;
};
// A subclass of Stmt used to replace a function/event handler/hook body.
class CPPStmt : public Stmt
{
class CPPStmt : public Stmt {
public:
CPPStmt(const char* _name, const char* filename, int line_num);
CPPStmt(const char* _name, const char* filename, int line_num);
const std::string& Name() { return name; }
const std::string& Name() { return name; }
// Sets/returns a hash associated with this statement. A value
// of 0 means "not set".
p_hash_type GetHash() const { return hash; }
void SetHash(p_hash_type h) { hash = h; }
// Sets/returns a hash associated with this statement. A value
// of 0 means "not set".
p_hash_type GetHash() const { return hash; }
void SetHash(p_hash_type h) { hash = h; }
// The following only get defined by lambda bodies.
virtual void SetLambdaCaptures(Frame* f) { }
virtual std::vector<ValPtr> SerializeLambdaCaptures() const { return std::vector<ValPtr>{}; }
// The following only get defined by lambda bodies.
virtual void SetLambdaCaptures(Frame* f) {}
virtual std::vector<ValPtr> SerializeLambdaCaptures() const { return std::vector<ValPtr>{}; }
virtual IntrusivePtr<CPPStmt> Clone() { return {NewRef{}, this}; }
virtual IntrusivePtr<CPPStmt> Clone() { return {NewRef{}, this}; }
protected:
// This method being called means that the inliner is running
// on compiled code, which shouldn't happen.
StmtPtr Duplicate() override
{
ASSERT(0);
return ThisPtr();
}
// This method being called means that the inliner is running
// on compiled code, which shouldn't happen.
StmtPtr Duplicate() override {
ASSERT(0);
return ThisPtr();
}
TraversalCode Traverse(TraversalCallback* cb) const override { return TC_CONTINUE; }
TraversalCode Traverse(TraversalCallback* cb) const override { return TC_CONTINUE; }
std::string name;
p_hash_type hash = 0ULL;
std::string name;
p_hash_type hash = 0ULL;
// A pseudo AST "call" node, used to support error localization.
CallExprPtr ce;
};
// A pseudo AST "call" node, used to support error localization.
CallExprPtr ce;
};
using CPPStmtPtr = IntrusivePtr<CPPStmt>;
@ -83,31 +77,29 @@ using CPPStmtPtr = IntrusivePtr<CPPStmt>;
// that CPPFunc is for lambdas generated directly by the compiler,
// rather than those explicitly present in scripts.
class CPPLambdaFunc : public ScriptFunc
{
class CPPLambdaFunc : public ScriptFunc {
public:
CPPLambdaFunc(std::string name, FuncTypePtr ft, CPPStmtPtr l_body);
CPPLambdaFunc(std::string name, FuncTypePtr ft, CPPStmtPtr l_body);
protected:
// Methods related to sending lambdas via Broker.
broker::expected<broker::data> SerializeCaptures() const override;
void SetCaptures(Frame* f) override;
// Methods related to sending lambdas via Broker.
broker::expected<broker::data> SerializeCaptures() const override;
void SetCaptures(Frame* f) override;
FuncPtr DoClone() override;
FuncPtr DoClone() override;
CPPStmtPtr l_body;
};
CPPStmtPtr l_body;
};
// Information associated with a given compiled script body: its
// Stmt subclass, priority, and any events that should be registered
// upon instantiating the body.
struct CompiledScript
{
CPPStmtPtr body;
int priority;
std::vector<std::string> events;
void (*finish_init_func)();
};
struct CompiledScript {
CPPStmtPtr body;
int priority;
std::vector<std::string> events;
void (*finish_init_func)();
};
// Maps hashes to compiled information.
extern std::unordered_map<p_hash_type, CompiledScript> compiled_scripts;
@ -125,6 +117,6 @@ extern std::unordered_map<p_hash_type, void (*)()> standalone_callbacks;
// Callbacks to finalize initialization of standalone compiled scripts.
extern std::vector<void (*)()> standalone_finalizations;
} // namespace detail
} // namespace detail
} // namespace zeek
} // namespace zeek

View file

@ -2,277 +2,254 @@
#include "zeek/script_opt/CPP/Compile.h"
namespace zeek::detail
{
namespace zeek::detail {
using namespace std;
void CPPCompile::CompileFunc(const FuncInfo& func)
{
if ( ! IsCompilable(func) )
return;
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();
const auto& body = func.Body();
auto fname = Canonicalize(BodyName(func).c_str()) + "_zf";
auto pf = func.Profile();
auto f = func.Func();
const auto& body = func.Body();
DefineBody(f->GetType(), pf, fname, body, nullptr, f->Flavor());
}
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()->GetID();
auto& ids = l->OuterIDs();
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()->GetID();
auto& ids = l->OuterIDs();
DefineBody(l_id->GetType<FuncType>(), pf, lname, body, &ids, FUNC_FLAVOR_FUNCTION);
}
DefineBody(l_id->GetType<FuncType>(), pf, lname, body, &ids, FUNC_FLAVOR_FUNCTION);
}
void CPPCompile::GenInvokeBody(const string& call, const TypePtr& t)
{
if ( ! t || t->Tag() == TYPE_VOID )
{
Emit("%s;", call);
Emit("return nullptr;");
}
else
Emit("return %s;", NativeToGT(call, t, GEN_VAL_PTR));
}
void CPPCompile::GenInvokeBody(const string& call, const TypePtr& t) {
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 string& fname,
const StmtPtr& body, const IDPList* lambda_ids, FunctionFlavor flavor)
{
locals.clear();
params.clear();
void CPPCompile::DefineBody(const FuncTypePtr& ft, const ProfileFunc* pf, const string& fname, const StmtPtr& body,
const IDPList* lambda_ids, FunctionFlavor flavor) {
locals.clear();
params.clear();
body_name = fname;
body_name = fname;
ret_type = ft->Yield();
in_hook = flavor == FUNC_FLAVOR_HOOK;
auto ret_type_str = in_hook ? "bool" : FullTypeName(ret_type);
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);
for ( const auto& p : pf->Params() )
params.emplace(p);
NL();
NL();
Emit("%s %s(%s)", ret_type_str, fname, ParamDecl(ft, lambda_ids, pf));
Emit("%s %s(%s)", ret_type_str, fname, ParamDecl(ft, lambda_ids, pf));
StartBlock();
StartBlock();
// Deal with "any" parameters, if any.
TranslateAnyParams(ft, pf);
// Deal with "any" parameters, if any.
TranslateAnyParams(ft, pf);
// Make sure that any events referred to in this function have
// been initialized.
InitializeEvents(pf);
// Make sure that any events referred to in this function have
// been initialized.
InitializeEvents(pf);
// Create the local variables.
DeclareLocals(pf, lambda_ids);
// Create the local variables.
DeclareLocals(pf, lambda_ids);
GenStmt(body);
GenStmt(body);
if ( in_hook )
{
Emit("return true;");
in_hook = false;
}
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;");
// 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();
}
EndBlock();
}
void CPPCompile::TranslateAnyParams(const FuncTypePtr& ft, const ProfileFunc* pf)
{
const auto& formals = ft->Params();
int n = formals->NumFields();
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;
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;
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;
const auto& pt = param_id->GetType();
if ( pt->Tag() == TYPE_ANY )
// It's already "any", nothing more to do.
continue;
auto any_i = string("any_param__CPP_") + Fmt(i);
auto any_i = string("any_param__CPP_") + Fmt(i);
Emit("%s %s = %s;", FullTypeName(pt), LocalName(param_id),
GenericValPtrToGT(any_i, pt, GEN_NATIVE));
}
}
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";
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();
// 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, e);
EndBlock();
Emit("did_init = true;");
EndBlock();
Emit("}");
}
}
// 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, 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.
IDSet lambda_set;
if ( lambda_ids )
for ( auto li : *lambda_ids )
lambda_set.insert(li);
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;
if ( lambda_ids )
for ( auto li : *lambda_ids )
lambda_set.insert(li);
const auto& ls = pf->Locals();
const auto& ls = pf->Locals();
// Track whether we generated a declaration. This is just for
// tidiness in the output.
bool did_decl = false;
// 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);
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];
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;
}
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);
}
locals.emplace(l, ln);
}
if ( did_decl )
NL();
}
if ( did_decl )
NL();
}
string CPPCompile::BodyName(const FuncInfo& func)
{
const auto& f = func.Func();
const auto& body = func.Body();
string fname = f->Name();
string CPPCompile::BodyName(const FuncInfo& func) {
const auto& f = func.Func();
const auto& body = func.Body();
string fname = f->Name();
// Extend name with location information.
auto loc = body->GetLocationInfo();
if ( loc->filename )
{
auto fn = loc->filename;
// Extend name with location information.
auto loc = body->GetLocationInfo();
if ( loc->filename ) {
auto fn = loc->filename;
// Skip leading goop that gets added by search paths.
while ( *fn == '.' || *fn == '/' )
++fn;
// Skip leading goop that gets added by search paths.
while ( *fn == '.' || *fn == '/' )
++fn;
auto canonicalize = [](char c) -> char
{
return isalnum(c) ? c : '_';
};
auto canonicalize = [](char c) -> char { return isalnum(c) ? c : '_'; };
string fns = fn;
transform(fns.begin(), fns.end(), fns.begin(), canonicalize);
string fns = fn;
transform(fns.begin(), fns.end(), fns.begin(), canonicalize);
if ( ! isalpha(fns[0]) )
// This can happen for filenames beginning with numbers.
fns = "_" + fns;
if ( ! isalpha(fns[0]) )
// This can happen for filenames beginning with numbers.
fns = "_" + fns;
fname = fns + "__" + fname;
}
fname = fns + "__" + fname;
}
const auto& bodies = f->GetBodies();
const auto& bodies = f->GetBodies();
if ( bodies.size() == 1 )
return fname;
if ( bodies.size() == 1 )
return fname;
// Make the name distinct-per-body.
// Make the name distinct-per-body.
size_t i;
for ( i = 0; i < bodies.size(); ++i )
if ( bodies[i].stmts == body )
break;
size_t 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");
if ( i >= bodies.size() )
reporter->InternalError("can't find body in CPPCompile::BodyName");
return fname + "__" + Fmt(static_cast<int>(i));
}
return fname + "__" + Fmt(static_cast<int>(i));
}
p_hash_type CPPCompile::BodyHash(const Stmt* body)
{
auto bn = body_names.find(body);
ASSERT(bn != body_names.end());
p_hash_type CPPCompile::BodyHash(const Stmt* body) {
auto bn = body_names.find(body);
ASSERT(bn != body_names.end());
auto& body_name = bn->second;
auto bh = body_hashes.find(body_name);
ASSERT(bh != body_hashes.end());
auto& body_name = bn->second;
auto bh = body_hashes.find(body_name);
ASSERT(bh != body_hashes.end());
return bh->second;
}
return bh->second;
}
string CPPCompile::GenArgs(const RecordTypePtr& params, const Expr* e)
{
const auto& exprs = e->AsListExpr()->Exprs();
string gen;
string CPPCompile::GenArgs(const RecordTypePtr& params, const Expr* e) {
const auto& exprs = e->AsListExpr()->Exprs();
string gen;
int n = exprs.size();
int n = exprs.size();
for ( auto i = 0; i < n; ++i )
{
auto e_i = exprs[i];
auto gt = GEN_NATIVE;
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;
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;
if ( param_any && ! arg_any )
gt = GEN_VAL_PTR;
auto expr_gen = GenExpr(e_i, gt);
auto expr_gen = GenExpr(e_i, gt);
if ( ! param_any && arg_any )
expr_gen = GenericValPtrToGT(expr_gen, param_t, GEN_NATIVE);
if ( ! param_any && arg_any )
expr_gen = GenericValPtrToGT(expr_gen, param_t, GEN_NATIVE);
gen += expr_gen;
if ( i < n - 1 )
gen += ", ";
}
gen += expr_gen;
if ( i < n - 1 )
gen += ", ";
}
return gen;
}
return gen;
}
} // zeek::detail
} // namespace zeek::detail

View file

@ -5,340 +5,312 @@
#include "zeek/script_opt/IDOptInfo.h"
#include "zeek/script_opt/ProfileFunc.h"
namespace zeek::detail
{
namespace zeek::detail {
using namespace std;
std::shared_ptr<CPP_InitInfo> CPPCompile::RegisterInitExpr(const ExprPtr& ep)
{
auto ename = InitExprName(ep);
std::shared_ptr<CPP_InitInfo> CPPCompile::RegisterInitExpr(const ExprPtr& ep) {
auto ename = InitExprName(ep);
auto ii = init_infos.find(ename);
if ( ii != init_infos.end() )
return ii->second;
auto ii = init_infos.find(ename);
if ( ii != init_infos.end() )
return ii->second;
auto wrapper_cl = string("wrapper_") + ename + "_cl";
auto wrapper_cl = string("wrapper_") + ename + "_cl";
auto gi = make_shared<CallExprInitInfo>(this, ep, ename, wrapper_cl);
call_exprs_info->AddInstance(gi);
init_infos[ename] = gi;
auto gi = make_shared<CallExprInitInfo>(this, ep, ename, wrapper_cl);
call_exprs_info->AddInstance(gi);
init_infos[ename] = gi;
return gi;
}
return gi;
}
void CPPCompile::GenInitExpr(std::shared_ptr<CallExprInitInfo> ce_init)
{
NL();
void CPPCompile::GenInitExpr(std::shared_ptr<CallExprInitInfo> ce_init) {
NL();
const auto& e = ce_init->GetExpr();
const auto& t = e->GetType();
const auto& ename = ce_init->Name();
const auto& wc = ce_init->WrapperClass();
const auto& e = ce_init->GetExpr();
const auto& t = e->GetType();
const auto& ename = ce_init->Name();
const auto& wc = ce_init->WrapperClass();
// First, create a CPPFunc that we can compile to compute 'e'.
auto name = string("wrapper_") + ename;
// First, create a CPPFunc that we can compile to compute 'e'.
auto name = string("wrapper_") + ename;
// Forward declaration of the function that computes 'e'.
Emit("static %s %s(Frame* f__CPP);", FullTypeName(t), name);
// Forward declaration of the function that computes 'e'.
Emit("static %s %s(Frame* f__CPP);", FullTypeName(t), name);
// Create the Func subclass that can be used in a CallExpr to
// evaluate 'e'.
Emit("class %s final : public CPPFunc", wc);
StartBlock();
// Create the Func subclass that can be used in a CallExpr to
// evaluate 'e'.
Emit("class %s final : public CPPFunc", wc);
StartBlock();
Emit("public:");
Emit("%s() : CPPFunc(\"%s\", %s)", wc, name, e->IsPure() ? "true" : "false");
Emit("public:");
Emit("%s() : CPPFunc(\"%s\", %s)", wc, name, e->IsPure() ? "true" : "false");
StartBlock();
Emit("type = make_intrusive<FuncType>(make_intrusive<RecordType>(new type_decl_list()), %s, "
"FUNC_FLAVOR_FUNCTION);",
GenTypeName(t));
StartBlock();
Emit(
"type = make_intrusive<FuncType>(make_intrusive<RecordType>(new type_decl_list()), %s, "
"FUNC_FLAVOR_FUNCTION);",
GenTypeName(t));
EndBlock();
EndBlock();
Emit("ValPtr Invoke(zeek::Args* args, Frame* parent) const override");
StartBlock();
Emit("ValPtr Invoke(zeek::Args* args, Frame* parent) const override");
StartBlock();
if ( IsNativeType(t) )
GenInvokeBody(name, t, "parent");
else
Emit("return %s(parent);", name);
if ( IsNativeType(t) )
GenInvokeBody(name, t, "parent");
else
Emit("return %s(parent);", name);
EndBlock();
EndBlock(true);
EndBlock();
EndBlock(true);
// Now the implementation of computing 'e'.
Emit("static %s %s(Frame* f__CPP)", FullTypeName(t), name);
StartBlock();
// Now the implementation of computing 'e'.
Emit("static %s %s(Frame* f__CPP)", FullTypeName(t), name);
StartBlock();
Emit("return %s;", GenExpr(e, GEN_NATIVE));
EndBlock();
Emit("return %s;", GenExpr(e, GEN_NATIVE));
EndBlock();
Emit("CallExprPtr %s;", ename);
}
Emit("CallExprPtr %s;", ename);
}
bool CPPCompile::IsSimpleInitExpr(const ExprPtr& e)
{
switch ( e->Tag() )
{
case EXPR_CONST:
case EXPR_NAME:
return true;
bool CPPCompile::IsSimpleInitExpr(const ExprPtr& e) {
switch ( e->Tag() ) {
case EXPR_CONST:
case EXPR_NAME: return true;
case EXPR_RECORD_COERCE:
{ // look for coercion of empty record
auto op = e->GetOp1();
case EXPR_RECORD_COERCE: { // look for coercion of empty record
auto op = e->GetOp1();
if ( op->Tag() != EXPR_RECORD_CONSTRUCTOR )
return false;
if ( op->Tag() != EXPR_RECORD_CONSTRUCTOR )
return false;
auto rc = static_cast<const RecordConstructorExpr*>(op.get());
const auto& exprs = rc->Op()->AsListExpr()->Exprs();
auto rc = static_cast<const RecordConstructorExpr*>(op.get());
const auto& exprs = rc->Op()->AsListExpr()->Exprs();
return exprs.length() == 0;
}
return exprs.length() == 0;
}
default:
return false;
}
}
default: return false;
}
}
string CPPCompile::InitExprName(const ExprPtr& e)
{
return init_exprs.KeyName(e);
}
string CPPCompile::InitExprName(const ExprPtr& e) { return init_exprs.KeyName(e); }
void CPPCompile::InitializeFieldMappings()
{
Emit("std::vector<CPP_FieldMapping> CPP__field_mappings__ = ");
void CPPCompile::InitializeFieldMappings() {
Emit("std::vector<CPP_FieldMapping> CPP__field_mappings__ = ");
StartBlock();
StartBlock();
for ( const auto& mapping : field_decls )
{
auto rt_arg = Fmt(mapping.first);
auto td = mapping.second;
auto type_arg = Fmt(TypeOffset(td->type));
auto attrs_arg = Fmt(AttributesOffset(td->attrs));
for ( const auto& mapping : field_decls ) {
auto rt_arg = Fmt(mapping.first);
auto td = mapping.second;
auto type_arg = Fmt(TypeOffset(td->type));
auto attrs_arg = Fmt(AttributesOffset(td->attrs));
Emit("CPP_FieldMapping(%s, \"%s\", %s, %s),", rt_arg, td->id, type_arg, attrs_arg);
}
Emit("CPP_FieldMapping(%s, \"%s\", %s, %s),", rt_arg, td->id, type_arg, attrs_arg);
}
EndBlock(true);
}
EndBlock(true);
}
void CPPCompile::InitializeEnumMappings()
{
Emit("std::vector<CPP_EnumMapping> CPP__enum_mappings__ = ");
void CPPCompile::InitializeEnumMappings() {
Emit("std::vector<CPP_EnumMapping> CPP__enum_mappings__ = ");
StartBlock();
StartBlock();
for ( const auto& mapping : enum_names )
Emit("CPP_EnumMapping(%s, \"%s\"),", Fmt(mapping.first), mapping.second);
for ( const auto& mapping : enum_names )
Emit("CPP_EnumMapping(%s, \"%s\"),", Fmt(mapping.first), mapping.second);
EndBlock(true);
}
EndBlock(true);
}
void CPPCompile::InitializeBiFs()
{
Emit("std::vector<CPP_LookupBiF> CPP__BiF_lookups__ = ");
void CPPCompile::InitializeBiFs() {
Emit("std::vector<CPP_LookupBiF> CPP__BiF_lookups__ = ");
StartBlock();
StartBlock();
for ( const auto& b : BiFs )
Emit("CPP_LookupBiF(%s, \"%s\"),", b.first, b.second);
for ( const auto& b : BiFs )
Emit("CPP_LookupBiF(%s, \"%s\"),", b.first, b.second);
EndBlock(true);
}
EndBlock(true);
}
void CPPCompile::InitializeStrings()
{
Emit("std::vector<const char*> CPP__Strings =");
void CPPCompile::InitializeStrings() {
Emit("std::vector<const char*> CPP__Strings =");
StartBlock();
StartBlock();
for ( const auto& s : ordered_tracked_strings )
Emit("\"%s\",", s);
for ( const auto& s : ordered_tracked_strings )
Emit("\"%s\",", s);
EndBlock(true);
}
EndBlock(true);
}
void CPPCompile::InitializeHashes()
{
Emit("std::vector<p_hash_type> CPP__Hashes =");
void CPPCompile::InitializeHashes() {
Emit("std::vector<p_hash_type> CPP__Hashes =");
StartBlock();
StartBlock();
for ( const auto& h : ordered_tracked_hashes )
Emit(Fmt(h) + ",");
for ( const auto& h : ordered_tracked_hashes )
Emit(Fmt(h) + ",");
EndBlock(true);
}
EndBlock(true);
}
void CPPCompile::InitializeConsts()
{
Emit("std::vector<CPP_ValElem> CPP__ConstVals =");
void CPPCompile::InitializeConsts() {
Emit("std::vector<CPP_ValElem> CPP__ConstVals =");
StartBlock();
StartBlock();
for ( const auto& c : consts )
Emit("CPP_ValElem(%s, %s),", TypeTagName(c.first), Fmt(c.second));
for ( const auto& c : consts )
Emit("CPP_ValElem(%s, %s),", TypeTagName(c.first), Fmt(c.second));
EndBlock(true);
}
EndBlock(true);
}
void CPPCompile::InitializeGlobals()
{
Emit("static void init_globals__CPP()");
StartBlock();
void CPPCompile::InitializeGlobals() {
Emit("static void init_globals__CPP()");
StartBlock();
Emit("Frame* f__CPP = nullptr;");
NL();
Emit("Frame* f__CPP = nullptr;");
NL();
for ( const auto& ginit : IDOptInfo::GetGlobalInitExprs() )
{
auto g = ginit.Id();
if ( pfs.Globals().count(g) == 0 )
continue;
for ( const auto& ginit : IDOptInfo::GetGlobalInitExprs() ) {
auto g = ginit.Id();
if ( pfs.Globals().count(g) == 0 )
continue;
auto ic = ginit.IC();
auto& init = ginit.Init();
auto ic = ginit.IC();
auto& init = ginit.Init();
if ( ic == INIT_NONE )
Emit(GenExpr(init, GEN_NATIVE, true) + ";");
if ( ic == INIT_NONE )
Emit(GenExpr(init, GEN_NATIVE, true) + ";");
else
{
// This branch occurs for += or -= initializations that
// use associated functions.
string ics;
if ( ic == INIT_EXTRA )
ics = "INIT_EXTRA";
else if ( ic == INIT_REMOVE )
ics = "INIT_REMOVE";
else
reporter->FatalError("bad initialization class in CPPCompile::InitializeGlobals()");
else {
// This branch occurs for += or -= initializations that
// use associated functions.
string ics;
if ( ic == INIT_EXTRA )
ics = "INIT_EXTRA";
else if ( ic == INIT_REMOVE )
ics = "INIT_REMOVE";
else
reporter->FatalError("bad initialization class in CPPCompile::InitializeGlobals()");
Emit("%s->SetValue(%s, %s);", globals[g->Name()], GenExpr(init, GEN_NATIVE, true), ics);
}
Emit("%s->SetValue(%s, %s);", globals[g->Name()], GenExpr(init, GEN_NATIVE, true), ics);
}
const auto& attrs = g->GetAttrs();
if ( attrs )
{
string attr_tags;
string attr_vals;
BuildAttrs(attrs, attr_tags, attr_vals);
Emit("assign_attrs__CPP(%s, %s, %s);", globals[g->Name()], attr_tags, attr_vals);
}
}
const auto& attrs = g->GetAttrs();
if ( attrs ) {
string attr_tags;
string attr_vals;
BuildAttrs(attrs, attr_tags, attr_vals);
Emit("assign_attrs__CPP(%s, %s, %s);", globals[g->Name()], attr_tags, attr_vals);
}
}
EndBlock();
}
EndBlock();
}
void CPPCompile::GenInitHook()
{
NL();
void CPPCompile::GenInitHook() {
NL();
Emit("int hook_in_init()");
Emit("int hook_in_init()");
StartBlock();
StartBlock();
Emit("CPP_init_funcs.push_back(init__CPP);");
Emit("CPP_init_funcs.push_back(init__CPP);");
if ( standalone )
GenLoad();
if ( standalone )
GenLoad();
Emit("return 0;");
EndBlock();
Emit("return 0;");
EndBlock();
// Trigger the activation of the hook at run-time.
NL();
Emit("static int dummy = hook_in_init();\n");
}
// Trigger the activation of the hook at run-time.
NL();
Emit("static int dummy = hook_in_init();\n");
}
void CPPCompile::GenStandaloneActivation()
{
NL();
void CPPCompile::GenStandaloneActivation() {
NL();
Emit("void standalone_activation__CPP()");
StartBlock();
Emit("void standalone_activation__CPP()");
StartBlock();
Emit("finish_init__CPP();");
NL();
Emit("finish_init__CPP();");
NL();
// For events and hooks, we need to add each compiled body *unless*
// it's already there (which could be the case if the standalone
// code wasn't run standalone but instead with the original scripts).
// For events, we also register them in order to activate the
// associated scripts.
// For events and hooks, we need to add each compiled body *unless*
// it's already there (which could be the case if the standalone
// code wasn't run standalone but instead with the original scripts).
// For events, we also register them in order to activate the
// associated scripts.
// First, build up a list of per-hook/event handler bodies.
unordered_map<const Func*, vector<p_hash_type>> func_bodies;
// First, build up a list of per-hook/event handler bodies.
unordered_map<const Func*, vector<p_hash_type>> func_bodies;
for ( const auto& func : funcs )
{
if ( func.ShouldSkip() )
continue;
auto f = func.Func();
auto fname = BodyName(func);
auto bname = Canonicalize(fname.c_str()) + "_zf";
if ( compiled_funcs.count(bname) == 0 )
// We didn't wind up compiling it.
continue;
auto bh = body_hashes.find(bname);
ASSERT(bh != body_hashes.end());
func_bodies[f].push_back(bh->second);
}
for ( auto& fb : func_bodies )
{
string hashes;
for ( auto h : fb.second )
{
if ( hashes.size() > 0 )
hashes += ", ";
hashes += Fmt(h);
}
hashes = "{" + hashes + "}";
auto f = fb.first;
auto fn = f->Name();
const auto& ft = f->GetType();
auto var = extract_var_name(fn);
auto mod = extract_module_name(fn);
auto fid = lookup_ID(var.c_str(), mod.c_str(), false, true, false);
if ( ! fid )
reporter->InternalError("can't find identifier %s", fn);
for ( const auto& func : funcs ) {
if ( func.ShouldSkip() )
continue;
auto exported = fid->IsExport() ? "true" : "false";
auto f = func.Func();
auto fname = BodyName(func);
auto bname = Canonicalize(fname.c_str()) + "_zf";
Emit("activate_bodies__CPP(\"%s\", \"%s\", %s, %s, %s);", var, mod, exported,
GenTypeName(ft), hashes);
}
if ( compiled_funcs.count(bname) == 0 )
// We didn't wind up compiling it.
continue;
EndBlock();
auto bh = body_hashes.find(bname);
ASSERT(bh != body_hashes.end());
func_bodies[f].push_back(bh->second);
}
NL();
Emit("void standalone_init__CPP()");
StartBlock();
Emit("init__CPP();");
Emit("standalone_activation__CPP();");
Emit("standalone_finalizations.push_back(load_BiFs__CPP);");
EndBlock();
}
for ( auto& fb : func_bodies ) {
string hashes;
for ( auto h : fb.second ) {
if ( hashes.size() > 0 )
hashes += ", ";
void CPPCompile::GenLoad()
{
Emit("register_scripts__CPP(%s, standalone_init__CPP);", Fmt(total_hash));
printf("global init_CPP_%llu = load_CPP(%llu);\n", total_hash, total_hash);
}
hashes += Fmt(h);
}
} // zeek::detail
hashes = "{" + hashes + "}";
auto f = fb.first;
auto fn = f->Name();
const auto& ft = f->GetType();
auto var = extract_var_name(fn);
auto mod = extract_module_name(fn);
auto fid = lookup_ID(var.c_str(), mod.c_str(), false, true, false);
if ( ! fid )
reporter->InternalError("can't find identifier %s", fn);
auto exported = fid->IsExport() ? "true" : "false";
Emit("activate_bodies__CPP(\"%s\", \"%s\", %s, %s, %s);", var, mod, exported, GenTypeName(ft), hashes);
}
EndBlock();
NL();
Emit("void standalone_init__CPP()");
StartBlock();
Emit("init__CPP();");
Emit("standalone_activation__CPP();");
Emit("standalone_finalizations.push_back(load_BiFs__CPP);");
EndBlock();
}
void CPPCompile::GenLoad() {
Emit("register_scripts__CPP(%s, standalone_init__CPP);", Fmt(total_hash));
printf("global init_CPP_%llu = load_CPP(%llu);\n", total_hash, total_hash);
}
} // namespace zeek::detail

File diff suppressed because it is too large Load diff

View file

@ -71,8 +71,7 @@
#pragma once
namespace zeek::detail
{
namespace zeek::detail {
class CPPCompile;
@ -81,595 +80,535 @@ class CPP_InitInfo;
// Abstract class for tracking information about a collection of initialization
// items.
class CPP_InitsInfo
{
class CPP_InitsInfo {
public:
CPP_InitsInfo(std::string _tag, std::string type) : tag(std::move(_tag))
{
base_name = std::string("CPP__") + tag + "__";
CPP_type = tag + type;
}
CPP_InitsInfo(std::string _tag, std::string type) : tag(std::move(_tag)) {
base_name = std::string("CPP__") + tag + "__";
CPP_type = tag + type;
}
virtual ~CPP_InitsInfo() { }
virtual ~CPP_InitsInfo() {}
// Returns the name of the C++ global that will hold the items' values
// at run-time, once initialized. These are all vectors, for which
// the generated code accesses a particular item by indexing the vector.
const std::string& InitsName() const { return base_name; }
// Returns the name of the C++ global that will hold the items' values
// at run-time, once initialized. These are all vectors, for which
// the generated code accesses a particular item by indexing the vector.
const std::string& InitsName() const { return base_name; }
// Returns the name of the C++ global used to hold the table we employ
// for table-driven initialization.
std::string InitializersName() const { return base_name + "init"; }
// Returns the name of the C++ global used to hold the table we employ
// for table-driven initialization.
std::string InitializersName() const { return base_name + "init"; }
// Returns the "name" of the given element in the run-time vector
// associated with this collection of initialization items. It's not
// really a name but rather a vector index, so for example Name(12)
// might return "CPP__Pattern__[12]", but we use the term Name because
// the representation used to be individualized globals, such as
// "CPP__Pattern__12".
std::string Name(int index) const;
// Returns the "name" of the given element in the run-time vector
// associated with this collection of initialization items. It's not
// really a name but rather a vector index, so for example Name(12)
// might return "CPP__Pattern__[12]", but we use the term Name because
// the representation used to be individualized globals, such as
// "CPP__Pattern__12".
std::string Name(int index) const;
// Returns the name that will correspond to the next item added to
// this set.
std::string NextName() const { return Name(size); }
// Returns the name that will correspond to the next item added to
// this set.
std::string NextName() const { return Name(size); }
// The largest initialization cohort of any item in this collection.
int MaxCohort() const { return static_cast<int>(instances.size()) - 1; }
// The largest initialization cohort of any item in this collection.
int MaxCohort() const { return static_cast<int>(instances.size()) - 1; }
// Returns the number of initializations in this collection that belong
// to the given cohort c.
int CohortSize(int c) const { return c > MaxCohort() ? 0 : instances[c].size(); }
// Returns the number of initializations in this collection that belong
// to the given cohort c.
int CohortSize(int c) const { return c > MaxCohort() ? 0 : instances[c].size(); }
// Returns the C++ type associated with this collection's run-time vector.
// This might be, for example, "PatternVal"
const std::string& CPPType() const { return CPP_type; }
// Returns the C++ type associated with this collection's run-time vector.
// This might be, for example, "PatternVal"
const std::string& CPPType() const { return CPP_type; }
// Sets the associated C++ type.
virtual void SetCPPType(std::string ct) { CPP_type = std::move(ct); }
// Sets the associated C++ type.
virtual void SetCPPType(std::string ct) { CPP_type = std::move(ct); }
// Returns the type associated with the table used for initialization
// (i.e., this is the type of the global returned by InitializersName()).
std::string InitsType() const { return inits_type; }
// Returns the type associated with the table used for initialization
// (i.e., this is the type of the global returned by InitializersName()).
std::string InitsType() const { return inits_type; }
// Add a new initialization instance to the collection.
void AddInstance(std::shared_ptr<CPP_InitInfo> g);
// Add a new initialization instance to the collection.
void AddInstance(std::shared_ptr<CPP_InitInfo> g);
// Emit code to populate the table used to initialize this collection.
void GenerateInitializers(CPPCompile* c);
// Emit code to populate the table used to initialize this collection.
void GenerateInitializers(CPPCompile* c);
protected:
// Computes offset_set - see below.
void BuildOffsetSet(CPPCompile* c);
// Computes offset_set - see below.
void BuildOffsetSet(CPPCompile* c);
// Returns a declaration suitable for the run-time vector that holds
// the initialized items in the collection.
std::string Declare() const;
// Returns a declaration suitable for the run-time vector that holds
// the initialized items in the collection.
std::string Declare() const;
// For a given cohort, generates the associated table elements for
// creating it.
void BuildCohort(CPPCompile* c, std::vector<std::shared_ptr<CPP_InitInfo>>& cohort);
// For a given cohort, generates the associated table elements for
// creating it.
void BuildCohort(CPPCompile* c, std::vector<std::shared_ptr<CPP_InitInfo>>& cohort);
// Given the initialization type and initializers for with a given
// cohort element, build the associated table element.
virtual void BuildCohortElement(CPPCompile* c, std::string init_type,
std::vector<std::string>& ivs);
// Given the initialization type and initializers for with a given
// cohort element, build the associated table element.
virtual void BuildCohortElement(CPPCompile* c, std::string init_type, std::vector<std::string>& ivs);
// Total number of initializers.
int size = 0;
// Total number of initializers.
int size = 0;
// Each cohort is represented by a vector whose elements correspond
// to the initialization information for a single item. This variable
// holds a vector of cohorts, indexed by the number of the cohort.
// (Note, some cohorts may be empty.)
std::vector<std::vector<std::shared_ptr<CPP_InitInfo>>> instances;
// Each cohort is represented by a vector whose elements correspond
// to the initialization information for a single item. This variable
// holds a vector of cohorts, indexed by the number of the cohort.
// (Note, some cohorts may be empty.)
std::vector<std::vector<std::shared_ptr<CPP_InitInfo>>> instances;
// Each cohort has associated with it a vector of offsets, specifying
// positions in the run-time vector of the items in the cohort.
//
// We reduce each such vector to an index into the collection of
// such vectors (as managed by an IndicesManager - see below).
//
// Once we've done that reduction, we can represent each cohort
// using a single index, and thus all of the cohorts using a vector
// of indices. We then reduce *that* vector to a single index,
// again using the IndicesManager. We store that single index
// in the "offset_set" variable.
int offset_set = 0;
// Each cohort has associated with it a vector of offsets, specifying
// positions in the run-time vector of the items in the cohort.
//
// We reduce each such vector to an index into the collection of
// such vectors (as managed by an IndicesManager - see below).
//
// Once we've done that reduction, we can represent each cohort
// using a single index, and thus all of the cohorts using a vector
// of indices. We then reduce *that* vector to a single index,
// again using the IndicesManager. We store that single index
// in the "offset_set" variable.
int offset_set = 0;
// Tag used to distinguish a particular collection of constants.
std::string tag;
// Tag used to distinguish a particular collection of constants.
std::string tag;
// C++ name for this collection of constants.
std::string base_name;
// C++ name for this collection of constants.
std::string base_name;
// C++ type associated with a single instance of these constants.
std::string CPP_type;
// C++ type associated with a single instance of these constants.
std::string CPP_type;
// C++ type associated with the collection of initializers.
std::string inits_type;
};
// C++ type associated with the collection of initializers.
std::string inits_type;
};
// A class for a collection of initialization items for which each item
// has a "custom" initializer (that is, a bespoke C++ object, rather than
// a simple C++ type or a vector of indices).
class CPP_CustomInitsInfo : public CPP_InitsInfo
{
class CPP_CustomInitsInfo : public CPP_InitsInfo {
public:
CPP_CustomInitsInfo(std::string _tag, std::string _type)
: CPP_InitsInfo(std::move(_tag), std::move(_type))
{
BuildInitType();
}
CPP_CustomInitsInfo(std::string _tag, std::string _type) : CPP_InitsInfo(std::move(_tag), std::move(_type)) {
BuildInitType();
}
void SetCPPType(std::string ct) override
{
CPP_InitsInfo::SetCPPType(std::move(ct));
BuildInitType();
}
void SetCPPType(std::string ct) override {
CPP_InitsInfo::SetCPPType(std::move(ct));
BuildInitType();
}
private:
void BuildInitType() { inits_type = std::string("CPP_CustomInits<") + CPPType() + ">"; }
};
void BuildInitType() { inits_type = std::string("CPP_CustomInits<") + CPPType() + ">"; }
};
// A class for a collection of initialization items corresponding to "basic"
// constants, i.e., those that can be represented either directly as C++
// constants, or as indices into a vector of C++ objects.
class CPP_BasicConstInitsInfo : public CPP_CustomInitsInfo
{
class CPP_BasicConstInitsInfo : public CPP_CustomInitsInfo {
public:
// In the following, if "c_type" is non-empty then it specifies the
// C++ type used to directly represent the constant. If empty, it
// indicates that we instead use an index into a separate vector.
CPP_BasicConstInitsInfo(std::string _tag, std::string type, std::string c_type)
: CPP_CustomInitsInfo(std::move(_tag), std::move(type))
{
if ( c_type.empty() )
inits_type = std::string("CPP_") + tag + "Consts";
else
inits_type = std::string("CPP_BasicConsts<") + CPP_type + ", " + c_type + ", " + tag +
"Val>";
}
// In the following, if "c_type" is non-empty then it specifies the
// C++ type used to directly represent the constant. If empty, it
// indicates that we instead use an index into a separate vector.
CPP_BasicConstInitsInfo(std::string _tag, std::string type, std::string c_type)
: CPP_CustomInitsInfo(std::move(_tag), std::move(type)) {
if ( c_type.empty() )
inits_type = std::string("CPP_") + tag + "Consts";
else
inits_type = std::string("CPP_BasicConsts<") + CPP_type + ", " + c_type + ", " + tag + "Val>";
}
void BuildCohortElement(CPPCompile* c, std::string init_type,
std::vector<std::string>& ivs) override;
};
void BuildCohortElement(CPPCompile* c, std::string init_type, std::vector<std::string>& ivs) override;
};
// A class for a collection of initialization items that are defined using
// other initialization items.
class CPP_CompoundInitsInfo : public CPP_InitsInfo
{
class CPP_CompoundInitsInfo : public CPP_InitsInfo {
public:
CPP_CompoundInitsInfo(std::string _tag, std::string type)
: CPP_InitsInfo(std::move(_tag), std::move(type))
{
if ( tag == "Type" )
// These need a refined version of CPP_IndexedInits
// in order to build different types dynamically.
inits_type = "CPP_TypeInits";
else
inits_type = std::string("CPP_IndexedInits<") + CPPType() + ">";
}
CPP_CompoundInitsInfo(std::string _tag, std::string type) : CPP_InitsInfo(std::move(_tag), std::move(type)) {
if ( tag == "Type" )
// These need a refined version of CPP_IndexedInits
// in order to build different types dynamically.
inits_type = "CPP_TypeInits";
else
inits_type = std::string("CPP_IndexedInits<") + CPPType() + ">";
}
void BuildCohortElement(CPPCompile* c, std::string init_type,
std::vector<std::string>& ivs) override;
};
void BuildCohortElement(CPPCompile* c, std::string init_type, std::vector<std::string>& ivs) override;
};
// Abstract class for tracking information about a single initialization item.
class CPP_InitInfo
{
class CPP_InitInfo {
public:
CPP_InitInfo(const IntrusivePtr<Obj>& _o) : o(_o.get()) { }
CPP_InitInfo(const Obj* _o) : o(_o) { }
CPP_InitInfo(const IntrusivePtr<Obj>& _o) : o(_o.get()) {}
CPP_InitInfo(const Obj* _o) : o(_o) {}
virtual ~CPP_InitInfo() { }
virtual ~CPP_InitInfo() {}
// Associates this item with an initialization collection and run-time
// vector offset.
void SetOffset(const CPP_InitsInfo* _inits_collection, int _offset)
{
inits_collection = _inits_collection;
offset = _offset;
}
// Associates this item with an initialization collection and run-time
// vector offset.
void SetOffset(const CPP_InitsInfo* _inits_collection, int _offset) {
inits_collection = _inits_collection;
offset = _offset;
}
// Returns the offset for this item into the associated run-time vector.
int Offset() const { return offset; }
// Returns the offset for this item into the associated run-time vector.
int Offset() const { return offset; }
// Returns the name that should be used for referring to this
// value in the generated code.
std::string Name() const { return inits_collection->Name(offset); }
// Returns the name that should be used for referring to this
// value in the generated code.
std::string Name() const { return inits_collection->Name(offset); }
// Returns this item's initialization cohort.
int InitCohort() const { return init_cohort; }
// Returns this item's initialization cohort.
int InitCohort() const { return init_cohort; }
// Returns this item's "final" initialization cohort. See
// discussion below.
int FinalInitCohort() const { return final_init_cohort ? final_init_cohort : init_cohort; }
// Returns this item's "final" initialization cohort. See
// discussion below.
int FinalInitCohort() const { return final_init_cohort ? final_init_cohort : init_cohort; }
// Returns the type used for this initializer.
virtual std::string InitializerType() const { return "<shouldn't-be-used>"; }
// Returns the type used for this initializer.
virtual std::string InitializerType() const { return "<shouldn't-be-used>"; }
// Returns values used for creating this value, one element per
// constructor parameter.
virtual void InitializerVals(std::vector<std::string>& ivs) const = 0;
// Returns values used for creating this value, one element per
// constructor parameter.
virtual void InitializerVals(std::vector<std::string>& ivs) const = 0;
const Obj* InitObj() const { return o; }
const Obj* InitObj() const { return o; }
protected:
// Returns an offset (into the run-time vector holding all Zeek
// constant values) corresponding to the given value. Registers
// the constant if needed.
std::string ValElem(CPPCompile* c, ValPtr v);
// Returns an offset (into the run-time vector holding all Zeek
// constant values) corresponding to the given value. Registers
// the constant if needed.
std::string ValElem(CPPCompile* c, ValPtr v);
// By default, values have no dependencies on other values
// being first initialized. Those that do must increase this
// value in their constructors.
int init_cohort = 0;
// By default, values have no dependencies on other values
// being first initialized. Those that do must increase this
// value in their constructors.
int init_cohort = 0;
// Some initializers (record and list types, in particular) become
// available for other initializers to use them after the first
// cohort is initialized; however, the final initialization comes
// later. If non-zero, this variable tracks the latter.
int final_init_cohort = 0;
// Some initializers (record and list types, in particular) become
// available for other initializers to use them after the first
// cohort is initialized; however, the final initialization comes
// later. If non-zero, this variable tracks the latter.
int final_init_cohort = 0;
// Tracks the collection to which this item belongs.
const CPP_InitsInfo* inits_collection = nullptr;
// Tracks the collection to which this item belongs.
const CPP_InitsInfo* inits_collection = nullptr;
// Offset of this item in the collection, or -1 if no association.
int offset = -1;
// Offset of this item in the collection, or -1 if no association.
int offset = -1;
// Associated object. Used for annotating output.
const Obj* o;
};
// Associated object. Used for annotating output.
const Obj* o;
};
// Information associated with initializing a basic (non-compound) constant.
class BasicConstInfo : public CPP_InitInfo
{
class BasicConstInfo : public CPP_InitInfo {
public:
BasicConstInfo(std::string _val) : CPP_InitInfo(nullptr), val(std::move(_val)) { }
BasicConstInfo(std::string _val) : CPP_InitInfo(nullptr), val(std::move(_val)) {}
void InitializerVals(std::vector<std::string>& ivs) const override { ivs.emplace_back(val); }
void InitializerVals(std::vector<std::string>& ivs) const override { ivs.emplace_back(val); }
private:
// All we need to track is the C++ representation of the constant.
std::string val;
};
// All we need to track is the C++ representation of the constant.
std::string val;
};
// Information associated with initializing a constant whose Val constructor
// takes a string.
class DescConstInfo : public CPP_InitInfo
{
class DescConstInfo : public CPP_InitInfo {
public:
DescConstInfo(CPPCompile* c, ValPtr v);
DescConstInfo(CPPCompile* c, ValPtr v);
void InitializerVals(std::vector<std::string>& ivs) const override { ivs.emplace_back(init); }
void InitializerVals(std::vector<std::string>& ivs) const override { ivs.emplace_back(init); }
private:
std::string init;
};
std::string init;
};
class EnumConstInfo : public CPP_InitInfo
{
class EnumConstInfo : public CPP_InitInfo {
public:
EnumConstInfo(CPPCompile* c, ValPtr v);
EnumConstInfo(CPPCompile* c, ValPtr v);
void InitializerVals(std::vector<std::string>& ivs) const override
{
ivs.emplace_back(std::to_string(e_type));
ivs.emplace_back(std::to_string(e_val));
}
void InitializerVals(std::vector<std::string>& ivs) const override {
ivs.emplace_back(std::to_string(e_type));
ivs.emplace_back(std::to_string(e_val));
}
private:
int e_type; // an index into the enum's Zeek type
int e_val; // integer value of the enum
};
int e_type; // an index into the enum's Zeek type
int e_val; // integer value of the enum
};
class StringConstInfo : public CPP_InitInfo
{
class StringConstInfo : public CPP_InitInfo {
public:
StringConstInfo(CPPCompile* c, ValPtr v);
StringConstInfo(CPPCompile* c, ValPtr v);
void InitializerVals(std::vector<std::string>& ivs) const override
{
ivs.emplace_back(std::to_string(chars));
ivs.emplace_back(std::to_string(len));
}
void InitializerVals(std::vector<std::string>& ivs) const override {
ivs.emplace_back(std::to_string(chars));
ivs.emplace_back(std::to_string(len));
}
private:
int chars; // index into vector of char*'s
int len; // length of the string
};
int chars; // index into vector of char*'s
int len; // length of the string
};
class PatternConstInfo : public CPP_InitInfo
{
class PatternConstInfo : public CPP_InitInfo {
public:
PatternConstInfo(CPPCompile* c, ValPtr v);
PatternConstInfo(CPPCompile* c, ValPtr v);
void InitializerVals(std::vector<std::string>& ivs) const override
{
ivs.emplace_back(std::to_string(pattern));
ivs.emplace_back(std::to_string(is_case_insensitive));
ivs.emplace_back(std::to_string(is_single_line));
}
void InitializerVals(std::vector<std::string>& ivs) const override {
ivs.emplace_back(std::to_string(pattern));
ivs.emplace_back(std::to_string(is_case_insensitive));
ivs.emplace_back(std::to_string(is_single_line));
}
private:
int pattern; // index into string representation of pattern
int is_case_insensitive; // case-insensitivity flag, 0 or 1
int is_single_line; // single-line flag, 0 or 1
};
int pattern; // index into string representation of pattern
int is_case_insensitive; // case-insensitivity flag, 0 or 1
int is_single_line; // single-line flag, 0 or 1
};
class PortConstInfo : public CPP_InitInfo
{
class PortConstInfo : public CPP_InitInfo {
public:
PortConstInfo(ValPtr v)
: CPP_InitInfo(v), p(static_cast<UnsignedValImplementation*>(v->AsPortVal())->Get())
{
}
PortConstInfo(ValPtr v) : CPP_InitInfo(v), p(static_cast<UnsignedValImplementation*>(v->AsPortVal())->Get()) {}
void InitializerVals(std::vector<std::string>& ivs) const override
{
ivs.emplace_back(std::to_string(p) + "U");
}
void InitializerVals(std::vector<std::string>& ivs) const override { ivs.emplace_back(std::to_string(p) + "U"); }
private:
zeek_uint_t p;
};
zeek_uint_t p;
};
// Abstract class for compound items (those defined in terms of other items).
class CompoundItemInfo : public CPP_InitInfo
{
class CompoundItemInfo : public CPP_InitInfo {
public:
// The first of these is used for items with custom Zeek types,
// the second when the type is generic/inapplicable.
CompoundItemInfo(CPPCompile* c, ValPtr v);
CompoundItemInfo(CPPCompile* _c) : CPP_InitInfo(nullptr), c(_c) { type = -1; }
// The first of these is used for items with custom Zeek types,
// the second when the type is generic/inapplicable.
CompoundItemInfo(CPPCompile* c, ValPtr v);
CompoundItemInfo(CPPCompile* _c) : CPP_InitInfo(nullptr), c(_c) { type = -1; }
void InitializerVals(std::vector<std::string>& ivs) const override
{
if ( type >= 0 )
ivs.emplace_back(std::to_string(type));
void InitializerVals(std::vector<std::string>& ivs) const override {
if ( type >= 0 )
ivs.emplace_back(std::to_string(type));
for ( auto& v : vals )
ivs.push_back(v);
}
for ( auto& v : vals )
ivs.push_back(v);
}
protected:
CPPCompile* c;
int type;
std::vector<std::string> vals; // initialization values
};
CPPCompile* c;
int type;
std::vector<std::string> vals; // initialization values
};
// This next set corresponds to compound Zeek constants of various types.
class ListConstInfo : public CompoundItemInfo
{
class ListConstInfo : public CompoundItemInfo {
public:
ListConstInfo(CPPCompile* c, ValPtr v);
};
ListConstInfo(CPPCompile* c, ValPtr v);
};
class VectorConstInfo : public CompoundItemInfo
{
class VectorConstInfo : public CompoundItemInfo {
public:
VectorConstInfo(CPPCompile* c, ValPtr v);
};
VectorConstInfo(CPPCompile* c, ValPtr v);
};
class RecordConstInfo : public CompoundItemInfo
{
class RecordConstInfo : public CompoundItemInfo {
public:
RecordConstInfo(CPPCompile* c, ValPtr v);
};
RecordConstInfo(CPPCompile* c, ValPtr v);
};
class TableConstInfo : public CompoundItemInfo
{
class TableConstInfo : public CompoundItemInfo {
public:
TableConstInfo(CPPCompile* c, ValPtr v);
};
TableConstInfo(CPPCompile* c, ValPtr v);
};
class FileConstInfo : public CompoundItemInfo
{
class FileConstInfo : public CompoundItemInfo {
public:
FileConstInfo(CPPCompile* c, ValPtr v);
};
FileConstInfo(CPPCompile* c, ValPtr v);
};
class FuncConstInfo : public CompoundItemInfo
{
class FuncConstInfo : public CompoundItemInfo {
public:
FuncConstInfo(CPPCompile* _c, ValPtr v);
FuncConstInfo(CPPCompile* _c, ValPtr v);
void InitializerVals(std::vector<std::string>& ivs) const override;
void InitializerVals(std::vector<std::string>& ivs) const override;
private:
FuncVal* fv;
};
FuncVal* fv;
};
// Initialization information for single attributes and sets of attributes.
class AttrInfo : public CompoundItemInfo
{
class AttrInfo : public CompoundItemInfo {
public:
AttrInfo(CPPCompile* c, const AttrPtr& attr);
};
AttrInfo(CPPCompile* c, const AttrPtr& attr);
};
class AttrsInfo : public CompoundItemInfo
{
class AttrsInfo : public CompoundItemInfo {
public:
AttrsInfo(CPPCompile* c, const AttributesPtr& attrs);
};
AttrsInfo(CPPCompile* c, const AttributesPtr& attrs);
};
// Information for initialization a Zeek global.
class GlobalInitInfo : public CPP_InitInfo
{
class GlobalInitInfo : public CPP_InitInfo {
public:
GlobalInitInfo(CPPCompile* c, const ID* g, std::string CPP_name);
GlobalInitInfo(CPPCompile* c, const ID* g, std::string CPP_name);
std::string InitializerType() const override { return "CPP_GlobalInit"; }
void InitializerVals(std::vector<std::string>& ivs) const override;
std::string InitializerType() const override { return "CPP_GlobalInit"; }
void InitializerVals(std::vector<std::string>& ivs) const override;
protected:
std::string Zeek_name;
std::string CPP_name;
int type;
int attrs;
std::string val;
bool exported;
bool func_with_no_val = false; // needed to handle some error situations
};
std::string Zeek_name;
std::string CPP_name;
int type;
int attrs;
std::string val;
bool exported;
bool func_with_no_val = false; // needed to handle some error situations
};
// Information for initializing an item corresponding to a Zeek function
// call, needed to associate complex expressions with attributes.
class CallExprInitInfo : public CPP_InitInfo
{
class CallExprInitInfo : public CPP_InitInfo {
public:
CallExprInitInfo(CPPCompile* c, ExprPtr e, std::string e_name, std::string wrapper_class);
CallExprInitInfo(CPPCompile* c, ExprPtr e, std::string e_name, std::string wrapper_class);
std::string InitializerType() const override
{
return std::string("CPP_CallExprInit<") + wrapper_class + ">";
}
void InitializerVals(std::vector<std::string>& ivs) const override { ivs.emplace_back(e_name); }
std::string InitializerType() const override { return std::string("CPP_CallExprInit<") + wrapper_class + ">"; }
void InitializerVals(std::vector<std::string>& ivs) const override { ivs.emplace_back(e_name); }
// Accessors, since code to initialize these is generated separately
// from that of most initialization collections.
const ExprPtr& GetExpr() const { return e; }
const std::string& Name() const { return e_name; }
const std::string& WrapperClass() const { return wrapper_class; }
// Accessors, since code to initialize these is generated separately
// from that of most initialization collections.
const ExprPtr& GetExpr() const { return e; }
const std::string& Name() const { return e_name; }
const std::string& WrapperClass() const { return wrapper_class; }
protected:
ExprPtr e;
std::string e_name;
std::string wrapper_class;
};
ExprPtr e;
std::string e_name;
std::string wrapper_class;
};
// Information for registering the class/function associated with a lambda.
class LambdaRegistrationInfo : public CPP_InitInfo
{
class LambdaRegistrationInfo : public CPP_InitInfo {
public:
LambdaRegistrationInfo(CPPCompile* c, std::string name, FuncTypePtr ft,
std::string wrapper_class, p_hash_type h, bool has_captures);
LambdaRegistrationInfo(CPPCompile* c, std::string name, FuncTypePtr ft, std::string wrapper_class, p_hash_type h,
bool has_captures);
std::string InitializerType() const override
{
return std::string("CPP_LambdaRegistration<") + wrapper_class + ">";
}
void InitializerVals(std::vector<std::string>& ivs) const override;
std::string InitializerType() const override {
return std::string("CPP_LambdaRegistration<") + wrapper_class + ">";
}
void InitializerVals(std::vector<std::string>& ivs) const override;
protected:
std::string name;
int func_type;
std::string wrapper_class;
p_hash_type h;
bool has_captures;
};
std::string name;
int func_type;
std::string wrapper_class;
p_hash_type h;
bool has_captures;
};
// Abstract class for representing information for initializing a Zeek type.
class AbstractTypeInfo : public CPP_InitInfo
{
class AbstractTypeInfo : public CPP_InitInfo {
public:
AbstractTypeInfo(CPPCompile* _c, TypePtr _t) : CPP_InitInfo(_t), c(_c), t(std::move(_t)) { }
AbstractTypeInfo(CPPCompile* _c, TypePtr _t) : CPP_InitInfo(_t), c(_c), t(std::move(_t)) {}
void InitializerVals(std::vector<std::string>& ivs) const override
{
ivs.emplace_back(std::to_string(static_cast<int>(t->Tag())));
AddInitializerVals(ivs);
}
void InitializerVals(std::vector<std::string>& ivs) const override {
ivs.emplace_back(std::to_string(static_cast<int>(t->Tag())));
AddInitializerVals(ivs);
}
virtual void AddInitializerVals(std::vector<std::string>& ivs) const { }
virtual void AddInitializerVals(std::vector<std::string>& ivs) const {}
protected:
CPPCompile* c;
TypePtr t; // the type we're initializing
};
CPPCompile* c;
TypePtr t; // the type we're initializing
};
// The following capture information for different Zeek types.
class BaseTypeInfo : public AbstractTypeInfo
{
class BaseTypeInfo : public AbstractTypeInfo {
public:
BaseTypeInfo(CPPCompile* _c, TypePtr _t) : AbstractTypeInfo(_c, std::move(_t)) { }
};
BaseTypeInfo(CPPCompile* _c, TypePtr _t) : AbstractTypeInfo(_c, std::move(_t)) {}
};
class EnumTypeInfo : public AbstractTypeInfo
{
class EnumTypeInfo : public AbstractTypeInfo {
public:
EnumTypeInfo(CPPCompile* _c, TypePtr _t) : AbstractTypeInfo(_c, std::move(_t)) { }
EnumTypeInfo(CPPCompile* _c, TypePtr _t) : AbstractTypeInfo(_c, std::move(_t)) {}
void AddInitializerVals(std::vector<std::string>& ivs) const override;
};
void AddInitializerVals(std::vector<std::string>& ivs) const override;
};
class OpaqueTypeInfo : public AbstractTypeInfo
{
class OpaqueTypeInfo : public AbstractTypeInfo {
public:
OpaqueTypeInfo(CPPCompile* _c, TypePtr _t) : AbstractTypeInfo(_c, std::move(_t)) { }
OpaqueTypeInfo(CPPCompile* _c, TypePtr _t) : AbstractTypeInfo(_c, std::move(_t)) {}
void AddInitializerVals(std::vector<std::string>& ivs) const override;
};
void AddInitializerVals(std::vector<std::string>& ivs) const override;
};
class TypeTypeInfo : public AbstractTypeInfo
{
class TypeTypeInfo : public AbstractTypeInfo {
public:
TypeTypeInfo(CPPCompile* c, TypePtr _t);
TypeTypeInfo(CPPCompile* c, TypePtr _t);
void AddInitializerVals(std::vector<std::string>& ivs) const override;
void AddInitializerVals(std::vector<std::string>& ivs) const override;
private:
TypePtr tt; // the type referred to by t
};
TypePtr tt; // the type referred to by t
};
class VectorTypeInfo : public AbstractTypeInfo
{
class VectorTypeInfo : public AbstractTypeInfo {
public:
VectorTypeInfo(CPPCompile* c, TypePtr _t);
VectorTypeInfo(CPPCompile* c, TypePtr _t);
void AddInitializerVals(std::vector<std::string>& ivs) const override;
void AddInitializerVals(std::vector<std::string>& ivs) const override;
private:
TypePtr yield;
};
TypePtr yield;
};
class ListTypeInfo : public AbstractTypeInfo
{
class ListTypeInfo : public AbstractTypeInfo {
public:
ListTypeInfo(CPPCompile* c, TypePtr _t);
ListTypeInfo(CPPCompile* c, TypePtr _t);
void AddInitializerVals(std::vector<std::string>& ivs) const override;
void AddInitializerVals(std::vector<std::string>& ivs) const override;
private:
const std::vector<TypePtr>& types;
};
const std::vector<TypePtr>& types;
};
class TableTypeInfo : public AbstractTypeInfo
{
class TableTypeInfo : public AbstractTypeInfo {
public:
TableTypeInfo(CPPCompile* c, TypePtr _t);
TableTypeInfo(CPPCompile* c, TypePtr _t);
void AddInitializerVals(std::vector<std::string>& ivs) const override;
void AddInitializerVals(std::vector<std::string>& ivs) const override;
private:
int indices;
TypePtr yield;
};
int indices;
TypePtr yield;
};
class FuncTypeInfo : public AbstractTypeInfo
{
class FuncTypeInfo : public AbstractTypeInfo {
public:
FuncTypeInfo(CPPCompile* c, TypePtr _t);
FuncTypeInfo(CPPCompile* c, TypePtr _t);
void AddInitializerVals(std::vector<std::string>& ivs) const override;
void AddInitializerVals(std::vector<std::string>& ivs) const override;
private:
FunctionFlavor flavor;
TypePtr params;
TypePtr yield;
};
FunctionFlavor flavor;
TypePtr params;
TypePtr yield;
};
class RecordTypeInfo : public AbstractTypeInfo
{
class RecordTypeInfo : public AbstractTypeInfo {
public:
RecordTypeInfo(CPPCompile* c, TypePtr _t);
RecordTypeInfo(CPPCompile* c, TypePtr _t);
void AddInitializerVals(std::vector<std::string>& ivs) const override;
void AddInitializerVals(std::vector<std::string>& ivs) const override;
private:
std::vector<std::string> field_names;
std::vector<TypePtr> field_types;
std::vector<int> field_attrs;
};
std::vector<std::string> field_names;
std::vector<TypePtr> field_types;
std::vector<int> field_attrs;
};
// Much of the table-driven initialization is based on vectors of indices,
// which we represent as vectors of int's, where each int is used to index a
@ -683,31 +622,29 @@ private:
// to a potentially large, deep set of indices using a single value - such as
// for CPP_InitsInfo's "offset_set" member variable.
class IndicesManager
{
class IndicesManager {
public:
IndicesManager() { }
IndicesManager() {}
// Adds a new vector-of-indices to the collection we're tracking,
// returning the offset that will be associated with it at run-time.
int AddIndices(std::vector<int> indices)
{
int n = indices_set.size();
indices_set.emplace_back(std::move(indices));
return n;
}
// Adds a new vector-of-indices to the collection we're tracking,
// returning the offset that will be associated with it at run-time.
int AddIndices(std::vector<int> indices) {
int n = indices_set.size();
indices_set.emplace_back(std::move(indices));
return n;
}
// Generates the initializations used to construct the managed
// vectors at run-time.
void Generate(CPPCompile* c);
// Generates the initializations used to construct the managed
// vectors at run-time.
void Generate(CPPCompile* c);
private:
// Each vector-of-indices being tracked. We could obtain some
// space and time savings by recognizing duplicate vectors
// (for example, empty vectors are very common), but as long
// as the code compiles and executes without undue overhead,
// this doesn't appear necessary.
std::vector<std::vector<int>> indices_set;
};
// Each vector-of-indices being tracked. We could obtain some
// space and time savings by recognizing duplicate vectors
// (for example, empty vectors are very common), but as long
// as the code compiles and executes without undue overhead,
// this doesn't appear necessary.
std::vector<std::vector<int>> indices_set;
};
} // zeek::detail
} // namespace zeek::detail

View file

@ -24,8 +24,7 @@
#include "zeek/script_opt/CPP/RuntimeVec.h"
#include "zeek/script_opt/ScriptOpt.h"
namespace zeek::detail
{
namespace zeek::detail {
using BoolValPtr = IntrusivePtr<zeek::BoolVal>;
using IntValPtr = IntrusivePtr<zeek::IntVal>;
@ -39,4 +38,4 @@ using FuncValPtr = IntrusivePtr<zeek::FuncVal>;
using FileValPtr = IntrusivePtr<zeek::FileVal>;
using SubNetValPtr = IntrusivePtr<zeek::SubNetVal>;
}
} // namespace zeek::detail

View file

@ -5,263 +5,231 @@
#include "zeek/EventRegistry.h"
#include "zeek/module_util.h"
namespace zeek::detail
{
namespace zeek::detail {
using namespace std;
vector<CPP_init_func> CPP_init_funcs;
// Calls all of the initialization hooks, in the order they were added.
void init_CPPs()
{
static bool need_init = true;
void init_CPPs() {
static bool need_init = true;
if ( need_init )
for ( auto f : CPP_init_funcs )
f();
if ( need_init )
for ( auto f : CPP_init_funcs )
f();
need_init = false;
}
need_init = false;
}
// This is a trick used to register the presence of compiled code.
// The initialization of the static variable will make CPP_init_hook
// non-null, which the main part of Zeek uses to tell that there's
// CPP code available.
static int flag_init_CPP()
{
CPP_init_hook = init_CPPs;
return 0;
}
static int flag_init_CPP() {
CPP_init_hook = init_CPPs;
return 0;
}
static int dummy = flag_init_CPP();
void register_type__CPP(TypePtr t, const string& name)
{
if ( t->GetName().size() > 0 )
// Already registered.
return;
void register_type__CPP(TypePtr t, const string& name) {
if ( t->GetName().size() > 0 )
// Already registered.
return;
t->SetName(name);
t->SetName(name);
auto id = install_ID(name.c_str(), GLOBAL_MODULE_NAME, true, false);
id->SetType(t);
id->MakeType();
}
auto id = install_ID(name.c_str(), GLOBAL_MODULE_NAME, true, false);
id->SetType(t);
id->MakeType();
}
void register_body__CPP(CPPStmtPtr body, int priority, p_hash_type hash, vector<string> events,
void (*finish_init)())
{
compiled_scripts[hash] = {std::move(body), priority, std::move(events), finish_init};
}
void register_body__CPP(CPPStmtPtr body, int priority, p_hash_type hash, vector<string> events, void (*finish_init)()) {
compiled_scripts[hash] = {std::move(body), priority, std::move(events), finish_init};
}
static unordered_map<p_hash_type, CompiledScript> compiled_standalone_scripts;
void register_standalone_body__CPP(CPPStmtPtr body, int priority, p_hash_type hash,
vector<string> events, void (*finish_init)())
{
// For standalone scripts we don't actually need finish_init, but
// we keep it for symmetry with compiled_scripts.
compiled_standalone_scripts[hash] = {std::move(body), priority, std::move(events), finish_init};
}
void register_standalone_body__CPP(CPPStmtPtr body, int priority, p_hash_type hash, vector<string> events,
void (*finish_init)()) {
// For standalone scripts we don't actually need finish_init, but
// we keep it for symmetry with compiled_scripts.
compiled_standalone_scripts[hash] = {std::move(body), priority, std::move(events), finish_init};
}
void register_lambda__CPP(CPPStmtPtr body, p_hash_type hash, const char* name, TypePtr t,
bool has_captures)
{
auto ft = cast_intrusive<FuncType>(t);
void register_lambda__CPP(CPPStmtPtr body, p_hash_type hash, const char* name, TypePtr t, bool has_captures) {
auto ft = cast_intrusive<FuncType>(t);
// Create the quasi-global.
auto id = install_ID(name, GLOBAL_MODULE_NAME, true, false);
auto func = make_intrusive<CPPLambdaFunc>(name, ft, body);
func->SetName(name);
// Create the quasi-global.
auto id = install_ID(name, GLOBAL_MODULE_NAME, true, false);
auto func = make_intrusive<CPPLambdaFunc>(name, ft, body);
func->SetName(name);
auto v = make_intrusive<FuncVal>(std::move(func));
id->SetVal(std::move(v));
id->SetType(ft);
auto v = make_intrusive<FuncVal>(std::move(func));
id->SetVal(std::move(v));
id->SetType(ft);
// Lambdas used in initializing global functions need to
// be registered, so that the initialization can find them.
// We do not, however, want to register *all* lambdas, because
// the ones that use captures cannot be used as regular
// function bodies.
if ( ! has_captures )
// Note, no support for lambdas that themselves refer
// to events.
register_body__CPP(body, 0, hash, {}, nullptr);
}
// Lambdas used in initializing global functions need to
// be registered, so that the initialization can find them.
// We do not, however, want to register *all* lambdas, because
// the ones that use captures cannot be used as regular
// function bodies.
if ( ! has_captures )
// Note, no support for lambdas that themselves refer
// to events.
register_body__CPP(body, 0, hash, {}, nullptr);
}
void register_scripts__CPP(p_hash_type h, void (*callback)())
{
ASSERT(standalone_callbacks.count(h) == 0);
standalone_callbacks[h] = callback;
}
void register_scripts__CPP(p_hash_type h, void (*callback)()) {
ASSERT(standalone_callbacks.count(h) == 0);
standalone_callbacks[h] = callback;
}
void activate_bodies__CPP(const char* fn, const char* module, bool exported, TypePtr t,
vector<p_hash_type> hashes)
{
auto ft = cast_intrusive<FuncType>(t);
auto fg = lookup_ID(fn, module, false, false, false);
void activate_bodies__CPP(const char* fn, const char* module, bool exported, TypePtr t, vector<p_hash_type> hashes) {
auto ft = cast_intrusive<FuncType>(t);
auto fg = lookup_ID(fn, module, false, false, false);
if ( ! fg )
{
fg = install_ID(fn, module, true, exported);
fg->SetType(ft);
}
if ( ! fg ) {
fg = install_ID(fn, module, true, exported);
fg->SetType(ft);
}
if ( ! fg->GetAttr(ATTR_IS_USED) )
fg->AddAttr(make_intrusive<Attr>(ATTR_IS_USED));
if ( ! fg->GetAttr(ATTR_IS_USED) )
fg->AddAttr(make_intrusive<Attr>(ATTR_IS_USED));
auto v = fg->GetVal();
if ( ! v )
{ // Create it.
vector<StmtPtr> no_bodies;
vector<int> no_priorities;
auto sf = make_intrusive<ScriptFunc>(fn, ft, no_bodies, no_priorities);
auto v = fg->GetVal();
if ( ! v ) { // Create it.
vector<StmtPtr> no_bodies;
vector<int> no_priorities;
auto sf = make_intrusive<ScriptFunc>(fn, ft, no_bodies, no_priorities);
v = make_intrusive<FuncVal>(std::move(sf));
fg->SetVal(v);
}
v = make_intrusive<FuncVal>(std::move(sf));
fg->SetVal(v);
}
auto f = v->AsFunc();
auto f = v->AsFunc();
// Events we need to register.
unordered_set<string> events;
// Events we need to register.
unordered_set<string> events;
if ( ft->Flavor() == FUNC_FLAVOR_EVENT )
events.insert(fn);
if ( ft->Flavor() == FUNC_FLAVOR_EVENT )
events.insert(fn);
vector<detail::IDPtr> no_inits; // empty initialization vector
int num_params = ft->Params()->NumFields();
vector<detail::IDPtr> no_inits; // empty initialization vector
int num_params = ft->Params()->NumFields();
for ( auto h : hashes )
{
// Add in the new body.
auto csi = compiled_standalone_scripts.find(h);
ASSERT(csi != compiled_standalone_scripts.end());
auto cs = csi->second;
for ( auto h : hashes ) {
// Add in the new body.
auto csi = compiled_standalone_scripts.find(h);
ASSERT(csi != compiled_standalone_scripts.end());
auto cs = csi->second;
f->AddBody(cs.body, no_inits, num_params, cs.priority);
added_bodies[fn].insert(h);
f->AddBody(cs.body, no_inits, num_params, cs.priority);
added_bodies[fn].insert(h);
events.insert(cs.events.begin(), cs.events.end());
}
events.insert(cs.events.begin(), cs.events.end());
}
for ( const auto& e : events )
{
auto eh = event_registry->Register(e);
eh->SetUsed();
}
}
for ( const auto& e : events ) {
auto eh = event_registry->Register(e);
eh->SetUsed();
}
}
IDPtr lookup_global__CPP(const char* g, const TypePtr& t, bool exported)
{
auto gl = lookup_ID(g, GLOBAL_MODULE_NAME, false, false, false);
IDPtr lookup_global__CPP(const char* g, const TypePtr& t, bool exported) {
auto gl = lookup_ID(g, GLOBAL_MODULE_NAME, false, false, false);
if ( ! gl )
{
gl = install_ID(g, GLOBAL_MODULE_NAME, true, exported);
gl->SetType(t);
}
if ( ! gl ) {
gl = install_ID(g, GLOBAL_MODULE_NAME, true, exported);
gl->SetType(t);
}
return gl;
}
return gl;
}
Func* lookup_bif__CPP(const char* bif)
{
auto b = lookup_ID(bif, GLOBAL_MODULE_NAME, false, false, false);
return (b && b->GetVal()) ? b->GetVal()->AsFunc() : nullptr;
}
Func* lookup_bif__CPP(const char* bif) {
auto b = lookup_ID(bif, GLOBAL_MODULE_NAME, false, false, false);
return (b && b->GetVal()) ? b->GetVal()->AsFunc() : nullptr;
}
FuncValPtr lookup_func__CPP(string name, int num_bodies, vector<p_hash_type> hashes,
const TypePtr& t)
{
auto ft = cast_intrusive<FuncType>(t);
FuncValPtr lookup_func__CPP(string name, int num_bodies, vector<p_hash_type> hashes, const TypePtr& t) {
auto ft = cast_intrusive<FuncType>(t);
if ( static_cast<int>(hashes.size()) < num_bodies )
{
// This happens for functions that have at least one
// uncompilable body.
auto gl = lookup_ID(name.c_str(), GLOBAL_MODULE_NAME, false, false, false);
if ( ! gl )
{
reporter->CPPRuntimeError("non-compiled function %s missing", name.c_str());
exit(1);
}
if ( static_cast<int>(hashes.size()) < num_bodies ) {
// This happens for functions that have at least one
// uncompilable body.
auto gl = lookup_ID(name.c_str(), GLOBAL_MODULE_NAME, false, false, false);
if ( ! gl ) {
reporter->CPPRuntimeError("non-compiled function %s missing", name.c_str());
exit(1);
}
auto v = gl->GetVal();
if ( ! v || v->GetType()->Tag() != TYPE_FUNC )
{
reporter->CPPRuntimeError("non-compiled function %s has an invalid value",
name.c_str());
exit(1);
}
auto v = gl->GetVal();
if ( ! v || v->GetType()->Tag() != TYPE_FUNC ) {
reporter->CPPRuntimeError("non-compiled function %s has an invalid value", name.c_str());
exit(1);
}
return cast_intrusive<FuncVal>(v);
}
return cast_intrusive<FuncVal>(v);
}
vector<StmtPtr> bodies;
vector<int> priorities;
vector<StmtPtr> bodies;
vector<int> priorities;
for ( auto h : hashes )
{
auto cs = compiled_scripts.find(h);
ASSERT(cs != compiled_scripts.end());
for ( auto h : hashes ) {
auto cs = compiled_scripts.find(h);
ASSERT(cs != compiled_scripts.end());
const auto& f = cs->second;
bodies.emplace_back(f.body);
priorities.push_back(f.priority);
const auto& f = cs->second;
bodies.emplace_back(f.body);
priorities.push_back(f.priority);
// This might register the same event more than once,
// if it's used in multiple bodies, but that's okay as
// the semantics for Register explicitly allow it.
for ( auto& e : f.events )
{
auto eh = event_registry->Register(e);
eh->SetUsed();
}
}
// This might register the same event more than once,
// if it's used in multiple bodies, but that's okay as
// the semantics for Register explicitly allow it.
for ( auto& e : f.events ) {
auto eh = event_registry->Register(e);
eh->SetUsed();
}
}
auto sf = make_intrusive<ScriptFunc>(std::move(name), std::move(ft), std::move(bodies),
std::move(priorities));
auto sf = make_intrusive<ScriptFunc>(std::move(name), std::move(ft), std::move(bodies), std::move(priorities));
return make_intrusive<FuncVal>(std::move(sf));
}
return make_intrusive<FuncVal>(std::move(sf));
}
IDPtr find_global__CPP(const char* g)
{
auto gl = lookup_ID(g, GLOBAL_MODULE_NAME, false, false, false);
IDPtr find_global__CPP(const char* g) {
auto gl = lookup_ID(g, GLOBAL_MODULE_NAME, false, false, false);
if ( ! gl )
reporter->CPPRuntimeError("global %s is missing", g);
if ( ! gl )
reporter->CPPRuntimeError("global %s is missing", g);
return gl;
}
return gl;
}
RecordTypePtr get_record_type__CPP(const char* record_type_name)
{
IDPtr existing_type;
RecordTypePtr get_record_type__CPP(const char* record_type_name) {
IDPtr existing_type;
if ( record_type_name && (existing_type = global_scope()->Find(record_type_name)) &&
existing_type->GetType()->Tag() == TYPE_RECORD )
return cast_intrusive<RecordType>(existing_type->GetType());
if ( record_type_name && (existing_type = global_scope()->Find(record_type_name)) &&
existing_type->GetType()->Tag() == TYPE_RECORD )
return cast_intrusive<RecordType>(existing_type->GetType());
return make_intrusive<RecordType>(new type_decl_list());
}
return make_intrusive<RecordType>(new type_decl_list());
}
EnumTypePtr get_enum_type__CPP(const string& enum_type_name)
{
auto existing_type = global_scope()->Find(enum_type_name);
EnumTypePtr get_enum_type__CPP(const string& enum_type_name) {
auto existing_type = global_scope()->Find(enum_type_name);
if ( existing_type && existing_type->GetType()->Tag() == TYPE_ENUM )
return cast_intrusive<EnumType>(existing_type->GetType());
else
return make_intrusive<EnumType>(enum_type_name);
}
if ( existing_type && existing_type->GetType()->Tag() == TYPE_ENUM )
return cast_intrusive<EnumType>(existing_type->GetType());
else
return make_intrusive<EnumType>(enum_type_name);
}
EnumValPtr make_enum__CPP(TypePtr t, zeek_int_t i)
{
auto et = cast_intrusive<EnumType>(std::move(t));
return make_intrusive<EnumVal>(et, i);
}
EnumValPtr make_enum__CPP(TypePtr t, zeek_int_t i) {
auto et = cast_intrusive<EnumType>(std::move(t));
return make_intrusive<EnumVal>(et, i);
}
} // namespace zeek::detail
} // namespace zeek::detail

View file

@ -8,28 +8,24 @@
#include "zeek/script_opt/CPP/Attrs.h"
#include "zeek/script_opt/CPP/Func.h"
namespace zeek
{
namespace zeek {
using FuncValPtr = IntrusivePtr<zeek::FuncVal>;
namespace detail
{
namespace detail {
// A version of TableType that allows us to first build a "stub" and
// then fill in its actual index & yield later - necessary for dealing
// with recursive types.
class CPPTableType : public TableType
{
class CPPTableType : public TableType {
public:
CPPTableType() : TableType(nullptr, nullptr){};
CPPTableType() : TableType(nullptr, nullptr){};
void SetIndexAndYield(TypeListPtr ind, TypePtr yield)
{
ind = std::move(indices);
yield_type = std::move(yield);
}
};
void SetIndexAndYield(TypeListPtr ind, TypePtr yield) {
ind = std::move(indices);
yield_type = std::move(yield);
}
};
// An initialization hook for a collection of compiled-to-C++ functions
// (the result of a single invocation of the compiler on a set of scripts).
@ -45,8 +41,8 @@ extern void register_type__CPP(TypePtr t, const std::string& name);
// given priority and hash. "events" is a list of event handlers
// relevant for the function body, which should be registered if the
// function body is going to be used.
extern void register_body__CPP(CPPStmtPtr body, int priority, p_hash_type hash,
std::vector<std::string> events, void (*finish_init)());
extern void register_body__CPP(CPPStmtPtr body, int priority, p_hash_type hash, std::vector<std::string> events,
void (*finish_init)());
// Same but for standalone function bodies.
extern void register_standalone_body__CPP(CPPStmtPtr body, int priority, p_hash_type hash,
@ -55,8 +51,7 @@ extern void register_standalone_body__CPP(CPPStmtPtr body, int priority, p_hash_
// Registers a lambda body as associated with the given hash. Includes
// the name of the lambda (so it can be made available as a quasi-global
// identifier), its type, and whether it needs captures.
extern void register_lambda__CPP(CPPStmtPtr body, p_hash_type hash, const char* name, TypePtr t,
bool has_captures);
extern void register_lambda__CPP(CPPStmtPtr body, p_hash_type hash, const char* name, TypePtr t, bool has_captures);
// Registers a callback for activating a set of scripts associated with
// the given hash.
@ -80,8 +75,7 @@ extern Func* lookup_bif__CPP(const char* bif);
// returns an associated FuncVal. It's a fatal error for the hash
// not to exist, because this function should only be called by compiled
// code that has ensured its existence.
extern FuncValPtr lookup_func__CPP(std::string name, int num_bodies, std::vector<p_hash_type> h,
const TypePtr& t);
extern FuncValPtr lookup_func__CPP(std::string name, int num_bodies, std::vector<p_hash_type> h, const TypePtr& t);
// Looks for a global with the given name, generating a run-time error
// if not present.
@ -101,5 +95,5 @@ extern EnumTypePtr get_enum_type__CPP(const std::string& enum_type_name);
// in the context of the given enum type 't'.
extern EnumValPtr make_enum__CPP(TypePtr t, zeek_int_t i);
} // namespace zeek::detail
} // namespace zeek
} // namespace detail
} // namespace zeek

View file

@ -10,224 +10,200 @@
using namespace std;
namespace zeek::detail
{
namespace zeek::detail {
template <class T>
template<class T>
void CPP_IndexedInits<T>::InitializeCohortWithOffsets(InitsManager* im, int cohort,
const std::vector<int>& cohort_offsets)
{
auto& co = this->inits[cohort];
for ( auto i = 0U; i < co.size(); ++i )
Generate(im, this->inits_vec, cohort_offsets[i], co[i]);
}
const std::vector<int>& cohort_offsets) {
auto& co = this->inits[cohort];
for ( auto i = 0U; i < co.size(); ++i )
Generate(im, this->inits_vec, cohort_offsets[i], co[i]);
}
template <class T>
void CPP_IndexedInits<T>::Generate(InitsManager* im, std::vector<EnumValPtr>& ivec, int offset,
ValElemVec& init_vals)
{
auto& e_type = im->Types(init_vals[0]);
int val = init_vals[1];
ivec[offset] = zeek::detail::make_enum__CPP(e_type, val);
}
template<class T>
void CPP_IndexedInits<T>::Generate(InitsManager* im, std::vector<EnumValPtr>& ivec, int offset, ValElemVec& init_vals) {
auto& e_type = im->Types(init_vals[0]);
int val = init_vals[1];
ivec[offset] = zeek::detail::make_enum__CPP(e_type, val);
}
template <class T>
template<class T>
void CPP_IndexedInits<T>::Generate(InitsManager* im, std::vector<StringValPtr>& ivec, int offset,
ValElemVec& init_vals)
{
auto chars = im->Strings(init_vals[0]);
int len = init_vals[1];
ivec[offset] = make_intrusive<StringVal>(len, chars);
}
ValElemVec& init_vals) {
auto chars = im->Strings(init_vals[0]);
int len = init_vals[1];
ivec[offset] = make_intrusive<StringVal>(len, chars);
}
template <class T>
template<class T>
void CPP_IndexedInits<T>::Generate(InitsManager* im, std::vector<PatternValPtr>& ivec, int offset,
ValElemVec& init_vals)
{
auto re = new RE_Matcher(im->Strings(init_vals[0]));
if ( init_vals[1] )
re->MakeCaseInsensitive();
if ( init_vals[2] )
re->MakeSingleLine();
ValElemVec& init_vals) {
auto re = new RE_Matcher(im->Strings(init_vals[0]));
if ( init_vals[1] )
re->MakeCaseInsensitive();
if ( init_vals[2] )
re->MakeSingleLine();
re->Compile();
re->Compile();
ivec[offset] = make_intrusive<PatternVal>(re);
}
ivec[offset] = make_intrusive<PatternVal>(re);
}
template <class T>
template<class T>
void CPP_IndexedInits<T>::Generate(InitsManager* im, std::vector<ListValPtr>& ivec, int offset,
ValElemVec& init_vals) const
{
auto l = make_intrusive<ListVal>(TYPE_ANY);
ValElemVec& init_vals) const {
auto l = make_intrusive<ListVal>(TYPE_ANY);
for ( auto& iv : init_vals )
l->Append(im->ConstVals(iv));
for ( auto& iv : init_vals )
l->Append(im->ConstVals(iv));
ivec[offset] = l;
}
ivec[offset] = l;
}
template <class T>
template<class T>
void CPP_IndexedInits<T>::Generate(InitsManager* im, std::vector<VectorValPtr>& ivec, int offset,
ValElemVec& init_vals) const
{
auto iv_it = init_vals.begin();
auto iv_end = init_vals.end();
auto t = *(iv_it++);
ValElemVec& init_vals) const {
auto iv_it = init_vals.begin();
auto iv_end = init_vals.end();
auto t = *(iv_it++);
auto vt = cast_intrusive<VectorType>(im->Types(t));
auto vv = make_intrusive<VectorVal>(vt);
auto vt = cast_intrusive<VectorType>(im->Types(t));
auto vv = make_intrusive<VectorVal>(vt);
while ( iv_it != iv_end )
vv->Append(im->ConstVals(*(iv_it++)));
while ( iv_it != iv_end )
vv->Append(im->ConstVals(*(iv_it++)));
ivec[offset] = vv;
}
ivec[offset] = vv;
}
template <class T>
template<class T>
void CPP_IndexedInits<T>::Generate(InitsManager* im, std::vector<RecordValPtr>& ivec, int offset,
ValElemVec& init_vals) const
{
auto iv_it = init_vals.begin();
auto iv_end = init_vals.end();
auto t = *(iv_it++);
ValElemVec& init_vals) const {
auto iv_it = init_vals.begin();
auto iv_end = init_vals.end();
auto t = *(iv_it++);
auto rt = cast_intrusive<RecordType>(im->Types(t));
auto rv = make_intrusive<RecordVal>(rt);
auto rt = cast_intrusive<RecordType>(im->Types(t));
auto rv = make_intrusive<RecordVal>(rt);
auto field = 0;
while ( iv_it != iv_end )
{
auto v = *(iv_it++);
if ( v >= 0 )
rv->Assign(field, im->ConstVals(v));
++field;
}
auto field = 0;
while ( iv_it != iv_end ) {
auto v = *(iv_it++);
if ( v >= 0 )
rv->Assign(field, im->ConstVals(v));
++field;
}
ivec[offset] = rv;
}
ivec[offset] = rv;
}
template <class T>
template<class T>
void CPP_IndexedInits<T>::Generate(InitsManager* im, std::vector<TableValPtr>& ivec, int offset,
ValElemVec& init_vals) const
{
auto iv_it = init_vals.begin();
auto iv_end = init_vals.end();
auto t = *(iv_it++);
auto attrs = *(iv_it++);
ValElemVec& init_vals) const {
auto iv_it = init_vals.begin();
auto iv_end = init_vals.end();
auto t = *(iv_it++);
auto attrs = *(iv_it++);
auto tt = cast_intrusive<TableType>(im->Types(t));
auto tv = make_intrusive<TableVal>(tt);
auto tt = cast_intrusive<TableType>(im->Types(t));
auto tv = make_intrusive<TableVal>(tt);
if ( attrs >= 0 )
tv->SetAttrs(im->Attributes(attrs));
if ( attrs >= 0 )
tv->SetAttrs(im->Attributes(attrs));
while ( iv_it != iv_end )
{
auto index = im->ConstVals(*(iv_it++));
auto v = *(iv_it++);
auto value = v >= 0 ? im->ConstVals(v) : nullptr;
tv->Assign(index, value);
}
while ( iv_it != iv_end ) {
auto index = im->ConstVals(*(iv_it++));
auto v = *(iv_it++);
auto value = v >= 0 ? im->ConstVals(v) : nullptr;
tv->Assign(index, value);
}
ivec[offset] = tv;
}
ivec[offset] = tv;
}
template <class T>
template<class T>
void CPP_IndexedInits<T>::Generate(InitsManager* im, std::vector<FileValPtr>& ivec, int offset,
ValElemVec& init_vals) const
{
// Note, in the following we use element 1, not 0, because we
// don't need the "type" value in element 0.
auto fn = im->Strings(init_vals[1]);
auto fv = make_intrusive<FileVal>(make_intrusive<File>(fn, "w"));
ValElemVec& init_vals) const {
// Note, in the following we use element 1, not 0, because we
// don't need the "type" value in element 0.
auto fn = im->Strings(init_vals[1]);
auto fv = make_intrusive<FileVal>(make_intrusive<File>(fn, "w"));
ivec[offset] = fv;
}
ivec[offset] = fv;
}
template <class T>
template<class T>
void CPP_IndexedInits<T>::Generate(InitsManager* im, std::vector<FuncValPtr>& ivec, int offset,
ValElemVec& init_vals) const
{
auto iv_it = init_vals.begin();
auto iv_end = init_vals.end();
auto t = *(iv_it++);
auto fn = im->Strings(*(iv_it++));
auto num_bodies = *(iv_it++);
ValElemVec& init_vals) const {
auto iv_it = init_vals.begin();
auto iv_end = init_vals.end();
auto t = *(iv_it++);
auto fn = im->Strings(*(iv_it++));
auto num_bodies = *(iv_it++);
std::vector<p_hash_type> hashes;
std::vector<p_hash_type> hashes;
while ( iv_it != iv_end )
hashes.push_back(im->Hashes(*(iv_it++)));
while ( iv_it != iv_end )
hashes.push_back(im->Hashes(*(iv_it++)));
ivec[offset] = lookup_func__CPP(fn, num_bodies, hashes, im->Types(t));
}
ivec[offset] = lookup_func__CPP(fn, num_bodies, hashes, im->Types(t));
}
template <class T>
template<class T>
void CPP_IndexedInits<T>::Generate(InitsManager* im, std::vector<AttrPtr>& ivec, int offset,
ValElemVec& init_vals) const
{
auto tag = static_cast<AttrTag>(init_vals[0]);
auto ae_tag = static_cast<AttrExprType>(init_vals[1]);
ValElemVec& init_vals) const {
auto tag = static_cast<AttrTag>(init_vals[0]);
auto ae_tag = static_cast<AttrExprType>(init_vals[1]);
if ( ae_tag == AE_NONE )
{
ivec[offset] = make_intrusive<Attr>(tag);
return;
}
if ( ae_tag == AE_NONE ) {
ivec[offset] = make_intrusive<Attr>(tag);
return;
}
ExprPtr e;
auto e_arg = init_vals[2];
ExprPtr e;
auto e_arg = init_vals[2];
switch ( ae_tag )
{
case AE_NONE:
// Shouldn't happen, per test above.
ASSERT(0);
break;
switch ( ae_tag ) {
case AE_NONE:
// Shouldn't happen, per test above.
ASSERT(0);
break;
case AE_CONST:
e = make_intrusive<ConstExpr>(im->ConstVals(e_arg));
break;
case AE_CONST: e = make_intrusive<ConstExpr>(im->ConstVals(e_arg)); break;
case AE_NAME:
{
auto name = im->Strings(e_arg);
auto gl = lookup_ID(name, GLOBAL_MODULE_NAME, false, false, false);
ASSERT(gl);
e = make_intrusive<NameExpr>(gl);
break;
}
case AE_NAME: {
auto name = im->Strings(e_arg);
auto gl = lookup_ID(name, GLOBAL_MODULE_NAME, false, false, false);
ASSERT(gl);
e = make_intrusive<NameExpr>(gl);
break;
}
case AE_RECORD:
{
auto t = im->Types(e_arg);
auto rt = cast_intrusive<RecordType>(t);
auto empty_vals = make_intrusive<ListExpr>();
auto construct = make_intrusive<RecordConstructorExpr>(empty_vals);
e = make_intrusive<RecordCoerceExpr>(construct, rt);
break;
}
case AE_RECORD: {
auto t = im->Types(e_arg);
auto rt = cast_intrusive<RecordType>(t);
auto empty_vals = make_intrusive<ListExpr>();
auto construct = make_intrusive<RecordConstructorExpr>(empty_vals);
e = make_intrusive<RecordCoerceExpr>(construct, rt);
break;
}
case AE_CALL:
e = im->CallExprs(e_arg);
break;
}
case AE_CALL: e = im->CallExprs(e_arg); break;
}
ivec[offset] = make_intrusive<Attr>(tag, e);
}
ivec[offset] = make_intrusive<Attr>(tag, e);
}
template <class T>
template<class T>
void CPP_IndexedInits<T>::Generate(InitsManager* im, std::vector<AttributesPtr>& ivec, int offset,
ValElemVec& init_vals) const
{
std::vector<AttrPtr> a_list;
ValElemVec& init_vals) const {
std::vector<AttrPtr> a_list;
for ( auto& iv : init_vals )
a_list.emplace_back(im->Attrs(iv));
for ( auto& iv : init_vals )
a_list.emplace_back(im->Attrs(iv));
ivec[offset] = make_intrusive<Attributes>(a_list, nullptr, false, false);
}
ivec[offset] = make_intrusive<Attributes>(a_list, nullptr, false, false);
}
// Instantiate the templates we'll need.
@ -244,325 +220,276 @@ template class CPP_IndexedInits<AttrPtr>;
template class CPP_IndexedInits<AttributesPtr>;
template class CPP_IndexedInits<TypePtr>;
void CPP_TypeInits::DoPreInits(InitsManager* im, const std::vector<int>& offsets_vec)
{
for ( auto cohort = 0U; cohort < offsets_vec.size(); ++cohort )
{
auto& co = inits[cohort];
auto& cohort_offsets = im->Indices(offsets_vec[cohort]);
for ( auto i = 0U; i < co.size(); ++i )
PreInit(im, cohort_offsets[i], co[i]);
}
}
void CPP_TypeInits::PreInit(InitsManager* im, int offset, ValElemVec& init_vals)
{
auto tag = static_cast<TypeTag>(init_vals[0]);
if ( tag == TYPE_LIST )
inits_vec[offset] = make_intrusive<TypeList>();
else if ( tag == TYPE_RECORD )
{
auto name = im->Strings(init_vals[1]);
if ( name[0] )
inits_vec[offset] = get_record_type__CPP(name);
else
inits_vec[offset] = get_record_type__CPP(nullptr);
}
else if ( tag == TYPE_TABLE )
inits_vec[offset] = make_intrusive<CPPTableType>();
// else no pre-initialization needed
}
void CPP_TypeInits::Generate(InitsManager* im, vector<TypePtr>& ivec, int offset,
ValElemVec& init_vals) const
{
auto tag = static_cast<TypeTag>(init_vals[0]);
TypePtr t;
switch ( tag )
{
case TYPE_ADDR:
case TYPE_ANY:
case TYPE_BOOL:
case TYPE_COUNT:
case TYPE_DOUBLE:
case TYPE_ERROR:
case TYPE_INT:
case TYPE_INTERVAL:
case TYPE_PATTERN:
case TYPE_PORT:
case TYPE_STRING:
case TYPE_TIME:
case TYPE_VOID:
case TYPE_SUBNET:
case TYPE_FILE:
t = base_type(tag);
break;
case TYPE_ENUM:
t = BuildEnumType(im, init_vals);
break;
case TYPE_OPAQUE:
t = BuildOpaqueType(im, init_vals);
break;
case TYPE_TYPE:
t = BuildTypeType(im, init_vals);
break;
case TYPE_VECTOR:
t = BuildVectorType(im, init_vals);
break;
case TYPE_LIST:
t = BuildTypeList(im, init_vals, offset);
break;
case TYPE_TABLE:
t = BuildTableType(im, init_vals, offset);
break;
case TYPE_FUNC:
t = BuildFuncType(im, init_vals);
break;
case TYPE_RECORD:
t = BuildRecordType(im, init_vals, offset);
break;
default:
ASSERT(0);
}
ivec[offset] = t;
}
TypePtr CPP_TypeInits::BuildEnumType(InitsManager* im, ValElemVec& init_vals) const
{
auto iv_it = init_vals.begin();
auto iv_end = init_vals.end();
auto name = im->Strings(*++iv_it); // skip element [0]
auto et = get_enum_type__CPP(name);
if ( et->Names().empty() )
{
++iv_it;
while ( iv_it != iv_end )
{
auto e_name = im->Strings(*(iv_it++));
auto e_val = *(iv_it++);
et->AddNameInternal(e_name, e_val);
}
}
return et;
}
TypePtr CPP_TypeInits::BuildOpaqueType(InitsManager* im, ValElemVec& init_vals) const
{
auto name = im->Strings(init_vals[1]);
return make_intrusive<OpaqueType>(name);
}
TypePtr CPP_TypeInits::BuildTypeType(InitsManager* im, ValElemVec& init_vals) const
{
auto& t = im->Types(init_vals[1]);
return make_intrusive<TypeType>(t);
}
TypePtr CPP_TypeInits::BuildVectorType(InitsManager* im, ValElemVec& init_vals) const
{
auto& t = im->Types(init_vals[1]);
return make_intrusive<VectorType>(t);
}
TypePtr CPP_TypeInits::BuildTypeList(InitsManager* im, ValElemVec& init_vals, int offset) const
{
const auto& tl = cast_intrusive<TypeList>(inits_vec[offset]);
auto iv_it = init_vals.begin();
auto iv_end = init_vals.end();
++iv_it;
while ( iv_it != iv_end )
tl->Append(im->Types(*(iv_it++)));
tl->CheckPure();
return tl;
}
TypePtr CPP_TypeInits::BuildTableType(InitsManager* im, ValElemVec& init_vals, int offset) const
{
auto t = cast_intrusive<CPPTableType>(inits_vec[offset]);
ASSERT(t);
void CPP_TypeInits::DoPreInits(InitsManager* im, const std::vector<int>& offsets_vec) {
for ( auto cohort = 0U; cohort < offsets_vec.size(); ++cohort ) {
auto& co = inits[cohort];
auto& cohort_offsets = im->Indices(offsets_vec[cohort]);
for ( auto i = 0U; i < co.size(); ++i )
PreInit(im, cohort_offsets[i], co[i]);
}
}
void CPP_TypeInits::PreInit(InitsManager* im, int offset, ValElemVec& init_vals) {
auto tag = static_cast<TypeTag>(init_vals[0]);
if ( tag == TYPE_LIST )
inits_vec[offset] = make_intrusive<TypeList>();
else if ( tag == TYPE_RECORD ) {
auto name = im->Strings(init_vals[1]);
if ( name[0] )
inits_vec[offset] = get_record_type__CPP(name);
else
inits_vec[offset] = get_record_type__CPP(nullptr);
}
else if ( tag == TYPE_TABLE )
inits_vec[offset] = make_intrusive<CPPTableType>();
// else no pre-initialization needed
}
void CPP_TypeInits::Generate(InitsManager* im, vector<TypePtr>& ivec, int offset, ValElemVec& init_vals) const {
auto tag = static_cast<TypeTag>(init_vals[0]);
TypePtr t;
switch ( tag ) {
case TYPE_ADDR:
case TYPE_ANY:
case TYPE_BOOL:
case TYPE_COUNT:
case TYPE_DOUBLE:
case TYPE_ERROR:
case TYPE_INT:
case TYPE_INTERVAL:
case TYPE_PATTERN:
case TYPE_PORT:
case TYPE_STRING:
case TYPE_TIME:
case TYPE_VOID:
case TYPE_SUBNET:
case TYPE_FILE: t = base_type(tag); break;
auto index = cast_intrusive<TypeList>(im->Types(init_vals[1]));
auto yield_i = init_vals[2];
auto yield = yield_i >= 0 ? im->Types(yield_i) : nullptr;
t->SetIndexAndYield(index, yield);
return t;
}
TypePtr CPP_TypeInits::BuildFuncType(InitsManager* im, ValElemVec& init_vals) const
{
auto p = cast_intrusive<RecordType>(im->Types(init_vals[1]));
auto yield_i = init_vals[2];
auto flavor = static_cast<FunctionFlavor>(init_vals[3]);
TypePtr y;
if ( yield_i >= 0 )
y = im->Types(yield_i);
else if ( flavor == FUNC_FLAVOR_FUNCTION || flavor == FUNC_FLAVOR_HOOK )
y = base_type(TYPE_VOID);
return make_intrusive<FuncType>(p, y, flavor);
}
TypePtr CPP_TypeInits::BuildRecordType(InitsManager* im, ValElemVec& init_vals, int offset) const
{
auto r = cast_intrusive<RecordType>(inits_vec[offset]);
ASSERT(r);
if ( r->NumFields() == 0 )
{
type_decl_list tl;
auto n = init_vals.size();
auto i = 2U;
while ( i < n )
{
auto s = im->Strings(init_vals[i++]);
auto id = util::copy_string(s);
auto type = im->Types(init_vals[i++]);
auto attrs_i = init_vals[i++];
AttributesPtr attrs;
if ( attrs_i >= 0 )
attrs = im->Attributes(attrs_i);
tl.append(new TypeDecl(id, type, attrs));
}
r->AddFieldsDirectly(tl);
}
return r;
}
int CPP_FieldMapping::ComputeOffset(InitsManager* im) const
{
auto r = im->Types(rec)->AsRecordType();
auto fm_offset = r->FieldOffset(field_name.c_str());
if ( fm_offset < 0 )
{ // field does not exist, create it
fm_offset = r->NumFields();
auto id = util::copy_string(field_name.c_str());
auto type = im->Types(field_type);
AttributesPtr attrs;
if ( field_attrs >= 0 )
attrs = im->Attributes(field_attrs);
type_decl_list tl;
tl.append(new TypeDecl(id, type, attrs));
r->AddFieldsDirectly(tl);
}
return fm_offset;
}
int CPP_EnumMapping::ComputeOffset(InitsManager* im) const
{
auto e = im->Types(e_type)->AsEnumType();
auto em_offset = e->Lookup(e_name);
if ( em_offset < 0 )
{ // enum constant does not exist, create it
em_offset = e->Names().size();
if ( e->Lookup(em_offset) )
reporter->InternalError("enum inconsistency while initializing compiled scripts");
e->AddNameInternal(e_name, em_offset);
}
return em_offset;
}
void CPP_GlobalInit::Generate(InitsManager* im, std::vector<void*>& /* inits_vec */,
int /* offset */) const
{
auto& t = im->Types(type);
global = lookup_global__CPP(name, t, exported);
if ( ! global->HasVal() )
{
if ( val >= 0 )
// Have explicit initialization value.
global->SetVal(im->ConstVals(val));
else if ( t->Tag() == TYPE_FUNC && ! func_with_no_val )
{
// Create a matching value so that this global can
// be used in other initializations. The code here
// mirrors that in activate_bodies__CPP().
auto fn = global->Name();
auto ft = cast_intrusive<FuncType>(t);
vector<StmtPtr> no_bodies;
vector<int> no_priorities;
auto sf = make_intrusive<ScriptFunc>(fn, ft, no_bodies, no_priorities);
auto v = make_intrusive<FuncVal>(std::move(sf));
global->SetVal(v);
}
}
if ( attrs >= 0 )
global->SetAttrs(im->Attributes(attrs));
}
void generate_indices_set(int* inits, std::vector<std::vector<int>>& indices_set)
{
// First figure out how many groups of indices there are, so we
// can pre-allocate the outer vector.
auto i_ptr = inits;
int num_inits = 0;
while ( *i_ptr >= 0 )
{
++num_inits;
int n = *i_ptr;
i_ptr += n + 1; // skip over vector elements
}
indices_set.reserve(num_inits);
i_ptr = inits;
while ( *i_ptr >= 0 )
{
int n = *i_ptr;
++i_ptr;
std::vector<int> indices;
indices.reserve(n);
for ( int i = 0; i < n; ++i )
indices.push_back(i_ptr[i]);
i_ptr += n;
indices_set.emplace_back(std::move(indices));
}
}
} // zeek::detail
case TYPE_ENUM: t = BuildEnumType(im, init_vals); break;
case TYPE_OPAQUE: t = BuildOpaqueType(im, init_vals); break;
case TYPE_TYPE: t = BuildTypeType(im, init_vals); break;
case TYPE_VECTOR: t = BuildVectorType(im, init_vals); break;
case TYPE_LIST: t = BuildTypeList(im, init_vals, offset); break;
case TYPE_TABLE: t = BuildTableType(im, init_vals, offset); break;
case TYPE_FUNC: t = BuildFuncType(im, init_vals); break;
case TYPE_RECORD: t = BuildRecordType(im, init_vals, offset); break;
default: ASSERT(0);
}
ivec[offset] = t;
}
TypePtr CPP_TypeInits::BuildEnumType(InitsManager* im, ValElemVec& init_vals) const {
auto iv_it = init_vals.begin();
auto iv_end = init_vals.end();
auto name = im->Strings(*++iv_it); // skip element [0]
auto et = get_enum_type__CPP(name);
if ( et->Names().empty() ) {
++iv_it;
while ( iv_it != iv_end ) {
auto e_name = im->Strings(*(iv_it++));
auto e_val = *(iv_it++);
et->AddNameInternal(e_name, e_val);
}
}
return et;
}
TypePtr CPP_TypeInits::BuildOpaqueType(InitsManager* im, ValElemVec& init_vals) const {
auto name = im->Strings(init_vals[1]);
return make_intrusive<OpaqueType>(name);
}
TypePtr CPP_TypeInits::BuildTypeType(InitsManager* im, ValElemVec& init_vals) const {
auto& t = im->Types(init_vals[1]);
return make_intrusive<TypeType>(t);
}
TypePtr CPP_TypeInits::BuildVectorType(InitsManager* im, ValElemVec& init_vals) const {
auto& t = im->Types(init_vals[1]);
return make_intrusive<VectorType>(t);
}
TypePtr CPP_TypeInits::BuildTypeList(InitsManager* im, ValElemVec& init_vals, int offset) const {
const auto& tl = cast_intrusive<TypeList>(inits_vec[offset]);
auto iv_it = init_vals.begin();
auto iv_end = init_vals.end();
++iv_it;
while ( iv_it != iv_end )
tl->Append(im->Types(*(iv_it++)));
tl->CheckPure();
return tl;
}
TypePtr CPP_TypeInits::BuildTableType(InitsManager* im, ValElemVec& init_vals, int offset) const {
auto t = cast_intrusive<CPPTableType>(inits_vec[offset]);
ASSERT(t);
auto index = cast_intrusive<TypeList>(im->Types(init_vals[1]));
auto yield_i = init_vals[2];
auto yield = yield_i >= 0 ? im->Types(yield_i) : nullptr;
t->SetIndexAndYield(index, yield);
return t;
}
TypePtr CPP_TypeInits::BuildFuncType(InitsManager* im, ValElemVec& init_vals) const {
auto p = cast_intrusive<RecordType>(im->Types(init_vals[1]));
auto yield_i = init_vals[2];
auto flavor = static_cast<FunctionFlavor>(init_vals[3]);
TypePtr y;
if ( yield_i >= 0 )
y = im->Types(yield_i);
else if ( flavor == FUNC_FLAVOR_FUNCTION || flavor == FUNC_FLAVOR_HOOK )
y = base_type(TYPE_VOID);
return make_intrusive<FuncType>(p, y, flavor);
}
TypePtr CPP_TypeInits::BuildRecordType(InitsManager* im, ValElemVec& init_vals, int offset) const {
auto r = cast_intrusive<RecordType>(inits_vec[offset]);
ASSERT(r);
if ( r->NumFields() == 0 ) {
type_decl_list tl;
auto n = init_vals.size();
auto i = 2U;
while ( i < n ) {
auto s = im->Strings(init_vals[i++]);
auto id = util::copy_string(s);
auto type = im->Types(init_vals[i++]);
auto attrs_i = init_vals[i++];
AttributesPtr attrs;
if ( attrs_i >= 0 )
attrs = im->Attributes(attrs_i);
tl.append(new TypeDecl(id, type, attrs));
}
r->AddFieldsDirectly(tl);
}
return r;
}
int CPP_FieldMapping::ComputeOffset(InitsManager* im) const {
auto r = im->Types(rec)->AsRecordType();
auto fm_offset = r->FieldOffset(field_name.c_str());
if ( fm_offset < 0 ) { // field does not exist, create it
fm_offset = r->NumFields();
auto id = util::copy_string(field_name.c_str());
auto type = im->Types(field_type);
AttributesPtr attrs;
if ( field_attrs >= 0 )
attrs = im->Attributes(field_attrs);
type_decl_list tl;
tl.append(new TypeDecl(id, type, attrs));
r->AddFieldsDirectly(tl);
}
return fm_offset;
}
int CPP_EnumMapping::ComputeOffset(InitsManager* im) const {
auto e = im->Types(e_type)->AsEnumType();
auto em_offset = e->Lookup(e_name);
if ( em_offset < 0 ) { // enum constant does not exist, create it
em_offset = e->Names().size();
if ( e->Lookup(em_offset) )
reporter->InternalError("enum inconsistency while initializing compiled scripts");
e->AddNameInternal(e_name, em_offset);
}
return em_offset;
}
void CPP_GlobalInit::Generate(InitsManager* im, std::vector<void*>& /* inits_vec */, int /* offset */) const {
auto& t = im->Types(type);
global = lookup_global__CPP(name, t, exported);
if ( ! global->HasVal() ) {
if ( val >= 0 )
// Have explicit initialization value.
global->SetVal(im->ConstVals(val));
else if ( t->Tag() == TYPE_FUNC && ! func_with_no_val ) {
// Create a matching value so that this global can
// be used in other initializations. The code here
// mirrors that in activate_bodies__CPP().
auto fn = global->Name();
auto ft = cast_intrusive<FuncType>(t);
vector<StmtPtr> no_bodies;
vector<int> no_priorities;
auto sf = make_intrusive<ScriptFunc>(fn, ft, no_bodies, no_priorities);
auto v = make_intrusive<FuncVal>(std::move(sf));
global->SetVal(v);
}
}
if ( attrs >= 0 )
global->SetAttrs(im->Attributes(attrs));
}
void generate_indices_set(int* inits, std::vector<std::vector<int>>& indices_set) {
// First figure out how many groups of indices there are, so we
// can pre-allocate the outer vector.
auto i_ptr = inits;
int num_inits = 0;
while ( *i_ptr >= 0 ) {
++num_inits;
int n = *i_ptr;
i_ptr += n + 1; // skip over vector elements
}
indices_set.reserve(num_inits);
i_ptr = inits;
while ( *i_ptr >= 0 ) {
int n = *i_ptr;
++i_ptr;
std::vector<int> indices;
indices.reserve(n);
for ( int i = 0; i < n; ++i )
indices.push_back(i_ptr[i]);
i_ptr += n;
indices_set.emplace_back(std::move(indices));
}
}
} // namespace zeek::detail

View file

@ -12,8 +12,7 @@
#pragma once
namespace zeek::detail
{
namespace zeek::detail {
using FileValPtr = IntrusivePtr<FileVal>;
using FuncValPtr = IntrusivePtr<FuncVal>;
@ -23,12 +22,11 @@ class InitsManager;
// An abstract helper class used to access elements of an initialization vector.
// We need the abstraction because InitsManager below needs to be able to refer
// to any of a range of templated classes.
class CPP_AbstractInitAccessor
{
class CPP_AbstractInitAccessor {
public:
virtual ~CPP_AbstractInitAccessor() { }
virtual ValPtr Get(int index) const { return nullptr; }
};
virtual ~CPP_AbstractInitAccessor() {}
virtual ValPtr Get(int index) const { return nullptr; }
};
// Convenient way to refer to an offset associated with a particular Zeek type.
using CPP_ValElem = std::pair<TypeTag, int>;
@ -37,196 +35,181 @@ using CPP_ValElem = std::pair<TypeTag, int>;
// initialization. We gather them together into a single object so as
// to avoid wiring in a set of globals that the various initialization
// methods have to know about.
class InitsManager
{
class InitsManager {
public:
InitsManager(std::vector<CPP_ValElem>& _const_vals,
std::map<TypeTag, std::shared_ptr<CPP_AbstractInitAccessor>>& _consts,
std::vector<std::vector<int>>& _indices, std::vector<const char*>& _strings,
std::vector<p_hash_type>& _hashes, std::vector<TypePtr>& _types,
std::vector<AttributesPtr>& _attributes, std::vector<AttrPtr>& _attrs,
std::vector<CallExprPtr>& _call_exprs)
: const_vals(_const_vals), consts(_consts), indices(_indices), strings(_strings),
hashes(_hashes), types(_types), attributes(_attributes), attrs(_attrs),
call_exprs(_call_exprs)
{
}
InitsManager(std::vector<CPP_ValElem>& _const_vals,
std::map<TypeTag, std::shared_ptr<CPP_AbstractInitAccessor>>& _consts,
std::vector<std::vector<int>>& _indices, std::vector<const char*>& _strings,
std::vector<p_hash_type>& _hashes, std::vector<TypePtr>& _types,
std::vector<AttributesPtr>& _attributes, std::vector<AttrPtr>& _attrs,
std::vector<CallExprPtr>& _call_exprs)
: const_vals(_const_vals),
consts(_consts),
indices(_indices),
strings(_strings),
hashes(_hashes),
types(_types),
attributes(_attributes),
attrs(_attrs),
call_exprs(_call_exprs) {}
// Provides generic access to Zeek constant values based on a single
// index.
ValPtr ConstVals(int offset) const
{
auto& cv = const_vals[offset];
return Consts(cv.first, cv.second);
}
// Provides generic access to Zeek constant values based on a single
// index.
ValPtr ConstVals(int offset) const {
auto& cv = const_vals[offset];
return Consts(cv.first, cv.second);
}
// Retrieves the Zeek constant value for a particular Zeek type.
ValPtr Consts(TypeTag tag, int index) const { return consts[tag]->Get(index); }
// Retrieves the Zeek constant value for a particular Zeek type.
ValPtr Consts(TypeTag tag, int index) const { return consts[tag]->Get(index); }
// Accessors for the sundry initialization vectors, each retrieving
// a specific element identified by an index/offset.
const std::vector<int>& Indices(int offset) const { return indices[offset]; }
const char* Strings(int offset) const
{
ASSERT(offset >= 0 && offset < static_cast<int>(strings.size()));
ASSERT(strings[offset]);
return strings[offset];
}
const p_hash_type Hashes(int offset) const
{
ASSERT(offset >= 0 && offset < static_cast<int>(hashes.size()));
return hashes[offset];
}
const TypePtr& Types(int offset) const
{
ASSERT(offset >= 0 && offset < static_cast<int>(types.size()));
ASSERT(types[offset]);
return types[offset];
}
const AttributesPtr& Attributes(int offset) const
{
ASSERT(offset >= 0 && offset < static_cast<int>(attributes.size()));
ASSERT(attributes[offset]);
return attributes[offset];
}
const AttrPtr& Attrs(int offset) const
{
ASSERT(offset >= 0 && offset < static_cast<int>(attrs.size()));
ASSERT(attrs[offset]);
return attrs[offset];
}
const CallExprPtr& CallExprs(int offset) const
{
ASSERT(offset >= 0 && offset < static_cast<int>(call_exprs.size()));
ASSERT(call_exprs[offset]);
return call_exprs[offset];
}
// Accessors for the sundry initialization vectors, each retrieving
// a specific element identified by an index/offset.
const std::vector<int>& Indices(int offset) const { return indices[offset]; }
const char* Strings(int offset) const {
ASSERT(offset >= 0 && offset < static_cast<int>(strings.size()));
ASSERT(strings[offset]);
return strings[offset];
}
const p_hash_type Hashes(int offset) const {
ASSERT(offset >= 0 && offset < static_cast<int>(hashes.size()));
return hashes[offset];
}
const TypePtr& Types(int offset) const {
ASSERT(offset >= 0 && offset < static_cast<int>(types.size()));
ASSERT(types[offset]);
return types[offset];
}
const AttributesPtr& Attributes(int offset) const {
ASSERT(offset >= 0 && offset < static_cast<int>(attributes.size()));
ASSERT(attributes[offset]);
return attributes[offset];
}
const AttrPtr& Attrs(int offset) const {
ASSERT(offset >= 0 && offset < static_cast<int>(attrs.size()));
ASSERT(attrs[offset]);
return attrs[offset];
}
const CallExprPtr& CallExprs(int offset) const {
ASSERT(offset >= 0 && offset < static_cast<int>(call_exprs.size()));
ASSERT(call_exprs[offset]);
return call_exprs[offset];
}
private:
std::vector<CPP_ValElem>& const_vals;
std::map<TypeTag, std::shared_ptr<CPP_AbstractInitAccessor>>& consts;
std::vector<std::vector<int>>& indices;
std::vector<const char*>& strings;
std::vector<p_hash_type>& hashes;
std::vector<TypePtr>& types;
std::vector<AttributesPtr>& attributes;
std::vector<AttrPtr>& attrs;
std::vector<CallExprPtr>& call_exprs;
};
std::vector<CPP_ValElem>& const_vals;
std::map<TypeTag, std::shared_ptr<CPP_AbstractInitAccessor>>& consts;
std::vector<std::vector<int>>& indices;
std::vector<const char*>& strings;
std::vector<p_hash_type>& hashes;
std::vector<TypePtr>& types;
std::vector<AttributesPtr>& attributes;
std::vector<AttrPtr>& attrs;
std::vector<CallExprPtr>& call_exprs;
};
// Manages an initialization vector of the given type.
template <class T> class CPP_Init
{
template<class T>
class CPP_Init {
public:
virtual ~CPP_Init() { }
virtual ~CPP_Init() {}
// Pre-initializes the given element of the vector, if necessary.
virtual void PreInit(InitsManager* im, std::vector<T>& inits_vec, int offset) const { }
// Pre-initializes the given element of the vector, if necessary.
virtual void PreInit(InitsManager* im, std::vector<T>& inits_vec, int offset) const {}
// Initializes the given element of the vector.
virtual void Generate(InitsManager* im, std::vector<T>& inits_vec, int offset) const { }
};
// Initializes the given element of the vector.
virtual void Generate(InitsManager* im, std::vector<T>& inits_vec, int offset) const {}
};
// Abstract class for creating a collection of initializers. T1 is
// the type of the generated vector, T2 the type of its initializers.
template <class T1, class T2> class CPP_AbstractInits
{
template<class T1, class T2>
class CPP_AbstractInits {
public:
CPP_AbstractInits(std::vector<T1>& _inits_vec, int _offsets_set, std::vector<T2> _inits)
: inits_vec(_inits_vec), offsets_set(_offsets_set), inits(std::move(_inits))
{
// Compute how big to make the vector.
int num_inits = 0;
CPP_AbstractInits(std::vector<T1>& _inits_vec, int _offsets_set, std::vector<T2> _inits)
: inits_vec(_inits_vec), offsets_set(_offsets_set), inits(std::move(_inits)) {
// Compute how big to make the vector.
int num_inits = 0;
for ( const auto& cohort : inits )
num_inits += cohort.size();
for ( const auto& cohort : inits )
num_inits += cohort.size();
inits_vec.resize(num_inits);
}
inits_vec.resize(num_inits);
}
// Initialize the given cohort of elements.
void InitializeCohort(InitsManager* im, int cohort)
{
// Get this object's vector-of-vector-of-indices.
auto& offsets_vec = im->Indices(offsets_set);
// Initialize the given cohort of elements.
void InitializeCohort(InitsManager* im, int cohort) {
// Get this object's vector-of-vector-of-indices.
auto& offsets_vec = im->Indices(offsets_set);
if ( cohort == 0 )
DoPreInits(im, offsets_vec);
if ( cohort == 0 )
DoPreInits(im, offsets_vec);
// Get the vector-of-indices for this cohort.
auto& cohort_offsets = im->Indices(offsets_vec[cohort]);
// Get the vector-of-indices for this cohort.
auto& cohort_offsets = im->Indices(offsets_vec[cohort]);
InitializeCohortWithOffsets(im, cohort, cohort_offsets);
}
InitializeCohortWithOffsets(im, cohort, cohort_offsets);
}
protected:
virtual void InitializeCohortWithOffsets(InitsManager* im, int cohort,
const std::vector<int>& cohort_offsets)
{
}
virtual void InitializeCohortWithOffsets(InitsManager* im, int cohort, const std::vector<int>& cohort_offsets) {}
// Pre-initialize all elements requiring it.
virtual void DoPreInits(InitsManager* im, const std::vector<int>& offsets_vec) { }
// Pre-initialize all elements requiring it.
virtual void DoPreInits(InitsManager* im, const std::vector<int>& offsets_vec) {}
// Generate a single element.
virtual void GenerateElement(InitsManager* im, T2& init, int offset) { }
// Generate a single element.
virtual void GenerateElement(InitsManager* im, T2& init, int offset) {}
// The initialization vector in its entirety.
std::vector<T1>& inits_vec;
// The initialization vector in its entirety.
std::vector<T1>& inits_vec;
// A meta-index for retrieving the vector-of-vector-of-indices.
int offsets_set;
// A meta-index for retrieving the vector-of-vector-of-indices.
int offsets_set;
// Indexed by cohort.
std::vector<T2> inits;
};
// Indexed by cohort.
std::vector<T2> inits;
};
// Manages an initialization vector that uses "custom" initializers
// (tailored ones rather than initializers based on indexing).
template <class T> using CPP_InitVec = std::vector<std::shared_ptr<CPP_Init<T>>>;
template <class T> class CPP_CustomInits : public CPP_AbstractInits<T, CPP_InitVec<T>>
{
template<class T>
using CPP_InitVec = std::vector<std::shared_ptr<CPP_Init<T>>>;
template<class T>
class CPP_CustomInits : public CPP_AbstractInits<T, CPP_InitVec<T>> {
public:
CPP_CustomInits(std::vector<T>& _inits_vec, int _offsets_set,
std::vector<CPP_InitVec<T>> _inits)
: CPP_AbstractInits<T, CPP_InitVec<T>>(_inits_vec, _offsets_set, std::move(_inits))
{
}
CPP_CustomInits(std::vector<T>& _inits_vec, int _offsets_set, std::vector<CPP_InitVec<T>> _inits)
: CPP_AbstractInits<T, CPP_InitVec<T>>(_inits_vec, _offsets_set, std::move(_inits)) {}
private:
void DoPreInits(InitsManager* im, const std::vector<int>& offsets_vec) override
{
int cohort = 0;
for ( const auto& co : this->inits )
{
auto& cohort_offsets = im->Indices(offsets_vec[cohort]);
for ( auto i = 0U; i < co.size(); ++i )
co[i]->PreInit(im, this->inits_vec, cohort_offsets[i]);
++cohort;
}
}
void DoPreInits(InitsManager* im, const std::vector<int>& offsets_vec) override {
int cohort = 0;
for ( const auto& co : this->inits ) {
auto& cohort_offsets = im->Indices(offsets_vec[cohort]);
for ( auto i = 0U; i < co.size(); ++i )
co[i]->PreInit(im, this->inits_vec, cohort_offsets[i]);
++cohort;
}
}
void InitializeCohortWithOffsets(InitsManager* im, int cohort,
const std::vector<int>& cohort_offsets) override
{
// Loop over the cohort's elements to initialize them.
auto& co = this->inits[cohort];
for ( auto i = 0U; i < co.size(); ++i )
co[i]->Generate(im, this->inits_vec, cohort_offsets[i]);
}
};
void InitializeCohortWithOffsets(InitsManager* im, int cohort, const std::vector<int>& cohort_offsets) override {
// Loop over the cohort's elements to initialize them.
auto& co = this->inits[cohort];
for ( auto i = 0U; i < co.size(); ++i )
co[i]->Generate(im, this->inits_vec, cohort_offsets[i]);
}
};
// Provides access to elements of an initialization vector of the given type.
template <class T> class CPP_InitAccessor : public CPP_AbstractInitAccessor
{
template<class T>
class CPP_InitAccessor : public CPP_AbstractInitAccessor {
public:
CPP_InitAccessor(std::vector<T>& _inits_vec) : inits_vec(_inits_vec) { }
CPP_InitAccessor(std::vector<T>& _inits_vec) : inits_vec(_inits_vec) {}
ValPtr Get(int index) const override { return inits_vec[index]; }
ValPtr Get(int index) const override { return inits_vec[index]; }
private:
std::vector<T>& inits_vec;
};
std::vector<T>& inits_vec;
};
// A type used for initializations that are based on indices into
// initialization vectors.
@ -235,82 +218,60 @@ using ValElemVecVec = std::vector<ValElemVec>;
// Manages an initialization vector of the given type whose elements are
// built up from previously constructed values in other initialization vectors.
template <class T> class CPP_IndexedInits : public CPP_AbstractInits<T, ValElemVecVec>
{
template<class T>
class CPP_IndexedInits : public CPP_AbstractInits<T, ValElemVecVec> {
public:
CPP_IndexedInits(std::vector<T>& _inits_vec, int _offsets_set,
std::vector<ValElemVecVec> _inits)
: CPP_AbstractInits<T, ValElemVecVec>(_inits_vec, _offsets_set, std::move(_inits))
{
}
CPP_IndexedInits(std::vector<T>& _inits_vec, int _offsets_set, std::vector<ValElemVecVec> _inits)
: CPP_AbstractInits<T, ValElemVecVec>(_inits_vec, _offsets_set, std::move(_inits)) {}
protected:
void InitializeCohortWithOffsets(InitsManager* im, int cohort,
const std::vector<int>& cohort_offsets) override;
void InitializeCohortWithOffsets(InitsManager* im, int cohort, const std::vector<int>& cohort_offsets) override;
// Note, in the following we pass in the inits_vec, even though
// the method will have direct access to it, because we want to
// use overloading to dispatch to custom generation for different
// types of values.
void Generate(InitsManager* im, std::vector<EnumValPtr>& ivec, int offset,
ValElemVec& init_vals);
void Generate(InitsManager* im, std::vector<StringValPtr>& ivec, int offset,
ValElemVec& init_vals);
void Generate(InitsManager* im, std::vector<PatternValPtr>& ivec, int offset,
ValElemVec& init_vals);
void Generate(InitsManager* im, std::vector<ListValPtr>& ivec, int offset,
ValElemVec& init_vals) const;
void Generate(InitsManager* im, std::vector<VectorValPtr>& ivec, int offset,
ValElemVec& init_vals) const;
void Generate(InitsManager* im, std::vector<RecordValPtr>& ivec, int offset,
ValElemVec& init_vals) const;
void Generate(InitsManager* im, std::vector<TableValPtr>& ivec, int offset,
ValElemVec& init_vals) const;
void Generate(InitsManager* im, std::vector<FileValPtr>& ivec, int offset,
ValElemVec& init_vals) const;
void Generate(InitsManager* im, std::vector<FuncValPtr>& ivec, int offset,
ValElemVec& init_vals) const;
void Generate(InitsManager* im, std::vector<AttrPtr>& ivec, int offset,
ValElemVec& init_vals) const;
void Generate(InitsManager* im, std::vector<AttributesPtr>& ivec, int offset,
ValElemVec& init_vals) const;
// Note, in the following we pass in the inits_vec, even though
// the method will have direct access to it, because we want to
// use overloading to dispatch to custom generation for different
// types of values.
void Generate(InitsManager* im, std::vector<EnumValPtr>& ivec, int offset, ValElemVec& init_vals);
void Generate(InitsManager* im, std::vector<StringValPtr>& ivec, int offset, ValElemVec& init_vals);
void Generate(InitsManager* im, std::vector<PatternValPtr>& ivec, int offset, ValElemVec& init_vals);
void Generate(InitsManager* im, std::vector<ListValPtr>& ivec, int offset, ValElemVec& init_vals) const;
void Generate(InitsManager* im, std::vector<VectorValPtr>& ivec, int offset, ValElemVec& init_vals) const;
void Generate(InitsManager* im, std::vector<RecordValPtr>& ivec, int offset, ValElemVec& init_vals) const;
void Generate(InitsManager* im, std::vector<TableValPtr>& ivec, int offset, ValElemVec& init_vals) const;
void Generate(InitsManager* im, std::vector<FileValPtr>& ivec, int offset, ValElemVec& init_vals) const;
void Generate(InitsManager* im, std::vector<FuncValPtr>& ivec, int offset, ValElemVec& init_vals) const;
void Generate(InitsManager* im, std::vector<AttrPtr>& ivec, int offset, ValElemVec& init_vals) const;
void Generate(InitsManager* im, std::vector<AttributesPtr>& ivec, int offset, ValElemVec& init_vals) const;
// The TypePtr initialization vector requires special treatment, since
// it has to dispatch on subclasses of TypePtr.
virtual void Generate(InitsManager* im, std::vector<TypePtr>& ivec, int offset,
ValElemVec& init_vals) const
{
ASSERT(0);
}
};
// The TypePtr initialization vector requires special treatment, since
// it has to dispatch on subclasses of TypePtr.
virtual void Generate(InitsManager* im, std::vector<TypePtr>& ivec, int offset, ValElemVec& init_vals) const {
ASSERT(0);
}
};
// A specialization of CPP_IndexedInits that supports initializing based
// on subclasses of TypePtr.
class CPP_TypeInits : public CPP_IndexedInits<TypePtr>
{
class CPP_TypeInits : public CPP_IndexedInits<TypePtr> {
public:
CPP_TypeInits(std::vector<TypePtr>& _inits_vec, int _offsets_set,
std::vector<std::vector<ValElemVec>> _inits)
: CPP_IndexedInits<TypePtr>(_inits_vec, _offsets_set, _inits)
{
}
CPP_TypeInits(std::vector<TypePtr>& _inits_vec, int _offsets_set, std::vector<std::vector<ValElemVec>> _inits)
: CPP_IndexedInits<TypePtr>(_inits_vec, _offsets_set, _inits) {}
protected:
void DoPreInits(InitsManager* im, const std::vector<int>& offsets_vec) override;
void PreInit(InitsManager* im, int offset, ValElemVec& init_vals);
void DoPreInits(InitsManager* im, const std::vector<int>& offsets_vec) override;
void PreInit(InitsManager* im, int offset, ValElemVec& init_vals);
void Generate(InitsManager* im, std::vector<TypePtr>& ivec, int offset,
ValElemVec& init_vals) const override;
void Generate(InitsManager* im, std::vector<TypePtr>& ivec, int offset, ValElemVec& init_vals) const override;
TypePtr BuildEnumType(InitsManager* im, ValElemVec& init_vals) const;
TypePtr BuildOpaqueType(InitsManager* im, ValElemVec& init_vals) const;
TypePtr BuildTypeType(InitsManager* im, ValElemVec& init_vals) const;
TypePtr BuildVectorType(InitsManager* im, ValElemVec& init_vals) const;
TypePtr BuildTypeList(InitsManager* im, ValElemVec& init_vals, int offset) const;
TypePtr BuildTableType(InitsManager* im, ValElemVec& init_vals, int offset) const;
TypePtr BuildFuncType(InitsManager* im, ValElemVec& init_vals) const;
TypePtr BuildRecordType(InitsManager* im, ValElemVec& init_vals, int offset) const;
};
TypePtr BuildEnumType(InitsManager* im, ValElemVec& init_vals) const;
TypePtr BuildOpaqueType(InitsManager* im, ValElemVec& init_vals) const;
TypePtr BuildTypeType(InitsManager* im, ValElemVec& init_vals) const;
TypePtr BuildVectorType(InitsManager* im, ValElemVec& init_vals) const;
TypePtr BuildTypeList(InitsManager* im, ValElemVec& init_vals, int offset) const;
TypePtr BuildTableType(InitsManager* im, ValElemVec& init_vals, int offset) const;
TypePtr BuildFuncType(InitsManager* im, ValElemVec& init_vals) const;
TypePtr BuildRecordType(InitsManager* im, ValElemVec& init_vals, int offset) const;
};
// Abstract class for initializing basic (non-compound) constants. T1 is
// the Zeek type for the constructed constant, T2 is the C++ type of its
@ -321,258 +282,227 @@ protected:
// would trade complexity here for complexity in InitsInfo. So we instead
// keep this class distinct, since at heart it's a simpler set of methods
// and that way we can keep them as such here.
template <class T1, typename T2> class CPP_AbstractBasicConsts
{
template<class T1, typename T2>
class CPP_AbstractBasicConsts {
public:
CPP_AbstractBasicConsts(std::vector<T1>& _inits_vec, int _offsets_set, std::vector<T2> _inits)
: inits_vec(_inits_vec), offsets_set(_offsets_set), inits(std::move(_inits))
{
inits_vec.resize(inits.size());
}
CPP_AbstractBasicConsts(std::vector<T1>& _inits_vec, int _offsets_set, std::vector<T2> _inits)
: inits_vec(_inits_vec), offsets_set(_offsets_set), inits(std::move(_inits)) {
inits_vec.resize(inits.size());
}
void InitializeCohort(InitsManager* im, int cohort)
{
ASSERT(cohort == 0);
auto& offsets_vec = im->Indices(offsets_set);
auto& cohort_offsets = im->Indices(offsets_vec[cohort]);
for ( auto i = 0U; i < inits.size(); ++i )
InitElem(im, cohort_offsets[i], i);
}
void InitializeCohort(InitsManager* im, int cohort) {
ASSERT(cohort == 0);
auto& offsets_vec = im->Indices(offsets_set);
auto& cohort_offsets = im->Indices(offsets_vec[cohort]);
for ( auto i = 0U; i < inits.size(); ++i )
InitElem(im, cohort_offsets[i], i);
}
protected:
virtual void InitElem(InitsManager* im, int offset, int index) { ASSERT(0); }
virtual void InitElem(InitsManager* im, int offset, int index) { ASSERT(0); }
protected:
// See CPP_AbstractInits for the nature of these.
std::vector<T1>& inits_vec;
int offsets_set;
std::vector<T2> inits;
};
// See CPP_AbstractInits for the nature of these.
std::vector<T1>& inits_vec;
int offsets_set;
std::vector<T2> inits;
};
// Class for initializing a basic constant of Zeek type T1, using initializers
// of C++ type T2. T1 is an intrusive pointer to a T3 type; for example, if
// T1 is a BoolValPtr then T3 will be BoolVal.
template <class T1, typename T2, class T3>
class CPP_BasicConsts : public CPP_AbstractBasicConsts<T1, T2>
{
template<class T1, typename T2, class T3>
class CPP_BasicConsts : public CPP_AbstractBasicConsts<T1, T2> {
public:
CPP_BasicConsts(std::vector<T1>& _inits_vec, int _offsets_set, std::vector<T2> _inits)
: CPP_AbstractBasicConsts<T1, T2>(_inits_vec, _offsets_set, std::move(_inits))
{
}
CPP_BasicConsts(std::vector<T1>& _inits_vec, int _offsets_set, std::vector<T2> _inits)
: CPP_AbstractBasicConsts<T1, T2>(_inits_vec, _offsets_set, std::move(_inits)) {}
void InitElem(InitsManager* /* im */, int offset, int index) override
{
this->inits_vec[offset] = make_intrusive<T3>(this->inits[index]);
}
};
void InitElem(InitsManager* /* im */, int offset, int index) override {
this->inits_vec[offset] = make_intrusive<T3>(this->inits[index]);
}
};
// Specific classes for basic constants that use string-based constructors.
class CPP_AddrConsts : public CPP_AbstractBasicConsts<AddrValPtr, int>
{
class CPP_AddrConsts : public CPP_AbstractBasicConsts<AddrValPtr, int> {
public:
CPP_AddrConsts(std::vector<AddrValPtr>& _inits_vec, int _offsets_set, std::vector<int> _inits)
: CPP_AbstractBasicConsts<AddrValPtr, int>(_inits_vec, _offsets_set, std::move(_inits))
{
}
CPP_AddrConsts(std::vector<AddrValPtr>& _inits_vec, int _offsets_set, std::vector<int> _inits)
: CPP_AbstractBasicConsts<AddrValPtr, int>(_inits_vec, _offsets_set, std::move(_inits)) {}
void InitElem(InitsManager* im, int offset, int index) override
{
auto s = im->Strings(this->inits[index]);
this->inits_vec[offset] = make_intrusive<AddrVal>(s);
}
};
void InitElem(InitsManager* im, int offset, int index) override {
auto s = im->Strings(this->inits[index]);
this->inits_vec[offset] = make_intrusive<AddrVal>(s);
}
};
class CPP_SubNetConsts : public CPP_AbstractBasicConsts<SubNetValPtr, int>
{
class CPP_SubNetConsts : public CPP_AbstractBasicConsts<SubNetValPtr, int> {
public:
CPP_SubNetConsts(std::vector<SubNetValPtr>& _inits_vec, int _offsets_set,
std::vector<int> _inits)
: CPP_AbstractBasicConsts<SubNetValPtr, int>(_inits_vec, _offsets_set, std::move(_inits))
{
}
CPP_SubNetConsts(std::vector<SubNetValPtr>& _inits_vec, int _offsets_set, std::vector<int> _inits)
: CPP_AbstractBasicConsts<SubNetValPtr, int>(_inits_vec, _offsets_set, std::move(_inits)) {}
void InitElem(InitsManager* im, int offset, int index) override
{
auto s = im->Strings(this->inits[index]);
this->inits_vec[offset] = make_intrusive<SubNetVal>(s);
}
};
void InitElem(InitsManager* im, int offset, int index) override {
auto s = im->Strings(this->inits[index]);
this->inits_vec[offset] = make_intrusive<SubNetVal>(s);
}
};
// Class for initializing a Zeek global. These don't go into an initialization
// vector, so we use void* as the underlying type.
class CPP_GlobalInit : public CPP_Init<void*>
{
class CPP_GlobalInit : public CPP_Init<void*> {
public:
CPP_GlobalInit(IDPtr& _global, const char* _name, int _type, int _attrs, int _val,
bool _exported, bool _func_with_no_val)
: CPP_Init<void*>(), global(_global), name(_name), type(_type), attrs(_attrs), val(_val),
exported(_exported), func_with_no_val(_func_with_no_val)
{
}
CPP_GlobalInit(IDPtr& _global, const char* _name, int _type, int _attrs, int _val, bool _exported,
bool _func_with_no_val)
: CPP_Init<void*>(),
global(_global),
name(_name),
type(_type),
attrs(_attrs),
val(_val),
exported(_exported),
func_with_no_val(_func_with_no_val) {}
void Generate(InitsManager* im, std::vector<void*>& /* inits_vec */,
int /* offset */) const override;
void Generate(InitsManager* im, std::vector<void*>& /* inits_vec */, int /* offset */) const override;
protected:
IDPtr& global;
const char* name;
int type;
int attrs;
int val;
bool exported;
bool func_with_no_val;
};
IDPtr& global;
const char* name;
int type;
int attrs;
int val;
bool exported;
bool func_with_no_val;
};
// Abstract class for constructing a CallExpr to evaluate a Zeek expression.
class CPP_AbstractCallExprInit : public CPP_Init<CallExprPtr>
{
class CPP_AbstractCallExprInit : public CPP_Init<CallExprPtr> {
public:
CPP_AbstractCallExprInit() : CPP_Init<CallExprPtr>() { }
};
CPP_AbstractCallExprInit() : CPP_Init<CallExprPtr>() {}
};
// Constructs a CallExpr that calls a given CPPFunc subclass.
template <class T> class CPP_CallExprInit : public CPP_AbstractCallExprInit
{
template<class T>
class CPP_CallExprInit : public CPP_AbstractCallExprInit {
public:
CPP_CallExprInit(CallExprPtr& _e_var) : CPP_AbstractCallExprInit(), e_var(_e_var) { }
CPP_CallExprInit(CallExprPtr& _e_var) : CPP_AbstractCallExprInit(), e_var(_e_var) {}
void Generate(InitsManager* /* im */, std::vector<CallExprPtr>& inits_vec,
int offset) const override
{
auto wrapper_class = make_intrusive<T>();
auto func_val = make_intrusive<FuncVal>(wrapper_class);
auto func_expr = make_intrusive<ConstExpr>(func_val);
auto empty_args = make_intrusive<ListExpr>();
void Generate(InitsManager* /* im */, std::vector<CallExprPtr>& inits_vec, int offset) const override {
auto wrapper_class = make_intrusive<T>();
auto func_val = make_intrusive<FuncVal>(wrapper_class);
auto func_expr = make_intrusive<ConstExpr>(func_val);
auto empty_args = make_intrusive<ListExpr>();
e_var = make_intrusive<CallExpr>(func_expr, empty_args);
inits_vec[offset] = e_var;
}
e_var = make_intrusive<CallExpr>(func_expr, empty_args);
inits_vec[offset] = e_var;
}
private:
// Where to store the expression once we've built it.
CallExprPtr& e_var;
};
// Where to store the expression once we've built it.
CallExprPtr& e_var;
};
// Abstract class for registering a lambda defined in terms of a CPPStmt.
class CPP_AbstractLambdaRegistration : public CPP_Init<void*>
{
class CPP_AbstractLambdaRegistration : public CPP_Init<void*> {
public:
CPP_AbstractLambdaRegistration() : CPP_Init<void*>() { }
};
CPP_AbstractLambdaRegistration() : CPP_Init<void*>() {}
};
// Registers a lambda defined in terms of a given CPPStmt subclass.
template <class T> class CPP_LambdaRegistration : public CPP_AbstractLambdaRegistration
{
template<class T>
class CPP_LambdaRegistration : public CPP_AbstractLambdaRegistration {
public:
CPP_LambdaRegistration(const char* _name, int _func_type, p_hash_type _h, bool _has_captures)
: CPP_AbstractLambdaRegistration(), name(_name), func_type(_func_type), h(_h),
has_captures(_has_captures)
{
}
CPP_LambdaRegistration(const char* _name, int _func_type, p_hash_type _h, bool _has_captures)
: CPP_AbstractLambdaRegistration(), name(_name), func_type(_func_type), h(_h), has_captures(_has_captures) {}
void Generate(InitsManager* im, std::vector<void*>& inits_vec, int offset) const override
{
auto l = make_intrusive<T>(name);
auto& ft = im->Types(func_type);
register_lambda__CPP(l, h, name, ft, has_captures);
}
void Generate(InitsManager* im, std::vector<void*>& inits_vec, int offset) const override {
auto l = make_intrusive<T>(name);
auto& ft = im->Types(func_type);
register_lambda__CPP(l, h, name, ft, has_captures);
}
protected:
const char* name;
int func_type;
p_hash_type h;
bool has_captures;
};
const char* name;
int func_type;
p_hash_type h;
bool has_captures;
};
// Constructs at run-time a mapping between abstract record field offsets used
// when compiling a set of scripts to their concrete offsets (which might differ
// from those during compilation due to loading of other scripts that extend
// various records).
class CPP_FieldMapping
{
class CPP_FieldMapping {
public:
CPP_FieldMapping(int _rec, std::string _field_name, int _field_type, int _field_attrs)
: rec(_rec), field_name(std::move(_field_name)), field_type(_field_type),
field_attrs(_field_attrs)
{
}
CPP_FieldMapping(int _rec, std::string _field_name, int _field_type, int _field_attrs)
: rec(_rec), field_name(std::move(_field_name)), field_type(_field_type), field_attrs(_field_attrs) {}
int ComputeOffset(InitsManager* im) const;
int ComputeOffset(InitsManager* im) const;
private:
int rec; // index to retrieve the record's type
std::string field_name; // which field this offset pertains to
int field_type; // the field's type, in case we have to construct it
int field_attrs; // the same for the field's attributes
};
int rec; // index to retrieve the record's type
std::string field_name; // which field this offset pertains to
int field_type; // the field's type, in case we have to construct it
int field_attrs; // the same for the field's attributes
};
// Constructs at run-time a mapping between abstract enum values used when
// compiling a set of scripts to their concrete values (which might differ
// from those during compilation due to loading of other scripts that extend
// the enum).
class CPP_EnumMapping
{
class CPP_EnumMapping {
public:
CPP_EnumMapping(int _e_type, std::string _e_name) : e_type(_e_type), e_name(std::move(_e_name))
{
}
CPP_EnumMapping(int _e_type, std::string _e_name) : e_type(_e_type), e_name(std::move(_e_name)) {}
int ComputeOffset(InitsManager* im) const;
int ComputeOffset(InitsManager* im) const;
private:
int e_type; // index to EnumType
std::string e_name; // which enum constant for that type
};
int e_type; // index to EnumType
std::string e_name; // which enum constant for that type
};
// Looks up a BiF of the given name, making it available to compiled
// code via a C++ global.
class CPP_LookupBiF
{
class CPP_LookupBiF {
public:
CPP_LookupBiF(zeek::Func*& _bif_func, std::string _bif_name)
: bif_func(_bif_func), bif_name(std::move(_bif_name))
{
}
CPP_LookupBiF(zeek::Func*& _bif_func, std::string _bif_name)
: bif_func(_bif_func), bif_name(std::move(_bif_name)) {}
void ResolveBiF() const
{
// We allow a BiF to be resolved multiple times. This is to
// support plugins that might load BiFs that aren't initially
// available, and also global initializations that might
// require (other) BiFs that *are* initially available.
if ( ! bif_func )
bif_func = lookup_bif__CPP(bif_name.c_str());
}
void ResolveBiF() const {
// We allow a BiF to be resolved multiple times. This is to
// support plugins that might load BiFs that aren't initially
// available, and also global initializations that might
// require (other) BiFs that *are* initially available.
if ( ! bif_func )
bif_func = lookup_bif__CPP(bif_name.c_str());
}
protected:
zeek::Func*& bif_func; // where to store the pointer to the BiF
std::string bif_name; // the BiF's name
};
zeek::Func*& bif_func; // where to store the pointer to the BiF
std::string bif_name; // the BiF's name
};
// Information needed to register a compiled function body (which makes it
// available to substitute for the body's AST). The compiler generates
// code that loops over a vector of these to perform the registrations.
struct CPP_RegisterBody
{
CPP_RegisterBody(std::string _func_name, void* _func, int _type_signature, int _priority,
p_hash_type _h, const char* _filename, int _line_num,
std::vector<std::string> _events)
: func_name(std::move(_func_name)), func(_func), type_signature(_type_signature),
priority(_priority), h(_h), filename(_filename), line_num(_line_num),
events(std::move(_events))
{
}
struct CPP_RegisterBody {
CPP_RegisterBody(std::string _func_name, void* _func, int _type_signature, int _priority, p_hash_type _h,
const char* _filename, int _line_num, std::vector<std::string> _events)
: func_name(std::move(_func_name)),
func(_func),
type_signature(_type_signature),
priority(_priority),
h(_h),
filename(_filename),
line_num(_line_num),
events(std::move(_events)) {}
std::string func_name; // name of the function
void* func; // pointer to C++
int type_signature;
int priority;
p_hash_type h;
const char* filename;
int line_num;
std::vector<std::string> events;
};
std::string func_name; // name of the function
void* func; // pointer to C++
int type_signature;
int priority;
p_hash_type h;
const char* filename;
int line_num;
std::vector<std::string> events;
};
// Helper function that takes a (large) array of int's and from them
// constructs the corresponding vector-of-vector-of-indices. Each
@ -581,4 +511,4 @@ struct CPP_RegisterBody
// end of the array upon encountering a "size" entry of -1.
extern void generate_indices_set(int* inits, std::vector<std::vector<int>>& indices_set);
} // zeek::detail
} // namespace zeek::detail

View file

@ -9,325 +9,285 @@
#include "zeek/Trigger.h"
#include "zeek/ZeekString.h"
namespace zeek::detail
{
namespace zeek::detail {
using namespace std;
StringValPtr str_concat__CPP(const String* s1, const String* s2)
{
vector<const String*> strings(2);
strings[0] = s1;
strings[1] = s2;
StringValPtr str_concat__CPP(const String* s1, const String* s2) {
vector<const String*> strings(2);
strings[0] = s1;
strings[1] = s2;
return make_intrusive<StringVal>(concatenate(strings));
}
return make_intrusive<StringVal>(concatenate(strings));
}
bool str_in__CPP(const String* s1, const String* s2)
{
auto s = reinterpret_cast<const unsigned char*>(s1->CheckString());
return util::strstr_n(s2->Len(), s2->Bytes(), s1->Len(), s) != -1;
}
bool str_in__CPP(const String* s1, const String* s2) {
auto s = reinterpret_cast<const unsigned char*>(s1->CheckString());
return util::strstr_n(s2->Len(), s2->Bytes(), s1->Len(), s) != -1;
}
ListValPtr index_val__CPP(vector<ValPtr> indices)
{
auto ind_v = make_intrusive<ListVal>(TYPE_ANY);
ListValPtr index_val__CPP(vector<ValPtr> indices) {
auto ind_v = make_intrusive<ListVal>(TYPE_ANY);
// In the future, we could provide N versions of this that
// unroll the loop.
for ( const auto& i : indices )
ind_v->Append(i);
// In the future, we could provide N versions of this that
// unroll the loop.
for ( const auto& i : indices )
ind_v->Append(i);
return ind_v;
}
return ind_v;
}
ValPtr index_table__CPP(const TableValPtr& t, vector<ValPtr> indices)
{
auto v = t->FindOrDefault(index_val__CPP(std::move(indices)));
if ( ! v )
reporter->CPPRuntimeError("no such index");
return v;
}
ValPtr index_table__CPP(const TableValPtr& t, vector<ValPtr> indices) {
auto v = t->FindOrDefault(index_val__CPP(std::move(indices)));
if ( ! v )
reporter->CPPRuntimeError("no such index");
return v;
}
ValPtr index_vec__CPP(const VectorValPtr& vec, int index)
{
if ( index < 0 )
index += vec->Size();
ValPtr index_vec__CPP(const VectorValPtr& vec, int index) {
if ( index < 0 )
index += vec->Size();
auto v = vec->ValAt(index);
if ( ! v )
reporter->CPPRuntimeError("no such index");
auto v = vec->ValAt(index);
if ( ! v )
reporter->CPPRuntimeError("no such index");
return v;
}
return v;
}
ValPtr index_string__CPP(const StringValPtr& svp, vector<ValPtr> indices)
{
return index_string(svp->AsString(), index_val__CPP(std::move(indices)).get());
}
ValPtr index_string__CPP(const StringValPtr& svp, vector<ValPtr> indices) {
return index_string(svp->AsString(), index_val__CPP(std::move(indices)).get());
}
ValPtr when_index_table__CPP(const TableValPtr& t, vector<ValPtr> indices)
{
auto v = index_table__CPP(t, std::move(indices));
if ( v && IndexExprWhen::evaluating > 0 )
IndexExprWhen::results.emplace_back(v);
return v;
}
ValPtr when_index_table__CPP(const TableValPtr& t, vector<ValPtr> indices) {
auto v = index_table__CPP(t, std::move(indices));
if ( v && IndexExprWhen::evaluating > 0 )
IndexExprWhen::results.emplace_back(v);
return v;
}
ValPtr when_index_vec__CPP(const VectorValPtr& vec, int index)
{
auto v = index_vec__CPP(vec, index);
if ( v && IndexExprWhen::evaluating > 0 )
IndexExprWhen::results.emplace_back(v);
return v;
}
ValPtr when_index_vec__CPP(const VectorValPtr& vec, int index) {
auto v = index_vec__CPP(vec, index);
if ( v && IndexExprWhen::evaluating > 0 )
IndexExprWhen::results.emplace_back(v);
return v;
}
ValPtr when_index_slice__CPP(VectorVal* vec, const ListVal* lv)
{
auto v = index_slice(vec, lv);
if ( v && IndexExprWhen::evaluating > 0 )
IndexExprWhen::results.emplace_back(v);
return v;
}
ValPtr when_index_slice__CPP(VectorVal* vec, const ListVal* lv) {
auto v = index_slice(vec, lv);
if ( v && IndexExprWhen::evaluating > 0 )
IndexExprWhen::results.emplace_back(v);
return v;
}
ValPtr when_invoke__CPP(Func* f, std::vector<ValPtr> args, Frame* frame, void* caller_addr)
{
auto trigger = frame->GetTrigger();
ValPtr when_invoke__CPP(Func* f, std::vector<ValPtr> args, Frame* frame, void* caller_addr) {
auto trigger = frame->GetTrigger();
if ( trigger )
{
Val* v = trigger->Lookup(caller_addr);
if ( v )
return {NewRef{}, v};
}
if ( trigger ) {
Val* v = trigger->Lookup(caller_addr);
if ( v )
return {NewRef{}, v};
}
frame->SetTriggerAssoc(caller_addr);
frame->SetTriggerAssoc(caller_addr);
auto res = f->Invoke(&args, frame);
if ( ! res )
throw CPPDelayedCallException();
auto res = f->Invoke(&args, frame);
if ( ! res )
throw CPPDelayedCallException();
return res;
}
return res;
}
ValPtr set_event__CPP(IDPtr g, ValPtr v, EventHandlerPtr& gh)
{
g->SetVal(v);
gh = event_registry->Register(g->Name());
return v;
}
ValPtr set_event__CPP(IDPtr g, ValPtr v, EventHandlerPtr& gh) {
g->SetVal(v);
gh = event_registry->Register(g->Name());
return v;
}
ValPtr cast_value_to_type__CPP(const ValPtr& v, const TypePtr& t)
{
auto result = cast_value_to_type(v.get(), t.get());
if ( ! result )
reporter->CPPRuntimeError("invalid cast of value with type '%s' to type '%s'",
type_name(v->GetType()->Tag()), type_name(t->Tag()));
return result;
}
ValPtr cast_value_to_type__CPP(const ValPtr& v, const TypePtr& t) {
auto result = cast_value_to_type(v.get(), t.get());
if ( ! result )
reporter->CPPRuntimeError("invalid cast of value with type '%s' to type '%s'", type_name(v->GetType()->Tag()),
type_name(t->Tag()));
return result;
}
ValPtr from_any__CPP(const ValPtr& v, const TypePtr& t)
{
auto vt = v->GetType()->Tag();
ValPtr from_any__CPP(const ValPtr& v, const TypePtr& t) {
auto vt = v->GetType()->Tag();
if ( vt != t->Tag() && vt != TYPE_ERROR )
reporter->CPPRuntimeError("incompatible \"any\" type (%s vs. %s)", type_name(vt),
type_name(t->Tag()));
if ( vt != t->Tag() && vt != TYPE_ERROR )
reporter->CPPRuntimeError("incompatible \"any\" type (%s vs. %s)", type_name(vt), type_name(t->Tag()));
return v;
}
return v;
}
ValPtr from_any_vec__CPP(const ValPtr& v, const TypePtr& t)
{
if ( ! v->AsVectorVal()->Concretize(t) )
reporter->CPPRuntimeError("incompatible \"vector of any\" type");
ValPtr from_any_vec__CPP(const ValPtr& v, const TypePtr& t) {
if ( ! v->AsVectorVal()->Concretize(t) )
reporter->CPPRuntimeError("incompatible \"vector of any\" type");
return v;
}
return v;
}
SubNetValPtr addr_mask__CPP(const IPAddr& a, uint32_t mask)
{
if ( a.GetFamily() == IPv4 )
{
if ( mask > 32 )
reporter->CPPRuntimeError("bad IPv4 subnet prefix length: %d", int(mask));
}
else
{
if ( mask > 128 )
reporter->CPPRuntimeError("bad IPv6 subnet prefix length: %d", int(mask));
}
SubNetValPtr addr_mask__CPP(const IPAddr& a, uint32_t mask) {
if ( a.GetFamily() == IPv4 ) {
if ( mask > 32 )
reporter->CPPRuntimeError("bad IPv4 subnet prefix length: %d", int(mask));
}
else {
if ( mask > 128 )
reporter->CPPRuntimeError("bad IPv6 subnet prefix length: %d", int(mask));
}
return make_intrusive<SubNetVal>(a, mask);
}
return make_intrusive<SubNetVal>(a, mask);
}
// Helper function for reporting invalidation of iterators.
static void check_iterators__CPP(bool invalid)
{
if ( invalid )
reporter->Warning("possible loop/iterator invalidation in compiled code");
}
static void check_iterators__CPP(bool invalid) {
if ( invalid )
reporter->Warning("possible loop/iterator invalidation in compiled code");
}
// Template for aggregate assignments of the form "v1[v2] = v3".
template <typename T> ValPtr assign_to_index__CPP(T v1, ValPtr v2, ValPtr v3)
{
bool iterators_invalidated = false;
auto err_msg = assign_to_index(std::move(v1), std::move(v2), v3, iterators_invalidated);
template<typename T>
ValPtr assign_to_index__CPP(T v1, ValPtr v2, ValPtr v3) {
bool iterators_invalidated = false;
auto err_msg = assign_to_index(std::move(v1), std::move(v2), v3, iterators_invalidated);
check_iterators__CPP(iterators_invalidated);
check_iterators__CPP(iterators_invalidated);
if ( err_msg )
reporter->CPPRuntimeError("%s", err_msg);
if ( err_msg )
reporter->CPPRuntimeError("%s", err_msg);
return v3;
}
return v3;
}
ValPtr assign_to_index__CPP(TableValPtr v1, ValPtr v2, ValPtr v3)
{
return assign_to_index__CPP<TableValPtr>(std::move(v1), std::move(v2), std::move(v3));
}
ValPtr assign_to_index__CPP(VectorValPtr v1, ValPtr v2, ValPtr v3)
{
return assign_to_index__CPP<VectorValPtr>(std::move(v1), std::move(v2), std::move(v3));
}
ValPtr assign_to_index__CPP(StringValPtr v1, ValPtr v2, ValPtr v3)
{
return assign_to_index__CPP<StringValPtr>(std::move(v1), std::move(v2), std::move(v3));
}
ValPtr assign_to_index__CPP(TableValPtr v1, ValPtr v2, ValPtr v3) {
return assign_to_index__CPP<TableValPtr>(std::move(v1), std::move(v2), std::move(v3));
}
ValPtr assign_to_index__CPP(VectorValPtr v1, ValPtr v2, ValPtr v3) {
return assign_to_index__CPP<VectorValPtr>(std::move(v1), std::move(v2), std::move(v3));
}
ValPtr assign_to_index__CPP(StringValPtr v1, ValPtr v2, ValPtr v3) {
return assign_to_index__CPP<StringValPtr>(std::move(v1), std::move(v2), std::move(v3));
}
void add_element__CPP(TableValPtr aggr, ListValPtr indices)
{
bool iterators_invalidated = false;
aggr->Assign(indices, nullptr, true, &iterators_invalidated);
check_iterators__CPP(iterators_invalidated);
}
void add_element__CPP(TableValPtr aggr, ListValPtr indices) {
bool iterators_invalidated = false;
aggr->Assign(indices, nullptr, true, &iterators_invalidated);
check_iterators__CPP(iterators_invalidated);
}
void remove_element__CPP(TableValPtr aggr, ListValPtr indices)
{
bool iterators_invalidated = false;
aggr->Remove(*indices.get(), true, &iterators_invalidated);
check_iterators__CPP(iterators_invalidated);
}
void remove_element__CPP(TableValPtr aggr, ListValPtr indices) {
bool iterators_invalidated = false;
aggr->Remove(*indices.get(), true, &iterators_invalidated);
check_iterators__CPP(iterators_invalidated);
}
// A helper function that takes a parallel vectors of attribute tags
// and values and returns a collective AttributesPtr corresponding to
// those instantiated attributes. For attributes that don't have
// associated expressions, the corresponding value should be nil.
static AttributesPtr build_attrs__CPP(vector<int> attr_tags, vector<ValPtr> attr_vals)
{
vector<AttrPtr> attrs;
int nattrs = attr_tags.size();
for ( auto i = 0; i < nattrs; ++i )
{
auto t_i = AttrTag(attr_tags[i]);
const auto& v_i = attr_vals[i];
ExprPtr e;
static AttributesPtr build_attrs__CPP(vector<int> attr_tags, vector<ValPtr> attr_vals) {
vector<AttrPtr> attrs;
int nattrs = attr_tags.size();
for ( auto i = 0; i < nattrs; ++i ) {
auto t_i = AttrTag(attr_tags[i]);
const auto& v_i = attr_vals[i];
ExprPtr e;
if ( v_i )
e = make_intrusive<ConstExpr>(v_i);
if ( v_i )
e = make_intrusive<ConstExpr>(v_i);
attrs.emplace_back(make_intrusive<Attr>(t_i, e));
}
attrs.emplace_back(make_intrusive<Attr>(t_i, e));
}
return make_intrusive<Attributes>(std::move(attrs), nullptr, false, false);
}
return make_intrusive<Attributes>(std::move(attrs), nullptr, false, false);
}
TableValPtr set_constructor__CPP(vector<ValPtr> elements, TableTypePtr t, vector<int> attr_tags,
vector<ValPtr> attr_vals)
{
auto attrs = build_attrs__CPP(std::move(attr_tags), std::move(attr_vals));
auto aggr = make_intrusive<TableVal>(std::move(t), std::move(attrs));
vector<ValPtr> attr_vals) {
auto attrs = build_attrs__CPP(std::move(attr_tags), std::move(attr_vals));
auto aggr = make_intrusive<TableVal>(std::move(t), std::move(attrs));
for ( auto& elem : elements )
aggr->Assign(std::move(elem), nullptr);
for ( auto& elem : elements )
aggr->Assign(std::move(elem), nullptr);
return aggr;
}
return aggr;
}
TableValPtr table_constructor__CPP(vector<ValPtr> indices, vector<ValPtr> vals, TableTypePtr t,
vector<int> attr_tags, vector<ValPtr> attr_vals)
{
const auto& yt = t->Yield();
auto n = indices.size();
TableValPtr table_constructor__CPP(vector<ValPtr> indices, vector<ValPtr> vals, TableTypePtr t, vector<int> attr_tags,
vector<ValPtr> attr_vals) {
const auto& yt = t->Yield();
auto n = indices.size();
auto attrs = build_attrs__CPP(std::move(attr_tags), std::move(attr_vals));
auto aggr = make_intrusive<TableVal>(std::move(t), std::move(attrs));
auto attrs = build_attrs__CPP(std::move(attr_tags), std::move(attr_vals));
auto aggr = make_intrusive<TableVal>(std::move(t), std::move(attrs));
for ( auto i = 0u; i < n; ++i )
{
auto v = check_and_promote(vals[i], yt, true);
if ( v )
aggr->Assign(std::move(indices[i]), std::move(v));
}
for ( auto i = 0u; i < n; ++i ) {
auto v = check_and_promote(vals[i], yt, true);
if ( v )
aggr->Assign(std::move(indices[i]), std::move(v));
}
return aggr;
}
return aggr;
}
void assign_attrs__CPP(IDPtr id, std::vector<int> attr_tags, std::vector<ValPtr> attr_vals)
{
id->SetAttrs(build_attrs__CPP(std::move(attr_tags), std::move(attr_vals)));
}
void assign_attrs__CPP(IDPtr id, std::vector<int> attr_tags, std::vector<ValPtr> attr_vals) {
id->SetAttrs(build_attrs__CPP(std::move(attr_tags), std::move(attr_vals)));
}
RecordValPtr record_constructor__CPP(vector<ValPtr> vals, RecordTypePtr t)
{
auto rv = make_intrusive<RecordVal>(t);
auto n = vals.size();
RecordValPtr record_constructor__CPP(vector<ValPtr> vals, RecordTypePtr t) {
auto rv = make_intrusive<RecordVal>(t);
auto n = vals.size();
for ( auto i = 0u; i < n; ++i )
{
auto& v_i = vals[i];
for ( auto i = 0u; i < n; ++i ) {
auto& v_i = vals[i];
if ( v_i && v_i->GetType()->Tag() == TYPE_VECTOR && v_i->AsVectorVal()->Size() == 0 )
{
const auto& t_ind = t->GetFieldType(i);
v_i->AsVectorVal()->Concretize(t_ind->Yield());
}
if ( v_i && v_i->GetType()->Tag() == TYPE_VECTOR && v_i->AsVectorVal()->Size() == 0 ) {
const auto& t_ind = t->GetFieldType(i);
v_i->AsVectorVal()->Concretize(t_ind->Yield());
}
rv->Assign(i, v_i);
}
rv->Assign(i, v_i);
}
return rv;
}
return rv;
}
RecordValPtr record_constructor_map__CPP(vector<ValPtr> vals, vector<int> map, RecordTypePtr t)
{
auto rv = make_intrusive<RecordVal>(t);
auto n = vals.size();
RecordValPtr record_constructor_map__CPP(vector<ValPtr> vals, vector<int> map, RecordTypePtr t) {
auto rv = make_intrusive<RecordVal>(t);
auto n = vals.size();
for ( auto i = 0u; i < n; ++i )
{
auto& v_i = vals[i];
auto ind = map[i];
for ( auto i = 0u; i < n; ++i ) {
auto& v_i = vals[i];
auto ind = map[i];
if ( v_i && v_i->GetType()->Tag() == TYPE_VECTOR && v_i->AsVectorVal()->Size() == 0 )
{
const auto& t_ind = t->GetFieldType(ind);
v_i->AsVectorVal()->Concretize(t_ind->Yield());
}
if ( v_i && v_i->GetType()->Tag() == TYPE_VECTOR && v_i->AsVectorVal()->Size() == 0 ) {
const auto& t_ind = t->GetFieldType(ind);
v_i->AsVectorVal()->Concretize(t_ind->Yield());
}
rv->Assign(ind, v_i);
}
rv->Assign(ind, v_i);
}
return rv;
}
return rv;
}
VectorValPtr vector_constructor__CPP(vector<ValPtr> vals, VectorTypePtr t)
{
auto vv = make_intrusive<VectorVal>(std::move(t));
auto n = vals.size();
VectorValPtr vector_constructor__CPP(vector<ValPtr> vals, VectorTypePtr t) {
auto vv = make_intrusive<VectorVal>(std::move(t));
auto n = vals.size();
for ( auto i = 0u; i < n; ++i )
vv->Assign(i, vals[i]);
for ( auto i = 0u; i < n; ++i )
vv->Assign(i, vals[i]);
return vv;
}
return vv;
}
ValPtr schedule__CPP(double dt, EventHandlerPtr event, vector<ValPtr> args)
{
if ( ! run_state::terminating )
timer_mgr->Add(new ScheduleTimer(event, std::move(args), dt));
ValPtr schedule__CPP(double dt, EventHandlerPtr event, vector<ValPtr> args) {
if ( ! run_state::terminating )
timer_mgr->Add(new ScheduleTimer(event, std::move(args), dt));
return nullptr;
}
return nullptr;
}
} // namespace zeek::detail
} // namespace zeek::detail

View file

@ -8,19 +8,16 @@
#include "zeek/OpaqueVal.h"
#include "zeek/script_opt/CPP/Func.h"
namespace zeek
{
namespace zeek {
using SubNetValPtr = IntrusivePtr<zeek::SubNetVal>;
namespace detail
{
namespace detail {
class CPPRuntime
{
class CPPRuntime {
public:
static auto RawOptField(const RecordValPtr& rv, int field) { return rv->RawOptField(field); }
};
static auto RawOptField(const RecordValPtr& rv, int field) { return rv->RawOptField(field); }
};
// Returns the concatenation of the given strings.
extern StringValPtr str_concat__CPP(const String* s1, const String* s2);
@ -50,27 +47,21 @@ extern ValPtr when_index_slice__CPP(VectorVal* vec, const ListVal* lv);
// Calls out to the given script or BiF function, which does not return
// a value.
inline ValPtr invoke_void__CPP(Func* f, std::vector<ValPtr> args, Frame* frame)
{
return f->Invoke(&args, frame);
}
inline ValPtr invoke_void__CPP(Func* f, std::vector<ValPtr> args, Frame* frame) { return f->Invoke(&args, frame); }
// Used for error propagation by failed calls.
class CPPInterpreterException : public InterpreterException
{
};
class CPPInterpreterException : public InterpreterException {};
// Calls out to the given script or BiF function. A separate function because
// of the need to (1) construct the "args" vector using {} initializers,
// but (2) needing to have the address of that vector.
inline ValPtr invoke__CPP(Func* f, std::vector<ValPtr> args, Frame* frame)
{
auto v = f->Invoke(&args, frame);
if ( ! v )
throw CPPInterpreterException();
inline ValPtr invoke__CPP(Func* f, std::vector<ValPtr> args, Frame* frame) {
auto v = f->Invoke(&args, frame);
if ( ! v )
throw CPPInterpreterException();
return v;
}
return v;
}
// The same, but raises an interpreter exception if the function does
// not return a value. Used for calls inside "when" conditions. The
@ -80,17 +71,14 @@ inline ValPtr invoke__CPP(Func* f, std::vector<ValPtr> args, Frame* frame)
extern ValPtr when_invoke__CPP(Func* f, std::vector<ValPtr> args, Frame* frame, void* caller_addr);
// Thrown when a call inside a "when" delays.
class CPPDelayedCallException : public InterpreterException
{
};
class CPPDelayedCallException : public InterpreterException {};
// Assigns the given value to the given global. A separate function because
// we also need to return the value, for use in assignment cascades.
inline ValPtr set_global__CPP(IDPtr g, ValPtr v)
{
g->SetVal(v);
return v;
}
inline ValPtr set_global__CPP(IDPtr g, ValPtr v) {
g->SetVal(v);
return v;
}
// Assigns the given global to the given value, which corresponds to an
// event handler.
@ -114,31 +102,28 @@ extern SubNetValPtr addr_mask__CPP(const IPAddr& a, uint32_t mask);
// Assigns the given field in the given record to the given value. A
// separate function to allow for assignment cascades.
inline ValPtr assign_field__CPP(RecordValPtr rec, int field, ValPtr v)
{
rec->Assign(field, v);
return v;
}
inline ValPtr assign_field__CPP(RecordValPtr rec, int field, ValPtr v) {
rec->Assign(field, v);
return v;
}
// Returns the given field in the given record. A separate function to
// support error handling.
inline ValPtr field_access__CPP(const RecordValPtr& rec, int field)
{
auto v = rec->GetFieldOrDefault(field);
if ( ! v )
reporter->CPPRuntimeError("field value missing");
inline ValPtr field_access__CPP(const RecordValPtr& rec, int field) {
auto v = rec->GetFieldOrDefault(field);
if ( ! v )
reporter->CPPRuntimeError("field value missing");
return v;
}
return v;
}
#define NATIVE_FIELD_ACCESS(type, zaccessor, vaccessor) \
inline type field_access_##type##__CPP(const RecordValPtr& r, int field) \
{ \
auto rv = CPPRuntime::RawOptField(r, field); \
if ( rv ) \
return (*rv).zaccessor(); \
return field_access__CPP(r, field)->vaccessor(); \
}
#define NATIVE_FIELD_ACCESS(type, zaccessor, vaccessor) \
inline type field_access_##type##__CPP(const RecordValPtr& r, int field) { \
auto rv = CPPRuntime::RawOptField(r, field); \
if ( rv ) \
return (*rv).zaccessor(); \
return field_access__CPP(r, field)->vaccessor(); \
}
NATIVE_FIELD_ACCESS(bool, AsInt, AsBool)
NATIVE_FIELD_ACCESS(int, AsInt, AsInt)
@ -146,14 +131,13 @@ NATIVE_FIELD_ACCESS(zeek_int_t, AsInt, AsInt)
NATIVE_FIELD_ACCESS(zeek_uint_t, AsCount, AsCount)
NATIVE_FIELD_ACCESS(double, AsDouble, AsDouble)
#define VP_FIELD_ACCESS(type, zaccessor) \
inline type##Ptr field_access_##type##__CPP(const RecordValPtr& r, int field) \
{ \
auto rv = CPPRuntime::RawOptField(r, field); \
if ( rv ) \
return {NewRef{}, rv->zaccessor()}; \
return cast_intrusive<type>(field_access__CPP(r, field)); \
}
#define VP_FIELD_ACCESS(type, zaccessor) \
inline type##Ptr field_access_##type##__CPP(const RecordValPtr& r, int field) { \
auto rv = CPPRuntime::RawOptField(r, field); \
if ( rv ) \
return {NewRef{}, rv->zaccessor()}; \
return cast_intrusive<type>(field_access__CPP(r, field)); \
}
VP_FIELD_ACCESS(StringVal, AsString)
VP_FIELD_ACCESS(AddrVal, AsAddr)
@ -182,53 +166,48 @@ extern void remove_element__CPP(TableValPtr aggr, ListValPtr indices);
// Returns the given table/set (which should be empty) coerced to
// the given Zeek type. A separate function in order to deal with
// error handling. Inlined because this gets invoked a lot.
inline TableValPtr table_coerce__CPP(const ValPtr& v, const TypePtr& t)
{
TableVal* tv = v->AsTableVal();
inline TableValPtr table_coerce__CPP(const ValPtr& v, const TypePtr& t) {
TableVal* tv = v->AsTableVal();
if ( tv->Size() > 0 )
reporter->CPPRuntimeError("coercion of non-empty table/set");
if ( tv->Size() > 0 )
reporter->CPPRuntimeError("coercion of non-empty table/set");
return make_intrusive<TableVal>(cast_intrusive<TableType>(t), tv->GetAttrs());
}
return make_intrusive<TableVal>(cast_intrusive<TableType>(t), tv->GetAttrs());
}
// For tables, executes t1 += t2.
inline TableValPtr table_append__CPP(const TableValPtr& t1, const TableValPtr& t2)
{
t2->AddTo(t1.get(), false);
return t1;
}
inline TableValPtr table_append__CPP(const TableValPtr& t1, const TableValPtr& t2) {
t2->AddTo(t1.get(), false);
return t1;
}
// For tables, executes t1 -= t2.
inline TableValPtr table_remove_from__CPP(const TableValPtr& t1, const TableValPtr& t2)
{
if ( t2->Size() > 0 )
t2->RemoveFrom(t1.get());
return t1;
}
inline TableValPtr table_remove_from__CPP(const TableValPtr& t1, const TableValPtr& t2) {
if ( t2->Size() > 0 )
t2->RemoveFrom(t1.get());
return t1;
}
// The same, for an empty record.
inline VectorValPtr vector_coerce__CPP(const ValPtr& v, const TypePtr& t)
{
VectorVal* vv = v->AsVectorVal();
inline VectorValPtr vector_coerce__CPP(const ValPtr& v, const TypePtr& t) {
VectorVal* vv = v->AsVectorVal();
if ( vv->Size() > 0 )
reporter->CPPRuntimeError("coercion of non-empty vector");
if ( vv->Size() > 0 )
reporter->CPPRuntimeError("coercion of non-empty vector");
return make_intrusive<VectorVal>(cast_intrusive<VectorType>(t));
}
return make_intrusive<VectorVal>(cast_intrusive<VectorType>(t));
}
// Constructs a set of the given type, containing the given elements, and
// with the associated attributes.
extern TableValPtr set_constructor__CPP(std::vector<ValPtr> elements, TableTypePtr t,
std::vector<int> attr_tags, std::vector<ValPtr> attr_vals);
extern TableValPtr set_constructor__CPP(std::vector<ValPtr> elements, TableTypePtr t, std::vector<int> attr_tags,
std::vector<ValPtr> attr_vals);
// Constructs a table of the given type, containing the given elements
// (specified as parallel index/value vectors), and with the associated
// attributes.
extern TableValPtr table_constructor__CPP(std::vector<ValPtr> indices, std::vector<ValPtr> vals,
TableTypePtr t, std::vector<int> attr_tags,
std::vector<ValPtr> attr_vals);
extern TableValPtr table_constructor__CPP(std::vector<ValPtr> indices, std::vector<ValPtr> vals, TableTypePtr t,
std::vector<int> attr_tags, std::vector<ValPtr> attr_vals);
// Assigns a set of attributes to an identifier.
extern void assign_attrs__CPP(IDPtr id, std::vector<int> attr_tags, std::vector<ValPtr> attr_vals);
@ -238,18 +217,16 @@ extern void assign_attrs__CPP(IDPtr id, std::vector<int> attr_tags, std::vector<
extern RecordValPtr record_constructor__CPP(std::vector<ValPtr> vals, RecordTypePtr t);
// Same, but with a map when using a named constructor.
extern RecordValPtr record_constructor_map__CPP(std::vector<ValPtr> vals, std::vector<int> map,
RecordTypePtr t);
extern RecordValPtr record_constructor_map__CPP(std::vector<ValPtr> vals, std::vector<int> map, RecordTypePtr t);
// Constructs a vector of the given type, populated with the given values.
extern VectorValPtr vector_constructor__CPP(std::vector<ValPtr> vals, VectorTypePtr t);
// For patterns, executes p1 += p2.
inline PatternValPtr re_append__CPP(const PatternValPtr& p1, const PatternValPtr& p2)
{
p2->AddTo(p1.get(), false);
return p1;
}
inline PatternValPtr re_append__CPP(const PatternValPtr& p1, const PatternValPtr& p2) {
p2->AddTo(p1.get(), false);
return p1;
}
// Schedules an event to occur at the given absolute time, parameterized
// with the given set of values. A separate function to facilitate avoiding
@ -257,52 +234,41 @@ inline PatternValPtr re_append__CPP(const PatternValPtr& p1, const PatternValPtr
extern ValPtr schedule__CPP(double dt, EventHandlerPtr event, std::vector<ValPtr> args);
// Simple helper functions for supporting absolute value.
inline zeek_uint_t iabs__CPP(zeek_int_t v)
{
return v < 0 ? -v : v;
}
inline zeek_uint_t iabs__CPP(zeek_int_t v) { return v < 0 ? -v : v; }
inline double fabs__CPP(double v)
{
return v < 0.0 ? -v : v;
}
inline double fabs__CPP(double v) { return v < 0.0 ? -v : v; }
// The following operations are provided using functions to support
// error checking/reporting.
inline zeek_int_t idiv__CPP(zeek_int_t v1, zeek_int_t v2)
{
if ( v2 == 0 )
reporter->CPPRuntimeError("division by zero");
return v1 / v2;
}
inline zeek_int_t idiv__CPP(zeek_int_t v1, zeek_int_t v2) {
if ( v2 == 0 )
reporter->CPPRuntimeError("division by zero");
return v1 / v2;
}
inline zeek_int_t imod__CPP(zeek_int_t v1, zeek_int_t v2)
{
if ( v2 == 0 )
reporter->CPPRuntimeError("modulo by zero");
return v1 % v2;
}
inline zeek_int_t imod__CPP(zeek_int_t v1, zeek_int_t v2) {
if ( v2 == 0 )
reporter->CPPRuntimeError("modulo by zero");
return v1 % v2;
}
inline zeek_uint_t udiv__CPP(zeek_uint_t v1, zeek_uint_t v2)
{
if ( v2 == 0 )
reporter->CPPRuntimeError("division by zero");
return v1 / v2;
}
inline zeek_uint_t udiv__CPP(zeek_uint_t v1, zeek_uint_t v2) {
if ( v2 == 0 )
reporter->CPPRuntimeError("division by zero");
return v1 / v2;
}
inline zeek_uint_t umod__CPP(zeek_uint_t v1, zeek_uint_t v2)
{
if ( v2 == 0 )
reporter->CPPRuntimeError("modulo by zero");
return v1 % v2;
}
inline zeek_uint_t umod__CPP(zeek_uint_t v1, zeek_uint_t v2) {
if ( v2 == 0 )
reporter->CPPRuntimeError("modulo by zero");
return v1 % v2;
}
inline double fdiv__CPP(double v1, double v2)
{
if ( v2 == 0.0 )
reporter->CPPRuntimeError("division by zero");
return v1 / v2;
}
inline double fdiv__CPP(double v1, double v2) {
if ( v2 == 0.0 )
reporter->CPPRuntimeError("division by zero");
return v1 / v2;
}
} // namespace zeek::detail
} // namespace zeek
} // namespace detail
} // namespace zeek

View file

@ -5,20 +5,18 @@
#include "zeek/Overflow.h"
#include "zeek/ZeekString.h"
namespace zeek::detail
{
namespace zeek::detail {
using namespace std;
// Helper function for ensuring that two vectors have matching sizes.
static bool check_vec_sizes__CPP(const VectorValPtr& v1, const VectorValPtr& v2)
{
if ( v1->Size() == v2->Size() )
return true;
static bool check_vec_sizes__CPP(const VectorValPtr& v1, const VectorValPtr& v2) {
if ( v1->Size() == v2->Size() )
return true;
reporter->CPPRuntimeError("vector operands are of different sizes");
return false;
}
reporter->CPPRuntimeError("vector operands are of different sizes");
return false;
}
// Helper function that returns a VectorTypePtr apt for use with the
// the given yield type. We don't just use the yield type directly
@ -28,35 +26,28 @@ static bool check_vec_sizes__CPP(const VectorValPtr& v1, const VectorValPtr& v2)
// convert the vector to the high-level representation if needed.
//
// One exception: for booleans ("is_bool" is true), we use those directly.
static VectorTypePtr base_vector_type__CPP(const VectorTypePtr& vt, bool is_bool = false)
{
switch ( vt->Yield()->InternalType() )
{
case TYPE_INTERNAL_INT:
{
auto base_tag = is_bool ? TYPE_BOOL : TYPE_INT;
return make_intrusive<VectorType>(base_type(base_tag));
}
static VectorTypePtr base_vector_type__CPP(const VectorTypePtr& vt, bool is_bool = false) {
switch ( vt->Yield()->InternalType() ) {
case TYPE_INTERNAL_INT: {
auto base_tag = is_bool ? TYPE_BOOL : TYPE_INT;
return make_intrusive<VectorType>(base_type(base_tag));
}
case TYPE_INTERNAL_UNSIGNED:
return make_intrusive<VectorType>(base_type(TYPE_COUNT));
case TYPE_INTERNAL_UNSIGNED: return make_intrusive<VectorType>(base_type(TYPE_COUNT));
case TYPE_INTERNAL_DOUBLE:
return make_intrusive<VectorType>(base_type(TYPE_DOUBLE));
case TYPE_INTERNAL_DOUBLE: return make_intrusive<VectorType>(base_type(TYPE_DOUBLE));
default:
return nullptr;
}
}
default: return nullptr;
}
}
// The kernel used for unary vector operations.
#define VEC_OP1_KERNEL(accessor, type, op) \
for ( unsigned int i = 0; i < v->Size(); ++i ) \
{ \
auto v_i = v->ValAt(i); \
if ( v_i ) \
v_result->Assign(i, make_intrusive<type>(op v_i->accessor())); \
}
#define VEC_OP1_KERNEL(accessor, type, op) \
for ( unsigned int i = 0; i < v->Size(); ++i ) { \
auto v_i = v->ValAt(i); \
if ( v_i ) \
v_result->Assign(i, make_intrusive<type>(op v_i->accessor())); \
}
// A macro (since it's beyond my templating skillz to deal with the
// "op" operator) for unary vector operations, invoking the kernel
@ -64,42 +55,38 @@ static VectorTypePtr base_vector_type__CPP(const VectorTypePtr& vt, bool is_bool
// is an optional kernel to use for vectors whose underlying type
// is "double". It needs to be optional because C++ will (rightfully)
// complain about applying certain C++ unary operations to doubles.
#define VEC_OP1(name, op, double_kernel) \
VectorValPtr vec_op_##name##__CPP(const VectorValPtr& v, const TypePtr& t) \
{ \
auto vt = base_vector_type__CPP(cast_intrusive<VectorType>(t)); \
auto v_result = make_intrusive<VectorVal>(vt); \
\
switch ( vt->Yield()->InternalType() ) \
{ \
case TYPE_INTERNAL_INT: \
{ \
VEC_OP1_KERNEL(AsInt, IntVal, op) \
break; \
} \
\
case TYPE_INTERNAL_UNSIGNED: \
{ \
VEC_OP1_KERNEL(AsCount, CountVal, op) \
break; \
} \
\
double_kernel \
\
default : break; \
} \
\
return v_result; \
}
#define VEC_OP1(name, op, double_kernel) \
VectorValPtr vec_op_##name##__CPP(const VectorValPtr& v, const TypePtr& t) { \
auto vt = base_vector_type__CPP(cast_intrusive<VectorType>(t)); \
auto v_result = make_intrusive<VectorVal>(vt); \
\
switch ( vt->Yield()->InternalType() ) { \
case TYPE_INTERNAL_INT: { \
VEC_OP1_KERNEL(AsInt, IntVal, op) \
break; \
} \
\
case TYPE_INTERNAL_UNSIGNED: { \
VEC_OP1_KERNEL(AsCount, CountVal, op) \
break; \
} \
\
double_kernel \
\
default : break; \
} \
\
return v_result; \
}
// Instantiates a double_kernel for a given operation.
#define VEC_OP1_WITH_DOUBLE(name, op) \
VEC_OP1( \
name, op, case TYPE_INTERNAL_DOUBLE \
: { \
VEC_OP1_KERNEL(AsDouble, DoubleVal, op) \
break; \
})
#define VEC_OP1_WITH_DOUBLE(name, op) \
VEC_OP1( \
name, op, case TYPE_INTERNAL_DOUBLE \
: { \
VEC_OP1_KERNEL(AsDouble, DoubleVal, op) \
break; \
})
// The unary operations supported for vectors.
VEC_OP1_WITH_DOUBLE(pos, +)
@ -109,52 +96,47 @@ VEC_OP1(comp, ~, )
// A kernel for applying a binary operation element-by-element to two
// vectors of a given low-level type.
#define VEC_OP2_KERNEL(accessor, type, op, zero_check) \
for ( unsigned int i = 0; i < v1->Size(); ++i ) \
{ \
auto v1_i = v1->ValAt(i); \
auto v2_i = v2->ValAt(i); \
if ( v1_i && v2_i ) \
{ \
if ( zero_check && v2_i->IsZero() ) \
reporter->CPPRuntimeError("division/modulo by zero"); \
else \
v_result->Assign(i, make_intrusive<type>(v1_i->accessor() op v2_i->accessor())); \
} \
}
#define VEC_OP2_KERNEL(accessor, type, op, zero_check) \
for ( unsigned int i = 0; i < v1->Size(); ++i ) { \
auto v1_i = v1->ValAt(i); \
auto v2_i = v2->ValAt(i); \
if ( v1_i && v2_i ) { \
if ( zero_check && v2_i->IsZero() ) \
reporter->CPPRuntimeError("division/modulo by zero"); \
else \
v_result->Assign(i, make_intrusive<type>(v1_i->accessor() op v2_i->accessor())); \
} \
}
// Analogous to VEC_OP1, instantiates a function for a given binary operation,
// with customimzable kernels for "int" and "double" operations.
// This version is for operations whose result type is the same as the
// operand type.
#define VEC_OP2(name, op, int_kernel, double_kernel, zero_check, is_bool) \
VectorValPtr vec_op_##name##__CPP(const VectorValPtr& v1, const VectorValPtr& v2) \
{ \
if ( ! check_vec_sizes__CPP(v1, v2) ) \
return nullptr; \
\
auto vt = base_vector_type__CPP(v1->GetType<VectorType>(), is_bool); \
auto v_result = make_intrusive<VectorVal>(vt); \
\
switch ( vt->Yield()->InternalType() ) \
{ \
case TYPE_INTERNAL_UNSIGNED: \
{ \
VEC_OP2_KERNEL(AsCount, CountVal, op, zero_check) \
break; \
} \
\
int_kernel double_kernel \
\
default : break; \
} \
\
return v_result; \
}
#define VEC_OP2(name, op, int_kernel, double_kernel, zero_check, is_bool) \
VectorValPtr vec_op_##name##__CPP(const VectorValPtr& v1, const VectorValPtr& v2) { \
if ( ! check_vec_sizes__CPP(v1, v2) ) \
return nullptr; \
\
auto vt = base_vector_type__CPP(v1->GetType<VectorType>(), is_bool); \
auto v_result = make_intrusive<VectorVal>(vt); \
\
switch ( vt->Yield()->InternalType() ) { \
case TYPE_INTERNAL_UNSIGNED: { \
VEC_OP2_KERNEL(AsCount, CountVal, op, zero_check) \
break; \
} \
\
int_kernel double_kernel \
\
default : break; \
} \
\
return v_result; \
}
// Instantiates a regular int_kernel for a binary operation.
#define VEC_OP2_WITH_INT(name, op, double_kernel, zero_check) \
VEC_OP2( \
#define VEC_OP2_WITH_INT(name, op, double_kernel, zero_check) \
VEC_OP2( \
name, op, case TYPE_INTERNAL_INT \
: { \
VEC_OP2_KERNEL(AsInt, IntVal, op, zero_check) \
@ -163,8 +145,8 @@ VEC_OP1(comp, ~, )
double_kernel, zero_check, false)
// Instantiates an int_kernel for boolean operations.
#define VEC_OP2_WITH_BOOL(name, op, zero_check) \
VEC_OP2( \
#define VEC_OP2_WITH_BOOL(name, op, zero_check) \
VEC_OP2( \
name, op, case TYPE_INTERNAL_INT \
: { \
VEC_OP2_KERNEL(AsBool, BoolVal, op, zero_check) \
@ -173,8 +155,8 @@ VEC_OP1(comp, ~, )
, zero_check, true)
// Instantiates a double_kernel for a binary operation.
#define VEC_OP2_WITH_DOUBLE(name, op, zero_check) \
VEC_OP2_WITH_INT( \
#define VEC_OP2_WITH_DOUBLE(name, op, zero_check) \
VEC_OP2_WITH_INT( \
name, op, case TYPE_INTERNAL_DOUBLE \
: { \
VEC_OP2_KERNEL(AsDouble, DoubleVal, op, zero_check) \
@ -198,42 +180,36 @@ VEC_OP2_WITH_INT(rshift, >>, , 0)
// A version of VEC_OP2 that instead supports relational operations, so
// the result type is always vector-of-bool.
#define VEC_REL_OP(name, op) \
VectorValPtr vec_op_##name##__CPP(const VectorValPtr& v1, const VectorValPtr& v2) \
{ \
if ( ! check_vec_sizes__CPP(v1, v2) ) \
return nullptr; \
\
auto vt = v1->GetType<VectorType>(); \
auto res_type = make_intrusive<VectorType>(base_type(TYPE_BOOL)); \
auto v_result = make_intrusive<VectorVal>(res_type); \
\
switch ( vt->Yield()->InternalType() ) \
{ \
case TYPE_INTERNAL_INT: \
{ \
VEC_OP2_KERNEL(AsInt, BoolVal, op, 0) \
break; \
} \
\
case TYPE_INTERNAL_UNSIGNED: \
{ \
VEC_OP2_KERNEL(AsCount, BoolVal, op, 0) \
break; \
} \
\
case TYPE_INTERNAL_DOUBLE: \
{ \
VEC_OP2_KERNEL(AsDouble, BoolVal, op, 0) \
break; \
} \
\
default: \
break; \
} \
\
return v_result; \
}
#define VEC_REL_OP(name, op) \
VectorValPtr vec_op_##name##__CPP(const VectorValPtr& v1, const VectorValPtr& v2) { \
if ( ! check_vec_sizes__CPP(v1, v2) ) \
return nullptr; \
\
auto vt = v1->GetType<VectorType>(); \
auto res_type = make_intrusive<VectorType>(base_type(TYPE_BOOL)); \
auto v_result = make_intrusive<VectorVal>(res_type); \
\
switch ( vt->Yield()->InternalType() ) { \
case TYPE_INTERNAL_INT: { \
VEC_OP2_KERNEL(AsInt, BoolVal, op, 0) \
break; \
} \
\
case TYPE_INTERNAL_UNSIGNED: { \
VEC_OP2_KERNEL(AsCount, BoolVal, op, 0) \
break; \
} \
\
case TYPE_INTERNAL_DOUBLE: { \
VEC_OP2_KERNEL(AsDouble, BoolVal, op, 0) \
break; \
} \
\
default: break; \
} \
\
return v_result; \
}
// The relational operations supported for vectors.
VEC_REL_OP(lt, <)
@ -243,244 +219,203 @@ VEC_REL_OP(ne, !=)
VEC_REL_OP(le, <=)
VEC_REL_OP(ge, >=)
VectorValPtr vec_op_add__CPP(VectorValPtr v, int incr)
{
const auto& yt = v->GetType()->Yield();
auto is_signed = yt->InternalType() == TYPE_INTERNAL_INT;
auto n = v->Size();
VectorValPtr vec_op_add__CPP(VectorValPtr v, int incr) {
const auto& yt = v->GetType()->Yield();
auto is_signed = yt->InternalType() == TYPE_INTERNAL_INT;
auto n = v->Size();
for ( unsigned int i = 0; i < n; ++i )
{
auto v_i = v->ValAt(i);
ValPtr new_v_i;
for ( unsigned int i = 0; i < n; ++i ) {
auto v_i = v->ValAt(i);
ValPtr new_v_i;
if ( is_signed )
new_v_i = val_mgr->Int(v_i->AsInt() + incr);
else
new_v_i = val_mgr->Count(v_i->AsCount() + incr);
if ( is_signed )
new_v_i = val_mgr->Int(v_i->AsInt() + incr);
else
new_v_i = val_mgr->Count(v_i->AsCount() + incr);
v->Assign(i, new_v_i);
}
v->Assign(i, new_v_i);
}
return v;
}
return v;
}
VectorValPtr vec_op_sub__CPP(VectorValPtr v, int i)
{
return vec_op_add__CPP(std::move(v), -i);
}
VectorValPtr vec_op_sub__CPP(VectorValPtr v, int i) { return vec_op_add__CPP(std::move(v), -i); }
// This function provides the core functionality. The arguments
// are applied as though they appeared left-to-right in a statement
// "s1 + v2 + v3 + s4". For any invocation, v2 will always be
// non-nil, and one-and-only-one of s1, v3, or s4 will be non-nil.
static VectorValPtr str_vec_op_str_vec_add__CPP(const StringValPtr& s1, const VectorValPtr& v2,
const VectorValPtr& v3, const StringValPtr& s4)
{
auto vt = v2->GetType<VectorType>();
auto v_result = make_intrusive<VectorVal>(vt);
auto n = v2->Size();
static VectorValPtr str_vec_op_str_vec_add__CPP(const StringValPtr& s1, const VectorValPtr& v2, const VectorValPtr& v3,
const StringValPtr& s4) {
auto vt = v2->GetType<VectorType>();
auto v_result = make_intrusive<VectorVal>(vt);
auto n = v2->Size();
for ( unsigned int i = 0; i < n; ++i )
{
vector<const String*> strings;
for ( unsigned int i = 0; i < n; ++i ) {
vector<const String*> strings;
auto v2_i = v2->ValAt(i);
if ( ! v2_i )
continue;
auto v2_i = v2->ValAt(i);
if ( ! v2_i )
continue;
auto s2 = v2_i->AsString();
const String* s3 = nullptr;
auto s2 = v2_i->AsString();
const String* s3 = nullptr;
if ( v3 )
{
auto v3_i = v3->ValAt(i);
if ( ! v3_i )
continue;
s3 = v3_i->AsString();
}
if ( v3 ) {
auto v3_i = v3->ValAt(i);
if ( ! v3_i )
continue;
s3 = v3_i->AsString();
}
if ( s1 )
strings.push_back(s1->AsString());
strings.push_back(s2);
if ( s3 )
strings.push_back(s3);
if ( s4 )
strings.push_back(s4->AsString());
if ( s1 )
strings.push_back(s1->AsString());
strings.push_back(s2);
if ( s3 )
strings.push_back(s3);
if ( s4 )
strings.push_back(s4->AsString());
auto res = make_intrusive<StringVal>(concatenate(strings));
v_result->Assign(i, res);
}
auto res = make_intrusive<StringVal>(concatenate(strings));
v_result->Assign(i, res);
}
return v_result;
}
return v_result;
}
VectorValPtr str_vec_op_add__CPP(const VectorValPtr& v1, const VectorValPtr& v2)
{
return str_vec_op_str_vec_add__CPP(nullptr, v1, v2, nullptr);
}
VectorValPtr str_vec_op_add__CPP(const VectorValPtr& v1, const VectorValPtr& v2) {
return str_vec_op_str_vec_add__CPP(nullptr, v1, v2, nullptr);
}
VectorValPtr str_vec_op_add__CPP(const VectorValPtr& v1, const StringValPtr& s2)
{
return str_vec_op_str_vec_add__CPP(nullptr, v1, nullptr, s2);
}
VectorValPtr str_vec_op_add__CPP(const VectorValPtr& v1, const StringValPtr& s2) {
return str_vec_op_str_vec_add__CPP(nullptr, v1, nullptr, s2);
}
VectorValPtr str_vec_op_add__CPP(const StringValPtr& s1, const VectorValPtr& v2)
{
return str_vec_op_str_vec_add__CPP(s1, v2, nullptr, nullptr);
}
VectorValPtr str_vec_op_add__CPP(const StringValPtr& s1, const VectorValPtr& v2) {
return str_vec_op_str_vec_add__CPP(s1, v2, nullptr, nullptr);
}
// Kernel for element-by-element string relationals. "rel1" and "rel2"
// codify which relational (</<=/==/!=/>=/>) we're aiming to support,
// in terms of how a Bstr_cmp() comparison should be assessed.
static VectorValPtr str_vec_op_kernel__CPP(const VectorValPtr& v1, const VectorValPtr& v2, int rel1,
int rel2)
{
auto res_type = make_intrusive<VectorType>(base_type(TYPE_BOOL));
auto v_result = make_intrusive<VectorVal>(res_type);
auto n = v1->Size();
static VectorValPtr str_vec_op_kernel__CPP(const VectorValPtr& v1, const VectorValPtr& v2, int rel1, int rel2) {
auto res_type = make_intrusive<VectorType>(base_type(TYPE_BOOL));
auto v_result = make_intrusive<VectorVal>(res_type);
auto n = v1->Size();
for ( unsigned int i = 0; i < n; ++i )
{
auto v1_i = v1->ValAt(i);
auto v2_i = v2->ValAt(i);
if ( ! v1_i || ! v2_i )
continue;
for ( unsigned int i = 0; i < n; ++i ) {
auto v1_i = v1->ValAt(i);
auto v2_i = v2->ValAt(i);
if ( ! v1_i || ! v2_i )
continue;
auto s1 = v1_i->AsString();
auto s2 = v2_i->AsString();
auto s1 = v1_i->AsString();
auto s2 = v2_i->AsString();
auto cmp = Bstr_cmp(s1, s2);
auto rel = (cmp == rel1) || (cmp == rel2);
auto cmp = Bstr_cmp(s1, s2);
auto rel = (cmp == rel1) || (cmp == rel2);
v_result->Assign(i, val_mgr->Bool(rel));
}
v_result->Assign(i, val_mgr->Bool(rel));
}
return v_result;
}
return v_result;
}
VectorValPtr str_vec_op_lt__CPP(const VectorValPtr& v1, const VectorValPtr& v2)
{
return str_vec_op_kernel__CPP(v1, v2, -1, -1);
}
VectorValPtr str_vec_op_le__CPP(const VectorValPtr& v1, const VectorValPtr& v2)
{
return str_vec_op_kernel__CPP(v1, v2, -1, 0);
}
VectorValPtr str_vec_op_eq__CPP(const VectorValPtr& v1, const VectorValPtr& v2)
{
return str_vec_op_kernel__CPP(v1, v2, 0, 0);
}
VectorValPtr str_vec_op_ne__CPP(const VectorValPtr& v1, const VectorValPtr& v2)
{
return str_vec_op_kernel__CPP(v1, v2, -1, 1);
}
VectorValPtr str_vec_op_gt__CPP(const VectorValPtr& v1, const VectorValPtr& v2)
{
return str_vec_op_kernel__CPP(v1, v2, 1, 1);
}
VectorValPtr str_vec_op_ge__CPP(const VectorValPtr& v1, const VectorValPtr& v2)
{
return str_vec_op_kernel__CPP(v1, v2, 0, 1);
}
VectorValPtr str_vec_op_lt__CPP(const VectorValPtr& v1, const VectorValPtr& v2) {
return str_vec_op_kernel__CPP(v1, v2, -1, -1);
}
VectorValPtr str_vec_op_le__CPP(const VectorValPtr& v1, const VectorValPtr& v2) {
return str_vec_op_kernel__CPP(v1, v2, -1, 0);
}
VectorValPtr str_vec_op_eq__CPP(const VectorValPtr& v1, const VectorValPtr& v2) {
return str_vec_op_kernel__CPP(v1, v2, 0, 0);
}
VectorValPtr str_vec_op_ne__CPP(const VectorValPtr& v1, const VectorValPtr& v2) {
return str_vec_op_kernel__CPP(v1, v2, -1, 1);
}
VectorValPtr str_vec_op_gt__CPP(const VectorValPtr& v1, const VectorValPtr& v2) {
return str_vec_op_kernel__CPP(v1, v2, 1, 1);
}
VectorValPtr str_vec_op_ge__CPP(const VectorValPtr& v1, const VectorValPtr& v2) {
return str_vec_op_kernel__CPP(v1, v2, 0, 1);
}
VectorValPtr vector_select__CPP(const VectorValPtr& v1, VectorValPtr v2, VectorValPtr v3)
{
auto vt = v2->GetType<VectorType>();
auto v_result = make_intrusive<VectorVal>(vt);
VectorValPtr vector_select__CPP(const VectorValPtr& v1, VectorValPtr v2, VectorValPtr v3) {
auto vt = v2->GetType<VectorType>();
auto v_result = make_intrusive<VectorVal>(vt);
if ( ! check_vec_sizes__CPP(v1, v2) || ! check_vec_sizes__CPP(v1, v3) )
return nullptr;
if ( ! check_vec_sizes__CPP(v1, v2) || ! check_vec_sizes__CPP(v1, v3) )
return nullptr;
auto n = v1->Size();
auto n = v1->Size();
for ( unsigned int i = 0; i < n; ++i )
{
auto vr_i = v1->BoolAt(i) ? v2->ValAt(i) : v3->ValAt(i);
v_result->Assign(i, std::move(vr_i));
}
for ( unsigned int i = 0; i < n; ++i ) {
auto vr_i = v1->BoolAt(i) ? v2->ValAt(i) : v3->ValAt(i);
v_result->Assign(i, std::move(vr_i));
}
return v_result;
}
return v_result;
}
VectorValPtr vector_coerce_to__CPP(const VectorValPtr& v, const TypePtr& targ)
{
auto res_t = cast_intrusive<VectorType>(targ);
auto v_result = make_intrusive<VectorVal>(std::move(res_t));
auto n = v->Size();
auto yt = targ->Yield();
auto ytag = yt->Tag();
VectorValPtr vector_coerce_to__CPP(const VectorValPtr& v, const TypePtr& targ) {
auto res_t = cast_intrusive<VectorType>(targ);
auto v_result = make_intrusive<VectorVal>(std::move(res_t));
auto n = v->Size();
auto yt = targ->Yield();
auto ytag = yt->Tag();
for ( unsigned int i = 0; i < n; ++i )
{
ValPtr v_i = v->ValAt(i);
if ( ! v_i )
continue;
for ( unsigned int i = 0; i < n; ++i ) {
ValPtr v_i = v->ValAt(i);
if ( ! v_i )
continue;
// We compute these for each element to cover the case where
// the coerced vector is of type "any".
auto& t_i = v_i->GetType();
auto it = t_i->InternalType();
// We compute these for each element to cover the case where
// the coerced vector is of type "any".
auto& t_i = v_i->GetType();
auto it = t_i->InternalType();
ValPtr r_i;
switch ( ytag )
{
case TYPE_BOOL:
r_i = val_mgr->Bool(v_i->CoerceToInt() != 0);
break;
ValPtr r_i;
switch ( ytag ) {
case TYPE_BOOL: r_i = val_mgr->Bool(v_i->CoerceToInt() != 0); break;
case TYPE_INT:
if ( (it == TYPE_INTERNAL_UNSIGNED || it == TYPE_INTERNAL_DOUBLE) &&
would_overflow(t_i.get(), yt.get(), v_i.get()) )
reporter->CPPRuntimeError(
"overflow promoting from unsigned/double to signed arithmetic value");
else
r_i = val_mgr->Int(v_i->CoerceToInt());
break;
case TYPE_INT:
if ( (it == TYPE_INTERNAL_UNSIGNED || it == TYPE_INTERNAL_DOUBLE) &&
would_overflow(t_i.get(), yt.get(), v_i.get()) )
reporter->CPPRuntimeError("overflow promoting from unsigned/double to signed arithmetic value");
else
r_i = val_mgr->Int(v_i->CoerceToInt());
break;
case TYPE_COUNT:
if ( (it == TYPE_INTERNAL_INT || it == TYPE_INTERNAL_DOUBLE) &&
would_overflow(t_i.get(), yt.get(), v_i.get()) )
reporter->CPPRuntimeError(
"overflow promoting from signed/double to signed arithmetic value");
else
r_i = val_mgr->Count(v_i->CoerceToUnsigned());
break;
case TYPE_COUNT:
if ( (it == TYPE_INTERNAL_INT || it == TYPE_INTERNAL_DOUBLE) &&
would_overflow(t_i.get(), yt.get(), v_i.get()) )
reporter->CPPRuntimeError("overflow promoting from signed/double to signed arithmetic value");
else
r_i = val_mgr->Count(v_i->CoerceToUnsigned());
break;
case TYPE_ENUM:
r_i = yt->AsEnumType()->GetEnumVal(v_i->CoerceToInt());
break;
case TYPE_ENUM: r_i = yt->AsEnumType()->GetEnumVal(v_i->CoerceToInt()); break;
case TYPE_PORT:
r_i = make_intrusive<PortVal>(v_i->CoerceToUnsigned());
break;
case TYPE_PORT: r_i = make_intrusive<PortVal>(v_i->CoerceToUnsigned()); break;
case TYPE_DOUBLE:
r_i = make_intrusive<DoubleVal>(v_i->CoerceToDouble());
break;
case TYPE_DOUBLE: r_i = make_intrusive<DoubleVal>(v_i->CoerceToDouble()); break;
case TYPE_INTERVAL:
r_i = make_intrusive<IntervalVal>(v_i->CoerceToDouble());
break;
case TYPE_INTERVAL: r_i = make_intrusive<IntervalVal>(v_i->CoerceToDouble()); break;
case TYPE_TIME:
r_i = make_intrusive<TimeVal>(v_i->CoerceToDouble());
break;
case TYPE_TIME: r_i = make_intrusive<TimeVal>(v_i->CoerceToDouble()); break;
default:
reporter->InternalError("bad vector type in vector_coerce_to__CPP");
}
default: reporter->InternalError("bad vector type in vector_coerce_to__CPP");
}
v_result->Assign(i, std::move(r_i));
}
v_result->Assign(i, std::move(r_i));
}
return v_result;
}
return v_result;
}
VectorValPtr vec_scalar_mixed_with_vector()
{
reporter->CPPRuntimeError("vector-mixed-with-scalar operations not supported");
return nullptr;
}
VectorValPtr vec_scalar_mixed_with_vector() {
reporter->CPPRuntimeError("vector-mixed-with-scalar operations not supported");
return nullptr;
}
} // namespace zeek::detail
} // namespace zeek::detail

View file

@ -10,24 +10,21 @@
#include "zeek/Val.h"
namespace zeek::detail
{
namespace zeek::detail {
// Appends v2 to the vector v1. A separate function because of the
// need to support assignment cascades.
inline ValPtr vector_append__CPP(VectorValPtr v1, const ValPtr& v2)
{
v1->Assign(v1->Size(), v2);
return v1;
}
inline ValPtr vector_append__CPP(VectorValPtr v1, const ValPtr& v2) {
v1->Assign(v1->Size(), v2);
return v1;
}
// Appends vector v2 to the vector v1.
inline ValPtr vector_vec_append__CPP(VectorValPtr v1, const VectorValPtr& v2)
{
if ( ! v2->AddTo(v1.get(), false) )
reporter->CPPRuntimeError("incompatible vector element assignment");
return v1;
}
inline ValPtr vector_vec_append__CPP(VectorValPtr v1, const VectorValPtr& v2) {
if ( ! v2->AddTo(v1.get(), false) )
reporter->CPPRuntimeError("incompatible vector element assignment");
return v1;
}
// Unary vector operations.
extern VectorValPtr vec_op_pos__CPP(const VectorValPtr& v, const TypePtr& t);
@ -94,4 +91,4 @@ extern VectorValPtr vec_coerce_to_double__CPP(const VectorValPtr& v, TypePtr tar
// that mix vector and scalar arguments.
extern VectorValPtr vec_scalar_mixed_with_vector();
} // namespace zeek::detail
} // namespace zeek::detail

File diff suppressed because it is too large Load diff

View file

@ -6,57 +6,55 @@
#include "zeek/script_opt/CPP/Util.h"
#include "zeek/script_opt/ProfileFunc.h"
namespace zeek::detail
{
namespace zeek::detail {
using namespace std;
template <class T> void CPPTracker<T>::AddKey(IntrusivePtr<T> key, p_hash_type h)
{
if ( HasKey(key) )
return;
template<class T>
void CPPTracker<T>::AddKey(IntrusivePtr<T> key, p_hash_type h) {
if ( HasKey(key) )
return;
if ( map2.count(h) == 0 )
{
auto index = keys.size();
keys.push_back(key);
if ( map2.count(h) == 0 ) {
auto index = keys.size();
keys.push_back(key);
map2[h] = index;
reps[h] = key.get();
}
map2[h] = index;
reps[h] = key.get();
}
ASSERT(h != 0); // check for hash botches
ASSERT(h != 0); // check for hash botches
map[key.get()] = h;
}
map[key.get()] = h;
}
template <class T> string CPPTracker<T>::KeyName(const T* key)
{
ASSERT(HasKey(key));
template<class T>
string CPPTracker<T>::KeyName(const T* key) {
ASSERT(HasKey(key));
auto hash = map[key];
ASSERT(hash != 0);
auto hash = map[key];
ASSERT(hash != 0);
auto rep = reps[hash];
auto gi = gi_s.find(rep);
if ( gi != gi_s.end() )
return gi->second->Name();
auto rep = reps[hash];
auto gi = gi_s.find(rep);
if ( gi != gi_s.end() )
return gi->second->Name();
auto index = map2[hash];
string ind = Fmt(index);
string full_name;
auto index = map2[hash];
string ind = Fmt(index);
string full_name;
if ( single_global )
full_name = base_name + "__CPP[" + ind + "]";
else
full_name = base_name + "_" + ind + "__CPP";
if ( single_global )
full_name = base_name + "__CPP[" + ind + "]";
else
full_name = base_name + "_" + ind + "__CPP";
return full_name;
}
return full_name;
}
// Instantiate the templates we'll need.
template class CPPTracker<Type>;
template class CPPTracker<Attributes>;
template class CPPTracker<Expr>;
} // zeek::detail
} // namespace zeek::detail

View file

@ -15,69 +15,64 @@
#include "zeek/script_opt/CPP/InitsInfo.h"
namespace zeek::detail
{
namespace zeek::detail {
// T is a type that has an IntrusivePtr instantiation.
template <class T> class CPPTracker
{
template<class T>
class CPPTracker {
public:
// The base name is used to construct key names. "single_global",
// if true, specifies that the names should be constructed as
// indexes into a single global, rather than as distinct globals.
CPPTracker(const char* _base_name, bool _single_global)
: base_name(_base_name), single_global(_single_global)
{
}
// The base name is used to construct key names. "single_global",
// if true, specifies that the names should be constructed as
// indexes into a single global, rather than as distinct globals.
CPPTracker(const char* _base_name, bool _single_global) : base_name(_base_name), single_global(_single_global) {}
// True if the given key has already been entered.
bool HasKey(const T* key) const { return map.count(key) > 0; }
bool HasKey(IntrusivePtr<T> key) const { return HasKey(key.get()); }
// True if the given key has already been entered.
bool HasKey(const T* key) const { return map.count(key) > 0; }
bool HasKey(IntrusivePtr<T> key) const { return HasKey(key.get()); }
// Only adds the key if it's not already present.
void AddKey(IntrusivePtr<T> key, p_hash_type h);
// Only adds the key if it's not already present.
void AddKey(IntrusivePtr<T> key, p_hash_type h);
void AddInitInfo(const T* rep, std::shared_ptr<CPP_InitInfo> gi) { gi_s[rep] = std::move(gi); }
void AddInitInfo(const T* rep, std::shared_ptr<CPP_InitInfo> gi) { gi_s[rep] = std::move(gi); }
// Returns the (C++ variable) name associated with the given key.
std::string KeyName(const T* key);
std::string KeyName(IntrusivePtr<T> key) { return KeyName(key.get()); }
// Returns the (C++ variable) name associated with the given key.
std::string KeyName(const T* key);
std::string KeyName(IntrusivePtr<T> key) { return KeyName(key.get()); }
// Returns all of the distinct keys entered into the tracker.
// A key is "distinct" if it's a representative.
const std::vector<IntrusivePtr<T>>& DistinctKeys() const { return keys; }
// Returns all of the distinct keys entered into the tracker.
// A key is "distinct" if it's a representative.
const std::vector<IntrusivePtr<T>>& DistinctKeys() const { return keys; }
// For a given key, get its representative.
const T* GetRep(const T* key)
{
ASSERT(HasKey(key));
return reps[map[key]];
}
const T* GetRep(IntrusivePtr<T> key) { return GetRep(key.get()); }
// For a given key, get its representative.
const T* GetRep(const T* key) {
ASSERT(HasKey(key));
return reps[map[key]];
}
const T* GetRep(IntrusivePtr<T> key) { return GetRep(key.get()); }
private:
// Maps keys to internal representations (i.e., hashes).
std::unordered_map<const T*, p_hash_type> map;
// Maps keys to internal representations (i.e., hashes).
std::unordered_map<const T*, p_hash_type> map;
std::unordered_map<const T*, std::shared_ptr<CPP_InitInfo>> gi_s;
std::unordered_map<const T*, std::shared_ptr<CPP_InitInfo>> gi_s;
// Maps internal representations to distinct values.
std::unordered_map<p_hash_type, int> map2;
// Maps internal representations to distinct values.
std::unordered_map<p_hash_type, int> map2;
// Tracks the set of distinct keys, to facilitate iterating over them.
// Each such key also has an entry in map2.
std::vector<IntrusivePtr<T>> keys;
// Tracks the set of distinct keys, to facilitate iterating over them.
// Each such key also has an entry in map2.
std::vector<IntrusivePtr<T>> keys;
// Maps internal representations back to keys.
std::unordered_map<p_hash_type, const T*> reps;
// Maps internal representations back to keys.
std::unordered_map<p_hash_type, const T*> reps;
// Used to construct key names.
std::string base_name;
// Used to construct key names.
std::string base_name;
// Whether to base the names out of a single global, or distinct
// globals.
bool single_global;
};
// Whether to base the names out of a single global, or distinct
// globals.
bool single_global;
};
} // zeek::detail
} // namespace zeek::detail

View file

@ -2,460 +2,296 @@
#include "zeek/script_opt/CPP/Compile.h"
namespace zeek::detail
{
namespace zeek::detail {
using namespace std;
bool CPPCompile::IsNativeType(const TypePtr& t) const
{
if ( ! t )
return true;
bool CPPCompile::IsNativeType(const TypePtr& t) const {
if ( ! t )
return true;
switch ( t->Tag() )
{
case TYPE_BOOL:
case TYPE_COUNT:
case TYPE_DOUBLE:
case TYPE_ENUM:
case TYPE_INT:
case TYPE_INTERVAL:
case TYPE_PORT:
case TYPE_TIME:
case TYPE_VOID:
return true;
switch ( t->Tag() ) {
case TYPE_BOOL:
case TYPE_COUNT:
case TYPE_DOUBLE:
case TYPE_ENUM:
case TYPE_INT:
case TYPE_INTERVAL:
case TYPE_PORT:
case TYPE_TIME:
case TYPE_VOID: return true;
case TYPE_ADDR:
case TYPE_ANY:
case TYPE_FILE:
case TYPE_FUNC:
case TYPE_OPAQUE:
case TYPE_PATTERN:
case TYPE_RECORD:
case TYPE_STRING:
case TYPE_SUBNET:
case TYPE_TABLE:
case TYPE_TYPE:
case TYPE_VECTOR:
return false;
case TYPE_ADDR:
case TYPE_ANY:
case TYPE_FILE:
case TYPE_FUNC:
case TYPE_OPAQUE:
case TYPE_PATTERN:
case TYPE_RECORD:
case TYPE_STRING:
case TYPE_SUBNET:
case TYPE_TABLE:
case TYPE_TYPE:
case TYPE_VECTOR: return false;
case TYPE_LIST:
// These occur when initializing tables.
return false;
case TYPE_LIST:
// These occur when initializing tables.
return false;
default:
reporter->InternalError("bad type in CPPCompile::IsNativeType");
return false;
}
}
default: reporter->InternalError("bad type in CPPCompile::IsNativeType"); return false;
}
}
string CPPCompile::NativeToGT(const string& expr, const TypePtr& t, GenType gt)
{
if ( gt == GEN_DONT_CARE )
return expr;
string CPPCompile::NativeToGT(const string& expr, const TypePtr& t, GenType gt) {
if ( gt == GEN_DONT_CARE )
return expr;
if ( gt == GEN_NATIVE || ! IsNativeType(t) )
return expr;
if ( gt == GEN_NATIVE || ! IsNativeType(t) )
return expr;
// Need to convert to a ValPtr.
switch ( t->Tag() )
{
case TYPE_VOID:
return expr;
// Need to convert to a ValPtr.
switch ( t->Tag() ) {
case TYPE_VOID: return expr;
case TYPE_BOOL:
return string("val_mgr->Bool(") + expr + ")";
case TYPE_BOOL: return string("val_mgr->Bool(") + expr + ")";
case TYPE_INT:
return string("val_mgr->Int(") + expr + ")";
case TYPE_INT: return string("val_mgr->Int(") + expr + ")";
case TYPE_COUNT:
return string("val_mgr->Count(") + expr + ")";
case TYPE_COUNT: return string("val_mgr->Count(") + expr + ")";
case TYPE_PORT:
return string("val_mgr->Port(") + expr + ")";
case TYPE_PORT: return string("val_mgr->Port(") + expr + ")";
case TYPE_ENUM:
return string("make_enum__CPP(") + GenTypeName(t) + ", " + expr + ")";
case TYPE_ENUM: return string("make_enum__CPP(") + GenTypeName(t) + ", " + expr + ")";
default:
return string("make_intrusive<") + IntrusiveVal(t) + ">(" + expr + ")";
}
}
default: return string("make_intrusive<") + IntrusiveVal(t) + ">(" + expr + ")";
}
}
string CPPCompile::GenericValPtrToGT(const string& expr, const TypePtr& t, GenType gt)
{
if ( gt != GEN_VAL_PTR && IsNativeType(t) )
return expr + NativeAccessor(t);
else
return string("cast_intrusive<") + IntrusiveVal(t) + ">(" + expr + ")";
}
string CPPCompile::GenericValPtrToGT(const string& expr, const TypePtr& t, GenType gt) {
if ( gt != GEN_VAL_PTR && IsNativeType(t) )
return expr + NativeAccessor(t);
else
return string("cast_intrusive<") + IntrusiveVal(t) + ">(" + expr + ")";
}
string CPPCompile::GenTypeName(const Type* t)
{
ASSERT(processed_types.count(TypeRep(t)) > 0);
return types.KeyName(TypeRep(t));
}
string CPPCompile::GenTypeName(const Type* t) {
ASSERT(processed_types.count(TypeRep(t)) > 0);
return types.KeyName(TypeRep(t));
}
const char* CPPCompile::TypeTagName(TypeTag tag)
{
switch ( tag )
{
case TYPE_ADDR:
return "TYPE_ADDR";
case TYPE_ANY:
return "TYPE_ANY";
case TYPE_BOOL:
return "TYPE_BOOL";
case TYPE_COUNT:
return "TYPE_COUNT";
case TYPE_DOUBLE:
return "TYPE_DOUBLE";
case TYPE_ENUM:
return "TYPE_ENUM";
case TYPE_ERROR:
return "TYPE_ERROR";
case TYPE_FILE:
return "TYPE_FILE";
case TYPE_FUNC:
return "TYPE_FUNC";
case TYPE_INT:
return "TYPE_INT";
case TYPE_INTERVAL:
return "TYPE_INTERVAL";
case TYPE_LIST:
return "TYPE_LIST";
case TYPE_OPAQUE:
return "TYPE_OPAQUE";
case TYPE_PATTERN:
return "TYPE_PATTERN";
case TYPE_PORT:
return "TYPE_PORT";
case TYPE_RECORD:
return "TYPE_RECORD";
case TYPE_STRING:
return "TYPE_STRING";
case TYPE_SUBNET:
return "TYPE_SUBNET";
case TYPE_TABLE:
return "TYPE_TABLE";
case TYPE_TIME:
return "TYPE_TIME";
case TYPE_TYPE:
return "TYPE_TYPE";
case TYPE_VECTOR:
return "TYPE_VECTOR";
case TYPE_VOID:
return "TYPE_VOID";
const char* CPPCompile::TypeTagName(TypeTag tag) {
switch ( tag ) {
case TYPE_ADDR: return "TYPE_ADDR";
case TYPE_ANY: return "TYPE_ANY";
case TYPE_BOOL: return "TYPE_BOOL";
case TYPE_COUNT: return "TYPE_COUNT";
case TYPE_DOUBLE: return "TYPE_DOUBLE";
case TYPE_ENUM: return "TYPE_ENUM";
case TYPE_ERROR: return "TYPE_ERROR";
case TYPE_FILE: return "TYPE_FILE";
case TYPE_FUNC: return "TYPE_FUNC";
case TYPE_INT: return "TYPE_INT";
case TYPE_INTERVAL: return "TYPE_INTERVAL";
case TYPE_LIST: return "TYPE_LIST";
case TYPE_OPAQUE: return "TYPE_OPAQUE";
case TYPE_PATTERN: return "TYPE_PATTERN";
case TYPE_PORT: return "TYPE_PORT";
case TYPE_RECORD: return "TYPE_RECORD";
case TYPE_STRING: return "TYPE_STRING";
case TYPE_SUBNET: return "TYPE_SUBNET";
case TYPE_TABLE: return "TYPE_TABLE";
case TYPE_TIME: return "TYPE_TIME";
case TYPE_TYPE: return "TYPE_TYPE";
case TYPE_VECTOR: return "TYPE_VECTOR";
case TYPE_VOID: return "TYPE_VOID";
default:
reporter->InternalError("bad type in CPPCompile::TypeTagName");
return nullptr;
}
}
default: reporter->InternalError("bad type in CPPCompile::TypeTagName"); return nullptr;
}
}
const char* CPPCompile::TypeName(const TypePtr& t)
{
switch ( t->Tag() )
{
case TYPE_BOOL:
return "bool";
case TYPE_COUNT:
return "zeek_uint_t";
case TYPE_DOUBLE:
return "double";
case TYPE_ENUM:
return "int";
case TYPE_INT:
return "zeek_int_t";
case TYPE_INTERVAL:
return "double";
case TYPE_PORT:
return "zeek_uint_t";
case TYPE_TIME:
return "double";
case TYPE_VOID:
return "void";
const char* CPPCompile::TypeName(const TypePtr& t) {
switch ( t->Tag() ) {
case TYPE_BOOL: return "bool";
case TYPE_COUNT: return "zeek_uint_t";
case TYPE_DOUBLE: return "double";
case TYPE_ENUM: return "int";
case TYPE_INT: return "zeek_int_t";
case TYPE_INTERVAL: return "double";
case TYPE_PORT: return "zeek_uint_t";
case TYPE_TIME: return "double";
case TYPE_VOID: return "void";
case TYPE_ADDR:
return "AddrVal";
case TYPE_ANY:
return "Val";
case TYPE_FILE:
return "FileVal";
case TYPE_FUNC:
return "FuncVal";
case TYPE_OPAQUE:
return "OpaqueVal";
case TYPE_PATTERN:
return "PatternVal";
case TYPE_RECORD:
return "RecordVal";
case TYPE_STRING:
return "StringVal";
case TYPE_SUBNET:
return "SubNetVal";
case TYPE_TABLE:
return "TableVal";
case TYPE_TYPE:
return "TypeVal";
case TYPE_VECTOR:
return "VectorVal";
case TYPE_ADDR: return "AddrVal";
case TYPE_ANY: return "Val";
case TYPE_FILE: return "FileVal";
case TYPE_FUNC: return "FuncVal";
case TYPE_OPAQUE: return "OpaqueVal";
case TYPE_PATTERN: return "PatternVal";
case TYPE_RECORD: return "RecordVal";
case TYPE_STRING: return "StringVal";
case TYPE_SUBNET: return "SubNetVal";
case TYPE_TABLE: return "TableVal";
case TYPE_TYPE: return "TypeVal";
case TYPE_VECTOR: return "VectorVal";
default:
reporter->InternalError("bad type in CPPCompile::TypeName");
return nullptr;
}
}
default: reporter->InternalError("bad type in CPPCompile::TypeName"); return nullptr;
}
}
const char* CPPCompile::FullTypeName(const TypePtr& t)
{
if ( ! t )
return "void";
const char* CPPCompile::FullTypeName(const TypePtr& t) {
if ( ! t )
return "void";
switch ( t->Tag() )
{
case TYPE_BOOL:
case TYPE_COUNT:
case TYPE_DOUBLE:
case TYPE_ENUM:
case TYPE_INT:
case TYPE_INTERVAL:
case TYPE_PORT:
case TYPE_TIME:
case TYPE_VOID:
return TypeName(t);
switch ( t->Tag() ) {
case TYPE_BOOL:
case TYPE_COUNT:
case TYPE_DOUBLE:
case TYPE_ENUM:
case TYPE_INT:
case TYPE_INTERVAL:
case TYPE_PORT:
case TYPE_TIME:
case TYPE_VOID: return TypeName(t);
case TYPE_ADDR:
return "AddrValPtr";
case TYPE_ANY:
return "ValPtr";
case TYPE_FILE:
return "FileValPtr";
case TYPE_FUNC:
return "FuncValPtr";
case TYPE_OPAQUE:
return "OpaqueValPtr";
case TYPE_PATTERN:
return "PatternValPtr";
case TYPE_RECORD:
return "RecordValPtr";
case TYPE_STRING:
return "StringValPtr";
case TYPE_SUBNET:
return "SubNetValPtr";
case TYPE_TABLE:
return "TableValPtr";
case TYPE_TYPE:
return "TypeValPtr";
case TYPE_VECTOR:
return "VectorValPtr";
case TYPE_ADDR: return "AddrValPtr";
case TYPE_ANY: return "ValPtr";
case TYPE_FILE: return "FileValPtr";
case TYPE_FUNC: return "FuncValPtr";
case TYPE_OPAQUE: return "OpaqueValPtr";
case TYPE_PATTERN: return "PatternValPtr";
case TYPE_RECORD: return "RecordValPtr";
case TYPE_STRING: return "StringValPtr";
case TYPE_SUBNET: return "SubNetValPtr";
case TYPE_TABLE: return "TableValPtr";
case TYPE_TYPE: return "TypeValPtr";
case TYPE_VECTOR: return "VectorValPtr";
default:
reporter->InternalError("bad type in CPPCompile::FullTypeName");
return nullptr;
}
}
default: reporter->InternalError("bad type in CPPCompile::FullTypeName"); return nullptr;
}
}
const char* CPPCompile::TypeType(const TypePtr& t)
{
switch ( t->Tag() )
{
case TYPE_RECORD:
return "RecordType";
case TYPE_TABLE:
return "TableType";
case TYPE_VECTOR:
return "VectorType";
const char* CPPCompile::TypeType(const TypePtr& t) {
switch ( t->Tag() ) {
case TYPE_RECORD: return "RecordType";
case TYPE_TABLE: return "TableType";
case TYPE_VECTOR: return "VectorType";
default:
reporter->InternalError("bad type in CPPCompile::TypeType");
return nullptr;
}
}
default: reporter->InternalError("bad type in CPPCompile::TypeType"); return nullptr;
}
}
shared_ptr<CPP_InitInfo> CPPCompile::RegisterType(const TypePtr& tp)
{
auto t = TypeRep(tp);
shared_ptr<CPP_InitInfo> CPPCompile::RegisterType(const TypePtr& tp) {
auto t = TypeRep(tp);
auto pt = processed_types.find(t);
if ( pt != processed_types.end() )
return pt->second;
auto pt = processed_types.find(t);
if ( pt != processed_types.end() )
return pt->second;
processed_types[t] = nullptr;
processed_types[t] = nullptr;
shared_ptr<CPP_InitInfo> gi;
shared_ptr<CPP_InitInfo> gi;
switch ( t->Tag() )
{
case TYPE_ADDR:
case TYPE_ANY:
case TYPE_BOOL:
case TYPE_COUNT:
case TYPE_DOUBLE:
case TYPE_ERROR:
case TYPE_INT:
case TYPE_INTERVAL:
case TYPE_PATTERN:
case TYPE_PORT:
case TYPE_STRING:
case TYPE_TIME:
case TYPE_VOID:
case TYPE_SUBNET:
case TYPE_FILE:
gi = make_shared<BaseTypeInfo>(this, tp);
break;
switch ( t->Tag() ) {
case TYPE_ADDR:
case TYPE_ANY:
case TYPE_BOOL:
case TYPE_COUNT:
case TYPE_DOUBLE:
case TYPE_ERROR:
case TYPE_INT:
case TYPE_INTERVAL:
case TYPE_PATTERN:
case TYPE_PORT:
case TYPE_STRING:
case TYPE_TIME:
case TYPE_VOID:
case TYPE_SUBNET:
case TYPE_FILE: gi = make_shared<BaseTypeInfo>(this, tp); break;
case TYPE_ENUM:
gi = make_shared<EnumTypeInfo>(this, tp);
break;
case TYPE_ENUM: gi = make_shared<EnumTypeInfo>(this, tp); break;
case TYPE_OPAQUE:
gi = make_shared<OpaqueTypeInfo>(this, tp);
break;
case TYPE_OPAQUE: gi = make_shared<OpaqueTypeInfo>(this, tp); break;
case TYPE_TYPE:
gi = make_shared<TypeTypeInfo>(this, tp);
break;
case TYPE_TYPE: gi = make_shared<TypeTypeInfo>(this, tp); break;
case TYPE_VECTOR:
gi = make_shared<VectorTypeInfo>(this, tp);
break;
case TYPE_VECTOR: gi = make_shared<VectorTypeInfo>(this, tp); break;
case TYPE_LIST:
gi = make_shared<ListTypeInfo>(this, tp);
break;
case TYPE_LIST: gi = make_shared<ListTypeInfo>(this, tp); break;
case TYPE_TABLE:
gi = make_shared<TableTypeInfo>(this, tp);
break;
case TYPE_TABLE: gi = make_shared<TableTypeInfo>(this, tp); break;
case TYPE_RECORD:
gi = make_shared<RecordTypeInfo>(this, tp);
break;
case TYPE_RECORD: gi = make_shared<RecordTypeInfo>(this, tp); break;
case TYPE_FUNC:
gi = make_shared<FuncTypeInfo>(this, tp);
break;
case TYPE_FUNC: gi = make_shared<FuncTypeInfo>(this, tp); break;
default:
reporter->InternalError("bad type in CPPCompile::RegisterType");
}
default: reporter->InternalError("bad type in CPPCompile::RegisterType");
}
type_info->AddInstance(gi);
processed_types[t] = gi;
type_info->AddInstance(gi);
processed_types[t] = gi;
types.AddInitInfo(t, gi);
types.AddInitInfo(t, gi);
return gi;
}
return gi;
}
const char* CPPCompile::NativeAccessor(const TypePtr& t)
{
switch ( t->Tag() )
{
case TYPE_BOOL:
return "->AsBool()";
case TYPE_COUNT:
return "->AsCount()";
case TYPE_DOUBLE:
return "->AsDouble()";
case TYPE_ENUM:
return "->AsEnum()";
case TYPE_INT:
return "->AsInt()";
case TYPE_INTERVAL:
return "->AsDouble()";
case TYPE_PORT:
return "->AsCount()";
case TYPE_TIME:
return "->AsDouble()";
const char* CPPCompile::NativeAccessor(const TypePtr& t) {
switch ( t->Tag() ) {
case TYPE_BOOL: return "->AsBool()";
case TYPE_COUNT: return "->AsCount()";
case TYPE_DOUBLE: return "->AsDouble()";
case TYPE_ENUM: return "->AsEnum()";
case TYPE_INT: return "->AsInt()";
case TYPE_INTERVAL: return "->AsDouble()";
case TYPE_PORT: return "->AsCount()";
case TYPE_TIME: return "->AsDouble()";
case TYPE_ADDR:
return "->AsAddrVal()";
case TYPE_FILE:
return "->AsFileVal()";
case TYPE_FUNC:
return "->AsFuncVal()";
case TYPE_OPAQUE:
return "->AsOpaqueVal()";
case TYPE_PATTERN:
return "->AsPatternVal()";
case TYPE_RECORD:
return "->AsRecordVal()";
case TYPE_STRING:
return "->AsStringVal()";
case TYPE_SUBNET:
return "->AsSubNetVal()";
case TYPE_TABLE:
return "->AsTableVal()";
case TYPE_TYPE:
return "->AsTypeVal()";
case TYPE_VECTOR:
return "->AsVectorVal()";
case TYPE_ADDR: return "->AsAddrVal()";
case TYPE_FILE: return "->AsFileVal()";
case TYPE_FUNC: return "->AsFuncVal()";
case TYPE_OPAQUE: return "->AsOpaqueVal()";
case TYPE_PATTERN: return "->AsPatternVal()";
case TYPE_RECORD: return "->AsRecordVal()";
case TYPE_STRING: return "->AsStringVal()";
case TYPE_SUBNET: return "->AsSubNetVal()";
case TYPE_TABLE: return "->AsTableVal()";
case TYPE_TYPE: return "->AsTypeVal()";
case TYPE_VECTOR: return "->AsVectorVal()";
case TYPE_ANY:
return ".get()";
case TYPE_ANY: return ".get()";
case TYPE_VOID:
return "";
case TYPE_VOID: return "";
default:
reporter->InternalError("bad type in CPPCompile::NativeAccessor");
return nullptr;
}
}
default: reporter->InternalError("bad type in CPPCompile::NativeAccessor"); return nullptr;
}
}
const char* CPPCompile::IntrusiveVal(const TypePtr& t)
{
switch ( t->Tag() )
{
case TYPE_BOOL:
return "BoolVal";
case TYPE_COUNT:
return "CountVal";
case TYPE_DOUBLE:
return "DoubleVal";
case TYPE_ENUM:
return "EnumVal";
case TYPE_INT:
return "IntVal";
case TYPE_INTERVAL:
return "IntervalVal";
case TYPE_PORT:
return "PortVal";
case TYPE_TIME:
return "TimeVal";
const char* CPPCompile::IntrusiveVal(const TypePtr& t) {
switch ( t->Tag() ) {
case TYPE_BOOL: return "BoolVal";
case TYPE_COUNT: return "CountVal";
case TYPE_DOUBLE: return "DoubleVal";
case TYPE_ENUM: return "EnumVal";
case TYPE_INT: return "IntVal";
case TYPE_INTERVAL: return "IntervalVal";
case TYPE_PORT: return "PortVal";
case TYPE_TIME: return "TimeVal";
case TYPE_ADDR:
return "AddrVal";
case TYPE_ANY:
return "Val";
case TYPE_FILE:
return "FileVal";
case TYPE_FUNC:
return "FuncVal";
case TYPE_OPAQUE:
return "OpaqueVal";
case TYPE_PATTERN:
return "PatternVal";
case TYPE_RECORD:
return "RecordVal";
case TYPE_STRING:
return "StringVal";
case TYPE_SUBNET:
return "SubNetVal";
case TYPE_TABLE:
return "TableVal";
case TYPE_TYPE:
return "TypeVal";
case TYPE_VECTOR:
return "VectorVal";
case TYPE_ADDR: return "AddrVal";
case TYPE_ANY: return "Val";
case TYPE_FILE: return "FileVal";
case TYPE_FUNC: return "FuncVal";
case TYPE_OPAQUE: return "OpaqueVal";
case TYPE_PATTERN: return "PatternVal";
case TYPE_RECORD: return "RecordVal";
case TYPE_STRING: return "StringVal";
case TYPE_SUBNET: return "SubNetVal";
case TYPE_TABLE: return "TableVal";
case TYPE_TYPE: return "TypeVal";
case TYPE_VECTOR: return "VectorVal";
default:
reporter->InternalError("bad type in CPPCompile::IntrusiveVal");
return nullptr;
}
}
default: reporter->InternalError("bad type in CPPCompile::IntrusiveVal"); return nullptr;
}
}
} // zeek::detail
} // namespace zeek::detail

View file

@ -8,126 +8,90 @@
#include "zeek/script_opt/StmtOptInfo.h"
namespace zeek::detail
{
namespace zeek::detail {
using namespace std;
string Fmt(double d)
{
// Special hack to preserve the signed-ness of the magic -0.0.
if ( d == 0.0 && signbit(d) )
return "-0.0";
string Fmt(double d) {
// Special hack to preserve the signed-ness of the magic -0.0.
if ( d == 0.0 && signbit(d) )
return "-0.0";
// Unfortunately, to_string(double) is hardwired to use %f with
// default of 6 digits precision.
char buf[8192];
snprintf(buf, sizeof buf, "%.17g", d);
return buf;
}
// Unfortunately, to_string(double) is hardwired to use %f with
// default of 6 digits precision.
char buf[8192];
snprintf(buf, sizeof buf, "%.17g", d);
return buf;
}
string scope_prefix(const string& scope)
{
return "zeek::detail::CPP_" + scope;
}
string scope_prefix(const string& scope) { return "zeek::detail::CPP_" + scope; }
string scope_prefix(int scope)
{
return scope_prefix(to_string(scope));
}
string scope_prefix(int scope) { return scope_prefix(to_string(scope)); }
bool is_CPP_compilable(const ProfileFunc* pf, const char** reason)
{
if ( analysis_options.allow_cond )
return true;
bool is_CPP_compilable(const ProfileFunc* pf, const char** reason) {
if ( analysis_options.allow_cond )
return true;
auto body = pf->ProfiledBody();
if ( body && ! body->GetOptInfo()->is_free_of_conditionals )
{
if ( reason )
*reason = "body may be affected by @if conditional";
return false;
}
auto body = pf->ProfiledBody();
if ( body && ! body->GetOptInfo()->is_free_of_conditionals ) {
if ( reason )
*reason = "body may be affected by @if conditional";
return false;
}
return true;
}
return true;
}
void lock_file(const string& fname, FILE* f)
{
if ( flock(fileno(f), LOCK_EX) < 0 )
{
char buf[256];
util::zeek_strerror_r(errno, buf, sizeof(buf));
reporter->Error("flock failed on %s: %s", fname.c_str(), buf);
exit(1);
}
}
void lock_file(const string& fname, FILE* f) {
if ( flock(fileno(f), LOCK_EX) < 0 ) {
char buf[256];
util::zeek_strerror_r(errno, buf, sizeof(buf));
reporter->Error("flock failed on %s: %s", fname.c_str(), buf);
exit(1);
}
}
void unlock_file(const string& fname, FILE* f)
{
if ( flock(fileno(f), LOCK_UN) < 0 )
{
char buf[256];
util::zeek_strerror_r(errno, buf, sizeof(buf));
reporter->Error("un-flock failed on %s: %s", fname.c_str(), buf);
exit(1);
}
}
void unlock_file(const string& fname, FILE* f) {
if ( flock(fileno(f), LOCK_UN) < 0 ) {
char buf[256];
util::zeek_strerror_r(errno, buf, sizeof(buf));
reporter->Error("un-flock failed on %s: %s", fname.c_str(), buf);
exit(1);
}
}
string CPPEscape(const char* b, int len)
{
string res;
string CPPEscape(const char* b, int len) {
string res;
for ( int i = 0; i < len; ++i )
{
unsigned char c = b[i];
for ( int i = 0; i < len; ++i ) {
unsigned char c = b[i];
switch ( c )
{
case '\a':
res += "\\a";
break;
case '\b':
res += "\\b";
break;
case '\f':
res += "\\f";
break;
case '\n':
res += "\\n";
break;
case '\r':
res += "\\r";
break;
case '\t':
res += "\\t";
break;
case '\v':
res += "\\v";
break;
switch ( c ) {
case '\a': res += "\\a"; break;
case '\b': res += "\\b"; break;
case '\f': res += "\\f"; break;
case '\n': res += "\\n"; break;
case '\r': res += "\\r"; break;
case '\t': res += "\\t"; break;
case '\v': res += "\\v"; break;
case '\\':
res += "\\\\";
break;
case '"':
res += "\\\"";
break;
case '\\': res += "\\\\"; break;
case '"': res += "\\\""; break;
default:
if ( isprint(c) )
res += c;
else
{
char buf[8192];
snprintf(buf, sizeof buf, "%03o", c);
res += "\\";
res += buf;
}
break;
}
}
default:
if ( isprint(c) )
res += c;
else {
char buf[8192];
snprintf(buf, sizeof buf, "%03o", c);
res += "\\";
res += buf;
}
break;
}
}
return res;
}
return res;
}
} // zeek::detail
} // namespace zeek::detail

View file

@ -6,18 +6,11 @@
#include "zeek/script_opt/ProfileFunc.h"
namespace zeek::detail
{
namespace zeek::detail {
// Conversions to strings.
inline std::string Fmt(int i)
{
return std::to_string(i);
}
inline std::string Fmt(p_hash_type u)
{
return std::to_string(u) + "ULL";
}
inline std::string Fmt(int i) { return std::to_string(i); }
inline std::string Fmt(p_hash_type u) { return std::to_string(u) + "ULL"; }
extern std::string Fmt(double d);
// Returns the prefix for the scoping used by the compiler.
@ -39,9 +32,6 @@ extern void unlock_file(const std::string& fname, FILE* f);
// For the given byte array / string, returns a version expanded
// with escape sequences in order to represent it as a C++ string.
extern std::string CPPEscape(const char* b, int len);
inline std::string CPPEscape(const char* s)
{
return CPPEscape(s, strlen(s));
}
inline std::string CPPEscape(const char* s) { return CPPEscape(s, strlen(s)); }
} // zeek::detail
} // namespace zeek::detail

View file

@ -3,156 +3,138 @@
#include "zeek/script_opt/CPP/Compile.h"
#include "zeek/script_opt/ProfileFunc.h"
namespace zeek::detail
{
namespace zeek::detail {
using namespace std;
void CPPCompile::CreateGlobal(const ID* g)
{
auto gn = string(g->Name());
bool is_bif = pfs.BiFGlobals().count(g) > 0;
void CPPCompile::CreateGlobal(const ID* g) {
auto gn = string(g->Name());
bool is_bif = pfs.BiFGlobals().count(g) > 0;
if ( pfs.Globals().count(g) == 0 )
{
// Only used in the context of calls. If it's compilable,
// then we'll call it directly.
if ( compilable_funcs.count(gn) > 0 )
{
AddGlobal(gn, "zf");
return;
}
if ( pfs.Globals().count(g) == 0 ) {
// Only used in the context of calls. If it's compilable,
// then we'll call it directly.
if ( compilable_funcs.count(gn) > 0 ) {
AddGlobal(gn, "zf");
return;
}
if ( is_bif )
{
AddBiF(g, false);
return;
}
}
if ( is_bif ) {
AddBiF(g, false);
return;
}
}
if ( AddGlobal(gn, "gl") )
{ // We'll be creating this global.
Emit("IDPtr %s;", globals[gn]);
if ( AddGlobal(gn, "gl") ) { // We'll be creating this global.
Emit("IDPtr %s;", globals[gn]);
if ( pfs.Events().count(gn) > 0 )
// This is an event that's also used as a variable.
Emit("EventHandlerPtr %s_ev;", globals[gn]);
if ( pfs.Events().count(gn) > 0 )
// This is an event that's also used as a variable.
Emit("EventHandlerPtr %s_ev;", globals[gn]);
auto gi = make_shared<GlobalInitInfo>(this, g, globals[gn]);
global_id_info->AddInstance(gi);
global_gis[g] = gi;
}
auto gi = make_shared<GlobalInitInfo>(this, g, globals[gn]);
global_id_info->AddInstance(gi);
global_gis[g] = gi;
}
if ( is_bif )
// This is a BiF that's referred to in a non-call context,
// so we didn't already add it above.
AddBiF(g, true);
if ( is_bif )
// This is a BiF that's referred to in a non-call context,
// so we didn't already add it above.
AddBiF(g, true);
global_vars.emplace(g);
}
global_vars.emplace(g);
}
std::shared_ptr<CPP_InitInfo> CPPCompile::RegisterGlobal(const ID* g)
{
auto gg = global_gis.find(g);
std::shared_ptr<CPP_InitInfo> CPPCompile::RegisterGlobal(const ID* g) {
auto gg = global_gis.find(g);
if ( gg != global_gis.end() )
return gg->second;
if ( gg != global_gis.end() )
return gg->second;
auto gn = string(g->Name());
auto gn = string(g->Name());
if ( globals.count(gn) == 0 )
{
// Create a name for it.
(void)IDNameStr(g);
if ( globals.count(gn) == 0 ) {
// Create a name for it.
(void)IDNameStr(g);
// That call may have created the initializer, in which
// case no need to repeat it.
gg = global_gis.find(g);
if ( gg != global_gis.end() )
return gg->second;
}
// That call may have created the initializer, in which
// case no need to repeat it.
gg = global_gis.find(g);
if ( gg != global_gis.end() )
return gg->second;
}
auto gi = make_shared<GlobalInitInfo>(this, g, globals[gn]);
global_id_info->AddInstance(gi);
global_gis[g] = gi;
auto gi = make_shared<GlobalInitInfo>(this, g, globals[gn]);
global_id_info->AddInstance(gi);
global_gis[g] = gi;
return gi;
}
return gi;
}
void CPPCompile::AddBiF(const ID* b, bool is_var)
{
auto bn = b->Name();
auto n = string(bn);
if ( is_var )
n = n + "_"; // make the name distinct
void CPPCompile::AddBiF(const ID* b, bool is_var) {
auto bn = b->Name();
auto n = string(bn);
if ( is_var )
n = n + "_"; // make the name distinct
if ( AddGlobal(n, "bif") )
Emit("Func* %s;", globals[n]);
if ( AddGlobal(n, "bif") )
Emit("Func* %s;", globals[n]);
ASSERT(BiFs.count(globals[n]) == 0);
BiFs[globals[n]] = bn;
}
ASSERT(BiFs.count(globals[n]) == 0);
BiFs[globals[n]] = bn;
}
bool CPPCompile::AddGlobal(const string& g, const char* suffix)
{
if ( globals.count(g) > 0 )
return false;
bool CPPCompile::AddGlobal(const string& g, const char* suffix) {
if ( globals.count(g) > 0 )
return false;
globals.emplace(g, GlobalName(g, suffix));
return true;
}
globals.emplace(g, GlobalName(g, suffix));
return true;
}
void CPPCompile::RegisterEvent(string ev_name)
{
body_events[body_name].emplace_back(std::move(ev_name));
}
void CPPCompile::RegisterEvent(string ev_name) { body_events[body_name].emplace_back(std::move(ev_name)); }
const string& CPPCompile::IDNameStr(const ID* id)
{
if ( id->IsGlobal() )
{
auto g = string(id->Name());
if ( globals.count(g) == 0 )
CreateGlobal(id);
return globals[g];
}
const string& CPPCompile::IDNameStr(const ID* id) {
if ( id->IsGlobal() ) {
auto g = string(id->Name());
if ( globals.count(g) == 0 )
CreateGlobal(id);
return globals[g];
}
auto l = locals.find(id);
ASSERT(l != locals.end());
return l->second;
}
auto l = locals.find(id);
ASSERT(l != locals.end());
return l->second;
}
string CPPCompile::LocalName(const ID* l) const
{
auto n = l->Name();
auto without_module = strstr(n, "::");
string CPPCompile::LocalName(const ID* l) const {
auto n = l->Name();
auto without_module = strstr(n, "::");
if ( without_module )
return Canonicalize(without_module + 2);
else
return Canonicalize(n);
}
if ( without_module )
return Canonicalize(without_module + 2);
else
return Canonicalize(n);
}
string CPPCompile::Canonicalize(const char* name) const
{
string cname;
string CPPCompile::Canonicalize(const char* name) const {
string cname;
for ( int i = 0; name[i]; ++i )
{
auto c = name[i];
for ( int i = 0; name[i]; ++i ) {
auto c = name[i];
// Strip <>'s - these get introduced for lambdas.
if ( c == '<' || c == '>' )
continue;
// Strip <>'s - these get introduced for lambdas.
if ( c == '<' || c == '>' )
continue;
if ( c == ':' || c == '-' )
c = '_';
if ( c == ':' || c == '-' )
c = '_';
cname += c;
}
cname += c;
}
// Add a trailing '_' to avoid conflicts with C++ keywords.
return cname + "_";
}
// Add a trailing '_' to avoid conflicts with C++ keywords.
return cname + "_";
}
} // zeek::detail
} // namespace zeek::detail