Oolite 1.91.0.7604-240417-a536cbe
Loading...
Searching...
No Matches
OOJSConsole.m
Go to the documentation of this file.
1/*
2
3OOJSConsole.m
4
5
6Oolite
7Copyright (C) 2004-2013 Giles C Williams and contributors
8
9Permission is hereby granted, free of charge, to any person obtaining a copy
10of this software and associated documentation files (the "Software"), to deal
11in the Software without restriction, including without limitation the rights
12to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13copies of the Software, and to permit persons to whom the Software is
14furnished to do so, subject to the following conditions:
15
16The above copyright notice and this permission notice shall be included in all
17copies or substantial portions of the Software.
18
19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25SOFTWARE.
26
27*/
28
29#ifndef OO_EXCLUDE_DEBUG_SUPPORT
30
31#import "OOJSConsole.h"
32#import "OODebugMonitor.h"
33#include <stdint.h>
34
36#import "OOJSScript.h"
37#import "OOJSVector.h"
38#import "OOJSEntity.h"
39#import "OOJSCall.h"
40#import "OOLoggingExtended.h"
41#import "OOConstToString.h"
43#import "OODebugFlags.h"
44#import "OODebugMonitor.h"
46#import "ResourceManager.h"
47
48
49@interface Entity (OODebugInspector)
50
51// Method added by inspector in Debug OXP under OS X only.
52- (void) inspect;
53
54@end
55
56
57NSString *OOPlatformDescription(void);
58
59
60static JSObject *sConsolePrototype = NULL;
61static JSObject *sConsoleSettingsPrototype = NULL;
62
63
64static JSBool ConsoleGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value);
65static JSBool ConsoleSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value);
66static void ConsoleFinalize(JSContext *context, JSObject *this);
67
68// Methods
69static JSBool ConsoleConsoleMessage(JSContext *context, uintN argc, jsval *vp);
70static JSBool ConsoleClearConsole(JSContext *context, uintN argc, jsval *vp);
71static JSBool ConsoleScriptStack(JSContext *context, uintN argc, jsval *vp);
72static JSBool ConsoleInspectEntity(JSContext *context, uintN argc, jsval *vp);
73#if OO_DEBUG
74static JSBool ConsoleCallObjCMethod(JSContext *context, uintN argc, jsval *vp);
75static JSBool ConsoleSetUpCallObjC(JSContext *context, uintN argc, jsval *vp);
76#endif
77static JSBool ConsoleIsExecutableJavaScript(JSContext *context, uintN argc, jsval *vp);
78static JSBool ConsoleDisplayMessagesInClass(JSContext *context, uintN argc, jsval *vp);
79static JSBool ConsoleSetDisplayMessagesInClass(JSContext *context, uintN argc, jsval *vp);
80static JSBool ConsoleWriteLogMarker(JSContext *context, uintN argc, jsval *vp);
81static JSBool ConsoleWriteMemoryStats(JSContext *context, uintN argc, jsval *vp);
82static JSBool ConsoleWriteJSMemoryStats(JSContext *context, uintN argc, jsval *vp);
83static JSBool ConsoleGarbageCollect(JSContext *context, uintN argc, jsval *vp);
84#if DEBUG
85static JSBool ConsoleDumpNamedRoots(JSContext *context, uintN argc, jsval *vp);
86static JSBool ConsoleDumpHeap(JSContext *context, uintN argc, jsval *vp);
87#endif
88#if OOJS_PROFILE
89static JSBool ConsoleProfile(JSContext *context, uintN argc, jsval *vp);
90static JSBool ConsoleGetProfile(JSContext *context, uintN argc, jsval *vp);
91static JSBool ConsoleTrace(JSContext *context, uintN argc, jsval *vp);
92#endif
93
94static JSBool ConsoleSettingsDeleteProperty(JSContext *context, JSObject *this, jsid propID, jsval *value);
95static JSBool ConsoleSettingsGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value);
96static JSBool ConsoleSettingsSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value);
97
98#if OOJS_PROFILE
99static JSBool PerformProfiling(JSContext *context, NSString *nominalFunction, uintN argc, jsval *argv, jsval *rval, BOOL trace, OOTimeProfile **profile);
100#endif
101
102
103static JSClass sConsoleClass =
104{
105 "Console",
106 JSCLASS_HAS_PRIVATE,
107
108 JS_PropertyStub, // addProperty
109 JS_PropertyStub, // delProperty
110 ConsoleGetProperty, // getProperty
111 ConsoleSetProperty, // setProperty
112 JS_EnumerateStub, // enumerate
113 JS_ResolveStub, // resolve
114 JS_ConvertStub, // convert
115 ConsoleFinalize, // finalize
116 JSCLASS_NO_OPTIONAL_MEMBERS
117};
118
119
120enum
121{
122 // Property IDs
123 kConsole_debugFlags, // debug flags, integer, read/write
124 kConsole_detailLevel, // graphics detail level, symbolic string, read/write
125 kConsole_maximumDetailLevel, // maximum graphics detail level, symbolic string, read-only
126 kConsole_displayFPS, // display FPS (and related info), boolean, read/write
127 kConsole_platformDescription, // Information about system we're running on in unspecified format, string, read-only
128 kConsole_ignoreDroppedPackets, // boolean (default false), read/write
129 kConsole_pedanticMode, // JS pedantic mode (JS_STRICT flag, not the same as "use strict"), boolean (default true), read/write
130 kConsole_showErrorLocations, // Show error/warning source locations, boolean (default true), read/write
131 kConsole_dumpStackForErrors, // Write stack dump when reporting error/exception, boolean (default false), read/write
132 kConsole_dumpStackForWarnings, // Write stack dump when reporting warning, boolean (default false), read/write
133
134 kConsole_glVendorString, // OpenGL GL_VENDOR string, string, read-only
135 kConsole_glRendererString, // OpenGL GL_RENDERER string, string, read-only
136 kConsole_glFixedFunctionTextureUnitCount, // GL_MAX_TEXTURE_UNITS_ARB, integer, read-only
137 kConsole_glFragmentShaderTextureUnitCount, // GL_MAX_TEXTURE_IMAGE_UNITS_ARB, integer, read-only
138
139 // Symbolic constants for debug flags:
150
153
154
155static JSPropertySpec sConsoleProperties[] =
156{
157 // JS name ID flags
160 { "maximumDetailLevel", kConsole_maximumDetailLevel, OOJS_PROP_READONLY_CB },
162 { "platformDescription", kConsole_platformDescription, OOJS_PROP_READONLY_CB },
164 { "ignoreDroppedPackets", kConsole_ignoreDroppedPackets, OOJS_PROP_READWRITE_CB },
168 { "glVendorString", kConsole_glVendorString, OOJS_PROP_READONLY_CB },
169 { "glRendererString", kConsole_glRendererString, OOJS_PROP_READONLY_CB },
170 { "glFixedFunctionTextureUnitCount", kConsole_glFixedFunctionTextureUnitCount, OOJS_PROP_READONLY_CB },
171 { "glFragmentShaderTextureUnitCount", kConsole_glFragmentShaderTextureUnitCount, OOJS_PROP_READONLY_CB },
172
173#define DEBUG_FLAG_DECL(x) { #x, kConsole_##x, OOJS_PROP_READONLY_CB }
184
186#undef DEBUG_FLAG_DECL
187
188 { 0 }
189};
190
191
192static JSFunctionSpec sConsoleMethods[] =
193{
194 // JS name Function min args
195 { "consoleMessage", ConsoleConsoleMessage, 2 },
196 { "clearConsole", ConsoleClearConsole, 0 },
197 { "scriptStack", ConsoleScriptStack, 0 },
198 { "inspectEntity", ConsoleInspectEntity, 1 },
199#if OO_DEBUG
200 { "__setUpCallObjC", ConsoleSetUpCallObjC, 1 },
201#endif
202 { "isExecutableJavaScript", ConsoleIsExecutableJavaScript, 2 },
203 { "displayMessagesInClass", ConsoleDisplayMessagesInClass, 1 },
204 { "setDisplayMessagesInClass", ConsoleSetDisplayMessagesInClass, 2 },
205 { "writeLogMarker", ConsoleWriteLogMarker, 0 },
206 { "writeMemoryStats", ConsoleWriteMemoryStats, 0 },
207 { "writeJSMemoryStats", ConsoleWriteJSMemoryStats, 0 },
208 { "garbageCollect", ConsoleGarbageCollect, 0 },
209#if DEBUG
210 { "dumpNamedRoots", ConsoleDumpNamedRoots, 0 },
211 { "dumpHeap", ConsoleDumpHeap, 0 },
212#endif
213#if OOJS_PROFILE
214 { "profile", ConsoleProfile, 1 },
215 { "getProfile", ConsoleGetProfile, 1 },
216 { "trace", ConsoleTrace, 1 },
217#endif
218 { 0 }
219};
220
221
222static JSClass sConsoleSettingsClass =
223{
224 "ConsoleSettings",
225 JSCLASS_HAS_PRIVATE,
226
227 JS_PropertyStub, // addProperty
228 ConsoleSettingsDeleteProperty, // delProperty
229 ConsoleSettingsGetProperty, // getProperty
230 ConsoleSettingsSetProperty, // setProperty
231 JS_EnumerateStub, // enumerate. FIXME: this should work.
232 JS_ResolveStub, // resolve
233 JS_ConvertStub, // convert
234 ConsoleFinalize, // finalize (same as Console)
235 JSCLASS_NO_OPTIONAL_MEMBERS
236};
237
238
239static void InitOOJSConsole(JSContext *context, JSObject *global)
240{
241 sConsolePrototype = JS_InitClass(context, global, NULL, &sConsoleClass, OOJSUnconstructableConstruct, 0, sConsoleProperties, sConsoleMethods, NULL, NULL);
243
244 sConsoleSettingsPrototype = JS_InitClass(context, global, NULL, &sConsoleSettingsClass, OOJSUnconstructableConstruct, 0, NULL, NULL, NULL, NULL);
246}
247
248
250{
251 sConsolePrototype = NULL;
252}
253
254
255JSObject *DebugMonitorToJSConsole(JSContext *context, OODebugMonitor *monitor)
256{
258
259 OOJavaScriptEngine *engine = nil;
260 JSObject *object = NULL;
261 JSObject *settingsObject = NULL;
262 jsval value;
263
264 NSCAssert(JS_EnterLocalRootScope(context), @"Failed to create JS GC root scope");
266
267 if (sConsolePrototype == NULL)
268 {
269 InitOOJSConsole(context, [engine globalObject]);
270 }
271
272 // Create Console object
273 object = JS_NewObject(context, &sConsoleClass, sConsolePrototype, NULL);
274 if (object != NULL)
275 {
276 if (!JS_SetPrivate(context, object, [monitor weakRetain])) object = NULL;
277 }
278
279 if (object != NULL)
280 {
281 // Create ConsoleSettings object
282 settingsObject = JS_NewObject(context, &sConsoleSettingsClass, sConsoleSettingsPrototype, NULL);
283 if (settingsObject != NULL)
284 {
285 if (!JS_SetPrivate(context, settingsObject, [monitor weakRetain])) settingsObject = NULL;
286 }
287 if (settingsObject != NULL)
288 {
289 value = OBJECT_TO_JSVAL(settingsObject);
290 if (!JS_SetProperty(context, object, "settings", &value))
291 {
292 settingsObject = NULL;
293 }
294 }
295
296 if (settingsObject == NULL) object = NULL;
297 }
298
299 JS_LeaveLocalRootScope(context);
300
301 return object;
302 // Analyzer: object leaked. (x2) [Expected, objects are retained by JS object.]
303
305}
306
307
308static JSBool ConsoleGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
309{
310 if (!JSID_IS_INT(propID)) return YES;
311
312 OOJS_NATIVE_ENTER(context)
313
314 switch (JSID_TO_INT(propID))
315 {
316#ifndef NDEBUG
318 *value = INT_TO_JSVAL((uint32_t)gDebugFlags);
319 break;
320#endif
321
323 *value = [OOStringFromGraphicsDetail([UNIVERSE detailLevel]) oo_jsValueInContext:context];
324 break;
325
327 *value = [OOStringFromGraphicsDetail([[OOOpenGLExtensionManager sharedManager] maximumDetailLevel]) oo_jsValueInContext:context];
328 break;
329
331 *value = OOJSValueFromBOOL([UNIVERSE displayFPS]);
332 break;
333
336 break;
337
339 {
340 uint32_t options = JS_GetOptions(context);
341 *value = OOJSValueFromBOOL(options & JSOPTION_STRICT);
342 }
343 break;
344
346 *value = OOJSValueFromBOOL([[OODebugMonitor sharedDebugMonitor] TCPIgnoresDroppedPackets]);
347 break;
348
350 *value = OOJSValueFromBOOL([[OOJavaScriptEngine sharedEngine] showErrorLocations]);
351 break;
352
354 *value = OOJSValueFromBOOL([[OOJavaScriptEngine sharedEngine] dumpStackForErrors]);
355 break;
356
358 *value = OOJSValueFromBOOL([[OOJavaScriptEngine sharedEngine] dumpStackForWarnings]);
359 break;
360
362 *value = OOJSValueFromNativeObject(context, [[OOOpenGLExtensionManager sharedManager] vendorString]);
363 break;
364
366 *value = OOJSValueFromNativeObject(context, [[OOOpenGLExtensionManager sharedManager] rendererString]);
367 break;
368
370 *value = INT_TO_JSVAL([[OOOpenGLExtensionManager sharedManager] textureUnitCount]);
371 break;
372
374 *value = INT_TO_JSVAL([[OOOpenGLExtensionManager sharedManager] textureImageUnitCount]);
375 break;
376
377#define DEBUG_FLAG_CASE(x) case kConsole_##x: *value = INT_TO_JSVAL(x); break;
388
390#undef DEBUG_FLAG_CASE
391
392 default:
394 return NO;
395 }
396
397 return YES;
398
400}
401
402
403static JSBool ConsoleSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value)
404{
405 if (!JSID_IS_INT(propID)) return YES;
406
407 OOJS_NATIVE_ENTER(context)
408
409 int32 iValue;
410 JSBool bValue = NO;
411 NSString *sValue;
412
413 switch (JSID_TO_INT(propID))
414 {
415#ifndef NDEBUG
417 if (JS_ValueToInt32(context, *value, &iValue))
418 {
419 gDebugFlags = iValue;
420 }
421 break;
422#endif
424 sValue = OOStringFromJSValue(context, *value);
426 [UNIVERSE setDetailLevel:OOGraphicsDetailFromString(sValue)];
428 break;
429
431 if (JS_ValueToBoolean(context, *value, &bValue))
432 {
433 [UNIVERSE setDisplayFPS:bValue];
434 }
435 break;
436
438 if (JS_ValueToBoolean(context, *value, &bValue))
439 {
440 uint32_t options = JS_GetOptions(context);
441 if (bValue) options |= JSOPTION_STRICT;
442 else options &= ~JSOPTION_STRICT;
443
444 JS_SetOptions(context, options);
445 }
446 break;
447
449 if (JS_ValueToBoolean(context, *value, &bValue))
450 {
452 }
453 break;
454
456 if (JS_ValueToBoolean(context, *value, &bValue))
457 {
459 }
460 break;
461
463 if (JS_ValueToBoolean(context, *value, &bValue))
464 {
466 }
467 break;
468
470 if (JS_ValueToBoolean(context, *value, &bValue))
471 {
473 }
474 break;
475
476 default:
478 return NO;
479 }
480
481 return YES;
482
484}
485
486
487static BOOL DoWeDefineAllDebugFlags(enum OODebugFlags flags) GCC_ATTR((unused));
489{
490 /* This function doesn't do anything, but will generate a warning
491 (Enumeration value 'DEBUG_FOO' not handled in switch) if a debug flag
492 is added without updating it. The point is that if you get such a
493 warning, you should first add a JS symbolic constant for the flag,
494 then add it to the switch to suppress the warning.
495 NOTE: don't add a default: to this switch, or I will have to hurt you.
496 -- Ahruman 2010-04-11
497 */
498 switch (flags)
499 {
501 case DEBUG_COLLISIONS:
502 case DEBUG_DOCKING:
507 case DEBUG_NO_DUST:
510 case DEBUG_MISC:
511 return YES;
512 }
513
514 return NO;
515}
516
517
518static void ConsoleFinalize(JSContext *context, JSObject *this)
519{
521
522 [(id)JS_GetPrivate(context, this) release];
523 JS_SetPrivate(context, this, nil);
524
526}
527
528
529static JSBool ConsoleSettingsDeleteProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
530{
531 OOJS_NATIVE_ENTER(context)
532
533 NSString *key = nil;
534 id monitor = nil;
535
536 if (!JSID_IS_STRING(propID)) return NO;
537 key = OOStringFromJSString(context, JSID_TO_STRING(propID));
538
539 monitor = OOJSNativeObjectFromJSObject(context, this);
540 if (![monitor isKindOfClass:[OODebugMonitor class]])
541 {
542 OOJSReportError(context, @"Expected OODebugMonitor, got %@ in %s. %@", [monitor class], __PRETTY_FUNCTION__, @"This is an internal error, please report it.");
543 return NO;
544 }
545
546 [monitor setConfigurationValue:nil forKey:key];
547 *value = JSVAL_TRUE;
548 return YES;
549
551}
552
553
554static JSBool ConsoleSettingsGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
555{
556 if (!JSID_IS_STRING(propID)) return YES;
557
558 OOJS_NATIVE_ENTER(context)
559
560 NSString *key = nil;
561 id settingValue = nil;
562 id monitor = nil;
563
564 key = OOStringFromJSString(context, JSID_TO_STRING(propID));
565
566 monitor = OOJSNativeObjectFromJSObject(context, this);
567 if (![monitor isKindOfClass:[OODebugMonitor class]])
568 {
569 OOJSReportError(context, @"Expected OODebugMonitor, got %@ in %s. %@", [monitor class], __PRETTY_FUNCTION__, @"This is an internal error, please report it.");
570 return NO;
571 }
572
573 settingValue = [monitor configurationValueForKey:key];
574 if (settingValue != NULL) *value = [settingValue oo_jsValueInContext:context];
575 else *value = JSVAL_VOID;
576
577 return YES;
578
580}
581
582
583static JSBool ConsoleSettingsSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value)
584{
585 if (!JSID_IS_STRING(propID)) return YES;
586
587 OOJS_NATIVE_ENTER(context)
588
589 NSString *key = nil;
590 id settingValue = nil;
591 id monitor = nil;
592
593 key = OOStringFromJSString(context, JSID_TO_STRING(propID));
594
595 monitor = OOJSNativeObjectFromJSObject(context, this);
596 if (![monitor isKindOfClass:[OODebugMonitor class]])
597 {
598 OOJSReportError(context, @"Expected OODebugMonitor, got %@ in %s. %@", [monitor class], __PRETTY_FUNCTION__, @"This is an internal error, please report it.");
599 return NO;
600 }
601
602 // Not OOJS_BEGIN_FULL_NATIVE() - we use JSAPI while paused.
604 if (JSVAL_IS_NULL(*value) || JSVAL_IS_VOID(*value))
605 {
606 [monitor setConfigurationValue:nil forKey:key];
607 }
608 else
609 {
610 settingValue = OOJSNativeObjectFromJSValue(context, *value);
611 if (settingValue != nil)
612 {
613 [monitor setConfigurationValue:settingValue forKey:key];
614 }
615 else
616 {
617 OOJSReportWarning(context, @"debugConsole.settings: could not convert %@ to native object.", OOStringFromJSValue(context, *value));
618 }
619 }
621
622 return YES;
623
625}
626
627
628// *** Methods ***
629
630// function consoleMessage(colorCode : String, message : String [, emphasisStart : Number, emphasisLength : Number]) : void
631static JSBool ConsoleConsoleMessage(JSContext *context, uintN argc, jsval *vp)
632{
633 NSRange emphasisRange = {0, 0};
634
635 OOJS_NATIVE_ENTER(context)
636
637 id monitor = nil;
638 NSString *colorKey = nil,
639 *message = nil;
640 jsdouble location, length;
641
642 // Not OOJS_BEGIN_FULL_NATIVE() - we use JSAPI while paused.
645 if (monitor == nil)
646 {
647 OOJSReportError(context, @"Expected OODebugMonitor, got %@ in %s. %@", [monitor class], __PRETTY_FUNCTION__, @"This is an internal error, please report it.");
649 return NO;
650 }
651
652 if (argc > 0) colorKey = OOStringFromJSValue(context,OOJS_ARGV[0]);
653 if (argc > 1) message = OOStringFromJSValue(context,OOJS_ARGV[1]);
654
655 if (argc > 3)
656 {
657 // Attempt to get two numbers, specifying an emphasis range.
658 if (JS_ValueToNumber(context, OOJS_ARGV[2], &location) &&
659 JS_ValueToNumber(context, OOJS_ARGV[3], &length))
660 {
661 emphasisRange = (NSRange){location, length};
662 }
663 }
664
665 if (message == nil)
666 {
667 if (colorKey == nil)
668 {
669 OOJSReportWarning(context, @"Console.consoleMessage() called with no parameters.");
670 }
671 else
672 {
673 message = colorKey;
674 colorKey = @"command-result";
675 }
676 }
677
678 if (message != nil)
679 {
680 [monitor appendJSConsoleLine:message
681 colorKey:colorKey
682 emphasisRange:emphasisRange];
683 }
685
687
689}
690
691
692// function clearConsole() : void
693static JSBool ConsoleClearConsole(JSContext *context, uintN argc, jsval *vp)
694{
695 OOJS_NATIVE_ENTER(context)
696
697 id monitor = nil;
698
699 monitor = OOJSNativeObjectFromJSObject(context, OOJS_THIS);
700 if (![monitor isKindOfClass:[OODebugMonitor class]])
701 {
702 OOJSReportError(context, @"Expected OODebugMonitor, got %@ in %s. %@", [monitor class], __PRETTY_FUNCTION__, @"This is an internal error, please report it.");
703 return NO;
704 }
705
706 [monitor clearJSConsole];
708
710}
711
712
713// function scriptStack() : Array
714static JSBool ConsoleScriptStack(JSContext *context, uintN argc, jsval *vp)
715{
716 OOJS_NATIVE_ENTER(context)
717
718 OOJS_RETURN_OBJECT([OOJSScript scriptStack]);
719
721}
722
723
724// function inspectEntity(entity : Entity) : void
725static JSBool ConsoleInspectEntity(JSContext *context, uintN argc, jsval *vp)
726{
727 OOJS_NATIVE_ENTER(context)
728
729 Entity *entity = nil;
730
731 if (JSValueToEntity(context, OOJS_ARGV[0], &entity))
732 {
734 if ([entity respondsToSelector:@selector(inspect)])
735 {
736 [entity inspect];
737 }
739 }
740
742
744}
745
746
747#if OO_DEBUG
748// function callObjC(selector : String [, ...]) : Object
749static JSBool ConsoleCallObjCMethod(JSContext *context, uintN argc, jsval *vp)
750{
751 OOJS_NATIVE_ENTER(context)
752
753 id object = nil;
754 jsval result;
755 BOOL OK;
756
757 object = OOJSNativeObjectFromJSObject(context, OOJS_THIS);
758 if (object == nil)
759 {
760 OOJSReportError(context, @"Attempt to call __callObjCMethod() for non-Objective-C object %@.", OOStringFromJSValueEvenIfNull(context, JS_THIS(context, vp)));
761 return NO;
762 }
763
765 result = JSVAL_VOID;
766 OK = OOJSCallObjCObjectMethod(context, object, [object oo_jsClassName], argc, OOJS_ARGV, &result);
768
769 OOJS_SET_RVAL(result);
770 return OK;
771
773}
774
775
776// function __setUpCallObjC(object) -- object is expected to be Object.prototye.
777static JSBool ConsoleSetUpCallObjC(JSContext *context, uintN argc, jsval *vp)
778{
779 OOJS_NATIVE_ENTER(context)
780
781 if (EXPECT_NOT(!JSVAL_IS_OBJECT(OOJS_ARGV[0])))
782 {
783 OOJSReportBadArguments(context, @"Console", @"__setUpCallObjC", argc, OOJS_ARGV, nil, @"Object.prototype");
784 return NO;
785 }
786
787 JSObject *obj = JSVAL_TO_OBJECT(OOJS_ARGV[0]);
788 JS_DefineFunction(context, obj, "callObjC", ConsoleCallObjCMethod, 1, OOJS_METHOD_READONLY);
790
792}
793#endif
794
795
796// function isExecutableJavaScript(this : Object, string : String) : Boolean
797static JSBool ConsoleIsExecutableJavaScript(JSContext *context, uintN argc, jsval *vp)
798{
799 OOJS_NATIVE_ENTER(context)
800
801 BOOL result = NO;
802 JSObject *target = NULL;
803
804 if (argc < 2 || !JS_ValueToObject(context, OOJS_ARGV[0], &target) || !JSVAL_IS_STRING(OOJS_ARGV[1]))
805 {
806 OOJS_RETURN_BOOL(NO); // Fail silently
807 }
808
809 // Not OOJS_BEGIN_FULL_NATIVE() - we use JSAPI while paused.
811
812 // FIXME: this must be possible using just JSAPI functions.
813 NSString *string = OOStringFromJSValue(context, OOJS_ARGV[1]);
814 NSData *stringData = [string dataUsingEncoding:NSUTF8StringEncoding];
815 result = JS_BufferIsCompilableUnit(context, target, [stringData bytes], [stringData length]);
816
818
819 OOJS_RETURN_BOOL(result);
820
822}
823
824
825// function displayMessagesInClass(class : String) : Boolean
826static JSBool ConsoleDisplayMessagesInClass(JSContext *context, uintN argc, jsval *vp)
827{
828 OOJS_NATIVE_ENTER(context)
829
830 NSString *messageClass = nil;
831
832 messageClass = OOStringFromJSValue(context, OOJS_ARGV[0]);
833 OOJS_RETURN_BOOL(messageClass != nil && OOLogWillDisplayMessagesInClass(messageClass));
834
836}
837
838
839// function setDisplayMessagesInClass(class : String, flag : Boolean) : void
840static JSBool ConsoleSetDisplayMessagesInClass(JSContext *context, uintN argc, jsval *vp)
841{
842 OOJS_NATIVE_ENTER(context)
843
844 NSString *messageClass = nil;
845 JSBool flag;
846
847 messageClass = OOStringFromJSValue(context, OOJS_ARGV[0]);
848 if (messageClass != nil && JS_ValueToBoolean(context, OOJS_ARGV[1], &flag))
849 {
850 OOLogSetDisplayMessagesInClass(messageClass, flag);
851 }
853
855}
856
857
858// function writeLogMarker() : void
859static JSBool ConsoleWriteLogMarker(JSContext *context, uintN argc, jsval *vp)
860{
861 OOJS_NATIVE_ENTER(context)
862
865
867}
868
869
870// function writeMemoryStats() : void
871static JSBool ConsoleWriteMemoryStats(JSContext *context, uintN argc, jsval *vp)
872{
873 OOJS_NATIVE_ENTER(context)
874
878
880
882}
883
884
885// function writeJSMemoryStats() : void
886static JSBool ConsoleWriteJSMemoryStats(JSContext *context, uintN argc, jsval *vp)
887{
888 OOJS_NATIVE_ENTER(context)
889
893
895
897}
898
899
900// function garbageCollect() : string
901static JSBool ConsoleGarbageCollect(JSContext *context, uintN argc, jsval *vp)
902{
903 OOJS_NATIVE_ENTER(context)
904
905 uint32_t bytesBefore = JS_GetGCParameter(JS_GetRuntime(context), JSGC_BYTES);
906 JS_GC(context);
907 uint32_t bytesAfter = JS_GetGCParameter(JS_GetRuntime(context), JSGC_BYTES);
908
909 OOJS_RETURN_OBJECT(([NSString stringWithFormat:@"Bytes before: %u Bytes after: %u", bytesBefore, bytesAfter]));
910
912}
913
914
915#if DEBUG
916typedef struct
917{
918 JSContext *context;
919 FILE *file;
920} DumpCallbackData;
921
922static void DumpCallback(const char *name, void *rp, JSGCRootType type, void *datap)
923{
924 assert(type == JS_GC_ROOT_VALUE_PTR || type == JS_GC_ROOT_GCTHING_PTR);
925
926 DumpCallbackData *data = datap;
927
928 const char *typeString = "unknown type";
929 jsval value;
930 switch (type)
931 {
932 case JS_GC_ROOT_VALUE_PTR:
933 typeString = "value";
934 value = *(jsval *)rp;
935 break;
936
937 case JS_GC_ROOT_GCTHING_PTR:
938 typeString = "gc-thing";
939 value = OBJECT_TO_JSVAL(*(JSObject **)rp);
940 }
941
942 fprintf(data->file, "%s @ %p (%s): %s\n", name, rp, typeString, [OOJSDescribeValue(data->context, value, NO) UTF8String]);
943}
944
945
946static JSBool ConsoleDumpNamedRoots(JSContext *context, uintN argc, jsval *vp)
947{
948 OOJS_NATIVE_ENTER(context)
949
950 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
951
952 BOOL OK = NO;
953 NSString *path = [[ResourceManager diagnosticFileLocation] stringByAppendingPathComponent:@"js-roots.txt"];
954 FILE *file = fopen([path UTF8String], "w");
955 if (file != NULL)
956 {
957 DumpCallbackData data =
958 {
959 .context = context,
960 .file = file
961 };
962 JS_DumpNamedRoots(JS_GetRuntime(context), DumpCallback, &data);
963 fclose(file);
964 OK = YES;
965 }
966
967 [pool release];
969
971}
972
973
974static JSBool ConsoleDumpHeap(JSContext *context, uintN argc, jsval *vp)
975{
976 OOJS_NATIVE_ENTER(context)
977
978 BOOL OK = NO;
979 NSString *path = [[ResourceManager diagnosticFileLocation] stringByAppendingPathComponent:@"js-heaps.txt"];
980 FILE *file = fopen([path UTF8String], "w");
981 if (file != NULL)
982 {
983 OK = JS_DumpHeap(context, file, NULL, 0, NULL, SIZE_MAX, NULL);
984 fclose(file);
985 }
986
988
990}
991#endif
992
993
994#if OOJS_PROFILE
995
996// function profile(func : function [, Object this = debugConsole.script]) : String
997static JSBool ConsoleProfile(JSContext *context, uintN argc, jsval *vp)
998{
999 OOJS_NATIVE_ENTER(context)
1000
1001 if (EXPECT_NOT(OOJSIsProfiling()))
1002 {
1003 OOJSReportError(context, @"Profiling functions may not be called while already profiling.");
1004 return NO;
1005 }
1006
1007 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1008 OOTimeProfile *profile = nil;
1009
1010 JSBool result = PerformProfiling(context, @"profile", argc, OOJS_ARGV, NULL, NO, &profile);
1011 if (result)
1012 {
1013 OOJS_SET_RVAL(OOJSValueFromNativeObject(context, [profile description]));
1014 }
1015
1016 [pool release];
1017 return result;
1018
1020}
1021
1022
1023// function getProfile(func : function [, Object this = debugConsole.script]) : Object { totalTime : Number, jsTime : Number, extensionTime : Number }
1024static JSBool ConsoleGetProfile(JSContext *context, uintN argc, jsval *vp)
1025{
1026 OOJS_NATIVE_ENTER(context)
1027
1028
1029 if (EXPECT_NOT(OOJSIsProfiling()))
1030 {
1031 OOJSReportError(context, @"Profiling functions may not be called while already profiling.");
1032 return NO;
1033 }
1034
1035 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1036 OOTimeProfile *profile = nil;
1037
1038 JSBool result = PerformProfiling(context, @"getProfile", argc, OOJS_ARGV, NULL, NO, &profile);
1039 if (result)
1040 {
1041 OOJS_SET_RVAL(OOJSValueFromNativeObject(context, profile));
1042 }
1043
1044 [pool release];
1045 return result;
1046
1048}
1049
1050
1051// function trace(func : function [, Object this = debugConsole.script]) : [return type of func]
1052static JSBool ConsoleTrace(JSContext *context, uintN argc, jsval *vp)
1053{
1054 OOJS_NATIVE_ENTER(context)
1055
1056 if (EXPECT_NOT(OOJSIsProfiling()))
1057 {
1058 OOJSReportError(context, @"Profiling functions may not be called while already profiling.");
1059 return NO;
1060 }
1061
1062 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1063 jsval rval;
1064
1065 JSBool result = PerformProfiling(context, @"trace", argc, OOJS_ARGV, &rval, YES, NULL);
1066 if (result)
1067 {
1068 OOJS_SET_RVAL(rval);
1069 }
1070
1071 [pool release];
1072 return result;
1073
1075}
1076
1077
1078static JSBool PerformProfiling(JSContext *context, NSString *nominalFunction, uintN argc, jsval *argv, jsval *outRval, BOOL trace, OOTimeProfile **outProfile)
1079{
1080 // Get function.
1081 jsval function = argv[0];
1082 if (!OOJSValueIsFunction(context, function))
1083 {
1084 OOJSReportBadArguments(context, @"Console", nominalFunction, 1, argv, nil, @"function");
1085 return NO;
1086 }
1087
1088 // Get "this" object.
1089 jsval this;
1090 if (argc > 1) this = argv[1];
1091 else
1092 {
1093 jsval debugConsole = OOJSValueFromNativeObject(context, [OODebugMonitor sharedDebugMonitor]);
1094 assert(JSVAL_IS_OBJECT(debugConsole) && !JSVAL_IS_NULL(debugConsole));
1095 JS_GetProperty(context, JSVAL_TO_OBJECT(debugConsole), "script", &this);
1096 }
1097
1098 JSObject *thisObj;
1099 if (!JS_ValueToObject(context, this, &thisObj)) thisObj = NULL;
1100
1101 jsval ignored;
1102 if (outRval == NULL) outRval = &ignored;
1103
1104 // Fiddle with time limiter.
1105 // We want to save the current limit, reset the limiter, and set the time limit to a long time.
1106#define LONG_TIME (1e7) // A long time - 115.7 days - but, crucially, finite.
1107
1108 OOTimeDelta originalLimit = OOJSGetTimeLimiterLimit();
1109 OOJSSetTimeLimiterLimit(LONG_TIME);
1111
1112 OOJSBeginProfiling(trace);
1113
1114 // Call the function.
1115 BOOL result = JS_CallFunctionValue(context, thisObj, function, 0, NULL, outRval);
1116
1117 // Get results.
1118 OOTimeProfile *profile = OOJSEndProfiling();
1119 if (outProfile != NULL) *outProfile = profile;
1120
1121 // Restore original timer state.
1122 OOJSSetTimeLimiterLimit(originalLimit);
1124
1125 JS_ReportPendingException(context);
1126
1127 return result;
1128}
1129
1130#endif // OOJS_PROFILE
1131
1132#endif /* OO_EXCLUDE_DEBUG_SUPPORT */
NSUInteger gDebugFlags
Definition main.m:7
OODebugFlags
Definition OODebugFlags.h:4
@ DEBUG_COLLISIONS
Definition OODebugFlags.h:7
@ DEBUG_NO_DUST
@ DEBUG_DOCKING
Definition OODebugFlags.h:8
@ DEBUG_SHADER_VALIDATION
@ DEBUG_MISC
@ DEBUG_OCTREE_LOGGING
Definition OODebugFlags.h:9
@ DEBUG_OCTREE_DRAW
@ DEBUG_NO_SHADER_FALLBACK
@ DEBUG_DRAW_NORMALS
@ DEBUG_LINKED_LISTS
Definition OODebugFlags.h:5
@ DEBUG_BOUNDING_BOXES
#define EXPECT_NOT(x)
#define GCC_ATTR(x)
BOOL OOJSCallObjCObjectMethod(JSContext *context, id object, NSString *oo_jsClassName, uintN argc, jsval *argv, jsval *outResult)
Definition OOJSCall.m:71
static JSFunctionSpec sConsoleMethods[]
static BOOL DoWeDefineAllDebugFlags(enum OODebugFlags flags) GCC_ATTR((unused))
static JSBool ConsoleIsExecutableJavaScript(JSContext *context, uintN argc, jsval *vp)
#define DEBUG_FLAG_CASE(x)
static JSObject * sConsolePrototype
Definition OOJSConsole.m:60
static void InitOOJSConsole(JSContext *context, JSObject *global)
static JSBool ConsoleWriteJSMemoryStats(JSContext *context, uintN argc, jsval *vp)
static JSBool ConsoleConsoleMessage(JSContext *context, uintN argc, jsval *vp)
static JSBool ConsoleSettingsSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value)
static JSBool ConsoleScriptStack(JSContext *context, uintN argc, jsval *vp)
static JSBool ConsoleGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
@ kConsole_detailLevel
@ kConsole_DEBUG_COLLISIONS
@ kConsole_platformDescription
@ kConsole_DEBUG_DRAW_NORMALS
@ kConsole_DEBUG_OCTREE_LOGGING
@ kConsole_glVendorString
@ kConsole_dumpStackForErrors
@ kConsole_dumpStackForWarnings
@ kConsole_showErrorLocations
@ kConsole_pedanticMode
@ kConsole_displayFPS
@ kConsole_ignoreDroppedPackets
@ kConsole_DEBUG_SHADER_VALIDATION
@ kConsole_DEBUG_NO_DUST
@ kConsole_DEBUG_OCTREE_DRAW
@ kConsole_DEBUG_BOUNDING_BOXES
@ kConsole_DEBUG_NO_SHADER_FALLBACK
@ kConsole_glRendererString
@ kConsole_maximumDetailLevel
@ kConsole_glFixedFunctionTextureUnitCount
@ kConsole_DEBUG_MISC
@ kConsole_glFragmentShaderTextureUnitCount
@ kConsole_DEBUG_DOCKING
@ kConsole_debugFlags
@ kConsole_DEBUG_LINKED_LISTS
static JSBool ConsoleGarbageCollect(JSContext *context, uintN argc, jsval *vp)
static JSBool ConsoleWriteMemoryStats(JSContext *context, uintN argc, jsval *vp)
static JSBool ConsoleDisplayMessagesInClass(JSContext *context, uintN argc, jsval *vp)
JSObject * DebugMonitorToJSConsole(JSContext *context, OODebugMonitor *monitor)
NSString * OOPlatformDescription(void)
static JSBool ConsoleSetDisplayMessagesInClass(JSContext *context, uintN argc, jsval *vp)
static JSClass sConsoleClass
static JSBool ConsoleSettingsGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
static JSBool ConsoleSettingsDeleteProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
static JSBool ConsoleInspectEntity(JSContext *context, uintN argc, jsval *vp)
static JSClass sConsoleSettingsClass
static JSBool ConsoleWriteLogMarker(JSContext *context, uintN argc, jsval *vp)
static JSPropertySpec sConsoleProperties[]
static JSBool ConsoleClearConsole(JSContext *context, uintN argc, jsval *vp)
static void ConsoleFinalize(JSContext *context, JSObject *this)
void OOJSConsoleDestroy(void)
#define DEBUG_FLAG_DECL(x)
static JSBool ConsoleSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value)
static JSObject * sConsoleSettingsPrototype
Definition OOJSConsole.m:61
#define OOJS_PROFILE_EXIT
#define OOJS_PROFILE_EXIT_VOID
#define OOJS_END_FULL_NATIVE
#define OOJS_BEGIN_FULL_NATIVE(context)
#define OOJS_NATIVE_ENTER(cx)
#define OOJS_NATIVE_EXIT
#define OOJS_PROFILE_ENTER
void OOJSResetTimeLimiter(void)
OOTimeDelta OOJSGetTimeLimiterLimit(void)
void OOJSSetTimeLimiterLimit(OOTimeDelta limit)
BOOL JSValueToEntity(JSContext *context, jsval value, Entity **outEntity)
Definition OOJSEntity.m:146
void OOJSPauseTimeLimiter(void)
id OOJSNativeObjectFromJSValue(JSContext *context, jsval value)
void OOJSReportWarning(JSContext *context, NSString *format,...)
#define OOJS_THIS
#define OOJS_SET_RVAL(v)
#define OOJS_PROP_READWRITE_CB
void OOJSRegisterObjectConverter(JSClass *theClass, OOJSClassConverterCallback converter)
OOINLINE jsval OOJSValueFromNativeObject(JSContext *context, id object)
id OOJSNativeObjectFromJSObject(JSContext *context, JSObject *object)
#define OOJS_RETURN_OBJECT(o)
void OOJSReportBadPropertySelector(JSContext *context, JSObject *thisObj, jsid propID, JSPropertySpec *propertySpec)
#define OOJS_RETURN_BOOL(v)
NSString * OOStringFromJSValue(JSContext *context, jsval value)
JSBool OOJSUnconstructableConstruct(JSContext *context, uintN argc, jsval *vp)
OOINLINE BOOL OOJSValueIsFunction(JSContext *context, jsval value)
NSString * OOJSDescribeValue(JSContext *context, jsval value, BOOL abbreviateObjects)
void OOJSReportError(JSContext *context, NSString *format,...)
#define OOJS_ARGV
OOINLINE jsval OOJSValueFromBOOL(int b) INLINE_CONST_FUNC
NSString * OOStringFromJSValueEvenIfNull(JSContext *context, jsval value)
id OOJSBasicPrivateObjectConverter(JSContext *context, JSObject *object)
void OOJSReportBadArguments(JSContext *context, NSString *scriptClass, NSString *function, uintN argc, jsval *argv, NSString *message, NSString *expectedArgsDescription)
#define OOJS_PROP_READONLY_CB
void OOJSResumeTimeLimiter(void)
#define OOJS_PROP_HIDDEN_READWRITE_CB
#define OOJS_RETURN_VOID
NSString * OOStringFromJSString(JSContext *context, JSString *string)
#define OOJS_METHOD_READONLY
id OOJSNativeObjectOfClassFromJSObject(JSContext *context, JSObject *object, Class requiredClass)
BOOL OOLogWillDisplayMessagesInClass(NSString *inMessageClass)
Definition OOLogging.m:144
void OOLogSetDisplayMessagesInClass(NSString *inClass, BOOL inFlag)
Definition OOLogging.m:182
void OOLogInsertMarker(void)
Definition OOLogging.m:632
return nil
double OOTimeDelta
Definition OOTypes.h:224
#define UNIVERSE
Definition Universe.h:833
void inspect()
void setTCPIgnoresDroppedPackets:(BOOL flag)
size_t dumpJSMemoryStatistics()
OODebugMonitor * sharedDebugMonitor()
void setDumpStackForWarnings:(BOOL value)
void setShowErrorLocations:(BOOL value)
OOJavaScriptEngine * sharedEngine()
void setDumpStackForErrors:(BOOL value)
OOOpenGLExtensionManager * sharedManager()
NSString * diagnosticFileLocation()