Oolite 1.91.0.7646-241128-10e222e
Loading...
Searching...
No Matches
OOJSEngineDebuggerHelpers.m
Go to the documentation of this file.
1/*
2
3OOJSEngineDebuggerHelpers.m
4
5JavaScript support for Oolite
6Copyright (C) 2007-2013 David Taylor and Jens Ayton.
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software
20Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21MA 02110-1301, USA.
22
23*/
24
25
26/*
27 These functions exist to help debugging JavaScript code. They can be called
28 directly from gdb, for example:
29
30 call (char *)JSValueToStrDbg(someValue)
31
32 The functions are:
33
34 const char *JSValueToStrDbg(jsval)
35 const char *JSObjectToStrDbg(JSObject *)
36 const char *JSStringToStrDbg(JSString *)
37 Converts any JS value/object/JSString to a string, using the complete
38 process and potentially calling into SpiderMonkey with a secondory
39 context and invoking JS toString() methods. This might mess up
40 SpiderMonkey internal state in some cases.
41
42 const char *JSValueToStrSafeDbg(jsval)
43 const char *JSObjectToStrSafeDbg(JSObject *)
44 const char *JSStringToStrSafeDbg(JSString *)
45 As above, but without calling into SpiderMonkey functions that require
46 a context. In particular, as of the FF4b9 version of SpiderMonkey only
47 interned strings can be converted, and for objects only the class name
48 is provided.
49
50 const char *JSIDToStrSafeDbg(jsid)
51 Like JSValueToStrSafeDbg() for jsids. (String jsids must always be
52 interned, so this is generally sufficient.)
53
54 const char *JSValueTypeDbg(jsval)
55 Returns the type of the jsval, or the class name if it's an object.
56
57 All dynamic strings are autoreleased.
58
59 Another useful function is OOJSDumpStack (results are found in the log):
60
61 call OOJSDumpStack(context)
62
63 A set of macros can be found in tools/gdb-macros.txt.
64 In almost all Oolite functions that deal with JavaScript, there is a single
65 JSContext called "context". In SpiderMonkey functions, it's called "cx".
66
67
68 In addition to calling them from the debug console, Xcode users might want
69 to use them in data formatters (by double-clicking the "Summary" field for
70 a variable of the appropriate type). I recommend the following:
71
72 jsval: {JSValueToStrSafeDbg($VAR)}:s
73 jsval*: {JSValueToStrSafeDbg(*$VAR)}:s
74 jsid: {JSIDToStrSafeDbg($VAR)}:s
75 JSObject*: {JSObjectToStrSafeDbg($VAR)}:s
76 JSString*: {JSStringToStrSafeDbg($VAR)}:s
77
78 These, and a variety of Oolite type formatters, can be set up using
79 Mac-specific/DataFormatters.
80*/
81
82
83#ifndef NDEBUG
84
86
87
88const char *JSValueToStrDbg(jsval val)
89{
90 JSContext *context = OOJSAcquireContext();
91 const char *result = [OOStringFromJSValueEvenIfNull(context, val) UTF8String];
92 OOJSRelinquishContext(context);
93
94 return result;
95}
96
97
98const char *JSObjectToStrDbg(JSObject *obj)
99{
100 if (obj == NULL) return "null";
101 return JSValueToStrDbg(OBJECT_TO_JSVAL(obj));
102}
103
104
105const char *JSStringToStrDbg(JSString *str)
106{
107 if (str == NULL) return "null";
108 return JSValueToStrDbg(STRING_TO_JSVAL(str));
109}
110
111
112const char *JSValueTypeDbg(jsval val)
113{
114 if (JSVAL_IS_INT(val)) return "integer";
115 if (JSVAL_IS_DOUBLE(val)) return "double";
116 if (JSVAL_IS_STRING(val)) return "string";
117 if (JSVAL_IS_BOOLEAN(val)) return "boolean";
118 if (JSVAL_IS_NULL(val)) return "null";
119 if (JSVAL_IS_VOID(val)) return "void";
120#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
121 if (JSVAL_IS_MAGIC_IMPL(val))
122 {
123 switch(val.s.payload.why)
124 {
125 case JS_ARRAY_HOLE: return "magic (array hole)";
126 case JS_ARGS_HOLE: return "magic (args hole)";
127 case JS_NATIVE_ENUMERATE: return "magic (native enumerate)";
128 case JS_NO_ITER_VALUE: return "magic (no iter value)";
129 case JS_GENERATOR_CLOSING: return "magic (generator closing)";
130 case JS_NO_CONSTANT: return "magic (no constant)";
131 case JS_THIS_POISON: return "magic (this poison)";
132 case JS_ARG_POISON: return "magic (arg poison)";
133 case JS_SERIALIZE_NO_NODE: return "magic (serialize no node)";
134 case JS_GENERIC_MAGIC: return "magic (generic)";
135 };
136 return "magic";
137 }
138#endif
139 if (JSVAL_IS_OBJECT(val)) return OOJSGetClass(NULL, JSVAL_TO_OBJECT(val))->name; // Fun fact: although a context is required if JS_THREADSAFE is defined, it isn't actually used.
140 return "unknown";
141}
142
143
144// Doesn't follow pointers, mess with requests or otherwise poke the SpiderMonkey.
145const char *JSValueToStrSafeDbg(jsval val)
146{
147 NSString *formatted = nil;
148
149 if (JSVAL_IS_INT(val)) formatted = [NSString stringWithFormat:@"%i", JSVAL_TO_INT(val)];
150 else if (JSVAL_IS_DOUBLE(val)) formatted = [NSString stringWithFormat:@"%g", JSVAL_TO_DOUBLE(val)];
151 else if (JSVAL_IS_BOOLEAN(val)) formatted = (JSVAL_TO_BOOLEAN(val)) ? @"true" : @"false";
152 else if (JSVAL_IS_STRING(val))
153 {
154 JSString *string = JSVAL_TO_STRING(val);
155 const jschar *chars = NULL;
156 size_t length = JS_GetStringLength(string);
157
158 if (JS_StringHasBeenInterned(string))
159 {
160 chars = JS_GetInternedStringChars(string);
161 }
162 // Flat strings can be extracted without a context, but cannot be detected.
163
164 if (chars == NULL) formatted = [NSString stringWithFormat:@"string [%zu chars]", length];
165 else formatted = [NSString stringWithCharacters:chars length:length];
166 }
167 else if (JSVAL_IS_VOID(val)) return "undefined";
168 else return JSValueTypeDbg(val);
169
170 return [formatted UTF8String];
171}
172
173
174const char *JSObjectToStrSafeDbg(JSObject *obj)
175{
176 if (obj == NULL) return "null";
177 return JSValueToStrSafeDbg(OBJECT_TO_JSVAL(obj));
178}
179
180
181const char *JSStringToStrSafeDbg(JSString *str)
182{
183 if (str == NULL) return "null";
184 return JSValueToStrSafeDbg(STRING_TO_JSVAL(str));
185}
186
187
188const char *JSIDToStrSafeDbg(jsid anID)
189{
190 NSString *formatted = nil;
191
192 if (JSID_IS_INT(anID)) formatted = [NSString stringWithFormat:@"%i", JSID_TO_INT(anID)];
193 else if (JSID_IS_VOID(anID)) return "void";
194 else if (JSID_IS_EMPTY(anID)) return "empty";
195 else if (JSID_IS_ZERO(anID)) return "0";
196 else if (JSID_IS_OBJECT(anID)) return OOJSGetClass(NULL, JSID_TO_OBJECT(anID))->name;
197 else if (JSID_IS_DEFAULT_XML_NAMESPACE(anID)) return "default XML namespace";
198 else if (JSID_IS_STRING(anID))
199 {
200 JSString *string = JSID_TO_STRING(anID);
201 const jschar *chars = NULL;
202 size_t length = JS_GetStringLength(string);
203
204 if (JS_StringHasBeenInterned(string))
205 {
206 chars = JS_GetInternedStringChars(string);
207 }
208 else
209 {
210 // Bug; jsid strings must be interned.
211 return "*** uninterned string in jsid! ***";
212 }
213 formatted = [NSString stringWithCharacters:chars length:length];
214 }
215 else
216 {
217 formatted = [NSString stringWithFormat:@"unknown <0x%llX>", (long long)JSID_BITS(anID)];
218 }
219
220 return [formatted UTF8String];
221}
222#endif
const char * JSValueToStrSafeDbg(jsval val)
const char * JSStringToStrDbg(JSString *str)
const char * JSValueToStrDbg(jsval val)
const char * JSObjectToStrSafeDbg(JSObject *obj)
const char * JSStringToStrSafeDbg(JSString *str)
const char * JSIDToStrSafeDbg(jsid anID)
const char * JSObjectToStrDbg(JSObject *obj)
const char * JSValueTypeDbg(jsval val)
OOINLINE JSContext * OOJSAcquireContext(void)
OOINLINE void OOJSRelinquishContext(JSContext *context)
OOINLINE JSClass * OOJSGetClass(JSContext *cx, JSObject *obj) ALWAYS_INLINE_FUNC
return nil