changes to Frames to support access to captured-by-copy-semantics variables

This commit is contained in:
Vern Paxson 2021-01-04 14:17:56 -08:00
parent 627fb8616e
commit 8f4b616d65
2 changed files with 51 additions and 9 deletions

View file

@ -30,6 +30,15 @@ Frame::Frame(int arg_size, const ScriptFunc* func, const zeek::Args* fn_args)
delayed = false; delayed = false;
closure = nullptr; 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() Frame::~Frame()
@ -80,13 +89,20 @@ void Frame::SetElementWeak(int n, Val* v)
void Frame::SetElement(const ID* id, ValPtr v) void Frame::SetElement(const ID* id, ValPtr v)
{ {
if ( closure ) if ( closure && IsOuterID(id) )
{
if ( IsOuterID(id) )
{ {
closure->SetElement(id, std::move(v)); closure->SetElement(id, std::move(v));
return; return;
} }
if ( captures )
{
auto cap_off = captures_offset_map->find(id->Name());
if ( cap_off != captures_offset_map->end() )
{
captures->SetElement(cap_off->second, std::move(v));
return;
}
} }
// do we have an offset for it? // do we have an offset for it?
@ -109,10 +125,14 @@ void Frame::SetElement(const ID* id, ValPtr v)
const ValPtr& Frame::GetElementByID(const ID* id) const const ValPtr& Frame::GetElementByID(const ID* id) const
{ {
if ( closure ) if ( closure && IsOuterID(id) )
{
if ( IsOuterID(id) )
return closure->GetElementByID(id); return closure->GetElementByID(id);
if ( captures )
{
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? // do we have an offset for it?
@ -185,6 +205,9 @@ Frame* Frame::Clone() const
if ( frame[i].val ) if ( frame[i].val )
other->frame[i].val = frame[i].val->Clone(); 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; return other;
} }

View file

@ -286,9 +286,12 @@ private:
*/ */
void ClearElement(int n); void ClearElement(int n);
/** Have we captured this id? */ /** Have we captured this id? Version for deprecated semantics. */
bool IsOuterID(const ID* in) const; 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 */ /** Serializes an offset_map */
static broker::expected<broker::data> static broker::expected<broker::data>
SerializeOffsetMap(const OffsetMap& in); SerializeOffsetMap(const OffsetMap& in);
@ -316,10 +319,12 @@ private:
/** Associates ID's offsets with values. */ /** Associates ID's offsets with values. */
std::unique_ptr<Element[]> frame; std::unique_ptr<Element[]> frame;
/** The enclosing frame of this frame. */ /** The enclosing frame of this frame. Used for reference semantics. */
Frame* closure; 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; IDPList outer_ids;
/** /**
@ -328,8 +333,22 @@ private:
*/ */
std::unique_ptr<OffsetMap> offset_map; std::unique_ptr<OffsetMap> 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. */ /** The function this frame is associated with. */
const ScriptFunc* function; const ScriptFunc* function;
// The following is only needed for the debugger.
/** The arguments to the function that this Frame is associated with. */ /** The arguments to the function that this Frame is associated with. */
const zeek::Args* func_args; const zeek::Args* func_args;