@Oli I think for the implementation of the last piece of stacked borrows, I'd like to have access to some global state from the memory access hooks (
memory_deallocated). The state should be shared across all allocations. What do you think would be the best way to do that?
I am talking about "function barriers", which get pushed when a reference is passed to a function and should get removed when the function returns. A naive implementation would be to store the index of the function in the call stack, and then on a pop iterate over all of memory to get rid of these barriers. But I don't want to iterate over all of memory...
So instead I think I will introduce an indirection: Every call frame gets an ID that is unique across program execution, and we use that ID in the barrier. We have a global table storing which IDs are no longer in use, where frames get added when they are popped. When we encounter a barrier, if its ID is one of a call stack that is marked in that table as having popped already, we just ignore it.
But that means I need access to this global table from the memory access hooks. My best idea so far: Re-introduce the
MemoryData that I killed some PRs ago, and pass that to the hooks. With the hooks being called from methods on allocations, that means those methods need to take a pointer to where the
MemoryData is. Kind of ugly, but not too bad --
MemoryData would be
() for CTFE so when CTFE accesses an allocation directly (outside of an execution), it can just pass
What about using Rc? That would be completely encapsulated in miri and the engine would never know
Would of course incur the memory cost of an additional pointer per AllocationExtra
how would that
Rc get into the hooks?
Uh, I don't know, I'm on mobile right now, so gimme a moment
So, you do in fact reintroduce the MemoryData, and you also add an AllocExtra method for
allocate, which produces the AllocExtra. You pass a reference to MemoryData to the allocate hook. CTFE just ignores the arg and has an empty function body producing the expected unit
So no more Default bound on AllocationExtra
Seems nicely symmetric with the deallocate hook
If you need access to the allocation itself during the allocate hook, pass an allocation with the empty tuple as AllocExtra
So you want every
AllocExtra to carry a pointer to the
MemoryData? Why is that better than passing in a pointer on every read/write/dealloc? Passing in
&() does not seem too bad?
well... every call from within miri-engine and miri is already given a
tcx, now a
&MemoryData, too... these arguments are just noise. Maybe we can make
get_mut return a wrapper around
Allocation which has the same methods as
Allocation but without the extra arguments
I do like not using
Default, I got some use for that, but I don't like that extra ptr-sized overhead of memory use everywhere. Hm.
but maybe I am overthinking it and one more ptr size per allocation is not worth the effort?
It's either complexity at every memory operation site or an Rc in the structure + one Mutex check per memory operation
the complexity at every operation site can be solved by making
get_mut return a wrapper around
Are you planning on trying to get stacked borrows into const eval $ever?
If not, then I think we should go with the extra
Rc in miri
Not sure about
$ever, but it'd probably kill compile times...
okay I will go with
Rc for now
Well you need an
Rc<Mutex<Data>> otherwise you can't mutate it ;)
I also think I will actually use a
HashSet of unique stack frame identifiers that have NOT been popped yet, that won't grow unboundedly like my original idea would^^