mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
533 lines
16 KiB
C++
533 lines
16 KiB
C++
// See the file "COPYING" in the main distribution directory for copyright.
|
|
|
|
#include "zeek/script_opt/CPP/RuntimeInits.h"
|
|
|
|
#include "zeek/Desc.h"
|
|
#include "zeek/File.h"
|
|
#include "zeek/RE.h"
|
|
#include "zeek/ZeekString.h"
|
|
#include "zeek/script_opt/CPP/RuntimeInitSupport.h"
|
|
|
|
using namespace std;
|
|
|
|
namespace zeek::detail {
|
|
|
|
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]);
|
|
}
|
|
|
|
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<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);
|
|
}
|
|
|
|
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();
|
|
|
|
re->Compile();
|
|
|
|
ivec[offset] = make_intrusive<PatternVal>(re);
|
|
}
|
|
|
|
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);
|
|
|
|
for ( auto& iv : init_vals )
|
|
l->Append(im->ConstVals(iv));
|
|
|
|
ivec[offset] = l;
|
|
}
|
|
|
|
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++);
|
|
|
|
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++)));
|
|
|
|
ivec[offset] = vv;
|
|
}
|
|
|
|
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++);
|
|
|
|
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;
|
|
}
|
|
|
|
ivec[offset] = rv;
|
|
}
|
|
|
|
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++);
|
|
|
|
auto tt = cast_intrusive<TableType>(im->Types(t));
|
|
auto tv = make_intrusive<TableVal>(tt);
|
|
|
|
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);
|
|
}
|
|
|
|
ivec[offset] = tv;
|
|
}
|
|
|
|
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"));
|
|
|
|
ivec[offset] = fv;
|
|
}
|
|
|
|
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++);
|
|
|
|
std::vector<p_hash_type> hashes;
|
|
|
|
while ( iv_it != iv_end )
|
|
hashes.push_back(im->Hashes(*(iv_it++)));
|
|
|
|
ivec[offset] = lookup_func__CPP(fn, num_bodies, hashes, im->Types(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]);
|
|
|
|
if ( ae_tag == AE_NONE ) {
|
|
ivec[offset] = make_intrusive<Attr>(tag);
|
|
return;
|
|
}
|
|
|
|
ExprPtr e;
|
|
auto e_arg = init_vals[2];
|
|
|
|
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_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_CALL: e = im->CallExprs(e_arg); break;
|
|
}
|
|
|
|
ivec[offset] = make_intrusive<Attr>(tag, e);
|
|
}
|
|
|
|
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;
|
|
|
|
for ( auto& iv : init_vals )
|
|
a_list.emplace_back(im->Attrs(iv));
|
|
|
|
ivec[offset] = make_intrusive<Attributes>(a_list, nullptr, false, false);
|
|
}
|
|
|
|
// Instantiate the templates we'll need.
|
|
|
|
template class CPP_IndexedInits<EnumValPtr>;
|
|
template class CPP_IndexedInits<StringValPtr>;
|
|
template class CPP_IndexedInits<PatternValPtr>;
|
|
template class CPP_IndexedInits<ListValPtr>;
|
|
template class CPP_IndexedInits<VectorValPtr>;
|
|
template class CPP_IndexedInits<RecordValPtr>;
|
|
template class CPP_IndexedInits<TableValPtr>;
|
|
template class CPP_IndexedInits<FileValPtr>;
|
|
template class CPP_IndexedInits<FuncValPtr>;
|
|
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 && init_vals[1] != NAMED_TYPE_MARKER ) {
|
|
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 && init_vals[1] != NAMED_TYPE_MARKER )
|
|
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]);
|
|
|
|
if ( init_vals.size() > 1 && init_vals[1] == NAMED_TYPE_MARKER ) {
|
|
auto name = im->Strings(init_vals[2]);
|
|
ivec[offset] = find_global__CPP(name)->GetType();
|
|
return;
|
|
}
|
|
|
|
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);
|
|
|
|
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]);
|
|
auto expressionless_return_okay = static_cast<FunctionFlavor>(init_vals[4]);
|
|
|
|
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);
|
|
|
|
auto ft = make_intrusive<FuncType>(p, y, flavor);
|
|
ft->SetExpressionlessReturnOkay(expressionless_return_okay);
|
|
return ft;
|
|
}
|
|
|
|
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
|
|
if ( field_type == DO_NOT_CONSTRUCT_VALUE_MARKER ) {
|
|
reporter->CPPRuntimeError("record field \"%s\" missing in %s", field_name.c_str(), obj_desc(r).c_str());
|
|
exit(1);
|
|
}
|
|
|
|
fm_offset = r->NumFields();
|
|
|
|
auto id = util::copy_string(field_name.c_str(), field_name.size());
|
|
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
|
|
if ( ! construct_if_missing ) {
|
|
reporter->CPPRuntimeError("enum element \"%s\" missing in %s", e_name.c_str(), obj_desc(e).c_str());
|
|
exit(1);
|
|
}
|
|
|
|
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_GlobalLookupInit::Generate(InitsManager* im, std::vector<void*>& /* inits_vec */, int /* offset */) const {
|
|
global = find_global__CPP(name);
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
size_t 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 != END_OF_VEC_VEC && *i_ptr != END_OF_VEC_VEC_VEC ) {
|
|
++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 != END_OF_VEC_VEC ) {
|
|
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));
|
|
}
|
|
|
|
return i_ptr - inits + 1;
|
|
}
|
|
|
|
std::vector<std::vector<std::vector<int>>> generate_indices_set(int* inits) {
|
|
std::vector<std::vector<std::vector<int>>> indices_set;
|
|
|
|
while ( *inits != END_OF_VEC_VEC_VEC ) {
|
|
std::vector<std::vector<int>> cohort_inits;
|
|
inits += generate_indices_set(inits, cohort_inits);
|
|
indices_set.push_back(std::move(cohort_inits));
|
|
}
|
|
|
|
return indices_set;
|
|
}
|
|
|
|
} // namespace zeek::detail
|