1 |
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 |
* vim: set ts=8 sw=4 et tw=80: |
3 |
* |
4 |
* ***** BEGIN LICENSE BLOCK ***** |
5 |
* Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
6 |
* |
7 |
* The contents of this file are subject to the Mozilla Public License Version |
8 |
* 1.1 (the "License"); you may not use this file except in compliance with |
9 |
* the License. You may obtain a copy of the License at |
10 |
* http://www.mozilla.org/MPL/ |
11 |
* |
12 |
* Software distributed under the License is distributed on an "AS IS" basis, |
13 |
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
14 |
* for the specific language governing rights and limitations under the |
15 |
* License. |
16 |
* |
17 |
* Copyright (C) 2007 Sun Microsystems, Inc. All Rights Reserved. |
18 |
* |
19 |
* Contributor(s): |
20 |
* Brendan Eich <brendan@mozilla.org> |
21 |
* |
22 |
* Alternatively, the contents of this file may be used under the terms of |
23 |
* either of the GNU General Public License Version 2 or later (the "GPL"), |
24 |
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
25 |
* in which case the provisions of the GPL or the LGPL are applicable instead |
26 |
* of those above. If you wish to allow use of your version of this file only |
27 |
* under the terms of either the GPL or the LGPL, and not to allow others to |
28 |
* use your version of this file under the terms of the MPL, indicate your |
29 |
* decision by deleting the provisions above and replace them with the notice |
30 |
* and other provisions required by the GPL or the LGPL. If you do not delete |
31 |
* the provisions above, a recipient may use your version of this file under |
32 |
* the terms of any one of the MPL, the GPL or the LGPL. |
33 |
* |
34 |
* ***** END LICENSE BLOCK ***** */ |
35 |
|
36 |
#include "jsapi.h" |
37 |
#include "jsutil.h" |
38 |
#include "jsatom.h" |
39 |
#include "jscntxt.h" |
40 |
#include "jsdbgapi.h" |
41 |
#include "jsfun.h" |
42 |
#include "jsinterp.h" |
43 |
#include "jsobj.h" |
44 |
#include "jsscript.h" |
45 |
#include "jsstr.h" |
46 |
|
47 |
#include "jsdtracef.h" |
48 |
#include <sys/types.h> |
49 |
|
50 |
#define TYPEOF(cx,v) (JSVAL_IS_NULL(v) ? JSTYPE_NULL : JS_TypeOfValue(cx,v)) |
51 |
|
52 |
static char dempty[] = "<null>"; |
53 |
|
54 |
static char * |
55 |
jsdtrace_fun_classname(JSFunction *fun) |
56 |
{ |
57 |
return (fun && |
58 |
!FUN_INTERPRETED(fun) && |
59 |
!(fun->flags & JSFUN_TRCINFO) && |
60 |
FUN_CLASP(fun)) |
61 |
? (char *)FUN_CLASP(fun)->name |
62 |
: dempty; |
63 |
} |
64 |
|
65 |
static char * |
66 |
jsdtrace_filename(JSStackFrame *fp) |
67 |
{ |
68 |
return (fp && fp->script && fp->script->filename) |
69 |
? (char *)fp->script->filename |
70 |
: dempty; |
71 |
} |
72 |
|
73 |
static int |
74 |
jsdtrace_fun_linenumber(JSContext *cx, JSFunction *fun) |
75 |
{ |
76 |
if (fun && FUN_INTERPRETED(fun)) |
77 |
return (int) JS_GetScriptBaseLineNumber(cx, FUN_SCRIPT(fun)); |
78 |
|
79 |
return 0; |
80 |
} |
81 |
|
82 |
int |
83 |
jsdtrace_frame_linenumber(JSContext *cx, JSStackFrame *fp) |
84 |
{ |
85 |
if (fp && fp->regs) |
86 |
return (int) js_FramePCToLineNumber(cx, fp); |
87 |
|
88 |
return 0; |
89 |
} |
90 |
|
91 |
/* |
92 |
* This function is used to convert function arguments and return value (jsval) |
93 |
* into the following based on each value's type tag: |
94 |
* |
95 |
* jsval returned |
96 |
* ------------------- |
97 |
* STRING -> char * |
98 |
* INT -> int |
99 |
* DOUBLE -> double * |
100 |
* BOOLEAN -> int |
101 |
* OBJECT -> void * |
102 |
* |
103 |
* All are presented as void * for DTrace consumers to use, after shifting or |
104 |
* masking out the JavaScript type bits. This allows D scripts to use ints and |
105 |
* booleans directly and copyinstr() for string arguments, when types are known |
106 |
* beforehand. |
107 |
* |
108 |
* This is used by the function-args and function-rval probes, which also |
109 |
* provide raw (unmasked) jsvals should type info be useful from D scripts. |
110 |
*/ |
111 |
static void * |
112 |
jsdtrace_jsvaltovoid(JSContext *cx, jsval argval) |
113 |
{ |
114 |
JSType type = TYPEOF(cx, argval); |
115 |
|
116 |
switch (type) { |
117 |
case JSTYPE_NULL: |
118 |
case JSTYPE_VOID: |
119 |
return (void *)JS_TYPE_STR(type); |
120 |
|
121 |
case JSTYPE_BOOLEAN: |
122 |
return (void *)JSVAL_TO_BOOLEAN(argval); |
123 |
|
124 |
case JSTYPE_STRING: |
125 |
return (void *)js_GetStringBytes(cx, JSVAL_TO_STRING(argval)); |
126 |
|
127 |
case JSTYPE_NUMBER: |
128 |
if (JSVAL_IS_INT(argval)) |
129 |
return (void *)JSVAL_TO_INT(argval); |
130 |
return JSVAL_TO_DOUBLE(argval); |
131 |
|
132 |
default: |
133 |
return JSVAL_TO_GCTHING(argval); |
134 |
} |
135 |
/* NOTREACHED */ |
136 |
} |
137 |
|
138 |
static char * |
139 |
jsdtrace_fun_name(JSContext *cx, JSFunction *fun) |
140 |
{ |
141 |
JSAtom *atom; |
142 |
char *name; |
143 |
|
144 |
if (!fun) |
145 |
return dempty; |
146 |
|
147 |
atom = fun->atom; |
148 |
if (!atom) { |
149 |
/* |
150 |
* TODO: maybe do more work here to figure out the name of the property |
151 |
* or variable that held the anonymous function that we're calling, if anyone |
152 |
* cares; an easy workaround is to just give your anonymous functions names. |
153 |
*/ |
154 |
return dempty; |
155 |
} |
156 |
|
157 |
name = (char *)js_GetStringBytes(cx, ATOM_TO_STRING(atom)); |
158 |
return name ? name : dempty; |
159 |
} |
160 |
|
161 |
/* |
162 |
* These functions call the DTrace macros for the JavaScript USDT probes. |
163 |
* Originally this code was inlined in the JavaScript code; however since |
164 |
* a number of operations are called, these have been placed into functions |
165 |
* to reduce any negative compiler optimization effect that the addition of |
166 |
* a number of usually unused lines of code would cause. |
167 |
*/ |
168 |
void |
169 |
jsdtrace_function_entry(JSContext *cx, JSStackFrame *fp, JSFunction *fun) |
170 |
{ |
171 |
JAVASCRIPT_FUNCTION_ENTRY( |
172 |
jsdtrace_filename(fp), |
173 |
jsdtrace_fun_classname(fun), |
174 |
jsdtrace_fun_name(cx, fun) |
175 |
); |
176 |
} |
177 |
|
178 |
void |
179 |
jsdtrace_function_info(JSContext *cx, JSStackFrame *fp, JSStackFrame *dfp, |
180 |
JSFunction *fun) |
181 |
{ |
182 |
JAVASCRIPT_FUNCTION_INFO( |
183 |
jsdtrace_filename(fp), |
184 |
jsdtrace_fun_classname(fun), |
185 |
jsdtrace_fun_name(cx, fun), |
186 |
jsdtrace_fun_linenumber(cx, fun), |
187 |
jsdtrace_filename(dfp), |
188 |
jsdtrace_frame_linenumber(cx, dfp) |
189 |
); |
190 |
} |
191 |
|
192 |
void |
193 |
jsdtrace_function_args(JSContext *cx, JSStackFrame *fp, JSFunction *fun, jsuint argc, jsval *argv) |
194 |
{ |
195 |
JAVASCRIPT_FUNCTION_ARGS( |
196 |
jsdtrace_filename(fp), |
197 |
jsdtrace_fun_classname(fun), |
198 |
jsdtrace_fun_name(cx, fun), |
199 |
argc, (void *)argv, |
200 |
(argc > 0) ? jsdtrace_jsvaltovoid(cx, argv[0]) : 0, |
201 |
(argc > 1) ? jsdtrace_jsvaltovoid(cx, argv[1]) : 0, |
202 |
(argc > 2) ? jsdtrace_jsvaltovoid(cx, argv[2]) : 0, |
203 |
(argc > 3) ? jsdtrace_jsvaltovoid(cx, argv[3]) : 0, |
204 |
(argc > 4) ? jsdtrace_jsvaltovoid(cx, argv[4]) : 0 |
205 |
); |
206 |
} |
207 |
|
208 |
void |
209 |
jsdtrace_function_rval(JSContext *cx, JSStackFrame *fp, JSFunction *fun, jsval *rval) |
210 |
{ |
211 |
JAVASCRIPT_FUNCTION_RVAL( |
212 |
jsdtrace_filename(fp), |
213 |
jsdtrace_fun_classname(fun), |
214 |
jsdtrace_fun_name(cx, fun), |
215 |
jsdtrace_fun_linenumber(cx, fun), |
216 |
(void *)rval, |
217 |
jsdtrace_jsvaltovoid(cx, *rval) |
218 |
); |
219 |
} |
220 |
|
221 |
void |
222 |
jsdtrace_function_return(JSContext *cx, JSStackFrame *fp, JSFunction *fun) |
223 |
{ |
224 |
JAVASCRIPT_FUNCTION_RETURN( |
225 |
jsdtrace_filename(fp), |
226 |
jsdtrace_fun_classname(fun), |
227 |
jsdtrace_fun_name(cx, fun) |
228 |
); |
229 |
} |
230 |
|
231 |
void |
232 |
jsdtrace_object_create_start(JSStackFrame *fp, JSClass *clasp) |
233 |
{ |
234 |
JAVASCRIPT_OBJECT_CREATE_START(jsdtrace_filename(fp), (char *)clasp->name); |
235 |
} |
236 |
|
237 |
void |
238 |
jsdtrace_object_create_done(JSStackFrame *fp, JSClass *clasp) |
239 |
{ |
240 |
JAVASCRIPT_OBJECT_CREATE_DONE(jsdtrace_filename(fp), (char *)clasp->name); |
241 |
} |
242 |
|
243 |
void |
244 |
jsdtrace_object_create(JSContext *cx, JSClass *clasp, JSObject *obj) |
245 |
{ |
246 |
JAVASCRIPT_OBJECT_CREATE( |
247 |
jsdtrace_filename(cx->fp), |
248 |
(char *)clasp->name, |
249 |
(uintptr_t)obj, |
250 |
jsdtrace_frame_linenumber(cx, cx->fp) |
251 |
); |
252 |
} |
253 |
|
254 |
void |
255 |
jsdtrace_object_finalize(JSObject *obj) |
256 |
{ |
257 |
JSClass *clasp; |
258 |
|
259 |
clasp = obj->getClass(); |
260 |
|
261 |
/* the first arg is NULL - reserved for future use (filename?) */ |
262 |
JAVASCRIPT_OBJECT_FINALIZE(NULL, (char *)clasp->name, (uintptr_t)obj); |
263 |
} |
264 |
|
265 |
void |
266 |
jsdtrace_execute_start(JSScript *script) |
267 |
{ |
268 |
JAVASCRIPT_EXECUTE_START( |
269 |
script->filename ? (char *)script->filename : dempty, |
270 |
script->lineno |
271 |
); |
272 |
} |
273 |
|
274 |
void |
275 |
jsdtrace_execute_done(JSScript *script) |
276 |
{ |
277 |
JAVASCRIPT_EXECUTE_DONE( |
278 |
script->filename ? (char *)script->filename : dempty, |
279 |
script->lineno |
280 |
); |
281 |
} |