From 092d049f8ee958b3475b9486fb2a65bb743e9a66 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Thu, 22 Sep 2011 21:19:16 -0700 Subject: [PATCH] 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. --- tools/binpac/src/pac_array.cc | 145 ++++++++++++++++++---------------- 1 file changed, 79 insertions(+), 66 deletions(-) diff --git a/tools/binpac/src/pac_array.cc b/tools/binpac/src/pac_array.cc index 7477ba050b..1d38011780 100644 --- a/tools/binpac/src/pac_array.cc +++ b/tools/binpac/src/pac_array.cc @@ -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; }