mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
binpac: Arrays now suport the &transient attribute.
If set, parsed elements won't actually be added to the array, and read access to the array aren't permitted. This is helpful to save memory in the case of large arrays for which elements don't need (or can't) be buffered.
This commit is contained in:
parent
5db7ba4050
commit
092d049f8e
1 changed files with 79 additions and 66 deletions
|
@ -92,6 +92,9 @@ Type *ArrayType::ElementDataType() const
|
|||
|
||||
string ArrayType::EvalElement(const string &array, const string &index) const
|
||||
{
|
||||
if ( attr_transient_ )
|
||||
throw Exception(this, "cannot access element in &transient array");
|
||||
|
||||
return strfmt("(*(%s))[%s]", array.c_str(), index.c_str());
|
||||
}
|
||||
|
||||
|
@ -130,18 +133,18 @@ void ArrayType::ProcessAttr(Attr *a)
|
|||
{
|
||||
if ( elemtype_->StaticSize(env()) != 1 )
|
||||
{
|
||||
throw Exception(elemtype_,
|
||||
throw Exception(elemtype_,
|
||||
"&restofdata can be applied"
|
||||
" to only byte arrays");
|
||||
}
|
||||
if ( length_ )
|
||||
{
|
||||
throw Exception(length_,
|
||||
throw Exception(length_,
|
||||
"&restofdata cannot be applied"
|
||||
" to arrays with specified length");
|
||||
}
|
||||
attr_restofdata_ = true;
|
||||
// As the array automatically extends to the end of
|
||||
// As the array automatically extends to the end of
|
||||
// data, we do not have to check boundary.
|
||||
SetBoundaryChecked();
|
||||
}
|
||||
|
@ -158,7 +161,7 @@ void ArrayType::ProcessAttr(Attr *a)
|
|||
bool ref_input = a->expr()->HasReference(input_macro_id);
|
||||
if ( ref_element && ref_input )
|
||||
{
|
||||
throw Exception(a->expr(),
|
||||
throw Exception(a->expr(),
|
||||
"cannot reference both $element and $input "
|
||||
"in the same &until---please separate them.");
|
||||
}
|
||||
|
@ -167,7 +170,7 @@ void ArrayType::ProcessAttr(Attr *a)
|
|||
{
|
||||
if ( attr_until_element_expr_ )
|
||||
{
|
||||
throw Exception(a->expr(),
|
||||
throw Exception(a->expr(),
|
||||
"multiple &until on $element");
|
||||
}
|
||||
attr_until_element_expr_ = a->expr();
|
||||
|
@ -176,7 +179,7 @@ void ArrayType::ProcessAttr(Attr *a)
|
|||
{
|
||||
if ( attr_until_input_expr_ )
|
||||
{
|
||||
throw Exception(a->expr(),
|
||||
throw Exception(a->expr(),
|
||||
"multiple &until on $input");
|
||||
}
|
||||
attr_until_input_expr_ = a->expr();
|
||||
|
@ -185,7 +188,7 @@ void ArrayType::ProcessAttr(Attr *a)
|
|||
{
|
||||
if ( attr_generic_until_expr_ )
|
||||
{
|
||||
throw Exception(a->expr(),
|
||||
throw Exception(a->expr(),
|
||||
"multiple &until condition");
|
||||
}
|
||||
attr_generic_until_expr_ = a->expr();
|
||||
|
@ -206,15 +209,15 @@ void ArrayType::Prepare(Env *env, int flags)
|
|||
ID *elem_var = new ID(fmt("%s__elem", value_var()->Name()));
|
||||
ID *elem_it_var = new ID(fmt("%s__it", elem_var->Name()));
|
||||
|
||||
elem_var_field_ =
|
||||
elem_var_field_ =
|
||||
new ParseVarField(Field::CLASS_MEMBER, elem_var, elemtype_);
|
||||
AddField(elem_var_field_);
|
||||
|
||||
if ( incremental_parsing() )
|
||||
{
|
||||
arraylength_var_field_ =
|
||||
arraylength_var_field_ =
|
||||
new PrivVarField(arraylength_var, extern_type_int->Clone());
|
||||
elem_it_var_field_ =
|
||||
elem_it_var_field_ =
|
||||
new PrivVarField(elem_it_var, extern_type_int->Clone());
|
||||
|
||||
AddField(arraylength_var_field_);
|
||||
|
@ -222,25 +225,25 @@ void ArrayType::Prepare(Env *env, int flags)
|
|||
}
|
||||
else
|
||||
{
|
||||
arraylength_var_field_ =
|
||||
arraylength_var_field_ =
|
||||
new TempVarField(arraylength_var, extern_type_int->Clone());
|
||||
elem_it_var_field_ =
|
||||
elem_it_var_field_ =
|
||||
new TempVarField(elem_it_var, extern_type_int->Clone());
|
||||
|
||||
arraylength_var_field_->Prepare(env);
|
||||
elem_it_var_field_->Prepare(env);
|
||||
|
||||
// Add elem_dataptr_var only when not parsing incrementally
|
||||
ID *elem_dataptr_var =
|
||||
ID *elem_dataptr_var =
|
||||
new ID(fmt("%s__dataptr", elem_var->Name()));
|
||||
elem_dataptr_var_field_ = new TempVarField(
|
||||
elem_dataptr_var,
|
||||
elem_dataptr_var,
|
||||
extern_type_const_byteptr->Clone());
|
||||
elem_dataptr_var_field_->Prepare(env);
|
||||
|
||||
// until(dataptr >= end_of_data)
|
||||
elem_dataptr_until_expr_ = new Expr(
|
||||
Expr::EXPR_GE,
|
||||
Expr::EXPR_GE,
|
||||
new Expr(elem_dataptr_var->clone()),
|
||||
new Expr(end_of_data->clone()));
|
||||
}
|
||||
|
@ -269,8 +272,8 @@ void ArrayType::GenArrayLength(Output *out_cc, Env *env, const DataPtr& data)
|
|||
|
||||
if ( length_ )
|
||||
{
|
||||
out_cc->println("%s = %s;",
|
||||
env->LValue(arraylength_var()),
|
||||
out_cc->println("%s = %s;",
|
||||
env->LValue(arraylength_var()),
|
||||
length_->EvalExpr(out_cc, env));
|
||||
|
||||
env->SetEvaluated(arraylength_var());
|
||||
|
@ -285,22 +288,22 @@ void ArrayType::GenArrayLength(Output *out_cc, Env *env, const DataPtr& data)
|
|||
env->LValue(arraylength_var()));
|
||||
out_cc->println("}");
|
||||
out_cc->dec_indent();
|
||||
|
||||
|
||||
// Check negative array length
|
||||
out_cc->println("if ( %s < 0 )",
|
||||
env->LValue(arraylength_var()));
|
||||
env->LValue(arraylength_var()));
|
||||
out_cc->inc_indent();
|
||||
out_cc->println("{");
|
||||
out_cc->println("%s = 0;",
|
||||
env->LValue(arraylength_var()));
|
||||
env->LValue(arraylength_var()));
|
||||
out_cc->println("}");
|
||||
out_cc->dec_indent();
|
||||
}
|
||||
else if ( attr_restofdata_ )
|
||||
{
|
||||
ASSERT(elemtype_->StaticSize(env) == 1);
|
||||
out_cc->println("%s = (%s) - (%s);",
|
||||
env->LValue(arraylength_var()),
|
||||
out_cc->println("%s = (%s) - (%s);",
|
||||
env->LValue(arraylength_var()),
|
||||
env->RValue(end_of_data),
|
||||
data.ptr_expr());
|
||||
env->SetEvaluated(arraylength_var());
|
||||
|
@ -313,6 +316,9 @@ void ArrayType::GenPubDecls(Output *out_h, Env *env)
|
|||
|
||||
if ( declared_as_type() )
|
||||
{
|
||||
if ( attr_transient_ )
|
||||
throw Exception(this, "cannot access element in &transient array");
|
||||
|
||||
out_h->println("int size() const { return %s ? %s->size() : 0; }",
|
||||
env->RValue(value_var()),
|
||||
env->RValue(value_var()));
|
||||
|
@ -339,7 +345,7 @@ void ArrayType::GenInitCode(Output *out_cc, Env *env)
|
|||
Type::GenInitCode(out_cc, env);
|
||||
if ( incremental_parsing() )
|
||||
{
|
||||
out_cc->println("%s = -1;",
|
||||
out_cc->println("%s = -1;",
|
||||
env->LValue(elem_it_var()));
|
||||
}
|
||||
}
|
||||
|
@ -352,10 +358,10 @@ void ArrayType::GenCleanUpCode(Output *out_cc, Env *env)
|
|||
if ( ! elem_var_field_ )
|
||||
{
|
||||
ID *elem_var = new ID(fmt("%s__elem", value_var()->Name()));
|
||||
elem_var_field_ =
|
||||
elem_var_field_ =
|
||||
new ParseVarField(
|
||||
Field::NOT_CLASS_MEMBER,
|
||||
elem_var,
|
||||
Field::NOT_CLASS_MEMBER,
|
||||
elem_var,
|
||||
elemtype_);
|
||||
elem_var_field_->Prepare(env);
|
||||
}
|
||||
|
@ -368,9 +374,9 @@ void ArrayType::GenCleanUpCode(Output *out_cc, Env *env)
|
|||
env->RValue(value_var()));
|
||||
out_cc->inc_indent();
|
||||
out_cc->println("{");
|
||||
out_cc->println("%s %s = (*%s)[i];",
|
||||
elemtype_->DataTypeStr().c_str(),
|
||||
env->LValue(elem_var()),
|
||||
out_cc->println("%s %s = (*%s)[i];",
|
||||
elemtype_->DataTypeStr().c_str(),
|
||||
env->LValue(elem_var()),
|
||||
lvalue());
|
||||
elemtype_->GenCleanUpCode(out_cc, env);
|
||||
out_cc->println("}");
|
||||
|
@ -389,7 +395,7 @@ string ArrayType::GenArrayInit(Output *out_cc, Env *env, bool known_array_length
|
|||
array_str = lvalue();
|
||||
if ( incremental_parsing() )
|
||||
{
|
||||
out_cc->println("if ( %s < 0 )",
|
||||
out_cc->println("if ( %s < 0 )",
|
||||
env->LValue(elem_it_var()));
|
||||
out_cc->inc_indent();
|
||||
out_cc->println("{");
|
||||
|
@ -397,12 +403,12 @@ string ArrayType::GenArrayInit(Output *out_cc, Env *env, bool known_array_length
|
|||
out_cc->println("%s = 0;", env->LValue(elem_it_var()));
|
||||
}
|
||||
|
||||
out_cc->println("%s = new %s;",
|
||||
out_cc->println("%s = new %s;",
|
||||
lvalue(), vector_str_.c_str());
|
||||
|
||||
if ( known_array_length )
|
||||
{
|
||||
out_cc->println("%s->reserve(%s);",
|
||||
out_cc->println("%s->reserve(%s);",
|
||||
lvalue(), env->RValue(arraylength_var()));
|
||||
}
|
||||
|
||||
|
@ -418,23 +424,30 @@ string ArrayType::GenArrayInit(Output *out_cc, Env *env, bool known_array_length
|
|||
void ArrayType::GenElementAssignment(Output *out_cc, Env *env,
|
||||
string const &array_str, bool use_vector)
|
||||
{
|
||||
if ( attr_transient_ )
|
||||
{
|
||||
// Just discard.
|
||||
out_cc->println("delete %s;", env->LValue(elem_var()));
|
||||
return;
|
||||
}
|
||||
|
||||
// Assign the element
|
||||
if ( ! use_vector )
|
||||
{
|
||||
out_cc->println("%s[%s] = %s;",
|
||||
array_str.c_str(),
|
||||
env->LValue(elem_it_var()),
|
||||
out_cc->println("%s[%s] = %s;",
|
||||
array_str.c_str(),
|
||||
env->LValue(elem_it_var()),
|
||||
env->LValue(elem_var()));
|
||||
}
|
||||
else
|
||||
{
|
||||
out_cc->println("%s->push_back(%s);",
|
||||
array_str.c_str(),
|
||||
out_cc->println("%s->push_back(%s);",
|
||||
array_str.c_str(),
|
||||
env->LValue(elem_var()));
|
||||
}
|
||||
}
|
||||
|
||||
void ArrayType::DoGenParseCode(Output *out_cc, Env *env,
|
||||
void ArrayType::DoGenParseCode(Output *out_cc, Env *env,
|
||||
const DataPtr& data, int flags)
|
||||
{
|
||||
GenArrayLength(out_cc, env, data);
|
||||
|
@ -466,10 +479,10 @@ void ArrayType::DoGenParseCode(Output *out_cc, Env *env,
|
|||
{
|
||||
// Do not compute size_var on incremental input
|
||||
compute_size_var = false;
|
||||
|
||||
|
||||
if ( ! incremental_parsing() &&
|
||||
( StaticSize(env) >= 0 ||
|
||||
( env->Evaluated(arraylength_var()) &&
|
||||
( env->Evaluated(arraylength_var()) &&
|
||||
elemtype_->StaticSize(env) >= 0 ) ) )
|
||||
{
|
||||
GenBoundaryCheck(out_cc, env, data);
|
||||
|
@ -491,7 +504,7 @@ void ArrayType::DoGenParseCode(Output *out_cc, Env *env,
|
|||
|
||||
if ( elem_dataptr_var() )
|
||||
{
|
||||
out_cc->println("const_byteptr %s = %s;",
|
||||
out_cc->println("const_byteptr %s = %s;",
|
||||
env->LValue(elem_dataptr_var()), data.ptr_expr());
|
||||
env->SetEvaluated(elem_dataptr_var());
|
||||
|
||||
|
@ -499,13 +512,13 @@ void ArrayType::DoGenParseCode(Output *out_cc, Env *env,
|
|||
}
|
||||
|
||||
string for_condition = known_array_length ?
|
||||
strfmt("%s < %s",
|
||||
env->LValue(elem_it_var()),
|
||||
strfmt("%s < %s",
|
||||
env->LValue(elem_it_var()),
|
||||
env->RValue(arraylength_var())) :
|
||||
"/* forever */";
|
||||
|
||||
out_cc->println("for (; %s; ++%s)",
|
||||
for_condition.c_str(),
|
||||
out_cc->println("for (; %s; ++%s)",
|
||||
for_condition.c_str(),
|
||||
env->LValue(elem_it_var()));
|
||||
out_cc->inc_indent();
|
||||
out_cc->println("{");
|
||||
|
@ -515,13 +528,13 @@ void ArrayType::DoGenParseCode(Output *out_cc, Env *env,
|
|||
|
||||
if ( elem_dataptr_var() )
|
||||
GenUntilCheck(out_cc, env, elem_dataptr_until_expr_, false);
|
||||
|
||||
|
||||
elemtype_->GenPreParsing(out_cc, env);
|
||||
elemtype_->GenParseCode(out_cc, env, elem_data, flags);
|
||||
|
||||
if ( incremental_parsing() )
|
||||
if ( incremental_parsing() )
|
||||
{
|
||||
out_cc->println("if ( ! %s )",
|
||||
out_cc->println("if ( ! %s )",
|
||||
elemtype_->parsing_complete(env).c_str());
|
||||
out_cc->inc_indent();
|
||||
out_cc->println("goto %s;", kNeedMoreData);
|
||||
|
@ -532,11 +545,11 @@ void ArrayType::DoGenParseCode(Output *out_cc, Env *env,
|
|||
|
||||
if ( elem_dataptr_var() )
|
||||
{
|
||||
out_cc->println("%s += %s;",
|
||||
env->LValue(elem_dataptr_var()),
|
||||
out_cc->println("%s += %s;",
|
||||
env->LValue(elem_dataptr_var()),
|
||||
elemtype_->DataSize(0, env, elem_data).c_str());
|
||||
out_cc->println("BINPAC_ASSERT(%s <= %s);",
|
||||
env->RValue(elem_dataptr_var()),
|
||||
env->RValue(elem_dataptr_var()),
|
||||
env->RValue(end_of_data));
|
||||
}
|
||||
|
||||
|
@ -556,7 +569,7 @@ void ArrayType::DoGenParseCode(Output *out_cc, Env *env,
|
|||
if ( compute_size_var && elem_dataptr_var() && ! env->Evaluated(size_var()) )
|
||||
{
|
||||
// Compute the data size
|
||||
out_cc->println("%s = %s - (%s);",
|
||||
out_cc->println("%s = %s - (%s);",
|
||||
env->LValue(size_var()),
|
||||
env->RValue(elem_dataptr_var()),
|
||||
data.ptr_expr());
|
||||
|
@ -572,7 +585,7 @@ void ArrayType::GenUntilInputCheck(Output *out_cc, Env *env)
|
|||
elem_input_var_id, extern_type_const_bytestring->Clone());
|
||||
elem_input_var_field_->Prepare(env);
|
||||
|
||||
out_cc->println("%s %s(%s, %s);",
|
||||
out_cc->println("%s %s(%s, %s);",
|
||||
extern_type_const_bytestring->DataTypeStr().c_str(),
|
||||
env->LValue(elem_input_var()),
|
||||
env->RValue(begin_of_data),
|
||||
|
@ -582,22 +595,22 @@ void ArrayType::GenUntilInputCheck(Output *out_cc, Env *env)
|
|||
GenUntilCheck(out_cc, env, attr_until_input_expr_, true);
|
||||
}
|
||||
|
||||
void ArrayType::GenUntilCheck(Output *out_cc, Env *env,
|
||||
void ArrayType::GenUntilCheck(Output *out_cc, Env *env,
|
||||
Expr *until_expr, bool delete_elem)
|
||||
{
|
||||
ASSERT(until_expr);
|
||||
|
||||
Env check_env(env, this);
|
||||
check_env.AddMacro(element_macro_id,
|
||||
check_env.AddMacro(element_macro_id,
|
||||
new Expr(elem_var()->clone()));
|
||||
if ( elem_input_var() )
|
||||
{
|
||||
check_env.AddMacro(input_macro_id,
|
||||
check_env.AddMacro(input_macro_id,
|
||||
new Expr(elem_input_var()->clone()));
|
||||
}
|
||||
|
||||
out_cc->println("// Check &until(%s)", until_expr->orig());
|
||||
out_cc->println("if ( %s )",
|
||||
out_cc->println("if ( %s )",
|
||||
until_expr->EvalExpr(out_cc, &check_env));
|
||||
out_cc->inc_indent();
|
||||
out_cc->println("{");
|
||||
|
@ -624,12 +637,12 @@ void ArrayType::GenDynamicSize(Output *out_cc, Env *env,
|
|||
const DataPtr& data)
|
||||
{
|
||||
ASSERT(! incremental_input());
|
||||
DEBUG_MSG("Generating dynamic size for array `%s'\n",
|
||||
DEBUG_MSG("Generating dynamic size for array `%s'\n",
|
||||
value_var()->Name());
|
||||
|
||||
int elem_w = elemtype_->StaticSize(env);
|
||||
if ( elem_w >= 0 &&
|
||||
! attr_until_element_expr_ &&
|
||||
! attr_until_element_expr_ &&
|
||||
! attr_until_input_expr_ &&
|
||||
( length_ || attr_restofdata_ ) )
|
||||
{
|
||||
|
@ -661,7 +674,7 @@ int ArrayType::StaticSize(Env *env) const
|
|||
if ( elem_w < 0 )
|
||||
return -1;
|
||||
|
||||
DEBUG_MSG("static size of %s:%s = %d * %d\n",
|
||||
DEBUG_MSG("static size of %s:%s = %d * %d\n",
|
||||
decl_id()->Name(), lvalue(), elem_w, num);
|
||||
|
||||
return num * elem_w;
|
||||
|
@ -675,18 +688,18 @@ void ArrayType::SetBoundaryChecked()
|
|||
|
||||
void ArrayType::DoMarkIncrementalInput()
|
||||
{
|
||||
elemtype_->MarkIncrementalInput();
|
||||
elemtype_->MarkIncrementalInput();
|
||||
}
|
||||
|
||||
bool ArrayType::RequiresAnalyzerContext()
|
||||
{
|
||||
{
|
||||
return Type::RequiresAnalyzerContext() ||
|
||||
( length_ && length_->RequiresAnalyzerContext() ) ||
|
||||
elemtype_->RequiresAnalyzerContext();
|
||||
( length_ && length_->RequiresAnalyzerContext() ) ||
|
||||
elemtype_->RequiresAnalyzerContext();
|
||||
}
|
||||
|
||||
bool ArrayType::DoTraverse(DataDepVisitor *visitor)
|
||||
{
|
||||
{
|
||||
if ( ! Type::DoTraverse(visitor) )
|
||||
return false;
|
||||
|
||||
|
@ -694,7 +707,7 @@ bool ArrayType::DoTraverse(DataDepVisitor *visitor)
|
|||
return false;
|
||||
|
||||
if ( ! elemtype_->Traverse(visitor) )
|
||||
return false;
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue