diff --git a/src/Frame.cc b/src/Frame.cc index 3640964829..6da6a24584 100644 --- a/src/Frame.cc +++ b/src/Frame.cc @@ -126,7 +126,8 @@ void Frame::Clear() Frame* Frame::Clone() { Frame* f = new Frame(size, function, func_args); - + f->Clear(); + for ( int i = 0; i < size; ++i ) f->frame[i] = frame[i] ? frame[i]->Clone() : 0; @@ -138,6 +139,19 @@ Frame* Frame::Clone() return f; } +Frame* Frame::SelectiveClone(id_list* selection) + { + Frame* other = new Frame(size, function, func_args); + + loop_over_list(*selection, i) + { + ID* current = (*selection)[i]; + other->frame[current->Offset()] = this->frame[current->Offset()]; + } + + return other; + } + void Frame::SetTrigger(Trigger* arg_trigger) { ClearTrigger(); @@ -211,6 +225,30 @@ Frame* ClosureFrame::Clone() return cf; } +Frame* ClosureFrame::SelectiveClone(id_list* choose) + { + id_list us; + // and + id_list them; + + loop_over_list(*choose, i) + { + ID* we = (*choose)[i]; + if (closure_contains(we)) + us.append(we); + else + them.append(we); + } + + Frame* me = this->closure->SelectiveClone(&us); + // and + Frame* you = this->body->SelectiveClone(&them); + + ClosureFrame* who = new ClosureFrame(me, you, nullptr); + who->closure_elements = this->closure_elements; + + return who; + } // Each ClosureFrame knows all of the outer IDs that are used inside of it. This is known at // parse time. These leverage that. If frame_1 encloses frame_2 then the location of a lookup @@ -225,13 +263,10 @@ Val* ClosureFrame::GatherFromClosure(const Frame* start, const ID* id) { const ClosureFrame* conductor = dynamic_cast(start); - auto closure_contains = [] (const ClosureFrame* cf, const ID* i) - { return cf->closure_elements.find(i->Name()) != cf->closure_elements.end(); }; - if ( ! conductor ) return start->NthElement(id->Offset()); - if (closure_contains(conductor, id)) + if (conductor->closure_contains(id)) return ClosureFrame::GatherFromClosure(conductor->closure, id); return conductor->NthElement(id->Offset()); @@ -241,13 +276,12 @@ void ClosureFrame::SetInClosure(Frame* start, const ID* id, Val* val) { ClosureFrame* conductor = dynamic_cast(start); - auto closure_contains = [] (const ClosureFrame* cf, const ID* i) - { return cf->closure_elements.find(i->Name()) != cf->closure_elements.end(); }; - if ( ! conductor ) start->SetElement(id->Offset(), val); - else if (closure_contains(conductor, id)) + + else if (conductor->closure_contains(id)) ClosureFrame::SetInClosure(conductor->closure, id, val); + else conductor->Frame::SetElement(id->Offset(), val); } diff --git a/src/Frame.h b/src/Frame.h index 93d9677844..5767a1ebeb 100644 --- a/src/Frame.h +++ b/src/Frame.h @@ -57,7 +57,7 @@ public: // Deep-copies values. virtual Frame* Clone(); // Only deep-copies values corresponding to requested IDs. - Frame* SelectiveClone(id_list* selection); + virtual Frame* SelectiveClone(id_list* selection); // If the frame is run in the context of a trigger condition evaluation, // the trigger needs to be registered. @@ -112,6 +112,7 @@ public: Val* GetElement(ID* id) const override; void SetElement(const ID* id, Val* v) override; Frame* Clone() override; + Frame* SelectiveClone(id_list* selection) override; private: Frame* closure; @@ -123,6 +124,9 @@ private: // Moves through the closure frames and associates val with id. static void SetInClosure(Frame* start, const ID* id, Val* val); + bool closure_contains(const ID* i) const + { return this->closure_elements.find(i->Name()) != this->closure_elements.end(); } + // Hashes c style strings. The strings need to be null-terminated. struct const_char_hasher { size_t operator()(const char* in) const diff --git a/src/Func.cc b/src/Func.cc index 9ff44ebc6b..b98116c050 100644 --- a/src/Func.cc +++ b/src/Func.cc @@ -488,23 +488,7 @@ void BroFunc::SetClosureFrame(Frame* f) reporter->InternalError ("Tried to override closure for BroFunc %s.", this->Name()); - this->closure = f ? f->Clone() : nullptr; - } - -void BroFunc::ShiftOffsets(int shift, std::shared_ptr idl) - { - id_list* tmp = idl.get(); - if (! idl || shift == 0) - { - // Nothing to do here. - return; - } - - loop_over_list(*tmp, i) - { - ID* id = (*tmp)[i]; - id->SetOffset(id->Offset() + shift); - } + this->closure = f ? f->SelectiveClone(this->outer_ids.get()) : nullptr; } Val* BroFunc::DoClone() diff --git a/src/Var.cc b/src/Var.cc index 90d2bef348..ca8ed38944 100644 --- a/src/Var.cc +++ b/src/Var.cc @@ -421,7 +421,6 @@ TraversalCode OuterIDBindingFinder::PreExpr(const Expr* expr) const NameExpr* e = static_cast(expr); - // TODO: Do we need to capture these as well? if ( e->Id()->IsGlobal() ) return TC_CONTINUE; diff --git a/testing/btest/Baseline/language.function-closures/out b/testing/btest/Baseline/language.function-closures/out index 53274969c7..dceeea9211 100644 --- a/testing/btest/Baseline/language.function-closures/out +++ b/testing/btest/Baseline/language.function-closures/out @@ -1,9 +1,9 @@ -expect: 3 -3 -expect: 5 -5 -expect: 5 -5 +expect: 4 +4 +expect: 8 +8 +expect: 8 +8 expect: T T expect: T diff --git a/testing/btest/language/function-closures.zeek b/testing/btest/language/function-closures.zeek index 928d0aa4f1..b480f7b1a9 100644 --- a/testing/btest/language/function-closures.zeek +++ b/testing/btest/language/function-closures.zeek @@ -1,24 +1,26 @@ # @TEST-EXEC: zeek -b %INPUT >out # @TEST-EXEC: btest-diff out +global numberone : count = 1; + function make_count_upper (start : count) : function(step : count) : count { return function(step : count) : count - { return (start += step); }; + { return (start += (step + numberone)); }; } event zeek_init() { # basic local one = make_count_upper(1); - print "expect: 3"; + print "expect: 4"; print one(2); # multiple instances local two = make_count_upper(one(1)); - print "expect: 5"; + print "expect: 8"; print two(1); - print "expect: 5"; + print "expect: 8"; print one(1); # deep copies @@ -26,7 +28,7 @@ event zeek_init() print "expect: T"; print c(1) == one(1); print "expect: T"; - print c(1) == two(2); + print c(1) == two(3); # a little more complicated ... local cat_dog = 100;