better isolation of ZAM instruction elements

hooks for tracking extended ZAM profiling location
This commit is contained in:
Vern Paxson 2024-03-10 17:09:34 -04:00 committed by Tim Wojtulewicz
parent dc376953fa
commit 9f9f01580f
6 changed files with 134 additions and 90 deletions

View file

@ -577,7 +577,7 @@ void ZAMCompiler::ReMapFrame() {
if ( new_slot < 0 ) {
ODesc d;
inst->stmt->GetLocationInfo()->Describe(&d);
inst->loc->Loc()->Describe(&d);
reporter->Error("%s: value used but not set: %s", d.Description(),
frame_denizens[slot]->Name());
}
@ -748,7 +748,7 @@ void ZAMCompiler::CheckSlotUse(int slot, const ZInstI* inst) {
if ( denizen_beginning.count(slot) == 0 ) {
ODesc d;
inst->stmt->GetLocationInfo()->Describe(&d);
inst->loc->Loc()->Describe(&d);
reporter->Error("%s: value used but not set: %s", d.Description(), frame_denizens[slot]->Name());
}

View file

@ -228,6 +228,7 @@ private:
const ZAMStmt Call(const ExprStmt* e);
const ZAMStmt AssignToCall(const ExprStmt* e);
const ZAMStmt DoCall(const CallExpr* c, const NameExpr* n);
bool CheckForBuiltIn(const ExprPtr& e, CallExprPtr c);
const ZAMStmt AssignVecElems(const Expr* e);
const ZAMStmt AssignTableElem(const Expr* e);

View file

@ -315,6 +315,7 @@ const ZAMStmt ZAMCompiler::CompileSchedule(const NameExpr* n, const ConstExpr* c
if ( len == 0 ) {
z = n ? ZInstI(OP_SCHEDULE0_ViH, FrameSlot(n), is_interval) : ZInstI(OP_SCHEDULE0_CiH, is_interval, c);
z.op_type = n ? OP_VV_I2 : OP_VC_I1;
z.aux = new ZInstAux(0);
}
else {
@ -330,7 +331,7 @@ const ZAMStmt ZAMCompiler::CompileSchedule(const NameExpr* n, const ConstExpr* c
z.aux = InternalBuildVals(l);
}
z.event_handler = h;
z.aux->event_handler = h;
return AddInst(z);
}
@ -349,12 +350,11 @@ const ZAMStmt ZAMCompiler::CompileEvent(EventHandler* h, const ListExpr* l) {
if ( n > 4 || ! all_vars ) { // do generic form
ZInstI z(OP_EVENT_HL);
z.aux = InternalBuildVals(l);
z.event_handler = h;
z.aux->event_handler = h;
return AddInst(z);
}
ZInstI z;
z.event_handler = h;
if ( n == 0 ) {
z.op = OP_EVENT0_X;
@ -403,6 +403,11 @@ const ZAMStmt ZAMCompiler::CompileEvent(EventHandler* h, const ListExpr* l) {
}
}
if ( ! z.aux )
z.aux = new ZInstAux(0);
z.aux->event_handler = h;
return AddInst(z);
}
@ -872,11 +877,8 @@ const ZAMStmt ZAMCompiler::AssignTableElem(const Expr* e) {
const ZAMStmt ZAMCompiler::Call(const ExprStmt* e) {
auto c = cast_intrusive<CallExpr>(e->StmtExprPtr());
if ( IsZAM_BuiltIn(c.get()) ) {
auto ret = LastInst();
insts1.back()->call_expr = std::move(c);
return ret;
}
if ( CheckForBuiltIn(c, c) )
return LastInst();
return DoCall(e->StmtExpr()->AsCallExpr(), nullptr);
}
@ -885,26 +887,37 @@ const ZAMStmt ZAMCompiler::AssignToCall(const ExprStmt* e) {
auto assign = e->StmtExpr()->AsAssignExpr();
auto call = cast_intrusive<CallExpr>(assign->GetOp2());
if ( IsZAM_BuiltIn(e->StmtExpr()) ) {
auto ret = LastInst();
insts1.back()->call_expr = call;
return ret;
}
if ( CheckForBuiltIn(e->StmtExprPtr(), call) )
return LastInst();
auto n = assign->GetOp1()->AsRefExpr()->GetOp1()->AsNameExpr();
return DoCall(call.get(), n);
}
bool ZAMCompiler::CheckForBuiltIn(const ExprPtr& e, CallExprPtr c) {
if ( ! IsZAM_BuiltIn(e.get()) )
return false;
auto ret = LastInst();
auto& i = insts1.back();
if ( ! i->aux )
i->aux = new ZInstAux(0);
i->aux->call_expr = c;
return true;
}
const ZAMStmt ZAMCompiler::DoCall(const CallExpr* c, const NameExpr* n) {
auto func = c->Func()->AsNameExpr();
auto func_id = func->IdPtr();
auto func_val = func_id->GetVal();
auto& args = c->Args()->Exprs();
int nargs = args.length();
int call_case = nargs;
bool indirect = ! func_id->IsGlobal() || ! func_id->GetVal();
bool indirect = ! func_id->IsGlobal() || ! func_val;
bool in_when = c->IsInWhen();
if ( indirect || in_when )
@ -1041,7 +1054,7 @@ const ZAMStmt ZAMCompiler::DoCall(const CallExpr* c, const NameExpr* n) {
z.aux->can_change_non_locals = true;
}
z.call_expr = {NewRef{}, const_cast<CallExpr*>(c)};
z.aux->call_expr = {NewRef{}, const_cast<CallExpr*>(c)};
if ( in_when )
z.SetType(n->GetType());
@ -1049,8 +1062,11 @@ const ZAMStmt ZAMCompiler::DoCall(const CallExpr* c, const NameExpr* n) {
if ( ! indirect || func_id->IsGlobal() ) {
z.aux->id_val = func_id;
if ( ! indirect )
z.func = func_id->GetVal()->AsFunc();
if ( ! indirect ) {
z.aux->func = func_id->GetVal()->AsFunc();
if ( z.aux->func->GetKind() == Func::BUILTIN_FUNC )
z.aux->is_BiF_call = true;
}
}
return AddInst(z);
@ -1064,11 +1080,11 @@ const ZAMStmt ZAMCompiler::ConstructTable(const NameExpr* n, const Expr* e) {
auto z = GenInst(OP_CONSTRUCT_TABLE_VV, n, width);
z.aux = InternalBuildVals(con, width + 1);
z.t = tt;
z.attrs = e->AsTableConstructorExpr()->GetAttrs();
z.aux->attrs = e->AsTableConstructorExpr()->GetAttrs();
auto zstmt = AddInst(z);
auto def_attr = z.attrs ? z.attrs->Find(ATTR_DEFAULT) : nullptr;
auto def_attr = z.aux->attrs ? z.aux->attrs->Find(ATTR_DEFAULT) : nullptr;
if ( ! def_attr || def_attr->GetExpr()->Tag() != EXPR_LAMBDA )
return zstmt;
@ -1102,7 +1118,7 @@ const ZAMStmt ZAMCompiler::ConstructSet(const NameExpr* n, const Expr* e) {
auto z = GenInst(OP_CONSTRUCT_SET_VV, n, width);
z.aux = InternalBuildVals(con, width);
z.t = e->GetType();
z.attrs = e->AsSetConstructorExpr()->GetAttrs();
z.aux->attrs = e->AsSetConstructorExpr()->GetAttrs();
return AddInst(z);
}

View file

@ -273,7 +273,7 @@ macro AssignV1T(v, t) {
# the instruction.
macro AssignV1(v) AssignV1T(v, z.t)
macro BRANCH(target_slot) { pc = z.target_slot; continue; }
macro BRANCH(target_slot) { DO_ZAM_PROFILE; pc = z.target_slot; continue; }
########## Unary Ops ##########
@ -1153,7 +1153,7 @@ direct-unary-op Table-Constructor ConstructTable
macro ConstructTableOrSetPre()
auto tt = cast_intrusive<TableType>(z.t);
auto new_t = new TableVal(tt, z.attrs);
auto new_t = new TableVal(tt, z.aux->attrs);
auto aux = z.aux;
auto n = aux->n;
auto ind_width = z.v2;
@ -1654,7 +1654,7 @@ macro WhenCall(func)
throw ZAMDelayedCallException();
auto& lhs = frame[z.v1];
auto trigger = f->GetTrigger();
Val* v = trigger ? trigger->Lookup(z.call_expr.get()) : nullptr;
Val* v = trigger ? trigger->Lookup(z.aux->call_expr.get()) : nullptr;
ValPtr vp;
if ( v )
vp = {NewRef{}, v};
@ -1666,7 +1666,7 @@ macro WhenCall(func)
std::vector<ValPtr> args;
for ( auto i = 0; i < n; ++i )
args.push_back(aux->ToVal(frame, i));
f->SetCall(z.call_expr.get());
f->SetCall(z.aux->call_expr.get());
/* It's possible that this function will call another that
* itself returns null because *it* is the actual blocker.
* That will set ZAM_error, which we need to ignore.
@ -1685,7 +1685,7 @@ macro WhenCall(func)
internal-op WhenCallN
type V
side-effects
eval WhenCall(z.func)
eval WhenCall(z.aux->func)
internal-op WhenIndCallN
type VV
@ -1703,7 +1703,7 @@ macro EvalScheduleArgs(time, is_delta, build_args)
double dt = time.double_val;
if ( is_delta )
dt += run_state::network_time;
auto handler = EventHandlerPtr(z.event_handler);
auto handler = EventHandlerPtr(z.aux->event_handler);
ValVec args;
build_args
auto timer = new ScheduleTimer(handler, std::move(args), dt);
@ -1744,19 +1744,19 @@ op1-read
custom-method return CompileEvent(h, l);
eval ValVec args;
z.aux->FillValVec(args, frame);
QueueEvent(z.event_handler, args);
QueueEvent(z.aux->event_handler, args);
internal-op Event0
type X
eval ValVec args(0);
QueueEvent(z.event_handler, args);
QueueEvent(z.aux->event_handler, args);
internal-op Event1
type V
op1-read
eval ValVec args(1);
args[0] = frame[z.v1].ToVal(z.t);
QueueEvent(z.event_handler, args);
QueueEvent(z.aux->event_handler, args);
internal-op Event2
type VV
@ -1764,7 +1764,7 @@ op1-read
eval ValVec args(2);
args[0] = frame[z.v1].ToVal(z.t);
args[1] = frame[z.v2].ToVal(z.t2);
QueueEvent(z.event_handler, args);
QueueEvent(z.aux->event_handler, args);
internal-op Event3
type VVV
@ -1774,7 +1774,7 @@ eval ValVec args(3);
args[0] = frame[z.v1].ToVal(z.t);
args[1] = frame[z.v2].ToVal(z.t2);
args[2] = frame[z.v3].ToVal(aux->elems[2].GetType());
QueueEvent(z.event_handler, args);
QueueEvent(z.aux->event_handler, args);
internal-op Event4
type VVVV
@ -1785,7 +1785,7 @@ eval ValVec args(4);
args[1] = frame[z.v2].ToVal(z.t2);
args[2] = frame[z.v3].ToVal(aux->elems[2].GetType());
args[3] = frame[z.v4].ToVal(aux->elems[3].GetType());
QueueEvent(z.event_handler, args);
QueueEvent(z.aux->event_handler, args);
op Return
@ -1795,6 +1795,7 @@ eval EvalReturn(nullptr,)
macro EvalReturn(val, type)
ret_u = val;
type
DO_ZAM_PROFILE
pc = end_pc;
continue;
@ -1819,6 +1820,7 @@ macro EvalSwitchBody(cases, postscript)
else
pc = t[v];
postscript
DO_ZAM_PROFILE
continue;
}
@ -2130,7 +2132,7 @@ eval auto vt = cast_intrusive<VectorType>(z.t);
internal-op Init-Table
type V
eval auto tt = cast_intrusive<TableType>(z.t);
auto t = new TableVal(tt, z.attrs);
auto t = new TableVal(tt, z.aux->attrs);
Unref(frame[z.v1].table_val);
frame[z.v1].table_val = t;
@ -2162,7 +2164,7 @@ macro BuildWhen(timeout)
if ( v )
local_aggrs.push_back(v);
}
(void)make_intrusive<trigger::Trigger>(wi, wi->WhenExprGlobals(), local_aggrs, timeout, f, z.loc.get());
(void)make_intrusive<trigger::Trigger>(wi, wi->WhenExprGlobals(), local_aggrs, timeout, f, z.loc->Loc());
########################################
# Internal
@ -2263,6 +2265,7 @@ internal-op Hook-Break
type X
eval flow = FLOW_BREAK;
pc = end_pc;
DO_ZAM_PROFILE
continue;
# Slot 2 gives frame size.

View file

@ -10,75 +10,87 @@ using std::string;
namespace zeek::detail {
void ZInst::Dump(zeek_uint_t inst_num, const FrameReMap* mappings) const {
// printf("v%d ", n);
void ZInst::Dump(FILE* f, zeek_uint_t inst_num, const FrameReMap* mappings, const string& prefix) const {
// fprintf(f, "v%d ", n);
auto id1 = VName(1, inst_num, mappings);
auto id2 = VName(2, inst_num, mappings);
auto id3 = VName(3, inst_num, mappings);
auto id4 = VName(4, inst_num, mappings);
Dump(id1, id2, id3, id4);
Dump(f, prefix, id1, id2, id3, id4);
}
void ZInst::Dump(const string& id1, const string& id2, const string& id3, const string& id4) const {
printf("%s ", ZOP_name(op));
// printf("(%s) ", op_type_name(op_type));
void ZInst::Dump(FILE* f, const string& prefix, const string& id1, const string& id2, const string& id3,
const string& id4) const {
fprintf(f, "%s ", ZOP_name(op));
// fprintf(f, "(%s) ", op_type_name(op_type));
if ( t && 0 )
printf("(%s) ", type_name(t->Tag()));
fprintf(f, "(%s) ", type_name(t->Tag()));
switch ( op_type ) {
case OP_X: break;
case OP_V: printf("%s", id1.c_str()); break;
case OP_V: fprintf(f, "%s", id1.c_str()); break;
case OP_VV: printf("%s, %s", id1.c_str(), id2.c_str()); break;
case OP_VV: fprintf(f, "%s, %s", id1.c_str(), id2.c_str()); break;
case OP_VVV: printf("%s, %s, %s", id1.c_str(), id2.c_str(), id3.c_str()); break;
case OP_VVV: fprintf(f, "%s, %s, %s", id1.c_str(), id2.c_str(), id3.c_str()); break;
case OP_VVVV: printf("%s, %s, %s, %s", id1.c_str(), id2.c_str(), id3.c_str(), id4.c_str()); break;
case OP_VVVV: fprintf(f, "%s, %s, %s, %s", id1.c_str(), id2.c_str(), id3.c_str(), id4.c_str()); break;
case OP_VVVC: printf("%s, %s, %s, %s", id1.c_str(), id2.c_str(), id3.c_str(), ConstDump().c_str()); break;
case OP_VVVC: fprintf(f, "%s, %s, %s, %s", id1.c_str(), id2.c_str(), id3.c_str(), ConstDump().c_str()); break;
case OP_C: printf("%s", ConstDump().c_str()); break;
case OP_C: fprintf(f, "%s", ConstDump().c_str()); break;
case OP_VC: printf("%s, %s", id1.c_str(), ConstDump().c_str()); break;
case OP_VC: fprintf(f, "%s, %s", id1.c_str(), ConstDump().c_str()); break;
case OP_VVC: printf("%s, %s, %s", id1.c_str(), id2.c_str(), ConstDump().c_str()); break;
case OP_VVC: fprintf(f, "%s, %s, %s", id1.c_str(), id2.c_str(), ConstDump().c_str()); break;
case OP_V_I1: printf("%d", v1); break;
case OP_V_I1: fprintf(f, "%d", v1); break;
case OP_VC_I1: printf("%d %s", v1, ConstDump().c_str()); break;
case OP_VC_I1: fprintf(f, "%d %s", v1, ConstDump().c_str()); break;
case OP_VV_FRAME: printf("%s, interpreter frame[%d]", id1.c_str(), v2); break;
case OP_VV_FRAME: fprintf(f, "%s, interpreter frame[%d]", id1.c_str(), v2); break;
case OP_VV_I2: printf("%s, %d", id1.c_str(), v2); break;
case OP_VV_I2: fprintf(f, "%s, %d", id1.c_str(), v2); break;
case OP_VV_I1_I2: printf("%d, %d", v1, v2); break;
case OP_VV_I1_I2: fprintf(f, "%d, %d", v1, v2); break;
case OP_VVC_I2: printf("%s, %d, %s", id1.c_str(), v2, ConstDump().c_str()); break;
case OP_VVC_I2: fprintf(f, "%s, %d, %s", id1.c_str(), v2, ConstDump().c_str()); break;
case OP_VVV_I3: printf("%s, %s, %d", id1.c_str(), id2.c_str(), v3); break;
case OP_VVV_I3: fprintf(f, "%s, %s, %d", id1.c_str(), id2.c_str(), v3); break;
case OP_VVV_I2_I3: printf("%s, %d, %d", id1.c_str(), v2, v3); break;
case OP_VVV_I2_I3: fprintf(f, "%s, %d, %d", id1.c_str(), v2, v3); break;
case OP_VVVV_I4: printf("%s, %s, %s, %d", id1.c_str(), id2.c_str(), id3.c_str(), v4); break;
case OP_VVVV_I4: fprintf(f, "%s, %s, %s, %d", id1.c_str(), id2.c_str(), id3.c_str(), v4); break;
case OP_VVVV_I3_I4: printf("%s, %s, %d, %d", id1.c_str(), id2.c_str(), v3, v4); break;
case OP_VVVV_I3_I4: fprintf(f, "%s, %s, %d, %d", id1.c_str(), id2.c_str(), v3, v4); break;
case OP_VVVV_I2_I3_I4: printf("%s, %d, %d, %d", id1.c_str(), v2, v3, v4); break;
case OP_VVVV_I2_I3_I4: fprintf(f, "%s, %d, %d, %d", id1.c_str(), v2, v3, v4); break;
case OP_VVVC_I3: printf("%s, %s, %d, %s", id1.c_str(), id2.c_str(), v3, ConstDump().c_str()); break;
case OP_VVVC_I3: fprintf(f, "%s, %s, %d, %s", id1.c_str(), id2.c_str(), v3, ConstDump().c_str()); break;
case OP_VVVC_I2_I3: printf("%s, %d, %d, %s", id1.c_str(), v2, v3, ConstDump().c_str()); break;
case OP_VVVC_I2_I3: fprintf(f, "%s, %d, %d, %s", id1.c_str(), v2, v3, ConstDump().c_str()); break;
case OP_VVVC_I1_I2_I3: printf("%d, %d, %d, %s", v1, v2, v3, ConstDump().c_str()); break;
case OP_VVVC_I1_I2_I3: fprintf(f, "%d, %d, %d, %s", v1, v2, v3, ConstDump().c_str()); break;
}
if ( func )
printf(" (func %s)", func->Name());
auto func = aux ? aux->func : nullptr;
printf("\n");
if ( func )
fprintf(f, " (func %s)", func->Name());
if ( loc ) {
auto l = loc->Describe(true);
if ( func && (func->GetBodies().empty() || func->GetBodies()[0].stmts->Tag() != STMT_ZAM) )
l = l + ";" + func->Name();
if ( ! prefix.empty() )
l = prefix + l;
fprintf(f, " // %s", l.c_str());
}
fprintf(f, "\n");
}
int ZInst::NumFrameSlots() const {
@ -286,16 +298,16 @@ string ZInst::ConstDump() const {
return d.Description();
}
void ZInstI::Dump(const FrameMap* frame_ids, const FrameReMap* remappings) const {
void ZInstI::Dump(FILE* f, const FrameMap* frame_ids, const FrameReMap* remappings) const {
int n = NumFrameSlots();
// printf("v%d ", n);
// fprintf(f, "v%d ", n);
auto id1 = VName(1, frame_ids, remappings);
auto id2 = VName(2, frame_ids, remappings);
auto id3 = VName(3, frame_ids, remappings);
auto id4 = VName(4, frame_ids, remappings);
ZInst::Dump(id1, id2, id3, id4);
ZInst::Dump(f, "", id1, id2, id3, id4);
}
string ZInstI::VName(int n, const FrameMap* frame_ids, const FrameReMap* remappings) const {

View file

@ -60,16 +60,22 @@ public:
ZInst(ZOp _op, ZAMOpType _op_type) {
op = _op;
op_type = _op_type;
ASSERT(curr_loc);
loc = curr_loc;
}
// Create a stub instruction that will be populated later.
ZInst() = default;
ZInst() {
ASSERT(curr_loc);
loc = curr_loc;
}
virtual ~ZInst() = default;
// Methods for printing out the instruction for debugging/maintenance.
void Dump(zeek_uint_t inst_num, const FrameReMap* mappings) const;
void Dump(const std::string& id1, const std::string& id2, const std::string& id3, const std::string& id4) const;
// Methods for printing out the instruction for debugging/profiling.
void Dump(FILE* f, zeek_uint_t inst_num, const FrameReMap* mappings, const std::string& prefix) const;
void Dump(FILE* f, const std::string& prefix, const std::string& id1, const std::string& id2,
const std::string& id3, const std::string& id4) const;
// Returns the name to use in identifying one of the slots/integer
// values (designated by "n"). "inst_num" identifies the instruction
@ -120,11 +126,7 @@ public:
// Type, usually for interpreting the constant.
TypePtr t = nullptr;
TypePtr t2 = nullptr; // just a few ops need two types
const Expr* e = nullptr; // only needed for "when" expressions
Func* func = nullptr; // used for calls
EventHandler* event_handler = nullptr; // used for referring to events
AttributesPtr attrs = nullptr; // used for things like constructors
TypePtr t2 = nullptr; // just a few ops need two types
// Auxiliary information. We could in principle use this to
// consolidate a bunch of the above, though at the cost of
@ -132,12 +134,9 @@ public:
// which is why we bundle these separately.
ZInstAux* aux = nullptr;
// Location associated with this instruction, for error reporting.
std::shared_ptr<Location> loc;
// Interpreter call expression associated with this instruction,
// for error reporting and stack backtraces.
CallExprPtr call_expr = nullptr;
// Location associated with this instruction, for error reporting
// and profiling.
std::shared_ptr<ZAMLocInfo> loc;
// Whether v1 represents a frame slot type for which we
// explicitly manage the memory.
@ -201,7 +200,7 @@ public:
ZInstI() {}
// If "remappings" is non-nil, then it is used instead of frame_ids.
void Dump(const FrameMap* frame_ids, const FrameReMap* remappings) const;
void Dump(FILE* f, const FrameMap* frame_ids, const FrameReMap* remappings) const;
// Note that this is *not* an override of the base class's VName
// but instead a method with similar functionality but somewhat
@ -294,9 +293,6 @@ public:
// a branch target).
int num_labels = 0;
// Used for debugging. Transformed into the ZInst "loc" field.
StmtPtr stmt = curr_stmt;
private:
// Initialize 'c' from the given ConstExpr.
void InitConst(const ConstExpr* ce);
@ -467,6 +463,22 @@ public:
// Used for accessing function names.
IDPtr id_val = nullptr;
// Interpreter call expression associated with this instruction,
// for error reporting and stack backtraces.
CallExprPtr call_expr = nullptr;
// Used for direct calls.
Func* func = nullptr;
// Whether we know that we're calling a BiF.
bool is_BiF_call = false;
// Used for referring to events.
EventHandler* event_handler = nullptr;
// Used for things like constructors.
AttributesPtr attrs = nullptr;
// Whether the instruction can lead to globals/captures changing.
// Currently only needed by the optimizer, but convenient to
// store here.