diff --git a/src/script_opt/ZAM/AM-Opt.cc b/src/script_opt/ZAM/AM-Opt.cc index 68fd594370..6bea39bb39 100644 --- a/src/script_opt/ZAM/AM-Opt.cc +++ b/src/script_opt/ZAM/AM-Opt.cc @@ -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()); } diff --git a/src/script_opt/ZAM/Compile.h b/src/script_opt/ZAM/Compile.h index 9d3744bed7..c08873729f 100644 --- a/src/script_opt/ZAM/Compile.h +++ b/src/script_opt/ZAM/Compile.h @@ -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); diff --git a/src/script_opt/ZAM/Expr.cc b/src/script_opt/ZAM/Expr.cc index cf74cccc4c..9f3953cb1f 100644 --- a/src/script_opt/ZAM/Expr.cc +++ b/src/script_opt/ZAM/Expr.cc @@ -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(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(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(c)}; + z.aux->call_expr = {NewRef{}, const_cast(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); } diff --git a/src/script_opt/ZAM/Ops.in b/src/script_opt/ZAM/Ops.in index d8c60b7d65..af66ad92ba 100644 --- a/src/script_opt/ZAM/Ops.in +++ b/src/script_opt/ZAM/Ops.in @@ -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(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 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(z.t); internal-op Init-Table type V eval auto tt = cast_intrusive(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(wi, wi->WhenExprGlobals(), local_aggrs, timeout, f, z.loc.get()); + (void)make_intrusive(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. diff --git a/src/script_opt/ZAM/ZInst.cc b/src/script_opt/ZAM/ZInst.cc index 88ef1134e0..c619e25984 100644 --- a/src/script_opt/ZAM/ZInst.cc +++ b/src/script_opt/ZAM/ZInst.cc @@ -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 { diff --git a/src/script_opt/ZAM/ZInst.h b/src/script_opt/ZAM/ZInst.h index dca8cae733..6b0bb890a5 100644 --- a/src/script_opt/ZAM/ZInst.h +++ b/src/script_opt/ZAM/ZInst.h @@ -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 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 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.