Skip to content

fix: Remove excessive CF_NOESCAPE and NS_NOESCAPE#76

Merged
jdtsmith merged 1 commit intojdtsmith:emacs-mac-30_1_expfrom
pkryger:dev-emacs-mac-30_1-noescape
Aug 11, 2025
Merged

fix: Remove excessive CF_NOESCAPE and NS_NOESCAPE#76
jdtsmith merged 1 commit intojdtsmith:emacs-mac-30_1_expfrom
pkryger:dev-emacs-mac-30_1-noescape

Conversation

@pkryger
Copy link
Contributor

@pkryger pkryger commented Aug 10, 2025

Analysed all occurrences of CF_NOESCAPE and NS_NOESCAPE and removed
where the annotation seemed to be excessive, for example when the
annotated block has been enqueued in a queue to execute in another loop.

Such a block, may have a an optimised placement as
NSConcreteGlobalBlock on stack on a callee side. This happen on
non-Apple clang Apple at least in version 7 (see [1]).

This is slightly different than fully disabling the blocks (see [2],
[3], and [4]), while trying to preserve as much of the NOESCAPES where
it seems to server a purpose.

  • src/macappkit.m (mac_within_gui, mac_within_lisp,
    mac_within_gui_and_here, mac_within_gui_allowing_inner_lisp): Remove
    excessive CF_NOESCAPE, for blocks that are passed and executed in
    other threads.
  • src/macterm.h (mac_within_gui) : Remove excessive CF_NOESCAPE, for
    blocks that are passed and executed in other threads.
  • src/macappkit.h (enumerateChildWindowsUsingBlock): Harmonise
    NS_NOESCAPE placement.
  • src/macappkit.m (enumerateChildWindowsUsingBlock): Harmonise
    CF_NOESCAPE placement.

[1] NixOS/nixpkgs#127902 (comment)
[2] #43
[3] #48
[4] #69

@pkryger pkryger mentioned this pull request Aug 10, 2025
- (void)enumerateChildWindowsUsingBlock:(NS_NOESCAPE void
(^)(NSWindow *child, BOOL *stop))block;
- (void)enumerateChildWindowsUsingBlock:(void
(NS_NOESCAPE ^)(NSWindow *child, BOOL *stop))block;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this just for consistency or does the order of the caret matter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right, this is for consistency only, the order doesn't matter.

Details

In a context of this gist.

I compiled a small example (just most important bits):

#define MY_NOESCAPE __attribute__ ((noescape))
void queue_block_1(void (^ MY_NOESCAPE block) (void)) {...}
void queue_block_2(void (MY_NOESCAPE ^block) (void)) {...}
void queue_block_3(MY_NOESCAPE void (^block) (void)) {...}
void queue_1(const char* arg)
{
  queue_block_1(^{
      printf("block_1: %s\n", arg);
    });
}

void queue_2(const char* arg)
{
  queue_block_2(^{
      printf("block_2: %s\n", arg);
    });
}

void queue_3(const char* arg)
{
  queue_block_3(^{
      printf("block_3: %s\n", arg);
    });
}

with $(brew --prefix llvm)/bin/clang -g -framework CoreFoundation -o reproducer_123 reproducer.m and then:

(lldb) dis -n queue_1
reproducer_123`queue_1:
[...]
reproducer_123[0x100000828] <+32>: mov    w8, #-0x2f800000 ; =-796917760
[...]
(lldb) dis -n queue_2
reproducer_123`queue_2:
[...]
reproducer_123[0x1000008c4] <+32>: mov    w8, #-0x2f800000 ; =-796917760
(lldb) dis -n queue_3
reproducer_123`queue_3:
[...]
reproducer_123[0x100000960] <+32>: mov    w8, #-0x2f800000 ; =-796917760

static void mac_within_gui_allowing_inner_lisp (void (^ CF_NOESCAPE) (void));
static void mac_within_lisp (void (^ CF_NOESCAPE) (void));
static void mac_within_gui_and_here (void (^) (void),
void (CF_NOESCAPE ^) (void));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here the idea is that block_here is executed locally, and so does not escape?

Copy link
Contributor Author

@pkryger pkryger Aug 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly that.

This is the only usage of block_here

@jdtsmith jdtsmith force-pushed the dev-emacs-mac-30_1-noescape branch from 206f229 to b71c4e9 Compare August 11, 2025 14:34
These annotations direct the compiler to optimize block allocation
assuming the function to which it is passed calls it locally, and does
not retain the block beyond the function body.

Analyzed all occurrences of CF_NOESCAPE and NS_NOESCAPE and removed
locations where the annotation seemed to be excessive, for example when
the annotated block has been enqueued in a queue to execute in another
loop.

Such a block may have a an optimized placement as
`NSConcreteGlobalBlock' on the stack on a callee side. This happen on
non-Apple clang Apple at least from version 7 (see [1]).

This tries to preserve as many of the NOESCAPES which serve a purpose;
see [2], [3], and [4].

* src/macappkit.m (mac_within_gui, mac_within_lisp,
  mac_within_gui_and_here, mac_within_gui_allowing_inner_lisp): Remove
  excessive CF_NOESCAPE annotations, for blocks that are passed and
  executed in other threads or saved on queues.
* src/macterm.h (mac_within_gui) : Remove excessive CF_NOESCAPE, for
  blocks that are passed and executed in other threads.
* src/macappkit.h (enumerateChildWindowsUsingBlock): Harmonize
  NS_NOESCAPE placement.
* src/macappkit.m (enumerateChildWindowsUsingBlock): Harmonize
  CF_NOESCAPE placement.

[1] NixOS/nixpkgs#127902 (comment)
[2] jdtsmith#43
[3] jdtsmith#48
[4] jdtsmith#69
@jdtsmith jdtsmith force-pushed the dev-emacs-mac-30_1-noescape branch from b71c4e9 to c3f3ce5 Compare August 11, 2025 14:36
@jdtsmith jdtsmith changed the title fix: Remove excessive CF_NOESCAPE and CS_NOESCAPE fix: Remove excessive CF_NOESCAPE and NS_NOESCAPE Aug 11, 2025
@jdtsmith jdtsmith merged commit 676e933 into jdtsmith:emacs-mac-30_1_exp Aug 11, 2025
@jdtsmith
Copy link
Owner

Thanks for your contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants