mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Merge remote-tracking branch 'origin/topic/vern/zam-rec-constr-opt2'
* origin/topic/vern/zam-rec-constr-opt2: ZAM optimizations for record creation
This commit is contained in:
commit
b586b59b69
10 changed files with 350 additions and 208 deletions
8
CHANGES
8
CHANGES
|
@ -1,3 +1,11 @@
|
||||||
|
6.2.0-dev.473 | 2024-01-25 20:54:56 +0100
|
||||||
|
|
||||||
|
* ZAM optimizations for record creation (Vern Paxson, Corelight)
|
||||||
|
|
||||||
|
includes reworking of managing "auxiliary" information for ZAM instructions
|
||||||
|
|
||||||
|
* testing/external: Revert commit hash for zeek-testing (Arne Welzel, Corelight)
|
||||||
|
|
||||||
6.2.0-dev.470 | 2024-01-25 12:25:57 +0100
|
6.2.0-dev.470 | 2024-01-25 12:25:57 +0100
|
||||||
|
|
||||||
* GH-3256: Intel: Introduce Intel::seen_policy() hook (Arne Welzel, Corelight)
|
* GH-3256: Intel: Introduce Intel::seen_policy() hook (Arne Welzel, Corelight)
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
6.2.0-dev.470
|
6.2.0-dev.473
|
||||||
|
|
14
src/Type.cc
14
src/Type.cc
|
@ -1059,20 +1059,20 @@ void RecordType::AddField(unsigned int field, const TypeDecl* td) {
|
||||||
auto def_attr = a ? a->Find(detail::ATTR_DEFAULT) : nullptr;
|
auto def_attr = a ? a->Find(detail::ATTR_DEFAULT) : nullptr;
|
||||||
auto def_expr = def_attr ? def_attr->GetExpr() : nullptr;
|
auto def_expr = def_attr ? def_attr->GetExpr() : nullptr;
|
||||||
|
|
||||||
std::unique_ptr<detail::FieldInit> init;
|
std::shared_ptr<detail::FieldInit> init;
|
||||||
|
|
||||||
if ( def_expr && ! IsErrorType(type->Tag()) ) {
|
if ( def_expr && ! IsErrorType(type->Tag()) ) {
|
||||||
if ( def_expr->Tag() == detail::EXPR_CONST ) {
|
if ( def_expr->Tag() == detail::EXPR_CONST ) {
|
||||||
auto zv = ZVal(def_expr->Eval(nullptr), type);
|
auto zv = ZVal(def_expr->Eval(nullptr), type);
|
||||||
|
|
||||||
if ( ZVal::IsManagedType(type) )
|
if ( ZVal::IsManagedType(type) )
|
||||||
init = std::make_unique<detail::DirectManagedFieldInit>(zv);
|
init = std::make_shared<detail::DirectManagedFieldInit>(zv);
|
||||||
else
|
else
|
||||||
init = std::make_unique<detail::DirectFieldInit>(zv);
|
init = std::make_shared<detail::DirectFieldInit>(zv);
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
auto efi = std::make_unique<detail::ExprFieldInit>(def_expr, type);
|
auto efi = std::make_shared<detail::ExprFieldInit>(def_expr, type);
|
||||||
creation_inits.emplace_back(field, std::move(efi));
|
creation_inits.emplace_back(field, std::move(efi));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1086,15 +1086,15 @@ void RecordType::AddField(unsigned int field, const TypeDecl* td) {
|
||||||
// and RecordType::CreationInitisOptimizer.
|
// and RecordType::CreationInitisOptimizer.
|
||||||
//
|
//
|
||||||
// init (nil) is appended to deferred_inits as placeholder.
|
// init (nil) is appended to deferred_inits as placeholder.
|
||||||
auto rfi = std::make_unique<detail::RecordFieldInit>(cast_intrusive<RecordType>(type));
|
auto rfi = std::make_shared<detail::RecordFieldInit>(cast_intrusive<RecordType>(type));
|
||||||
creation_inits.emplace_back(field, std::move(rfi));
|
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_shared<detail::TableFieldInit>(cast_intrusive<TableType>(type), a);
|
||||||
|
|
||||||
else if ( tag == TYPE_VECTOR )
|
else if ( tag == TYPE_VECTOR )
|
||||||
init = std::make_unique<detail::VectorFieldInit>(cast_intrusive<VectorType>(type));
|
init = std::make_shared<detail::VectorFieldInit>(cast_intrusive<VectorType>(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
deferred_inits.push_back(std::move(init));
|
deferred_inits.push_back(std::move(init));
|
||||||
|
|
|
@ -30,10 +30,12 @@ using TableValPtr = IntrusivePtr<TableVal>;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
class Attributes;
|
||||||
class CompositeHash;
|
class CompositeHash;
|
||||||
class Expr;
|
class Expr;
|
||||||
class ListExpr;
|
class ListExpr;
|
||||||
class Attributes;
|
class ZAMCompiler;
|
||||||
|
|
||||||
using ListExprPtr = IntrusivePtr<ListExpr>;
|
using ListExprPtr = IntrusivePtr<ListExpr>;
|
||||||
|
|
||||||
// The following tracks how to initialize a given record field.
|
// The following tracks how to initialize a given record field.
|
||||||
|
@ -734,7 +736,7 @@ private:
|
||||||
// Field initializations that can be deferred to first access,
|
// Field initializations that can be deferred to first access,
|
||||||
// beneficial for fields that are separately initialized prior
|
// beneficial for fields that are separately initialized prior
|
||||||
// to first access. Nil pointers mean "skip initializing the field".
|
// to first access. Nil pointers mean "skip initializing the field".
|
||||||
std::vector<std::unique_ptr<detail::FieldInit>> deferred_inits;
|
std::vector<std::shared_ptr<detail::FieldInit>> deferred_inits;
|
||||||
|
|
||||||
// Field initializations that need to be done upon record creation,
|
// Field initializations that need to be done upon record creation,
|
||||||
// rather than deferred. These are expressions whose value might
|
// rather than deferred. These are expressions whose value might
|
||||||
|
@ -742,10 +744,11 @@ private:
|
||||||
//
|
//
|
||||||
// Such initializations are uncommon, so we represent them using
|
// Such initializations are uncommon, so we represent them using
|
||||||
// <fieldoffset, init> pairs.
|
// <fieldoffset, init> pairs.
|
||||||
std::vector<std::pair<int, std::unique_ptr<detail::FieldInit>>> creation_inits;
|
std::vector<std::pair<int, std::shared_ptr<detail::FieldInit>>> creation_inits;
|
||||||
|
|
||||||
class CreationInitsOptimizer;
|
class CreationInitsOptimizer;
|
||||||
friend zeek::RecordVal;
|
friend zeek::RecordVal;
|
||||||
|
friend zeek::detail::ZAMCompiler;
|
||||||
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; }
|
||||||
|
|
||||||
|
|
10
src/Val.cc
10
src/Val.cc
|
@ -2784,7 +2784,6 @@ TableVal::TableRecordDependencies TableVal::parse_time_table_record_dependencies
|
||||||
RecordVal::RecordTypeValMap RecordVal::parse_time_records;
|
RecordVal::RecordTypeValMap RecordVal::parse_time_records;
|
||||||
|
|
||||||
RecordVal::RecordVal(RecordTypePtr t, bool init_fields) : Val(t), is_managed(t->ManagedFields()) {
|
RecordVal::RecordVal(RecordTypePtr t, bool init_fields) : Val(t), is_managed(t->ManagedFields()) {
|
||||||
origin = nullptr;
|
|
||||||
rt = std::move(t);
|
rt = std::move(t);
|
||||||
|
|
||||||
int n = rt->NumFields();
|
int n = rt->NumFields();
|
||||||
|
@ -2810,6 +2809,12 @@ RecordVal::RecordVal(RecordTypePtr t, bool init_fields) : Val(t), is_managed(t->
|
||||||
record_val.reserve(n);
|
record_val.reserve(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RecordVal::RecordVal(RecordTypePtr t, std::vector<std::optional<ZVal>> init_vals)
|
||||||
|
: Val(t), is_managed(t->ManagedFields()) {
|
||||||
|
rt = std::move(t);
|
||||||
|
record_val = std::move(init_vals);
|
||||||
|
}
|
||||||
|
|
||||||
RecordVal::~RecordVal() {
|
RecordVal::~RecordVal() {
|
||||||
auto n = record_val.size();
|
auto n = record_val.size();
|
||||||
|
|
||||||
|
@ -3016,11 +3021,10 @@ void RecordVal::DescribeReST(ODesc* d) const {
|
||||||
ValPtr RecordVal::DoClone(CloneState* state) {
|
ValPtr RecordVal::DoClone(CloneState* state) {
|
||||||
// We set origin to 0 here. Origin only seems to be used for exactly one
|
// We set origin to 0 here. Origin only seems to be used for exactly one
|
||||||
// purpose - to find the connection record that is associated with a
|
// purpose - to find the connection record that is associated with a
|
||||||
// record. As we cannot guarantee that it will ber zeroed out at the
|
// record. As we cannot guarantee that it will be zeroed out at the
|
||||||
// appropriate time (as it seems to be guaranteed for the original record)
|
// appropriate time (as it seems to be guaranteed for the original record)
|
||||||
// we don't touch it.
|
// we don't touch it.
|
||||||
auto rv = make_intrusive<RecordVal>(rt, false);
|
auto rv = make_intrusive<RecordVal>(rt, false);
|
||||||
rv->origin = nullptr;
|
|
||||||
state->NewClone(this, rv);
|
state->NewClone(this, rv);
|
||||||
|
|
||||||
int n = NumFields();
|
int n = NumFields();
|
||||||
|
|
|
@ -1392,6 +1392,10 @@ protected:
|
||||||
friend class zeek::detail::CPPRuntime;
|
friend class zeek::detail::CPPRuntime;
|
||||||
friend class zeek::detail::CompositeHash;
|
friend class zeek::detail::CompositeHash;
|
||||||
|
|
||||||
|
// Constructor for use by script optimization, directly initializing
|
||||||
|
// record_vals from the second argument.
|
||||||
|
RecordVal(RecordTypePtr t, std::vector<std::optional<ZVal>> init_vals);
|
||||||
|
|
||||||
RecordValPtr DoCoerceTo(RecordTypePtr other, bool allow_orphaning) const;
|
RecordValPtr DoCoerceTo(RecordTypePtr other, bool allow_orphaning) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1436,7 +1440,7 @@ protected:
|
||||||
|
|
||||||
void AddedField(int field) { Modified(); }
|
void AddedField(int field) { Modified(); }
|
||||||
|
|
||||||
Obj* origin;
|
Obj* origin = nullptr;
|
||||||
|
|
||||||
using RecordTypeValMap = std::unordered_map<RecordType*, std::vector<RecordValPtr>>;
|
using RecordTypeValMap = std::unordered_map<RecordType*, std::vector<RecordValPtr>>;
|
||||||
static RecordTypeValMap parse_time_records;
|
static RecordTypeValMap parse_time_records;
|
||||||
|
|
|
@ -432,26 +432,27 @@ void ZAMCompiler::ComputeFrameLifetimes() {
|
||||||
case OP_LAMBDA_VV: {
|
case OP_LAMBDA_VV: {
|
||||||
auto aux = inst->aux;
|
auto aux = inst->aux;
|
||||||
int n = aux->n;
|
int n = aux->n;
|
||||||
auto& slots = aux->slots;
|
for ( int i = 0; i < n; ++i ) {
|
||||||
for ( int i = 0; i < n; ++i )
|
auto slot_i = aux->elems[i].Slot();
|
||||||
if ( slots[i] >= 0 )
|
if ( slot_i >= 0 )
|
||||||
ExtendLifetime(slots[i], EndOfLoop(inst, 1));
|
ExtendLifetime(slot_i, EndOfLoop(inst, 1));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Look for slots in auxiliary information.
|
// Look for slots in auxiliary information.
|
||||||
auto aux = inst->aux;
|
auto aux = inst->aux;
|
||||||
if ( ! aux || ! aux->slots )
|
if ( ! aux || ! aux->elems_has_slots )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
int n = aux->n;
|
int n = aux->n;
|
||||||
auto& slots = aux->slots;
|
|
||||||
for ( auto j = 0; j < n; ++j ) {
|
for ( auto j = 0; j < n; ++j ) {
|
||||||
if ( slots[j] < 0 )
|
auto slot_j = aux->elems[j].Slot();
|
||||||
|
if ( slot_j < 0 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ExtendLifetime(slots[j], EndOfLoop(inst, 1));
|
ExtendLifetime(slot_j, EndOfLoop(inst, 1));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -562,11 +563,11 @@ void ZAMCompiler::ReMapFrame() {
|
||||||
default:
|
default:
|
||||||
// Update slots in auxiliary information.
|
// Update slots in auxiliary information.
|
||||||
auto aux = inst->aux;
|
auto aux = inst->aux;
|
||||||
if ( ! aux || ! aux->slots )
|
if ( ! aux || ! aux->elems_has_slots )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
for ( auto j = 0; j < aux->n; ++j ) {
|
for ( auto j = 0; j < aux->n; ++j ) {
|
||||||
auto& slot = aux->slots[j];
|
auto slot = aux->elems[j].Slot();
|
||||||
|
|
||||||
if ( slot < 0 )
|
if ( slot < 0 )
|
||||||
// This is instead a constant.
|
// This is instead a constant.
|
||||||
|
@ -581,7 +582,7 @@ void ZAMCompiler::ReMapFrame() {
|
||||||
frame_denizens[slot]->Name());
|
frame_denizens[slot]->Name());
|
||||||
}
|
}
|
||||||
|
|
||||||
slot = new_slot;
|
aux->elems[j].SetSlot(new_slot);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -858,9 +859,9 @@ bool ZAMCompiler::VarIsUsed(int slot) const {
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
auto aux = inst->aux;
|
auto aux = inst->aux;
|
||||||
if ( aux && aux->slots ) {
|
if ( aux && aux->elems_has_slots ) {
|
||||||
for ( int j = 0; j < aux->n; ++j )
|
for ( int j = 0; j < aux->n; ++j )
|
||||||
if ( aux->slots[j] == slot )
|
if ( aux->elems[j].Slot() == slot )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1100,23 +1100,84 @@ const ZAMStmt ZAMCompiler::ConstructSet(const NameExpr* n, const Expr* e) {
|
||||||
|
|
||||||
const ZAMStmt ZAMCompiler::ConstructRecord(const NameExpr* n, const Expr* e) {
|
const ZAMStmt ZAMCompiler::ConstructRecord(const NameExpr* n, const Expr* e) {
|
||||||
auto rc = e->AsRecordConstructorExpr();
|
auto rc = e->AsRecordConstructorExpr();
|
||||||
|
auto rt = e->GetType()->AsRecordType();
|
||||||
|
|
||||||
ZInstI z;
|
auto aux = InternalBuildVals(rc->Op().get());
|
||||||
|
|
||||||
if ( rc->Map() ) {
|
// Note that we set the vector to the full size of the record being
|
||||||
z = GenInst(OP_CONSTRUCT_KNOWN_RECORD_V, n);
|
// constructed, *not* the size of any map (which could be smaller).
|
||||||
z.aux = InternalBuildVals(rc->Op().get());
|
// This is because we want to provide the vector directly to the
|
||||||
z.aux->map = *rc->Map();
|
// constructor.
|
||||||
}
|
aux->zvec.resize(rt->NumFields());
|
||||||
else {
|
|
||||||
z = GenInst(OP_CONSTRUCT_RECORD_V, n);
|
if ( pfs->HasSideEffects(SideEffectsOp::CONSTRUCTION, e->GetType()) )
|
||||||
z.aux = InternalBuildVals(rc->Op().get());
|
aux->can_change_non_locals = true;
|
||||||
|
|
||||||
|
ZOp op;
|
||||||
|
|
||||||
|
const auto& map = rc->Map();
|
||||||
|
if ( map ) {
|
||||||
|
aux->map = *map;
|
||||||
|
|
||||||
|
auto fi = std::make_unique<std::vector<std::pair<int, std::shared_ptr<detail::FieldInit>>>>();
|
||||||
|
|
||||||
|
// Populate the field inits as needed.
|
||||||
|
for ( auto& c : rt->CreationInits() ) {
|
||||||
|
bool seen = false;
|
||||||
|
for ( auto r : *map )
|
||||||
|
if ( c.first == r ) {
|
||||||
|
// Superseded by a constructor element;
|
||||||
|
seen = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! seen )
|
||||||
|
// Need to generate field dynamically.
|
||||||
|
fi->push_back(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( fi->empty() )
|
||||||
|
op = OP_CONSTRUCT_KNOWN_RECORD_V;
|
||||||
|
else {
|
||||||
|
op = OP_CONSTRUCT_KNOWN_RECORD_WITH_INITS_V;
|
||||||
|
aux->field_inits = std::move(fi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
op = OP_CONSTRUCT_DIRECT_RECORD_V;
|
||||||
|
|
||||||
|
ZInstI z = GenInst(op, n);
|
||||||
|
|
||||||
|
z.aux = aux;
|
||||||
z.t = e->GetType();
|
z.t = e->GetType();
|
||||||
|
|
||||||
if ( pfs->HasSideEffects(SideEffectsOp::CONSTRUCTION, z.t) )
|
auto inst = AddInst(z);
|
||||||
z.aux->can_change_non_locals = true;
|
|
||||||
|
// If one of the initialization values is an unspecified vector (which
|
||||||
|
// in general we can't know until run-time) then we'll need to
|
||||||
|
// "concretize" it. We first see whether this is a possibility, since
|
||||||
|
// it usually isn't, by counting up how many of the record fields are
|
||||||
|
// vectors.
|
||||||
|
std::vector<int> vector_fields; // holds indices of the vector fields
|
||||||
|
for ( int i = 0; i < z.aux->n; ++i ) {
|
||||||
|
auto field_ind = map ? (*map)[i] : i;
|
||||||
|
auto& field_t = rt->GetFieldType(field_ind);
|
||||||
|
if ( field_t->Tag() == TYPE_VECTOR && field_t->Yield()->Tag() != TYPE_ANY )
|
||||||
|
vector_fields.push_back(field_ind);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( vector_fields.empty() )
|
||||||
|
// Common case of no vector fields, we're done.
|
||||||
|
return inst;
|
||||||
|
|
||||||
|
// Need to add a separate instruction for concretizing the fields.
|
||||||
|
z = GenInst(OP_CONCRETIZE_VECTOR_FIELDS_V, n);
|
||||||
|
z.t = e->GetType();
|
||||||
|
int nf = static_cast<int>(vector_fields.size());
|
||||||
|
z.aux = new ZInstAux(nf);
|
||||||
|
z.aux->elems_has_slots = false; // we're storing field offsets, not slots
|
||||||
|
for ( int i = 0; i < nf; ++i )
|
||||||
|
z.aux->Add(i, vector_fields[i]);
|
||||||
|
|
||||||
return AddInst(z);
|
return AddInst(z);
|
||||||
}
|
}
|
||||||
|
@ -1212,7 +1273,7 @@ const ZAMStmt ZAMCompiler::RecordCoerce(const NameExpr* n, const Expr* e) {
|
||||||
z.aux->Add(i, map[i], nullptr);
|
z.aux->Add(i, map[i], nullptr);
|
||||||
|
|
||||||
// Mark the integer entries in z.aux as not being frame slots as usual.
|
// Mark the integer entries in z.aux as not being frame slots as usual.
|
||||||
z.aux->slots = nullptr;
|
z.aux->elems_has_slots = false;
|
||||||
|
|
||||||
if ( pfs->HasSideEffects(SideEffectsOp::CONSTRUCTION, e->GetType()) )
|
if ( pfs->HasSideEffects(SideEffectsOp::CONSTRUCTION, e->GetType()) )
|
||||||
z.aux->can_change_non_locals = true;
|
z.aux->can_change_non_locals = true;
|
||||||
|
|
|
@ -1198,35 +1198,48 @@ eval ConstructTableOrSetPre()
|
||||||
|
|
||||||
direct-unary-op Record-Constructor ConstructRecord
|
direct-unary-op Record-Constructor ConstructRecord
|
||||||
|
|
||||||
internal-op Construct-Record
|
macro ConstructRecordPost()
|
||||||
type V
|
|
||||||
eval EvalConstructRecord(, i)
|
|
||||||
|
|
||||||
macro EvalConstructRecord(map_init, map_accessor)
|
|
||||||
auto rt = cast_intrusive<RecordType>(z.t);
|
|
||||||
auto new_r = new RecordVal(rt);
|
|
||||||
auto aux = z.aux;
|
|
||||||
auto n = aux->n;
|
|
||||||
map_init
|
|
||||||
for ( auto i = 0; i < n; ++i )
|
|
||||||
{
|
|
||||||
auto v_i = aux->ToVal(frame, i);
|
|
||||||
auto ind = map_accessor;
|
|
||||||
if ( v_i && v_i->GetType()->Tag() == TYPE_VECTOR &&
|
|
||||||
v_i->GetType<VectorType>()->IsUnspecifiedVector() )
|
|
||||||
{
|
|
||||||
const auto& t_ind = rt->GetFieldType(ind);
|
|
||||||
v_i->AsVectorVal()->Concretize(t_ind->Yield());
|
|
||||||
}
|
|
||||||
new_r->Assign(ind, v_i);
|
|
||||||
}
|
|
||||||
auto& r = frame[z.v1].record_val;
|
auto& r = frame[z.v1].record_val;
|
||||||
Unref(r);
|
Unref(r);
|
||||||
r = new_r;
|
r = new RecordVal(cast_intrusive<RecordType>(z.t), init_vals);
|
||||||
|
|
||||||
internal-op Construct-Known-Record
|
op Construct-Direct-Record
|
||||||
type V
|
type V
|
||||||
eval EvalConstructRecord(auto& map = aux->map;, map[i])
|
eval auto& init_vals = z.aux->ToZValVec(frame);
|
||||||
|
ConstructRecordPost()
|
||||||
|
|
||||||
|
op Construct-Known-Record
|
||||||
|
type V
|
||||||
|
eval auto& init_vals = z.aux->ToZValVecWithMap(frame);
|
||||||
|
ConstructRecordPost()
|
||||||
|
|
||||||
|
op Construct-Known-Record-With-Inits
|
||||||
|
type V
|
||||||
|
eval auto& init_vals = z.aux->ToZValVecWithMap(frame);
|
||||||
|
for ( auto& fi : *z.aux->field_inits )
|
||||||
|
init_vals[fi.first] = fi.second->Generate();
|
||||||
|
ConstructRecordPost()
|
||||||
|
|
||||||
|
# Special instruction for concretizing vectors that are fields in a
|
||||||
|
# newly-constructed record. "aux" holds which fields in the record to
|
||||||
|
# inspect.
|
||||||
|
op Concretize-Vector-Fields
|
||||||
|
op1-read
|
||||||
|
type V
|
||||||
|
eval auto rt = cast_intrusive<RecordType>(z.t);
|
||||||
|
auto r = frame[z.v1].record_val;
|
||||||
|
auto aux = z.aux;
|
||||||
|
auto n = aux->n;
|
||||||
|
for ( auto i = 0; i < n; ++i )
|
||||||
|
{
|
||||||
|
auto v_i = r->GetField(aux->elems[i].IntVal());
|
||||||
|
ASSERT(v_i);
|
||||||
|
if ( v_i->GetType<VectorType>()->IsUnspecifiedVector() )
|
||||||
|
{
|
||||||
|
const auto& t_i = rt->GetFieldType(i);
|
||||||
|
v_i->AsVectorVal()->Concretize(t_i->Yield());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
direct-unary-op Vector-Constructor ConstructVector
|
direct-unary-op Vector-Constructor ConstructVector
|
||||||
|
|
||||||
|
@ -1757,21 +1770,21 @@ internal-op Event3
|
||||||
type VVV
|
type VVV
|
||||||
op1-read
|
op1-read
|
||||||
eval ValVec args(3);
|
eval ValVec args(3);
|
||||||
|
auto& aux = z.aux;
|
||||||
args[0] = frame[z.v1].ToVal(z.t);
|
args[0] = frame[z.v1].ToVal(z.t);
|
||||||
args[1] = frame[z.v2].ToVal(z.t2);
|
args[1] = frame[z.v2].ToVal(z.t2);
|
||||||
auto types = z.aux->types;
|
args[2] = frame[z.v3].ToVal(aux->elems[2].GetType());
|
||||||
args[2] = frame[z.v3].ToVal(types[2]);
|
|
||||||
QueueEvent(z.event_handler, args);
|
QueueEvent(z.event_handler, args);
|
||||||
|
|
||||||
internal-op Event4
|
internal-op Event4
|
||||||
type VVVV
|
type VVVV
|
||||||
op1-read
|
op1-read
|
||||||
eval ValVec args(4);
|
eval ValVec args(4);
|
||||||
|
auto& aux = z.aux;
|
||||||
args[0] = frame[z.v1].ToVal(z.t);
|
args[0] = frame[z.v1].ToVal(z.t);
|
||||||
args[1] = frame[z.v2].ToVal(z.t2);
|
args[1] = frame[z.v2].ToVal(z.t2);
|
||||||
auto types = z.aux->types;
|
args[2] = frame[z.v3].ToVal(aux->elems[2].GetType());
|
||||||
args[2] = frame[z.v3].ToVal(types[2]);
|
args[3] = frame[z.v4].ToVal(aux->elems[3].GetType());
|
||||||
args[3] = frame[z.v4].ToVal(types[3]);
|
|
||||||
QueueEvent(z.event_handler, args);
|
QueueEvent(z.event_handler, args);
|
||||||
|
|
||||||
|
|
||||||
|
@ -2256,11 +2269,11 @@ eval auto& aux = z.aux;
|
||||||
auto captures = std::make_unique<std::vector<ZVal>>();
|
auto captures = std::make_unique<std::vector<ZVal>>();
|
||||||
for ( auto i = 0; i < aux->n; ++i )
|
for ( auto i = 0; i < aux->n; ++i )
|
||||||
{
|
{
|
||||||
auto slot = aux->slots[i];
|
auto slot = aux->elems[i].Slot();
|
||||||
if ( slot >= 0 )
|
if ( slot >= 0 )
|
||||||
{
|
{
|
||||||
auto& cp = frame[aux->slots[i]];
|
auto& cp = frame[slot];
|
||||||
if ( aux->is_managed[i] )
|
if ( aux->elems[i].IsManaged() )
|
||||||
zeek::Ref(cp.ManagedVal());
|
zeek::Ref(cp.ManagedVal());
|
||||||
captures->push_back(cp);
|
captures->push_back(cp);
|
||||||
}
|
}
|
||||||
|
@ -2355,7 +2368,7 @@ eval LogWritePre(frame[z.v2].ToVal(log_ID_enum_type), v3)
|
||||||
internal-op Log-WriteC
|
internal-op Log-WriteC
|
||||||
side-effects OP_LOG_WRITEC_V OP_V
|
side-effects OP_LOG_WRITEC_V OP_V
|
||||||
type VV
|
type VV
|
||||||
eval LogWritePre(z.aux->constants[0], v2)
|
eval LogWritePre(z.aux->elems[0].Constant(), v2)
|
||||||
LogWriteResPost()
|
LogWriteResPost()
|
||||||
|
|
||||||
# Versions that discard the return value.
|
# Versions that discard the return value.
|
||||||
|
@ -2370,7 +2383,7 @@ internal-op Log-WriteC
|
||||||
side-effects
|
side-effects
|
||||||
op1-read
|
op1-read
|
||||||
type V
|
type V
|
||||||
eval LogWritePre(z.aux->constants[0], v1)
|
eval LogWritePre(z.aux->elems[0].Constant(), v1)
|
||||||
LogWriteNoResPost()
|
LogWriteNoResPost()
|
||||||
|
|
||||||
internal-op Broker-Flush-Logs
|
internal-op Broker-Flush-Logs
|
||||||
|
@ -2460,23 +2473,21 @@ eval Cat1FullVal(frame[z.v2])
|
||||||
internal-op CatN
|
internal-op CatN
|
||||||
type V
|
type V
|
||||||
eval auto aux = z.aux;
|
eval auto aux = z.aux;
|
||||||
auto slots = z.aux->slots;
|
|
||||||
auto& ca = aux->cat_args;
|
auto& ca = aux->cat_args;
|
||||||
int n = aux->n;
|
int n = aux->n;
|
||||||
size_t max_size = 0;
|
size_t max_size = 0;
|
||||||
for ( int i = 0; i < n; ++i )
|
for ( int i = 0; i < n; ++i )
|
||||||
max_size += ca[i]->MaxSize(frame, slots[i]);
|
max_size += ca[i]->MaxSize(frame, aux->elems[i].Slot());
|
||||||
auto res = new char[max_size + /* slop */ n + 1];
|
auto res = new char[max_size + /* slop */ n + 1];
|
||||||
auto res_p = res;
|
auto res_p = res;
|
||||||
for ( int i = 0; i < n; ++i )
|
for ( int i = 0; i < n; ++i )
|
||||||
ca[i]->RenderInto(frame, slots[i], res_p);
|
ca[i]->RenderInto(frame, aux->elems[i].Slot(), res_p);
|
||||||
*res_p = '\0';
|
*res_p = '\0';
|
||||||
auto s = new String(true, reinterpret_cast<byte_vec>(res), res_p - res);
|
auto s = new String(true, reinterpret_cast<byte_vec>(res), res_p - res);
|
||||||
Cat1Op(ZVal(new StringVal(s)))
|
Cat1Op(ZVal(new StringVal(s)))
|
||||||
|
|
||||||
macro CatNPre()
|
macro CatNPre()
|
||||||
auto aux = z.aux;
|
auto aux = z.aux;
|
||||||
auto slots = z.aux->slots;
|
|
||||||
auto& ca = aux->cat_args;
|
auto& ca = aux->cat_args;
|
||||||
|
|
||||||
macro CatNMid()
|
macro CatNMid()
|
||||||
|
@ -2491,113 +2502,113 @@ macro CatNPost()
|
||||||
internal-op Cat2
|
internal-op Cat2
|
||||||
type V
|
type V
|
||||||
eval CatNPre()
|
eval CatNPre()
|
||||||
size_t max_size = ca[0]->MaxSize(frame, slots[0]);
|
size_t max_size = ca[0]->MaxSize(frame, aux->elems[0].Slot());
|
||||||
max_size += ca[1]->MaxSize(frame, slots[1]);
|
max_size += ca[1]->MaxSize(frame, aux->elems[1].Slot());
|
||||||
CatNMid()
|
CatNMid()
|
||||||
ca[0]->RenderInto(frame, slots[0], res_p);
|
ca[0]->RenderInto(frame, aux->elems[0].Slot(), res_p);
|
||||||
ca[1]->RenderInto(frame, slots[1], res_p);
|
ca[1]->RenderInto(frame, aux->elems[1].Slot(), res_p);
|
||||||
CatNPost()
|
CatNPost()
|
||||||
|
|
||||||
internal-op Cat3
|
internal-op Cat3
|
||||||
type V
|
type V
|
||||||
eval CatNPre()
|
eval CatNPre()
|
||||||
size_t max_size = ca[0]->MaxSize(frame, slots[0]);
|
size_t max_size = ca[0]->MaxSize(frame, aux->elems[0].Slot());
|
||||||
max_size += ca[1]->MaxSize(frame, slots[1]);
|
max_size += ca[1]->MaxSize(frame, aux->elems[1].Slot());
|
||||||
max_size += ca[2]->MaxSize(frame, slots[2]);
|
max_size += ca[2]->MaxSize(frame, aux->elems[2].Slot());
|
||||||
CatNMid()
|
CatNMid()
|
||||||
ca[0]->RenderInto(frame, slots[0], res_p);
|
ca[0]->RenderInto(frame, aux->elems[0].Slot(), res_p);
|
||||||
ca[1]->RenderInto(frame, slots[1], res_p);
|
ca[1]->RenderInto(frame, aux->elems[1].Slot(), res_p);
|
||||||
ca[2]->RenderInto(frame, slots[2], res_p);
|
ca[2]->RenderInto(frame, aux->elems[2].Slot(), res_p);
|
||||||
CatNPost()
|
CatNPost()
|
||||||
|
|
||||||
internal-op Cat4
|
internal-op Cat4
|
||||||
type V
|
type V
|
||||||
eval CatNPre()
|
eval CatNPre()
|
||||||
size_t max_size = ca[0]->MaxSize(frame, slots[0]);
|
size_t max_size = ca[0]->MaxSize(frame, aux->elems[0].Slot());
|
||||||
max_size += ca[1]->MaxSize(frame, slots[1]);
|
max_size += ca[1]->MaxSize(frame, aux->elems[1].Slot());
|
||||||
max_size += ca[2]->MaxSize(frame, slots[2]);
|
max_size += ca[2]->MaxSize(frame, aux->elems[2].Slot());
|
||||||
max_size += ca[3]->MaxSize(frame, slots[3]);
|
max_size += ca[3]->MaxSize(frame, aux->elems[3].Slot());
|
||||||
CatNMid()
|
CatNMid()
|
||||||
ca[0]->RenderInto(frame, slots[0], res_p);
|
ca[0]->RenderInto(frame, aux->elems[0].Slot(), res_p);
|
||||||
ca[1]->RenderInto(frame, slots[1], res_p);
|
ca[1]->RenderInto(frame, aux->elems[1].Slot(), res_p);
|
||||||
ca[2]->RenderInto(frame, slots[2], res_p);
|
ca[2]->RenderInto(frame, aux->elems[2].Slot(), res_p);
|
||||||
ca[3]->RenderInto(frame, slots[3], res_p);
|
ca[3]->RenderInto(frame, aux->elems[3].Slot(), res_p);
|
||||||
CatNPost()
|
CatNPost()
|
||||||
|
|
||||||
internal-op Cat5
|
internal-op Cat5
|
||||||
type V
|
type V
|
||||||
eval CatNPre()
|
eval CatNPre()
|
||||||
size_t max_size = ca[0]->MaxSize(frame, slots[0]);
|
size_t max_size = ca[0]->MaxSize(frame, aux->elems[0].Slot());
|
||||||
max_size += ca[1]->MaxSize(frame, slots[1]);
|
max_size += ca[1]->MaxSize(frame, aux->elems[1].Slot());
|
||||||
max_size += ca[2]->MaxSize(frame, slots[2]);
|
max_size += ca[2]->MaxSize(frame, aux->elems[2].Slot());
|
||||||
max_size += ca[3]->MaxSize(frame, slots[3]);
|
max_size += ca[3]->MaxSize(frame, aux->elems[3].Slot());
|
||||||
max_size += ca[4]->MaxSize(frame, slots[4]);
|
max_size += ca[4]->MaxSize(frame, aux->elems[4].Slot());
|
||||||
CatNMid()
|
CatNMid()
|
||||||
ca[0]->RenderInto(frame, slots[0], res_p);
|
ca[0]->RenderInto(frame, aux->elems[0].Slot(), res_p);
|
||||||
ca[1]->RenderInto(frame, slots[1], res_p);
|
ca[1]->RenderInto(frame, aux->elems[1].Slot(), res_p);
|
||||||
ca[2]->RenderInto(frame, slots[2], res_p);
|
ca[2]->RenderInto(frame, aux->elems[2].Slot(), res_p);
|
||||||
ca[3]->RenderInto(frame, slots[3], res_p);
|
ca[3]->RenderInto(frame, aux->elems[3].Slot(), res_p);
|
||||||
ca[4]->RenderInto(frame, slots[4], res_p);
|
ca[4]->RenderInto(frame, aux->elems[4].Slot(), res_p);
|
||||||
CatNPost()
|
CatNPost()
|
||||||
|
|
||||||
internal-op Cat6
|
internal-op Cat6
|
||||||
type V
|
type V
|
||||||
eval CatNPre()
|
eval CatNPre()
|
||||||
size_t max_size = ca[0]->MaxSize(frame, slots[0]);
|
size_t max_size = ca[0]->MaxSize(frame, aux->elems[0].Slot());
|
||||||
max_size += ca[1]->MaxSize(frame, slots[1]);
|
max_size += ca[1]->MaxSize(frame, aux->elems[1].Slot());
|
||||||
max_size += ca[2]->MaxSize(frame, slots[2]);
|
max_size += ca[2]->MaxSize(frame, aux->elems[2].Slot());
|
||||||
max_size += ca[3]->MaxSize(frame, slots[3]);
|
max_size += ca[3]->MaxSize(frame, aux->elems[3].Slot());
|
||||||
max_size += ca[4]->MaxSize(frame, slots[4]);
|
max_size += ca[4]->MaxSize(frame, aux->elems[4].Slot());
|
||||||
max_size += ca[5]->MaxSize(frame, slots[5]);
|
max_size += ca[5]->MaxSize(frame, aux->elems[5].Slot());
|
||||||
CatNMid()
|
CatNMid()
|
||||||
ca[0]->RenderInto(frame, slots[0], res_p);
|
ca[0]->RenderInto(frame, aux->elems[0].Slot(), res_p);
|
||||||
ca[1]->RenderInto(frame, slots[1], res_p);
|
ca[1]->RenderInto(frame, aux->elems[1].Slot(), res_p);
|
||||||
ca[2]->RenderInto(frame, slots[2], res_p);
|
ca[2]->RenderInto(frame, aux->elems[2].Slot(), res_p);
|
||||||
ca[3]->RenderInto(frame, slots[3], res_p);
|
ca[3]->RenderInto(frame, aux->elems[3].Slot(), res_p);
|
||||||
ca[4]->RenderInto(frame, slots[4], res_p);
|
ca[4]->RenderInto(frame, aux->elems[4].Slot(), res_p);
|
||||||
ca[5]->RenderInto(frame, slots[5], res_p);
|
ca[5]->RenderInto(frame, aux->elems[5].Slot(), res_p);
|
||||||
CatNPost()
|
CatNPost()
|
||||||
|
|
||||||
internal-op Cat7
|
internal-op Cat7
|
||||||
type V
|
type V
|
||||||
eval CatNPre()
|
eval CatNPre()
|
||||||
size_t max_size = ca[0]->MaxSize(frame, slots[0]);
|
size_t max_size = ca[0]->MaxSize(frame, aux->elems[0].Slot());
|
||||||
max_size += ca[1]->MaxSize(frame, slots[1]);
|
max_size += ca[1]->MaxSize(frame, aux->elems[1].Slot());
|
||||||
max_size += ca[2]->MaxSize(frame, slots[2]);
|
max_size += ca[2]->MaxSize(frame, aux->elems[2].Slot());
|
||||||
max_size += ca[3]->MaxSize(frame, slots[3]);
|
max_size += ca[3]->MaxSize(frame, aux->elems[3].Slot());
|
||||||
max_size += ca[4]->MaxSize(frame, slots[4]);
|
max_size += ca[4]->MaxSize(frame, aux->elems[4].Slot());
|
||||||
max_size += ca[5]->MaxSize(frame, slots[5]);
|
max_size += ca[5]->MaxSize(frame, aux->elems[5].Slot());
|
||||||
max_size += ca[6]->MaxSize(frame, slots[6]);
|
max_size += ca[6]->MaxSize(frame, aux->elems[6].Slot());
|
||||||
CatNMid()
|
CatNMid()
|
||||||
ca[0]->RenderInto(frame, slots[0], res_p);
|
ca[0]->RenderInto(frame, aux->elems[0].Slot(), res_p);
|
||||||
ca[1]->RenderInto(frame, slots[1], res_p);
|
ca[1]->RenderInto(frame, aux->elems[1].Slot(), res_p);
|
||||||
ca[2]->RenderInto(frame, slots[2], res_p);
|
ca[2]->RenderInto(frame, aux->elems[2].Slot(), res_p);
|
||||||
ca[3]->RenderInto(frame, slots[3], res_p);
|
ca[3]->RenderInto(frame, aux->elems[3].Slot(), res_p);
|
||||||
ca[4]->RenderInto(frame, slots[4], res_p);
|
ca[4]->RenderInto(frame, aux->elems[4].Slot(), res_p);
|
||||||
ca[5]->RenderInto(frame, slots[5], res_p);
|
ca[5]->RenderInto(frame, aux->elems[5].Slot(), res_p);
|
||||||
ca[6]->RenderInto(frame, slots[6], res_p);
|
ca[6]->RenderInto(frame, aux->elems[6].Slot(), res_p);
|
||||||
CatNPost()
|
CatNPost()
|
||||||
|
|
||||||
internal-op Cat8
|
internal-op Cat8
|
||||||
type V
|
type V
|
||||||
eval CatNPre()
|
eval CatNPre()
|
||||||
size_t max_size = ca[0]->MaxSize(frame, slots[0]);
|
size_t max_size = ca[0]->MaxSize(frame, aux->elems[0].Slot());
|
||||||
max_size += ca[1]->MaxSize(frame, slots[1]);
|
max_size += ca[1]->MaxSize(frame, aux->elems[1].Slot());
|
||||||
max_size += ca[2]->MaxSize(frame, slots[2]);
|
max_size += ca[2]->MaxSize(frame, aux->elems[2].Slot());
|
||||||
max_size += ca[3]->MaxSize(frame, slots[3]);
|
max_size += ca[3]->MaxSize(frame, aux->elems[3].Slot());
|
||||||
max_size += ca[4]->MaxSize(frame, slots[4]);
|
max_size += ca[4]->MaxSize(frame, aux->elems[4].Slot());
|
||||||
max_size += ca[5]->MaxSize(frame, slots[5]);
|
max_size += ca[5]->MaxSize(frame, aux->elems[5].Slot());
|
||||||
max_size += ca[6]->MaxSize(frame, slots[6]);
|
max_size += ca[6]->MaxSize(frame, aux->elems[6].Slot());
|
||||||
max_size += ca[7]->MaxSize(frame, slots[7]);
|
max_size += ca[7]->MaxSize(frame, aux->elems[7].Slot());
|
||||||
CatNMid()
|
CatNMid()
|
||||||
ca[0]->RenderInto(frame, slots[0], res_p);
|
ca[0]->RenderInto(frame, aux->elems[0].Slot(), res_p);
|
||||||
ca[1]->RenderInto(frame, slots[1], res_p);
|
ca[1]->RenderInto(frame, aux->elems[1].Slot(), res_p);
|
||||||
ca[2]->RenderInto(frame, slots[2], res_p);
|
ca[2]->RenderInto(frame, aux->elems[2].Slot(), res_p);
|
||||||
ca[3]->RenderInto(frame, slots[3], res_p);
|
ca[3]->RenderInto(frame, aux->elems[3].Slot(), res_p);
|
||||||
ca[4]->RenderInto(frame, slots[4], res_p);
|
ca[4]->RenderInto(frame, aux->elems[4].Slot(), res_p);
|
||||||
ca[5]->RenderInto(frame, slots[5], res_p);
|
ca[5]->RenderInto(frame, aux->elems[5].Slot(), res_p);
|
||||||
ca[6]->RenderInto(frame, slots[6], res_p);
|
ca[6]->RenderInto(frame, aux->elems[6].Slot(), res_p);
|
||||||
ca[7]->RenderInto(frame, slots[7], res_p);
|
ca[7]->RenderInto(frame, aux->elems[7].Slot(), res_p);
|
||||||
CatNPost()
|
CatNPost()
|
||||||
|
|
||||||
internal-op Analyzer--Name
|
internal-op Analyzer--Name
|
||||||
|
|
|
@ -302,6 +302,65 @@ private:
|
||||||
void InitConst(const ConstExpr* ce);
|
void InitConst(const ConstExpr* ce);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Class for tracking one element of auxiliary information. This can be an
|
||||||
|
// integer, often specifying a frame slot, or a Val representing a constant.
|
||||||
|
// The class also tracks any associated type and caches whether it's "managed".
|
||||||
|
class AuxElem {
|
||||||
|
public:
|
||||||
|
AuxElem() {}
|
||||||
|
|
||||||
|
// Different ways of setting the specifics of the element.
|
||||||
|
void SetInt(int _i) { i = _i; }
|
||||||
|
void SetInt(int _i, TypePtr _t) {
|
||||||
|
i = _i;
|
||||||
|
SetType(_t);
|
||||||
|
}
|
||||||
|
void SetSlot(int slot) { i = slot; }
|
||||||
|
void SetConstant(ValPtr _c) {
|
||||||
|
c = std::move(_c);
|
||||||
|
// c might be null in some contexts.
|
||||||
|
if ( c ) {
|
||||||
|
SetType(c->GetType());
|
||||||
|
zc = ZVal(c, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the element as a Val object.
|
||||||
|
ValPtr ToVal(const ZVal* frame) const {
|
||||||
|
if ( c )
|
||||||
|
return c;
|
||||||
|
else
|
||||||
|
return frame[i].ToVal(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the element as a ZVal object.
|
||||||
|
ZVal ToZVal(const ZVal* frame) const {
|
||||||
|
ZVal zv = c ? zc : frame[i];
|
||||||
|
if ( is_managed )
|
||||||
|
Ref(zv.ManagedVal());
|
||||||
|
return zv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Slot() const { return i; }
|
||||||
|
int IntVal() const { return i; }
|
||||||
|
const ValPtr& Constant() const { return c; }
|
||||||
|
ZVal ZConstant() const { return zc; }
|
||||||
|
const TypePtr& GetType() const { return t; }
|
||||||
|
bool IsManaged() const { return is_managed; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SetType(TypePtr _t) {
|
||||||
|
t = std::move(_t);
|
||||||
|
is_managed = t ? ZVal::IsManagedType(t) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = -1; // -1 = "not a slot"
|
||||||
|
ValPtr c;
|
||||||
|
ZVal zc;
|
||||||
|
TypePtr t;
|
||||||
|
bool is_managed = false;
|
||||||
|
};
|
||||||
|
|
||||||
// Auxiliary information, used when the fixed ZInst layout lacks
|
// Auxiliary information, used when the fixed ZInst layout lacks
|
||||||
// sufficient expressiveness to represent all of the elements that
|
// sufficient expressiveness to represent all of the elements that
|
||||||
// an instruction needs.
|
// an instruction needs.
|
||||||
|
@ -311,53 +370,41 @@ public:
|
||||||
// tracking slots, constants, and types.
|
// tracking slots, constants, and types.
|
||||||
ZInstAux(int _n) {
|
ZInstAux(int _n) {
|
||||||
n = _n;
|
n = _n;
|
||||||
if ( n > 0 ) {
|
if ( n > 0 )
|
||||||
slots = ints = new int[n];
|
elems = new AuxElem[n];
|
||||||
constants = new ValPtr[n];
|
|
||||||
types = new TypePtr[n];
|
|
||||||
is_managed = new bool[n];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~ZInstAux() {
|
~ZInstAux() {
|
||||||
delete[] ints;
|
delete[] elems;
|
||||||
delete[] constants;
|
|
||||||
delete[] types;
|
|
||||||
delete[] is_managed;
|
|
||||||
delete[] cat_args;
|
delete[] cat_args;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the i'th element of the parallel arrays as a ValPtr.
|
// Returns the i'th element of the elements as a ValPtr.
|
||||||
ValPtr ToVal(const ZVal* frame, int i) const {
|
ValPtr ToVal(const ZVal* frame, int i) const { return elems[i].ToVal(frame); }
|
||||||
if ( constants[i] )
|
ZVal ToZVal(const ZVal* frame, int i) const { return elems[i].ToZVal(frame); }
|
||||||
return constants[i];
|
|
||||||
else
|
|
||||||
return frame[slots[i]].ToVal(types[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the parallel arrays as a ListValPtr.
|
// Returns the elements as a ListValPtr.
|
||||||
ListValPtr ToListVal(const ZVal* frame) const {
|
ListValPtr ToListVal(const ZVal* frame) const {
|
||||||
auto lv = make_intrusive<ListVal>(TYPE_ANY);
|
auto lv = make_intrusive<ListVal>(TYPE_ANY);
|
||||||
for ( auto i = 0; i < n; ++i )
|
for ( auto i = 0; i < n; ++i )
|
||||||
lv->Append(ToVal(frame, i));
|
lv->Append(elems[i].ToVal(frame));
|
||||||
|
|
||||||
return lv;
|
return lv;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts the parallel arrays to a ListValPtr suitable for
|
// Converts the elements to a ListValPtr suitable for use as indices
|
||||||
// use as indices for indexing a table or set. "offset" specifies
|
// for indexing a table or set. "offset" specifies which index we're
|
||||||
// which index we're looking for (there can be a bunch for
|
// looking for (there can be a bunch for constructors), and "width"
|
||||||
// constructors), and "width" the number of elements in a single
|
// the number of elements in a single index.
|
||||||
// index.
|
|
||||||
ListValPtr ToIndices(const ZVal* frame, int offset, int width) const {
|
ListValPtr ToIndices(const ZVal* frame, int offset, int width) const {
|
||||||
auto lv = make_intrusive<ListVal>(TYPE_ANY);
|
auto lv = make_intrusive<ListVal>(TYPE_ANY);
|
||||||
for ( auto i = 0; i < 0 + width; ++i )
|
for ( auto i = 0; i < 0 + width; ++i )
|
||||||
lv->Append(ToVal(frame, offset + i));
|
lv->Append(elems[offset + i].ToVal(frame));
|
||||||
|
|
||||||
return lv;
|
return lv;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the parallel arrays converted to a vector of ValPtr's.
|
// Returns the elements converted to a vector of ValPtr's.
|
||||||
const ValVec& ToValVec(const ZVal* frame) {
|
const ValVec& ToValVec(const ZVal* frame) {
|
||||||
vv.clear();
|
vv.clear();
|
||||||
FillValVec(vv, frame);
|
FillValVec(vv, frame);
|
||||||
|
@ -365,49 +412,45 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populates the given vector of ValPtr's with the conversion
|
// Populates the given vector of ValPtr's with the conversion
|
||||||
// of the parallel arrays.
|
// of the elements.
|
||||||
void FillValVec(ValVec& vec, const ZVal* frame) const {
|
void FillValVec(ValVec& vec, const ZVal* frame) const {
|
||||||
for ( auto i = 0; i < n; ++i )
|
for ( auto i = 0; i < n; ++i )
|
||||||
vec.push_back(ToVal(frame, i));
|
vec.push_back(elems[i].ToVal(frame));
|
||||||
}
|
}
|
||||||
|
|
||||||
// When building up a ZInstAux, sets one element of the parallel
|
// Returns the elements converted to a vector of ZVal's.
|
||||||
// arrays to a given frame slot and type.
|
const auto& ToZValVec(const ZVal* frame) {
|
||||||
void Add(int i, int slot, TypePtr t) {
|
for ( auto i = 0; i < n; ++i )
|
||||||
ints[i] = slot;
|
zvec[i] = elems[i].ToZVal(frame);
|
||||||
constants[i] = nullptr;
|
return zvec;
|
||||||
types[i] = t;
|
|
||||||
is_managed[i] = t ? ZVal::IsManagedType(t) : false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Same, but using the "map" to determine where to place the values.
|
||||||
|
// Returns a non-const value because in this situation other updates
|
||||||
|
// may be coming to the vector, too.
|
||||||
|
auto& ToZValVecWithMap(const ZVal* frame) {
|
||||||
|
for ( auto i = 0; i < n; ++i )
|
||||||
|
zvec[map[i]] = elems[i].ToZVal(frame);
|
||||||
|
return zvec;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When building up a ZInstAux, sets one element to a given frame slot
|
||||||
|
// and type.
|
||||||
|
void Add(int i, int slot, TypePtr t) { elems[i].SetInt(slot, t); }
|
||||||
|
|
||||||
|
// Same, but for non-slot integers.
|
||||||
|
void Add(int i, int v_i) { elems[i].SetInt(v_i); }
|
||||||
|
|
||||||
// Same but for constants.
|
// Same but for constants.
|
||||||
void Add(int i, ValPtr c) {
|
void Add(int i, ValPtr c) { elems[i].SetConstant(c); }
|
||||||
ints[i] = -1;
|
|
||||||
constants[i] = c;
|
|
||||||
types[i] = nullptr;
|
|
||||||
is_managed[i] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Member variables. We could add accessors for manipulating
|
// Member variables. We could add accessors for manipulating
|
||||||
// these (and make the variables private), but for convenience we
|
// these (and make the variables private), but for convenience we
|
||||||
// make them directly available.
|
// make them directly available.
|
||||||
|
|
||||||
// These are parallel arrays, used to build up lists of values.
|
int n; // size of elements
|
||||||
// Each element is either an integer or a constant. Usually the
|
AuxElem* elems = nullptr;
|
||||||
// integer is a frame slot (in which case "slots" points to "ints";
|
bool elems_has_slots = true;
|
||||||
// if not, it's nil).
|
|
||||||
//
|
|
||||||
// We track associated types, too, enabling us to use
|
|
||||||
// ZVal::ToVal to convert frame slots or constants to ValPtr's;
|
|
||||||
// and, as a performance optimization, whether those types
|
|
||||||
// indicate the slot needs to be managed.
|
|
||||||
|
|
||||||
int n; // size of arrays
|
|
||||||
int* slots = nullptr; // either nil or points to ints
|
|
||||||
int* ints = nullptr;
|
|
||||||
ValPtr* constants = nullptr;
|
|
||||||
TypePtr* types = nullptr;
|
|
||||||
bool* is_managed = nullptr;
|
|
||||||
|
|
||||||
// Ingredients associated with lambdas ...
|
// Ingredients associated with lambdas ...
|
||||||
ScriptFuncPtr primary_func;
|
ScriptFuncPtr primary_func;
|
||||||
|
@ -429,8 +472,8 @@ public:
|
||||||
// store here.
|
// store here.
|
||||||
bool can_change_non_locals = false;
|
bool can_change_non_locals = false;
|
||||||
|
|
||||||
// The following is only used for OP_CONSTRUCT_KNOWN_RECORD_V,
|
// The following is used for constructing records, to map elements in
|
||||||
// to map elements in slots/constants/types to record field offsets.
|
// slots/constants/types to record field offsets.
|
||||||
std::vector<int> map;
|
std::vector<int> map;
|
||||||
|
|
||||||
///// The following four apply to looping over the elements of tables.
|
///// The following four apply to looping over the elements of tables.
|
||||||
|
@ -453,6 +496,13 @@ public:
|
||||||
// If we cared about memory penny-pinching, we could make this
|
// If we cared about memory penny-pinching, we could make this
|
||||||
// a pointer and only instantiate as needed.
|
// a pointer and only instantiate as needed.
|
||||||
ValVec vv;
|
ValVec vv;
|
||||||
|
|
||||||
|
// Similar, but for ZVal's (used when constructing RecordVal's).
|
||||||
|
std::vector<std::optional<ZVal>> zvec;
|
||||||
|
|
||||||
|
// If non-nil, used for constructing records. Each pair gives the index
|
||||||
|
// into the final record and the associated field initializer.
|
||||||
|
std::unique_ptr<std::vector<std::pair<int, std::shared_ptr<detail::FieldInit>>>> field_inits;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns a human-readable version of the given ZAM op-code.
|
// Returns a human-readable version of the given ZAM op-code.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue