From 8f4b616d6576e9b7d73d621515b82fe475e3ffe7 Mon Sep 17 00:00:00 2001 From: Vern Paxson Date: Mon, 4 Jan 2021 14:17:56 -0800 Subject: [PATCH] changes to Frames to support access to captured-by-copy-semantics variables --- src/Frame.cc | 35 +++++++++++++++++++++++++++++------ src/Frame.h | 25 ++++++++++++++++++++++--- 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/Frame.cc b/src/Frame.cc index 12a01bb57e..05f4d3117f 100644 --- a/src/Frame.cc +++ b/src/Frame.cc @@ -30,6 +30,15 @@ Frame::Frame(int arg_size, const ScriptFunc* func, const zeek::Args* fn_args) delayed = false; closure = nullptr; + + // We could Ref()/Unref() the captures frame, but there's really + // no need because by definition this current frame exists to + // enable execution of the function, and its captures frame won't + // go away until the function itself goes away, which can only be + // after this frame does. + captures = function ? function->GetCapturesFrame() : nullptr; + captures_offset_map = + function ? function->GetCapturesOffsetMap() : nullptr; } Frame::~Frame() @@ -80,11 +89,18 @@ void Frame::SetElementWeak(int n, Val* v) void Frame::SetElement(const ID* id, ValPtr v) { - if ( closure ) + if ( closure && IsOuterID(id) ) { - if ( IsOuterID(id) ) + closure->SetElement(id, std::move(v)); + return; + } + + if ( captures ) + { + auto cap_off = captures_offset_map->find(id->Name()); + if ( cap_off != captures_offset_map->end() ) { - closure->SetElement(id, std::move(v)); + captures->SetElement(cap_off->second, std::move(v)); return; } } @@ -109,10 +125,14 @@ void Frame::SetElement(const ID* id, ValPtr v) const ValPtr& Frame::GetElementByID(const ID* id) const { - if ( closure ) + if ( closure && IsOuterID(id) ) + return closure->GetElementByID(id); + + if ( captures ) { - if ( IsOuterID(id) ) - return closure->GetElementByID(id); + auto cap_off = captures_offset_map->find(id->Name()); + if ( cap_off != captures_offset_map->end() ) + return captures->GetElement(cap_off->second); } // do we have an offset for it? @@ -185,6 +205,9 @@ Frame* Frame::Clone() const if ( frame[i].val ) other->frame[i].val = frame[i].val->Clone(); + // Note, there's no need to clone "captures" or "captures_offset_map" + // since those get created fresh when constructing "other". + return other; } diff --git a/src/Frame.h b/src/Frame.h index e78bdcf492..7f5abd0e4c 100644 --- a/src/Frame.h +++ b/src/Frame.h @@ -286,9 +286,12 @@ private: */ void ClearElement(int n); - /** Have we captured this id? */ + /** Have we captured this id? Version for deprecated semantics. */ bool IsOuterID(const ID* in) const; + /** Have we captured this id? Version for current semantics. */ + bool IsCaptureID(const ID* in) const; + /** Serializes an offset_map */ static broker::expected SerializeOffsetMap(const OffsetMap& in); @@ -316,10 +319,12 @@ private: /** Associates ID's offsets with values. */ std::unique_ptr frame; - /** The enclosing frame of this frame. */ + /** The enclosing frame of this frame. Used for reference semantics. */ Frame* closure; - /** ID's used in this frame from the enclosing frame. */ + /** ID's used in this frame from the enclosing frame, when using + * reference semantics (closure != nullptr). + */ IDPList outer_ids; /** @@ -328,8 +333,22 @@ private: */ std::unique_ptr offset_map; + /** Frame used for captures (if any) with copy semantics. */ + Frame* captures; + + /** Maps IDs to offsets into the "captures" frame. If the ID + * isn't present, then it's not a capture. + * + * We keep this separate from offset_map to help ensure we don't + * confuse code from the deprecated semantics with the current + * semantics. + */ + const OffsetMap* captures_offset_map; + /** The function this frame is associated with. */ const ScriptFunc* function; + + // The following is only needed for the debugger. /** The arguments to the function that this Frame is associated with. */ const zeek::Args* func_args;