LCOV - code coverage report
Current view: top level - Core/Debug - OODebugMonitor.m (source / functions) Hit Total Coverage
Test: coverxygen.info Lines: 0 36 0.0 %
Date: 2025-05-28 07:50:54 Functions: 0 0 -

          Line data    Source code
       1           0 : /*
       2             : 
       3             : OODebugMonitor.m
       4             : 
       5             : 
       6             : Oolite debug support
       7             : 
       8             : Copyright (C) 2007-2013 Jens Ayton
       9             : 
      10             : Permission is hereby granted, free of charge, to any person obtaining a copy
      11             : of this software and associated documentation files (the "Software"), to deal
      12             : in the Software without restriction, including without limitation the rights
      13             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      14             : copies of the Software, and to permit persons to whom the Software is
      15             : furnished to do so, subject to the following conditions:
      16             : 
      17             : The above copyright notice and this permission notice shall be included in all
      18             : copies or substantial portions of the Software.
      19             : 
      20             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      21             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      23             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      25             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      26             : SOFTWARE.
      27             : 
      28             : */
      29             : 
      30             : #ifndef OO_EXCLUDE_DEBUG_SUPPORT
      31             : 
      32             : 
      33             : #import "OODebugMonitor.h"
      34             : #import "OOCollectionExtractors.h"
      35             : #import "OOLoggingExtended.h"
      36             : #import "ResourceManager.h"
      37             : #import "NSStringOOExtensions.h"
      38             : 
      39             : #import "OOJSConsole.h"
      40             : #import "OOJSScript.h"
      41             : #import "OOJSEngineTimeManagement.h"
      42             : #import "OOJSSpecialFunctions.h"
      43             : 
      44             : #import "NSObjectOOExtensions.h"
      45             : #import "OOTexture.h"
      46             : #import "OOConcreteTexture.h"
      47             : #import "OODrawable.h"
      48             : 
      49             : 
      50           0 : static OODebugMonitor *sSingleton = nil;
      51             : 
      52             : 
      53             : @interface OODebugMonitor (Private) <OOJavaScriptEngineMonitor>
      54             : 
      55           0 : - (void) setUpDebugConsoleScript;
      56           0 : - (void) javaScriptEngineWillReset:(NSNotification *)notification;
      57             : 
      58           0 : - (void)disconnectDebuggerWithMessage:(NSString *)message;
      59             : 
      60           0 : - (NSDictionary *)mergedConfiguration;
      61             : 
      62             : /*      Convert a configuration dictionary to a standard form. In particular,
      63             :         convert all colour specifiers to RGBA arrays with values in [0, 1], and
      64             :         converts "show-console" values to booleans.
      65             : */
      66           0 : - (NSMutableDictionary *)normalizeConfigDictionary:(NSDictionary *)dictionary;
      67           0 : - (id)normalizeConfigValue:(id)value forKey:(NSString *)key;
      68             : 
      69           0 : - (NSArray *)loadSourceFile:(NSString *)filePath;
      70             : 
      71             : @end
      72             : 
      73             : 
      74             : @implementation OODebugMonitor
      75             : #if OOLITE_GNUSTEP
      76             :         NSString                                        *NSApplicationWillTerminateNotification = @"ApplicationWillTerminate";
      77             : #endif
      78             : 
      79           0 : - (id)init
      80             : {
      81             :         NSUserDefaults                          *defaults = nil;
      82             :         NSMutableDictionary                     *config = nil;
      83             :         
      84             :         self = [super init];
      85             :         if (self != nil)
      86             :         {
      87             :                 config = [[[ResourceManager dictionaryFromFilesNamed:@"debugConfig.plist"
      88             :                                                                                                         inFolder:@"Config"
      89             :                                                                                                         andMerge:YES] mutableCopy] autorelease];
      90             :                 _configFromOXPs = [[self normalizeConfigDictionary:config] copy];
      91             :                 
      92             :                 defaults = [NSUserDefaults standardUserDefaults];
      93             :                 config = [self normalizeConfigDictionary:[defaults dictionaryForKey:@"debug-settings-override"]];
      94             :                 if (config == nil)  config = [NSMutableDictionary dictionary];
      95             :                 _configOverrides = [config retain];
      96             :                 
      97             :                 _TCPIgnoresDroppedPackets = NO;
      98             :                 
      99             :                 OOJavaScriptEngine *jsEng = [OOJavaScriptEngine sharedEngine];
     100             : #if OOJSENGINE_MONITOR_SUPPORT
     101             :                 [jsEng setMonitor:self];
     102             : #endif
     103             :                 
     104             :                 [self setUpDebugConsoleScript];
     105             :                 
     106             :                 [[NSNotificationCenter defaultCenter] addObserver:self
     107             :                                                                                                  selector:@selector(applicationWillTerminate:)
     108             :                                                                                                          name:NSApplicationWillTerminateNotification
     109             :                                                                                                    object:nil];
     110             :                 
     111             :                 [[NSNotificationCenter defaultCenter] addObserver:self
     112             :                                                                                                  selector:@selector(javaScriptEngineWillReset:)
     113             :                                                                                                          name:kOOJavaScriptEngineWillResetNotification
     114             :                                                                                                    object:jsEng];
     115             :                 
     116             :                 [[NSNotificationCenter defaultCenter] addObserver:self
     117             :                                                                                                  selector:@selector(setUpDebugConsoleScript)
     118             :                                                                                                          name:kOOJavaScriptEngineDidResetNotification
     119             :                                                                                                    object:jsEng];
     120             :         }
     121             :         
     122             :         return self;
     123             : }
     124             : 
     125             : 
     126           0 : - (void)dealloc
     127             : {
     128             :         [self disconnectDebuggerWithMessage:@"Debug controller object destroyed while debugging in progress."];
     129             :         
     130             :         [_configFromOXPs release];
     131             :         [_configOverrides release];
     132             :         
     133             :         [_fgColors release];
     134             :         [_bgColors release];
     135             :         [_sourceFiles release];
     136             :         
     137             :         if (_jsSelf != NULL)
     138             :         {
     139             :                 [[OOJavaScriptEngine sharedEngine] removeGCObjectRoot:&_jsSelf];
     140             :         }
     141             :         
     142             :         [super dealloc];
     143             : }
     144             : 
     145             : 
     146             : + (OODebugMonitor *) sharedDebugMonitor
     147             : {
     148             :         // NOTE: assumes single-threaded access. The debug monitor is not, on the whole, thread safe.
     149             :         if (sSingleton == nil)
     150             :         {
     151             :                 sSingleton = [[self alloc] init];
     152             :         }
     153             :         
     154             :         return sSingleton;
     155             : }
     156             : 
     157             : 
     158             : - (BOOL)setDebugger:(id<OODebuggerInterface>)newDebugger
     159             : {
     160             :         NSString                                        *error = nil;
     161             :         
     162             :         if (newDebugger != _debugger)
     163             :         {
     164             :                 // Disconnect existing debugger, if any.
     165             :                 if (newDebugger != nil)
     166             :                 {
     167             :                         [self disconnectDebuggerWithMessage:@"New debugger set."];
     168             :                 }
     169             :                 else
     170             :                 {
     171             :                         [self disconnectDebuggerWithMessage:@"Debugger disconnected programatically."];
     172             :                 }
     173             :                 
     174             :                 // If a new debugger was specified, try to connect it.
     175             :                 if (newDebugger != nil)
     176             :                 {
     177             :                         @try
     178             :                         {
     179             :                                 if ([newDebugger connectDebugMonitor:self errorMessage:&error])
     180             :                                 {
     181             :                                         [newDebugger debugMonitor:self
     182             :                                                         noteConfiguration:[self mergedConfiguration]];
     183             :                                         _debugger = [newDebugger retain];
     184             :                                 }
     185             :                                 else
     186             :                                 {
     187             :                                         OOLog(@"debugMonitor.setDebugger.failed", @"Could not connect to debugger %@, because an error occurred: %@", newDebugger, error);
     188             :                                 }
     189             :                         }
     190             :                         @catch (NSException *exception)
     191             :                         {
     192             :                                 OOLog(@"debugMonitor.setDebugger.failed", @"Could not connect to debugger %@, because an exception occurred: %@ -- %@", newDebugger, [exception name], [exception reason]);
     193             :                         }
     194             :                 }
     195             :         }
     196             :         
     197             :         return _debugger == newDebugger;
     198             : }
     199             : 
     200             : 
     201           0 : - (oneway void)performJSConsoleCommand:(in NSString *)command
     202             : {
     203             :         JSContext *context = OOJSAcquireContext();
     204             :         jsval commandVal = OOJSValueFromNativeObject(context, command);
     205             :         OOJSStartTimeLimiterWithTimeLimit(kOOJSLongTimeLimit);
     206             :         [_script callMethod:OOJSID("consolePerformJSCommand") inContext:context withArguments:&commandVal count:1 result:NULL];
     207             :         OOJSStopTimeLimiter();
     208             :         OOJSRelinquishContext(context);
     209             : }
     210             : 
     211             : 
     212             : - (void)appendJSConsoleLine:(id)string
     213             :                                    colorKey:(NSString *)colorKey
     214             :                           emphasisRange:(NSRange)emphasisRange
     215             : {
     216             :         if (string == nil)  return;
     217             :         OOJSPauseTimeLimiter();
     218             :         @try
     219             :         {
     220             :                 [_debugger debugMonitor:self
     221             :                                 jsConsoleOutput:string
     222             :                                            colorKey:colorKey
     223             :                                   emphasisRange:emphasisRange];
     224             :         }
     225             :         @catch (NSException *exception)
     226             :         {
     227             :                 OOLog(@"debugMonitor.debuggerConnection.exception", @"Exception while attempting to send JavaScript console text to debugger: %@ -- %@", [exception name], [exception reason]);
     228             :         }
     229             :         OOJSResumeTimeLimiter();
     230             : }
     231             : 
     232             : 
     233             : - (void)appendJSConsoleLine:(id)string
     234             :                                    colorKey:(NSString *)colorKey
     235             : {
     236             :         [self appendJSConsoleLine:string
     237             :                                          colorKey:colorKey
     238             :                                 emphasisRange:NSMakeRange(0, 0)];
     239             : }
     240             : 
     241             : 
     242             : - (void)clearJSConsole
     243             : {
     244             :         OOJSPauseTimeLimiter();
     245             :         @try
     246             :         {
     247             :                 [_debugger debugMonitorClearConsole:self];
     248             :         }
     249             :         @catch (NSException *exception)
     250             :         {
     251             :                 OOLog(@"debugMonitor.debuggerConnection.exception", @"Exception while attempting to clear JavaScript console: %@ -- %@", [exception name], [exception reason]);
     252             :         }
     253             :         OOJSResumeTimeLimiter();
     254             : }
     255             : 
     256             : 
     257             : - (void)showJSConsole
     258             : {
     259             :         OOJSPauseTimeLimiter();
     260             :         @try
     261             :         {
     262             :                 [_debugger debugMonitorShowConsole:self];
     263             :         }
     264             :         @catch (NSException *exception)
     265             :         {
     266             :                 OOLog(@"debugMonitor.debuggerConnection.exception", @"Exception while attempting to show JavaScript console: %@ -- %@", [exception name], [exception reason]);
     267             :         }
     268             :         OOJSResumeTimeLimiter();
     269             : }
     270             : 
     271             : 
     272           0 : - (id)configurationValueForKey:(in NSString *)key
     273             : {
     274             :         return [self configurationValueForKey:key class:Nil defaultValue:nil];
     275             : }
     276             : 
     277             : 
     278             : - (id)configurationValueForKey:(NSString *)key class:(Class)class defaultValue:(id)value
     279             : {
     280             :         id                                                      result = nil;
     281             :         
     282             :         if (class == Nil)  class = [NSObject class];
     283             :         
     284             :         result = [_configOverrides objectForKey:key];
     285             :         if (![result isKindOfClass:class] && result != [NSNull null])  result = [_configFromOXPs objectForKey:key];
     286             :         if (![result isKindOfClass:class] && result != [NSNull null])  result = [[value retain] autorelease];
     287             :         if (result == [NSNull null])  result = nil;
     288             :         
     289             :         return result;
     290             : }
     291             : 
     292             : 
     293             : - (long long)configurationIntValueForKey:(NSString *)key defaultValue:(long long)value
     294             : {
     295             :         long long                                       result;
     296             :         id                                                      object = nil;
     297             :         
     298             :         object = [self configurationValueForKey:key];
     299             :         if ([object respondsToSelector:@selector(longLongValue)])  result = [object longLongValue];
     300             :         else if ([object respondsToSelector:@selector(intValue)])  result = [object intValue];
     301             :         else  result = value;
     302             :         
     303             :         return result;
     304             : }
     305             : 
     306             : 
     307           0 : - (void)setConfigurationValue:(in id)value forKey:(in NSString *)key
     308             : {
     309             :         if (key == nil)  return;
     310             :         
     311             :         value = [self normalizeConfigValue:value forKey:key];
     312             :         
     313             :         if (value == nil)
     314             :         {
     315             :                 [_configOverrides removeObjectForKey:key];
     316             :         }
     317             :         else
     318             :         {
     319             :                 if (_configOverrides == nil)  _configOverrides = [[NSMutableDictionary alloc] init];
     320             :                 [_configOverrides setObject:value forKey:key];
     321             :         }
     322             :         
     323             :         // Send changed value to debugger
     324             :         if (value == nil)
     325             :         {
     326             :                 // Setting a nil value removes an override, and may reveal an underlying OXP-defined value
     327             :                 value = [self configurationValueForKey:key];
     328             :         }
     329             :         @try
     330             :         {
     331             :                 [_debugger debugMonitor:self
     332             :    noteChangedConfigrationValue:value
     333             :                                                  forKey:key];
     334             :         }
     335             :         @catch (NSException *exception)
     336             :         {
     337             :                 OOLog(@"debugMonitor.debuggerConnection.exception", @"Exception while attempting to send configuration update to debugger: %@ -- %@", [exception name], [exception reason]);
     338             :         }
     339             : }
     340             : 
     341             : 
     342             : - (NSArray *)configurationKeys
     343             : {
     344             :         NSMutableSet                            *result = nil;
     345             :         
     346             :         result = [NSMutableSet setWithCapacity:[_configFromOXPs count] + [_configOverrides count]];
     347             :         [result addObjectsFromArray:[_configFromOXPs allKeys]];
     348             :         [result addObjectsFromArray:[_configOverrides allKeys]];
     349             :         
     350             :         return [[result allObjects] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
     351             : }
     352             : 
     353             : 
     354             : - (BOOL) debuggerConnected
     355             : {
     356             :         return _debugger != nil;
     357             : }
     358             : 
     359             : 
     360           0 : - (void) writeMemStat:(NSString *)format, ...
     361             : {
     362             :         va_list args;
     363             :         va_start(args, format);
     364             :         NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
     365             :         va_end(args);
     366             :         
     367             :         OOLog(@"debug.memStats", @"%@", message);
     368             :         [self appendJSConsoleLine:message colorKey:@"command-result"];
     369             :         
     370             :         [message release];
     371             : }
     372             : 
     373             : 
     374           0 : static NSString *SizeString(size_t size)
     375             : {
     376             :         enum
     377             :         {
     378             :                 kThreshold = 2  // 2 KiB, 2 MiB etc.
     379             :         };
     380             :         
     381             :         unsigned magnitude = 0;
     382             :         NSString *suffix = @"";
     383             :         
     384             :         if (size < kThreshold << 10)
     385             :         {
     386             :                 return [NSString stringWithFormat:@"%zu bytes", size];
     387             :         }
     388             :         if (size < kThreshold << 20)
     389             :         {
     390             :                 magnitude = 1;
     391             :                 suffix = @"KiB";
     392             :         }
     393             :         else if (size < ((size_t)kThreshold << 30))
     394             :         {
     395             :                 magnitude = 2;
     396             :                 suffix = @"MiB";
     397             :         }
     398             :         else
     399             :         {
     400             :                 magnitude = 3;
     401             :                 suffix = @"GiB";
     402             :         }
     403             :         
     404             :         float unit = 1 << (magnitude * 10);
     405             :         float sizef = (float)size / unit;
     406             :         sizef = round(sizef * 100.0f) / 100.f;
     407             :         
     408             :         return [NSString stringWithFormat:@"%.2f %@", sizef, suffix];
     409             : }
     410             : 
     411             : 
     412           0 : typedef struct
     413             : {
     414           0 :         NSMutableSet            *entityTextures;
     415           0 :         NSMutableSet            *visibleEntityTextures;
     416           0 :         NSMutableSet            *seenEntities;
     417           0 :         unsigned                        seenCount;
     418           0 :         size_t                          totalEntityObjSize;
     419           0 :         size_t                          totalDrawableSize;
     420             : } EntityDumpState;
     421             : 
     422             : 
     423           0 : - (void) dumpEntity:(id)entity withState:(EntityDumpState *)state parentVisible:(BOOL)parentVisible
     424             : {
     425             :         if ([state->seenEntities containsObject:entity] || entity == nil)  return;
     426             :         [state->seenEntities addObject:entity];
     427             :         
     428             :         state->seenCount++;
     429             :         
     430             :         size_t entitySize = [entity oo_objectSize];
     431             :         size_t drawableSize = 0;
     432             :         if ([entity isKindOfClass:[OOEntityWithDrawable class]])
     433             :         {
     434             :                 OODrawable *drawable = [entity drawable];
     435             :                 drawableSize = [drawable totalSize];
     436             :         }
     437             :         
     438             :         BOOL visible = parentVisible && [entity isVisible];
     439             :         
     440             :         NSSet *textures = [entity allTextures];
     441             :         if (textures != nil)
     442             :         {
     443             :                 [state->entityTextures unionSet:textures];
     444             :                 if (visible)  [state->visibleEntityTextures unionSet:textures];
     445             :         }
     446             :         
     447             :         NSString *extra = @"";
     448             :         if (visible)
     449             :         {
     450             :                 extra = [extra stringByAppendingString:@", visible"];
     451             :         }
     452             :         
     453             :         if (drawableSize != 0)
     454             :         {
     455             :                 extra = [extra stringByAppendingFormat:@", drawable: %@", SizeString(drawableSize)];
     456             :         }
     457             :         
     458             :         [self writeMemStat:@"%@: %@%@", [entity shortDescription], SizeString(entitySize), extra];
     459             :         
     460             :         state->totalEntityObjSize += entitySize;
     461             :         state->totalDrawableSize += drawableSize;
     462             :         
     463             :         OOLogIndent();
     464             :         if ([entity isShip])
     465             :         {
     466             :                 NSEnumerator *subEnum = nil;
     467             :                 id subentity = nil;
     468             :                 for (subEnum = [entity subEntityEnumerator]; (subentity = [subEnum nextObject]); )
     469             :                 {
     470             :                         [self dumpEntity:subentity withState:state parentVisible:visible];
     471             :                 }
     472             :                 
     473             :                 if ([entity isPlayer])
     474             :                 {
     475             :                         NSUInteger i, count = [entity dialMaxMissiles];
     476             :                         for (i = 0; i < count; i++)
     477             :                         {
     478             :                                 subentity = [entity missileForPylon:i];
     479             :                                 if (subentity != nil)  [self dumpEntity:subentity withState:state parentVisible:NO];
     480             :                         }
     481             :                 }
     482             :         }
     483             :         if ([entity isPlanet])
     484             :         {
     485             : #if NEW_PLANETS
     486             :                 // FIXME: dump atmosphere texture.
     487             : #else
     488             :                 PlanetEntity *atmosphere = [entity atmosphere];
     489             :                 if (atmosphere != nil)
     490             :                 {
     491             :                         [self dumpEntity:atmosphere withState:state parentVisible:visible];
     492             :                 }
     493             : #endif
     494             :         }
     495             :         if ([entity isWormhole])
     496             :         {
     497             :                 NSEnumerator *shipEnum = nil;
     498             :                 NSDictionary *shipInfo = nil;
     499             :                 for (shipEnum = [[entity shipsInTransit] objectEnumerator]; (shipInfo = [shipEnum nextObject]); )
     500             :                 {
     501             :                         ShipEntity *ship = [shipInfo objectForKey:@"ship"];
     502             :                         [self dumpEntity:ship withState:state parentVisible:NO];
     503             :                 }
     504             :         }
     505             :         OOLogOutdent();
     506             : }
     507             : 
     508             : 
     509             : - (void) dumpMemoryStatistics
     510             : {
     511             :         OOLog(@"debug.memStats", @"%@", @"Memory statistics:");
     512             :         OOLogIndent();
     513             :         
     514             :         //      Get texture retain counts before the entity dumper starts messing with them.
     515             :         NSSet *allTextures = [OOTexture allTextures];
     516             :         NSMutableDictionary *textureRefCounts = [NSMutableDictionary dictionaryWithCapacity:[allTextures count]];
     517             :         
     518             :         OOTexture *tex = nil;
     519             :         NSEnumerator *texEnum = nil;
     520             :         for (texEnum = [allTextures objectEnumerator]; (tex = [texEnum nextObject]); )
     521             :         {
     522             :                 // We subtract one because allTextures retains the textures.
     523             :                 [textureRefCounts setObject:[NSNumber numberWithUnsignedInteger:[tex retainCount] - 1] forKey:[NSValue valueWithNonretainedObject:tex]];
     524             :         }
     525             :         
     526             :         size_t totalSize = 0;
     527             :         
     528             :         [self writeMemStat:@"Entitites:"];
     529             :         OOLogIndent();
     530             :         
     531             :         NSArray *entities = [UNIVERSE entityList];
     532             :         EntityDumpState entityDumpState =
     533             :         {
     534             :                 .entityTextures = [NSMutableSet set],
     535             :                 .visibleEntityTextures = [NSMutableSet set],
     536             :                 .seenEntities = [NSMutableSet set]
     537             :         };
     538             :         
     539             :         id entity = nil;
     540             :         NSEnumerator *entityEnum = nil;
     541             :         for (entityEnum = [entities objectEnumerator]; (entity = [entityEnum nextObject]); )
     542             :         {
     543             :                 [self dumpEntity:entity withState:&entityDumpState parentVisible:YES];
     544             :         }
     545             :         for (entityEnum = [[PLAYER scannedWormholes] objectEnumerator]; (entity = [entityEnum nextObject]); )
     546             :         {
     547             :                 [self dumpEntity:entity withState:&entityDumpState parentVisible:YES];
     548             :         }
     549             :         
     550             :         OOLogOutdent();
     551             :         [self writeMemStat:@"Total entity size (excluding %u entities not accounted for): %@ (%@ entity objects, %@ drawables)",
     552             :          gLiveEntityCount - entityDumpState.seenCount,
     553             :          SizeString(entityDumpState.totalEntityObjSize + entityDumpState.totalDrawableSize),
     554             :          SizeString(entityDumpState.totalEntityObjSize),
     555             :          SizeString(entityDumpState.totalDrawableSize)];
     556             :         totalSize += entityDumpState.totalEntityObjSize + entityDumpState.totalDrawableSize;
     557             :         
     558             :         /*      Sort textures so that textures in the "recent cache" come first by age,
     559             :                 followed by others.
     560             :         */
     561             :         NSMutableArray *textures = [[[OOTexture cachedTexturesByAge] mutableCopy] autorelease];
     562             :         
     563             :         for (texEnum = [allTextures objectEnumerator]; (tex = [texEnum nextObject]); )
     564             :         {
     565             :                 if ([textures indexOfObject:tex] == NSNotFound)
     566             :                 {
     567             :                         [textures addObject:tex];
     568             :                 }
     569             :         }
     570             :         
     571             :         size_t totalTextureObjSize = 0;
     572             :         size_t totalTextureDataSize = 0;
     573             :         size_t visibleTextureDataSize = 0;
     574             :         
     575             :         [self writeMemStat:@"Textures:"];
     576             :         OOLogIndent();
     577             :         
     578             :         for (texEnum = [textures objectEnumerator]; (tex = [texEnum nextObject]); )
     579             :         {
     580             :                 size_t objSize = [tex oo_objectSize];
     581             :                 size_t dataSize = [tex dataSize];
     582             :                 
     583             : #if OOTEXTURE_RELOADABLE
     584             :                 NSString *byteCountSuffix = @"";
     585             : #else
     586             :                 NSString *byteCountSuffix = @" (* 2)";
     587             : #endif
     588             :                 
     589             :                 NSString *usage = @"";
     590             :                 if ([entityDumpState.visibleEntityTextures containsObject:tex])
     591             :                 {
     592             :                         visibleTextureDataSize += dataSize;     // NOT doubled if !OOTEXTURE_RELOADABLE, because we're interested in what the GPU sees.
     593             :                         usage = @", visible";
     594             :                 }
     595             :                 else if ([entityDumpState.entityTextures containsObject:tex])
     596             :                 {
     597             :                         usage = @", active";
     598             :                 }
     599             :                 
     600             :                 unsigned refCount = [textureRefCounts oo_unsignedIntForKey:[NSValue valueWithNonretainedObject:tex]];
     601             :                 
     602             :                 [self writeMemStat:@"%@: [%u refs%@] %@%@",
     603             :                  [tex name],
     604             :                  refCount,
     605             :                  usage,
     606             :                  SizeString(objSize + dataSize),
     607             :                  byteCountSuffix];
     608             :                 
     609             :                 totalTextureDataSize += dataSize;
     610             :                 totalTextureObjSize += objSize;
     611             :         }
     612             :         totalSize += totalTextureObjSize + totalTextureDataSize;
     613             :         
     614             :         OOLogOutdent();
     615             :         
     616             : #if !OOTEXTURE_RELOADABLE
     617             :         totalTextureDataSize *= 2;
     618             : #endif
     619             :         [self writeMemStat:@"Total texture size: %@ (%@ object overhead, %@ data, %@ visible texture data)",
     620             :          SizeString(totalTextureObjSize + totalTextureDataSize),
     621             :          SizeString(totalTextureObjSize),
     622             :          SizeString(totalTextureDataSize),
     623             :          SizeString(visibleTextureDataSize)];
     624             :         
     625             :         totalSize += [self dumpJSMemoryStatistics];
     626             :         
     627             :         [self writeMemStat:@"Total: %@", SizeString(totalSize)];
     628             :         
     629             :         OOLogOutdent();
     630             : }
     631             : 
     632             : 
     633             : - (size_t) dumpJSMemoryStatistics
     634             : {
     635             :         JSContext *context = OOJSAcquireContext();
     636             :         
     637             :         JSRuntime *runtime = JS_GetRuntime(context);
     638             :         size_t jsSize = JS_GetGCParameter(runtime, JSGC_BYTES);
     639             :         size_t jsMax = JS_GetGCParameter(runtime, JSGC_MAX_BYTES);
     640             :         uint32_t jsGCCount = JS_GetGCParameter(runtime, JSGC_NUMBER);
     641             :         
     642             :         OOJSRelinquishContext(context);
     643             :         
     644             :         [self writeMemStat:@"JavaScript heap: %@ (limit %@, %u collections to date)", SizeString(jsSize), SizeString(jsMax), jsGCCount];
     645             :         return jsSize;
     646             : }
     647             : 
     648             : 
     649             : - (void) setTCPIgnoresDroppedPackets:(BOOL)flag
     650             : {
     651             :         if (_TCPIgnoresDroppedPackets != flag)
     652             :         {
     653             :                 OOLog(@"debugMonitor.TCPSettings", @"The TCP console will %@ TCP packets.",
     654             :                                 (flag ? @"try to stay connected, ignoring dropped" : @"disconnect if an error affects"));
     655             :         }
     656             :         _TCPIgnoresDroppedPackets = flag;
     657             : }
     658             : 
     659             : 
     660             : - (BOOL) TCPIgnoresDroppedPackets
     661             : {
     662             :         return _TCPIgnoresDroppedPackets;
     663             : }
     664             : 
     665             : 
     666             : - (void) setUsingPlugInController:(BOOL)flag
     667             : {
     668             :         _usingPlugInController = flag;
     669             : }
     670             : 
     671             : 
     672             : - (BOOL) usingPlugInController
     673             : {
     674             :         return _usingPlugInController;
     675             : }
     676             : 
     677             : 
     678           0 : - (NSString *)sourceCodeForFile:(in NSString *)filePath line:(in unsigned)line
     679             : {
     680             :         id                                                      linesForFile = nil;
     681             :         
     682             :         linesForFile = [_sourceFiles objectForKey:filePath];
     683             :         
     684             :         if (linesForFile == nil)
     685             :         {
     686             :                 linesForFile = [self loadSourceFile:filePath];
     687             :                 if (linesForFile == nil)  linesForFile = [NSArray arrayWithObject:[NSString stringWithFormat:@"<Can't load file %@>", filePath]];
     688             :                 
     689             :                 if (_sourceFiles == nil)  _sourceFiles = [[NSMutableDictionary alloc] init];
     690             :                 [_sourceFiles setObject:linesForFile forKey:filePath];
     691             :         }
     692             :         
     693             :         if ([linesForFile count] < line || line == 0)  return @"<line out of range!>";
     694             :         
     695             :         return [linesForFile objectAtIndex:line - 1];
     696             : }
     697             : 
     698             : 
     699           0 : - (void)disconnectDebugger:(in id<OODebuggerInterface>)debugger
     700             :                                    message:(in NSString *)message
     701             : {
     702             :         if (debugger == nil)  return;
     703             :                 
     704             :         if (debugger == _debugger)
     705             :         {
     706             :                 [self disconnectDebuggerWithMessage:message];
     707             :         }
     708             :         else
     709             :         {
     710             :                 OOLog(@"debugMonitor.disconnect.ignored", @"Attempt to disconnect debugger %@, which is not current debugger; ignoring.", debugger);
     711             :         }
     712             : }
     713             : 
     714             : 
     715             : #if OOLITE_GNUSTEP
     716             : - (void) applicationWillTerminate
     717             : {
     718             :         [[NSNotificationCenter defaultCenter] postNotificationName:NSApplicationWillTerminateNotification object:nil];
     719             : }
     720             : #endif
     721             : 
     722             : 
     723           0 : - (void)applicationWillTerminate:(NSNotification *)notification
     724             : {
     725             :         if (_configOverrides != nil)
     726             :         {
     727             :                 [[NSUserDefaults standardUserDefaults] setObject:_configOverrides forKey:@"debug-settings-override"];
     728             :         }
     729             :         
     730             :         [self disconnectDebuggerWithMessage:@"Oolite is terminating."];
     731             : }
     732             : 
     733             : 
     734             : @end
     735             : 
     736             : 
     737             : @implementation OODebugMonitor (Private)
     738             : 
     739             : - (void) setUpDebugConsoleScript
     740             : {
     741             :         JSContext *context = OOJSAcquireContext();
     742             :         /*      The path to the console script is saved in this here static variable
     743             :                 so that we can reload it when resetting into strict mode.
     744             :                 -- Ahruman 2011-02-06
     745             :         */
     746             :         static NSString *path = nil;
     747             :         
     748             :         if (path == nil)
     749             :         {
     750             :                 path = [[ResourceManager pathForFileNamed:@"oolite-debug-console.js" inFolder:@"Scripts"] retain];
     751             :         }
     752             :         if (path != nil)
     753             :         {
     754             :                 NSDictionary *jsProps = [NSDictionary dictionaryWithObjectsAndKeys:
     755             :                                                                  self, @"console",
     756             :                                                                  JSSpecialFunctionsObjectWrapper(context), @"special",
     757             :                                                                  nil];
     758             :                 _script = [[OOJSScript scriptWithPath:path properties:jsProps] retain];
     759             :         }
     760             :         
     761             :         // If no script, just make console visible globally as debugConsole.
     762             :         if (_script == nil)
     763             :         {
     764             :                 JSObject *global = [[OOJavaScriptEngine sharedEngine] globalObject];
     765             :                 JS_DefineProperty(context, global, "debugConsole", [self oo_jsValueInContext:context], NULL, NULL, JSPROP_ENUMERATE);
     766             :         }
     767             :         
     768             :         OOJSRelinquishContext(context);
     769             : }
     770             : 
     771             : 
     772             : - (void) javaScriptEngineWillReset:(NSNotification *)notification
     773             : {
     774             :         DESTROY(_script);
     775             :         _jsSelf = NULL;
     776             :         
     777             :         OOJSConsoleDestroy();
     778             : }
     779             : 
     780             : 
     781             : - (void)disconnectDebuggerWithMessage:(NSString *)message
     782             : {
     783             :         @try
     784             :         {
     785             :                 [_debugger disconnectDebugMonitor:self message:message];
     786             :         }
     787             :         @catch (NSException *exception)
     788             :         {
     789             :                 OOLog(@"debugMonitor.debuggerConnection.exception", @"Exception while attempting to disconnect debugger: %@ -- %@", [exception name], [exception reason]);
     790             :         }
     791             :         
     792             :         id debugger = _debugger;
     793             :         _debugger = nil;
     794             :         [debugger release];
     795             : }
     796             : 
     797             : 
     798             : - (NSDictionary *)mergedConfiguration
     799             : {
     800             :         NSMutableDictionary                     *result = nil;
     801             :         
     802             :         result = [NSMutableDictionary dictionary];
     803             :         if (_configFromOXPs != nil)  [result addEntriesFromDictionary:_configFromOXPs];
     804             :         if (_configOverrides != nil)  [result addEntriesFromDictionary:_configOverrides];
     805             :         
     806             :         return result;
     807             : }
     808             : 
     809             : 
     810             : - (NSArray *)loadSourceFile:(NSString *)filePath
     811             : {
     812             :         NSString                                        *contents = nil;
     813             :         NSArray                                         *lines = nil;
     814             :         
     815             :         if (filePath == nil)  return nil;
     816             :         
     817             :         contents = [NSString stringWithContentsOfUnicodeFile:filePath];
     818             :         if (contents == nil)  return nil;
     819             :         
     820             :         /*      Extract lines from file.
     821             : FIXME: this works with CRLF and LF, but not CR.
     822             :                 */
     823             :         lines = [contents componentsSeparatedByString:@"\n"];
     824             :         return lines;
     825             : }
     826             : 
     827             : 
     828             : - (NSMutableDictionary *)normalizeConfigDictionary:(NSDictionary *)dictionary
     829             : {
     830             :         NSMutableDictionary             *result = nil;
     831             :         NSEnumerator                    *keyEnum = nil;
     832             :         NSString                                *key = nil;
     833             :         id                                              value = nil;
     834             :         
     835             :         result = [NSMutableDictionary dictionaryWithCapacity:[dictionary count]];
     836             :         for (keyEnum = [dictionary keyEnumerator]; (key = [keyEnum nextObject]); )
     837             :         {
     838             :                 value = [dictionary objectForKey:key];
     839             :                 value = [self normalizeConfigValue:value forKey:key];
     840             :                 
     841             :                 if (key != nil && value != nil)  [result setObject:value forKey:key];
     842             :         }
     843             :         
     844             :         return result;
     845             : }
     846             : 
     847             : 
     848             : - (id)normalizeConfigValue:(id)value forKey:(NSString *)key
     849             : {
     850             :         OOColor                                 *color = nil;
     851             :         BOOL                                    boolValue;
     852             :         
     853             :         if (value != nil)
     854             :         {
     855             :                 if ([key hasSuffix:@"-color"] || [key hasSuffix:@"-colour"])
     856             :                 {
     857             :                         color = [OOColor colorWithDescription:value];
     858             :                         value = [color normalizedArray];
     859             :                 }
     860             :                 else if ([key hasPrefix:@"show-console"])
     861             :                 {
     862             :                         boolValue = OOBooleanFromObject(value, NO);
     863             :                         value = [NSNumber numberWithBool:boolValue];
     864             :                 }
     865             :         }
     866             :         
     867             :         return value;
     868             : }
     869             : 
     870             : 
     871           0 : - (oneway void)jsEngine:(in byref OOJavaScriptEngine *)engine
     872             :                                 context:(in JSContext *)context
     873             :                                   error:(in JSErrorReport *)errorReport
     874             :                           stackSkip:(in unsigned)stackSkip
     875             :                 showingLocation:(in BOOL)showLocation
     876             :                         withMessage:(in NSString *)message
     877             : {
     878             :         NSString                                        *colorKey = nil;
     879             :         NSString                                        *prefix = nil;
     880             :         NSString                                        *filePath = nil;
     881             :         NSString                                        *sourceLine = nil;
     882             :         NSString                                        *scriptLine = nil;
     883             :         NSMutableString                         *formattedMessage = nil;
     884             :         NSRange                                         emphasisRange;
     885             :         NSString                                        *showKey = nil;
     886             :         
     887             :         if (_debugger == nil)  return;
     888             :         
     889             :         if (errorReport->flags & JSREPORT_WARNING)
     890             :         {
     891             :                 colorKey = @"warning";
     892             :                 prefix = @"Warning";
     893             :         }
     894             :         else if (errorReport->flags & JSREPORT_EXCEPTION)
     895             :         {
     896             :                 colorKey = @"exception";
     897             :                 prefix = @"Exception";
     898             :         }
     899             :         else
     900             :         {
     901             :                 colorKey = @"error";
     902             :                 prefix = @"Error";
     903             :         }
     904             :         
     905             :         if (errorReport->flags & JSREPORT_STRICT)
     906             :         {
     907             :                 prefix = [prefix stringByAppendingString:@" (strict mode)"];
     908             :         }
     909             :         
     910             :         // Prefix and subsequent colon should be bold:
     911             :         emphasisRange = NSMakeRange(0, [prefix length] + 1);
     912             :         
     913             :         formattedMessage = [NSMutableString stringWithFormat:@"%@: %@", prefix, message];
     914             :         
     915             :         // Note that the "active script" isn't necessarily the one causing the
     916             :         // error, since one script can call another's methods.
     917             :         
     918             :         // avoid windows DEP exceptions!
     919             :         OOJSScript *thisScript = [[OOJSScript currentlyRunningScript] weakRetain];
     920             :         scriptLine = [[thisScript weakRefUnderlyingObject] displayName];
     921             :         [thisScript release];
     922             :         
     923             :         if (scriptLine != nil)
     924             :         {
     925             :                 [formattedMessage appendFormat:@"\n    Active script: %@", scriptLine];
     926             :         }
     927             :         
     928             :         if (showLocation && stackSkip == 0)
     929             :         {
     930             :                 // Append file name and line
     931             :                 if (errorReport->filename != NULL)  filePath = [NSString stringWithUTF8String:errorReport->filename];
     932             :                 if ([filePath length] != 0)
     933             :                 {
     934             :                         [formattedMessage appendFormat:@"\n    %@, line %u", [filePath lastPathComponent], errorReport->lineno];
     935             :                         
     936             :                         // Append source code
     937             :                         sourceLine = [self sourceCodeForFile:filePath line:errorReport->lineno];
     938             :                         if (sourceLine != nil)
     939             :                         {
     940             :                                 [formattedMessage appendFormat:@":\n    %@", sourceLine];
     941             :                         }
     942             :                 }
     943             :         }
     944             :         
     945             :         [self appendJSConsoleLine:formattedMessage
     946             :                                          colorKey:colorKey
     947             :                                 emphasisRange:emphasisRange];
     948             :         
     949             :         if (errorReport->flags & JSREPORT_WARNING)  showKey = @"show-console-on-warning";
     950             :         else  showKey = @"show-console-on-error";     // if not a warning, it's a proper error.
     951             :         if (OOBooleanFromObject([self configurationValueForKey:showKey], NO))
     952             :         {
     953             :                 [self showJSConsole];
     954             :         }
     955             : }
     956             : 
     957             : 
     958           0 : - (oneway void)jsEngine:(in byref OOJavaScriptEngine *)engine
     959             :                                 context:(in JSContext *)context
     960             :                          logMessage:(in NSString *)message
     961             :                                 ofClass:(in NSString *)messageClass
     962             : {
     963             :         [self appendJSConsoleLine:message colorKey:@"log"];
     964             :         if (OOBooleanFromObject([self configurationValueForKey:@"show-console-on-log"], NO))
     965             :         {
     966             :                 [self showJSConsole];
     967             :         }
     968             : }
     969             : 
     970             : 
     971           0 : - (jsval)oo_jsValueInContext:(JSContext *)context
     972             : {
     973             :         if (_jsSelf == NULL)
     974             :         {
     975             :                 _jsSelf = DebugMonitorToJSConsole(context, self);
     976             :                 if (_jsSelf != NULL)
     977             :                 {
     978             :                         if (!OOJSAddGCObjectRoot(context, &_jsSelf, "debug console"))
     979             :                         {
     980             :                                 _jsSelf = NULL;
     981             :                         }
     982             :                 }
     983             :         }
     984             :         
     985             :         if (_jsSelf != NULL)  return OBJECT_TO_JSVAL(_jsSelf);
     986             :         else  return JSVAL_NULL;
     987             : }
     988             : 
     989             : @end
     990             : 
     991             : 
     992             : @implementation OODebugMonitor (Singleton)
     993             : 
     994             : /*      Canonical singleton boilerplate.
     995             : See Cocoa Fundamentals Guide: Creating a Singleton Instance.
     996             : See also +sharedDebugMonitor above.
     997             : 
     998             : NOTE: assumes single-threaded access.
     999             : */
    1000             : 
    1001           0 : + (id)allocWithZone:(NSZone *)inZone
    1002             : {
    1003             :         if (sSingleton == nil)
    1004             :         {
    1005             :                 sSingleton = [super allocWithZone:inZone];
    1006             :                 return sSingleton;
    1007             :         }
    1008             :         return nil;
    1009             : }
    1010             : 
    1011             : 
    1012           0 : - (id)copyWithZone:(NSZone *)inZone
    1013             : {
    1014             :         return self;
    1015             : }
    1016             : 
    1017             : 
    1018           0 : - (id)retain
    1019             : {
    1020             :         return self;
    1021             : }
    1022             : 
    1023             : 
    1024           0 : - (NSUInteger)retainCount
    1025             : {
    1026             :         return UINT_MAX;
    1027             : }
    1028             : 
    1029             : 
    1030           0 : - (void)release
    1031             : {}
    1032             : 
    1033             : 
    1034           0 : - (id)autorelease
    1035             : {
    1036             :         return self;
    1037             : }
    1038             : 
    1039             : @end
    1040             : 
    1041             : #endif /* OO_EXCLUDE_DEBUG_SUPPORT */

Generated by: LCOV version 1.14