From 06522c0264876975de9cf92348e71ac2af3241a8 Mon Sep 17 00:00:00 2001 From: Vern Paxson Date: Fri, 16 Jun 2023 15:41:00 -0700 Subject: [PATCH] support in ScriptFunc class for ZVal-oriented vector of captures --- src/Func.cc | 111 ++++++++++++++++++++++++++++++++++++++++++++++------ src/Func.h | 26 ++++++++++++ 2 files changed, 125 insertions(+), 12 deletions(-) diff --git a/src/Func.cc b/src/Func.cc index 77fd7a2dd0..008aa29c5e 100644 --- a/src/Func.cc +++ b/src/Func.cc @@ -324,6 +324,15 @@ ScriptFunc::ScriptFunc(std::string _name, FuncTypePtr ft, std::vector b ScriptFunc::~ScriptFunc() { + if ( captures_vec ) + { + auto& cvec = *captures_vec; + auto& captures = *type->GetCaptures(); + for ( int i = 0; i < captures.size(); ++i ) + if ( captures[i].IsManaged() ) + ZVal::DeleteManagedType(cvec[i]); + } + delete captures_frame; delete captures_offset_mapping; } @@ -506,31 +515,77 @@ void ScriptFunc::CreateCaptures(Frame* f) if ( ! captures ) return; - // Create a private Frame to hold the values of captured variables, - // and a mapping from those variables to their offsets in the Frame. - delete captures_frame; - delete captures_offset_mapping; - captures_frame = new Frame(captures->size(), this, nullptr); - captures_offset_mapping = new OffsetMap; + // Create *either* a private Frame to hold the values of captured + // variables, and a mapping from those variables to their offsets + // in the Frame; *or* a ZVal frame if this script has a ZAM-compiled + // body. + ASSERT(bodies.size() == 1); + + if ( bodies[0].stmts->Tag() == STMT_ZAM ) + captures_vec = std::make_unique>(); + else + { + delete captures_frame; + delete captures_offset_mapping; + captures_frame = new Frame(captures->size(), this, nullptr); + captures_offset_mapping = new OffsetMap; + } int offset = 0; for ( const auto& c : *captures ) { - auto v = f->GetElementByID(c.id); + auto v = f->GetElementByID(c.Id()); if ( v ) { - if ( c.deep_copy || ! v->Modifiable() ) + if ( c.IsDeepCopy() || ! v->Modifiable() ) v = v->Clone(); - captures_frame->SetElement(offset, std::move(v)); + if ( captures_vec ) + // Don't use v->GetType() here, as that might + // be "any" and we need to convert. + captures_vec->push_back(ZVal(v, c.Id()->GetType())); + else + captures_frame->SetElement(offset, std::move(v)); } - (*captures_offset_mapping)[c.id->Name()] = offset; + else if ( captures_vec ) + captures_vec->push_back(ZVal()); + + if ( ! captures_vec ) + (*captures_offset_mapping)[c.Id()->Name()] = offset; + ++offset; } } +void ScriptFunc::CreateCaptures(std::unique_ptr> cvec) + { + const auto& captures = *type->GetCaptures(); + + ASSERT(cvec->size() == captures.size()); + ASSERT(bodies.size() == 1 && bodies[0].stmts->Tag() == STMT_ZAM); + + captures_vec = std::move(cvec); + + auto n = captures.size(); + for ( auto i = 0U; i < n; ++i ) + { + auto& c_i = captures[i]; + auto& cv_i = (*captures_vec)[i]; + + if ( c_i.IsDeepCopy() ) + { + auto& t = c_i.Id()->GetType(); + auto new_cv_i = cv_i.ToVal(t)->Clone(); + if ( c_i.IsManaged() ) + ZVal::DeleteManagedType(cv_i); + + cv_i = ZVal(new_cv_i, t); + } + } + } + void ScriptFunc::SetCaptures(Frame* f) { const auto& captures = type->GetCaptures(); @@ -544,7 +599,7 @@ void ScriptFunc::SetCaptures(Frame* f) int offset = 0; for ( const auto& c : *captures ) { - (*captures_offset_mapping)[c.id->Name()] = offset; + (*captures_offset_mapping)[c.Id()->Name()] = offset; ++offset; } } @@ -633,13 +688,45 @@ FuncPtr ScriptFunc::DoClone() *other->captures_offset_mapping = *captures_offset_mapping; } + if ( captures_vec ) + { + auto cv_i = captures_vec->begin(); + auto cv_copy = std::make_unique>(); + for ( auto& c : *type->GetCaptures() ) + { + // Need to clone cv_i. + auto& t_i = c.Id()->GetType(); + auto cv_i_val = cv_i->ToVal(t_i)->Clone(); + cv_copy->push_back(ZVal(cv_i_val, t_i)); + ++cv_i; + } + + other->captures_vec = std::move(cv_copy); + } + return other; } broker::expected ScriptFunc::SerializeCaptures() const { + if ( captures_vec ) + { + auto& cv = *captures_vec; + auto& captures = *type->GetCaptures(); + int n = captures_vec->size(); + auto temp_frame = make_intrusive(n, this, nullptr); + + for ( int i = 0; i < n; ++i ) + { + auto c_i = cv[i].ToVal(captures[i].Id()->GetType()); + temp_frame->SetElement(i, c_i); + } + + return temp_frame->Serialize(); + } + if ( captures_frame ) - return captures_frame->SerializeCopyFrame(); + return captures_frame->Serialize(); // No captures, return an empty vector. return broker::vector{}; diff --git a/src/Func.h b/src/Func.h index c67ad7e6c9..53f1e6c19a 100644 --- a/src/Func.h +++ b/src/Func.h @@ -192,6 +192,17 @@ public: */ void CreateCaptures(Frame* f); + /** + * Uses the given set of ZVal's for captures. Note that this is + * different from the method above, which uses its argument to + * compute the captures, rather than here where they are pre-computed. + * + * Makes deep copies if required. + * + * @param cvec a vector of ZVal's corresponding to the captures. + */ + void CreateCaptures(std::unique_ptr> cvec); + /** * Returns the frame associated with this function for tracking * captures, or nil if there isn't one. @@ -200,6 +211,18 @@ public: */ Frame* GetCapturesFrame() const { return captures_frame; } + /** + * Returns the set of ZVal's used for captures. It's okay to modify + * these as long as memory-management is done for managed entries. + * + * @return internal vector of ZVal's kept for persisting captures + */ + auto& GetCapturesVec() const + { + ASSERT(captures_vec); + return *captures_vec; + } + // Same definition as in Frame.h. using OffsetMap = std::unordered_map; @@ -294,6 +317,9 @@ private: OffsetMap* captures_offset_mapping = nullptr; + // Captures when using ZVal block instead of a Frame. + std::unique_ptr> captures_vec; + // The most recently added/updated body ... StmtPtr current_body;