Mercurial > vim
view src/os_macosx.m @ 34021:46ebf4ffad49 v9.0.2186
patch 9.0.2186: LTCG compile error ARM64 for write_chars
Commit: https://github.com/vim/vim/commit/38bea30f53da8e4a8847407404597b255b20334e
Author: Saleem Abdulrasool <compnerd@compnerd.org>
Date: Wed Dec 27 18:57:12 2023 +0100
patch 9.0.2186: LTCG compile error ARM64 for write_chars
Problem: LTCG compile error on Win/ARM64 for `write_chars()`
Solution: Explicitly initialise the storage to use data rather than BSS
(Saleem Abdulrasool)
win32: add a workaround for a LTCG issue on Windows ARM64
It appears that the implicit initialisation which would push `g_coords`
into BSS causes an aliasing issue with LTCG on ARM64. By explicitly
initialising the value, we use usual data storage but prevent the
aliasing. This allows the console version of VIM to run on Windows
ARM64 again.
fixes: #13453
closes: #13775
Signed-off-by: Saleem Abdulrasool <compnerd@compnerd.org>
Signed-off-by: Christian Brabandt <cb@256bit.org>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Wed, 27 Dec 2023 19:15:03 +0100 |
parents | ca4e81de477a |
children |
line wrap: on
line source
/* vi:set ts=8 sts=4 sw=4 noet: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* * os_macosx.m -- Mac specific things for Mac OS X. */ /* Suppress compiler warnings to non-C89 code. */ #if defined(__clang__) && defined(__STRICT_ANSI__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wc99-extensions" # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdeclaration-after-statement" #endif /* Avoid a conflict for the definition of Boolean between Mac header files and * X11 header files. */ #define NO_X11_INCLUDES #include <stdbool.h> #include <mach/boolean.h> #include <sys/errno.h> #include <stdlib.h> #ifdef FEAT_RELTIME #include <dispatch/dispatch.h> #endif #include "vim.h" #import <AppKit/AppKit.h> /* * Clipboard support for the console. */ #if defined(FEAT_CLIPBOARD) /* Used to identify clipboard data copied from Vim. */ NSString *VimPboardType = @"VimPboardType"; void clip_mch_lose_selection(Clipboard_T *cbd UNUSED) { } int clip_mch_own_selection(Clipboard_T *cbd UNUSED) { /* This is called whenever there is a new selection and 'guioptions' * contains the "a" flag (automatically copy selection). Return TRUE, else * the "a" flag does nothing. Note that there is no concept of "ownership" * of the clipboard in Mac OS X. */ return TRUE; } void clip_mch_request_selection(Clipboard_T *cbd) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSPasteboard *pb = [NSPasteboard generalPasteboard]; #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 NSArray *supportedTypes = [NSArray arrayWithObjects:VimPboardType, NSPasteboardTypeString, nil]; #else NSArray *supportedTypes = [NSArray arrayWithObjects:VimPboardType, NSStringPboardType, nil]; #endif NSString *bestType = [pb availableTypeFromArray:supportedTypes]; if (!bestType) goto releasepool; int motion_type = MAUTO; NSString *string = nil; if ([bestType isEqual:VimPboardType]) { /* This type should consist of an array with two objects: * 1. motion type (NSNumber) * 2. text (NSString) * If this is not the case we fall back on using NSPasteboardTypeString. */ id plist = [pb propertyListForType:VimPboardType]; if ([plist isKindOfClass:[NSArray class]] && [plist count] == 2) { id obj = [plist objectAtIndex:1]; if ([obj isKindOfClass:[NSString class]]) { motion_type = [[plist objectAtIndex:0] intValue]; string = obj; } } } if (!string) { /* Use NSPasteboardTypeString. The motion type is detected automatically. */ #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 NSMutableString *mstring = [[pb stringForType:NSPasteboardTypeString] mutableCopy]; #else NSMutableString *mstring = [[pb stringForType:NSStringPboardType] mutableCopy]; #endif if (!mstring) goto releasepool; /* Replace unrecognized end-of-line sequences with \x0a (line feed). */ NSRange range = { 0, [mstring length] }; unsigned n = [mstring replaceOccurrencesOfString:@"\x0d\x0a" withString:@"\x0a" options:0 range:range]; if (0 == n) { n = [mstring replaceOccurrencesOfString:@"\x0d" withString:@"\x0a" options:0 range:range]; } string = mstring; } /* Default to MAUTO, uses MCHAR or MLINE depending on trailing NL. */ if (!(MCHAR == motion_type || MLINE == motion_type || MBLOCK == motion_type || MAUTO == motion_type)) motion_type = MAUTO; char_u *str = (char_u*)[string UTF8String]; int len = [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; if (input_conv.vc_type != CONV_NONE) str = string_convert(&input_conv, str, &len); if (str) clip_yank_selection(motion_type, str, len, cbd); if (input_conv.vc_type != CONV_NONE) vim_free(str); releasepool: [pool release]; } /* * Send the current selection to the clipboard. */ void clip_mch_set_selection(Clipboard_T *cbd) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; /* If the '*' register isn't already filled in, fill it in now. */ cbd->owned = TRUE; clip_get_selection(cbd); cbd->owned = FALSE; /* Get the text to put on the pasteboard. */ long_u llen = 0; char_u *str = 0; int motion_type = clip_convert_selection(&str, &llen, cbd); if (motion_type < 0) goto releasepool; /* TODO: Avoid overflow. */ int len = (int)llen; if (output_conv.vc_type != CONV_NONE) { char_u *conv_str = string_convert(&output_conv, str, &len); if (conv_str) { vim_free(str); str = conv_str; } } if (len > 0) { NSString *string = [[NSString alloc] initWithBytes:str length:len encoding:NSUTF8StringEncoding]; /* See clip_mch_request_selection() for info on pasteboard types. */ NSPasteboard *pb = [NSPasteboard generalPasteboard]; #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 NSArray *supportedTypes = [NSArray arrayWithObjects:VimPboardType, NSPasteboardTypeString, nil]; #else NSArray *supportedTypes = [NSArray arrayWithObjects:VimPboardType, NSStringPboardType, nil]; #endif [pb declareTypes:supportedTypes owner:nil]; NSNumber *motion = [NSNumber numberWithInt:motion_type]; NSArray *plist = [NSArray arrayWithObjects:motion, string, nil]; [pb setPropertyList:plist forType:VimPboardType]; #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 [pb setString:string forType:NSPasteboardTypeString]; #else [pb setString:string forType:NSStringPboardType]; #endif [string release]; } vim_free(str); releasepool: [pool release]; } #endif /* FEAT_CLIPBOARD */ #ifdef FEAT_RELTIME /* * The following timer code is based on a Gist by Jorgen Lundman: * * https://gist.github.com/lundman */ typedef struct macos_timer macos_timer_T; static void _timer_cancel(void *arg UNUSED) { // This is not currently used, but it might be useful in the future and // it is non-trivial enough to provide as usable implementation. # if 0 macos_timer_T *timerid = (macos_timer_T *)arg; dispatch_release(timerid->tim_timer); dispatch_release(timerid->tim_queue); timerid->tim_timer = NULL; timerid->tim_queue = NULL; free(timerid); # endif } static void _timer_handler(void *arg) { macos_timer_T *timerid = (macos_timer_T *)arg; union sigval sv; sv.sival_ptr = timerid->tim_arg; if (timerid->tim_func != NULL) timerid->tim_func(sv); } static uint64_t itime_to_ns(const struct timespec *it) { time_t sec = it->tv_sec; long nsec = it->tv_nsec; uint64_t ns = NSEC_PER_SEC * sec + nsec; return ns == 0 ? DISPATCH_TIME_FOREVER : ns; } /* * A partial emulation of the POSIX timer_create function. * * The limitations and differences include: * * - Only CLOCK_REALTIME and CLOCK_MONOTONIC are supported as clockid * values. * - Even if CLOCK_REALTIME is specified, internally the mach_absolute_time * source is used internally. * - The only notification method supported is SIGEV_THREAD. */ inline int timer_create(clockid_t clockid, struct sigevent *sevp, timer_t *timerid) { macos_timer_T *timer = NULL; // We only support real time and monotonic clocks; and SIGEV_THREAD // notification. In practice, there is no difference between the two // types of clocks on MacOS - we always use the mach_machine_time // source. if ( (clockid != CLOCK_REALTIME && clockid != CLOCK_MONOTONIC) || sevp->sigev_notify != SIGEV_THREAD) { semsg("clockid: %d %d", clockid, CLOCK_REALTIME); semsg("notify: %d %d", sevp->sigev_notify, SIGEV_THREAD); errno = ENOTSUP; return -1; } timer = (macos_timer_T *)malloc(sizeof(macos_timer_T)); if (timer == NULL) { errno = ENOMEM; return -1; } *timerid = timer; timer->tim_queue = dispatch_queue_create( "org.vim.timerqueue", NULL); if (timer->tim_queue == NULL) { errno = ENOMEM; return -1; } timer->tim_timer = dispatch_source_create( DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timer->tim_queue); if (timer->tim_timer == NULL) { errno = ENOMEM; return -1; } timer->tim_func = sevp->sigev_notify_function; timer->tim_arg = sevp->sigev_value.sival_ptr; dispatch_set_context(timer->tim_timer, timer); dispatch_source_set_event_handler_f(timer->tim_timer, _timer_handler); dispatch_source_set_cancel_handler_f(timer->tim_timer, _timer_cancel); dispatch_resume(timer->tim_timer); return 0; } /* * A partial emulation of the POSIX timer_settime function. * * The limitations and differences include: * * - The flags argument is ignored. The supplied new_value is therefore * always treated as a relative time. * - The old_value argument is ignored. */ int timer_settime( timer_t timerid, int unused_flags UNUSED, const struct itimerspec *new_value, struct itimerspec *old_value UNUSED) { uint64_t first_shot = itime_to_ns(&new_value->it_value); if (timerid == NULL) return 0; if (first_shot == DISPATCH_TIME_FOREVER) { dispatch_source_set_timer( timerid->tim_timer, first_shot, first_shot, 0); } else { uint64_t interval = itime_to_ns(&new_value->it_interval); dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, first_shot); dispatch_source_set_timer(timerid->tim_timer, start, interval, 0); } return 0; } /* * An emulation of the POSIX timer_delete function. * * Disabled because it is not currently used, but an implemented provided * for completeness and possible future use. */ int timer_delete(timer_t timerid) { /* Calls _timer_cancel() */ if (timerid != NULL) dispatch_source_cancel(timerid->tim_timer); return 0; } #endif /* FEAT_RELTIME */ #ifdef FEAT_SOUND static NSMutableDictionary<NSNumber*, NSSound*> *sounds_list = nil; /// A delegate for handling when a sound has stopped playing, in /// order to clean up the sound and to send a callback. @interface SoundDelegate : NSObject<NSSoundDelegate>; - (id) init:(long) sound_id callback:(soundcb_T*) callback; - (void) sound:(NSSound *)sound didFinishPlaying:(BOOL)flag; @property (readonly) long sound_id; @property (readonly) soundcb_T *callback; @end @implementation SoundDelegate - (id) init:(long) sound_id callback:(soundcb_T*) callback { if ([super init]) { _sound_id = sound_id; _callback = callback; } return self; } - (void) sound:(NSSound *)sound didFinishPlaying:(BOOL)flag { if (sounds_list != nil) { if (_callback) { call_sound_callback(_callback, _sound_id, flag ? 0 : 1); delete_sound_callback(_callback); _callback = NULL; } [sounds_list removeObjectForKey:[NSNumber numberWithLong:_sound_id]]; } // Release itself. Do that here instead of earlier because NSSound only // holds weak reference to this object. [self release]; } @end void process_cfrunloop(void) { if (sounds_list != nil && [sounds_list count] > 0) { // Continually drain the run loop of events. Currently, this // is only used for processing sound callbacks, because // NSSound relies of this runloop to call back to the // delegate. @autoreleasepool { while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource) ; // do nothing } } } bool sound_mch_play(const char_u* sound_name, long sound_id, soundcb_T *callback, bool playfile) { @autoreleasepool { NSString *sound_name_ns = [[[NSString alloc] initWithUTF8String:(const char*)sound_name] autorelease]; NSSound* sound = playfile ? [[[NSSound alloc] initWithContentsOfFile:sound_name_ns byReference:YES] autorelease] : [NSSound soundNamed:sound_name_ns]; if (!sound) { return false; } if (sounds_list == nil) { sounds_list = [[NSMutableDictionary<NSNumber*, NSSound*> alloc] init]; } sounds_list[[NSNumber numberWithLong:sound_id]] = sound; // Make a delegate to handle when the sound stops. No need to call // autorelease because NSSound only holds a weak reference to it. SoundDelegate *delegate = [[SoundDelegate alloc] init:sound_id callback:callback]; [sound setDelegate:delegate]; [sound play]; } return true; } void sound_mch_stop(long sound_id) { @autoreleasepool { NSSound *sound = sounds_list[[NSNumber numberWithLong:sound_id]]; if (sound != nil) { // Stop the sound. No need to release it because the delegate will do // it for us. [sound stop]; } } } void sound_mch_clear(void) { if (sounds_list != nil) { @autoreleasepool { for (NSSound *sound in [sounds_list allValues]) { [sound stop]; } [sounds_list release]; sounds_list = nil; } } } void sound_mch_free(void) { sound_mch_clear(); } #endif // FEAT_SOUND /* Lift the compiler warning suppression. */ #if defined(__clang__) && defined(__STRICT_ANSI__) # pragma clang diagnostic pop # pragma clang diagnostic pop #endif