mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 01:19:28 +01:00
Revert "JBR-8651 Pycharm Crashing after lock/sleep: SIGABRT at # C [libsystem_kernel.dylib+0x9388] __pthread_kill / __displaycb_handle_block_invoke"
This reverts commit 986d578731.
This commit is contained in:
@@ -741,7 +741,8 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
|
||||
DECLARE_CLASS_RETURN(jc_CPlatformView, "sun/lwawt/macosx/CPlatformView", NULL);
|
||||
DECLARE_FIELD_RETURN(jf_Peer, jc_CPlatformView, "peer", "Lsun/lwawt/LWWindowPeer;", NULL);
|
||||
if ((env == NULL) || (m_cPlatformView == NULL)) {
|
||||
NSAPP_AWT_LOG_MESSAGE(@"Apple AWT: Error AWTView:awtComponent given bad parameters.");
|
||||
NSLog(@"Apple AWT : Error AWTView:awtComponent given bad parameters.");
|
||||
NSLog(@"%@",[NSThread callStackSymbols]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -754,7 +755,8 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
|
||||
DECLARE_CLASS_RETURN(jc_LWWindowPeer, "sun/lwawt/LWWindowPeer", NULL);
|
||||
DECLARE_FIELD_RETURN(jf_Target, jc_LWWindowPeer, "target", "Ljava/awt/Component;", NULL);
|
||||
if (peer == NULL) {
|
||||
NSAPP_AWT_LOG_MESSAGE(@"Apple AWT: Error AWTView:awtComponent got null peer from CPlatformView");
|
||||
NSLog(@"Apple AWT : Error AWTView:awtComponent got null peer from CPlatformView");
|
||||
NSLog(@"%@",[NSThread callStackSymbols]);
|
||||
return NULL;
|
||||
}
|
||||
jobject comp = (*env)->GetObjectField(env, peer, jf_Target);
|
||||
|
||||
@@ -232,9 +232,10 @@ AWT_NS_WINDOW_IMPLEMENTATION
|
||||
};
|
||||
void (*_objc_msgSendSuper)(struct objc_super *, SEL) = (void *)&objc_msgSendSuper; //cast our pointer so the compiler can sort out the ABI
|
||||
(*_objc_msgSendSuper)(&mySuper, @selector(_changeJustMain));
|
||||
} @catch (NSException *exception) {
|
||||
} @catch (NSException *ex) {
|
||||
NSLog(@"WARNING: suppressed exception from _changeJustMain (workaround for JBR-2562)");
|
||||
NSAPP_AWT_LOG_EXCEPTION(exception);
|
||||
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
|
||||
[NSApplicationAWT logException:ex forProcess:processInfo];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1058,9 +1059,10 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
NSRect frame;
|
||||
@try {
|
||||
frame = ConvertNSScreenRect(env, [self.nsWindow frame]);
|
||||
} @catch (NSException *exception) {
|
||||
} @catch (NSException *e) {
|
||||
NSLog(@"WARNING: suppressed exception from ConvertNSScreenRect() in [AWTWindow _deliverMoveResizeEvent]");
|
||||
NSAPP_AWT_LOG_EXCEPTION(exception);
|
||||
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
|
||||
[NSApplicationAWT logException:e forProcess:processInfo];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1394,9 +1396,7 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
jobject target = (*env)->GetObjectField(env, platformWindow, jf_target);
|
||||
if (target) {
|
||||
h = (CGFloat) (*env)->CallFloatMethod(env, target, jm_internalCustomTitleBarHeight);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
} else {
|
||||
if (!(*env)->ExceptionCheck(env)) {
|
||||
self.customTitleBarControlsVisible = (BOOL) (*env)->CallBooleanMethod(env, target, jm_internalCustomTitleBarControlsVisible);
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, target);
|
||||
@@ -1565,8 +1565,8 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
GET_CPLATFORM_WINDOW_CLASS();
|
||||
DECLARE_METHOD(jm_deliverNCMouseDown, jc_CPlatformWindow, "deliverNCMouseDown", "()V");
|
||||
(*env)->CallVoidMethod(env, platformWindow, jm_deliverNCMouseDown);
|
||||
(*env)->DeleteLocalRef(env, platformWindow);
|
||||
CHECK_EXCEPTION();
|
||||
(*env)->DeleteLocalRef(env, platformWindow);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2234,7 +2234,6 @@ JNI_COCOA_ENTER(env);
|
||||
DECLARE_METHOD_RETURN(jm_isIgnoreMouseEvents, jc_Window, "isIgnoreMouseEvents", "()Z", 0);
|
||||
isIgnoreMouseEvents = (*env)->CallBooleanMethod(env, awtWindow, jm_isIgnoreMouseEvents) == JNI_TRUE ? YES : NO;
|
||||
(*env)->DeleteLocalRef(env, awtWindow);
|
||||
CHECK_EXCEPTION();
|
||||
}
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
BOOL isApplicationOwner = NO;
|
||||
if (NSApp != nil) {
|
||||
if ([NSApp isMemberOfClass:[NSApplication class]] && overrideDelegate) shouldInstall = YES;
|
||||
if ([NSApplicationAWT isNSApplicationAWT]) {
|
||||
if ([NSApp isKindOfClass:[NSApplicationAWT class]]) {
|
||||
shouldInstall = YES;
|
||||
isApplicationOwner = YES;
|
||||
}
|
||||
@@ -213,7 +213,7 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
|
||||
// Prep for about and preferences menu
|
||||
BOOL usingDefaultNib = YES;
|
||||
if ([NSApplicationAWT isNSApplicationAWT]) {
|
||||
if ([NSApp isKindOfClass:[NSApplicationAWT class]]) {
|
||||
usingDefaultNib = [NSApp usingDefaultNib];
|
||||
}
|
||||
if (!usingDefaultNib) return self;
|
||||
|
||||
@@ -102,7 +102,6 @@ JNI_COCOA_ENTER(env);
|
||||
// Pass the data to drop target:
|
||||
@try {
|
||||
(*env)->CallVoidMethod(env, jthis, newDataMethod, jformat, jdropdata); // AWT_THREADING Safe (!appKit)
|
||||
CHECK_EXCEPTION();
|
||||
} @catch (NSException *ex) {
|
||||
DLog2(@"[CDropTargetContextPeer startTransfer]: exception in newData() for %d.\n", (NSInteger) jdroptarget);
|
||||
(*env)->DeleteGlobalRef(env, jdropdata);
|
||||
|
||||
@@ -116,7 +116,6 @@ static void displaycb_handle
|
||||
(CGDirectDisplayID displayId, CGDisplayChangeSummaryFlags flags, void *userInfo)
|
||||
{
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
JNI_COCOA_ENTER(env);
|
||||
|
||||
if (TRACE_DISPLAY_CALLBACKS) {
|
||||
@@ -153,6 +152,7 @@ JNI_COCOA_ENTER(env);
|
||||
block:^()
|
||||
{
|
||||
@try {
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
jobject graphicsEnv = (*env)->NewLocalRef(env, cgeRef);
|
||||
if (graphicsEnv == NULL) return; // ref already GC'd
|
||||
DECLARE_CLASS(jc_CGraphicsEnvironment, "sun/awt/CGraphicsEnvironment");
|
||||
@@ -173,6 +173,7 @@ JNI_COCOA_ENTER(env);
|
||||
|
||||
// braces to reduce variable scope
|
||||
{
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
jobject graphicsEnv = (*env)->NewLocalRef(env, cgeRef);
|
||||
if (graphicsEnv == NULL) return; // ref already GC'd
|
||||
DECLARE_CLASS(jc_CGraphicsEnvironment, "sun/awt/CGraphicsEnvironment");
|
||||
|
||||
@@ -223,12 +223,6 @@ void JavaCT_DrawGlyphVector
|
||||
// Using the Quartz Surface Data context, draw a hot-substituted character run
|
||||
void JavaCT_DrawTextUsingQSD(JNIEnv *env, const QuartzSDOps *qsdo, const AWTStrike *strike, const jchar *chars, const jsize length)
|
||||
{
|
||||
NSAttributedString *attribString = nil;
|
||||
CTTypesetterRef typeSetterRef = NULL;
|
||||
CTLineRef lineRef = NULL;
|
||||
|
||||
JNI_COCOA_ENTER(env);
|
||||
|
||||
CGContextRef cgRef = qsdo->cgRef;
|
||||
|
||||
AWTFont *awtFont = strike->fAWTFont;
|
||||
@@ -257,18 +251,20 @@ JNI_COCOA_ENTER(env);
|
||||
|
||||
CTTypesetterRef typeSetterRef = CTTypesetterCreateWithAttributedStringAndOptions((CFAttributedStringRef) attribString, (CFDictionaryRef) ctsDictionaryFor(nsFont, JRSFontStyleUsesFractionalMetrics(strike->fStyle)));
|
||||
*/
|
||||
attribString = [[NSAttributedString alloc]
|
||||
NSAttributedString *attribString = [[NSAttributedString alloc]
|
||||
initWithString:string
|
||||
attributes:ctsDictionaryFor(nsFont, JRSFontStyleUsesFractionalMetrics(strike->fStyle))];
|
||||
|
||||
typeSetterRef = CTTypesetterCreateWithAttributedString((CFAttributedStringRef) attribString);
|
||||
CTTypesetterRef typeSetterRef = CTTypesetterCreateWithAttributedString((CFAttributedStringRef) attribString);
|
||||
|
||||
CFRange range = {0, length};
|
||||
lineRef = CTTypesetterCreateLine(typeSetterRef, range);
|
||||
CTLineRef lineRef = CTTypesetterCreateLine(typeSetterRef, range);
|
||||
|
||||
CTLineDraw(lineRef, cgRef);
|
||||
|
||||
JNI_COCOA_EXIT_WITH_ACTION(env, ( [attribString release], CFRelease_even_NULL(lineRef), CFRelease_even_NULL(typeSetterRef) ) );
|
||||
[attribString release];
|
||||
CFRelease(lineRef);
|
||||
CFRelease(typeSetterRef);
|
||||
}
|
||||
|
||||
|
||||
@@ -284,16 +280,16 @@ static void DrawTextContext
|
||||
return;
|
||||
}
|
||||
|
||||
JNI_COCOA_ENTER(env);
|
||||
|
||||
qsdo->BeginSurface(env, qsdo, SD_Text);
|
||||
if (qsdo->cgRef == NULL)
|
||||
{
|
||||
qsdo->FinishSurface(env, qsdo);
|
||||
return;
|
||||
}
|
||||
|
||||
CGContextRef cgRef = qsdo->cgRef;
|
||||
|
||||
|
||||
CGContextSaveGState(cgRef);
|
||||
JRSFontSetRenderingStyleOnContext(cgRef, strike->fStyle);
|
||||
|
||||
@@ -307,7 +303,7 @@ JNI_COCOA_ENTER(env);
|
||||
|
||||
CGContextRestoreGState(cgRef);
|
||||
|
||||
JNI_COCOA_RENDERER_EXIT(env);
|
||||
qsdo->FinishSurface(env, qsdo);
|
||||
}
|
||||
|
||||
#pragma mark --- Glyph Vector Pipeline ---
|
||||
@@ -532,34 +528,40 @@ static inline void doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc
|
||||
CGSize advances[length];
|
||||
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);
|
||||
}
|
||||
else {
|
||||
CGGlyph *glyphs = NULL;
|
||||
int *uniChars = NULL;
|
||||
CGSize *advances = NULL;
|
||||
@try {
|
||||
// otherwise, we should malloc and free buffers for this large run
|
||||
glyphs = (CGGlyph *)malloc(sizeof(CGGlyph) * length);
|
||||
uniChars = (int *) malloc(sizeof(int) * length);
|
||||
advances = (CGSize *) malloc(sizeof(CGSize) * length);
|
||||
else
|
||||
{
|
||||
// otherwise, we should malloc and free buffers for this large run
|
||||
CGGlyph *glyphs = (CGGlyph *)malloc(sizeof(CGGlyph) * length);
|
||||
int *uniChars = (int *)malloc(sizeof(int) * length);
|
||||
CGSize *advances = (CGSize *)malloc(sizeof(CGSize) * length);
|
||||
|
||||
if ((glyphs == NULL) || (uniChars == NULL) || (advances == NULL)) {
|
||||
[NSException raise:NSMallocException format:@"allocation failure (%s:%d %s)", __FILE__, __LINE__, __FUNCTION__];
|
||||
} else {
|
||||
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);
|
||||
}
|
||||
} @finally {
|
||||
if (glyphs != NULL) {
|
||||
if (glyphs == NULL || uniChars == NULL || advances == NULL)
|
||||
{
|
||||
(*env)->DeleteLocalRef(env, glyphsArray);
|
||||
[NSException raise:NSMallocException format:@"%s-%s:%d", __FILE__, __FUNCTION__, __LINE__];
|
||||
if (glyphs)
|
||||
{
|
||||
free(glyphs);
|
||||
}
|
||||
if (uniChars != NULL) {
|
||||
if (uniChars)
|
||||
{
|
||||
free(uniChars);
|
||||
}
|
||||
if (advances != NULL) {
|
||||
if (advances)
|
||||
{
|
||||
free(advances);
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, glyphsArray);
|
||||
return;
|
||||
}
|
||||
|
||||
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);
|
||||
|
||||
free(glyphs);
|
||||
free(uniChars);
|
||||
free(advances);
|
||||
}
|
||||
|
||||
(*env)->DeleteLocalRef(env, glyphsArray);
|
||||
}
|
||||
|
||||
// Setup and save the state of the CGContext, and apply any java.awt.Font transforms to the context.
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#import <objc/runtime.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <Security/AuthSession.h>
|
||||
#import <ExceptionHandling/NSExceptionHandler.h>
|
||||
|
||||
#import "JNIUtilities.h"
|
||||
#import "LWCToolkit.h"
|
||||
@@ -204,22 +203,19 @@ static BOOL inDoDragDropLoop;
|
||||
}
|
||||
|
||||
- (void)perform {
|
||||
@try {
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
|
||||
DECLARE_CLASS(sjc_Runnable, "java/lang/Runnable");
|
||||
DECLARE_METHOD(jm_Runnable_run, sjc_Runnable, "run", "()V");
|
||||
(*env)->CallVoidMethod(env, self.runnable, jm_Runnable_run);
|
||||
CHECK_EXCEPTION();
|
||||
} @finally {
|
||||
[self release];
|
||||
}
|
||||
JNIEnv* env = [ThreadUtilities getJNIEnvUncached];
|
||||
DECLARE_CLASS(sjc_Runnable, "java/lang/Runnable");
|
||||
DECLARE_METHOD(jm_Runnable_run, sjc_Runnable, "run", "()V");
|
||||
(*env)->CallVoidMethod(env, self.runnable, jm_Runnable_run);
|
||||
CHECK_EXCEPTION();
|
||||
[self release];
|
||||
}
|
||||
@end
|
||||
|
||||
void setBusy(BOOL busy) {
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
JNI_COCOA_ENTER(env);
|
||||
DECLARE_CLASS(jc_AWTAutoShutdown, "sun/awt/AWTAutoShutdown");
|
||||
|
||||
if (busy) {
|
||||
@@ -229,8 +225,7 @@ void setBusy(BOOL busy) {
|
||||
DECLARE_STATIC_METHOD(jm_notifyFreeMethod, jc_AWTAutoShutdown, "notifyToolkitThreadFree", "()V");
|
||||
(*env)->CallStaticVoidMethod(env, jc_AWTAutoShutdown, jm_notifyFreeMethod);
|
||||
}
|
||||
CHECK_EXCEPTION();
|
||||
JNI_COCOA_EXIT(env);
|
||||
CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
static void setUpAWTAppKit(BOOL installObservers)
|
||||
@@ -274,6 +269,7 @@ static void setUpAWTAppKit(BOOL installObservers)
|
||||
DECLARE_STATIC_METHOD(jsm_installToolkitThreadInJava, jc_LWCToolkit, "installToolkitThreadInJava", "()V");
|
||||
(*env)->CallStaticVoidMethod(env, jc_LWCToolkit, jsm_installToolkitThreadInJava);
|
||||
CHECK_EXCEPTION();
|
||||
|
||||
}
|
||||
|
||||
BOOL isSWTInWebStart(JNIEnv* env) {
|
||||
@@ -281,6 +277,11 @@ BOOL isSWTInWebStart(JNIEnv* env) {
|
||||
return [@"true" isCaseInsensitiveLike:swtWebStart];
|
||||
}
|
||||
|
||||
static void AWT_NSUncaughtExceptionHandler(NSException *exception) {
|
||||
NSLog(@"Apple AWT Internal Exception: %@", [exception description]);
|
||||
NSLog(@"trace: %@", [exception callStackSymbols]);
|
||||
}
|
||||
|
||||
@interface AWTStarter : NSObject
|
||||
+ (void)start:(BOOL)headless;
|
||||
+ (void)starter:(BOOL)onMainThread headless:(BOOL)headless;
|
||||
@@ -373,73 +374,70 @@ BOOL isSWTInWebStart(JNIEnv* env) {
|
||||
if (delegate != nil) {
|
||||
OSXAPP_SetApplicationDelegate(delegate);
|
||||
}
|
||||
// Intercept any exception to let NSApplicationAWT handle them:
|
||||
NSExceptionHandler* exceptionHandler = [NSExceptionHandler defaultExceptionHandler];
|
||||
exceptionHandler.exceptionHandlingMask = NSLogAndHandleEveryExceptionMask;
|
||||
[exceptionHandler setDelegate:[NSApplication sharedApplication]];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)starter:(BOOL)wasOnMainThread headless:(BOOL)headless {
|
||||
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||
@try {
|
||||
// Headless mode trumps either ordinary AWT or SWT-in-AWT mode. Declare us a daemon and return.
|
||||
if (headless) {
|
||||
// Note that we don't install run loop observers in headless mode
|
||||
// because we don't need them (see 7174704)
|
||||
if (!forceEmbeddedMode) {
|
||||
setUpAWTAppKit(false);
|
||||
}
|
||||
[AWTStarter markAppAsDaemon];
|
||||
return;
|
||||
// Add the exception handler of last resort
|
||||
NSSetUncaughtExceptionHandler(AWT_NSUncaughtExceptionHandler);
|
||||
|
||||
// Headless mode trumps either ordinary AWT or SWT-in-AWT mode. Declare us a daemon and return.
|
||||
if (headless) {
|
||||
// Note that we don't install run loop observers in headless mode
|
||||
// because we don't need them (see 7174704)
|
||||
if (!forceEmbeddedMode) {
|
||||
setUpAWTAppKit(false);
|
||||
}
|
||||
|
||||
if (forceEmbeddedMode) {
|
||||
AWT_STARTUP_LOG(@"in SWT or SWT/WebStart mode");
|
||||
|
||||
// Init a default NSApplication instance instead of the NSApplicationAWT.
|
||||
// Note that [NSApp isRunning] will return YES after that, though
|
||||
// this behavior isn't specified anywhere. We rely on that.
|
||||
NSApplicationLoad();
|
||||
}
|
||||
|
||||
// This will create a NSApplicationAWT for standalone AWT programs, unless there is
|
||||
// already a NSApplication instance. If there is already a NSApplication instance,
|
||||
// and -[NSApplication isRunning] returns YES, AWT is embedded inside another
|
||||
// AppKit Application.
|
||||
NSApplication *app = [NSApplicationAWT sharedApplication];
|
||||
isEmbedded = ![NSApplicationAWT isNSApplicationAWT];
|
||||
|
||||
if (!isEmbedded) {
|
||||
// Install run loop observers and set the AppKit Java thread name
|
||||
setUpAWTAppKit(true);
|
||||
}
|
||||
|
||||
// AWT gets to this point BEFORE NSApplicationDidFinishLaunchingNotification is sent.
|
||||
if (![app isRunning]) {
|
||||
AWT_STARTUP_LOG(@"+[AWTStarter startAWT]: ![app isRunning]");
|
||||
// This is where the AWT AppKit thread parks itself to process events.
|
||||
[NSApplicationAWT runAWTLoopWithApp:app];
|
||||
} else {
|
||||
// We're either embedded, or showing a splash screen
|
||||
if (isEmbedded) {
|
||||
AWT_STARTUP_LOG(@"running embedded");
|
||||
|
||||
// We don't track if the runloop is busy, so set it free to let AWT finish when it needs
|
||||
setBusy(NO);
|
||||
} else {
|
||||
AWT_STARTUP_LOG(@"running after showing a splash screen");
|
||||
}
|
||||
|
||||
// Signal so that JNI_OnLoad can proceed.
|
||||
if (!wasOnMainThread) [AWTStarter appKitIsRunning:nil];
|
||||
|
||||
// Proceed to exit this call as there is no reason to run the NSApplication event loop.
|
||||
}
|
||||
} @finally {
|
||||
[pool drain];
|
||||
[AWTStarter markAppAsDaemon];
|
||||
return;
|
||||
}
|
||||
|
||||
if (forceEmbeddedMode) {
|
||||
AWT_STARTUP_LOG(@"in SWT or SWT/WebStart mode");
|
||||
|
||||
// Init a default NSApplication instance instead of the NSApplicationAWT.
|
||||
// Note that [NSApp isRunning] will return YES after that, though
|
||||
// this behavior isn't specified anywhere. We rely on that.
|
||||
NSApplicationLoad();
|
||||
}
|
||||
|
||||
// This will create a NSApplicationAWT for standalone AWT programs, unless there is
|
||||
// already a NSApplication instance. If there is already a NSApplication instance,
|
||||
// and -[NSApplication isRunning] returns YES, AWT is embedded inside another
|
||||
// AppKit Application.
|
||||
NSApplication *app = [NSApplicationAWT sharedApplication];
|
||||
isEmbedded = ![NSApp isKindOfClass:[NSApplicationAWT class]];
|
||||
|
||||
if (!isEmbedded) {
|
||||
// Install run loop observers and set the AppKit Java thread name
|
||||
setUpAWTAppKit(true);
|
||||
}
|
||||
|
||||
// AWT gets to this point BEFORE NSApplicationDidFinishLaunchingNotification is sent.
|
||||
if (![app isRunning]) {
|
||||
AWT_STARTUP_LOG(@"+[AWTStarter startAWT]: ![app isRunning]");
|
||||
// This is where the AWT AppKit thread parks itself to process events.
|
||||
[NSApplicationAWT runAWTLoopWithApp: app];
|
||||
} else {
|
||||
// We're either embedded, or showing a splash screen
|
||||
if (isEmbedded) {
|
||||
AWT_STARTUP_LOG(@"running embedded");
|
||||
|
||||
// We don't track if the runloop is busy, so set it free to let AWT finish when it needs
|
||||
setBusy(NO);
|
||||
} else {
|
||||
AWT_STARTUP_LOG(@"running after showing a splash screen");
|
||||
}
|
||||
|
||||
// Signal so that JNI_OnLoad can proceed.
|
||||
if (!wasOnMainThread) [AWTStarter appKitIsRunning:nil];
|
||||
|
||||
// Proceed to exit this call as there is no reason to run the NSApplication event loop.
|
||||
}
|
||||
|
||||
[pool drain];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -454,8 +452,9 @@ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_nativeSyncQueue
|
||||
{
|
||||
long currentEventNum = [AWTToolkit getEventCount];
|
||||
|
||||
NSApplicationAWT* app = [NSApplicationAWT sharedApplicationAWT];
|
||||
if (app != nil) {
|
||||
NSApplication* sharedApp = [NSApplication sharedApplication];
|
||||
if ([sharedApp isKindOfClass:[NSApplicationAWT class]]) {
|
||||
NSApplicationAWT* theApp = (NSApplicationAWT*)sharedApp;
|
||||
// We use two different API to post events to the application,
|
||||
// - [NSApplication postEvent]
|
||||
// - CGEventPost(), see CRobot.m
|
||||
@@ -466,30 +465,25 @@ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_nativeSyncQueue
|
||||
|
||||
// If the native drag is in progress, skip native sync.
|
||||
if (!AWTToolkit.inDoDragDropLoop) {
|
||||
@try {
|
||||
[app postDummyEvent:false];
|
||||
} @finally {
|
||||
[app waitForDummyEvent:timeout / 2.0];
|
||||
}
|
||||
[theApp postDummyEvent:false];
|
||||
[theApp waitForDummyEvent:timeout / 2.0];
|
||||
}
|
||||
// test the condition again as inDoDragDropLoop may have changed?
|
||||
if (!AWTToolkit.inDoDragDropLoop) {
|
||||
@try {
|
||||
[app postDummyEvent:true];
|
||||
} @finally {
|
||||
[app waitForDummyEvent:timeout / 2.0];
|
||||
}
|
||||
[theApp postDummyEvent:true];
|
||||
[theApp waitForDummyEvent:timeout / 2.0];
|
||||
}
|
||||
|
||||
} else {
|
||||
// could happen if we are embedded inside SWT application,
|
||||
// in this case just spin a single empty block through
|
||||
// the event loop to give it a chance to process pending events
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:[ThreadUtilities GetEmptyBlock]];
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){}];
|
||||
}
|
||||
|
||||
if (([AWTToolkit getEventCount] - currentEventNum) != 0) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
@@ -502,7 +496,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_flushNativeSelectors
|
||||
(JNIEnv *env, jclass clz)
|
||||
{
|
||||
JNI_COCOA_ENTER(env);
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:[ThreadUtilities GetEmptyBlock]];
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){}];
|
||||
JNI_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
@@ -899,9 +893,6 @@ JNIEXPORT void JNICALL
|
||||
Java_sun_lwawt_macosx_LWCToolkit_initIDs
|
||||
(JNIEnv *env, jclass klass) {
|
||||
|
||||
// Add the exception handler of last resort:
|
||||
GetAWTUncaughtExceptionHandler();
|
||||
|
||||
JNI_COCOA_ENTER(env);
|
||||
|
||||
gNumberOfButtons = sun_lwawt_macosx_LWCToolkit_BUTTONS;
|
||||
@@ -923,7 +914,8 @@ Java_sun_lwawt_macosx_LWCToolkit_initIDs
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < gNumberOfButtons; i++) {
|
||||
int i;
|
||||
for (i = 0; i < gNumberOfButtons; i++) {
|
||||
gButtonDownMasks[i] = tmp[i];
|
||||
}
|
||||
|
||||
|
||||
@@ -1339,7 +1339,6 @@ static void treeNodeExpandedCollapsedImpl(
|
||||
const jobject cAccessibleGlobal = (*env)->NewGlobalRef(env, cAccessible);
|
||||
|
||||
if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
if (cAccessibleGlobal != NULL) {
|
||||
(*env)->DeleteGlobalRef(env, cAccessibleGlobal);
|
||||
}
|
||||
@@ -1528,7 +1527,7 @@ void nativeAnnounceAppKit(
|
||||
|
||||
JNIEnv* const env = [ThreadUtilities getJNIEnv];
|
||||
if (env == NULL) { // unlikely
|
||||
NSAPP_AWT_LOG_MESSAGE(@"Failed to get JNIEnv instance");
|
||||
NSLog(@"%s: failed to get JNIEnv instance\n%@\n", __func__, [NSThread callStackSymbols]);
|
||||
return; // I believe it's dangerous to go on announcing in that case
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ JNIEXPORT JAWT_DrawingSurfaceInfo* JNICALL awt_DrawingSurface_GetDrawingSurfaceI
|
||||
DECLARE_METHOD_RETURN(jm_getPointer, jc_PlatformComponent, "getPointer", "()J", NULL);
|
||||
AWTSurfaceLayers *surfaceLayers = jlong_to_ptr((*env)->CallLongMethod(env, platformComponent, jm_getPointer));
|
||||
// REMIND: assert(surfaceLayers)
|
||||
CHECK_EXCEPTION();
|
||||
|
||||
dsi->platformInfo = surfaceLayers;
|
||||
dsi->ds = ds;
|
||||
|
||||
@@ -1087,8 +1087,7 @@ extern void initSamplers(id<MTLDevice> device);
|
||||
}
|
||||
|
||||
CVReturn mtlDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* nowTime, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) {
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
|
||||
JNI_COCOA_ENTER(env);
|
||||
JNI_COCOA_ENTER();
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLContext_mtlDisplayLinkCallback: ctx=%p", displayLinkContext);
|
||||
|
||||
MTLDisplayLinkState *dlState = (__bridge MTLDisplayLinkState*) displayLinkContext;
|
||||
@@ -1131,7 +1130,7 @@ CVReturn mtlDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp*
|
||||
|
||||
[ThreadUtilities performOnMainThread:@selector(redraw:) on:mtlc withObject:@(displayID)
|
||||
waitUntilDone:NO useJavaModes:NO]; // critical
|
||||
JNI_COCOA_EXIT(env);
|
||||
JNI_COCOA_EXIT();
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ void
|
||||
MTLGC_DestroyMTLGraphicsConfig(jlong pConfigInfo)
|
||||
{
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLGC_DestroyMTLGraphicsConfig");
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
|
||||
JNI_COCOA_ENTER(env);
|
||||
__block MTLGraphicsConfigInfo *mtlinfo = (MTLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
|
||||
if (mtlinfo == NULL) {
|
||||
|
||||
@@ -569,7 +569,9 @@ Java_sun_java2d_metal_MTLLayer_nativeCreateLayer
|
||||
(JNIEnv *env, jobject obj, jboolean perfCountersEnabled)
|
||||
{
|
||||
__block MTLLayer *layer = nil;
|
||||
JNI_COCOA_ENTER(env);
|
||||
|
||||
JNI_COCOA_ENTER(env);
|
||||
|
||||
jobject javaLayer = (*env)->NewWeakGlobalRef(env, obj);
|
||||
|
||||
// Wait and ensure main thread creates the MTLLayer instance now:
|
||||
@@ -581,7 +583,8 @@ Java_sun_java2d_metal_MTLLayer_nativeCreateLayer
|
||||
if (TRACE_DISPLAY) {
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "MTLLayer_nativeCreateLayer: created layer[%p]", layer);
|
||||
}
|
||||
JNI_COCOA_EXIT(env);
|
||||
JNI_COCOA_EXIT(env);
|
||||
|
||||
return ptr_to_jlong(layer);
|
||||
}
|
||||
|
||||
@@ -590,7 +593,6 @@ JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_metal_MTLLayer_validate
|
||||
(JNIEnv *env, jclass cls, jlong layerPtr, jobject surfaceData)
|
||||
{
|
||||
JNI_COCOA_ENTER(env);
|
||||
MTLLayer *layer = OBJC(layerPtr);
|
||||
|
||||
if (surfaceData != NULL) {
|
||||
@@ -642,7 +644,6 @@ Java_sun_java2d_metal_MTLLayer_validate
|
||||
layer.ctx = NULL;
|
||||
[layer stopRedraw:YES];
|
||||
}
|
||||
JNI_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
@@ -687,6 +688,7 @@ Java_sun_java2d_metal_MTLLayer_blitTexture
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
[layer blitTexture];
|
||||
JNI_COCOA_EXIT(env);
|
||||
}
|
||||
@@ -696,11 +698,13 @@ Java_sun_java2d_metal_MTLLayer_nativeSetOpaque
|
||||
(JNIEnv *env, jclass cls, jlong layerPtr, jboolean opaque)
|
||||
{
|
||||
JNI_COCOA_ENTER(env);
|
||||
|
||||
MTLLayer *layer = jlong_to_ptr(layerPtr);
|
||||
// Ensure main thread changes the MTLLayer instance later:
|
||||
[ThreadUtilities performOnMainThreadWaiting:NO useJavaModes:NO // critical
|
||||
block:^(){
|
||||
[layer setOpaque:(opaque == JNI_TRUE)];
|
||||
}];
|
||||
|
||||
JNI_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ static const char* mtlOpToStr(uint op);
|
||||
BOOL sync = NO; \
|
||||
jint opcode = -1; \
|
||||
const NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; \
|
||||
@try {
|
||||
@try
|
||||
|
||||
/*
|
||||
* Derived from JNI_COCOA_EXIT(env):
|
||||
@@ -70,18 +70,23 @@ static const char* mtlOpToStr(uint op);
|
||||
* If there is a Java exception that has been thrown that should escape.
|
||||
* And ensure we drain the auto-release pool.
|
||||
*/
|
||||
#define RENDER_LOOP_EXIT(env, className) \
|
||||
} @catch (NSException *exception) { \
|
||||
#define RENDER_LOOP_EXIT(env, className) \
|
||||
@catch (NSException *e) { \
|
||||
lwc_plog(env, "%s_flushBuffer: Failed opcode=%s op=%s dstType=%s ctx=%p", \
|
||||
className, mtlOpCodeToStr(opcode), mtlOpToStr(mtlPreviousOp), \
|
||||
mtlDstTypeToStr(DST_TYPE(dstOps)), mtlc); \
|
||||
char* str = [NSString stringWithFormat:@"%@", [e description]].UTF8String; \
|
||||
lwc_plog(env, "%s_flushBuffer Exception: %s", className, str); \
|
||||
str = [NSString stringWithFormat:@"%@", [e callStackSymbols]].UTF8String; \
|
||||
lwc_plog(env, "%s_flushBuffer callstack: %s", className, str); \
|
||||
/* Finally (JetBrains Runtime only) report this message to JVM crash log: */ \
|
||||
JNU_LOG_EVENT(env, "%s_flushBuffer: Failed opcode=%s op=%s dstType=%s ctx=%p", \
|
||||
className, mtlOpCodeToStr(opcode), mtlOpToStr(mtlPreviousOp), \
|
||||
mtlDstTypeToStr(DST_TYPE(dstOps)), mtlc); \
|
||||
/* report exception to the NSApplicationAWT exception handler: */ \
|
||||
NSAPP_AWT_REPORT_EXCEPTION(exception, NO); \
|
||||
} @finally { \
|
||||
/* report fatal failure to make a crash report: */ \
|
||||
JNU_Fatal(env, __FILE__, __LINE__, "flushBuffer failed"); \
|
||||
} \
|
||||
@finally { \
|
||||
/* flush GPU state before draining pool: */ \
|
||||
MTLRenderQueue_reset(mtlc, sync); \
|
||||
[pool drain]; \
|
||||
@@ -172,7 +177,7 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
|
||||
|
||||
// Handle any NSException thrown:
|
||||
RENDER_LOOP_ENTER(env)
|
||||
|
||||
{
|
||||
while (b < end) {
|
||||
opcode = NEXT_INT(b);
|
||||
|
||||
@@ -953,7 +958,7 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
|
||||
return;
|
||||
}
|
||||
} // while op
|
||||
|
||||
}
|
||||
RENDER_LOOP_EXIT(env, "MTLRenderQueue");
|
||||
}
|
||||
|
||||
|
||||
@@ -172,13 +172,8 @@ MTLSD_SetNativeDimensions(JNIEnv *env, BMTLSDOps *mtlsdo,
|
||||
}
|
||||
|
||||
JNU_SetFieldByName(env, NULL, sdObject, "nativeWidth", "I", width);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
} else {
|
||||
if (!((*env)->ExceptionCheck(env))) {
|
||||
JNU_SetFieldByName(env, NULL, sdObject, "nativeHeight", "I", height);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
}
|
||||
}
|
||||
|
||||
(*env)->DeleteLocalRef(env, sdObject);
|
||||
@@ -220,12 +215,8 @@ MTLSD_Delete(JNIEnv *env, BMTLSDOps *bmtlsdo)
|
||||
void
|
||||
MTLSD_Dispose(JNIEnv *env, SurfaceDataOps *ops)
|
||||
{
|
||||
jboolean exc;
|
||||
JNU_CallStaticMethodByName(env, &exc, "sun/java2d/metal/MTLSurfaceData",
|
||||
JNU_CallStaticMethodByName(env, NULL, "sun/java2d/metal/MTLSurfaceData",
|
||||
"dispose", "(J)V", ptr_to_jlong(ops));
|
||||
if (exc) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,18 +28,15 @@
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "ThreadUtilities.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
/* Define to 1 to check for pending exceptions in JNI_COCOA_EXIT */
|
||||
#define CHECK_PENDING_EXCEPTION 0
|
||||
|
||||
/******** LOGGING SUPPORT *********/
|
||||
|
||||
#define LOG_NULL(dst_var, name) \
|
||||
if (dst_var == NULL) { \
|
||||
NSLog(@"Bad JNI lookup %s\n%@", name, [NSThread callStackSymbols]); \
|
||||
NSLog(@"Bad JNI lookup %s\n", name); \
|
||||
NSLog(@"%@",[NSThread callStackSymbols]); \
|
||||
if ([NSThread isMainThread] == NO) { \
|
||||
if (!(*env)->ExceptionCheck(env)) { \
|
||||
JNU_ThrowInternalError(env, "Bad JNI Lookup"); \
|
||||
@@ -189,36 +186,22 @@
|
||||
#define CHECK_EXCEPTION_IN_ENV(env) { \
|
||||
jthrowable exc = (*(env))->ExceptionOccurred(env); \
|
||||
if (exc != NULL) { \
|
||||
if ([NSThread isMainThread]) { \
|
||||
if ([NSThread isMainThread] == YES) { \
|
||||
if (getenv("JNU_APPKIT_TRACE")) { \
|
||||
(*(env))->ExceptionDescribe(env); \
|
||||
NSLog(@"%@", [NSThread callStackSymbols]); \
|
||||
NSLog(@"%@",[NSThread callStackSymbols]); \
|
||||
} else { \
|
||||
(*(env))->ExceptionClear(env); \
|
||||
} \
|
||||
} \
|
||||
(*env)->ExceptionClear(env); \
|
||||
} \
|
||||
if (getenv("JNU_NO_COCOA_EXCEPTION") == NULL) {\
|
||||
[NSException raise:NSGenericException \
|
||||
format:@"%@", ThrowableToNSString(env, exc)]; \
|
||||
} else { \
|
||||
(*(env))->ExceptionClear(env); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
* Use this macro to raise an NSException.
|
||||
* The message is a printf-style format string.
|
||||
* The arguments are the arguments to the format string.
|
||||
*
|
||||
* ONLY FOR DEBUGGING PURPOSES.
|
||||
* for example:
|
||||
* TEST_RAISE_EXCEPTION(@"LWCToolkit.setBusy: busy = %d", busy);
|
||||
*/
|
||||
#define TEST_RAISE_EXCEPTION(message, ...) { \
|
||||
[NSException raise:NSGenericException \
|
||||
format:@"RAISE_EXCEPTION in (%s:%d %s): %@", \
|
||||
__FILE__, __LINE__, __FUNCTION__, \
|
||||
[NSString stringWithFormat:message, ##__VA_ARGS__] \
|
||||
]; \
|
||||
}
|
||||
};
|
||||
|
||||
#define CHECK_EXCEPTION() CHECK_EXCEPTION_IN_ENV(env)
|
||||
|
||||
@@ -226,21 +209,7 @@
|
||||
CHECK_EXCEPTION(); \
|
||||
if ((x) == NULL) { \
|
||||
return y; \
|
||||
}
|
||||
|
||||
#define __JNI_LOG_EXCEPTION(exception) \
|
||||
NSAPP_AWT_LOG_EXCEPTION_PREFIX(exception, @"Apple AWT Cocoa Exception");
|
||||
|
||||
#if (CHECK_PENDING_EXCEPTION == 1)
|
||||
#define __JNI_CHECK_PENDING_EXCEPTION(env) \
|
||||
@try { \
|
||||
CHECK_EXCEPTION_IN_ENV(env); \
|
||||
} @catch (NSException *exception) { \
|
||||
__JNI_LOG_EXCEPTION(exception); \
|
||||
}
|
||||
#else
|
||||
#define __JNI_CHECK_PENDING_EXCEPTION(env) {}
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Create a pool and initiate a try block to catch any exception */
|
||||
#define JNI_COCOA_ENTER(env) \
|
||||
@@ -252,24 +221,28 @@
|
||||
* And ensure we drain the auto-release pool.
|
||||
*/
|
||||
#define JNI_COCOA_EXIT(env) \
|
||||
} @catch (NSException *exception) { \
|
||||
__JNI_LOG_EXCEPTION(exception); \
|
||||
} @finally { \
|
||||
__JNI_CHECK_PENDING_EXCEPTION(env); \
|
||||
} \
|
||||
@catch (NSException *e) { \
|
||||
NSLog(@"Apple AWT Cocoa Exception: %@", [e description]); \
|
||||
NSLog(@"Apple AWT Cocoa Exception callstack: %@", [e callStackSymbols]); \
|
||||
} \
|
||||
@finally { \
|
||||
[pool drain]; \
|
||||
}
|
||||
};
|
||||
|
||||
/* Same as above but adds a clean up action.
|
||||
* Requires that whatever is being cleaned up is in scope.
|
||||
*/
|
||||
#define JNI_COCOA_EXIT_WITH_ACTION(env, action) \
|
||||
} @catch (NSException *exception) { \
|
||||
__JNI_LOG_EXCEPTION(exception); \
|
||||
} \
|
||||
@catch (NSException *e) { \
|
||||
{ action; }; \
|
||||
} @finally { \
|
||||
__JNI_CHECK_PENDING_EXCEPTION(env); \
|
||||
NSLog(@"Apple AWT Cocoa Exception: %@", [e description]); \
|
||||
NSLog(@"Apple AWT Cocoa Exception callstack: %@", [e callStackSymbols]); \
|
||||
} \
|
||||
@finally { \
|
||||
[pool drain]; \
|
||||
}
|
||||
};
|
||||
|
||||
/******** STRING CONVERSION SUPPORT *********/
|
||||
|
||||
|
||||
@@ -115,6 +115,8 @@ jstring NormalizedPathJavaStringFromNSString(JNIEnv* env, NSString *str) {
|
||||
}
|
||||
|
||||
NSString *ThrowableToNSString(JNIEnv *env, jthrowable exc) {
|
||||
(*env)->ExceptionClear(env);
|
||||
|
||||
if (JNU_IsInstanceOfByName(env, exc, "java/lang/OutOfMemoryError")) {
|
||||
static NSString* const OOMEDescr = @"OutOfMemoryError";
|
||||
return OOMEDescr;
|
||||
@@ -126,26 +128,17 @@ NSString *ThrowableToNSString(JNIEnv *env, jthrowable exc) {
|
||||
DECLARE_METHOD_RETURN(jm_getStackTrace, sjc_Throwable, "getStackTrace",
|
||||
"()[Ljava/lang/StackTraceElement;", nil);
|
||||
jobject jstr = (*env)->CallObjectMethod(env, exc, jm_toString);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
}
|
||||
|
||||
NSString* result = JavaStringToNSString(env, jstr);
|
||||
|
||||
jobjectArray frames =
|
||||
(jobjectArray) (*env)->CallObjectMethod(env, exc, jm_getStackTrace);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
}
|
||||
if (frames != NULL) {
|
||||
jsize framesLen = (*env)->GetArrayLength(env, frames);
|
||||
|
||||
for (int i = 0; i < framesLen; i++) {
|
||||
jobject stackElem = (*env)->GetObjectArrayElement(env, frames, i);
|
||||
jobject stackElemStr = (*env)->CallObjectMethod(env, stackElem, jm_toString);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
}
|
||||
NSString *frameStr = JavaStringToNSString(env, stackElemStr);
|
||||
result = [result stringByAppendingFormat:@"\n%@", frameStr];
|
||||
(*env)->DeleteLocalRef(env, stackElem);
|
||||
@@ -157,3 +150,4 @@ NSString *ThrowableToNSString(JNIEnv *env, jthrowable exc) {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,24 +41,7 @@ JNIEXPORT @interface NSApplicationAWT : NSApplication {
|
||||
- (void) waitForDummyEvent:(double) timeout;
|
||||
|
||||
+ (void) runAWTLoopWithApp:(NSApplication*)app;
|
||||
+ (void) interruptAWTLoop;
|
||||
|
||||
+ (BOOL) isNSApplicationAWT;
|
||||
+ (NSApplicationAWT*) sharedApplicationAWT;
|
||||
|
||||
- (void) reportException:(NSException *)exception;
|
||||
- (void) reportException:(NSException *)exception uncaught:(BOOL)uncaught
|
||||
file:(const char*)file line:(int)line function:(const char*)function;
|
||||
|
||||
+ (void) logException:(NSException *)exception;
|
||||
+ (void) logException:(NSException *)exception
|
||||
file:(const char*)file line:(int)line function:(const char*)function;
|
||||
+ (void) logException:(NSException *)exception prefix:(NSString *)prefix
|
||||
file:(const char*)file line:(int)line function:(const char*)function;
|
||||
|
||||
+ (void) logMessage:(NSString *)message;
|
||||
+ (void) logMessage:(NSString *)message
|
||||
file:(const char*)file line:(int)line function:(const char*)function;
|
||||
+ (void)logException:(NSException *)exception forProcess:(NSProcessInfo*)processInfo;
|
||||
|
||||
@end
|
||||
|
||||
@@ -70,3 +53,4 @@ JNIEXPORT @interface NSApplicationAWT : NSApplication {
|
||||
@end
|
||||
|
||||
JNIEXPORT void OSXAPP_SetApplicationDelegate(id <NSApplicationDelegate> delegate);
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#import "NSApplicationAWT.h"
|
||||
|
||||
#import <objc/runtime.h>
|
||||
#import <ExceptionHandling/NSExceptionHandler.h>
|
||||
#import <JavaRuntimeSupport/JavaRuntimeSupport.h>
|
||||
|
||||
#import "PropertiesUtilities.h"
|
||||
@@ -39,17 +38,6 @@
|
||||
*/
|
||||
DEF_STATIC_JNI_OnLoad
|
||||
|
||||
/* may be worth to use system properties ? */
|
||||
#define MAX_RETRY_WRITE_EXCEPTION 3
|
||||
#define MAX_WRITE_EXCEPTION 50
|
||||
#define MAX_LOGGED_EXCEPTION 1000
|
||||
|
||||
#define JBR_ERR_PID_FILE @"%@/jbr_err_pid%d.log"
|
||||
/** JBR file pattern with extra count parameter (see MAX_WRITE_EXCEPTION) */
|
||||
#define JBR_ERR_PID_FILE_COUNT @"%@/jbr_err_pid%d-%02d.log"
|
||||
|
||||
#define NO_FILE_LINE_FUNCTION_ARGS file:nil line:0 function:nil
|
||||
|
||||
static BOOL sUsingDefaultNIB = YES;
|
||||
static NSString *SHARED_FRAMEWORK_BUNDLE = @"/System/Library/Frameworks/JavaVM.framework";
|
||||
static id <NSApplicationDelegate> applicationDelegate = nil;
|
||||
@@ -135,14 +123,9 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
[NSBundle loadNibFile:defaultNibFile externalNameTable: [NSDictionary dictionaryWithObject:self forKey:@"NSOwner"] withZone:nil];
|
||||
|
||||
// Set user defaults to not try to parse application arguments.
|
||||
NSDictionary *defaults = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
(shouldCrashOnException() ? @"YES" : @"NO"), @"NSApplicationCrashOnExceptions",
|
||||
@"NO", @"NSTreatUnknownArgumentsAsOpen",
|
||||
/* fix for JBR-3127 Modal dialogs invoked from modal or floating dialogs are opened in full screen */
|
||||
@"NO", @"NSWindowAllowsImplicitFullScreen",
|
||||
nil];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
|
||||
NSUserDefaults * defs = [NSUserDefaults standardUserDefaults];
|
||||
NSDictionary * noOpenDict = [NSDictionary dictionaryWithObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"];
|
||||
[defs registerDefaults:noOpenDict];
|
||||
|
||||
// Fix up the dock icon now that we are registered with CAS and the Dock.
|
||||
[self setDockIconWithEnv:env];
|
||||
@@ -174,6 +157,9 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
|
||||
[super finishLaunching];
|
||||
|
||||
// fix for JBR-3127 Modal dialogs invoked from modal or floating dialogs are opened in full screen
|
||||
[defs setBool:NO forKey:@"NSWindowAllowsImplicitFullScreen"];
|
||||
|
||||
// temporary possibility to load deprecated NSJavaVirtualMachine (just for testing)
|
||||
// todo: remove when completely tested on BigSur
|
||||
// see https://youtrack.jetbrains.com/issue/JBR-3127#focus=Comments-27-4684465.0-0
|
||||
@@ -333,6 +319,8 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
}
|
||||
|
||||
+ (void) runAWTLoopWithApp:(NSApplication*)app {
|
||||
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||
|
||||
// Define the special Critical RunLoop mode to ensure action executed ASAP:
|
||||
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:[ThreadUtilities criticalRunLoopMode]];
|
||||
|
||||
@@ -340,36 +328,20 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:[ThreadUtilities javaRunLoopMode]];
|
||||
|
||||
do {
|
||||
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||
@try {
|
||||
[app run];
|
||||
} @catch (NSException *exception) {
|
||||
NSLog(@"Apple AWT runAWTLoop Exception: %@\nCallstack: %@",
|
||||
[exception description], [exception callStackSymbols]);
|
||||
} @catch (NSException* e) {
|
||||
NSLog(@"Apple AWT Startup Exception: %@", [e description]);
|
||||
NSLog(@"Apple AWT Startup Exception callstack: %@", [e callStackSymbols]);
|
||||
NSLog(@"Apple AWT Restarting Native Event Thread");
|
||||
|
||||
// interrupt the run loop now:
|
||||
[NSApplicationAWT interruptAWTLoop];
|
||||
} @ finally {
|
||||
[pool drain];
|
||||
[app stop:app];
|
||||
}
|
||||
} while (YES);
|
||||
}
|
||||
|
||||
/*
|
||||
* Thread-safe:
|
||||
* stop the shared application (run loop [NSApplication run])
|
||||
* and restart it
|
||||
*/
|
||||
+ (void) interruptAWTLoop {
|
||||
NSLog(@"Apple AWT Restarting Native Event Thread...");
|
||||
NSApplication *app = [NSApplicationAWT sharedApplication];
|
||||
// mark the current run loop [NSApplication run] to be stopped:
|
||||
[app stop:app];
|
||||
// send event to interrupt the run loop now (after the current event is processed):
|
||||
[app abortModal];
|
||||
[pool drain];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)usingDefaultNib {
|
||||
return sUsingDefaultNIB;
|
||||
}
|
||||
@@ -408,34 +380,27 @@ untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)deqFlag {
|
||||
// NSTimeInterval has microseconds precision
|
||||
#define TS_EQUAL(ts1, ts2) (fabs((ts1) - (ts2)) < 1e-6)
|
||||
|
||||
- (void)sendEvent:(NSEvent *)event {
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
@try {
|
||||
if ([event type] == NSApplicationDefined
|
||||
&& TS_EQUAL([event timestamp], dummyEventTimestamp)
|
||||
&& (short)[event subtype] == NativeSyncQueueEvent
|
||||
&& [event data1] == NativeSyncQueueEvent
|
||||
&& [event data2] == NativeSyncQueueEvent) {
|
||||
[seenDummyEventLock lockWhenCondition:NO];
|
||||
[seenDummyEventLock unlockWithCondition:YES];
|
||||
} else if ([event type] == NSApplicationDefined
|
||||
&& (short)[event subtype] == ExecuteBlockEvent
|
||||
&& [event data1] != 0 && [event data2] == ExecuteBlockEvent) {
|
||||
void (^block)() = (void (^)()) [event data1];
|
||||
block();
|
||||
[block release];
|
||||
} else if ([event type] == NSEventTypeKeyUp && ([event modifierFlags] & NSCommandKeyMask)) {
|
||||
// Cocoa won't send us key up event when releasing a key while Cmd is down,
|
||||
// so we have to do it ourselves.
|
||||
[[self keyWindow] sendEvent:event];
|
||||
} else {
|
||||
[super sendEvent:event];
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
// report exception to the NSApplicationAWT exception handler:
|
||||
NSAPP_AWT_REPORT_EXCEPTION(exception, NO);
|
||||
} @finally {
|
||||
[pool drain];
|
||||
- (void)sendEvent:(NSEvent *)event
|
||||
{
|
||||
if ([event type] == NSApplicationDefined
|
||||
&& TS_EQUAL([event timestamp], dummyEventTimestamp)
|
||||
&& (short)[event subtype] == NativeSyncQueueEvent
|
||||
&& [event data1] == NativeSyncQueueEvent
|
||||
&& [event data2] == NativeSyncQueueEvent) {
|
||||
[seenDummyEventLock lockWhenCondition:NO];
|
||||
[seenDummyEventLock unlockWithCondition:YES];
|
||||
} else if ([event type] == NSApplicationDefined
|
||||
&& (short)[event subtype] == ExecuteBlockEvent
|
||||
&& [event data1] != 0 && [event data2] == ExecuteBlockEvent) {
|
||||
void (^block)() = (void (^)()) [event data1];
|
||||
block();
|
||||
[block release];
|
||||
} else if ([event type] == NSEventTypeKeyUp && ([event modifierFlags] & NSCommandKeyMask)) {
|
||||
// Cocoa won't send us key up event when releasing a key while Cmd is down,
|
||||
// so we have to do it ourselves.
|
||||
[[self keyWindow] sendEvent:event];
|
||||
} else {
|
||||
[super sendEvent:event];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -448,23 +413,19 @@ untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)deqFlag {
|
||||
{
|
||||
void (^copy)() = [block copy];
|
||||
NSInteger encode = (NSInteger) copy;
|
||||
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
@try {
|
||||
NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined
|
||||
location: NSMakePoint(0,0)
|
||||
modifierFlags: 0
|
||||
timestamp: 0
|
||||
windowNumber: 0
|
||||
context: nil
|
||||
subtype: ExecuteBlockEvent
|
||||
data1: encode
|
||||
data2: ExecuteBlockEvent];
|
||||
NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined
|
||||
location: NSMakePoint(0,0)
|
||||
modifierFlags: 0
|
||||
timestamp: 0
|
||||
windowNumber: 0
|
||||
context: nil
|
||||
subtype: ExecuteBlockEvent
|
||||
data1: encode
|
||||
data2: ExecuteBlockEvent];
|
||||
|
||||
[NSApp postEvent: event atStart: NO];
|
||||
} @finally {
|
||||
[pool drain];
|
||||
}
|
||||
[NSApp postEvent: event atStart: NO];
|
||||
[pool drain];
|
||||
}
|
||||
|
||||
- (void)postDummyEvent:(bool)useCocoa {
|
||||
@@ -472,272 +433,86 @@ untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)deqFlag {
|
||||
dummyEventTimestamp = [NSProcessInfo processInfo].systemUptime;
|
||||
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
@try {
|
||||
NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined
|
||||
location: NSMakePoint(0,0)
|
||||
modifierFlags: 0
|
||||
timestamp: dummyEventTimestamp
|
||||
windowNumber: 0
|
||||
context: nil
|
||||
subtype: NativeSyncQueueEvent
|
||||
data1: NativeSyncQueueEvent
|
||||
data2: NativeSyncQueueEvent];
|
||||
if (useCocoa) {
|
||||
[NSApp postEvent:event atStart:NO];
|
||||
} else {
|
||||
ProcessSerialNumber psn;
|
||||
GetCurrentProcess(&psn);
|
||||
CGEventPostToPSN(&psn, [event CGEvent]);
|
||||
}
|
||||
} @finally {
|
||||
[pool drain];
|
||||
NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined
|
||||
location: NSMakePoint(0,0)
|
||||
modifierFlags: 0
|
||||
timestamp: dummyEventTimestamp
|
||||
windowNumber: 0
|
||||
context: nil
|
||||
subtype: NativeSyncQueueEvent
|
||||
data1: NativeSyncQueueEvent
|
||||
data2: NativeSyncQueueEvent];
|
||||
if (useCocoa) {
|
||||
[NSApp postEvent:event atStart:NO];
|
||||
} else {
|
||||
ProcessSerialNumber psn;
|
||||
GetCurrentProcess(&psn);
|
||||
CGEventPostToPSN(&psn, [event CGEvent]);
|
||||
}
|
||||
[pool drain];
|
||||
}
|
||||
|
||||
- (void)waitForDummyEvent:(double)timeout {
|
||||
bool unlock = true;
|
||||
@try {
|
||||
if (timeout >= 0) {
|
||||
double sec = timeout / 1000;
|
||||
unlock = [seenDummyEventLock lockWhenCondition:YES
|
||||
beforeDate:[NSDate dateWithTimeIntervalSinceNow:sec]];
|
||||
} else {
|
||||
[seenDummyEventLock lockWhenCondition:YES];
|
||||
}
|
||||
if (unlock) {
|
||||
[seenDummyEventLock unlock];
|
||||
}
|
||||
} @finally {
|
||||
[seenDummyEventLock release];
|
||||
seenDummyEventLock = nil;
|
||||
if (timeout >= 0) {
|
||||
double sec = timeout / 1000;
|
||||
unlock = [seenDummyEventLock lockWhenCondition:YES
|
||||
beforeDate:[NSDate dateWithTimeIntervalSinceNow:sec]];
|
||||
} else {
|
||||
[seenDummyEventLock lockWhenCondition:YES];
|
||||
}
|
||||
}
|
||||
|
||||
// Provide helper methods to get the shared NSApplicationAWT instance
|
||||
+ (BOOL) isNSApplicationAWT {
|
||||
return [NSApp isKindOfClass:[NSApplicationAWT class]];
|
||||
}
|
||||
|
||||
+ (NSApplicationAWT*) sharedApplicationAWT {
|
||||
return [NSApplicationAWT isNSApplicationAWT] ? (NSApplicationAWT*)[NSApplication sharedApplication] : nil;
|
||||
}
|
||||
|
||||
// Provide info from unhandled ObjectiveC exceptions
|
||||
|
||||
/*
|
||||
* Handle all exceptions handled by NSApplication.
|
||||
*
|
||||
* Note: depending on the userDefaults.NSApplicationCrashOnExceptions (YES/ NO) flag,
|
||||
* (set in finishLaunching), calling with crash or not the JVM.
|
||||
*/
|
||||
- (void) reportException:(NSException *)exception {
|
||||
[self reportException:exception uncaught:NO NO_FILE_LINE_FUNCTION_ARGS];
|
||||
}
|
||||
|
||||
- (void) _crashOnException:(NSException *)exception {
|
||||
[self crashOnException:exception uncaught:NO withEnv:[ThreadUtilities getJNIEnvUncached] NO_FILE_LINE_FUNCTION_ARGS];
|
||||
}
|
||||
|
||||
// implementation (internals)
|
||||
- (void) reportException:(NSException *)exception uncaught:(BOOL)uncaught
|
||||
file:(const char*)file line:(int)line function:(const char*)function
|
||||
{
|
||||
@autoreleasepool {
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
|
||||
if (shouldCrashOnException()) {
|
||||
// calling [super reportException:exception] will cause a crash
|
||||
// so _crashOnException:exception will be then called but losing details.
|
||||
// Use the direct approach (full details):
|
||||
[self crashOnException:exception uncaught:uncaught withEnv:env
|
||||
file:file line:line function:function];
|
||||
} else {
|
||||
NSMutableString *info = [[[NSMutableString alloc] init] autorelease];
|
||||
[NSApplicationAWT logException:exception uncaught:uncaught forProcess:[NSProcessInfo processInfo]
|
||||
withEnv:env prefix:@"Reported " to:info file:file line:line function:function];
|
||||
|
||||
// interrupt the run loop now:
|
||||
[NSApplicationAWT interruptAWTLoop];
|
||||
}
|
||||
if (unlock) {
|
||||
[seenDummyEventLock unlock];
|
||||
}
|
||||
[seenDummyEventLock release];
|
||||
|
||||
seenDummyEventLock = nil;
|
||||
}
|
||||
|
||||
- (void) crashOnException:(NSException *)exception uncaught:(BOOL)uncaught withEnv:(JNIEnv *)env
|
||||
file:(const char*)file line:(int)line function:(const char*)function
|
||||
{
|
||||
//Provide info from unhandled ObjectiveC exceptions
|
||||
+ (void)logException:(NSException *)exception forProcess:(NSProcessInfo*)processInfo {
|
||||
@autoreleasepool {
|
||||
NSMutableString *info = [[[NSMutableString alloc] init] autorelease];
|
||||
[NSApplicationAWT logException:exception uncaught:uncaught forProcess:[NSProcessInfo processInfo]
|
||||
withEnv:env prefix:@"Crash: " to:info file:file line:line function:function];
|
||||
[info appendString:
|
||||
[NSString stringWithFormat:
|
||||
@"Exception in NSApplicationAWT:\n %@\n",
|
||||
exception]];
|
||||
|
||||
if (shouldCrashOnException()) {
|
||||
// Use JNU_Fatal macro to trigger JVM fatal error with the esception information and generate hs_err_ file
|
||||
JNU_Fatal(env, __FILE__, __LINE__, [info UTF8String]); \
|
||||
}
|
||||
}
|
||||
}
|
||||
NSArray<NSString *> *stack = [exception callStackSymbols];
|
||||
|
||||
// log exception methods
|
||||
+ (void) logException:(NSException *)exception {
|
||||
[NSApplicationAWT logException:exception NO_FILE_LINE_FUNCTION_ARGS];
|
||||
}
|
||||
|
||||
+ (void) logException:(NSException *)exception
|
||||
file:(const char*)file line:(int)line function:(const char*)function
|
||||
{
|
||||
[NSApplicationAWT logException:exception prefix:@"Log: "
|
||||
file:file line:line function:function];
|
||||
}
|
||||
|
||||
+ (void) logException:(NSException *)exception prefix:(NSString *)prefix
|
||||
file:(const char*)file line:(int)line function:(const char*)function
|
||||
{
|
||||
@autoreleasepool {
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
|
||||
NSMutableString *info = [[[NSMutableString alloc] init] autorelease];
|
||||
[NSApplicationAWT logException:exception uncaught:NO forProcess:[NSProcessInfo processInfo]
|
||||
withEnv:env prefix:prefix to:info
|
||||
file:file line:line function:function];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void) logException:(NSException *)exception uncaught:(BOOL)uncaught forProcess:(NSProcessInfo *)processInfo
|
||||
withEnv:(JNIEnv *)env prefix:(NSString *)prefix to:(NSMutableString *)info
|
||||
file:(const char*)file line:(int)line function:(const char*)function
|
||||
{
|
||||
static int loggedException = 0;
|
||||
static int writtenException = 0;
|
||||
|
||||
if (loggedException < MAX_LOGGED_EXCEPTION) {
|
||||
[NSApplicationAWT toString:exception uncaught:uncaught prefix:prefix to:info
|
||||
file:file line:line function:function];
|
||||
|
||||
[NSApplicationAWT logMessage:info withEnv:env];
|
||||
|
||||
if (++loggedException == MAX_LOGGED_EXCEPTION) {
|
||||
NSLog(@"Stop logging follow-up exceptions (max %d logged exceptions reached)",
|
||||
MAX_LOGGED_EXCEPTION);
|
||||
for (NSUInteger i = 0; i < stack.count; i++) {
|
||||
[info appendString:stack[i]];
|
||||
[info appendString:@"\n"];
|
||||
}
|
||||
|
||||
if (writtenException < MAX_WRITE_EXCEPTION) {
|
||||
const NSString *homePath = [processInfo environment][@"HOME"];
|
||||
if (homePath != nil) {
|
||||
const int processID = [processInfo processIdentifier];
|
||||
const NSString *fileName = [NSString stringWithFormat:JBR_ERR_PID_FILE, homePath, processID];
|
||||
NSLog(@"%@", info);
|
||||
|
||||
BOOL available = NO;
|
||||
int retry = 0;
|
||||
NSString *realFileName = nil;
|
||||
int count = 0;
|
||||
do {
|
||||
realFileName = (count == 0) ? fileName :
|
||||
[NSString stringWithFormat:JBR_ERR_PID_FILE_COUNT, homePath, processID, count];
|
||||
int processID = [processInfo processIdentifier];
|
||||
NSDictionary *env = [[NSProcessInfo processInfo] environment];
|
||||
NSString *homePath = env[@"HOME"];
|
||||
if (homePath != nil) {
|
||||
NSString *fileName =
|
||||
[NSString stringWithFormat:@"%@/jbr_err_pid%d.log",
|
||||
homePath, processID];
|
||||
|
||||
available = ![[NSFileManager defaultManager] fileExistsAtPath:realFileName];
|
||||
|
||||
if (available) {
|
||||
NSLog(@"Writing exception to '%@'...", realFileName);
|
||||
// write the exception atomatically to the file:
|
||||
if ([info writeToFile:realFileName
|
||||
atomically:YES
|
||||
encoding:NSUTF8StringEncoding
|
||||
error:NULL])
|
||||
{
|
||||
if (++writtenException == MAX_WRITE_EXCEPTION) {
|
||||
NSLog(@"Stop writing follow-up exceptions (max %d written exceptions reached)",
|
||||
MAX_WRITE_EXCEPTION);
|
||||
}
|
||||
} else {
|
||||
if (++retry >= MAX_RETRY_WRITE_EXCEPTION) {
|
||||
NSLog(@"Failed to write exception to '%@' after %d retries", realFileName,
|
||||
MAX_RETRY_WRITE_EXCEPTION);
|
||||
break;
|
||||
}
|
||||
// retry few times:
|
||||
available = NO;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
} while (!available);
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:fileName]) {
|
||||
[info writeToFile:fileName
|
||||
atomically:YES
|
||||
encoding:NSUTF8StringEncoding
|
||||
error:NULL];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ (void) logMessage:(NSString *)message {
|
||||
[NSApplicationAWT logMessage:message NO_FILE_LINE_FUNCTION_ARGS];
|
||||
- (void)_crashOnException:(NSException *)exception {
|
||||
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
|
||||
[NSApplicationAWT logException:exception
|
||||
forProcess:processInfo];
|
||||
// Use SIGILL to generate hs_err_ file as well
|
||||
kill([processInfo processIdentifier], SIGILL);
|
||||
}
|
||||
|
||||
+ (void) logMessage:(NSString *)message
|
||||
file:(const char*)file line:(int)line function:(const char*)function
|
||||
{
|
||||
@autoreleasepool {
|
||||
[NSApplicationAWT logMessage:message
|
||||
callStackSymbols:[NSThread callStackSymbols]
|
||||
withEnv:[ThreadUtilities getJNIEnvUncached]
|
||||
file:file line:line function:function];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void) logMessage:(NSString *)message callStackSymbols:(NSArray<NSString *> *)callStackSymbols withEnv:(JNIEnv *)env
|
||||
file:(const char*)file line:(int)line function:(const char*)function
|
||||
{
|
||||
NSMutableString *info = [[[NSMutableString alloc] init] autorelease];
|
||||
[NSApplicationAWT toString:message callStackSymbols:callStackSymbols to:info
|
||||
file:file line:line function:function];
|
||||
|
||||
[NSApplicationAWT logMessage:info withEnv:env];
|
||||
}
|
||||
|
||||
+ (void) logMessage:(NSString *)info withEnv:(JNIEnv *)env {
|
||||
// Always log to the console first:
|
||||
NSLog(@"%@", info);
|
||||
// Send to PlatformLogger too:
|
||||
lwc_plog(env, "%s", info.UTF8String);
|
||||
}
|
||||
|
||||
+ (void) toString:(NSException *)exception uncaught:(BOOL)uncaught prefix:(NSString *)prefix to:(NSMutableString *)info
|
||||
file:(const char*)file line:(int)line function:(const char*)function
|
||||
{
|
||||
const char* uncaughtMark = (uncaught) ? "Uncaught " : "";
|
||||
|
||||
NSString *header = (file != nil) ?
|
||||
[NSString stringWithFormat: @"%@%sException (%s:%d %s):\n%@\n", prefix, uncaughtMark, file, line, function, exception]
|
||||
: [NSString stringWithFormat: @"%@%sException (unknown):\n%@\n", prefix, uncaughtMark, exception];
|
||||
[info appendString:header];
|
||||
|
||||
[NSApplicationAWT toString:[exception callStackSymbols] to:info];
|
||||
}
|
||||
|
||||
+ (void) toString:(NSString *)message callStackSymbols:(NSArray<NSString *> *)callStackSymbols to:(NSMutableString *)info
|
||||
file:(const char*)file line:(int)line function:(const char*)function
|
||||
{
|
||||
NSString *header = (file != nil) ?
|
||||
[NSString stringWithFormat: @"%@ (%s:%d %s):\n", message, file, line, function]
|
||||
: [NSString stringWithFormat: @"%@ (unknown):\n", message];
|
||||
[info appendString:header];
|
||||
|
||||
[NSApplicationAWT toString:callStackSymbols to:info];
|
||||
}
|
||||
|
||||
+ (void) toString:(NSArray<NSString *> *)callStackSymbols to:(NSMutableString *)info
|
||||
{
|
||||
for (NSUInteger i = 0; i < callStackSymbols.count; i++) {
|
||||
[info appendFormat:@" %@\n", callStackSymbols[i]];
|
||||
}
|
||||
}
|
||||
|
||||
// --- NSExceptionHandlerDelegate category to handle all exceptions ---
|
||||
- (BOOL) exceptionHandler:(NSExceptionHandler *)sender
|
||||
shouldHandleException:(NSException *)exception mask:(NSUInteger)aMask {
|
||||
/* handle all exception types to invoke reportException:exception */
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL) exceptionHandler:(NSExceptionHandler *)sender
|
||||
shouldLogException:(NSException *)exception mask:(NSUInteger)aMask {
|
||||
/* disable default logging (stderr) */
|
||||
return NO;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@@ -130,30 +130,6 @@ do { \
|
||||
/* bit flag to coalesce CGDisplayReconfigureCallbacks */
|
||||
#define MAIN_CALLBACK_CGDISPLAY_RECONFIGURE 1
|
||||
|
||||
/* log given message (with thread call stack) */
|
||||
#define NSAPP_AWT_LOG_MESSAGE(message) \
|
||||
[ThreadUtilities logMessage:message file:__FILE__ line:__LINE__ function:__FUNCTION__]
|
||||
|
||||
/* log given exception (ignored or explicitely muted) */
|
||||
#define NSAPP_AWT_LOG_EXCEPTION(exception) \
|
||||
[ThreadUtilities logException:exception file:__FILE__ line:__LINE__ function:__FUNCTION__]
|
||||
|
||||
#define NSAPP_AWT_LOG_EXCEPTION_PREFIX(exception, prefixValue) \
|
||||
[ThreadUtilities logException:exception prefix:prefixValue file:__FILE__ line:__LINE__ function:__FUNCTION__]
|
||||
|
||||
/* report the given exception (ignored or explicitely muted), may crash the JVM (JNU_Fatal) */
|
||||
#define NSAPP_AWT_REPORT_EXCEPTION(exception, uncaughtFlag) \
|
||||
[ThreadUtilities reportException:exception uncaught:uncaughtFlag file:__FILE__ line:__LINE__ function:__FUNCTION__]
|
||||
|
||||
/* CFRelease wrapper that ignores NULL argument */
|
||||
JNIEXPORT void CFRelease_even_NULL(CFTypeRef cf);
|
||||
|
||||
/* Return true if uncaught exceptions should crash JVM (JNU_Fatal) */
|
||||
BOOL shouldCrashOnException();
|
||||
|
||||
/* Get AWT's NSUncaughtExceptionHandler */
|
||||
JNIEXPORT NSUncaughtExceptionHandler* GetAWTUncaughtExceptionHandler(void);
|
||||
|
||||
@interface RunLoopCallbackQueue : NSObject
|
||||
|
||||
@property(readwrite, atomic) u_long coalesingflags;
|
||||
@@ -204,25 +180,8 @@ __attribute__((visibility("default")))
|
||||
*/
|
||||
@property (class, nonatomic, readonly) BOOL blockingEventDispatchThread;
|
||||
|
||||
+ (void (^)()) GetEmptyBlock;
|
||||
|
||||
+ (void) reportException:(NSException *)exception;
|
||||
+ (void) reportException:(NSException *)exception uncaught:(BOOL)uncaught
|
||||
file:(const char*)file line:(int)line function:(const char*)function;
|
||||
|
||||
+ (void) logException:(NSException *)exception;
|
||||
+ (void) logException:(NSException *)exception
|
||||
file:(const char*)file line:(int)line function:(const char*)function;
|
||||
+ (void) logException:(NSException *)exception prefix:(NSString *)prefix
|
||||
file:(const char*)file line:(int)line function:(const char*)function;
|
||||
|
||||
+ (void) logMessage:(NSString *)message;
|
||||
+ (void) logMessage:(NSString *)message
|
||||
file:(const char*)file line:(int)line function:(const char*)function;
|
||||
|
||||
+ (JNIEnv*)getJNIEnv;
|
||||
+ (JNIEnv*)getJNIEnvUncached;
|
||||
|
||||
+ (void)detachCurrentThread;
|
||||
+ (void)setAppkitThreadGroup:(jobject)group;
|
||||
+ (void)setApplicationOwner:(BOOL)owner;
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#import "JNIUtilities.h"
|
||||
#import "PropertiesUtilities.h"
|
||||
#import "ThreadUtilities.h"
|
||||
#import "NSApplicationAWT.h"
|
||||
|
||||
|
||||
#define RUN_BLOCK_IF(COND, block) \
|
||||
@@ -41,45 +40,6 @@
|
||||
/* See LWCToolkit.APPKIT_THREAD_NAME */
|
||||
#define MAIN_THREAD_NAME "AppKit Thread"
|
||||
|
||||
void CFRelease_even_NULL(CFTypeRef cf) {
|
||||
if (cf != NULL) {
|
||||
CFRelease(cf);
|
||||
}
|
||||
}
|
||||
|
||||
// Global CrashOnException handling flags used by:
|
||||
// - UncaughtExceptionHandler
|
||||
// - NSApplicationAWT _crashOnException:(NSException *)exception
|
||||
static BOOL isAWTCrashOnException() {
|
||||
static int awtCrashOnException = -1;
|
||||
if (awtCrashOnException == -1) {
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
|
||||
if (env == NULL) return NO;
|
||||
NSString* awtCrashOnExceptionProp = [PropertiesUtilities javaSystemPropertyForKey:@"apple.awt.crashOnException"
|
||||
withEnv:env];
|
||||
awtCrashOnException = [@"true" isCaseInsensitiveLike:awtCrashOnExceptionProp] ? YES : NO;
|
||||
}
|
||||
return (BOOL)awtCrashOnException;
|
||||
}
|
||||
|
||||
BOOL shouldCrashOnException() {
|
||||
static int crashOnException = -1;
|
||||
if (crashOnException == -1) {
|
||||
BOOL shouldCrashOnException = NO;
|
||||
#if defined(DEBUG)
|
||||
shouldCrashOnException = YES;
|
||||
#endif
|
||||
if (!shouldCrashOnException) {
|
||||
shouldCrashOnException = isAWTCrashOnException();
|
||||
}
|
||||
crashOnException = shouldCrashOnException;
|
||||
if (crashOnException) {
|
||||
NSLog(@"WARNING: shouldCrashOnException ENABLED");
|
||||
}
|
||||
}
|
||||
return (BOOL)crashOnException;
|
||||
}
|
||||
|
||||
/* Returns the MainThread latency threshold in milliseconds
|
||||
* used to detect slow operations that may cause high latencies or delays.
|
||||
* If negative, the MainThread monitor is disabled */
|
||||
@@ -129,24 +89,6 @@ static const int TRACE_BLOCKING_FLAGS = 0;
|
||||
/* RunLoop traceability identifier generators */
|
||||
static atomic_long mainThreadActionId = 0L;
|
||||
|
||||
// --- AWT's NSUncaughtExceptionHandler ---
|
||||
static void AWT_NSUncaughtExceptionHandler(NSException *exception) {
|
||||
// report exception to the NSApplicationAWT exception handler:
|
||||
NSAPP_AWT_REPORT_EXCEPTION(exception, YES);
|
||||
}
|
||||
|
||||
/* Get AWT's NSUncaughtExceptionHandler */
|
||||
NSUncaughtExceptionHandler* GetAWTUncaughtExceptionHandler(void) {
|
||||
static NSUncaughtExceptionHandler* _awtUncaughtExceptionHandler;
|
||||
static dispatch_once_t oncePredicate;
|
||||
|
||||
dispatch_once(&oncePredicate, ^{
|
||||
_awtUncaughtExceptionHandler = AWT_NSUncaughtExceptionHandler;
|
||||
NSSetUncaughtExceptionHandler(_awtUncaughtExceptionHandler);
|
||||
});
|
||||
return _awtUncaughtExceptionHandler;
|
||||
}
|
||||
|
||||
static inline void doLog(JNIEnv* env, const char *formatMsg, ...) {
|
||||
if (enableTracingNSLog) {
|
||||
va_list args;
|
||||
@@ -189,78 +131,6 @@ static long eventDispatchThreadPtr = (long)nil;
|
||||
static BOOL _blockingEventDispatchThread = NO;
|
||||
static BOOL _blockingMainThread = NO;
|
||||
|
||||
// Empty block optimization using 1 single instance and avoid Block_copy macro
|
||||
|
||||
+ (void (^)()) GetEmptyBlock {
|
||||
static id _emptyBlock = nil;
|
||||
if (_emptyBlock == nil) {
|
||||
_emptyBlock = ^(){};
|
||||
}
|
||||
return _emptyBlock;
|
||||
}
|
||||
|
||||
+ (BOOL) IsEmptyBlock:(void (^)())block {
|
||||
return (block == [ThreadUtilities GetEmptyBlock]);
|
||||
}
|
||||
|
||||
#define Custom_Block_copy(block) ( ([ThreadUtilities IsEmptyBlock:block]) ? block : Block_copy(block) )
|
||||
|
||||
/*
|
||||
* When running a block where either we don't wait, or it needs to run on another thread
|
||||
* we need to copy it from stack to heap, use the copy in the call and release after use.
|
||||
* Do this only when we must because it could be expensive.
|
||||
* Note : if waiting cross-thread, possibly the stack allocated copy is accessible ?
|
||||
*/
|
||||
+ (void)invokeBlockCopy:(void (^)(void))blockCopy {
|
||||
if (![ThreadUtilities IsEmptyBlock:blockCopy]) {
|
||||
@try {
|
||||
blockCopy();
|
||||
} @finally {
|
||||
Block_release(blockCopy);
|
||||
#if (CHECK_PENDING_EXCEPTION == 1)
|
||||
__JNI_CHECK_PENDING_EXCEPTION([ThreadUtilities getJNIEnvUncached]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Exception handling bridge
|
||||
+ (void) reportException:(NSException *)exception {
|
||||
[[NSApplicationAWT sharedApplicationAWT] reportException:exception];
|
||||
}
|
||||
|
||||
+ (void) reportException:(NSException *)exception uncaught:(BOOL)uncaught
|
||||
file:(const char*)file line:(int)line function:(const char*)function
|
||||
{
|
||||
[[NSApplicationAWT sharedApplicationAWT] reportException:exception uncaught:uncaught file:file line:line function:function];
|
||||
}
|
||||
|
||||
+ (void) logException:(NSException *)exception {
|
||||
[NSApplicationAWT logException:exception];
|
||||
}
|
||||
|
||||
+ (void) logException:(NSException *)exception
|
||||
file:(const char*)file line:(int)line function:(const char*)function
|
||||
{
|
||||
[NSApplicationAWT logException:exception file:file line:line function:function];
|
||||
}
|
||||
|
||||
+ (void) logException:(NSException *)exception prefix:(NSString *)prefix
|
||||
file:(const char*)file line:(int)line function:(const char*)function
|
||||
{
|
||||
[NSApplicationAWT logException:exception prefix:prefix file:file line:line function:function];
|
||||
}
|
||||
|
||||
+ (void) logMessage:(NSString *)message {
|
||||
[NSApplicationAWT logMessage:message];
|
||||
}
|
||||
|
||||
+ (void) logMessage:(NSString *)message
|
||||
file:(const char*)file line:(int)line function:(const char*)function
|
||||
{
|
||||
[NSApplicationAWT logMessage:message file:file line:line function:function];
|
||||
}
|
||||
|
||||
static BOOL isEventDispatchThread() {
|
||||
return (long)[NSThread currentThread] == eventDispatchThreadPtr;
|
||||
}
|
||||
@@ -325,13 +195,9 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
}
|
||||
|
||||
+ (JNIEnv*)getJNIEnvUncached {
|
||||
if ([NSThread isMainThread] && (appKitEnv != NULL)) {
|
||||
return appKitEnv;
|
||||
} else {
|
||||
JNIEnv *env = NULL;
|
||||
attachCurrentThread((void **)&env);
|
||||
return env;
|
||||
}
|
||||
JNIEnv *env = NULL;
|
||||
attachCurrentThread((void **)&env);
|
||||
return env;
|
||||
}
|
||||
|
||||
+ (void)detachCurrentThread {
|
||||
@@ -379,7 +245,17 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
[ThreadUtilities resetTraceContext];
|
||||
}
|
||||
}
|
||||
doLog([ThreadUtilities getJNIEnvUncached], "setAppkitThreadGroup: exit");
|
||||
}
|
||||
|
||||
/*
|
||||
* When running a block where either we don't wait, or it needs to run on another thread
|
||||
* we need to copy it from stack to heap, use the copy in the call and release after use.
|
||||
* Do this only when we must because it could be expensive.
|
||||
* Note : if waiting cross-thread, possibly the stack allocated copy is accessible ?
|
||||
*/
|
||||
+ (void)invokeBlockCopy:(void (^)(void))blockCopy {
|
||||
blockCopy();
|
||||
Block_release(blockCopy);
|
||||
}
|
||||
|
||||
+ (NSString*)getCaller:(NSString*)prefixSymbol {
|
||||
@@ -423,7 +299,7 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
{
|
||||
RUN_BLOCK_IF([NSThread isMainThread], block);
|
||||
|
||||
[ThreadUtilities performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:Custom_Block_copy(block)
|
||||
[ThreadUtilities performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:Block_copy(block)
|
||||
waitUntilDone:NO useJavaModes:useJavaModes];
|
||||
}
|
||||
|
||||
@@ -445,7 +321,7 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
{
|
||||
RUN_BLOCK_IF([NSThread isMainThread] && wait, block);
|
||||
|
||||
[ThreadUtilities performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:Custom_Block_copy(block)
|
||||
[ThreadUtilities performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:Block_copy(block)
|
||||
waitUntilDone:wait useJavaModes:useJavaModes];
|
||||
}
|
||||
|
||||
@@ -815,7 +691,7 @@ JNIEXPORT void lwc_plog(JNIEnv* env, const char *formatMsg, ...) {
|
||||
if (midWarn != NULL) {
|
||||
va_list args;
|
||||
va_start(args, formatMsg);
|
||||
/* formatted message can be large (stack trace) => 16 kb buffer size */
|
||||
/* formatted message can be large (stack trace ?) => 16 kb */
|
||||
const int bufSize = 16 * 1024;
|
||||
char buf[bufSize];
|
||||
#pragma clang diagnostic push
|
||||
@@ -824,29 +700,17 @@ JNIEXPORT void lwc_plog(JNIEnv* env, const char *formatMsg, ...) {
|
||||
#pragma clang diagnostic pop
|
||||
va_end(args);
|
||||
|
||||
BOOL logged = NO;
|
||||
const jstring javaString = (*env)->NewStringUTF(env, buf);
|
||||
|
||||
if ((javaString != NULL) && (*env)->ExceptionCheck(env) == JNI_FALSE) {
|
||||
// call PlatformLogger.warning(javaString):
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
// fallback:
|
||||
NSLog(@"%s\n", buf); \
|
||||
} else {
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
(*env)->CallVoidMethod(env, loggerObject, midWarn, javaString);
|
||||
|
||||
// derived from CHECK_EXCEPTION but NO NSException raised:
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
// fallback:
|
||||
(*(env))->ExceptionDescribe(env);
|
||||
// note: [NSApplicationAWT logMessage:message] is not used
|
||||
// to avoid reentrancy issues.
|
||||
NSLog(@"%@", [NSThread callStackSymbols]);
|
||||
} else {
|
||||
logged = YES;
|
||||
}
|
||||
CHECK_EXCEPTION();
|
||||
return;
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, javaString);
|
||||
if (!logged) {
|
||||
// fallback:
|
||||
NSLog(@"%s\n", buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -915,22 +779,10 @@ JNIEXPORT void lwc_plog(JNIEnv* env, const char *formatMsg, ...) {
|
||||
- (void)processQueuedCallbacks {
|
||||
const NSUInteger count = [self.queue count];
|
||||
if (count != 0) {
|
||||
#if (CHECK_PENDING_EXCEPTION == 1)
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
#endif
|
||||
for (NSUInteger i = 0; i < count; i++) {
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
@try {
|
||||
void (^blockCopy)(void) = (void (^)()) [self.queue objectAtIndex:i];
|
||||
// invoke callback:
|
||||
[ThreadUtilities invokeBlockCopy:blockCopy];
|
||||
} @catch (NSException *exception) {
|
||||
// report exception to the NSApplicationAWT exception handler:
|
||||
NSAPP_AWT_REPORT_EXCEPTION(exception, NO);
|
||||
} @finally {
|
||||
__JNI_CHECK_PENDING_EXCEPTION(env);
|
||||
[pool drain];
|
||||
}
|
||||
void (^blockCopy)(void) = (void (^)())[self.queue objectAtIndex: i];
|
||||
// invoke callback:
|
||||
[ThreadUtilities invokeBlockCopy:blockCopy];
|
||||
}
|
||||
// reset queue anyway:
|
||||
[self reset];
|
||||
|
||||
Reference in New Issue
Block a user