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
|
||||
|
||||
* 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_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->Tag() == detail::EXPR_CONST ) {
|
||||
auto zv = ZVal(def_expr->Eval(nullptr), type);
|
||||
|
||||
if ( ZVal::IsManagedType(type) )
|
||||
init = std::make_unique<detail::DirectManagedFieldInit>(zv);
|
||||
init = std::make_shared<detail::DirectManagedFieldInit>(zv);
|
||||
else
|
||||
init = std::make_unique<detail::DirectFieldInit>(zv);
|
||||
init = std::make_shared<detail::DirectFieldInit>(zv);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -1086,15 +1086,15 @@ void RecordType::AddField(unsigned int field, const TypeDecl* td) {
|
|||
// and RecordType::CreationInitisOptimizer.
|
||||
//
|
||||
// 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));
|
||||
}
|
||||
|
||||
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 )
|
||||
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));
|
||||
|
|
|
@ -30,10 +30,12 @@ using TableValPtr = IntrusivePtr<TableVal>;
|
|||
|
||||
namespace detail {
|
||||
|
||||
class Attributes;
|
||||
class CompositeHash;
|
||||
class Expr;
|
||||
class ListExpr;
|
||||
class Attributes;
|
||||
class ZAMCompiler;
|
||||
|
||||
using ListExprPtr = IntrusivePtr<ListExpr>;
|
||||
|
||||
// The following tracks how to initialize a given record field.
|
||||
|
@ -734,7 +736,7 @@ private:
|
|||
// Field initializations that can be deferred to first access,
|
||||
// beneficial for fields that are separately initialized prior
|
||||
// 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,
|
||||
// rather than deferred. These are expressions whose value might
|
||||
|
@ -742,10 +744,11 @@ private:
|
|||
//
|
||||
// Such initializations are uncommon, so we represent them using
|
||||
// <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;
|
||||
friend zeek::RecordVal;
|
||||
friend zeek::detail::ZAMCompiler;
|
||||
const auto& DeferredInits() const { return deferred_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::RecordVal(RecordTypePtr t, bool init_fields) : Val(t), is_managed(t->ManagedFields()) {
|
||||
origin = nullptr;
|
||||
rt = std::move(t);
|
||||
|
||||
int n = rt->NumFields();
|
||||
|
@ -2810,6 +2809,12 @@ RecordVal::RecordVal(RecordTypePtr t, bool init_fields) : Val(t), is_managed(t->
|
|||
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() {
|
||||
auto n = record_val.size();
|
||||
|
||||
|
@ -3016,11 +3021,10 @@ void RecordVal::DescribeReST(ODesc* d) const {
|
|||
ValPtr RecordVal::DoClone(CloneState* state) {
|
||||
// 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
|
||||
// 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)
|
||||
// we don't touch it.
|
||||
auto rv = make_intrusive<RecordVal>(rt, false);
|
||||
rv->origin = nullptr;
|
||||
state->NewClone(this, rv);
|
||||
|
||||
int n = NumFields();
|
||||
|
|
|
@ -1392,6 +1392,10 @@ protected:
|
|||
friend class zeek::detail::CPPRuntime;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -1436,7 +1440,7 @@ protected:
|
|||
|
||||
void AddedField(int field) { Modified(); }
|
||||
|
||||
Obj* origin;
|
||||
Obj* origin = nullptr;
|
||||
|
||||
using RecordTypeValMap = std::unordered_map<RecordType*, std::vector<RecordValPtr>>;
|
||||
static RecordTypeValMap parse_time_records;
|
||||
|
|
|
@ -432,26 +432,27 @@ void ZAMCompiler::ComputeFrameLifetimes() {
|
|||
case OP_LAMBDA_VV: {
|
||||
auto aux = inst->aux;
|
||||
int n = aux->n;
|
||||
auto& slots = aux->slots;
|
||||
for ( int i = 0; i < n; ++i )
|
||||
if ( slots[i] >= 0 )
|
||||
ExtendLifetime(slots[i], EndOfLoop(inst, 1));
|
||||
for ( int i = 0; i < n; ++i ) {
|
||||
auto slot_i = aux->elems[i].Slot();
|
||||
if ( slot_i >= 0 )
|
||||
ExtendLifetime(slot_i, EndOfLoop(inst, 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// Look for slots in auxiliary information.
|
||||
auto aux = inst->aux;
|
||||
if ( ! aux || ! aux->slots )
|
||||
if ( ! aux || ! aux->elems_has_slots )
|
||||
break;
|
||||
|
||||
int n = aux->n;
|
||||
auto& slots = aux->slots;
|
||||
for ( auto j = 0; j < n; ++j ) {
|
||||
if ( slots[j] < 0 )
|
||||
auto slot_j = aux->elems[j].Slot();
|
||||
if ( slot_j < 0 )
|
||||
continue;
|
||||
|
||||
ExtendLifetime(slots[j], EndOfLoop(inst, 1));
|
||||
ExtendLifetime(slot_j, EndOfLoop(inst, 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -562,11 +563,11 @@ void ZAMCompiler::ReMapFrame() {
|
|||
default:
|
||||
// Update slots in auxiliary information.
|
||||
auto aux = inst->aux;
|
||||
if ( ! aux || ! aux->slots )
|
||||
if ( ! aux || ! aux->elems_has_slots )
|
||||
break;
|
||||
|
||||
for ( auto j = 0; j < aux->n; ++j ) {
|
||||
auto& slot = aux->slots[j];
|
||||
auto slot = aux->elems[j].Slot();
|
||||
|
||||
if ( slot < 0 )
|
||||
// This is instead a constant.
|
||||
|
@ -581,7 +582,7 @@ void ZAMCompiler::ReMapFrame() {
|
|||
frame_denizens[slot]->Name());
|
||||
}
|
||||
|
||||
slot = new_slot;
|
||||
aux->elems[j].SetSlot(new_slot);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -858,9 +859,9 @@ bool ZAMCompiler::VarIsUsed(int slot) const {
|
|||
return true;
|
||||
|
||||
auto aux = inst->aux;
|
||||
if ( aux && aux->slots ) {
|
||||
if ( aux && aux->elems_has_slots ) {
|
||||
for ( int j = 0; j < aux->n; ++j )
|
||||
if ( aux->slots[j] == slot )
|
||||
if ( aux->elems[j].Slot() == slot )
|
||||
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) {
|
||||
auto rc = e->AsRecordConstructorExpr();
|
||||
auto rt = e->GetType()->AsRecordType();
|
||||
|
||||
ZInstI z;
|
||||
auto aux = InternalBuildVals(rc->Op().get());
|
||||
|
||||
if ( rc->Map() ) {
|
||||
z = GenInst(OP_CONSTRUCT_KNOWN_RECORD_V, n);
|
||||
z.aux = InternalBuildVals(rc->Op().get());
|
||||
z.aux->map = *rc->Map();
|
||||
// Note that we set the vector to the full size of the record being
|
||||
// constructed, *not* the size of any map (which could be smaller).
|
||||
// This is because we want to provide the vector directly to the
|
||||
// constructor.
|
||||
aux->zvec.resize(rt->NumFields());
|
||||
|
||||
if ( pfs->HasSideEffects(SideEffectsOp::CONSTRUCTION, e->GetType()) )
|
||||
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 {
|
||||
z = GenInst(OP_CONSTRUCT_RECORD_V, n);
|
||||
z.aux = InternalBuildVals(rc->Op().get());
|
||||
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();
|
||||
|
||||
if ( pfs->HasSideEffects(SideEffectsOp::CONSTRUCTION, z.t) )
|
||||
z.aux->can_change_non_locals = true;
|
||||
auto inst = AddInst(z);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
@ -1212,7 +1273,7 @@ const ZAMStmt ZAMCompiler::RecordCoerce(const NameExpr* n, const Expr* e) {
|
|||
z.aux->Add(i, map[i], nullptr);
|
||||
|
||||
// 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()) )
|
||||
z.aux->can_change_non_locals = true;
|
||||
|
|
|
@ -1198,35 +1198,48 @@ eval ConstructTableOrSetPre()
|
|||
|
||||
direct-unary-op Record-Constructor ConstructRecord
|
||||
|
||||
internal-op Construct-Record
|
||||
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);
|
||||
}
|
||||
macro ConstructRecordPost()
|
||||
auto& r = frame[z.v1].record_val;
|
||||
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
|
||||
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
|
||||
|
||||
|
@ -1757,21 +1770,21 @@ internal-op Event3
|
|||
type VVV
|
||||
op1-read
|
||||
eval ValVec args(3);
|
||||
auto& aux = z.aux;
|
||||
args[0] = frame[z.v1].ToVal(z.t);
|
||||
args[1] = frame[z.v2].ToVal(z.t2);
|
||||
auto types = z.aux->types;
|
||||
args[2] = frame[z.v3].ToVal(types[2]);
|
||||
args[2] = frame[z.v3].ToVal(aux->elems[2].GetType());
|
||||
QueueEvent(z.event_handler, args);
|
||||
|
||||
internal-op Event4
|
||||
type VVVV
|
||||
op1-read
|
||||
eval ValVec args(4);
|
||||
auto& aux = z.aux;
|
||||
args[0] = frame[z.v1].ToVal(z.t);
|
||||
args[1] = frame[z.v2].ToVal(z.t2);
|
||||
auto types = z.aux->types;
|
||||
args[2] = frame[z.v3].ToVal(types[2]);
|
||||
args[3] = frame[z.v4].ToVal(types[3]);
|
||||
args[2] = frame[z.v3].ToVal(aux->elems[2].GetType());
|
||||
args[3] = frame[z.v4].ToVal(aux->elems[3].GetType());
|
||||
QueueEvent(z.event_handler, args);
|
||||
|
||||
|
||||
|
@ -2256,11 +2269,11 @@ eval auto& aux = z.aux;
|
|||
auto captures = std::make_unique<std::vector<ZVal>>();
|
||||
for ( auto i = 0; i < aux->n; ++i )
|
||||
{
|
||||
auto slot = aux->slots[i];
|
||||
auto slot = aux->elems[i].Slot();
|
||||
if ( slot >= 0 )
|
||||
{
|
||||
auto& cp = frame[aux->slots[i]];
|
||||
if ( aux->is_managed[i] )
|
||||
auto& cp = frame[slot];
|
||||
if ( aux->elems[i].IsManaged() )
|
||||
zeek::Ref(cp.ManagedVal());
|
||||
captures->push_back(cp);
|
||||
}
|
||||
|
@ -2355,7 +2368,7 @@ eval LogWritePre(frame[z.v2].ToVal(log_ID_enum_type), v3)
|
|||
internal-op Log-WriteC
|
||||
side-effects OP_LOG_WRITEC_V OP_V
|
||||
type VV
|
||||
eval LogWritePre(z.aux->constants[0], v2)
|
||||
eval LogWritePre(z.aux->elems[0].Constant(), v2)
|
||||
LogWriteResPost()
|
||||
|
||||
# Versions that discard the return value.
|
||||
|
@ -2370,7 +2383,7 @@ internal-op Log-WriteC
|
|||
side-effects
|
||||
op1-read
|
||||
type V
|
||||
eval LogWritePre(z.aux->constants[0], v1)
|
||||
eval LogWritePre(z.aux->elems[0].Constant(), v1)
|
||||
LogWriteNoResPost()
|
||||
|
||||
internal-op Broker-Flush-Logs
|
||||
|
@ -2460,23 +2473,21 @@ eval Cat1FullVal(frame[z.v2])
|
|||
internal-op CatN
|
||||
type V
|
||||
eval auto aux = z.aux;
|
||||
auto slots = z.aux->slots;
|
||||
auto& ca = aux->cat_args;
|
||||
int n = aux->n;
|
||||
size_t max_size = 0;
|
||||
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_p = res;
|
||||
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';
|
||||
auto s = new String(true, reinterpret_cast<byte_vec>(res), res_p - res);
|
||||
Cat1Op(ZVal(new StringVal(s)))
|
||||
|
||||
macro CatNPre()
|
||||
auto aux = z.aux;
|
||||
auto slots = z.aux->slots;
|
||||
auto& ca = aux->cat_args;
|
||||
|
||||
macro CatNMid()
|
||||
|
@ -2491,113 +2502,113 @@ macro CatNPost()
|
|||
internal-op Cat2
|
||||
type V
|
||||
eval CatNPre()
|
||||
size_t max_size = ca[0]->MaxSize(frame, slots[0]);
|
||||
max_size += ca[1]->MaxSize(frame, slots[1]);
|
||||
size_t max_size = ca[0]->MaxSize(frame, aux->elems[0].Slot());
|
||||
max_size += ca[1]->MaxSize(frame, aux->elems[1].Slot());
|
||||
CatNMid()
|
||||
ca[0]->RenderInto(frame, slots[0], res_p);
|
||||
ca[1]->RenderInto(frame, slots[1], res_p);
|
||||
ca[0]->RenderInto(frame, aux->elems[0].Slot(), res_p);
|
||||
ca[1]->RenderInto(frame, aux->elems[1].Slot(), res_p);
|
||||
CatNPost()
|
||||
|
||||
internal-op Cat3
|
||||
type V
|
||||
eval CatNPre()
|
||||
size_t max_size = ca[0]->MaxSize(frame, slots[0]);
|
||||
max_size += ca[1]->MaxSize(frame, slots[1]);
|
||||
max_size += ca[2]->MaxSize(frame, slots[2]);
|
||||
size_t max_size = ca[0]->MaxSize(frame, aux->elems[0].Slot());
|
||||
max_size += ca[1]->MaxSize(frame, aux->elems[1].Slot());
|
||||
max_size += ca[2]->MaxSize(frame, aux->elems[2].Slot());
|
||||
CatNMid()
|
||||
ca[0]->RenderInto(frame, slots[0], res_p);
|
||||
ca[1]->RenderInto(frame, slots[1], res_p);
|
||||
ca[2]->RenderInto(frame, slots[2], res_p);
|
||||
ca[0]->RenderInto(frame, aux->elems[0].Slot(), res_p);
|
||||
ca[1]->RenderInto(frame, aux->elems[1].Slot(), res_p);
|
||||
ca[2]->RenderInto(frame, aux->elems[2].Slot(), res_p);
|
||||
CatNPost()
|
||||
|
||||
internal-op Cat4
|
||||
type V
|
||||
eval CatNPre()
|
||||
size_t max_size = ca[0]->MaxSize(frame, slots[0]);
|
||||
max_size += ca[1]->MaxSize(frame, slots[1]);
|
||||
max_size += ca[2]->MaxSize(frame, slots[2]);
|
||||
max_size += ca[3]->MaxSize(frame, slots[3]);
|
||||
size_t max_size = ca[0]->MaxSize(frame, aux->elems[0].Slot());
|
||||
max_size += ca[1]->MaxSize(frame, aux->elems[1].Slot());
|
||||
max_size += ca[2]->MaxSize(frame, aux->elems[2].Slot());
|
||||
max_size += ca[3]->MaxSize(frame, aux->elems[3].Slot());
|
||||
CatNMid()
|
||||
ca[0]->RenderInto(frame, slots[0], res_p);
|
||||
ca[1]->RenderInto(frame, slots[1], res_p);
|
||||
ca[2]->RenderInto(frame, slots[2], res_p);
|
||||
ca[3]->RenderInto(frame, slots[3], res_p);
|
||||
ca[0]->RenderInto(frame, aux->elems[0].Slot(), res_p);
|
||||
ca[1]->RenderInto(frame, aux->elems[1].Slot(), res_p);
|
||||
ca[2]->RenderInto(frame, aux->elems[2].Slot(), res_p);
|
||||
ca[3]->RenderInto(frame, aux->elems[3].Slot(), res_p);
|
||||
CatNPost()
|
||||
|
||||
internal-op Cat5
|
||||
type V
|
||||
eval CatNPre()
|
||||
size_t max_size = ca[0]->MaxSize(frame, slots[0]);
|
||||
max_size += ca[1]->MaxSize(frame, slots[1]);
|
||||
max_size += ca[2]->MaxSize(frame, slots[2]);
|
||||
max_size += ca[3]->MaxSize(frame, slots[3]);
|
||||
max_size += ca[4]->MaxSize(frame, slots[4]);
|
||||
size_t max_size = ca[0]->MaxSize(frame, aux->elems[0].Slot());
|
||||
max_size += ca[1]->MaxSize(frame, aux->elems[1].Slot());
|
||||
max_size += ca[2]->MaxSize(frame, aux->elems[2].Slot());
|
||||
max_size += ca[3]->MaxSize(frame, aux->elems[3].Slot());
|
||||
max_size += ca[4]->MaxSize(frame, aux->elems[4].Slot());
|
||||
CatNMid()
|
||||
ca[0]->RenderInto(frame, slots[0], res_p);
|
||||
ca[1]->RenderInto(frame, slots[1], res_p);
|
||||
ca[2]->RenderInto(frame, slots[2], res_p);
|
||||
ca[3]->RenderInto(frame, slots[3], res_p);
|
||||
ca[4]->RenderInto(frame, slots[4], res_p);
|
||||
ca[0]->RenderInto(frame, aux->elems[0].Slot(), res_p);
|
||||
ca[1]->RenderInto(frame, aux->elems[1].Slot(), res_p);
|
||||
ca[2]->RenderInto(frame, aux->elems[2].Slot(), res_p);
|
||||
ca[3]->RenderInto(frame, aux->elems[3].Slot(), res_p);
|
||||
ca[4]->RenderInto(frame, aux->elems[4].Slot(), res_p);
|
||||
CatNPost()
|
||||
|
||||
internal-op Cat6
|
||||
type V
|
||||
eval CatNPre()
|
||||
size_t max_size = ca[0]->MaxSize(frame, slots[0]);
|
||||
max_size += ca[1]->MaxSize(frame, slots[1]);
|
||||
max_size += ca[2]->MaxSize(frame, slots[2]);
|
||||
max_size += ca[3]->MaxSize(frame, slots[3]);
|
||||
max_size += ca[4]->MaxSize(frame, slots[4]);
|
||||
max_size += ca[5]->MaxSize(frame, slots[5]);
|
||||
size_t max_size = ca[0]->MaxSize(frame, aux->elems[0].Slot());
|
||||
max_size += ca[1]->MaxSize(frame, aux->elems[1].Slot());
|
||||
max_size += ca[2]->MaxSize(frame, aux->elems[2].Slot());
|
||||
max_size += ca[3]->MaxSize(frame, aux->elems[3].Slot());
|
||||
max_size += ca[4]->MaxSize(frame, aux->elems[4].Slot());
|
||||
max_size += ca[5]->MaxSize(frame, aux->elems[5].Slot());
|
||||
CatNMid()
|
||||
ca[0]->RenderInto(frame, slots[0], res_p);
|
||||
ca[1]->RenderInto(frame, slots[1], res_p);
|
||||
ca[2]->RenderInto(frame, slots[2], res_p);
|
||||
ca[3]->RenderInto(frame, slots[3], res_p);
|
||||
ca[4]->RenderInto(frame, slots[4], res_p);
|
||||
ca[5]->RenderInto(frame, slots[5], res_p);
|
||||
ca[0]->RenderInto(frame, aux->elems[0].Slot(), res_p);
|
||||
ca[1]->RenderInto(frame, aux->elems[1].Slot(), res_p);
|
||||
ca[2]->RenderInto(frame, aux->elems[2].Slot(), res_p);
|
||||
ca[3]->RenderInto(frame, aux->elems[3].Slot(), res_p);
|
||||
ca[4]->RenderInto(frame, aux->elems[4].Slot(), res_p);
|
||||
ca[5]->RenderInto(frame, aux->elems[5].Slot(), res_p);
|
||||
CatNPost()
|
||||
|
||||
internal-op Cat7
|
||||
type V
|
||||
eval CatNPre()
|
||||
size_t max_size = ca[0]->MaxSize(frame, slots[0]);
|
||||
max_size += ca[1]->MaxSize(frame, slots[1]);
|
||||
max_size += ca[2]->MaxSize(frame, slots[2]);
|
||||
max_size += ca[3]->MaxSize(frame, slots[3]);
|
||||
max_size += ca[4]->MaxSize(frame, slots[4]);
|
||||
max_size += ca[5]->MaxSize(frame, slots[5]);
|
||||
max_size += ca[6]->MaxSize(frame, slots[6]);
|
||||
size_t max_size = ca[0]->MaxSize(frame, aux->elems[0].Slot());
|
||||
max_size += ca[1]->MaxSize(frame, aux->elems[1].Slot());
|
||||
max_size += ca[2]->MaxSize(frame, aux->elems[2].Slot());
|
||||
max_size += ca[3]->MaxSize(frame, aux->elems[3].Slot());
|
||||
max_size += ca[4]->MaxSize(frame, aux->elems[4].Slot());
|
||||
max_size += ca[5]->MaxSize(frame, aux->elems[5].Slot());
|
||||
max_size += ca[6]->MaxSize(frame, aux->elems[6].Slot());
|
||||
CatNMid()
|
||||
ca[0]->RenderInto(frame, slots[0], res_p);
|
||||
ca[1]->RenderInto(frame, slots[1], res_p);
|
||||
ca[2]->RenderInto(frame, slots[2], res_p);
|
||||
ca[3]->RenderInto(frame, slots[3], res_p);
|
||||
ca[4]->RenderInto(frame, slots[4], res_p);
|
||||
ca[5]->RenderInto(frame, slots[5], res_p);
|
||||
ca[6]->RenderInto(frame, slots[6], res_p);
|
||||
ca[0]->RenderInto(frame, aux->elems[0].Slot(), res_p);
|
||||
ca[1]->RenderInto(frame, aux->elems[1].Slot(), res_p);
|
||||
ca[2]->RenderInto(frame, aux->elems[2].Slot(), res_p);
|
||||
ca[3]->RenderInto(frame, aux->elems[3].Slot(), res_p);
|
||||
ca[4]->RenderInto(frame, aux->elems[4].Slot(), res_p);
|
||||
ca[5]->RenderInto(frame, aux->elems[5].Slot(), res_p);
|
||||
ca[6]->RenderInto(frame, aux->elems[6].Slot(), res_p);
|
||||
CatNPost()
|
||||
|
||||
internal-op Cat8
|
||||
type V
|
||||
eval CatNPre()
|
||||
size_t max_size = ca[0]->MaxSize(frame, slots[0]);
|
||||
max_size += ca[1]->MaxSize(frame, slots[1]);
|
||||
max_size += ca[2]->MaxSize(frame, slots[2]);
|
||||
max_size += ca[3]->MaxSize(frame, slots[3]);
|
||||
max_size += ca[4]->MaxSize(frame, slots[4]);
|
||||
max_size += ca[5]->MaxSize(frame, slots[5]);
|
||||
max_size += ca[6]->MaxSize(frame, slots[6]);
|
||||
max_size += ca[7]->MaxSize(frame, slots[7]);
|
||||
size_t max_size = ca[0]->MaxSize(frame, aux->elems[0].Slot());
|
||||
max_size += ca[1]->MaxSize(frame, aux->elems[1].Slot());
|
||||
max_size += ca[2]->MaxSize(frame, aux->elems[2].Slot());
|
||||
max_size += ca[3]->MaxSize(frame, aux->elems[3].Slot());
|
||||
max_size += ca[4]->MaxSize(frame, aux->elems[4].Slot());
|
||||
max_size += ca[5]->MaxSize(frame, aux->elems[5].Slot());
|
||||
max_size += ca[6]->MaxSize(frame, aux->elems[6].Slot());
|
||||
max_size += ca[7]->MaxSize(frame, aux->elems[7].Slot());
|
||||
CatNMid()
|
||||
ca[0]->RenderInto(frame, slots[0], res_p);
|
||||
ca[1]->RenderInto(frame, slots[1], res_p);
|
||||
ca[2]->RenderInto(frame, slots[2], res_p);
|
||||
ca[3]->RenderInto(frame, slots[3], res_p);
|
||||
ca[4]->RenderInto(frame, slots[4], res_p);
|
||||
ca[5]->RenderInto(frame, slots[5], res_p);
|
||||
ca[6]->RenderInto(frame, slots[6], res_p);
|
||||
ca[7]->RenderInto(frame, slots[7], res_p);
|
||||
ca[0]->RenderInto(frame, aux->elems[0].Slot(), res_p);
|
||||
ca[1]->RenderInto(frame, aux->elems[1].Slot(), res_p);
|
||||
ca[2]->RenderInto(frame, aux->elems[2].Slot(), res_p);
|
||||
ca[3]->RenderInto(frame, aux->elems[3].Slot(), res_p);
|
||||
ca[4]->RenderInto(frame, aux->elems[4].Slot(), res_p);
|
||||
ca[5]->RenderInto(frame, aux->elems[5].Slot(), res_p);
|
||||
ca[6]->RenderInto(frame, aux->elems[6].Slot(), res_p);
|
||||
ca[7]->RenderInto(frame, aux->elems[7].Slot(), res_p);
|
||||
CatNPost()
|
||||
|
||||
internal-op Analyzer--Name
|
||||
|
|
|
@ -302,6 +302,65 @@ private:
|
|||
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
|
||||
// sufficient expressiveness to represent all of the elements that
|
||||
// an instruction needs.
|
||||
|
@ -311,53 +370,41 @@ public:
|
|||
// tracking slots, constants, and types.
|
||||
ZInstAux(int _n) {
|
||||
n = _n;
|
||||
if ( n > 0 ) {
|
||||
slots = ints = new int[n];
|
||||
constants = new ValPtr[n];
|
||||
types = new TypePtr[n];
|
||||
is_managed = new bool[n];
|
||||
}
|
||||
if ( n > 0 )
|
||||
elems = new AuxElem[n];
|
||||
}
|
||||
|
||||
~ZInstAux() {
|
||||
delete[] ints;
|
||||
delete[] constants;
|
||||
delete[] types;
|
||||
delete[] is_managed;
|
||||
delete[] elems;
|
||||
delete[] cat_args;
|
||||
}
|
||||
|
||||
// Returns the i'th element of the parallel arrays as a ValPtr.
|
||||
ValPtr ToVal(const ZVal* frame, int i) const {
|
||||
if ( constants[i] )
|
||||
return constants[i];
|
||||
else
|
||||
return frame[slots[i]].ToVal(types[i]);
|
||||
}
|
||||
// Returns the i'th element of the elements as a ValPtr.
|
||||
ValPtr ToVal(const ZVal* frame, int i) const { return elems[i].ToVal(frame); }
|
||||
ZVal ToZVal(const ZVal* frame, int i) const { return elems[i].ToZVal(frame); }
|
||||
|
||||
// Returns the parallel arrays as a ListValPtr.
|
||||
// Returns the elements as a ListValPtr.
|
||||
ListValPtr ToListVal(const ZVal* frame) const {
|
||||
auto lv = make_intrusive<ListVal>(TYPE_ANY);
|
||||
for ( auto i = 0; i < n; ++i )
|
||||
lv->Append(ToVal(frame, i));
|
||||
lv->Append(elems[i].ToVal(frame));
|
||||
|
||||
return lv;
|
||||
}
|
||||
|
||||
// Converts the parallel arrays to a ListValPtr suitable for
|
||||
// use as indices for indexing a table or set. "offset" specifies
|
||||
// which index we're looking for (there can be a bunch for
|
||||
// constructors), and "width" the number of elements in a single
|
||||
// index.
|
||||
// Converts the elements to a ListValPtr suitable for use as indices
|
||||
// for indexing a table or set. "offset" specifies which index we're
|
||||
// looking for (there can be a bunch for constructors), and "width"
|
||||
// the number of elements in a single index.
|
||||
ListValPtr ToIndices(const ZVal* frame, int offset, int width) const {
|
||||
auto lv = make_intrusive<ListVal>(TYPE_ANY);
|
||||
for ( auto i = 0; i < 0 + width; ++i )
|
||||
lv->Append(ToVal(frame, offset + i));
|
||||
lv->Append(elems[offset + i].ToVal(frame));
|
||||
|
||||
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) {
|
||||
vv.clear();
|
||||
FillValVec(vv, frame);
|
||||
|
@ -365,49 +412,45 @@ public:
|
|||
}
|
||||
|
||||
// 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 {
|
||||
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
|
||||
// arrays to a given frame slot and type.
|
||||
void Add(int i, int slot, TypePtr t) {
|
||||
ints[i] = slot;
|
||||
constants[i] = nullptr;
|
||||
types[i] = t;
|
||||
is_managed[i] = t ? ZVal::IsManagedType(t) : false;
|
||||
// Returns the elements converted to a vector of ZVal's.
|
||||
const auto& ToZValVec(const ZVal* frame) {
|
||||
for ( auto i = 0; i < n; ++i )
|
||||
zvec[i] = elems[i].ToZVal(frame);
|
||||
return zvec;
|
||||
}
|
||||
|
||||
// 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.
|
||||
void Add(int i, ValPtr c) {
|
||||
ints[i] = -1;
|
||||
constants[i] = c;
|
||||
types[i] = nullptr;
|
||||
is_managed[i] = false;
|
||||
}
|
||||
void Add(int i, ValPtr c) { elems[i].SetConstant(c); }
|
||||
|
||||
// Member variables. We could add accessors for manipulating
|
||||
// these (and make the variables private), but for convenience we
|
||||
// make them directly available.
|
||||
|
||||
// These are parallel arrays, used to build up lists of values.
|
||||
// Each element is either an integer or a constant. Usually the
|
||||
// integer is a frame slot (in which case "slots" points to "ints";
|
||||
// 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;
|
||||
int n; // size of elements
|
||||
AuxElem* elems = nullptr;
|
||||
bool elems_has_slots = true;
|
||||
|
||||
// Ingredients associated with lambdas ...
|
||||
ScriptFuncPtr primary_func;
|
||||
|
@ -429,8 +472,8 @@ public:
|
|||
// store here.
|
||||
bool can_change_non_locals = false;
|
||||
|
||||
// The following is only used for OP_CONSTRUCT_KNOWN_RECORD_V,
|
||||
// to map elements in slots/constants/types to record field offsets.
|
||||
// The following is used for constructing records, to map elements in
|
||||
// slots/constants/types to record field offsets.
|
||||
std::vector<int> map;
|
||||
|
||||
///// 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
|
||||
// a pointer and only instantiate as needed.
|
||||
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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue