mirror of
https://github.com/zeek/zeek.git
synced 2025-10-09 10:08:20 +00:00
optimize record construction by deferring initializations of aggregates
This commit is contained in:
parent
2e2afa5e11
commit
0787c130d0
5 changed files with 190 additions and 158 deletions
217
src/Type.cc
217
src/Type.cc
|
@ -992,39 +992,102 @@ void TypeDecl::DescribeReST(ODesc* d, bool roles_only) const
|
|||
}
|
||||
}
|
||||
|
||||
// The following tracks how to initialize a given field, for fast execution
|
||||
// of Create().
|
||||
|
||||
class FieldInit
|
||||
class DirectFieldInit final : public FieldInit
|
||||
{
|
||||
public:
|
||||
// The type of initialization for the field.
|
||||
enum
|
||||
DirectFieldInit(ZVal _init_val) : init_val(_init_val) { }
|
||||
|
||||
ZVal Generate() const override { return init_val; }
|
||||
|
||||
private:
|
||||
ZVal init_val;
|
||||
};
|
||||
|
||||
class DirectManagedFieldInit final : public FieldInit
|
||||
{
|
||||
public:
|
||||
DirectManagedFieldInit(ZVal _init_val) : init_val(_init_val) { }
|
||||
~DirectManagedFieldInit() { ZVal::DeleteManagedType(init_val); }
|
||||
|
||||
ZVal Generate() const override
|
||||
{
|
||||
R_INIT_NONE, // skip this entry
|
||||
zeek::Ref(init_val.ManagedVal());
|
||||
return init_val;
|
||||
}
|
||||
|
||||
R_INIT_DIRECT, // look in direct_init for raw value
|
||||
R_INIT_DIRECT_MANAGED, // same, but managed type
|
||||
private:
|
||||
ZVal init_val;
|
||||
};
|
||||
|
||||
R_INIT_DEF, // look in def_expr for expression
|
||||
class ExprFieldInit final : public FieldInit
|
||||
{
|
||||
public:
|
||||
// Initialization requires evaluating the given expression,
|
||||
// yielding the a value of the given type (which might require
|
||||
// coercion for some records).
|
||||
ExprFieldInit(detail::ExprPtr _init_expr, TypePtr _init_type)
|
||||
: init_expr(std::move(_init_expr)), init_type(std::move(_init_type))
|
||||
{
|
||||
if ( init_type->Tag() == TYPE_RECORD && ! same_type(init_expr->GetType(), init_type) )
|
||||
coerce_type = cast_intrusive<RecordType>(init_type);
|
||||
}
|
||||
|
||||
R_INIT_RECORD, // field requires a new record
|
||||
R_INIT_TABLE, // field requires a new table/set
|
||||
R_INIT_VECTOR, // field requires a new vector
|
||||
} init_type = R_INIT_NONE;
|
||||
ZVal Generate() const override
|
||||
{
|
||||
auto v = init_expr->Eval(nullptr);
|
||||
if ( ! v )
|
||||
{
|
||||
reporter->Error("failed &default in record creation");
|
||||
return ZVal();
|
||||
}
|
||||
|
||||
bool def_coerce = false; // whether coercion's required
|
||||
if ( coerce_type )
|
||||
v = v->AsRecordVal()->CoerceTo(coerce_type);
|
||||
|
||||
// For R_INIT_DIRECT/R_INIT_DIRECT_MANAGED:
|
||||
ZVal direct_init;
|
||||
return ZVal(v, init_type);
|
||||
}
|
||||
|
||||
detail::ExprPtr def_expr;
|
||||
TypePtr def_type;
|
||||
private:
|
||||
detail::ExprPtr init_expr;
|
||||
TypePtr init_type;
|
||||
RecordTypePtr coerce_type; // non-nil iff coercion is required
|
||||
};
|
||||
|
||||
RecordTypePtr r_type; // for R_INIT_RECORD
|
||||
TableTypePtr t_type; // for R_INIT_TABLE
|
||||
detail::AttributesPtr attrs; // attributes for R_INIT_TABLE
|
||||
VectorTypePtr v_type; // for R_INIT_VECTOR
|
||||
class RecordFieldInit final : public FieldInit
|
||||
{
|
||||
public:
|
||||
RecordFieldInit(RecordTypePtr _init_type) : init_type(std::move(_init_type)) { }
|
||||
|
||||
ZVal Generate() const override { return ZVal(new RecordVal(init_type)); }
|
||||
|
||||
private:
|
||||
RecordTypePtr init_type;
|
||||
};
|
||||
|
||||
class TableFieldInit final : public FieldInit
|
||||
{
|
||||
public:
|
||||
TableFieldInit(TableTypePtr _init_type, detail::AttributesPtr _attrs)
|
||||
: init_type(std::move(_init_type)), attrs(std::move(_attrs))
|
||||
{
|
||||
}
|
||||
|
||||
ZVal Generate() const override { return ZVal(new TableVal(init_type, attrs)); }
|
||||
|
||||
private:
|
||||
TableTypePtr init_type;
|
||||
detail::AttributesPtr attrs;
|
||||
};
|
||||
|
||||
class VectorFieldInit final : public FieldInit
|
||||
{
|
||||
public:
|
||||
VectorFieldInit(VectorTypePtr _init_type) : init_type(std::move(_init_type)) { }
|
||||
|
||||
ZVal Generate() const override { return ZVal(new VectorVal(init_type)); }
|
||||
|
||||
private:
|
||||
VectorTypePtr init_type;
|
||||
};
|
||||
|
||||
RecordType::RecordType(type_decl_list* arg_types) : Type(TYPE_RECORD)
|
||||
|
@ -1064,7 +1127,8 @@ RecordType::~RecordType()
|
|||
}
|
||||
|
||||
for ( auto fi : field_inits )
|
||||
delete fi;
|
||||
if ( fi )
|
||||
delete *fi;
|
||||
}
|
||||
|
||||
void RecordType::AddField(unsigned int field, const TypeDecl* td)
|
||||
|
@ -1074,53 +1138,43 @@ void RecordType::AddField(unsigned int field, const TypeDecl* td)
|
|||
|
||||
managed_fields.push_back(ZVal::IsManagedType(td->type));
|
||||
|
||||
auto init = new FieldInit();
|
||||
init->init_type = FieldInit::R_INIT_NONE;
|
||||
|
||||
init->attrs = td->attrs;
|
||||
|
||||
// We defer error-checking until here so that we can keep field_inits
|
||||
// and managed_fields correctly tracking the associated fields.
|
||||
|
||||
if ( field_ids.count(td->id) != 0 )
|
||||
{
|
||||
reporter->Error("duplicate field '%s' found in record definition", td->id);
|
||||
field_inits.push_back(init);
|
||||
field_inits.push_back(std::nullopt);
|
||||
return;
|
||||
}
|
||||
|
||||
field_ids.insert(std::string(td->id));
|
||||
|
||||
auto a = init->attrs;
|
||||
|
||||
auto a = td->attrs;
|
||||
auto type = td->type;
|
||||
|
||||
auto def_attr = a ? a->Find(detail::ATTR_DEFAULT) : nullptr;
|
||||
auto def_expr = def_attr ? def_attr->GetExpr() : nullptr;
|
||||
|
||||
std::optional<FieldInit*> init;
|
||||
|
||||
if ( def_expr && ! IsErrorType(type->Tag()) )
|
||||
{
|
||||
if ( type->Tag() == TYPE_RECORD && def_expr->GetType()->Tag() == TYPE_RECORD &&
|
||||
! same_type(def_expr->GetType(), type) )
|
||||
init->def_coerce = true;
|
||||
|
||||
if ( def_expr->Tag() == detail::EXPR_CONST )
|
||||
{
|
||||
auto v = def_expr->Eval(nullptr);
|
||||
auto zv = ZVal(v, type);
|
||||
|
||||
if ( ZVal::IsManagedType(type) )
|
||||
init->init_type = FieldInit::R_INIT_DIRECT_MANAGED;
|
||||
init = new DirectManagedFieldInit(zv);
|
||||
else
|
||||
init->init_type = FieldInit::R_INIT_DIRECT;
|
||||
|
||||
init->direct_init = ZVal(v, type);
|
||||
init = new DirectFieldInit(zv);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
init->init_type = FieldInit::R_INIT_DEF;
|
||||
init->def_expr = def_expr;
|
||||
init->def_type = def_expr->GetType();
|
||||
auto efi = new ExprFieldInit(def_expr, type);
|
||||
field_expr_inits.emplace_back(std::make_pair(field, efi));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1129,22 +1183,13 @@ void RecordType::AddField(unsigned int field, const TypeDecl* td)
|
|||
TypeTag tag = type->Tag();
|
||||
|
||||
if ( tag == TYPE_RECORD )
|
||||
{
|
||||
init->init_type = FieldInit::R_INIT_RECORD;
|
||||
init->r_type = cast_intrusive<RecordType>(type);
|
||||
}
|
||||
init = new RecordFieldInit(cast_intrusive<RecordType>(type));
|
||||
|
||||
else if ( tag == TYPE_TABLE )
|
||||
{
|
||||
init->init_type = FieldInit::R_INIT_TABLE;
|
||||
init->t_type = cast_intrusive<TableType>(type);
|
||||
}
|
||||
init = new TableFieldInit(cast_intrusive<TableType>(type), a);
|
||||
|
||||
else if ( tag == TYPE_VECTOR )
|
||||
{
|
||||
init->init_type = FieldInit::R_INIT_VECTOR;
|
||||
init->v_type = cast_intrusive<VectorType>(type);
|
||||
}
|
||||
init = new VectorFieldInit(cast_intrusive<VectorType>(type));
|
||||
}
|
||||
|
||||
field_inits.push_back(init);
|
||||
|
@ -1342,68 +1387,6 @@ void RecordType::AddFieldsDirectly(const type_decl_list& others, bool add_log_at
|
|||
num_fields = types->length();
|
||||
}
|
||||
|
||||
void RecordType::Create(std::vector<std::optional<ZVal>>& r) const
|
||||
{
|
||||
int n = NumFields();
|
||||
|
||||
for ( int i = 0; i < n; ++i )
|
||||
{
|
||||
auto* init = field_inits[i];
|
||||
|
||||
ZVal r_i;
|
||||
|
||||
switch ( init->init_type )
|
||||
{
|
||||
case FieldInit::R_INIT_NONE:
|
||||
r.push_back(std::nullopt);
|
||||
continue;
|
||||
|
||||
case FieldInit::R_INIT_DIRECT:
|
||||
r_i = init->direct_init;
|
||||
break;
|
||||
|
||||
case FieldInit::R_INIT_DIRECT_MANAGED:
|
||||
r_i = init->direct_init;
|
||||
zeek::Ref(r_i.ManagedVal());
|
||||
break;
|
||||
|
||||
case FieldInit::R_INIT_DEF:
|
||||
{
|
||||
auto v = init->def_expr->Eval(nullptr);
|
||||
if ( v )
|
||||
{
|
||||
const auto& t = init->def_type;
|
||||
|
||||
if ( init->def_coerce )
|
||||
{
|
||||
auto rt = cast_intrusive<RecordType>(t);
|
||||
v = v->AsRecordVal()->CoerceTo(rt);
|
||||
}
|
||||
|
||||
r_i = ZVal(v, t);
|
||||
}
|
||||
else
|
||||
reporter->Error("failed &default in record creation");
|
||||
}
|
||||
break;
|
||||
|
||||
case FieldInit::R_INIT_RECORD:
|
||||
r_i = ZVal(new RecordVal(init->r_type));
|
||||
break;
|
||||
|
||||
case FieldInit::R_INIT_TABLE:
|
||||
r_i = ZVal(new TableVal(init->t_type, init->attrs));
|
||||
break;
|
||||
|
||||
case FieldInit::R_INIT_VECTOR:
|
||||
r_i = ZVal(new VectorVal(init->v_type));
|
||||
break;
|
||||
}
|
||||
|
||||
r.push_back(r_i);
|
||||
}
|
||||
}
|
||||
|
||||
void RecordType::DescribeFields(ODesc* d) const
|
||||
{
|
||||
if ( d->IsReadable() )
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue