X-Git-Url: https://git.ralfj.de/web.git/blobdiff_plain/c4c5bcaf9f0a9d9da4d246f9ec2f478234966903..b45ff0e7e99561afa0586c95bf1d6c661e0daf6d:/personal/_posts/2018-08-07-stacked-borrows.md?ds=sidebyside diff --git a/personal/_posts/2018-08-07-stacked-borrows.md b/personal/_posts/2018-08-07-stacked-borrows.md index 3577e3d..f523482 100644 --- a/personal/_posts/2018-08-07-stacked-borrows.md +++ b/personal/_posts/2018-08-07-stacked-borrows.md @@ -198,7 +198,7 @@ However, I now came to the conclusion that tagging pointers is a price worth pay I hope you now have a clear idea of the basic structure of the model I am proposing: The stack of borrows, the freeze flag, and references tagged with the time at which they got created. The full model is not quite as simple, but it is not much more complicated either. -We need two add just two more concepts: Retagging and barriers. +We need to add just two more concepts: Retagging and barriers. ### 4.1 Retagging @@ -442,7 +442,7 @@ Now we can look at what happens for each operation. - Compute `new_bor` from `new_tag` and the type of the reference being created. - `reactivate(bor)`. - If this is a function argument coming in: `loc.borrows.push(FnBarrier(stack_height))`. - - `initiate(new_bor)`. Note that this is a NOP if `new_bor` is already active -- in particular, if the location is frozen and this is a shared reference with interior mutability, we do *not* push anything on top of the barrier. This is important, because we do not want to push that might unfreeze the location when being reactivated. + - `initiate(new_bor)`. Note that this is a NOP if `new_bor` is already active -- in particular, if the location is frozen and this is a shared reference with interior mutability, we do *not* push anything on top of the barrier. This is important, because any reactivation that unfreezes this location must lead to UB while the barrier is still present. - Change reference tag to `new_tag`. * Any time a raw pointer is created from a reference, we might have to do a raw reborrow. - `reactivate(bor)`. @@ -450,6 +450,7 @@ Now we can look at what happens for each operation. * Any time a function returns, we have to clean up the barriers. - Iterate over all of memory and remove the matching `FnBarrier`. This is where the "stack" becomes a bit of a lie, because we also remove barriers from the middle of a stack.
This could be optimized by adding an indirection, so we just have to record somewhere that this function call has ended. +* Any time memory is deallocated, this counts as mutation, so the usual rules for that apply. After that, the stacks of the deallocated bytes must not contain any barriers. If you want to test your own understanding of "Stacked Borrows", I invite you to go back to [Section 2.2 of "Types as Contracts"]({% post_url 2017-07-17-types-as-contracts %}#22-examples) and look at the three examples here.