mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
updates to ZAM operations / gen-zam regularization, other than the operations themselves
This commit is contained in:
parent
1d7e71b499
commit
5fc2c601b4
17 changed files with 422 additions and 294 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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[];
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue