Copying or disposing of a non-escaping block can be a no-op. A non-escaping block on the stack doesn't have to be copied to the heap as we know it won't be called after its lifetime ends.
rdar://problem/39352313
Differential D49303
[CodeGen][ObjC] Treat non-escaping blocks as global blocks to make copy/dispose a no-op ahatanak on Jul 13 2018, 9:36 AM. Authored by
Details Copying or disposing of a non-escaping block can be a no-op. A non-escaping block on the stack doesn't have to be copied to the heap as we know it won't be called after its lifetime ends. rdar://problem/39352313
Diff Detail
Event TimelineComment Actions Please test that we still copy captures correctly into the block object and destroy them when the block object is destroyed. For the sorts of ephemeral blocks that we currently mark non-escaping, we can think about optimizing that away, too, but for now please test that we still perform captures normally. Comment Actions There is a bug in my patch where the capture cleanups aren't pushed when doesNotEscape() returns true. I'm working on a fix. Comment Actions Fix a bug where the capture cleanups weren't pushed when BlockDecl::doesNotEscape() returns true. Test that, when ARC is enabled, captures are retained and copied into the stack block object and destroyed when the stack block object goes out of scope.
Comment Actions Add a comment that explains the meaning of BLOCK_IS_NOESCAPE to the docs. Rename function needsCopyDispose to needsCopyDisposeHelpers. Comment Actions Thanks. A couple tiny things and then LGTM.
Comment Actions Blocks that don't capture anything have always been allocated globally. This optimization is using the global ISA for blocks that do capture locals but which are known statically (on penalty of UB) to not escape the original scope of the block literal. Using the global ISA causes attempts to copy these blocks to have no effect, in case the program attempts to do unnecessary copies despite the block being declared non-escaping. |
Something happened to my older comments here, but please document the meaning of this flag. Specifically, it is set on blocks that do have captures (and thus are not true global blocks) but which are known not to escape for various other reasons. Please include the fact that it implies BLOCK_IS_GLOBAL and explain why.