updates to ZAM operations / gen-zam regularization, other than the operations themselves

This commit is contained in:
Vern Paxson 2024-08-05 10:13:35 +01:00 committed by Arne Welzel
parent 1d7e71b499
commit 5fc2c601b4
17 changed files with 422 additions and 294 deletions

View file

@ -291,6 +291,9 @@ protected:
*/
virtual void SetCaptures(Frame* f);
// Captures when using ZVal block instead of a Frame.
std::unique_ptr<std::vector<ZVal>> captures_vec;
private:
size_t frame_size = 0;
@ -304,9 +307,6 @@ private:
OffsetMap* captures_offset_mapping = nullptr;
// Captures when using ZVal block instead of a Frame.
std::unique_ptr<std::vector<ZVal>> captures_vec;
// The most recently added/updated body ...
StmtPtr current_body;

View file

@ -303,7 +303,7 @@ bool ZAMCompiler::PruneUnused() {
if ( assignmentless_op.count(inst->op) == 0 )
reporter->InternalError("inconsistency in re-flavoring instruction with side effects");
inst->op_type = assignmentless_op_type[inst->op];
inst->op_type = assignmentless_op_class[inst->op];
inst->op = assignmentless_op[inst->op];
inst->v1 = inst->v2;
@ -336,8 +336,8 @@ void ZAMCompiler::ComputeFrameLifetimes() {
// Some special-casing.
switch ( inst->op ) {
case OP_NEXT_TABLE_ITER_VV:
case OP_NEXT_TABLE_ITER_VAL_VAR_VVV: {
case OP_NEXT_TABLE_ITER_fb:
case OP_NEXT_TABLE_ITER_VAL_VAR_Vfb: {
// These assign to an arbitrary long list of variables.
auto& iter_vars = inst->aux->loop_vars;
auto depth = inst->loop_depth;
@ -361,21 +361,21 @@ void ZAMCompiler::ComputeFrameLifetimes() {
}
// No need to check the additional "var" associated
// with OP_NEXT_TABLE_ITER_VAL_VAR_VVV as that's
// with OP_NEXT_TABLE_ITER_VAL_VAR_Vfb as that's
// a slot-1 assignment. However, similar to other
// loop variables, mark this as a usage.
if ( inst->op == OP_NEXT_TABLE_ITER_VAL_VAR_VVV )
if ( inst->op == OP_NEXT_TABLE_ITER_VAL_VAR_Vfb )
ExtendLifetime(inst->v1, EndOfLoop(inst, depth));
} break;
case OP_NEXT_TABLE_ITER_NO_VARS_VV: break;
case OP_NEXT_TABLE_ITER_NO_VARS_fb: break;
case OP_NEXT_TABLE_ITER_VAL_VAR_NO_VARS_VVV: {
case OP_NEXT_TABLE_ITER_VAL_VAR_NO_VARS_Vfb: {
auto depth = inst->loop_depth;
ExtendLifetime(inst->v1, EndOfLoop(inst, depth));
} break;
case OP_NEXT_VECTOR_ITER_VAL_VAR_VVVV: {
case OP_NEXT_VECTOR_ITER_VAL_VAR_VVsb: {
CheckSlotAssignment(inst->v2, inst);
auto depth = inst->loop_depth;
@ -383,13 +383,13 @@ void ZAMCompiler::ComputeFrameLifetimes() {
ExtendLifetime(inst->v2, EndOfLoop(inst, depth));
} break;
case OP_NEXT_VECTOR_BLANK_ITER_VAL_VAR_VVV: {
case OP_NEXT_VECTOR_BLANK_ITER_VAL_VAR_Vsb: {
auto depth = inst->loop_depth;
ExtendLifetime(inst->v1, EndOfLoop(inst, depth));
} break;
case OP_NEXT_VECTOR_ITER_VVV:
case OP_NEXT_STRING_ITER_VVV:
case OP_NEXT_VECTOR_ITER_Vsb:
case OP_NEXT_STRING_ITER_Vsb:
// Sometimes loops are written that don't actually
// use the iteration variable. However, we still
// need to mark the variable as having usage
@ -401,12 +401,12 @@ void ZAMCompiler::ComputeFrameLifetimes() {
ExtendLifetime(inst->v1, EndOfLoop(inst, inst->loop_depth));
break;
case OP_NEXT_VECTOR_BLANK_ITER_VV:
case OP_NEXT_STRING_BLANK_ITER_VV: break;
case OP_NEXT_VECTOR_BLANK_ITER_sb:
case OP_NEXT_STRING_BLANK_ITER_sb: break;
case OP_INIT_TABLE_LOOP_VV:
case OP_INIT_VECTOR_LOOP_VV:
case OP_INIT_STRING_LOOP_VV: {
case OP_INIT_TABLE_LOOP_Vf:
case OP_INIT_VECTOR_LOOP_Vs:
case OP_INIT_STRING_LOOP_Vs: {
// For all of these, the scope of the aggregate being
// looped over is the entire loop, even if it doesn't
// directly appear in it, and not just the initializer.
@ -423,14 +423,30 @@ void ZAMCompiler::ComputeFrameLifetimes() {
continue;
}
case OP_STORE_GLOBAL_V: {
case OP_STORE_GLOBAL_g: {
// Use of the global goes to here.
auto slot = frame_layout1[globalsI[inst->v1].id.get()];
ExtendLifetime(slot, EndOfLoop(inst, 1));
break;
}
case OP_LAMBDA_VV: {
case OP_DETERMINE_TYPE_MATCH_VV: {
auto aux = inst->aux;
int n = aux->n;
for ( int i = 0; i < n; ++i ) {
auto slot_i = aux->elems[i].Slot();
if ( slot_i >= 0 ) {
CheckSlotAssignment(slot_i, inst);
// The variable gets used in the switch that
// immediately follows this instruction, hence
// "i + 1" in the following.
ExtendLifetime(slot_i, insts1[i + 1]);
}
}
break;
}
case OP_LAMBDA_Vi: {
auto aux = inst->aux;
int n = aux->n;
for ( int i = 0; i < n; ++i ) {
@ -486,8 +502,7 @@ void ZAMCompiler::ReMapFrame() {
auto vars = inst_beginnings[inst];
for ( auto v : vars ) {
// Don't remap variables whose values aren't actually
// used.
// Don't remap variables whose values aren't actually used.
int slot = frame_layout1[v];
if ( denizen_ending.count(slot) > 0 )
ReMapVar(v, slot, i);
@ -549,9 +564,15 @@ void ZAMCompiler::ReMapFrame() {
// Handle special cases.
switch ( inst->op ) {
case OP_NEXT_TABLE_ITER_VV:
case OP_NEXT_TABLE_ITER_VAL_VAR_VVV: {
// Rewrite iteration variables.
case OP_INIT_TABLE_LOOP_Vf:
case OP_NEXT_TABLE_ITER_fb:
case OP_NEXT_TABLE_ITER_VAL_VAR_Vfb: {
// Rewrite iteration variables. Strictly speaking we only
// need to do this for the INIT, not the NEXT, since the
// latter currently doesn't access the variables directly but
// instead uses pointers set up by the INIT. We do both types
// here, though, to keep things consistent and to help avoid
// surprises if the implementation changes in the future.
auto& iter_vars = inst->aux->loop_vars;
for ( auto& v : iter_vars ) {
if ( v < 0 )

View file

@ -25,13 +25,13 @@ ZAMStmt ZAMCompiler::GenGoTo(GoToSet& v) {
}
ZAMStmt ZAMCompiler::GoToStub() {
ZInstI z(OP_GOTO_V, 0);
ZInstI z(OP_GOTO_b, 0);
z.op_type = OP_V_I1;
return AddInst(z);
}
ZAMStmt ZAMCompiler::GoTo(const InstLabel l) {
ZInstI inst(OP_GOTO_V, 0);
ZInstI inst(OP_GOTO_b, 0);
inst.target = l;
inst.target_slot = 1;
inst.op_type = OP_V_I1;

View file

@ -27,8 +27,10 @@ SimpleZBI::SimpleZBI(std::string name, ZOp _const_op, ZOp _op, bool _ret_val_mat
bool SimpleZBI::Build(ZAMCompiler* zam, const NameExpr* n, const ExprPList& args) const {
ZInstI z;
if ( nargs == 0 ) {
if ( n )
if ( n ) {
z = ZInstI(op, zam->Frame1Slot(n, OP1_WRITE));
z.is_managed = ZVal::IsManagedType(n->GetType());
}
else
z = ZInstI(op);
}
@ -59,12 +61,9 @@ bool SimpleZBI::Build(ZAMCompiler* zam, const NameExpr* n, const ExprPList& args
z.c = ZVal(args[0]->AsConstExpr()->ValuePtr(), t);
}
z.t = t;
z.SetType(t);
}
if ( n )
z.is_managed = ZVal::IsManagedType(n->GetType());
zam->AddInst(z);
return true;
@ -104,7 +103,7 @@ bool CondZBI::BuildCond(ZAMCompiler* zam, const ExprPList& args, int& branch_v)
auto a0_slot = zam->FrameSlot(a0->AsNameExpr());
z = ZInstI(cond_op, a0_slot, 0);
z.op_type = OP_VV_I2;
z.t = a0->GetType();
z.SetType(a0->GetType());
branch_v = 2;
}
@ -129,7 +128,7 @@ bool OptAssignZBI::Build(ZAMCompiler* zam, const NameExpr* n, const ExprPList& a
ASSERT(nargs == 1);
auto a0 = zam->FrameSlot(args[0]->AsNameExpr());
z = ZInstI(op2, a0);
z.t = args[0]->GetType();
z.SetType(args[0]->GetType());
}
zam->AddInst(z);
@ -145,7 +144,7 @@ bool CatZBI::Build(ZAMCompiler* zam, const NameExpr* n, const ExprPList& args) c
if ( args.empty() ) {
// Weird, but easy enough to support.
z = ZInstI(OP_CAT1_VC, nslot);
z.t = n->GetType();
z.SetType(n->GetType());
z.c = ZVal(val_mgr->EmptyString());
}
@ -168,18 +167,18 @@ bool CatZBI::Build(ZAMCompiler* zam, const NameExpr* n, const ExprPList& args) c
else if ( a0->GetType()->Tag() != TYPE_STRING ) {
if ( a0->Tag() == EXPR_NAME ) {
z = zam->GenInst(OP_CAT1FULL_VV, n, a0->AsNameExpr());
z.t = a0->GetType();
z.SetType(a0->GetType());
}
else {
z = ZInstI(OP_CAT1_VC, nslot);
z.t = n->GetType();
z.SetType(n->GetType());
z.c = ZVal(ZAM_val_cat(a0->AsConstExpr()->ValuePtr()));
}
}
else if ( a0->Tag() == EXPR_CONST ) {
z = zam->GenInst(OP_CAT1_VC, n, a0->AsConstExpr());
z.t = n->GetType();
z.SetType(n->GetType());
}
else
@ -388,12 +387,12 @@ bool MultiZBI::Build(ZAMCompiler* zam, const NameExpr* n, const ExprPList& args)
z.is_managed = ZVal::IsManagedType(n->GetType());
if ( ! consts.empty() ) {
z.t = consts[0]->GetType();
z.c = ZVal(consts[0], z.t);
z.SetType(consts[0]->GetType());
z.c = ZVal(consts[0], z.GetType());
}
if ( type_arg >= 0 && ! z.t )
z.t = args[type_arg]->GetType();
if ( type_arg >= 0 && ! z.GetType() )
z.SetType(args[type_arg]->GetType());
zam->AddInst(z);
@ -434,14 +433,14 @@ SimpleZBI sta_ZBI{"subnet_to_addr", OP_SUBNET_TO_ADDR_VV, 1};
SimpleZBI ttd_ZBI{"time_to_double", OP_TIME_TO_DOUBLE_VV, 1};
SimpleZBI tl_ZBI{"to_lower", OP_TO_LOWER_VV, 1};
CondZBI ce_ZBI{"connection_exists", OP_CONN_EXISTS_VV, OP_CONN_EXISTS_COND_VV, 1};
CondZBI iip_ZBI{"is_icmp_port", OP_IS_ICMP_PORT_VV, OP_IS_ICMP_PORT_COND_VV, 1};
CondZBI itp_ZBI{"is_tcp_port", OP_IS_TCP_PORT_VV, OP_IS_TCP_PORT_COND_VV, 1};
CondZBI iup_ZBI{"is_udp_port", OP_IS_UDP_PORT_VV, OP_IS_UDP_PORT_COND_VV, 1};
CondZBI iv4_ZBI{"is_v4_addr", OP_IS_V4_ADDR_VV, OP_IS_V4_ADDR_COND_VV, 1};
CondZBI iv6_ZBI{"is_v6_addr", OP_IS_V6_ADDR_VV, OP_IS_V6_ADDR_COND_VV, 1};
CondZBI rlt_ZBI{"reading_live_traffic", OP_READING_LIVE_TRAFFIC_V, OP_READING_LIVE_TRAFFIC_COND_V, 0};
CondZBI rt_ZBI{"reading_traces", OP_READING_TRACES_V, OP_READING_TRACES_COND_V, 0};
CondZBI ce_ZBI{"connection_exists", OP_CONN_EXISTS_VV, OP_CONN_EXISTS_COND_Vb, 1};
CondZBI iip_ZBI{"is_icmp_port", OP_IS_ICMP_PORT_VV, OP_IS_ICMP_PORT_COND_Vb, 1};
CondZBI itp_ZBI{"is_tcp_port", OP_IS_TCP_PORT_VV, OP_IS_TCP_PORT_COND_Vb, 1};
CondZBI iup_ZBI{"is_udp_port", OP_IS_UDP_PORT_VV, OP_IS_UDP_PORT_COND_Vb, 1};
CondZBI iv4_ZBI{"is_v4_addr", OP_IS_V4_ADDR_VV, OP_IS_V4_ADDR_COND_Vb, 1};
CondZBI iv6_ZBI{"is_v6_addr", OP_IS_V6_ADDR_VV, OP_IS_V6_ADDR_COND_Vb, 1};
CondZBI rlt_ZBI{"reading_live_traffic", OP_READING_LIVE_TRAFFIC_V, OP_READING_LIVE_TRAFFIC_COND_b, 0};
CondZBI rt_ZBI{"reading_traces", OP_READING_TRACES_V, OP_READING_TRACES_COND_b, 0};
// These have a different form to avoid invoking copy constructors.
auto cat_ZBI = CatZBI();
@ -468,48 +467,48 @@ OptAssignZBI rtc_ZBI{ "PacketAnalyzer::TEREDO::remove_teredo_connection",
MultiZBI faa_ZBI{ "Files::__add_analyzer",
{{{VVV}, {OP_FILES_ADD_ANALYZER_VVV, OP_VVV}},
{{VCV}, {OP_FILES_ADD_ANALYZER_ViV, OP_VVC}}},
{{VCV}, {OP_FILES_ADD_ANALYZER_VCV, OP_VVC}}},
{{{VVV}, {OP_FILES_ADD_ANALYZER_VVVV, OP_VVVV}},
{{VCV}, {OP_FILES_ADD_ANALYZER_VViV, OP_VVVC}}},
{{VCV}, {OP_FILES_ADD_ANALYZER_VVCV, OP_VVVC}}},
1
};
MultiZBI fra_ZBI{ "Files::__remove_analyzer",
{{{VVV}, {OP_FILES_REMOVE_ANALYZER_VVV, OP_VVV}},
{{VCV}, {OP_FILES_REMOVE_ANALYZER_ViV, OP_VVC}}},
{{VCV}, {OP_FILES_REMOVE_ANALYZER_VCV, OP_VVC}}},
{{{VVV}, {OP_FILES_REMOVE_ANALYZER_VVVV, OP_VVVV}},
{{VCV}, {OP_FILES_REMOVE_ANALYZER_VViV, OP_VVVC}}},
{{VCV}, {OP_FILES_REMOVE_ANALYZER_VVCV, OP_VVVC}}},
1
};
MultiZBI fsrb_ZBI{ "Files::__set_reassembly_buffer",
{{{VV}, {OP_FILES_SET_REASSEMBLY_BUFFER_VV, OP_VV}},
{{VC}, {OP_FILES_SET_REASSEMBLY_BUFFER_VC, OP_VV_I2}}},
{{VC}, {OP_FILES_SET_REASSEMBLY_BUFFER_Vi, OP_VV_I2}}},
{{{VV}, {OP_FILES_SET_REASSEMBLY_BUFFER_VVV, OP_VVV}},
{{VC}, {OP_FILES_SET_REASSEMBLY_BUFFER_VVC, OP_VVV_I3}}}
{{VC}, {OP_FILES_SET_REASSEMBLY_BUFFER_VVi, OP_VVV_I3}}}
};
MultiZBI lw_ZBI{ "Log::__write",
{{{VV}, {OP_LOG_WRITE_VV, OP_VV}},
{{CV}, {OP_LOG_WRITEC_V, OP_V}}},
{{CV}, {OP_LOG_WRITE_CV, OP_V}}},
{{{VV}, {OP_LOG_WRITE_VVV, OP_VVV}},
{{CV}, {OP_LOG_WRITEC_VV, OP_VV}}}
{{CV}, {OP_LOG_WRITEC_VCV, OP_VV}}}
};
MultiZBI gccbt_ZBI{ "get_current_conn_bytes_threshold", true,
{{{VV}, {OP_GET_BYTES_THRESH_VVV, OP_VVV}},
{{VC}, {OP_GET_BYTES_THRESH_VVi, OP_VVC}}}
{{VC}, {OP_GET_BYTES_THRESH_VVC, OP_VVC}}}
};
MultiZBI sccbt_ZBI{ "set_current_conn_bytes_threshold",
{{{VVV}, {OP_SET_BYTES_THRESH_VVV, OP_VVV}},
{{VVC}, {OP_SET_BYTES_THRESH_VVi, OP_VVC}},
{{VCV}, {OP_SET_BYTES_THRESH_ViV, OP_VVC}},
{{VCC}, {OP_SET_BYTES_THRESH_Vii, OP_VVC_I2}}},
{{VVC}, {OP_SET_BYTES_THRESH_VVC, OP_VVC}},
{{VCV}, {OP_SET_BYTES_THRESH_VCV, OP_VVC}},
{{VCC}, {OP_SET_BYTES_THRESH_VCi, OP_VVC_I2}}},
{{{VVV}, {OP_SET_BYTES_THRESH_VVVV, OP_VVVV}},
{{VVC}, {OP_SET_BYTES_THRESH_VVVi, OP_VVVC}},
{{VCV}, {OP_SET_BYTES_THRESH_VViV, OP_VVVC}},
{{VCC}, {OP_SET_BYTES_THRESH_VVii, OP_VVVC_I3}}}
{{VVC}, {OP_SET_BYTES_THRESH_VVVC, OP_VVVC}},
{{VCV}, {OP_SET_BYTES_THRESH_VVCV, OP_VVVC}},
{{VCC}, {OP_SET_BYTES_THRESH_VVCi, OP_VVVC_I3}}}
};
MultiZBI sw_ZBI{ "starts_with", true,
@ -532,12 +531,12 @@ MultiZBI strstr_ZBI{ "strstr", true,
MultiZBI sb_ZBI{ "sub_bytes", true,
{{{VVV}, {OP_SUB_BYTES_VVVV, OP_VVVV}},
{{VVC}, {OP_SUB_BYTES_VVVi, OP_VVVC}},
{{VCV}, {OP_SUB_BYTES_VViV, OP_VVVC}},
{{VCC}, {OP_SUB_BYTES_VVii, OP_VVVC_I3}},
{{CVV}, {OP_SUB_BYTES_VVVC, OP_VVVC}},
{{CVC}, {OP_SUB_BYTES_VViC, OP_VVVC_I3}},
{{CCV}, {OP_SUB_BYTES_ViVC, OP_VVVC_I3}}}
{{VVC}, {OP_SUB_BYTES_VVVC, OP_VVVC}},
{{VCV}, {OP_SUB_BYTES_VVCV, OP_VVVC}},
{{VCC}, {OP_SUB_BYTES_VVCi, OP_VVVC_I3}},
{{CVV}, {OP_SUB_BYTES_VCVV, OP_VVVC}},
{{CVC}, {OP_SUB_BYTES_VCVi, OP_VVVC_I3}},
{{CCV}, {OP_SUB_BYTES2_VCVi, OP_VVVC_I3}}}
};
// clang-format on

View file

@ -48,8 +48,7 @@ FixedCatArg::FixedCatArg(TypePtr _t) : t(std::move(_t)) {
}
}
void FixedCatArg::RenderInto(ZVal* zframe, int slot, char*& res) {
auto& z = zframe[slot];
void FixedCatArg::RenderInto(const ZVal& z, char*& res) {
int n;
const char* text;
std::string str;
@ -140,8 +139,8 @@ void FixedCatArg::RenderInto(ZVal* zframe, int slot, char*& res) {
}
}
size_t PatternCatArg::ComputeMaxSize(ZVal* zframe, int slot) {
text = zframe[slot].AsPattern()->AsPattern()->PatternText();
size_t PatternCatArg::ComputeMaxSize(const ZVal& zv) {
text = zv.AsPattern()->AsPattern()->PatternText();
n = strlen(text);
return n;
}

View file

@ -13,9 +13,9 @@ public:
virtual ~CatArg() {}
size_t MaxSize(ZVal* zframe, int slot) { return max_size ? *max_size : ComputeMaxSize(zframe, slot); }
size_t MaxSize(const ZVal& zv) { return max_size ? *max_size : ComputeMaxSize(zv); }
virtual void RenderInto(ZVal* zframe, int slot, char*& res) {
virtual void RenderInto(const ZVal& zv, char*& res) {
auto n = *max_size;
memcpy(res, s->data(), n);
res += n;
@ -25,7 +25,7 @@ protected:
CatArg() {}
CatArg(size_t _max_size) : max_size(_max_size) {}
virtual size_t ComputeMaxSize(ZVal* zframe, int slot) { return 0; }
virtual size_t ComputeMaxSize(const ZVal& zv) { return 0; }
// Present if max size is known a priori.
std::optional<size_t> max_size;
@ -38,7 +38,7 @@ class FixedCatArg : public CatArg {
public:
FixedCatArg(TypePtr t);
void RenderInto(ZVal* zframe, int slot, char*& res) override;
void RenderInto(const ZVal& zv, char*& res) override;
protected:
TypePtr t;
@ -49,22 +49,22 @@ class StringCatArg : public CatArg {
public:
StringCatArg() : CatArg() {}
void RenderInto(ZVal* zframe, int slot, char*& res) override {
auto s = zframe[slot].AsString();
void RenderInto(const ZVal& zv, char*& res) override {
auto s = zv.AsString();
auto n = s->Len();
memcpy(res, s->Bytes(), n);
res += n;
}
protected:
size_t ComputeMaxSize(ZVal* zframe, int slot) override { return zframe[slot].AsString()->Len(); }
size_t ComputeMaxSize(const ZVal& zv) override { return zv.AsString()->Len(); }
};
class PatternCatArg : public CatArg {
public:
PatternCatArg() : CatArg() {}
void RenderInto(ZVal* zframe, int slot, char*& res) override {
void RenderInto(const ZVal& zv, char*& res) override {
*(res++) = '/';
strcpy(res, text);
res += n;
@ -72,7 +72,7 @@ public:
}
protected:
size_t ComputeMaxSize(ZVal* zframe, int slot) override;
size_t ComputeMaxSize(const ZVal& zv) override;
const char* text = nullptr;
size_t n = 0;
@ -82,7 +82,7 @@ class DescCatArg : public CatArg {
public:
DescCatArg(TypePtr _t) : CatArg(), t(std::move(_t)) { d.SetStyle(RAW_STYLE); }
void RenderInto(ZVal* zframe, int slot, char*& res) override {
void RenderInto(const ZVal& zv, char*& res) override {
auto n = d.Len();
memcpy(res, d.Bytes(), n);
res += n;
@ -90,8 +90,8 @@ public:
}
protected:
size_t ComputeMaxSize(ZVal* zframe, int slot) override {
zframe[slot].ToVal(t)->Describe(&d);
size_t ComputeMaxSize(const ZVal& zv) override {
zv.ToVal(t)->Describe(&d);
return d.Len();
}

View file

@ -229,8 +229,8 @@ private:
const ZAMStmt CompileIndex(const NameExpr* n1, int n2_slot, const TypePtr& n2_type, const ListExpr* l,
bool in_when);
const ZAMStmt BuildLambda(const NameExpr* n, LambdaExpr* le);
const ZAMStmt BuildLambda(int n_slot, LambdaExpr* le);
const ZAMStmt BuildLambda(const NameExpr* n, ExprPtr le); // marker
const ZAMStmt BuildLambda(int n_slot, ExprPtr le); // marker
// Second argument is which instruction slot holds the branch target.
const ZAMStmt GenCond(const Expr* e, int& branch_v);

View file

@ -203,6 +203,7 @@ StmtPtr ZAMCompiler::CompileBody() {
auto zb = make_intrusive<ZBody>(fname, this);
zb->SetInsts(insts2);
zb->SetLocationInfo(body->GetLocationInfo());
// Could erase insts1 here to recover memory, but it's handy
// for debugging.
@ -218,7 +219,9 @@ void ZAMCompiler::ResolveHookBreaks() {
// Rewrite the breaks.
for ( auto& b : breaks[0] ) {
auto& i = insts1[b.stmt_num];
auto aux = i->aux;
*i = ZInstI(OP_HOOK_BREAK_X);
i->aux = aux;
}
}

View file

@ -246,7 +246,7 @@ const ZAMStmt ZAMCompiler::CompileAssignExpr(const AssignExpr* e) {
}
if ( rhs->Tag() == EXPR_LAMBDA )
return BuildLambda(lhs, rhs->AsLambdaExpr());
return BuildLambda(lhs, op2);
if ( rhs->Tag() == EXPR_COND && r1->GetType()->Tag() == TYPE_VECTOR )
return Bool_Vec_CondVVVV(lhs, r1->AsNameExpr(), r2->AsNameExpr(), r3->AsNameExpr());
@ -466,20 +466,23 @@ const ZAMStmt ZAMCompiler::CompileFieldLHSAssignExpr(const FieldLHSAssignExpr* e
auto field = e->Field();
if ( rhs->Tag() == EXPR_NAME )
return Field_LHS_AssignFV(e, rhs->AsNameExpr());
return Field_LHS_AssignFVi(e, rhs->AsNameExpr(), field);
if ( rhs->Tag() == EXPR_CONST )
return Field_LHS_AssignFC(e, rhs->AsConstExpr());
return Field_LHS_AssignFCi(e, rhs->AsConstExpr(), field);
auto r1 = rhs->GetOp1();
auto r2 = rhs->GetOp2();
if ( rhs->Tag() == EXPR_FIELD ) {
auto rhs_f = rhs->AsFieldExpr();
if ( r1->Tag() == EXPR_NAME )
return Field_LHS_AssignFVi(e, r1->AsNameExpr(), rhs_f->Field());
return Field_LHS_AssignFCi(e, r1->AsConstExpr(), rhs_f->Field());
// Note, the LHS field comes after the RHS field rather than before,
// to maintain layout symmetry close to that for non-field RHS's.
if ( r1->Tag() == EXPR_NAME )
return Field_LHS_AssignFVii(e, r1->AsNameExpr(), rhs_f->Field(), field);
return Field_LHS_AssignFCii(e, r1->AsConstExpr(), rhs_f->Field(), field);
}
if ( r1 && r1->IsConst() )
@ -564,7 +567,7 @@ const ZAMStmt ZAMCompiler::CompileEvent(EventHandler* h, const ListExpr* l) {
else {
auto n0 = exprs[0]->AsNameExpr();
z.v1 = FrameSlot(n0);
z.t = n0->GetType();
z.SetType(n0->GetType());
if ( n == 1 ) {
z.op = OP_EVENT1_V;
@ -574,7 +577,7 @@ const ZAMStmt ZAMCompiler::CompileEvent(EventHandler* h, const ListExpr* l) {
else {
auto n1 = exprs[1]->AsNameExpr();
z.v2 = FrameSlot(n1);
z.t2 = n1->GetType();
z.SetType2(n1->GetType());
if ( n == 2 ) {
z.op = OP_EVENT2_VV;
@ -630,7 +633,7 @@ const ZAMStmt ZAMCompiler::CompileInExpr(const NameExpr* n1, const NameExpr* n2,
if ( op3_t->AsTableType()->IsPatternIndex() && op2_t->Tag() == TYPE_STRING )
a = n2 ? OP_STR_IN_PAT_TBL_VVV : OP_STR_IN_PAT_TBL_VCV;
else
a = n2 ? OP_VAL_IS_IN_TABLE_VVV : OP_CONST_IS_IN_TABLE_VCV;
a = n2 ? OP_VAL_IS_IN_TABLE_VVV : OP_CONST_IS_IN_TABLE_VVC;
}
else if ( op2->GetType()->Tag() == TYPE_PATTERN )
a = n2 ? (n3 ? OP_P_IN_S_VVV : OP_P_IN_S_VVC) : OP_P_IN_S_VCV;
@ -692,11 +695,11 @@ const ZAMStmt ZAMCompiler::CompileInExpr(const NameExpr* n1, const ListExpr* l,
else {
auto l_e0_c = l_e[0]->AsConstExpr();
ZOp op = is_vec ? OP_CONST_IS_IN_VECTOR_VCV : OP_CONST_IS_IN_TABLE_VCV;
ZOp op = is_vec ? OP_CONST_IS_IN_VECTOR_VCV : OP_CONST_IS_IN_TABLE_VVC;
z = GenInst(op, n1, l_e0_c, n2);
}
z.t = l_e[0]->GetType();
z.SetType(l_e[0]->GetType());
return AddInst(z);
}
@ -717,21 +720,21 @@ const ZAMStmt ZAMCompiler::CompileInExpr(const NameExpr* n1, const ListExpr* l,
if ( l_e0_n && l_e1_n ) {
z = GenInst(OP_VAL2_IS_IN_TABLE_VVVV, n1, l_e0_n, l_e1_n, n2);
z.t2 = l_e0_n->GetType();
z.SetType2(l_e0_n->GetType());
}
else if ( l_e0_n ) {
ASSERT(l_e1_c);
z = GenInst(OP_VAL2_IS_IN_TABLE_VVVC, n1, l_e0_n, n2, l_e1_c);
z.t2 = l_e0_n->GetType();
z.SetType2(l_e0_n->GetType());
}
else if ( l_e1_n ) {
ASSERT(l_e0_c);
z = GenInst(OP_VAL2_IS_IN_TABLE_VVCV, n1, l_e1_n, n2, l_e0_c);
z.t2 = l_e1_n->GetType();
z.SetType2(l_e1_n->GetType());
}
else {
@ -743,7 +746,7 @@ const ZAMStmt ZAMCompiler::CompileInExpr(const NameExpr* n1, const ListExpr* l,
auto slot = TempForConst(l_e0_c);
z = ZInstI(OP_VAL2_IS_IN_TABLE_VVVC, FrameSlot(n1), slot, FrameSlot(n2), l_e1_c);
z.op_type = OP_VVVC;
z.t2 = l_e0_c->GetType();
z.SetType2(l_e0_c->GetType());
}
return AddInst(z);
@ -817,7 +820,7 @@ const ZAMStmt ZAMCompiler::CompileIndex(const NameExpr* n1, int n2_slot, const T
z = ZInstI(zop, Frame1Slot(n1, zop), n2_slot, n3_slot);
}
else {
auto zop = OP_INDEX_STRINGC_VVV;
auto zop = OP_INDEX_STRINGC_VVi;
z = ZInstI(zop, Frame1Slot(n1, zop), n2_slot, c);
z.op_type = OP_VVV_I3;
}
@ -846,11 +849,11 @@ const ZAMStmt ZAMCompiler::CompileIndex(const NameExpr* n1, int n2_slot, const T
ZOp zop;
if ( in_when )
zop = OP_WHEN_INDEX_VECC_VVV;
zop = OP_WHEN_INDEX_VECC_VVi;
else if ( is_any )
zop = OP_INDEX_ANY_VECC_VVV;
zop = OP_INDEX_ANY_VECC_VVi;
else
zop = OP_INDEX_VECC_VVV;
zop = OP_INDEX_VECC_VVi;
z = ZInstI(zop, Frame1Slot(n1, zop), n2_slot, c);
z.op_type = OP_VVV_I3;
@ -932,18 +935,18 @@ const ZAMStmt ZAMCompiler::CompileIndex(const NameExpr* n1, int n2_slot, const T
return AddInst(z);
}
const ZAMStmt ZAMCompiler::BuildLambda(const NameExpr* n, LambdaExpr* le) {
return BuildLambda(Frame1Slot(n, OP1_WRITE), le);
const ZAMStmt ZAMCompiler::BuildLambda(const NameExpr* n, ExprPtr e) {
return BuildLambda(Frame1Slot(n, OP1_WRITE), std::move(e));
}
const ZAMStmt ZAMCompiler::BuildLambda(int n_slot, LambdaExpr* le) {
auto& captures = le->GetCaptures();
const ZAMStmt ZAMCompiler::BuildLambda(int n_slot, ExprPtr e) {
auto lambda = cast_intrusive<LambdaExpr>(e);
auto& captures = lambda->GetCaptures();
int ncaptures = captures ? captures->size() : 0;
auto aux = new ZInstAux(ncaptures);
aux->primary_func = le->PrimaryFunc();
aux->lambda_name = le->Name();
aux->id_val = le->Ingredients()->GetID();
aux->lambda = cast_intrusive<LambdaExpr>(std::move(e));
aux->id_val = lambda->Ingredients()->GetID();
for ( int i = 0; i < ncaptures; ++i ) {
auto& id_i = (*captures)[i].Id();
@ -954,7 +957,7 @@ const ZAMStmt ZAMCompiler::BuildLambda(int n_slot, LambdaExpr* le) {
aux->Add(i, FrameSlot(id_i), id_i->GetType());
}
auto z = ZInstI(OP_LAMBDA_VV, n_slot, le->PrimaryFunc()->FrameSize());
auto z = ZInstI(OP_LAMBDA_Vi, n_slot, lambda->PrimaryFunc()->FrameSize());
z.op_type = OP_VV_I2;
z.aux = aux;
@ -1031,7 +1034,7 @@ const ZAMStmt ZAMCompiler::AssignVecElems(const Expr* e) {
inst = Vector_Elem_AssignVVC(lhs, n2, c3);
}
TopMainInst()->t = t3;
TopMainInst()->SetType(t3);
return inst;
}
@ -1048,7 +1051,7 @@ const ZAMStmt ZAMCompiler::AssignVecElems(const Expr* e) {
else
inst = Vector_Elem_AssignVVi(lhs, n3, index);
TopMainInst()->t = t3;
TopMainInst()->SetType(t3);
return inst;
}
@ -1068,7 +1071,7 @@ const ZAMStmt ZAMCompiler::AssignTableElem(const Expr* e) {
z = GenInst(OP_TABLE_ELEM_ASSIGN_VC, op1, op3->AsConstExpr());
z.aux = InternalBuildVals(op2);
z.t = op3->GetType();
z.SetType(op3->GetType());
if ( pfs->HasSideEffects(SideEffectsOp::WRITE, op1->GetType()) )
z.aux->can_change_non_locals = true;
@ -1159,7 +1162,7 @@ const ZAMStmt ZAMCompiler::DoCall(const CallExpr* c, const NameExpr* n) {
}
}
z.t = arg0->GetType();
z.SetType(arg0->GetType());
}
else {
@ -1184,10 +1187,12 @@ const ZAMStmt ZAMCompiler::DoCall(const CallExpr* c, const NameExpr* n) {
default:
if ( in_when ) {
if ( indirect )
op = OP_WHENINDCALLN_VV;
else
if ( ! indirect )
op = OP_WHENCALLN_V;
else if ( func_id->IsGlobal() )
op = OP_WHEN_ID_INDCALLN_V;
else
op = OP_WHENINDCALLN_VV;
}
else if ( indirect ) {
@ -1279,9 +1284,9 @@ const ZAMStmt ZAMCompiler::ConstructTable(const NameExpr* n, const Expr* e) {
auto tt = cast_intrusive<TableType>(n->GetType());
auto width = tt->GetIndices()->GetTypes().size();
auto z = GenInst(OP_CONSTRUCT_TABLE_VV, n, width);
auto z = GenInst(OP_CONSTRUCT_TABLE_Vi, n, width);
z.aux = InternalBuildVals(con, width + 1);
z.t = tt;
z.SetType(tt);
ASSERT(e->Tag() == EXPR_TABLE_CONSTRUCTOR);
z.aux->attrs = static_cast<const TableConstructorExpr*>(e)->GetAttrs();
@ -1291,7 +1296,7 @@ const ZAMStmt ZAMCompiler::ConstructTable(const NameExpr* n, const Expr* e) {
if ( ! def_attr || def_attr->GetExpr()->Tag() != EXPR_LAMBDA )
return zstmt;
auto def_lambda = def_attr->GetExpr()->AsLambdaExpr();
auto def_lambda = cast_intrusive<LambdaExpr>(def_attr->GetExpr());
auto dl_t = def_lambda->GetType()->AsFuncType();
auto& captures = dl_t->GetCaptures();
@ -1308,7 +1313,7 @@ const ZAMStmt ZAMCompiler::ConstructTable(const NameExpr* n, const Expr* e) {
z = GenInst(OP_SET_TABLE_DEFAULT_LAMBDA_VV, n, slot);
z.op_type = OP_VV;
z.t = def_lambda->GetType();
z.SetType(def_lambda->GetType());
return AddInst(z);
}
@ -1318,9 +1323,9 @@ const ZAMStmt ZAMCompiler::ConstructSet(const NameExpr* n, const Expr* e) {
auto tt = n->GetType()->AsTableType();
auto width = tt->GetIndices()->GetTypes().size();
auto z = GenInst(OP_CONSTRUCT_SET_VV, n, width);
auto z = GenInst(OP_CONSTRUCT_SET_Vi, n, width);
z.aux = InternalBuildVals(con, width);
z.t = e->GetType();
z.SetType(e->GetType());
ASSERT(e->Tag() == EXPR_SET_CONSTRUCTOR);
z.aux->attrs = static_cast<const SetConstructorExpr*>(e)->GetAttrs();
@ -1391,13 +1396,13 @@ const ZAMStmt ZAMCompiler::ConstructRecord(const NameExpr* n, const Expr* e, boo
if ( fi->empty() ) {
if ( network_time_index >= 0 )
op = OP_CONSTRUCT_KNOWN_RECORD_WITH_NT_VV;
op = OP_CONSTRUCT_KNOWN_RECORD_WITH_NT_Vi;
else
op = OP_CONSTRUCT_KNOWN_RECORD_V;
}
else {
if ( network_time_index >= 0 )
op = OP_CONSTRUCT_KNOWN_RECORD_WITH_INITS_AND_NT_VV;
op = OP_CONSTRUCT_KNOWN_RECORD_WITH_INITS_AND_NT_Vi;
else
op = OP_CONSTRUCT_KNOWN_RECORD_WITH_INITS_V;
aux->field_inits = std::move(fi);
@ -1411,12 +1416,12 @@ const ZAMStmt ZAMCompiler::ConstructRecord(const NameExpr* n, const Expr* e, boo
if ( is_from_rec ) {
// Map non-from-rec operand to the from-rec equivalent.
switch ( op ) {
case OP_CONSTRUCT_KNOWN_RECORD_WITH_NT_VV: op = OP_CONSTRUCT_KNOWN_RECORD_WITH_NT_FROM_VVV; break;
case OP_CONSTRUCT_KNOWN_RECORD_WITH_NT_Vi: op = OP_CONSTRUCT_KNOWN_RECORD_WITH_NT_FROM_VVi; break;
case OP_CONSTRUCT_KNOWN_RECORD_V: op = OP_CONSTRUCT_KNOWN_RECORD_FROM_VV; break;
case OP_CONSTRUCT_KNOWN_RECORD_WITH_INITS_AND_NT_VV:
op = OP_CONSTRUCT_KNOWN_RECORD_WITH_INITS_AND_NT_FROM_VVV;
case OP_CONSTRUCT_KNOWN_RECORD_WITH_INITS_AND_NT_Vi:
op = OP_CONSTRUCT_KNOWN_RECORD_WITH_INITS_AND_NT_FROM_VVi;
break;
case OP_CONSTRUCT_KNOWN_RECORD_WITH_INITS_V:
@ -1448,7 +1453,7 @@ const ZAMStmt ZAMCompiler::ConstructRecord(const NameExpr* n, const Expr* e, boo
z = network_time_index >= 0 ? GenInst(op, n, network_time_index) : GenInst(op, n);
z.aux = aux;
z.t = rec_e->GetType();
z.SetType(rec_e->GetType());
auto inst = AddInst(z);
@ -1488,7 +1493,7 @@ const ZAMStmt ZAMCompiler::ConstructRecord(const NameExpr* n, const Expr* e, boo
// Need to add a separate instruction for concretizing the fields.
z = GenInst(OP_CONCRETIZE_VECTOR_FIELDS_V, n);
z.t = rec_e->GetType();
z.SetType(rec_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
@ -1503,7 +1508,7 @@ const ZAMStmt ZAMCompiler::ConstructVector(const NameExpr* n, const Expr* e) {
auto z = GenInst(OP_CONSTRUCT_VECTOR_V, n);
z.aux = InternalBuildVals(con);
z.t = e->GetType();
z.SetType(e->GetType());
return AddInst(z);
}
@ -1626,8 +1631,8 @@ const ZAMStmt ZAMCompiler::Is(const NameExpr* n, const Expr* e) {
int op_slot = FrameSlot(op);
ZInstI z(OP_IS_VV, Frame1Slot(n, OP_IS_VV), op_slot);
z.t2 = op->GetType();
z.SetType(is->TestType());
z.SetType2(op->GetType());
return AddInst(z);
}

View file

@ -15,21 +15,54 @@ namespace zeek::detail {
class TableIterInfo {
public:
// No constructor needed, as all of our member variables are
// instead instantiated via BeginLoop(). This allows us to
// reuse TableIterInfo objects to lower the overhead associated
// with executing ZBody::Exec for non-recursive functions.
// Empty constructor for a simple version that initializes all the
// member variables via BeginLoop(). Helpful for supporting recursive
// functions that include table iterations.
TableIterInfo() {}
// Version that populates the fixed fields up front, with the
// dynamic ones being done with SetLoopVars().
TableIterInfo(const std::vector<TypePtr>* _loop_var_types, const std::vector<bool>* _lvt_is_managed,
TypePtr _value_var_type) {
SetIterInfo(_loop_var_types, _lvt_is_managed, std::move(_value_var_type));
}
// Sets the fixed fields.
void SetIterInfo(const std::vector<TypePtr>* _loop_var_types, const std::vector<bool>* _lvt_is_managed,
TypePtr _value_var_type) {
loop_var_types = _loop_var_types;
lvt_is_managed = _lvt_is_managed;
value_var_type = std::move(_value_var_type);
}
// We do, however, want to make sure that when we go out of scope,
// if we have any pending iterators we clear them.
~TableIterInfo() { Clear(); }
// Start looping over the elements of the given table. "_aux"
// Start looping over the elements of the given table. "aux"
// provides information about the index variables, their types,
// and the type of the value variable (if any).
void BeginLoop(TableValPtr _tv, ZInstAux* _aux) {
tv = _tv;
aux = _aux;
void BeginLoop(TableValPtr _tv, ZVal* frame, ZInstAux* aux) {
tv = std::move(_tv);
for ( auto lv : aux->loop_vars )
if ( lv < 0 )
loop_vars.push_back(nullptr);
else
loop_vars.push_back(&frame[lv]);
SetIterInfo(&aux->types, &aux->is_managed, aux->value_var_type);
PrimeIter();
}
void BeginLoop(TableValPtr _tv, std::vector<ZVal*> _loop_vars) {
tv = std::move(_tv);
loop_vars = std::move(_loop_vars);
PrimeIter();
}
void PrimeIter() {
auto tvd = tv->AsTable();
tbl_iter = tvd->begin();
tbl_end = tvd->end();
@ -43,18 +76,17 @@ public:
// Performs the next iteration (assuming IsDoneIterating() returned
// false), assigning to the index variables.
void NextIter(ZVal* frame) {
void NextIter() {
auto ind_lv = tv->RecreateIndex(*(*tbl_iter)->GetHashKey());
for ( int i = 0; i < ind_lv->Length(); ++i ) {
ValPtr ind_lv_p = ind_lv->Idx(i);
auto lv = aux->loop_vars[i];
if ( lv < 0 )
auto lv = loop_vars[i];
if ( ! lv )
continue;
auto& var = frame[lv];
if ( aux->is_managed[i] )
ZVal::DeleteManagedType(var);
auto& t = aux->types[i];
var = ZVal(ind_lv_p, t);
ValPtr ind_lv_p = ind_lv->Idx(i);
if ( (*lvt_is_managed)[i] )
ZVal::DeleteManagedType(*lv);
*lv = ZVal(ind_lv_p, (*loop_var_types)[i]);
}
IterFinished();
@ -63,7 +95,7 @@ public:
// For the current iteration, returns the corresponding value.
ZVal IterValue() {
auto tev = (*tbl_iter)->value;
return ZVal(tev->GetVal(), aux->value_var_type);
return ZVal(tev->GetVal(), value_var_type);
}
// Called upon finishing the iteration.
@ -78,8 +110,10 @@ public:
private:
TableValPtr tv = nullptr;
// Associated auxiliary information.
ZInstAux* aux = nullptr;
std::vector<ZVal*> loop_vars;
const std::vector<TypePtr>* loop_var_types;
const std::vector<bool>* lvt_is_managed;
TypePtr value_var_type;
std::optional<DictIterator<TableEntryVal>> tbl_iter;
std::optional<DictIterator<TableEntryVal>> tbl_end;

View file

@ -127,9 +127,9 @@ const ZAMStmt ZAMCompiler::AddInst(const ZInstI& inst, bool suppress_non_local)
auto gs = pending_global_store;
pending_global_store = -1;
auto store_inst = ZInstI(OP_STORE_GLOBAL_V, gs);
auto store_inst = ZInstI(OP_STORE_GLOBAL_g, gs);
store_inst.op_type = OP_V_I1;
store_inst.t = globalsI[gs].id->GetType();
store_inst.SetType(globalsI[gs].id->GetType());
return AddInst(store_inst);
}
@ -138,15 +138,15 @@ const ZAMStmt ZAMCompiler::AddInst(const ZInstI& inst, bool suppress_non_local)
auto cs = pending_capture_store;
pending_capture_store = -1;
auto& cv = *func->GetType()->AsFuncType()->GetCaptures();
auto& cv = *func->GetType()->GetCaptures();
auto& c_id = cv[cs].Id();
ZOp op;
if ( ZVal::IsManagedType(c_id->GetType()) )
op = OP_STORE_MANAGED_CAPTURE_VV;
op = OP_STORE_MANAGED_CAPTURE_Vi;
else
op = OP_STORE_CAPTURE_VV;
op = OP_STORE_CAPTURE_Vi;
auto store_inst = ZInstI(op, RawSlot(c_id.get()), cs);
store_inst.op_type = OP_VV_I2;

View file

@ -132,7 +132,7 @@ const ZAMStmt ZAMCompiler::IfElse(const Expr* e, const Stmt* s1, const Stmt* s2)
if ( e->Tag() == EXPR_NAME ) {
auto n = e->AsNameExpr();
ZOp op = (s1 && s2) ? OP_IF_ELSE_VV : (s1 ? OP_IF_VV : OP_IF_NOT_VV);
ZOp op = (s1 && s2) ? OP_IF_ELSE_Vb : (s1 ? OP_IF_Vb : OP_IF_NOT_Vb);
ZInstI cond(op, FrameSlot(n), 0);
cond_stmt = AddInst(cond);
@ -160,66 +160,67 @@ const ZAMStmt ZAMCompiler::IfElse(const Expr* e, const Stmt* s1, const Stmt* s2)
// Only the else clause is non-empty.
auto s2_end = CompileStmt(s2);
AddCFT(insts1.back(), CFT_BLOCK_END);
// For complex conditionals, we need to invert their sense since
// we're switching to "if ( ! cond ) s2".
auto z = insts1[cond_stmt.stmt_num];
switch ( z->op ) {
case OP_IF_ELSE_VV:
case OP_IF_VV:
case OP_IF_NOT_VV:
case OP_IF_ELSE_Vb:
case OP_IF_Vb:
case OP_IF_NOT_Vb:
// These are generated correctly above, no need
// to fix up.
break;
case OP_HAS_FIELD_COND_VVV: z->op = OP_NOT_HAS_FIELD_COND_VVV; break;
case OP_NOT_HAS_FIELD_COND_VVV: z->op = OP_HAS_FIELD_COND_VVV; break;
case OP_HAS_FIELD_COND_Vib: z->op = OP_NOT_HAS_FIELD_COND_Vib; break;
case OP_NOT_HAS_FIELD_COND_Vib: z->op = OP_HAS_FIELD_COND_Vib; break;
case OP_CONN_EXISTS_COND_VV: z->op = OP_NOT_CONN_EXISTS_COND_VV; break;
case OP_NOT_CONN_EXISTS_COND_VV: z->op = OP_CONN_EXISTS_COND_VV; break;
case OP_CONN_EXISTS_COND_Vb: z->op = OP_NOT_CONN_EXISTS_COND_Vb; break;
case OP_NOT_CONN_EXISTS_COND_Vb: z->op = OP_CONN_EXISTS_COND_Vb; break;
case OP_IS_ICMP_PORT_COND_VV: z->op = OP_NOT_IS_ICMP_PORT_COND_VV; break;
case OP_NOT_IS_ICMP_PORT_COND_VV: z->op = OP_IS_ICMP_PORT_COND_VV; break;
case OP_IS_ICMP_PORT_COND_Vb: z->op = OP_NOT_IS_ICMP_PORT_COND_Vb; break;
case OP_NOT_IS_ICMP_PORT_COND_Vb: z->op = OP_IS_ICMP_PORT_COND_Vb; break;
case OP_IS_TCP_PORT_COND_VV: z->op = OP_NOT_IS_TCP_PORT_COND_VV; break;
case OP_NOT_IS_TCP_PORT_COND_VV: z->op = OP_IS_TCP_PORT_COND_VV; break;
case OP_IS_TCP_PORT_COND_Vb: z->op = OP_NOT_IS_TCP_PORT_COND_Vb; break;
case OP_NOT_IS_TCP_PORT_COND_Vb: z->op = OP_IS_TCP_PORT_COND_Vb; break;
case OP_IS_UDP_PORT_COND_VV: z->op = OP_NOT_IS_UDP_PORT_COND_VV; break;
case OP_NOT_IS_UDP_PORT_COND_VV: z->op = OP_IS_UDP_PORT_COND_VV; break;
case OP_IS_UDP_PORT_COND_Vb: z->op = OP_NOT_IS_UDP_PORT_COND_Vb; break;
case OP_NOT_IS_UDP_PORT_COND_Vb: z->op = OP_IS_UDP_PORT_COND_Vb; break;
case OP_IS_V4_ADDR_COND_VV: z->op = OP_NOT_IS_V4_ADDR_COND_VV; break;
case OP_NOT_IS_V4_ADDR_COND_VV: z->op = OP_IS_V4_ADDR_COND_VV; break;
case OP_IS_V4_ADDR_COND_Vb: z->op = OP_NOT_IS_V4_ADDR_COND_Vb; break;
case OP_NOT_IS_V4_ADDR_COND_Vb: z->op = OP_IS_V4_ADDR_COND_Vb; break;
case OP_IS_V6_ADDR_COND_VV: z->op = OP_NOT_IS_V6_ADDR_COND_VV; break;
case OP_NOT_IS_V6_ADDR_COND_VV: z->op = OP_IS_V6_ADDR_COND_VV; break;
case OP_IS_V6_ADDR_COND_Vb: z->op = OP_NOT_IS_V6_ADDR_COND_Vb; break;
case OP_NOT_IS_V6_ADDR_COND_Vb: z->op = OP_IS_V6_ADDR_COND_Vb; break;
case OP_READING_LIVE_TRAFFIC_COND_V: z->op = OP_NOT_READING_LIVE_TRAFFIC_COND_V; break;
case OP_NOT_READING_LIVE_TRAFFIC_COND_V: z->op = OP_READING_LIVE_TRAFFIC_COND_V; break;
case OP_READING_LIVE_TRAFFIC_COND_b: z->op = OP_NOT_READING_LIVE_TRAFFIC_COND_b; break;
case OP_NOT_READING_LIVE_TRAFFIC_COND_b: z->op = OP_READING_LIVE_TRAFFIC_COND_b; break;
case OP_READING_TRACES_COND_V: z->op = OP_NOT_READING_TRACES_COND_V; break;
case OP_NOT_READING_TRACES_COND_V: z->op = OP_READING_TRACES_COND_V; break;
case OP_READING_TRACES_COND_b: z->op = OP_NOT_READING_TRACES_COND_b; break;
case OP_NOT_READING_TRACES_COND_b: z->op = OP_READING_TRACES_COND_b; break;
case OP_TABLE_HAS_ELEMENTS_COND_VV: z->op = OP_NOT_TABLE_HAS_ELEMENTS_COND_VV; break;
case OP_NOT_TABLE_HAS_ELEMENTS_COND_VV: z->op = OP_TABLE_HAS_ELEMENTS_COND_VV; break;
case OP_TABLE_HAS_ELEMENTS_COND_Vb: z->op = OP_NOT_TABLE_HAS_ELEMENTS_COND_Vb; break;
case OP_NOT_TABLE_HAS_ELEMENTS_COND_Vb: z->op = OP_TABLE_HAS_ELEMENTS_COND_Vb; break;
case OP_VECTOR_HAS_ELEMENTS_COND_VV: z->op = OP_NOT_VECTOR_HAS_ELEMENTS_COND_VV; break;
case OP_NOT_VECTOR_HAS_ELEMENTS_COND_VV: z->op = OP_VECTOR_HAS_ELEMENTS_COND_VV; break;
case OP_VECTOR_HAS_ELEMENTS_COND_Vb: z->op = OP_NOT_VECTOR_HAS_ELEMENTS_COND_Vb; break;
case OP_NOT_VECTOR_HAS_ELEMENTS_COND_Vb: z->op = OP_VECTOR_HAS_ELEMENTS_COND_Vb; break;
case OP_VAL_IS_IN_TABLE_COND_VVV: z->op = OP_VAL_IS_NOT_IN_TABLE_COND_VVV; break;
case OP_VAL_IS_NOT_IN_TABLE_COND_VVV: z->op = OP_VAL_IS_IN_TABLE_COND_VVV; break;
case OP_VAL_IS_IN_TABLE_COND_VVb: z->op = OP_NOT_VAL_IS_IN_TABLE_COND_VVb; break;
case OP_NOT_VAL_IS_IN_TABLE_COND_VVb: z->op = OP_VAL_IS_IN_TABLE_COND_VVb; break;
case OP_CONST_IS_IN_TABLE_COND_VVC: z->op = OP_CONST_IS_NOT_IN_TABLE_COND_VVC; break;
case OP_CONST_IS_NOT_IN_TABLE_COND_VVC: z->op = OP_CONST_IS_IN_TABLE_COND_VVC; break;
case OP_CONST_IS_IN_TABLE_COND_VCb: z->op = OP_NOT_CONST_IS_IN_TABLE_COND_VCb; break;
case OP_NOT_CONST_IS_IN_TABLE_COND_VCb: z->op = OP_CONST_IS_IN_TABLE_COND_VCb; break;
case OP_VAL2_IS_IN_TABLE_COND_VVVV: z->op = OP_VAL2_IS_NOT_IN_TABLE_COND_VVVV; break;
case OP_VAL2_IS_NOT_IN_TABLE_COND_VVVV: z->op = OP_VAL2_IS_IN_TABLE_COND_VVVV; break;
case OP_VAL2_IS_IN_TABLE_COND_VVVb: z->op = OP_VAL2_IS_NOT_IN_TABLE_COND_VVVb; break;
case OP_VAL2_IS_NOT_IN_TABLE_COND_VVVb: z->op = OP_VAL2_IS_IN_TABLE_COND_VVVb; break;
case OP_VAL2_IS_IN_TABLE_COND_VVVC: z->op = OP_VAL2_IS_NOT_IN_TABLE_COND_VVVC; break;
case OP_VAL2_IS_NOT_IN_TABLE_COND_VVVC: z->op = OP_VAL2_IS_IN_TABLE_COND_VVVC; break;
case OP_VAL2_IS_IN_TABLE_COND_VVbC: z->op = OP_VAL2_IS_NOT_IN_TABLE_COND_VVbC; break;
case OP_VAL2_IS_NOT_IN_TABLE_COND_VVbC: z->op = OP_VAL2_IS_IN_TABLE_COND_VVbC; break;
case OP_VAL2_IS_IN_TABLE_COND_VVCV: z->op = OP_VAL2_IS_NOT_IN_TABLE_COND_VVCV; break;
case OP_VAL2_IS_NOT_IN_TABLE_COND_VVCV: z->op = OP_VAL2_IS_IN_TABLE_COND_VVCV; break;
case OP_VAL2_IS_IN_TABLE_COND_VVCb: z->op = OP_VAL2_IS_NOT_IN_TABLE_COND_VVCb; break;
case OP_VAL2_IS_NOT_IN_TABLE_COND_VVCb: z->op = OP_VAL2_IS_IN_TABLE_COND_VVCb; break;
default: reporter->InternalError("inconsistency in ZAMCompiler::IfElse");
}
@ -234,7 +235,7 @@ const ZAMStmt ZAMCompiler::GenCond(const Expr* e, int& branch_v) {
if ( e->Tag() == EXPR_HAS_FIELD ) {
auto hf = e->AsHasFieldExpr();
auto z = GenInst(OP_HAS_FIELD_COND_VVV, op1->AsNameExpr(), hf->Field());
auto z = GenInst(OP_HAS_FIELD_COND_Vib, op1->AsNameExpr(), hf->Field());
z.op_type = OP_VVV_I2_I3;
branch_v = 3;
return AddInst(z);
@ -251,15 +252,15 @@ const ZAMStmt ZAMCompiler::GenCond(const Expr* e, int& branch_v) {
}
if ( op1->Tag() == EXPR_NAME ) {
auto z = GenInst(OP_VAL_IS_IN_TABLE_COND_VVV, op1->AsNameExpr(), op2, 0);
z.t = op1->GetType();
auto z = GenInst(OP_VAL_IS_IN_TABLE_COND_VVb, op1->AsNameExpr(), op2, 0);
z.SetType(op1->GetType());
branch_v = 3;
return AddInst(z);
}
if ( op1->Tag() == EXPR_CONST ) {
auto z = GenInst(OP_CONST_IS_IN_TABLE_COND_VVC, op2, op1->AsConstExpr(), 0);
z.t = op1->GetType();
auto z = GenInst(OP_CONST_IS_IN_TABLE_COND_VCb, op2, op1->AsConstExpr(), 0);
z.SetType(op1->GetType());
branch_v = 2;
return AddInst(z);
}
@ -286,30 +287,30 @@ const ZAMStmt ZAMCompiler::GenCond(const Expr* e, int& branch_v) {
ZInstI z;
if ( name0 && name1 ) {
z = GenInst(OP_VAL2_IS_IN_TABLE_COND_VVVV, n0, n1, op2, 0);
z = GenInst(OP_VAL2_IS_IN_TABLE_COND_VVVb, n0, n1, op2, 0);
branch_v = 4;
z.t2 = n0->GetType();
z.SetType2(n0->GetType());
}
else if ( name0 ) {
z = GenInst(OP_VAL2_IS_IN_TABLE_COND_VVVC, n0, op2, c1, 0);
z = GenInst(OP_VAL2_IS_IN_TABLE_COND_VVbC, n0, op2, c1, 0);
branch_v = 3;
z.t2 = n0->GetType();
z.SetType2(n0->GetType());
}
else if ( name1 ) {
z = GenInst(OP_VAL2_IS_IN_TABLE_COND_VVCV, n1, op2, c0, 0);
z = GenInst(OP_VAL2_IS_IN_TABLE_COND_VVCb, n1, op2, c0, 0);
branch_v = 3;
z.t2 = n1->GetType();
z.SetType2(n1->GetType());
}
else { // Both are constants, assign first to temporary.
auto slot = TempForConst(c0);
z = ZInstI(OP_VAL2_IS_IN_TABLE_COND_VVVC, slot, FrameSlot(op2), 0, c1);
z = ZInstI(OP_VAL2_IS_IN_TABLE_COND_VVbC, slot, FrameSlot(op2), 0, c1);
z.op_type = OP_VVVC_I3;
branch_v = 3;
z.t2 = c0->GetType();
z.SetType2(c0->GetType());
}
return AddInst(z);
@ -328,9 +329,9 @@ const ZAMStmt ZAMCompiler::GenCond(const Expr* e, int& branch_v) {
ZOp op;
if ( aggr->GetType()->Tag() == TYPE_TABLE )
op = OP_TABLE_HAS_ELEMENTS_COND_VV;
op = OP_TABLE_HAS_ELEMENTS_COND_Vb;
else
op = OP_VECTOR_HAS_ELEMENTS_COND_VV;
op = OP_VECTOR_HAS_ELEMENTS_COND_Vb;
branch_v = 2;
return AddInst(GenInst(op, aggr, +0));
@ -409,37 +410,42 @@ const ZAMStmt ZAMCompiler::ValueSwitch(const SwitchStmt* sw, const NameExpr* v,
// Figure out which jump table we're using.
auto t = v ? v->GetType() : c->GetType();
return GenSwitch(sw, slot, t->InternalType());
}
const ZAMStmt ZAMCompiler::GenSwitch(const SwitchStmt* sw, int slot, InternalTypeTag it) {
int tbl = 0;
ZOp op;
switch ( t->InternalType() ) {
switch ( it ) {
case TYPE_INTERNAL_INT:
op = OP_SWITCHI_VVV;
op = OP_SWITCHI_Vii;
tbl = int_casesI.size();
break;
case TYPE_INTERNAL_UNSIGNED:
op = OP_SWITCHU_VVV;
op = OP_SWITCHU_Vii;
tbl = uint_casesI.size();
break;
case TYPE_INTERNAL_DOUBLE:
op = OP_SWITCHD_VVV;
op = OP_SWITCHD_Vii;
tbl = double_casesI.size();
break;
case TYPE_INTERNAL_STRING:
op = OP_SWITCHS_VVV;
op = OP_SWITCHS_Vii;
tbl = str_casesI.size();
break;
case TYPE_INTERNAL_ADDR:
op = OP_SWITCHA_VVV;
op = OP_SWITCHA_Vii;
tbl = str_casesI.size();
break;
case TYPE_INTERNAL_SUBNET:
op = OP_SWITCHN_VVV;
op = OP_SWITCHN_Vii;
tbl = str_casesI.size();
break;
@ -723,29 +729,39 @@ const ZAMStmt ZAMCompiler::LoopOverTable(const ForStmt* f, const NameExpr* val)
auto iter_slot = table_iters.size();
table_iters.emplace_back();
auto z = ZInstI(OP_INIT_TABLE_LOOP_VV, FrameSlot(val), iter_slot);
z.op_type = OP_VV_I2;
z.SetType(value_var ? value_var->GetType() : nullptr);
z.aux = aux;
auto zi = ZInstI(OP_INIT_TABLE_LOOP_Vf, FrameSlot(val), iter_slot);
zi.op_type = OP_VV_I2;
if ( value_var )
zi.SetType(value_var->GetType());
zi.aux = aux;
auto init_end = AddInst(z);
(void)AddInst(zi);
ZInstI zn;
auto iter_head = StartingBlock();
if ( value_var ) {
ZOp op = no_loop_vars ? OP_NEXT_TABLE_ITER_VAL_VAR_NO_VARS_VVV : OP_NEXT_TABLE_ITER_VAL_VAR_VVV;
z = ZInstI(op, FrameSlot(value_var), iter_slot, 0);
z.CheckIfManaged(value_var->GetType());
z.op_type = OP_VVV_I2_I3;
ZOp op = no_loop_vars ? OP_NEXT_TABLE_ITER_VAL_VAR_NO_VARS_Vfb : OP_NEXT_TABLE_ITER_VAL_VAR_Vfb;
zn = ZInstI(op, FrameSlot(value_var), iter_slot, 0);
zn.CheckIfManaged(value_var->GetType());
zn.op_type = OP_VVV_I2_I3;
}
else {
ZOp op = no_loop_vars ? OP_NEXT_TABLE_ITER_NO_VARS_VV : OP_NEXT_TABLE_ITER_VV;
z = ZInstI(op, iter_slot, 0);
z.op_type = OP_VV_I1_I2;
ZOp op = no_loop_vars ? OP_NEXT_TABLE_ITER_NO_VARS_fb : OP_NEXT_TABLE_ITER_fb;
zn = ZInstI(op, iter_slot, 0);
zn.op_type = OP_VV_I1_I2;
}
z.aux = aux; // so ZOpt.cc can get to it
// Need a separate instance of aux so the CFT info doesn't get shared with
// the loop init. We populate it with the loop_vars (only) because the
// optimizer needs access to those for (1) tracking their lifetime, and
// (2) remapping them (not strictly needed, see the comment in ReMapFrame()).
zn.aux = new ZInstAux(0);
zn.aux->loop_vars = aux->loop_vars;
AddCFT(&zn, CFT_LOOP);
AddCFT(&zn, CFT_LOOP_COND);
return FinishLoop(iter_head, z, body, iter_slot, true);
return FinishLoop(iter_head, zn, body, iter_slot, true);
}
const ZAMStmt ZAMCompiler::LoopOverVector(const ForStmt* f, const NameExpr* val) {
@ -755,7 +771,7 @@ const ZAMStmt ZAMCompiler::LoopOverVector(const ForStmt* f, const NameExpr* val)
int iter_slot = num_step_iters++;
auto z = ZInstI(OP_INIT_VECTOR_LOOP_VV, FrameSlot(val), iter_slot);
auto z = ZInstI(OP_INIT_VECTOR_LOOP_Vs, FrameSlot(val), iter_slot);
z.op_type = OP_VV_I2;
auto init_end = AddInst(z);
@ -765,29 +781,31 @@ const ZAMStmt ZAMCompiler::LoopOverVector(const ForStmt* f, const NameExpr* val)
if ( value_var ) {
if ( slot >= 0 ) {
z = ZInstI(OP_NEXT_VECTOR_ITER_VAL_VAR_VVVV, slot, FrameSlot(value_var), iter_slot, 0);
z = ZInstI(OP_NEXT_VECTOR_ITER_VAL_VAR_VVsb, slot, FrameSlot(value_var), iter_slot, 0);
z.op_type = OP_VVVV_I3_I4;
}
else {
z = ZInstI(OP_NEXT_VECTOR_BLANK_ITER_VAL_VAR_VVV, FrameSlot(value_var), iter_slot, 0);
z = ZInstI(OP_NEXT_VECTOR_BLANK_ITER_VAL_VAR_Vsb, FrameSlot(value_var), iter_slot, 0);
z.op_type = OP_VVV_I2_I3;
}
z.t = value_var->GetType();
z.is_managed = ZVal::IsManagedType(z.t);
z.SetType(value_var->GetType());
}
else {
if ( slot >= 0 ) {
z = ZInstI(OP_NEXT_VECTOR_ITER_VVV, slot, iter_slot, 0);
z = ZInstI(OP_NEXT_VECTOR_ITER_Vsb, slot, iter_slot, 0);
z.op_type = OP_VVV_I2_I3;
}
else {
z = ZInstI(OP_NEXT_VECTOR_BLANK_ITER_VV, iter_slot, 0);
z = ZInstI(OP_NEXT_VECTOR_BLANK_ITER_sb, iter_slot, 0);
z.op_type = OP_VV_I1_I2;
}
}
AddCFT(&z, CFT_LOOP);
AddCFT(&z, CFT_LOOP_COND);
return FinishLoop(iter_head, z, f->LoopBody(), iter_slot, false);
}
@ -802,12 +820,12 @@ const ZAMStmt ZAMCompiler::LoopOverString(const ForStmt* f, const Expr* e) {
ZInstI z;
if ( n ) {
z = ZInstI(OP_INIT_STRING_LOOP_VV, FrameSlot(n), iter_slot);
z = ZInstI(OP_INIT_STRING_LOOP_Vs, FrameSlot(n), iter_slot);
z.op_type = OP_VV_I2;
}
else {
ASSERT(c);
z = ZInstI(OP_INIT_STRING_LOOP_VC, iter_slot, c);
z = ZInstI(OP_INIT_STRING_LOOP_Cs, iter_slot, c);
z.op_type = OP_VC_I1;
}
@ -815,15 +833,18 @@ const ZAMStmt ZAMCompiler::LoopOverString(const ForStmt* f, const Expr* e) {
auto iter_head = StartingBlock();
if ( loop_var->IsBlank() ) {
z = ZInstI(OP_NEXT_STRING_BLANK_ITER_VV, iter_slot, 0);
z = ZInstI(OP_NEXT_STRING_BLANK_ITER_sb, iter_slot, 0);
z.op_type = OP_VV_I1_I2;
}
else {
z = ZInstI(OP_NEXT_STRING_ITER_VVV, FrameSlot(loop_var), iter_slot, 0);
z = ZInstI(OP_NEXT_STRING_ITER_Vsb, FrameSlot(loop_var), iter_slot, 0);
z.op_type = OP_VVV_I2_I3;
z.is_managed = true;
}
AddCFT(&z, CFT_LOOP);
AddCFT(&z, CFT_LOOP_COND);
return FinishLoop(iter_head, z, f->LoopBody(), iter_slot, false);
}
@ -832,7 +853,11 @@ const ZAMStmt ZAMCompiler::Loop(const Stmt* body) {
PushBreaks();
auto head = StartingBlock();
(void)CompileStmt(body);
auto b = CompileStmt(body);
AddCFT(insts1[head.stmt_num], CFT_LOOP);
AddCFT(insts1[b.stmt_num], CFT_BLOCK_END);
auto tail = GoTo(GoToTarget(head));
ResolveNexts(GoToTarget(head));
@ -845,11 +870,12 @@ const ZAMStmt ZAMCompiler::FinishLoop(const ZAMStmt iter_head, ZInstI& iter_stmt
bool is_table) {
auto loop_iter = AddInst(iter_stmt);
auto body_end = CompileStmt(body);
AddCFT(insts1[body_end.stmt_num], CFT_BLOCK_END);
// We only need cleanup for looping over tables, but for now we
// need some sort of placeholder instruction (until the optimizer
// can elide it) to resolve loop exits.
ZOp op = is_table ? OP_END_TABLE_LOOP_V : OP_NOP;
ZOp op = is_table ? OP_END_TABLE_LOOP_f : OP_NOP;
auto loop_end = GoTo(GoToTarget(iter_head));
auto z = ZInstI(op, iter_slot);
@ -875,6 +901,12 @@ const ZAMStmt ZAMCompiler::CompileReturn(const ReturnStmt* r) {
if ( retvars.empty() ) { // a "true" return
if ( e ) {
if ( pf->ProfiledFunc()->Flavor() == FUNC_FLAVOR_HOOK ) {
ASSERT(e->GetType()->Tag() == TYPE_BOOL);
auto true_c = make_intrusive<ConstExpr>(val_mgr->True());
return ReturnC(true_c.get());
}
if ( e->Tag() == EXPR_NAME )
return ReturnV(e->AsNameExpr());
else
@ -970,7 +1002,7 @@ const ZAMStmt ZAMCompiler::CompileWhen(const WhenStmt* ws) {
auto timeout = wi->TimeoutExpr();
auto lambda = NewSlot(true);
(void)BuildLambda(lambda, wi->Lambda().get());
(void)BuildLambda(lambda, wi->Lambda());
std::vector<IDPtr> local_aggr_slots;
for ( auto& l : wi->WhenExprLocals() )
@ -1006,8 +1038,7 @@ const ZAMStmt ZAMCompiler::CompileWhen(const WhenStmt* ws) {
if ( ws->IsReturn() ) {
(void)AddInst(z);
z = ZInstI(OP_RETURN_C);
z.c = ZVal();
z = ZInstI(OP_WHEN_RETURN_X);
}
return AddInst(z);

View file

@ -40,7 +40,7 @@ void ZAMCompiler::LoadParam(const ID* id) {
ZOp op;
op = AssignmentFlavor(OP_LOAD_VAL_VV, id->GetType()->Tag());
op = AssignmentFlavor(OP_LOAD_VAL_Vi, id->GetType()->Tag());
int slot = AddToFrame(id);
@ -57,9 +57,9 @@ const ZAMStmt ZAMCompiler::LoadGlobal(const ID* id) {
if ( id->IsType() )
// Need a special load for these, as they don't fit
// with the usual template.
op = OP_LOAD_GLOBAL_TYPE_VV;
op = OP_LOAD_GLOBAL_TYPE_Vg;
else
op = AssignmentFlavor(OP_LOAD_GLOBAL_VV, id->GetType()->Tag());
op = AssignmentFlavor(OP_LOAD_GLOBAL_Vg, id->GetType()->Tag());
auto slot = RawSlot(id);
@ -78,13 +78,14 @@ const ZAMStmt ZAMCompiler::LoadCapture(const ID* id) {
ZOp op;
if ( ZVal::IsManagedType(id->GetType()) )
op = OP_LOAD_MANAGED_CAPTURE_VV;
op = OP_LOAD_MANAGED_CAPTURE_Vi;
else
op = OP_LOAD_CAPTURE_VV;
op = OP_LOAD_CAPTURE_Vi;
auto slot = RawSlot(id);
ZInstI z(op, slot, CaptureOffset(id));
z.SetType(id->GetType());
z.op_type = OP_VV_I2;
return AddInst(z, true);

View file

@ -230,16 +230,16 @@ ValPtr ZInst::ConstVal() const {
bool ZInst::IsLoopIterationAdvancement() const {
switch ( op ) {
case OP_NEXT_TABLE_ITER_VV:
case OP_NEXT_TABLE_ITER_NO_VARS_VV:
case OP_NEXT_TABLE_ITER_VAL_VAR_VVV:
case OP_NEXT_TABLE_ITER_VAL_VAR_NO_VARS_VVV:
case OP_NEXT_VECTOR_ITER_VVV:
case OP_NEXT_VECTOR_BLANK_ITER_VV:
case OP_NEXT_VECTOR_ITER_VAL_VAR_VVVV:
case OP_NEXT_VECTOR_BLANK_ITER_VAL_VAR_VVV:
case OP_NEXT_STRING_ITER_VVV:
case OP_NEXT_STRING_BLANK_ITER_VV: return true;
case OP_NEXT_TABLE_ITER_fb:
case OP_NEXT_TABLE_ITER_NO_VARS_fb:
case OP_NEXT_TABLE_ITER_VAL_VAR_Vfb:
case OP_NEXT_TABLE_ITER_VAL_VAR_NO_VARS_Vfb:
case OP_NEXT_VECTOR_ITER_Vsb:
case OP_NEXT_VECTOR_BLANK_ITER_sb:
case OP_NEXT_VECTOR_ITER_VAL_VAR_VVsb:
case OP_NEXT_VECTOR_BLANK_ITER_VAL_VAR_Vsb:
case OP_NEXT_STRING_ITER_Vsb:
case OP_NEXT_STRING_BLANK_ITER_sb: return true;
default: return false;
}
@ -282,7 +282,7 @@ bool ZInst::AssignsToSlot1() const {
bool ZInst::AssignsToSlot(int slot) const {
switch ( op ) {
case OP_NEXT_VECTOR_ITER_VAL_VAR_VVVV: return slot == 1 || slot == 2;
case OP_NEXT_VECTOR_ITER_VAL_VAR_VVsb: return slot == 1 || slot == 2;
default: return slot == 1 && AssignsToSlot1();
}
@ -351,7 +351,7 @@ TraversalCode ZInstAux::Traverse(TraversalCallback* cb) const {
HANDLE_TC_STMT_PRE(tc);
}
for ( auto& lvt : loop_var_types ) {
for ( auto& lvt : types ) {
tc = lvt->Traverse(cb);
HANDLE_TC_STMT_PRE(tc);
}
@ -437,8 +437,9 @@ string ZInstI::VName(int n, const FrameMap* frame_ids, const FrameReMap* remappi
bool ZInstI::DoesNotContinue() const {
switch ( op ) {
case OP_GOTO_V:
case OP_GOTO_b:
case OP_HOOK_BREAK_X:
case OP_WHEN_RETURN_X:
case OP_RETURN_C:
case OP_RETURN_V:
case OP_RETURN_X: return true;
@ -476,7 +477,7 @@ bool ZInstI::IsDirectAssignment() const {
bool ZInstI::HasCaptures() const {
switch ( op ) {
case OP_LAMBDA_VV:
case OP_LAMBDA_Vi:
case OP_WHEN_V:
case OP_WHEN_TIMEOUT_VV:
case OP_WHEN_TIMEOUT_VC: return true;
@ -636,7 +637,7 @@ void ZInstI::UpdateSlots(std::vector<int>& slot_mapping) {
}
bool ZInstI::IsGlobalLoad() const {
if ( op == OP_LOAD_GLOBAL_TYPE_VV )
if ( op == OP_LOAD_GLOBAL_TYPE_Vg )
// These don't have flavors.
return true;
@ -645,7 +646,7 @@ bool ZInstI::IsGlobalLoad() const {
if ( global_ops.empty() ) { // Initialize the set.
for ( int t = 0; t < NUM_TYPES; ++t ) {
TypeTag tag = TypeTag(t);
ZOp global_op_flavor = AssignmentFlavor(OP_LOAD_GLOBAL_VV, tag, false);
ZOp global_op_flavor = AssignmentFlavor(OP_LOAD_GLOBAL_Vg, tag, false);
if ( global_op_flavor != OP_NOP )
global_ops.insert(global_op_flavor);
@ -655,11 +656,11 @@ bool ZInstI::IsGlobalLoad() const {
return global_ops.count(op) > 0;
}
bool ZInstI::IsCaptureLoad() const { return op == OP_LOAD_CAPTURE_VV || op == OP_LOAD_MANAGED_CAPTURE_VV; }
bool ZInstI::IsCaptureLoad() const { return op == OP_LOAD_CAPTURE_Vi || op == OP_LOAD_MANAGED_CAPTURE_Vi; }
void ZInstI::InitConst(const ConstExpr* ce) {
auto v = ce->ValuePtr();
t = ce->GetType();
SetType(ce->GetType());
c = ZVal(v, t);
if ( ZAM_error )

View file

@ -127,9 +127,19 @@ public:
// Meta-data associated with the execution.
protected:
// These are protected to ensure that setting 't' is done via SetType(),
// so we can keep is_managed consistent with it. We don't need that
// for 't2' but keep them together for consistency.
// Type, usually for interpreting the constant.
TypePtr t = nullptr;
TypePtr t2 = nullptr; // just a few ops need two types
TypePtr t;
TypePtr t2; // just a few ops need two types
public:
const TypePtr& GetType() const { return t; }
const TypePtr& GetType2() const { return t2; }
// Auxiliary information. We could in principle use this to
// consolidate a bunch of the above, though at the cost of
@ -143,7 +153,7 @@ public:
// Whether v1 represents a frame slot type for which we
// explicitly manage the memory.
bool is_managed = false;
std::optional<bool> is_managed;
};
// A intermediary ZAM instruction, one that includes information/methods
@ -217,7 +227,7 @@ public:
// True if this instruction always branches elsewhere. Different
// from DoesNotContinue() in that returns & hook breaks do not
// continue, but they are not branches.
bool IsUnconditionalBranch() const { return op == OP_GOTO_V; }
bool IsUnconditionalBranch() const { return op == OP_GOTO_b; }
// True if this instruction is of the form "v1 = v2".
bool IsDirectAssignment() const;
@ -257,19 +267,19 @@ public:
bool IsLoad() const { return op_type == OP_VV_FRAME || IsNonLocalLoad(); }
// True if the instruction corresponds to storing a global.
bool IsGlobalStore() const { return op == OP_STORE_GLOBAL_V; }
bool IsGlobalStore() const { return op == OP_STORE_GLOBAL_g; }
void CheckIfManaged(const TypePtr& t) {
if ( ZVal::IsManagedType(t) )
is_managed = true;
}
void CheckIfManaged(const TypePtr& t) { is_managed = ZVal::IsManagedType(t); }
void SetType(TypePtr _t) {
t = std::move(_t);
ASSERT(t);
if ( t )
CheckIfManaged(t);
}
void SetType2(TypePtr _t) { t2 = std::move(_t); }
// Whether the instruction should be included in final code
// generation.
bool live = true;
@ -340,6 +350,21 @@ public:
return zv;
}
// The same, but for read-only access for which memory-management is
// not required.
const ZVal& ToDirectZVal(const ZVal* frame) const {
if ( c )
return zc;
if ( i >= 0 )
return frame[i];
// Currently the way we use AuxElem's we shouldn't get here, but
// just in case we do, return something sound rather than mis-indexing
// the frame.
static ZVal null_zval;
return null_zval;
}
int Slot() const { return i; }
int IntVal() const { return i; }
const ValPtr& Constant() const { return c; }
@ -453,11 +478,8 @@ public:
AuxElem* elems = nullptr;
bool elems_has_slots = true;
// Ingredients associated with lambdas ...
ScriptFuncPtr primary_func;
// ... and its name.
std::string lambda_name;
// Info for constructing lambdas.
LambdaExprPtr lambda;
// For "when" statements.
std::shared_ptr<WhenInfo> wi;
@ -466,11 +488,11 @@ public:
std::unique_ptr<CatArg>* cat_args = nullptr;
// Used for accessing function names.
IDPtr id_val = nullptr;
IDPtr id_val;
// Interpreter call expression associated with this instruction,
// for error reporting and stack backtraces.
CallExprPtr call_expr = nullptr;
CallExprPtr call_expr;
// Used for direct calls.
Func* func = nullptr;
@ -555,8 +577,8 @@ extern std::unordered_map<ZOp, std::unordered_map<TypeTag, ZOp>> assignment_flav
// value is superfluous.
extern std::unordered_map<ZOp, ZOp> assignmentless_op;
// Maps flavorful assignments to what op-type their non-assignment
// Maps flavorful assignments to what operand class their non-assignment
// counterpart uses.
extern std::unordered_map<ZOp, ZAMOpType> assignmentless_op_type;
extern std::unordered_map<ZOp, ZAMOpType> assignmentless_op_class;
} // namespace zeek::detail

View file

@ -57,7 +57,7 @@ bool op_side_effects[] = {
std::unordered_map<ZOp, std::unordered_map<TypeTag, ZOp>> assignment_flavor;
std::unordered_map<ZOp, ZOp> assignmentless_op;
std::unordered_map<ZOp, ZAMOpType> assignmentless_op_type;
std::unordered_map<ZOp, ZAMOpType> assignmentless_op_class;
ZOp AssignmentFlavor(ZOp orig, TypeTag tag, bool strict) {
static bool did_init = false;

View file

@ -4,6 +4,8 @@
#pragma once
#include <string>
namespace zeek::detail {
// Opcodes associated with ZAM instructions.
@ -59,6 +61,16 @@ enum ZAMOp1Flavor {
OP1_INTERNAL, // we're doing some internal manipulation of the slot
};
// Used to describe ZAM instructions for validation.
struct ZAMInstDesc {
std::string op_class; // associated class
std::string op_types; // operand types
std::string op_eval; // evaluation
};
// Provides access to the validation description of each operation.
extern std::unordered_map<ZOp, ZAMInstDesc> zam_inst_desc;
// Maps an operand to its flavor.
extern ZAMOp1Flavor op1_flavor[];