mirror of
https://github.com/zeek/zeek.git
synced 2025-10-04 15:48:19 +00:00
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:
parent
7b8e7ed72c
commit
f5a76c1aed
786 changed files with 131714 additions and 153609 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue