Script optimization maintenance and updates:

maintenance fixes for variadic run-time checks, '_' placeholder identifier
  "-O allow-cond" permits compiling scripts to C++ when influenced by @if conditionals
  more robust standalone compile-to-C++ properties
  fix for nested "when" statements
  test suite updates
This commit is contained in:
Vern Paxson 2022-11-08 11:56:32 -08:00
parent bc0284aefa
commit ee0a6f6835
40 changed files with 257 additions and 158 deletions

View file

@ -194,6 +194,7 @@ public:
call = arg_call; call = arg_call;
SetTriggerAssoc((void*)call); SetTriggerAssoc((void*)call);
} }
void SetOnlyCall(const CallExpr* arg_call) { call = arg_call; }
const CallExpr* GetCall() const { return call; } const CallExpr* GetCall() const { return call; }
void SetTriggerAssoc(const void* arg_assoc) { assoc = arg_assoc; } void SetTriggerAssoc(const void* arg_assoc) { assoc = arg_assoc; }

View file

@ -206,13 +206,15 @@ static void print_analysis_help()
fprintf(stderr, "\n--optimize options when generating C++:\n"); fprintf(stderr, "\n--optimize options when generating C++:\n");
fprintf(stderr, " add-C++ add C++ script bodies to existing generated code\n"); fprintf(stderr, " add-C++ add C++ script bodies to existing generated code\n");
fprintf(
stderr,
" allow-cond allow standalone compilation of functions influenced by conditionals\n");
fprintf(stderr, " gen-C++ generate C++ script bodies\n"); fprintf(stderr, " gen-C++ generate C++ script bodies\n");
fprintf(stderr, " gen-standalone-C++ generate \"standalone\" C++ script bodies\n"); fprintf(stderr, " gen-standalone-C++ generate \"standalone\" C++ script bodies\n");
fprintf(stderr, " help print this list\n"); fprintf(stderr, " help print this list\n");
fprintf(stderr, " report-C++ report available C++ script bodies and exit\n"); fprintf(stderr, " report-C++ report available C++ script bodies and exit\n");
fprintf(stderr, " report-uncompilable print names of functions that can't be compiled\n"); fprintf(stderr, " report-uncompilable print names of functions that can't be compiled\n");
fprintf(stderr, " use-C++ use available C++ script bodies\n"); fprintf(stderr, " use-C++ use available C++ script bodies\n");
fprintf(stderr, "\n experimental options for incremental compilation:\n");
} }
static void set_analysis_option(const char* opt, Options& opts) static void set_analysis_option(const char* opt, Options& opts)
@ -240,6 +242,8 @@ static void set_analysis_option(const char* opt, Options& opts)
a_o.activate = a_o.dump_ZAM = true; a_o.activate = a_o.dump_ZAM = true;
else if ( util::streq(opt, "add-C++") ) else if ( util::streq(opt, "add-C++") )
a_o.add_CPP = true; a_o.add_CPP = true;
else if ( util::streq(opt, "allow-cond") )
a_o.allow_cond = true;
else if ( util::streq(opt, "gen-C++") ) else if ( util::streq(opt, "gen-C++") )
a_o.gen_CPP = true; a_o.gen_CPP = true;
else if ( util::streq(opt, "gen-standalone-C++") ) else if ( util::streq(opt, "gen-standalone-C++") )

View file

@ -101,13 +101,9 @@ void CPPCompile::CreateFunction(const FuncTypePtr& ft, const ProfileFunc* pf, co
compiled_funcs.emplace(fname); compiled_funcs.emplace(fname);
} }
auto h = pf->HashVal(); body_hashes[fname] = pf->HashVal();
body_hashes[fname] = h;
body_priorities[fname] = priority; body_priorities[fname] = priority;
body_names.emplace(body.get(), fname); body_names.emplace(body.get(), fname);
total_hash = merge_p_hashes(total_hash, h);
} }
void CPPCompile::DeclareSubclass(const FuncTypePtr& ft, const ProfileFunc* pf, const string& fname, void CPPCompile::DeclareSubclass(const FuncTypePtr& ft, const ProfileFunc* pf, const string& fname,

View file

@ -73,9 +73,8 @@ void CPPCompile::Compile(bool report_uncompilable)
working_dir = buf; working_dir = buf;
GenProlog();
unordered_set<string> filenames_reported_as_skipped; unordered_set<string> filenames_reported_as_skipped;
bool had_to_skip = false;
// Determine which functions we can call directly, and reuse // Determine which functions we can call directly, and reuse
// previously compiled instances of those if present. // previously compiled instances of those if present.
@ -84,11 +83,19 @@ void CPPCompile::Compile(bool report_uncompilable)
const auto& f = func.Func(); const auto& f = func.Func();
auto& ofiles = analysis_options.only_files; auto& ofiles = analysis_options.only_files;
auto allow_cond = analysis_options.allow_cond;
string fn = func.Body()->GetLocationInfo()->filename; string fn = func.Body()->GetLocationInfo()->filename;
if ( ! func.ShouldSkip() && ! ofiles.empty() && files_with_conditionals.count(fn) > 0 ) if ( ! allow_cond && ! func.ShouldSkip() && ! ofiles.empty() &&
files_with_conditionals.count(fn) > 0 )
{ {
if ( filenames_reported_as_skipped.count(fn) == 0 ) if ( report_uncompilable )
reporter->Warning(
"%s cannot be compiled to C++ due to source file %s having conditional code",
f->Name(), fn.c_str());
else if ( filenames_reported_as_skipped.count(fn) == 0 )
{ {
reporter->Warning( reporter->Warning(
"skipping compilation of files in %s due to presence of conditional code", "skipping compilation of files in %s due to presence of conditional code",
@ -96,6 +103,7 @@ void CPPCompile::Compile(bool report_uncompilable)
filenames_reported_as_skipped.insert(fn); filenames_reported_as_skipped.insert(fn);
} }
had_to_skip = true;
func.SetSkip(true); func.SetSkip(true);
} }
@ -114,17 +122,30 @@ void CPPCompile::Compile(bool report_uncompilable)
} }
else else
{ {
if ( reason && standalone ) if ( reason && report_uncompilable )
reporter->Error("%s cannot be compiled to standalone C++ due to %s", f->Name(), {
reason); had_to_skip = true;
reporter->Warning("%s cannot be compiled to C++ due to %s", f->Name(), reason);
else if ( reason && report_uncompilable ) }
fprintf(stderr, "%s cannot be compiled to C++ due to %s\n", f->Name(), reason);
not_fully_compilable.insert(f->Name()); not_fully_compilable.insert(f->Name());
} }
} }
if ( standalone && had_to_skip )
reporter->FatalError(
"aborting standalone compilation to C++ due to having to skip some functions");
// Generate a hash unique for this compilation.
for ( const auto& func : funcs )
if ( ! func.ShouldSkip() )
total_hash = merge_p_hashes(total_hash, func.Profile()->HashVal());
auto t = util::current_time();
total_hash = merge_p_hashes(total_hash, hash<double>{}(t));
GenProlog();
// Track all of the types we'll be using. // Track all of the types we'll be using.
for ( const auto& t : pfs.RepTypes() ) for ( const auto& t : pfs.RepTypes() )
{ {
@ -213,7 +234,7 @@ void CPPCompile::GenProlog()
Emit("#include \"zeek/script_opt/CPP/Runtime.h\"\n"); Emit("#include \"zeek/script_opt/CPP/Runtime.h\"\n");
Emit("namespace zeek::detail { //\n"); Emit("namespace zeek::detail { //\n");
Emit("namespace CPP_%s { // %s\n", Fmt(addl_tag), working_dir); Emit("namespace CPP_%s { // %s\n", Fmt(total_hash), working_dir);
// The following might-or-might-not wind up being populated/used. // The following might-or-might-not wind up being populated/used.
Emit("std::vector<int> field_mapping;"); Emit("std::vector<int> field_mapping;");

View file

@ -305,11 +305,13 @@ string CPPCompile::GenCallExpr(const CallExpr* c, GenType gt)
auto f_id = f->AsNameExpr()->Id(); auto f_id = f->AsNameExpr()->Id();
const auto& params = f_id->GetType()->AsFuncType()->Params(); const auto& params = f_id->GetType()->AsFuncType()->Params();
auto id_name = f_id->Name(); auto id_name = f_id->Name();
auto nargs = args_l->Exprs().length();
bool is_compiled = compiled_simple_funcs.count(id_name) > 0; bool is_compiled = compiled_simple_funcs.count(id_name) > 0;
bool was_compiled = hashed_funcs.count(id_name) > 0; bool was_compiled = hashed_funcs.count(id_name) > 0;
bool is_variadic = params->NumFields() == 1 && nargs != 1;
if ( ! is_async && (is_compiled || was_compiled) ) if ( ! is_async && ! is_variadic && (is_compiled || was_compiled) )
{ // Can call directly. { // Can call directly.
string fname; string fname;
@ -318,7 +320,7 @@ string CPPCompile::GenCallExpr(const CallExpr* c, GenType gt)
else else
fname = compiled_simple_funcs[id_name]; fname = compiled_simple_funcs[id_name];
if ( args_l->Exprs().length() > 0 ) if ( nargs > 0 )
gen = fname + "(" + GenArgs(params, args_l) + ", f__CPP)"; gen = fname + "(" + GenArgs(params, args_l) + ", f__CPP)";
else else
gen = fname + "(f__CPP)"; gen = fname + "(f__CPP)";
@ -1097,6 +1099,10 @@ string CPPCompile::GenDirectAssign(const ExprPtr& lhs, const string& rhs_native,
const string& rhs_val_ptr, GenType gt, bool top_level) const string& rhs_val_ptr, GenType gt, bool top_level)
{ {
auto n = lhs->AsNameExpr()->Id(); auto n = lhs->AsNameExpr()->Id();
if ( n->IsBlank() )
return rhs_native;
auto name = IDNameStr(n); auto name = IDNameStr(n);
string gen; string gen;

View file

@ -338,14 +338,7 @@ void CPPCompile::GenStandaloneActivation()
void CPPCompile::GenLoad() void CPPCompile::GenLoad()
{ {
// First, generate a hash unique to this compilation.
auto t = util::current_time();
auto th = hash<double>{}(t);
total_hash = merge_p_hashes(total_hash, th);
Emit("register_scripts__CPP(%s, standalone_init__CPP);", Fmt(total_hash)); Emit("register_scripts__CPP(%s, standalone_init__CPP);", Fmt(total_hash));
printf("global init_CPP_%llu = load_CPP(%llu);\n", total_hash, total_hash); printf("global init_CPP_%llu = load_CPP(%llu);\n", total_hash, total_hash);
} }

View file

@ -162,7 +162,7 @@ about associated expressions/statements, making them hard to puzzle out.
This could be fixed, but would add execution overhead in passing around This could be fixed, but would add execution overhead in passing around
the necessary strings / `Location` objects. the necessary strings / `Location` objects.
* To avoid subtle bugs, the compiler will refrain from compiling script elements (functions, hooks, event handlers) that include conditional code. In addition, when using `--optimize-files` it will not compile any functions appearing in a source file that includes conditional code (even if it's not in a function body). * To avoid subtle bugs, the compiler will refrain from compiling script elements (functions, hooks, event handlers) that include conditional code. In addition, when using `--optimize-files` it will not compile any functions appearing in a source file that includes conditional code (even if it's not in a function body). You can override this refusal with `-O allow-cond`.
* Code compiled with `-O gen-standalone-C++` will not execute any global * Code compiled with `-O gen-standalone-C++` will not execute any global
statements when invoked using the "stand-in" script. The right fix for statements when invoked using the "stand-in" script. The right fix for
@ -170,7 +170,7 @@ this is to shift from encapsulating global statements in a pseudo-function,
as currently done, to instead be in a pseudo-event handler. as currently done, to instead be in a pseudo-event handler.
* Code compiled with `-O gen-standalone-C++` likely has bugs if that * Code compiled with `-O gen-standalone-C++` likely has bugs if that
code requires initializing a global variable that specifies extend fields in code requires initializing a global variable that specifies extending fields in
an extensible record (i.e., fields added using `redef`). an extensible record (i.e., fields added using `redef`).
* If a lambda generates an event that is not otherwise referred to, that * If a lambda generates an event that is not otherwise referred to, that

View file

@ -4,6 +4,7 @@
#pragma once #pragma once
#include "zeek/Frame.h"
#include "zeek/Val.h" #include "zeek/Val.h"
#include "zeek/script_opt/CPP/Func.h" #include "zeek/script_opt/CPP/Func.h"
@ -46,6 +47,7 @@ extern ValPtr when_index_slice__CPP(VectorVal* vec, const ListVal* lv);
// but (2) needing to have the address of that vector. // but (2) needing to have the address of that vector.
inline ValPtr invoke__CPP(Func* f, std::vector<ValPtr> args, Frame* frame) inline ValPtr invoke__CPP(Func* f, std::vector<ValPtr> args, Frame* frame)
{ {
frame->SetOnlyCall(nullptr);
return f->Invoke(&args, frame); return f->Invoke(&args, frame);
} }

View file

@ -499,13 +499,16 @@ void CPPCompile::GenForOverTable(const ExprPtr& tbl, const IDPtr& value_var,
Emit("auto* current_tev__CPP = lve__CPP.value;"); Emit("auto* current_tev__CPP = lve__CPP.value;");
Emit("auto ind_lv__CPP = tv__CPP->RecreateIndex(*k__CPP);"); Emit("auto ind_lv__CPP = tv__CPP->RecreateIndex(*k__CPP);");
if ( value_var ) if ( value_var && ! value_var->IsBlank() )
Emit("%s = %s;", IDName(value_var), Emit("%s = %s;", IDName(value_var),
GenericValPtrToGT("current_tev__CPP->GetVal()", value_var->GetType(), GEN_NATIVE)); GenericValPtrToGT("current_tev__CPP->GetVal()", value_var->GetType(), GEN_NATIVE));
for ( int i = 0; i < loop_vars->length(); ++i ) for ( int i = 0; i < loop_vars->length(); ++i )
{ {
auto var = (*loop_vars)[i]; auto var = (*loop_vars)[i];
if ( var->IsBlank() )
continue;
const auto& v_t = var->GetType(); const auto& v_t = var->GetType();
auto acc = NativeAccessor(v_t); auto acc = NativeAccessor(v_t);
@ -526,9 +529,12 @@ void CPPCompile::GenForOverVector(const ExprPtr& vec, const IDPtr& value_var,
Emit("if ( ! vv__CPP->Has(i__CPP) ) continue;"); Emit("if ( ! vv__CPP->Has(i__CPP) ) continue;");
Emit("%s = i__CPP;", IDName((*loop_vars)[0])); auto lv0 = (*loop_vars)[0];
if ( value_var ) if ( ! lv0->IsBlank() )
Emit("%s = i__CPP;", IDName(lv0));
if ( value_var && ! value_var->IsBlank() )
{ {
auto vv = IDName(value_var); auto vv = IDName(value_var);
auto access = "vv__CPP->ValAt(i__CPP)"; auto access = "vv__CPP->ValAt(i__CPP)";
@ -545,7 +551,10 @@ void CPPCompile::GenForOverString(const ExprPtr& str, const IDPList* loop_vars)
StartBlock(); StartBlock();
Emit("auto sv__CPP = make_intrusive<StringVal>(1, (const char*) sval__CPP->Bytes() + i__CPP);"); Emit("auto sv__CPP = make_intrusive<StringVal>(1, (const char*) sval__CPP->Bytes() + i__CPP);");
Emit("%s = std::move(sv__CPP);", IDName((*loop_vars)[0]));
auto lv0 = (*loop_vars)[0];
if ( ! lv0->IsBlank() )
Emit("%s = std::move(sv__CPP);", IDName(lv0));
} }
} // zeek::detail } // zeek::detail

View file

@ -28,7 +28,7 @@ string Fmt(double d)
string scope_prefix(const string& scope) string scope_prefix(const string& scope)
{ {
return string("zeek::detail::CPP_") + scope + "::"; return "zeek::detail::CPP_" + scope;
} }
string scope_prefix(int scope) string scope_prefix(int scope)
@ -38,6 +38,9 @@ string scope_prefix(int scope)
bool is_CPP_compilable(const ProfileFunc* pf, const char** reason) bool is_CPP_compilable(const ProfileFunc* pf, const char** reason)
{ {
if ( analysis_options.allow_cond )
return true;
auto body = pf->ProfiledBody(); auto body = pf->ProfiledBody();
if ( body && ! body->GetOptInfo()->is_free_of_conditionals ) if ( body && ! body->GetOptInfo()->is_free_of_conditionals )
{ {

View file

@ -15,7 +15,7 @@ The maintenance workflow:
to check in updates to the list of how the compiler currently fares to check in updates to the list of how the compiler currently fares
on various btests (see end of this doc): on various btests (see end of this doc):
Wed Oct 12 11:36:46 PDT 2022 Mon Nov 7 14:30:51 PST 2022
2. Run "find-test-files.sh" to generate a list (to stdout) of all of the 2. Run "find-test-files.sh" to generate a list (to stdout) of all of the
possible Zeek source files found in the test suite. possible Zeek source files found in the test suite.
@ -62,23 +62,19 @@ These BTests won't successfully run due to the indicated issue:
bad-constructor - uses a complex old-style constructor that bad-constructor - uses a complex old-style constructor that
should be updated should be updated
bad-when - deliberately has old-style "when" without captures bad-when - deliberately has old-style "when" without captures
cond - not compilable due to the presence of conditional code
deprecated - uses deprecated features not support for -O gen-C++ deprecated - uses deprecated features not support for -O gen-C++
test-glitch - fails because of how we do testing: the first -O gen-C++ test-glitch - fails because of how we do testing: the first -O gen-C++
pass leaves httpd running, which causes the second -O use-C++ pass leaves httpd running, which causes the second -O use-C++
pass to fail when it tries to start up a new httpd pass to fail when it tries to start up a new httpd
opaque - needs a global whose value is (or contains) an opaque value,
not currently supported
skipped - test can be skipped due to environmental reasons (e.g., skipped - test can be skipped due to environmental reasons (e.g.,
whether we have a certain Kerberos setup) whether we have a certain Kerberos setup)
Database Of Known Issues (keep sorted) Database Of Known Issues (keep sorted)
../testing/btest/bifs/table_values.zeek bad-constructor ../testing/btest/bifs/table_values.zeek bad-constructor
../testing/btest/language/alternate-event-hook-prototypes.zeek deprecated
../testing/btest/language/redef-same-prefixtable-idx.zeek deprecated
../testing/btest/language/table-redef.zeek deprecated
../testing/btest/language/when-aggregates.zeek bad-when
../testing/btest/scripts/base/protocols/krb/smb2_krb.test skipped ../testing/btest/scripts/base/protocols/krb/smb2_krb.test skipped
../testing/btest/scripts/base/protocols/krb/smb2_krb_nokeytab.test skipped ../testing/btest/scripts/base/protocols/krb/smb2_krb_nokeytab.test skipped
../testing/btest/scripts/base/utils/active-http.test test-glitch ../testing/btest/scripts/base/utils/active-http.test test-glitch
../testing/btest/scripts/policy/frameworks/dpd/packet-segment-logging.zeek cond
../testing/btest/scripts/policy/misc/dump-events.zeek skipped ../testing/btest/scripts/policy/misc/dump-events.zeek skipped

View file

@ -180,6 +180,11 @@ ExprPtr Inliner::CheckForInlining(CallExprPtr c)
if ( function->GetKind() != Func::SCRIPT_FUNC ) if ( function->GetKind() != Func::SCRIPT_FUNC )
return c; return c;
// Check for mismatches in argument count due to single-arg-of-type-any
// loophole used for variadic BiFs.
if ( function->GetType()->Params()->NumFields() == 1 && c->Args()->Exprs().size() != 1 )
return c;
auto func_vf = static_cast<ScriptFunc*>(function); auto func_vf = static_cast<ScriptFunc*>(function);
if ( inline_ables.count(func_vf) == 0 ) if ( inline_ables.count(func_vf) == 0 )

View file

@ -278,6 +278,7 @@ static void init_options()
check_env_opt("ZEEK_COMPILE_ALL", analysis_options.compile_all); check_env_opt("ZEEK_COMPILE_ALL", analysis_options.compile_all);
check_env_opt("ZEEK_REPORT_CPP", analysis_options.report_CPP); check_env_opt("ZEEK_REPORT_CPP", analysis_options.report_CPP);
check_env_opt("ZEEK_USE_CPP", analysis_options.use_CPP); check_env_opt("ZEEK_USE_CPP", analysis_options.use_CPP);
check_env_opt("ZEEK_ALLOW_COND", analysis_options.allow_cond);
if ( analysis_options.gen_standalone_CPP || analysis_options.add_CPP ) if ( analysis_options.gen_standalone_CPP || analysis_options.add_CPP )
analysis_options.gen_CPP = true; analysis_options.gen_CPP = true;
@ -288,6 +289,10 @@ static void init_options()
if ( analysis_options.use_CPP && generating_CPP ) if ( analysis_options.use_CPP && generating_CPP )
reporter->FatalError("generating C++ incompatible with using C++"); reporter->FatalError("generating C++ incompatible with using C++");
if ( analysis_options.allow_cond && ! analysis_options.gen_standalone_CPP )
reporter->FatalError(
"\"-O allow-cond\" only relevant when also using \"-O gen-standalone-C++\"");
auto usage = getenv("ZEEK_USAGE_ISSUES"); auto usage = getenv("ZEEK_USAGE_ISSUES");
if ( usage ) if ( usage )

View file

@ -110,6 +110,10 @@ struct AnalyOpt
// If true, report on available C++ bodies. // If true, report on available C++ bodies.
bool report_CPP = false; bool report_CPP = false;
// If true, allow standalone compilation in the presence of
// conditional code.
bool allow_cond = false;
}; };
extern AnalyOpt analysis_options; extern AnalyOpt analysis_options;

View file

@ -600,7 +600,7 @@ bool ForStmt::IsReduced(Reducer* c) const
if ( ! c->IDsAreReduced(loop_vars) ) if ( ! c->IDsAreReduced(loop_vars) )
return false; return false;
if ( value_var && ! c->ID_IsReduced(value_var) ) if ( value_var && (value_var->IsBlank() || ! c->ID_IsReduced(value_var)) )
return false; return false;
return body->IsReduced(c); return body->IsReduced(c);
@ -608,6 +608,13 @@ bool ForStmt::IsReduced(Reducer* c) const
StmtPtr ForStmt::DoReduce(Reducer* c) StmtPtr ForStmt::DoReduce(Reducer* c)
{ {
if ( value_var && value_var->IsBlank() )
{
auto no_vv = make_intrusive<ForStmt>(loop_vars, e);
no_vv->AddBody(body);
return TransformMe(no_vv, c);
}
StmtPtr red_e_stmt; StmtPtr red_e_stmt;
if ( c->Optimizing() ) if ( c->Optimizing() )

View file

@ -368,6 +368,10 @@ void ZAMCompiler::ComputeFrameLifetimes()
for ( auto v : iter_vars ) for ( auto v : iter_vars )
{ {
if ( v < 0 )
// This happens for '_' dummy
continue;
CheckSlotAssignment(v, inst); CheckSlotAssignment(v, inst);
// Also mark it as usage throughout the // Also mark it as usage throughout the
@ -410,6 +414,13 @@ void ZAMCompiler::ComputeFrameLifetimes()
} }
break; break;
case OP_NEXT_VECTOR_BLANK_ITER_VAL_VAR_VVV:
{
auto depth = inst->loop_depth;
ExtendLifetime(inst->v1, EndOfLoop(inst, depth));
}
break;
case OP_NEXT_VECTOR_ITER_VVV: case OP_NEXT_VECTOR_ITER_VVV:
case OP_NEXT_STRING_ITER_VVV: case OP_NEXT_STRING_ITER_VVV:
// Sometimes loops are written that don't actually // Sometimes loops are written that don't actually
@ -423,6 +434,10 @@ void ZAMCompiler::ComputeFrameLifetimes()
ExtendLifetime(inst->v1, EndOfLoop(inst, inst->loop_depth)); ExtendLifetime(inst->v1, EndOfLoop(inst, inst->loop_depth));
break; break;
case OP_NEXT_VECTOR_BLANK_ITER_VV:
case OP_NEXT_STRING_BLANK_ITER_VV:
break;
case OP_INIT_TABLE_LOOP_VV: case OP_INIT_TABLE_LOOP_VV:
case OP_INIT_VECTOR_LOOP_VV: case OP_INIT_VECTOR_LOOP_VV:
case OP_INIT_STRING_LOOP_VV: case OP_INIT_STRING_LOOP_VV:
@ -573,7 +588,9 @@ void ZAMCompiler::ReMapFrame()
auto& iter_vars = inst->aux->loop_vars; auto& iter_vars = inst->aux->loop_vars;
for ( auto& v : iter_vars ) for ( auto& v : iter_vars )
{ {
ASSERT(v >= 0 && v < n1_slots); if ( v < 0 )
continue;
ASSERT(v < n1_slots);
v = frame1_to_frame2[v]; v = frame1_to_frame2[v];
} }
} }

View file

@ -52,10 +52,13 @@ public:
for ( int i = 0; i < ind_lv->Length(); ++i ) for ( int i = 0; i < ind_lv->Length(); ++i )
{ {
ValPtr ind_lv_p = ind_lv->Idx(i); ValPtr ind_lv_p = ind_lv->Idx(i);
auto& var = frame[aux->loop_vars[i]]; auto lv = aux->loop_vars[i];
auto& t = aux->loop_var_types[i]; if ( lv < 0 )
if ( ZVal::IsManagedType(t) ) continue;
auto& var = frame[lv];
if ( aux->lvt_is_managed[i] )
ZVal::DeleteManagedType(var); ZVal::DeleteManagedType(var);
auto& t = aux->loop_var_types[i];
var = ZVal(ind_lv_p, t); var = ZVal(ind_lv_p, t);
} }

View file

@ -1743,24 +1743,35 @@ op1-read
eval auto& vv = frame[z.v1].vector_val->RawVec(); eval auto& vv = frame[z.v1].vector_val->RawVec();
step_iters[z.v2].InitLoop(vv); step_iters[z.v2].InitLoop(vv);
macro NextVectorIterCore(info, branch)
auto& si = step_iters[info];
if ( si.IsDoneIterating() )
BRANCH(branch)
const auto& vv = *si.vv;
if ( ! vv[si.iter] )
{ /* Account for vector hole. Re-execute for next position. */
si.IterFinished();
--pc; /* so we then increment to here again */
break;
}
internal-op Next-Vector-Iter internal-op Next-Vector-Iter
# v1 = iteration variable # v1 = iteration variable
# v2 = iteration info # v2 = iteration info
# v3 = branch target if loop done # v3 = branch target if loop done
type VVV type VVV
eval auto& si = step_iters[z.v2]; eval NextVectorIterCore(z.v2, v3)
if ( si.IsDoneIterating() )
BRANCH(v3)
const auto& vv = *si.vv;
if ( ! vv[si.iter] )
{ // Account for vector hole. Re-execute for next position.
si.IterFinished();
--pc; // so we then increment to here again
break;
}
frame[z.v1].uint_val = si.iter; frame[z.v1].uint_val = si.iter;
si.IterFinished(); si.IterFinished();
internal-op Next-Vector-Blank-Iter
# v1 = iteration info
# v2 = branch target if loop done
op1-internal
type VV
eval NextVectorIterCore(z.v1, v2)
si.IterFinished();
internal-op Next-Vector-Iter-Val-Var internal-op Next-Vector-Iter-Val-Var
# v1 = iteration variable # v1 = iteration variable
# v2 = value variable # v2 = value variable
@ -1768,16 +1779,7 @@ internal-op Next-Vector-Iter-Val-Var
# v4 = branch target if loop done # v4 = branch target if loop done
op1-read-write op1-read-write
type VVVV type VVVV
eval auto& si = step_iters[z.v3]; eval NextVectorIterCore(z.v3, v4)
if ( si.IsDoneIterating() )
BRANCH(v4)
const auto& vv = *si.vv;
if ( ! vv[si.iter] )
{ // Account for vector hole. Re-execute for next position.
si.IterFinished();
--pc; // so we then increment to here again
break;
}
frame[z.v1].uint_val = si.iter; frame[z.v1].uint_val = si.iter;
if ( z.is_managed ) if ( z.is_managed )
frame[z.v2] = BuildVal(vv[si.iter]->ToVal(z.t), z.t); frame[z.v2] = BuildVal(vv[si.iter]->ToVal(z.t), z.t);
@ -1785,6 +1787,18 @@ eval auto& si = step_iters[z.v3];
frame[z.v2] = *vv[si.iter]; frame[z.v2] = *vv[si.iter];
si.IterFinished(); si.IterFinished();
internal-op Next-Vector-Blank-Iter-Val-Var
# v1 = value variable
# v2 = iteration info
# v3 = branch target if loop done
type VVV
eval NextVectorIterCore(z.v2, v3)
if ( z.is_managed )
frame[z.v1] = BuildVal(vv[si.iter]->ToVal(z.t), z.t);
else
frame[z.v1] = *vv[si.iter];
si.IterFinished();
internal-op Init-String-Loop internal-op Init-String-Loop
type VV type VV
@ -1809,6 +1823,16 @@ eval auto& si = step_iters[z.v2];
frame[z.v1].string_val = sv; frame[z.v1].string_val = sv;
si.IterFinished(); si.IterFinished();
internal-op Next-String-Blank-Iter
# v1 = iteration info
# v2 = branch target if loop done
op1-internal
type VV
eval auto& si = step_iters[z.v1];
if ( si.IsDoneIterating() )
BRANCH(v2)
si.IterFinished();
internal-op End-Table-Loop internal-op End-Table-Loop
op1-internal op1-internal
type V type V

View file

@ -811,11 +811,14 @@ const ZAMStmt ZAMCompiler::LoopOverTable(const ForStmt* f, const NameExpr* val)
{ {
auto id = (*loop_vars)[i]; auto id = (*loop_vars)[i];
if ( body_pf.Locals().count(id) == 0 ) if ( body_pf.Locals().count(id) == 0 || id->IsBlank() )
++num_unused; ++num_unused;
aux->loop_vars.push_back(FrameSlot(id)); int slot = id->IsBlank() ? -1 : FrameSlot(id);
aux->loop_var_types.push_back(id->GetType()); aux->loop_vars.push_back(slot);
auto& t = id->GetType();
aux->loop_var_types.push_back(t);
aux->lvt_is_managed.push_back(ZVal::IsManagedType(t));
} }
bool no_loop_vars = (num_unused == loop_vars->length()); bool no_loop_vars = (num_unused == loop_vars->length());
@ -874,19 +877,37 @@ const ZAMStmt ZAMCompiler::LoopOverVector(const ForStmt* f, const NameExpr* val)
auto init_end = AddInst(z); auto init_end = AddInst(z);
auto iter_head = StartingBlock(); auto iter_head = StartingBlock();
int slot = loop_var->IsBlank() ? -1 : FrameSlot(loop_var);
if ( value_var ) if ( value_var )
{ {
z = ZInstI(OP_NEXT_VECTOR_ITER_VAL_VAR_VVVV, FrameSlot(loop_var), FrameSlot(value_var), if ( slot >= 0 )
iter_slot, 0); {
z = ZInstI(OP_NEXT_VECTOR_ITER_VAL_VAR_VVVV, 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.op_type = OP_VVV_I2_I3;
}
z.t = value_var->GetType(); z.t = value_var->GetType();
z.is_managed = ZVal::IsManagedType(z.t); z.is_managed = ZVal::IsManagedType(z.t);
z.op_type = OP_VVVV_I3_I4;
} }
else else
{ {
z = ZInstI(OP_NEXT_VECTOR_ITER_VVV, FrameSlot(loop_var), iter_slot, 0); if ( slot >= 0 )
z.op_type = OP_VVV_I2_I3; {
z = ZInstI(OP_NEXT_VECTOR_ITER_VVV, slot, iter_slot, 0);
z.op_type = OP_VVV_I2_I3;
}
else
{
z = ZInstI(OP_NEXT_VECTOR_BLANK_ITER_VV, iter_slot, 0);
z.op_type = OP_VV_I1_I2;
}
} }
return FinishLoop(iter_head, z, f->LoopBody(), iter_slot, false); return FinishLoop(iter_head, z, f->LoopBody(), iter_slot, false);
@ -918,9 +939,17 @@ const ZAMStmt ZAMCompiler::LoopOverString(const ForStmt* f, const Expr* e)
auto init_end = AddInst(z); auto init_end = AddInst(z);
auto iter_head = StartingBlock(); auto iter_head = StartingBlock();
z = ZInstI(OP_NEXT_STRING_ITER_VVV, FrameSlot(loop_var), iter_slot, 0); if ( loop_var->IsBlank() )
z.is_managed = true; {
z.op_type = OP_VVV_I2_I3; z = ZInstI(OP_NEXT_STRING_BLANK_ITER_VV, 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.op_type = OP_VVV_I2_I3;
z.is_managed = true;
}
return FinishLoop(iter_head, z, f->LoopBody(), iter_slot, false); return FinishLoop(iter_head, z, f->LoopBody(), iter_slot, false);
} }

View file

@ -423,13 +423,15 @@ public:
// to map elements in slots/constants/types to record field offsets. // to map elements in slots/constants/types to record field offsets.
std::vector<int> map; std::vector<int> map;
///// The following three apply to looping over the elements of tables. ///// The following four apply to looping over the elements of tables.
// Frame slots of iteration variables, such as "[v1, v2, v3] in aggr". // Frame slots of iteration variables, such as "[v1, v2, v3] in aggr".
// A negative value means "skip assignment".
std::vector<int> loop_vars; std::vector<int> loop_vars;
// Their types. // Their types and whether they're managed.
std::vector<TypePtr> loop_var_types; std::vector<TypePtr> loop_var_types;
std::vector<bool> lvt_is_managed;
// Type associated with the "value" entry, for "k, value in aggr" // Type associated with the "value" entry, for "k, value in aggr"
// iteration. // iteration.

View file

@ -1,58 +0,0 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
[a=42, b=Foo, c=<uninitialized>, d=Bar, e=tt]
{
[a] = [type_name=count, log=F, value=42, default_val=<uninitialized>],
[d] = [type_name=string, log=T, value=Bar, default_val=<uninitialized>],
[b] = [type_name=string, log=F, value=Foo, default_val=Foo],
[c] = [type_name=double, log=F, value=<uninitialized>, default_val=<uninitialized>],
[e] = [type_name=any, log=F, value=tt, default_val=<uninitialized>]
}
F
{
[a] = [type_name=bool, log=F, value=<uninitialized>, default_val=<uninitialized>],
[d] = [type_name=string, log=T, value=<uninitialized>, default_val=<uninitialized>],
[b] = [type_name=string, log=F, value=<uninitialized>, default_val=Bar],
[m] = [type_name=record myrec, log=F, value=<uninitialized>, default_val=<uninitialized>],
[c] = [type_name=double, log=F, value=<uninitialized>, default_val=<uninitialized>]
}
{
[a] = [type_name=bool, log=F, value=<uninitialized>, default_val=<uninitialized>],
[d] = [type_name=string, log=T, value=<uninitialized>, default_val=<uninitialized>],
[b] = [type_name=string, log=F, value=<uninitialized>, default_val=Bar],
[m] = [type_name=record myrec, log=F, value=<uninitialized>, default_val=<uninitialized>],
[c] = [type_name=double, log=F, value=<uninitialized>, default_val=<uninitialized>]
}
{
[a] = [type_name=count, log=F, value=42, default_val=<uninitialized>],
[d] = [type_name=string, log=T, value=Bar, default_val=<uninitialized>],
[b] = [type_name=string, log=F, value=Foo, default_val=Foo],
[c] = [type_name=double, log=F, value=<uninitialized>, default_val=<uninitialized>],
[e] = [type_name=any, log=F, value=mystring, default_val=<uninitialized>]
}
{
}
{
[myfield] = [type_name=bool, log=F, value=<uninitialized>, default_val=<uninitialized>]
}
{
[a] = [type_name=bool, log=F, value=<uninitialized>, default_val=<uninitialized>],
[d] = [type_name=string, log=T, value=<uninitialized>, default_val=<uninitialized>],
[b] = [type_name=string, log=F, value=<uninitialized>, default_val=Bar],
[m] = [type_name=record myrec, log=F, value=<uninitialized>, default_val=<uninitialized>],
[c] = [type_name=double, log=F, value=<uninitialized>, default_val=<uninitialized>]
}
{
[a] = [type_name=count, log=F, value=<uninitialized>, default_val=<uninitialized>],
[d] = [type_name=string, log=T, value=<uninitialized>, default_val=<uninitialized>],
[b] = [type_name=string, log=F, value=<uninitialized>, default_val=Foo],
[c] = [type_name=double, log=F, value=<uninitialized>, default_val=<uninitialized>],
[e] = [type_name=any, log=F, value=<uninitialized>, default_val=<uninitialized>]
}
{
[a] = [type_name=set[double], log=F, value=<uninitialized>, default_val=<uninitialized>],
[d] = [type_name=table[double,string] of table[string] of vector of string, log=F, value=<uninitialized>, default_val=<uninitialized>],
[b] = [type_name=set[double,string], log=F, value=<uninitialized>, default_val=<uninitialized>],
[c] = [type_name=set[double,record tt], log=F, value=<uninitialized>, default_val=<uninitialized>],
[e] = [type_name=vector of vector of string, log=F, value=<uninitialized>, default_val=<uninitialized>]
}

View file

@ -1,6 +1,6 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error in <...>/main.zeek, lines 517-518: Failed to attach master store backend_failure: (Option::set_change_handler(Broker::metrics_export_prefixes, to_any_coerceBroker::update_metrics_export_prefixes, (coerce 0 to int))) error: Failed to attach master store backend_failure:
error in <...>/main.zeek, lines 517-518: Could not create Broker master store '../fail' (Option::set_change_handler(Broker::metrics_export_prefixes, to_any_coerceBroker::update_metrics_export_prefixes, (coerce 0 to int))) error: Could not create Broker master store '../fail'
error in <no location>: invalid Broker store handle (broker::store::{}) error in <no location>: invalid Broker store handle (broker::store::{})
error in <no location>: invalid Broker store handle (broker::store::{}) error in <no location>: invalid Broker store handle (broker::store::{})
error in <no location>: invalid Broker store handle (broker::store::{}) error in <no location>: invalid Broker store handle (broker::store::{})

View file

@ -1,7 +1,7 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
reporter_info|init test-info|<...>/main.zeek, lines 517-518|XXXXXXXXXX.XXXXXX reporter_info|init test-info||XXXXXXXXXX.XXXXXX
reporter_warning|init test-warning|<...>/main.zeek, lines 517-518|XXXXXXXXXX.XXXXXX reporter_warning|init test-warning||XXXXXXXXXX.XXXXXX
reporter_error|init test-error|<...>/main.zeek, lines 517-518|XXXXXXXXXX.XXXXXX reporter_error|init test-error||XXXXXXXXXX.XXXXXX
reporter_info|done test-info||XXXXXXXXXX.XXXXXX reporter_info|done test-info||XXXXXXXXXX.XXXXXX
reporter_warning|done test-warning||XXXXXXXXXX.XXXXXX reporter_warning|done test-warning||XXXXXXXXXX.XXXXXX
reporter_error|done test-error||XXXXXXXXXX.XXXXXX reporter_error|done test-error||XXXXXXXXXX.XXXXXX

View file

@ -2,9 +2,9 @@
pre test-info pre test-info
warning: pre test-warning warning: pre test-warning
error: pre test-error error: pre test-error
<...>/main.zeek, lines 517-518: init test-info init test-info
warning in <...>/main.zeek, lines 517-518: init test-warning warning: init test-warning
error in <...>/main.zeek, lines 517-518: init test-error error: init test-error
done test-info done test-info
warning: done test-warning warning: done test-warning
error: done test-error error: done test-error

View file

@ -1,2 +1,2 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
<...>/pp-alarms.zeek, line 100: Hello, Zeek! Hello, Zeek!

View file

@ -7,5 +7,5 @@
#open XXXX-XX-XX-XX-XX-XX #open XXXX-XX-XX-XX-XX-XX
#fields ts level message location #fields ts level message location
#types time enum string string #types time enum string string
XXXXXXXXXX.XXXXXX Reporter::INFO Hello, Zeek! <...>/pp-alarms.zeek, line 100 XXXXXXXXXX.XXXXXX Reporter::INFO Hello, Zeek! (empty)
#close XXXX-XX-XX-XX-XX-XX #close XXXX-XX-XX-XX-XX-XX

View file

@ -1,6 +1,6 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
runtime error in <...>/queue.zeek, line 152: vector index assignment failed for invalid type 'myrec', value: [a=T, b=hi, c=<uninitialized>], expression: Queue::ret[Queue::j], call stack: runtime error in <...>/queue.zeek, line 152: vector index assignment failed for invalid type 'myrec', value: [a=T, b=hi, c=<uninitialized>], expression: Queue::ret[Queue::j], call stack:
#0 Queue::get_vector([initialized=T, vals={[2] = test,[3] = [a=T, b=hi, c=<uninitialized>],[5] = 3,[0] = hello,[6] = jkl;,[4] = asdf,[1] = goodbye}, settings=[max_len=<uninitialized>], top=7, bottom=0, size=0], [hello, goodbye, test]) at <...>/main.zeek:517 #0 Queue::get_vector([initialized=T, vals={[2] = test,[3] = [a=T, b=hi, c=<uninitialized>],[5] = 3,[0] = hello,[6] = jkl;,[4] = asdf,[1] = goodbye}, settings=[max_len=<uninitialized>], top=7, bottom=0, size=0], [hello, goodbye, test])
#1 zeek_init() #1 zeek_init()

View file

@ -2,13 +2,13 @@
Reporter::Hook - Exercise Reporter Hook (dynamic, version 1.0.0) Reporter::Hook - Exercise Reporter Hook (dynamic, version 1.0.0)
Implements Reporter (priority 0) Implements Reporter (priority 0)
| Hook Some Info <...>/main.zeek, lines 517-518 | Hook Some Info
| Hook error An Error <...>/main.zeek, lines 517-518 | Hook error An Error
| Hook error An Error that does not show up in the log <...>/main.zeek, lines 517-518 | Hook error An Error that does not show up in the log
| Hook runtime error in compiled code field value missing | Hook runtime error in compiled code field value missing
| Hook warning A warning <...>/main.zeek, lines 517-518 | Hook warning A warning
<...>/main.zeek, lines 517-518: Some Info Some Info
error in <...>/main.zeek, lines 517-518: An Error error: An Error
error in <...>/main.zeek, lines 517-518: An Error that does not show up in the log error: An Error that does not show up in the log
runtime error in compiled code: field value missing runtime error in compiled code: field value missing
warning in <...>/main.zeek, lines 517-518: A warning warning: A warning

View file

@ -7,8 +7,8 @@
#open XXXX-XX-XX-XX-XX-XX #open XXXX-XX-XX-XX-XX-XX
#fields ts level message location #fields ts level message location
#types time enum string string #types time enum string string
XXXXXXXXXX.XXXXXX Reporter::INFO Some Info <...>/main.zeek, lines 517-518 XXXXXXXXXX.XXXXXX Reporter::INFO Some Info (empty)
XXXXXXXXXX.XXXXXX Reporter::WARNING A warning <...>/main.zeek, lines 517-518 XXXXXXXXXX.XXXXXX Reporter::WARNING A warning (empty)
XXXXXXXXXX.XXXXXX Reporter::ERROR An Error <...>/main.zeek, lines 517-518 XXXXXXXXXX.XXXXXX Reporter::ERROR An Error (empty)
XXXXXXXXXX.XXXXXX Reporter::ERROR field value missing (empty) XXXXXXXXXX.XXXXXX Reporter::ERROR field value missing (empty)
#close XXXX-XX-XX-XX-XX-XX #close XXXX-XX-XX-XX-XX-XX

View file

@ -0,0 +1,2 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error: cat_sep() takes at least 2 arguments, got 1

View file

@ -0,0 +1,2 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error: expected type string for default, got count

View file

@ -0,0 +1,2 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error: expected type string for separator, got count

View file

@ -0,0 +1,2 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error: expected type string for separator, got record

View file

@ -0,0 +1,2 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error: cat_sep() takes at least 2 arguments, got 0

View file

@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error: no such event group: my-group
disable non existing event group, F

View file

@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error: no such event group: MyModule
enabling non existing module event group, F

View file

@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error: no such event group: MyModule
disable non existing module event group, F

View file

@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error: no such event group: my-group
enable non existing event group, F

View file

@ -0,0 +1,2 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
runtime error: too many arguments for function call

View file

@ -0,0 +1,6 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
zeek_init() &priority=10
l=a local x=1
zeek_init() &priority=-10
l=a local x=1
l=a local x=1