mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Fix deferred record initialization
Put RecordFieldInit instances into creation_inits during parsing and determine their deferrability in an InitPostScript step. Any RecordFieldInits can be deferred are moved into deferred_inits. Closes #3260
This commit is contained in:
parent
7d6c8d7224
commit
384e7e6b25
3 changed files with 107 additions and 1 deletions
93
src/Type.cc
93
src/Type.cc
|
@ -13,7 +13,9 @@
|
||||||
#include "zeek/Desc.h"
|
#include "zeek/Desc.h"
|
||||||
#include "zeek/Expr.h"
|
#include "zeek/Expr.h"
|
||||||
#include "zeek/Reporter.h"
|
#include "zeek/Reporter.h"
|
||||||
|
#include "zeek/RunState.h"
|
||||||
#include "zeek/Scope.h"
|
#include "zeek/Scope.h"
|
||||||
|
#include "zeek/Traverse.h"
|
||||||
#include "zeek/Val.h"
|
#include "zeek/Val.h"
|
||||||
#include "zeek/Var.h"
|
#include "zeek/Var.h"
|
||||||
#include "zeek/module_util.h"
|
#include "zeek/module_util.h"
|
||||||
|
@ -1065,6 +1067,8 @@ public:
|
||||||
return ZVal(v, init_type);
|
return ZVal(v, init_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsDeferrable() const override { return false; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
detail::ExprPtr init_expr;
|
detail::ExprPtr init_expr;
|
||||||
TypePtr init_type;
|
TypePtr init_type;
|
||||||
|
@ -1080,6 +1084,12 @@ public:
|
||||||
|
|
||||||
ZVal Generate() const override { return ZVal(new RecordVal(init_type)); }
|
ZVal Generate() const override { return ZVal(new RecordVal(init_type)); }
|
||||||
|
|
||||||
|
bool IsDeferrable() const override
|
||||||
|
{
|
||||||
|
assert(! run_state::is_parsing);
|
||||||
|
return init_type->IsDeferrable();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RecordTypePtr init_type;
|
RecordTypePtr init_type;
|
||||||
};
|
};
|
||||||
|
@ -1116,6 +1126,59 @@ private:
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
|
// Helper TraversalCallback optimizing RecordType instances by moving
|
||||||
|
// deferrable FieldInits from creation_inits to deferred_inits once
|
||||||
|
// parsing has completed.
|
||||||
|
class RecordType::CreationInitsOptimizer : public detail::TraversalCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
detail::TraversalCode PreID(const detail::ID* id) override
|
||||||
|
{
|
||||||
|
if ( const auto& t = id->GetType() )
|
||||||
|
HANDLE_TC_TYPE_POST(t->Traverse(this));
|
||||||
|
|
||||||
|
return detail::TC_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::TraversalCode PreType(const Type* t) override
|
||||||
|
{
|
||||||
|
if ( analyzed_types.count(t) > 0 )
|
||||||
|
return detail::TC_ABORTSTMT;
|
||||||
|
|
||||||
|
analyzed_types.emplace(t);
|
||||||
|
|
||||||
|
if ( t->Tag() == TYPE_RECORD )
|
||||||
|
{
|
||||||
|
auto* rt = const_cast<RecordType*>(t->AsRecordType());
|
||||||
|
OptimizeCreationInits(rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return detail::TC_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void OptimizeCreationInits(RecordType* rt)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for ( auto& ci : rt->creation_inits )
|
||||||
|
{
|
||||||
|
if ( ! ci.second->IsDeferrable() )
|
||||||
|
rt->creation_inits[i++] = std::move(ci);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(! rt->deferred_inits[ci.first]);
|
||||||
|
rt->deferred_inits[ci.first].swap(ci.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Discard remaining elements.
|
||||||
|
rt->creation_inits.resize(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Endless recursion avoidance.
|
||||||
|
std::unordered_set<const Type*> analyzed_types;
|
||||||
|
};
|
||||||
|
|
||||||
RecordType::RecordType(type_decl_list* arg_types) : Type(TYPE_RECORD)
|
RecordType::RecordType(type_decl_list* arg_types) : Type(TYPE_RECORD)
|
||||||
{
|
{
|
||||||
types = arg_types;
|
types = arg_types;
|
||||||
|
@ -1132,6 +1195,12 @@ RecordType::RecordType(type_decl_list* arg_types) : Type(TYPE_RECORD)
|
||||||
num_orig_fields = num_fields;
|
num_orig_fields = num_fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RecordType::InitPostScript()
|
||||||
|
{
|
||||||
|
auto cb = CreationInitsOptimizer();
|
||||||
|
detail::traverse_all(&cb);
|
||||||
|
}
|
||||||
|
|
||||||
// in this case the clone is actually not so shallow, since
|
// in this case the clone is actually not so shallow, since
|
||||||
// it gets modified by everyone.
|
// it gets modified by everyone.
|
||||||
TypePtr RecordType::ShallowClone()
|
TypePtr RecordType::ShallowClone()
|
||||||
|
@ -1205,7 +1274,15 @@ void RecordType::AddField(unsigned int field, const TypeDecl* td)
|
||||||
TypeTag tag = type->Tag();
|
TypeTag tag = type->Tag();
|
||||||
|
|
||||||
if ( tag == TYPE_RECORD )
|
if ( tag == TYPE_RECORD )
|
||||||
init = std::make_unique<detail::RecordFieldInit>(cast_intrusive<RecordType>(type));
|
{
|
||||||
|
// Initially, put record fields into creation_inits. Once parsing has
|
||||||
|
// completed, they may move into deferred_inits. See RecordType::InitPostScript()
|
||||||
|
// and RecordType::CreationInitisOptimizer.
|
||||||
|
//
|
||||||
|
// init (nil) is appended to deferred_inits as placeholder.
|
||||||
|
auto rfi = std::make_unique<detail::RecordFieldInit>(cast_intrusive<RecordType>(type));
|
||||||
|
creation_inits.emplace_back(field, std::move(rfi));
|
||||||
|
}
|
||||||
|
|
||||||
else if ( tag == TYPE_TABLE )
|
else if ( tag == TYPE_TABLE )
|
||||||
init = std::make_unique<detail::TableFieldInit>(cast_intrusive<TableType>(type), a);
|
init = std::make_unique<detail::TableFieldInit>(cast_intrusive<TableType>(type), a);
|
||||||
|
@ -1589,6 +1666,20 @@ detail::TraversalCode RecordType::Traverse(detail::TraversalCallback* cb) const
|
||||||
HANDLE_TC_TYPE_POST(tc);
|
HANDLE_TC_TYPE_POST(tc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RecordType::IsDeferrable() const
|
||||||
|
{
|
||||||
|
assert(! run_state::is_parsing);
|
||||||
|
auto is_deferrable = [](const auto& p) -> bool
|
||||||
|
{
|
||||||
|
return p.second->IsDeferrable();
|
||||||
|
};
|
||||||
|
|
||||||
|
// If all creation_inits are deferrable, this record type is deferrable, too.
|
||||||
|
// It will be optimized later on. Note, all_of() returns true for an empty
|
||||||
|
// range, which is correct.
|
||||||
|
return std::all_of(creation_inits.begin(), creation_inits.end(), is_deferrable);
|
||||||
|
}
|
||||||
|
|
||||||
FileType::FileType(TypePtr yield_type) : Type(TYPE_FILE), yield(std::move(yield_type)) { }
|
FileType::FileType(TypePtr yield_type) : Type(TYPE_FILE), yield(std::move(yield_type)) { }
|
||||||
|
|
||||||
FileType::~FileType() = default;
|
FileType::~FileType() = default;
|
||||||
|
|
13
src/Type.h
13
src/Type.h
|
@ -44,6 +44,9 @@ public:
|
||||||
|
|
||||||
// Return the initialization value of the field.
|
// Return the initialization value of the field.
|
||||||
virtual ZVal Generate() const = 0;
|
virtual ZVal Generate() const = 0;
|
||||||
|
|
||||||
|
// Can initialization of the field be deferred?
|
||||||
|
virtual bool IsDeferrable() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
@ -734,6 +737,15 @@ public:
|
||||||
|
|
||||||
detail::TraversalCode Traverse(detail::TraversalCallback* cb) const override;
|
detail::TraversalCode Traverse(detail::TraversalCallback* cb) const override;
|
||||||
|
|
||||||
|
// Can initialization of record values of this type be deferred?
|
||||||
|
//
|
||||||
|
// When record types contain non-const &default expressions or recursively
|
||||||
|
// contain any nested records that themselves are not deferrable,
|
||||||
|
// initialization can not be deferred, otherwise possible.
|
||||||
|
bool IsDeferrable() const;
|
||||||
|
|
||||||
|
static void InitPostScript();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RecordType() { types = nullptr; }
|
RecordType() { types = nullptr; }
|
||||||
|
|
||||||
|
@ -754,6 +766,7 @@ private:
|
||||||
// <fieldoffset, init> pairs.
|
// <fieldoffset, init> pairs.
|
||||||
std::vector<std::pair<int, std::unique_ptr<detail::FieldInit>>> creation_inits;
|
std::vector<std::pair<int, std::unique_ptr<detail::FieldInit>>> creation_inits;
|
||||||
|
|
||||||
|
class CreationInitsOptimizer;
|
||||||
friend zeek::RecordVal;
|
friend zeek::RecordVal;
|
||||||
const auto& DeferredInits() const { return deferred_inits; }
|
const auto& DeferredInits() const { return deferred_inits; }
|
||||||
const auto& CreationInits() const { return creation_inits; }
|
const auto& CreationInits() const { return creation_inits; }
|
||||||
|
|
|
@ -869,6 +869,8 @@ SetupResult setup(int argc, char** argv, Options* zopts)
|
||||||
if ( reporter->Errors() > 0 )
|
if ( reporter->Errors() > 0 )
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
|
RecordType::InitPostScript();
|
||||||
|
|
||||||
telemetry_mgr->InitPostScript();
|
telemetry_mgr->InitPostScript();
|
||||||
iosource_mgr->InitPostScript();
|
iosource_mgr->InitPostScript();
|
||||||
log_mgr->InitPostScript();
|
log_mgr->InitPostScript();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue