1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sw=4 et tw=99:
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 : * The Original Code is Mozilla Communicator client code, released
18 : * March 31, 1998.
19 : *
20 : * The Initial Developer of the Original Code is
21 : * Netscape Communications Corporation.
22 : * Portions created by the Initial Developer are Copyright (C) 1998
23 : * the Initial Developer. All Rights Reserved.
24 : *
25 : * Contributor(s):
26 : * Nick Fitzgerald <nfitzgerald@mozilla.com>
27 : *
28 : * Alternatively, the contents of this file may be used under the terms of
29 : * either of the GNU General Public License Version 2 or later (the "GPL"),
30 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 : * in which case the provisions of the GPL or the LGPL are applicable instead
32 : * of those above. If you wish to allow use of your version of this file only
33 : * under the terms of either the GPL or the LGPL, and not to allow others to
34 : * use your version of this file under the terms of the MPL, indicate your
35 : * decision by deleting the provisions above and replace them with the notice
36 : * and other provisions required by the GPL or the LGPL. If you do not delete
37 : * the provisions above, a recipient may use your version of this file under
38 : * the terms of any one of the MPL, the GPL or the LGPL.
39 : *
40 : * ***** END LICENSE BLOCK ***** */
41 :
42 : /*
43 : * JS debugging API.
44 : */
45 : #include <string.h>
46 : #include <stdarg.h>
47 : #include "jsprvtd.h"
48 : #include "jstypes.h"
49 : #include "jsutil.h"
50 : #include "jsclist.h"
51 : #include "jsapi.h"
52 : #include "jscntxt.h"
53 : #include "jsversion.h"
54 : #include "jsdbgapi.h"
55 : #include "jsfun.h"
56 : #include "jsgc.h"
57 : #include "jsgcmark.h"
58 : #include "jsinterp.h"
59 : #include "jslock.h"
60 : #include "jsobj.h"
61 : #include "jsopcode.h"
62 : #include "jsscope.h"
63 : #include "jsscript.h"
64 : #include "jsstr.h"
65 : #include "jswatchpoint.h"
66 : #include "jswrapper.h"
67 :
68 : #include "frontend/BytecodeEmitter.h"
69 : #include "frontend/Parser.h"
70 : #include "vm/Debugger.h"
71 :
72 : #include "jsatominlines.h"
73 : #include "jsinferinlines.h"
74 : #include "jsobjinlines.h"
75 : #include "jsinterpinlines.h"
76 : #include "jsscopeinlines.h"
77 : #include "jsscriptinlines.h"
78 :
79 : #include "vm/Stack-inl.h"
80 :
81 : #include "jsautooplen.h"
82 :
83 : #ifdef __APPLE__
84 : #include "sharkctl.h"
85 : #endif
86 :
87 : using namespace js;
88 : using namespace js::gc;
89 :
90 : JS_PUBLIC_API(JSBool)
91 1350 : JS_GetDebugMode(JSContext *cx)
92 : {
93 1350 : return cx->compartment->debugMode();
94 : }
95 :
96 : JS_PUBLIC_API(JSBool)
97 6852 : JS_SetDebugMode(JSContext *cx, JSBool debug)
98 : {
99 6852 : return JS_SetDebugModeForCompartment(cx, cx->compartment, debug);
100 : }
101 :
102 : JS_PUBLIC_API(void)
103 6847 : JS_SetRuntimeDebugMode(JSRuntime *rt, JSBool debug)
104 : {
105 6847 : rt->debugMode = !!debug;
106 6847 : }
107 :
108 : namespace js {
109 :
110 : JSTrapStatus
111 15284752 : ScriptDebugPrologue(JSContext *cx, StackFrame *fp)
112 : {
113 15284752 : JS_ASSERT(fp == cx->fp());
114 :
115 15284752 : if (fp->isFramePushedByExecute()) {
116 63600 : if (JSInterpreterHook hook = cx->runtime->debugHooks.executeHook)
117 5101 : fp->setHookData(hook(cx, Jsvalify(fp), true, 0, cx->runtime->debugHooks.executeHookData));
118 : } else {
119 15221152 : if (JSInterpreterHook hook = cx->runtime->debugHooks.callHook)
120 2895817 : fp->setHookData(hook(cx, Jsvalify(fp), true, 0, cx->runtime->debugHooks.callHookData));
121 : }
122 :
123 : Value rval;
124 15284752 : JSTrapStatus status = Debugger::onEnterFrame(cx, &rval);
125 15284752 : switch (status) {
126 : case JSTRAP_CONTINUE:
127 15282631 : break;
128 : case JSTRAP_THROW:
129 27 : cx->setPendingException(rval);
130 27 : break;
131 : case JSTRAP_ERROR:
132 2049 : cx->clearPendingException();
133 2049 : break;
134 : case JSTRAP_RETURN:
135 45 : fp->setReturnValue(rval);
136 45 : break;
137 : default:
138 0 : JS_NOT_REACHED("bad Debugger::onEnterFrame JSTrapStatus value");
139 : }
140 15284752 : return status;
141 : }
142 :
143 : bool
144 15285465 : ScriptDebugEpilogue(JSContext *cx, StackFrame *fp, bool okArg)
145 : {
146 15285465 : JS_ASSERT(fp == cx->fp());
147 15285465 : JSBool ok = okArg;
148 :
149 15285465 : if (void *hookData = fp->maybeHookData()) {
150 2900900 : if (fp->isFramePushedByExecute()) {
151 5101 : if (JSInterpreterHook hook = cx->runtime->debugHooks.executeHook)
152 5101 : hook(cx, Jsvalify(fp), false, &ok, hookData);
153 : } else {
154 2895799 : if (JSInterpreterHook hook = cx->runtime->debugHooks.callHook)
155 2895799 : hook(cx, Jsvalify(fp), false, &ok, hookData);
156 : }
157 : }
158 :
159 15285465 : return Debugger::onLeaveFrame(cx, ok);
160 : }
161 :
162 : } /* namespace js */
163 :
164 : JS_FRIEND_API(JSBool)
165 7413 : JS_SetDebugModeForCompartment(JSContext *cx, JSCompartment *comp, JSBool debug)
166 : {
167 7413 : return comp->setDebugModeFromC(cx, !!debug);
168 : }
169 :
170 : static JSBool
171 1350 : CheckDebugMode(JSContext *cx)
172 : {
173 1350 : JSBool debugMode = JS_GetDebugMode(cx);
174 : /*
175 : * :TODO:
176 : * This probably should be an assertion, since it's indicative of a severe
177 : * API misuse.
178 : */
179 1350 : if (!debugMode) {
180 : JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage,
181 0 : NULL, JSMSG_NEED_DEBUG_MODE);
182 : }
183 1350 : return debugMode;
184 : }
185 :
186 : JS_PUBLIC_API(JSBool)
187 1 : JS_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep)
188 : {
189 1 : assertSameCompartment(cx, script);
190 1 : if (!CheckDebugMode(cx))
191 0 : return JS_FALSE;
192 :
193 1 : return script->setStepModeFlag(cx, singleStep);
194 : }
195 :
196 : JS_PUBLIC_API(JSBool)
197 377 : JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc, JSTrapHandler handler, jsval closure)
198 : {
199 377 : assertSameCompartment(cx, script, closure);
200 :
201 377 : if (!CheckDebugMode(cx))
202 0 : return false;
203 :
204 377 : BreakpointSite *site = script->getOrCreateBreakpointSite(cx, pc, NULL);
205 377 : if (!site)
206 0 : return false;
207 377 : site->setTrap(cx, handler, closure);
208 377 : return true;
209 : }
210 :
211 : JS_PUBLIC_API(void)
212 36 : JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
213 : JSTrapHandler *handlerp, jsval *closurep)
214 : {
215 36 : if (BreakpointSite *site = script->getBreakpointSite(pc)) {
216 27 : site->clearTrap(cx, handlerp, closurep);
217 : } else {
218 9 : if (handlerp)
219 0 : *handlerp = NULL;
220 9 : if (closurep)
221 0 : *closurep = JSVAL_VOID;
222 : }
223 36 : }
224 :
225 : JS_PUBLIC_API(void)
226 1741059 : JS_ClearScriptTraps(JSContext *cx, JSScript *script)
227 : {
228 1741059 : script->clearTraps(cx);
229 1741059 : }
230 :
231 : JS_PUBLIC_API(void)
232 0 : JS_ClearAllTrapsForCompartment(JSContext *cx)
233 : {
234 0 : cx->compartment->clearTraps(cx);
235 0 : }
236 :
237 : JS_PUBLIC_API(JSBool)
238 1 : JS_SetInterrupt(JSRuntime *rt, JSInterruptHook hook, void *closure)
239 : {
240 1 : rt->debugHooks.interruptHook = hook;
241 1 : rt->debugHooks.interruptHookData = closure;
242 1 : return JS_TRUE;
243 : }
244 :
245 : JS_PUBLIC_API(JSBool)
246 282 : JS_ClearInterrupt(JSRuntime *rt, JSInterruptHook *hoop, void **closurep)
247 : {
248 282 : if (hoop)
249 0 : *hoop = rt->debugHooks.interruptHook;
250 282 : if (closurep)
251 0 : *closurep = rt->debugHooks.interruptHookData;
252 282 : rt->debugHooks.interruptHook = 0;
253 282 : rt->debugHooks.interruptHookData = 0;
254 282 : return JS_TRUE;
255 : }
256 :
257 : /************************************************************************/
258 :
259 : JS_PUBLIC_API(JSBool)
260 3630 : JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id,
261 : JSWatchPointHandler handler, JSObject *closure)
262 : {
263 3630 : assertSameCompartment(cx, obj);
264 3630 : id = js_CheckForStringIndex(id);
265 :
266 : JSObject *origobj;
267 : Value v;
268 : unsigned attrs;
269 : jsid propid;
270 :
271 3630 : origobj = obj;
272 3630 : OBJ_TO_INNER_OBJECT(cx, obj);
273 3630 : if (!obj)
274 0 : return false;
275 :
276 7260 : AutoValueRooter idroot(cx);
277 3630 : if (JSID_IS_INT(id)) {
278 0 : propid = id;
279 3630 : } else if (JSID_IS_OBJECT(id)) {
280 0 : JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH_PROP);
281 0 : return false;
282 : } else {
283 3630 : if (!js_ValueToStringId(cx, IdToValue(id), &propid))
284 0 : return false;
285 3630 : propid = js_CheckForStringIndex(propid);
286 3630 : idroot.set(IdToValue(propid));
287 : }
288 :
289 : /*
290 : * If, by unwrapping and innerizing, we changed the object, check
291 : * again to make sure that we're allowed to set a watch point.
292 : */
293 3630 : if (origobj != obj && !CheckAccess(cx, obj, propid, JSACC_WATCH, &v, &attrs))
294 0 : return false;
295 :
296 3630 : if (!obj->isNative()) {
297 : JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH,
298 0 : obj->getClass()->name);
299 0 : return false;
300 : }
301 :
302 3630 : types::MarkTypePropertyConfigured(cx, obj, propid);
303 :
304 3630 : WatchpointMap *wpmap = cx->compartment->watchpointMap;
305 3630 : if (!wpmap) {
306 225 : wpmap = cx->runtime->new_<WatchpointMap>();
307 225 : if (!wpmap || !wpmap->init()) {
308 0 : js_ReportOutOfMemory(cx);
309 0 : return false;
310 : }
311 225 : cx->compartment->watchpointMap = wpmap;
312 : }
313 3630 : return wpmap->watch(cx, obj, propid, handler, closure);
314 : }
315 :
316 : JS_PUBLIC_API(JSBool)
317 945 : JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsid id,
318 : JSWatchPointHandler *handlerp, JSObject **closurep)
319 : {
320 945 : assertSameCompartment(cx, obj, id);
321 :
322 945 : id = js_CheckForStringIndex(id);
323 945 : if (WatchpointMap *wpmap = cx->compartment->watchpointMap)
324 9 : wpmap->unwatch(obj, id, handlerp, closurep);
325 945 : return true;
326 : }
327 :
328 : JS_PUBLIC_API(JSBool)
329 0 : JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj)
330 : {
331 0 : assertSameCompartment(cx, obj);
332 :
333 0 : if (WatchpointMap *wpmap = cx->compartment->watchpointMap)
334 0 : wpmap->unwatchObject(obj);
335 0 : return true;
336 : }
337 :
338 : JS_PUBLIC_API(JSBool)
339 19908 : JS_ClearAllWatchPoints(JSContext *cx)
340 : {
341 19908 : if (JSCompartment *comp = cx->compartment) {
342 18505 : if (WatchpointMap *wpmap = comp->watchpointMap)
343 216 : wpmap->clear();
344 : }
345 19908 : return true;
346 : }
347 :
348 : /************************************************************************/
349 :
350 : JS_PUBLIC_API(unsigned)
351 1498606 : JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
352 : {
353 1498606 : return js::PCToLineNumber(script, pc);
354 : }
355 :
356 : JS_PUBLIC_API(jsbytecode *)
357 18 : JS_LineNumberToPC(JSContext *cx, JSScript *script, unsigned lineno)
358 : {
359 18 : return js_LineNumberToPC(script, lineno);
360 : }
361 :
362 : JS_PUBLIC_API(jsbytecode *)
363 0 : JS_EndPC(JSContext *cx, JSScript *script)
364 : {
365 0 : return script->code + script->length;
366 : }
367 :
368 : JS_PUBLIC_API(JSBool)
369 0 : JS_GetLinePCs(JSContext *cx, JSScript *script,
370 : unsigned startLine, unsigned maxLines,
371 : unsigned* count, unsigned** retLines, jsbytecode*** retPCs)
372 : {
373 : unsigned* lines;
374 : jsbytecode** pcs;
375 0 : size_t len = (script->length > maxLines ? maxLines : script->length);
376 0 : lines = (unsigned*) cx->malloc_(len * sizeof(unsigned));
377 0 : if (!lines)
378 0 : return JS_FALSE;
379 :
380 0 : pcs = (jsbytecode**) cx->malloc_(len * sizeof(jsbytecode*));
381 0 : if (!pcs) {
382 0 : cx->free_(lines);
383 0 : return JS_FALSE;
384 : }
385 :
386 0 : unsigned lineno = script->lineno;
387 0 : unsigned offset = 0;
388 0 : unsigned i = 0;
389 0 : for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
390 0 : offset += SN_DELTA(sn);
391 0 : SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
392 0 : if (type == SRC_SETLINE || type == SRC_NEWLINE) {
393 0 : if (type == SRC_SETLINE)
394 0 : lineno = (unsigned) js_GetSrcNoteOffset(sn, 0);
395 : else
396 0 : lineno++;
397 :
398 0 : if (lineno >= startLine) {
399 0 : lines[i] = lineno;
400 0 : pcs[i] = script->code + offset;
401 0 : if (++i >= maxLines)
402 0 : break;
403 : }
404 : }
405 : }
406 :
407 0 : *count = i;
408 0 : if (retLines)
409 0 : *retLines = lines;
410 : else
411 0 : cx->free_(lines);
412 :
413 0 : if (retPCs)
414 0 : *retPCs = pcs;
415 : else
416 0 : cx->free_(pcs);
417 :
418 0 : return JS_TRUE;
419 : }
420 :
421 : JS_PUBLIC_API(unsigned)
422 0 : JS_GetFunctionArgumentCount(JSContext *cx, JSFunction *fun)
423 : {
424 0 : return fun->nargs;
425 : }
426 :
427 : JS_PUBLIC_API(JSBool)
428 0 : JS_FunctionHasLocalNames(JSContext *cx, JSFunction *fun)
429 : {
430 0 : return fun->script()->bindings.hasLocalNames();
431 : }
432 :
433 : extern JS_PUBLIC_API(uintptr_t *)
434 0 : JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **markp)
435 : {
436 0 : Vector<JSAtom *> localNames(cx);
437 0 : if (!fun->script()->bindings.getLocalNameArray(cx, &localNames))
438 0 : return NULL;
439 :
440 : /* Munge data into the API this method implements. Avert your eyes! */
441 0 : *markp = cx->tempLifoAlloc().mark();
442 :
443 0 : uintptr_t *names = cx->tempLifoAlloc().newArray<uintptr_t>(localNames.length());
444 0 : if (!names) {
445 0 : js_ReportOutOfMemory(cx);
446 0 : return NULL;
447 : }
448 :
449 : JS_ASSERT(sizeof(*names) == sizeof(*localNames.begin()));
450 0 : js_memcpy(names, localNames.begin(), localNames.length() * sizeof(*names));
451 0 : return names;
452 : }
453 :
454 : extern JS_PUBLIC_API(JSAtom *)
455 0 : JS_LocalNameToAtom(uintptr_t w)
456 : {
457 0 : return JS_LOCAL_NAME_TO_ATOM(w);
458 : }
459 :
460 : extern JS_PUBLIC_API(JSString *)
461 0 : JS_AtomKey(JSAtom *atom)
462 : {
463 0 : return atom;
464 : }
465 :
466 : extern JS_PUBLIC_API(void)
467 0 : JS_ReleaseFunctionLocalNameArray(JSContext *cx, void *mark)
468 : {
469 0 : cx->tempLifoAlloc().release(mark);
470 0 : }
471 :
472 : JS_PUBLIC_API(JSScript *)
473 1867666 : JS_GetFunctionScript(JSContext *cx, JSFunction *fun)
474 : {
475 1867666 : return fun->maybeScript();
476 : }
477 :
478 : JS_PUBLIC_API(JSNative)
479 0 : JS_GetFunctionNative(JSContext *cx, JSFunction *fun)
480 : {
481 0 : return fun->maybeNative();
482 : }
483 :
484 : JS_PUBLIC_API(JSPrincipals *)
485 230417 : JS_GetScriptPrincipals(JSContext *cx, JSScript *script)
486 : {
487 230417 : return script->principals;
488 : }
489 :
490 : JS_PUBLIC_API(JSPrincipals *)
491 40 : JS_GetScriptOriginPrincipals(JSContext *cx, JSScript *script)
492 : {
493 40 : return script->originPrincipals;
494 : }
495 :
496 : /************************************************************************/
497 :
498 : /*
499 : * Stack Frame Iterator
500 : */
501 : JS_PUBLIC_API(JSStackFrame *)
502 5042415 : JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
503 : {
504 5042415 : StackFrame *fp = Valueify(*iteratorp);
505 5042415 : *iteratorp = Jsvalify((fp == NULL) ? js_GetTopStackFrame(cx, FRAME_EXPAND_ALL) : fp->prev());
506 5042415 : return *iteratorp;
507 : }
508 :
509 : JS_PUBLIC_API(JSScript *)
510 3595737 : JS_GetFrameScript(JSContext *cx, JSStackFrame *fp)
511 : {
512 3595737 : return Valueify(fp)->maybeScript();
513 : }
514 :
515 : JS_PUBLIC_API(jsbytecode *)
516 1496576 : JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
517 : {
518 1496576 : return Valueify(fp)->pcQuadratic(cx->stack);
519 : }
520 :
521 : JS_PUBLIC_API(void *)
522 410104 : JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fpArg)
523 : {
524 410104 : StackFrame *fp = Valueify(fpArg);
525 410104 : if (fp->annotation() && fp->isScriptFrame()) {
526 0 : JSPrincipals *principals = fp->scopeChain().principals(cx);
527 :
528 0 : if (principals) {
529 : /*
530 : * Give out an annotation only if privileges have not been revoked
531 : * or disabled globally.
532 : */
533 0 : return fp->annotation();
534 : }
535 : }
536 :
537 410104 : return NULL;
538 : }
539 :
540 : JS_PUBLIC_API(void)
541 0 : JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation)
542 : {
543 0 : Valueify(fp)->setAnnotation(annotation);
544 0 : }
545 :
546 : JS_PUBLIC_API(JSBool)
547 1505742 : JS_IsScriptFrame(JSContext *cx, JSStackFrame *fp)
548 : {
549 1505742 : return !Valueify(fp)->isDummyFrame();
550 : }
551 :
552 : JS_PUBLIC_API(JSObject *)
553 2950 : JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fpArg)
554 : {
555 2950 : StackFrame *fp = Valueify(fpArg);
556 2950 : JS_ASSERT(cx->stack.containsSlow(fp));
557 :
558 5900 : js::AutoCompartment ac(cx, &fp->scopeChain());
559 2950 : if (!ac.enter())
560 0 : return NULL;
561 :
562 : /* Force creation of argument and call objects if not yet created */
563 2950 : (void) JS_GetFrameCallObject(cx, Jsvalify(fp));
564 2950 : return GetScopeChain(cx, fp);
565 : }
566 :
567 : JS_PUBLIC_API(JSObject *)
568 3346 : JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fpArg)
569 : {
570 3346 : StackFrame *fp = Valueify(fpArg);
571 3346 : JS_ASSERT(cx->stack.containsSlow(fp));
572 :
573 3346 : if (!fp->isFunctionFrame())
574 1312 : return NULL;
575 :
576 4068 : js::AutoCompartment ac(cx, &fp->scopeChain());
577 2034 : if (!ac.enter())
578 0 : return NULL;
579 :
580 : /*
581 : * XXX ill-defined: null return here means error was reported, unlike a
582 : * null returned above or in the #else
583 : */
584 2034 : if (!fp->hasCallObj() && fp->isNonEvalFunctionFrame())
585 865 : return CallObject::createForFunction(cx, fp);
586 1169 : return &fp->callObj();
587 : }
588 :
589 : JS_PUBLIC_API(JSBool)
590 475 : JS_GetFrameThis(JSContext *cx, JSStackFrame *fpArg, jsval *thisv)
591 : {
592 475 : StackFrame *fp = Valueify(fpArg);
593 475 : if (fp->isDummyFrame())
594 0 : return false;
595 :
596 950 : js::AutoCompartment ac(cx, &fp->scopeChain());
597 475 : if (!ac.enter())
598 0 : return false;
599 :
600 475 : if (!ComputeThis(cx, fp))
601 0 : return false;
602 475 : *thisv = fp->thisValue();
603 475 : return true;
604 : }
605 :
606 : JS_PUBLIC_API(JSFunction *)
607 1496506 : JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
608 : {
609 1496506 : return Valueify(fp)->maybeScriptFunction();
610 : }
611 :
612 : JS_PUBLIC_API(JSObject *)
613 2098452 : JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fpArg)
614 : {
615 2098452 : StackFrame *fp = Valueify(fpArg);
616 2098452 : if (!fp->isFunctionFrame())
617 230824 : return NULL;
618 :
619 1867628 : JS_ASSERT(fp->callee().isFunction());
620 1867628 : return &fp->callee();
621 : }
622 :
623 : JS_PUBLIC_API(JSFunction *)
624 6 : JS_GetScriptFunction(JSContext *cx, JSScript *script)
625 : {
626 6 : return script->function();
627 : }
628 :
629 : JS_PUBLIC_API(JSObject *)
630 1 : JS_GetParentOrScopeChain(JSContext *cx, JSObject *obj)
631 : {
632 1 : return obj->enclosingScope();
633 : }
634 :
635 : JS_PUBLIC_API(JSBool)
636 0 : JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp)
637 : {
638 0 : return Valueify(fp)->isConstructing();
639 : }
640 :
641 : JS_PUBLIC_API(JSObject *)
642 0 : JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp)
643 : {
644 0 : return Valueify(fp)->maybeCalleev().toObjectOrNull();
645 : }
646 :
647 : JS_PUBLIC_API(JSBool)
648 0 : JS_GetValidFrameCalleeObject(JSContext *cx, JSStackFrame *fp, jsval *vp)
649 : {
650 : Value v;
651 :
652 0 : if (!Valueify(fp)->getValidCalleeObject(cx, &v))
653 0 : return false;
654 0 : *vp = v.isObject() ? v : JSVAL_VOID;
655 0 : return true;
656 : }
657 :
658 : JS_PUBLIC_API(JSBool)
659 0 : JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp)
660 : {
661 0 : return Valueify(fp)->isDebuggerFrame();
662 : }
663 :
664 : JS_PUBLIC_API(JSBool)
665 0 : JS_IsGlobalFrame(JSContext *cx, JSStackFrame *fp)
666 : {
667 0 : return Valueify(fp)->isGlobalFrame();
668 : }
669 :
670 : JS_PUBLIC_API(jsval)
671 0 : JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp)
672 : {
673 0 : return Valueify(fp)->returnValue();
674 : }
675 :
676 : JS_PUBLIC_API(void)
677 0 : JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fpArg, jsval rval)
678 : {
679 0 : StackFrame *fp = Valueify(fpArg);
680 : #ifdef JS_METHODJIT
681 0 : JS_ASSERT_IF(fp->isScriptFrame(), fp->script()->debugMode);
682 : #endif
683 0 : assertSameCompartment(cx, fp, rval);
684 0 : fp->setReturnValue(rval);
685 0 : }
686 :
687 : /************************************************************************/
688 :
689 : JS_PUBLIC_API(const char *)
690 1703587 : JS_GetScriptFilename(JSContext *cx, JSScript *script)
691 : {
692 1703587 : return script->filename;
693 : }
694 :
695 : JS_PUBLIC_API(const jschar *)
696 1 : JS_GetScriptSourceMap(JSContext *cx, JSScript *script)
697 : {
698 1 : return script->sourceMap;
699 : }
700 :
701 : JS_PUBLIC_API(unsigned)
702 210394 : JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script)
703 : {
704 210394 : return script->lineno;
705 : }
706 :
707 : JS_PUBLIC_API(unsigned)
708 7 : JS_GetScriptLineExtent(JSContext *cx, JSScript *script)
709 : {
710 7 : return js_GetScriptLineExtent(script);
711 : }
712 :
713 : JS_PUBLIC_API(JSVersion)
714 0 : JS_GetScriptVersion(JSContext *cx, JSScript *script)
715 : {
716 0 : return VersionNumber(script->getVersion());
717 : }
718 :
719 : /***************************************************************************/
720 :
721 : JS_PUBLIC_API(void)
722 560 : JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata)
723 : {
724 560 : rt->debugHooks.newScriptHook = hook;
725 560 : rt->debugHooks.newScriptHookData = callerdata;
726 560 : }
727 :
728 : JS_PUBLIC_API(void)
729 560 : JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook,
730 : void *callerdata)
731 : {
732 560 : rt->debugHooks.destroyScriptHook = hook;
733 560 : rt->debugHooks.destroyScriptHookData = callerdata;
734 560 : }
735 :
736 : /***************************************************************************/
737 :
738 : JS_PUBLIC_API(JSBool)
739 972 : JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fpArg,
740 : const jschar *chars, unsigned length,
741 : const char *filename, unsigned lineno,
742 : jsval *rval)
743 : {
744 972 : if (!CheckDebugMode(cx))
745 0 : return false;
746 :
747 972 : Env *env = JS_GetFrameScopeChain(cx, fpArg);
748 972 : if (!env)
749 0 : return false;
750 :
751 1944 : js::AutoCompartment ac(cx, env);
752 972 : if (!ac.enter())
753 0 : return false;
754 :
755 972 : StackFrame *fp = Valueify(fpArg);
756 972 : return EvaluateInEnv(cx, env, fp, chars, length, filename, lineno, rval);
757 : }
758 :
759 : JS_PUBLIC_API(JSBool)
760 0 : JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp,
761 : const char *bytes, unsigned length,
762 : const char *filename, unsigned lineno,
763 : jsval *rval)
764 : {
765 : jschar *chars;
766 : JSBool ok;
767 0 : size_t len = length;
768 :
769 0 : if (!CheckDebugMode(cx))
770 0 : return JS_FALSE;
771 :
772 0 : chars = InflateString(cx, bytes, &len);
773 0 : if (!chars)
774 0 : return JS_FALSE;
775 0 : length = (unsigned) len;
776 : ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length, filename, lineno,
777 0 : rval);
778 0 : cx->free_(chars);
779 :
780 0 : return ok;
781 : }
782 :
783 : /************************************************************************/
784 :
785 : /* This all should be reworked to avoid requiring JSScopeProperty types. */
786 :
787 : JS_PUBLIC_API(JSScopeProperty *)
788 3 : JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp)
789 : {
790 : const Shape *shape;
791 :
792 : /* The caller passes null in *iteratorp to get things started. */
793 3 : shape = (Shape *) *iteratorp;
794 3 : if (!shape)
795 2 : shape = obj->lastProperty();
796 : else
797 1 : shape = shape->previous();
798 :
799 3 : if (!shape->previous()) {
800 2 : JS_ASSERT(shape->isEmptyShape());
801 2 : shape = NULL;
802 : }
803 :
804 3 : return *iteratorp = reinterpret_cast<JSScopeProperty *>(const_cast<Shape *>(shape));
805 : }
806 :
807 : JS_PUBLIC_API(JSBool)
808 532 : JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
809 : JSPropertyDesc *pd)
810 : {
811 532 : assertSameCompartment(cx, obj);
812 532 : Shape *shape = (Shape *) sprop;
813 532 : pd->id = IdToJsval(shape->propid());
814 :
815 532 : JSBool wasThrowing = cx->isExceptionPending();
816 532 : Value lastException = UndefinedValue();
817 532 : if (wasThrowing)
818 0 : lastException = cx->getPendingException();
819 532 : cx->clearPendingException();
820 :
821 532 : if (!js_GetProperty(cx, obj, shape->propid(), &pd->value)) {
822 0 : if (!cx->isExceptionPending()) {
823 0 : pd->flags = JSPD_ERROR;
824 0 : pd->value = JSVAL_VOID;
825 : } else {
826 0 : pd->flags = JSPD_EXCEPTION;
827 0 : pd->value = cx->getPendingException();
828 : }
829 : } else {
830 532 : pd->flags = 0;
831 : }
832 :
833 532 : if (wasThrowing)
834 0 : cx->setPendingException(lastException);
835 :
836 532 : pd->flags |= (shape->enumerable() ? JSPD_ENUMERATE : 0)
837 532 : | (!shape->writable() ? JSPD_READONLY : 0)
838 1596 : | (!shape->configurable() ? JSPD_PERMANENT : 0);
839 532 : pd->spare = 0;
840 532 : if (shape->getter() == CallObject::getArgOp) {
841 253 : pd->slot = shape->shortid();
842 253 : pd->flags |= JSPD_ARGUMENT;
843 279 : } else if (shape->getter() == CallObject::getVarOp) {
844 55 : pd->slot = shape->shortid();
845 55 : pd->flags |= JSPD_VARIABLE;
846 : } else {
847 224 : pd->slot = 0;
848 : }
849 532 : pd->alias = JSVAL_VOID;
850 :
851 532 : return JS_TRUE;
852 : }
853 :
854 : JS_PUBLIC_API(JSBool)
855 344 : JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda)
856 : {
857 344 : assertSameCompartment(cx, obj);
858 344 : Class *clasp = obj->getClass();
859 344 : if (!obj->isNative() || (clasp->flags & JSCLASS_NEW_ENUMERATE)) {
860 : JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
861 0 : JSMSG_CANT_DESCRIBE_PROPS, clasp->name);
862 0 : return JS_FALSE;
863 : }
864 344 : if (!clasp->enumerate(cx, obj))
865 0 : return JS_FALSE;
866 :
867 : /* Return an empty pda early if obj has no own properties. */
868 344 : if (obj->nativeEmpty()) {
869 55 : pda->length = 0;
870 55 : pda->array = NULL;
871 55 : return JS_TRUE;
872 : }
873 :
874 289 : uint32_t n = obj->propertyCount();
875 289 : JSPropertyDesc *pd = (JSPropertyDesc *) cx->malloc_(size_t(n) * sizeof(JSPropertyDesc));
876 289 : if (!pd)
877 0 : return JS_FALSE;
878 289 : uint32_t i = 0;
879 531 : for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront()) {
880 531 : if (!js_AddRoot(cx, &pd[i].id, NULL))
881 0 : goto bad;
882 531 : if (!js_AddRoot(cx, &pd[i].value, NULL))
883 0 : goto bad;
884 531 : Shape *shape = const_cast<Shape *>(&r.front());
885 531 : if (!JS_GetPropertyDesc(cx, obj, reinterpret_cast<JSScopeProperty *>(shape), &pd[i]))
886 0 : goto bad;
887 531 : if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL))
888 0 : goto bad;
889 531 : if (++i == n)
890 289 : break;
891 : }
892 289 : pda->length = i;
893 289 : pda->array = pd;
894 289 : return JS_TRUE;
895 :
896 : bad:
897 0 : pda->length = i + 1;
898 0 : pda->array = pd;
899 0 : JS_PutPropertyDescArray(cx, pda);
900 0 : return JS_FALSE;
901 : }
902 :
903 : JS_PUBLIC_API(void)
904 289 : JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda)
905 : {
906 : JSPropertyDesc *pd;
907 : uint32_t i;
908 :
909 289 : pd = pda->array;
910 820 : for (i = 0; i < pda->length; i++) {
911 531 : js_RemoveRoot(cx->runtime, &pd[i].id);
912 531 : js_RemoveRoot(cx->runtime, &pd[i].value);
913 531 : if (pd[i].flags & JSPD_ALIAS)
914 0 : js_RemoveRoot(cx->runtime, &pd[i].alias);
915 : }
916 289 : cx->free_(pd);
917 289 : }
918 :
919 : /************************************************************************/
920 :
921 : JS_PUBLIC_API(JSBool)
922 1986 : JS_SetDebuggerHandler(JSRuntime *rt, JSDebuggerHandler handler, void *closure)
923 : {
924 1986 : rt->debugHooks.debuggerHandler = handler;
925 1986 : rt->debugHooks.debuggerHandlerData = closure;
926 1986 : return JS_TRUE;
927 : }
928 :
929 : JS_PUBLIC_API(JSBool)
930 0 : JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure)
931 : {
932 0 : rt->debugHooks.sourceHandler = handler;
933 0 : rt->debugHooks.sourceHandlerData = closure;
934 0 : return JS_TRUE;
935 : }
936 :
937 : JS_PUBLIC_API(JSBool)
938 564 : JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
939 : {
940 564 : rt->debugHooks.executeHook = hook;
941 564 : rt->debugHooks.executeHookData = closure;
942 564 : return JS_TRUE;
943 : }
944 :
945 : JS_PUBLIC_API(JSBool)
946 567 : JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
947 : {
948 567 : rt->debugHooks.callHook = hook;
949 567 : rt->debugHooks.callHookData = closure;
950 567 : return JS_TRUE;
951 : }
952 :
953 : JS_PUBLIC_API(JSBool)
954 584 : JS_SetThrowHook(JSRuntime *rt, JSThrowHook hook, void *closure)
955 : {
956 584 : rt->debugHooks.throwHook = hook;
957 584 : rt->debugHooks.throwHookData = closure;
958 584 : return JS_TRUE;
959 : }
960 :
961 : JS_PUBLIC_API(JSBool)
962 564 : JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure)
963 : {
964 564 : rt->debugHooks.debugErrorHook = hook;
965 564 : rt->debugHooks.debugErrorHookData = closure;
966 564 : return JS_TRUE;
967 : }
968 :
969 : /************************************************************************/
970 :
971 : JS_PUBLIC_API(size_t)
972 0 : JS_GetObjectTotalSize(JSContext *cx, JSObject *obj)
973 : {
974 0 : return obj->computedSizeOfThisSlotsElements();
975 : }
976 :
977 : static size_t
978 0 : GetAtomTotalSize(JSContext *cx, JSAtom *atom)
979 : {
980 : size_t nbytes;
981 :
982 0 : nbytes = sizeof(JSAtom *) + sizeof(JSDHashEntryStub);
983 0 : nbytes += sizeof(JSString);
984 0 : nbytes += (atom->length() + 1) * sizeof(jschar);
985 0 : return nbytes;
986 : }
987 :
988 : JS_PUBLIC_API(size_t)
989 0 : JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun)
990 : {
991 : size_t nbytes;
992 :
993 0 : nbytes = sizeof *fun;
994 0 : nbytes += JS_GetObjectTotalSize(cx, fun);
995 0 : if (fun->isInterpreted())
996 0 : nbytes += JS_GetScriptTotalSize(cx, fun->script());
997 0 : if (fun->atom)
998 0 : nbytes += GetAtomTotalSize(cx, fun->atom);
999 0 : return nbytes;
1000 : }
1001 :
1002 : JS_PUBLIC_API(size_t)
1003 0 : JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
1004 : {
1005 : size_t nbytes, pbytes;
1006 : jssrcnote *sn, *notes;
1007 : JSObjectArray *objarray;
1008 : JSPrincipals *principals;
1009 :
1010 0 : nbytes = sizeof *script;
1011 0 : nbytes += script->length * sizeof script->code[0];
1012 0 : nbytes += script->natoms * sizeof script->atoms[0];
1013 0 : for (size_t i = 0; i < script->natoms; i++)
1014 0 : nbytes += GetAtomTotalSize(cx, script->atoms[i]);
1015 :
1016 0 : if (script->filename)
1017 0 : nbytes += strlen(script->filename) + 1;
1018 :
1019 0 : notes = script->notes();
1020 0 : for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
1021 0 : continue;
1022 0 : nbytes += (sn - notes + 1) * sizeof *sn;
1023 :
1024 0 : if (JSScript::isValidOffset(script->objectsOffset)) {
1025 0 : objarray = script->objects();
1026 0 : size_t i = objarray->length;
1027 0 : nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
1028 0 : do {
1029 0 : nbytes += JS_GetObjectTotalSize(cx, objarray->vector[--i]);
1030 : } while (i != 0);
1031 : }
1032 :
1033 0 : if (JSScript::isValidOffset(script->regexpsOffset)) {
1034 0 : objarray = script->regexps();
1035 0 : size_t i = objarray->length;
1036 0 : nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
1037 0 : do {
1038 0 : nbytes += JS_GetObjectTotalSize(cx, objarray->vector[--i]);
1039 : } while (i != 0);
1040 : }
1041 :
1042 0 : if (JSScript::isValidOffset(script->trynotesOffset)) {
1043 : nbytes += sizeof(JSTryNoteArray) +
1044 0 : script->trynotes()->length * sizeof(JSTryNote);
1045 : }
1046 :
1047 0 : principals = script->principals;
1048 0 : if (principals) {
1049 0 : JS_ASSERT(principals->refcount);
1050 0 : pbytes = sizeof *principals;
1051 0 : if (principals->refcount > 1)
1052 0 : pbytes = JS_HOWMANY(pbytes, principals->refcount);
1053 0 : nbytes += pbytes;
1054 : }
1055 :
1056 0 : return nbytes;
1057 : }
1058 :
1059 : JS_PUBLIC_API(JSBool)
1060 1453003 : JS_IsSystemObject(JSContext *cx, JSObject *obj)
1061 : {
1062 1453003 : return obj->isSystem();
1063 : }
1064 :
1065 : JS_PUBLIC_API(JSBool)
1066 1445262 : JS_MakeSystemObject(JSContext *cx, JSObject *obj)
1067 : {
1068 1445262 : return obj->setSystem(cx);
1069 : }
1070 :
1071 : /************************************************************************/
1072 :
1073 : JS_FRIEND_API(void)
1074 36 : js_RevertVersion(JSContext *cx)
1075 : {
1076 36 : cx->clearVersionOverride();
1077 36 : }
1078 :
1079 : JS_PUBLIC_API(const JSDebugHooks *)
1080 1404 : JS_GetGlobalDebugHooks(JSRuntime *rt)
1081 : {
1082 1404 : return &rt->debugHooks;
1083 : }
1084 :
1085 : /************************************************************************/
1086 :
1087 : /* Profiling-related API */
1088 :
1089 : /* Thread-unsafe error management */
1090 :
1091 : static char gLastError[2000];
1092 :
1093 : static void
1094 : #ifdef __GNUC__
1095 : __attribute__((unused,format(printf,1,2)))
1096 : #endif
1097 0 : UnsafeError(const char *format, ...)
1098 : {
1099 : va_list args;
1100 0 : va_start(args, format);
1101 0 : (void) vsnprintf(gLastError, sizeof(gLastError), format, args);
1102 0 : va_end(args);
1103 :
1104 0 : gLastError[sizeof(gLastError) - 1] = '\0';
1105 0 : }
1106 :
1107 : JS_PUBLIC_API(const char *)
1108 0 : JS_UnsafeGetLastProfilingError()
1109 : {
1110 0 : return gLastError;
1111 : }
1112 :
1113 : JS_PUBLIC_API(JSBool)
1114 0 : JS_StartProfiling(const char *profileName)
1115 : {
1116 0 : JSBool ok = JS_TRUE;
1117 : #if defined(MOZ_SHARK) && defined(__APPLE__)
1118 : if (!Shark::Start()) {
1119 : UnsafeError("Failed to start Shark for %s", profileName);
1120 : ok = JS_FALSE;
1121 : }
1122 : #endif
1123 : #ifdef MOZ_VTUNE
1124 : if (!js_StartVtune(profileName))
1125 : ok = JS_FALSE;
1126 : #endif
1127 0 : return ok;
1128 : }
1129 :
1130 : JS_PUBLIC_API(JSBool)
1131 0 : JS_StopProfiling(const char *profileName)
1132 : {
1133 0 : JSBool ok = JS_TRUE;
1134 : #if defined(MOZ_SHARK) && defined(__APPLE__)
1135 : Shark::Stop();
1136 : #endif
1137 : #ifdef MOZ_VTUNE
1138 : if (!js_StopVtune())
1139 : ok = JS_FALSE;
1140 : #endif
1141 0 : return ok;
1142 : }
1143 :
1144 : /*
1145 : * Start or stop whatever platform- and configuration-specific profiling
1146 : * backends are available.
1147 : */
1148 : static JSBool
1149 0 : ControlProfilers(bool toState)
1150 : {
1151 0 : JSBool ok = JS_TRUE;
1152 :
1153 0 : if (! Probes::ProfilingActive && toState) {
1154 : #if defined(MOZ_SHARK) && defined(__APPLE__)
1155 : if (!Shark::Start()) {
1156 : UnsafeError("Failed to start Shark");
1157 : ok = JS_FALSE;
1158 : }
1159 : #endif
1160 : #ifdef MOZ_CALLGRIND
1161 : if (! js_StartCallgrind()) {
1162 : UnsafeError("Failed to start Callgrind");
1163 : ok = JS_FALSE;
1164 : }
1165 : #endif
1166 : #ifdef MOZ_VTUNE
1167 : if (! js_ResumeVtune())
1168 : ok = JS_FALSE;
1169 : #endif
1170 0 : } else if (Probes::ProfilingActive && ! toState) {
1171 : #if defined(MOZ_SHARK) && defined(__APPLE__)
1172 : Shark::Stop();
1173 : #endif
1174 : #ifdef MOZ_CALLGRIND
1175 : if (! js_StopCallgrind()) {
1176 : UnsafeError("failed to stop Callgrind");
1177 : ok = JS_FALSE;
1178 : }
1179 : #endif
1180 : #ifdef MOZ_VTUNE
1181 : if (! js_PauseVtune())
1182 : ok = JS_FALSE;
1183 : #endif
1184 : }
1185 :
1186 0 : Probes::ProfilingActive = toState;
1187 :
1188 0 : return ok;
1189 : }
1190 :
1191 : /*
1192 : * Pause/resume whatever profiling mechanism is currently compiled
1193 : * in, if applicable. This will not affect things like dtrace.
1194 : *
1195 : * Do not mix calls to these APIs with calls to the individual
1196 : * profilers' pause/resume functions, because only overall state is
1197 : * tracked, not the state of each profiler.
1198 : */
1199 : JS_PUBLIC_API(JSBool)
1200 0 : JS_PauseProfilers(const char *profileName)
1201 : {
1202 0 : return ControlProfilers(false);
1203 : }
1204 :
1205 : JS_PUBLIC_API(JSBool)
1206 0 : JS_ResumeProfilers(const char *profileName)
1207 : {
1208 0 : return ControlProfilers(true);
1209 : }
1210 :
1211 : JS_PUBLIC_API(JSBool)
1212 0 : JS_DumpProfile(const char *outfile, const char *profileName)
1213 : {
1214 0 : JSBool ok = JS_TRUE;
1215 : #ifdef MOZ_CALLGRIND
1216 : js_DumpCallgrind(outfile);
1217 : #endif
1218 0 : return ok;
1219 : }
1220 :
1221 : #ifdef MOZ_PROFILING
1222 :
1223 : struct RequiredStringArg {
1224 : JSContext *mCx;
1225 : char *mBytes;
1226 : RequiredStringArg(JSContext *cx, unsigned argc, jsval *vp, size_t argi, const char *caller)
1227 : : mCx(cx), mBytes(NULL)
1228 : {
1229 : if (argc <= argi) {
1230 : JS_ReportError(cx, "%s: not enough arguments", caller);
1231 : } else if (!JSVAL_IS_STRING(JS_ARGV(cx, vp)[argi])) {
1232 : JS_ReportError(cx, "%s: invalid arguments (string expected)", caller);
1233 : } else {
1234 : mBytes = JS_EncodeString(cx, JSVAL_TO_STRING(JS_ARGV(cx, vp)[argi]));
1235 : }
1236 : }
1237 : operator void*() {
1238 : return (void*) mBytes;
1239 : }
1240 : ~RequiredStringArg() {
1241 : if (mBytes)
1242 : mCx->free_(mBytes);
1243 : }
1244 : };
1245 :
1246 : static JSBool
1247 : StartProfiling(JSContext *cx, unsigned argc, jsval *vp)
1248 : {
1249 : if (argc == 0) {
1250 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StartProfiling(NULL)));
1251 : return JS_TRUE;
1252 : }
1253 :
1254 : RequiredStringArg profileName(cx, argc, vp, 0, "startProfiling");
1255 : if (!profileName)
1256 : return JS_FALSE;
1257 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StartProfiling(profileName.mBytes)));
1258 : return JS_TRUE;
1259 : }
1260 :
1261 : static JSBool
1262 : StopProfiling(JSContext *cx, unsigned argc, jsval *vp)
1263 : {
1264 : if (argc == 0) {
1265 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StopProfiling(NULL)));
1266 : return JS_TRUE;
1267 : }
1268 :
1269 : RequiredStringArg profileName(cx, argc, vp, 0, "stopProfiling");
1270 : if (!profileName)
1271 : return JS_FALSE;
1272 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StopProfiling(profileName.mBytes)));
1273 : return JS_TRUE;
1274 : }
1275 :
1276 : static JSBool
1277 : PauseProfilers(JSContext *cx, unsigned argc, jsval *vp)
1278 : {
1279 : if (argc == 0) {
1280 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_PauseProfilers(NULL)));
1281 : return JS_TRUE;
1282 : }
1283 :
1284 : RequiredStringArg profileName(cx, argc, vp, 0, "pauseProfiling");
1285 : if (!profileName)
1286 : return JS_FALSE;
1287 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_PauseProfilers(profileName.mBytes)));
1288 : return JS_TRUE;
1289 : }
1290 :
1291 : static JSBool
1292 : ResumeProfilers(JSContext *cx, unsigned argc, jsval *vp)
1293 : {
1294 : if (argc == 0) {
1295 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_ResumeProfilers(NULL)));
1296 : return JS_TRUE;
1297 : }
1298 :
1299 : RequiredStringArg profileName(cx, argc, vp, 0, "resumeProfiling");
1300 : if (!profileName)
1301 : return JS_FALSE;
1302 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_ResumeProfilers(profileName.mBytes)));
1303 : return JS_TRUE;
1304 : }
1305 :
1306 : /* Usage: DumpProfile([filename[, profileName]]) */
1307 : static JSBool
1308 : DumpProfile(JSContext *cx, unsigned argc, jsval *vp)
1309 : {
1310 : bool ret;
1311 : if (argc == 0) {
1312 : ret = JS_DumpProfile(NULL, NULL);
1313 : } else {
1314 : RequiredStringArg filename(cx, argc, vp, 0, "dumpProfile");
1315 : if (!filename)
1316 : return JS_FALSE;
1317 :
1318 : if (argc == 1) {
1319 : ret = JS_DumpProfile(filename.mBytes, NULL);
1320 : } else {
1321 : RequiredStringArg profileName(cx, argc, vp, 1, "dumpProfile");
1322 : if (!profileName)
1323 : return JS_FALSE;
1324 :
1325 : ret = JS_DumpProfile(filename.mBytes, profileName.mBytes);
1326 : }
1327 : }
1328 :
1329 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(ret));
1330 : return true;
1331 : }
1332 :
1333 : #ifdef MOZ_SHARK
1334 :
1335 : static JSBool
1336 : IgnoreAndReturnTrue(JSContext *cx, unsigned argc, jsval *vp)
1337 : {
1338 : JS_SET_RVAL(cx, vp, JSVAL_TRUE);
1339 : return true;
1340 : }
1341 :
1342 : #endif
1343 :
1344 : #ifdef MOZ_CALLGRIND
1345 : static JSBool
1346 : StartCallgrind(JSContext *cx, unsigned argc, jsval *vp)
1347 : {
1348 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StartCallgrind()));
1349 : return JS_TRUE;
1350 : }
1351 :
1352 : static JSBool
1353 : StopCallgrind(JSContext *cx, unsigned argc, jsval *vp)
1354 : {
1355 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StopCallgrind()));
1356 : return JS_TRUE;
1357 : }
1358 :
1359 : static JSBool
1360 : DumpCallgrind(JSContext *cx, unsigned argc, jsval *vp)
1361 : {
1362 : if (argc == 0) {
1363 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_DumpCallgrind(NULL)));
1364 : return JS_TRUE;
1365 : }
1366 :
1367 : RequiredStringArg outFile(cx, argc, vp, 0, "dumpCallgrind");
1368 : if (!outFile)
1369 : return JS_FALSE;
1370 :
1371 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_DumpCallgrind(outFile.mBytes)));
1372 : return JS_TRUE;
1373 : }
1374 : #endif
1375 :
1376 : #ifdef MOZ_VTUNE
1377 : static JSBool
1378 : StartVtune(JSContext *cx, unsigned argc, jsval *vp)
1379 : {
1380 : RequiredStringArg profileName(cx, argc, vp, 0, "startVtune");
1381 : if (!profileName)
1382 : return JS_FALSE;
1383 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StartVtune(profileName.mBytes)));
1384 : return JS_TRUE;
1385 : }
1386 :
1387 : static JSBool
1388 : StopVtune(JSContext *cx, unsigned argc, jsval *vp)
1389 : {
1390 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StopVtune()));
1391 : return JS_TRUE;
1392 : }
1393 :
1394 : static JSBool
1395 : PauseVtune(JSContext *cx, unsigned argc, jsval *vp)
1396 : {
1397 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_PauseVtune()));
1398 : return JS_TRUE;
1399 : }
1400 :
1401 : static JSBool
1402 : ResumeVtune(JSContext *cx, unsigned argc, jsval *vp)
1403 : {
1404 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_ResumeVtune()));
1405 : return JS_TRUE;
1406 : }
1407 : #endif
1408 :
1409 : static JSFunctionSpec profiling_functions[] = {
1410 : JS_FN("startProfiling", StartProfiling, 1,0),
1411 : JS_FN("stopProfiling", StopProfiling, 1,0),
1412 : JS_FN("pauseProfilers", PauseProfilers, 1,0),
1413 : JS_FN("resumeProfilers", ResumeProfilers, 1,0),
1414 : JS_FN("dumpProfile", DumpProfile, 2,0),
1415 : #ifdef MOZ_SHARK
1416 : /* Keep users of the old shark API happy. */
1417 : JS_FN("connectShark", IgnoreAndReturnTrue, 0,0),
1418 : JS_FN("disconnectShark", IgnoreAndReturnTrue, 0,0),
1419 : JS_FN("startShark", StartProfiling, 0,0),
1420 : JS_FN("stopShark", StopProfiling, 0,0),
1421 : #endif
1422 : #ifdef MOZ_CALLGRIND
1423 : JS_FN("startCallgrind", StartCallgrind, 0,0),
1424 : JS_FN("stopCallgrind", StopCallgrind, 0,0),
1425 : JS_FN("dumpCallgrind", DumpCallgrind, 1,0),
1426 : #endif
1427 : #ifdef MOZ_VTUNE
1428 : JS_FN("startVtune", js_StartVtune, 1,0),
1429 : JS_FN("stopVtune", js_StopVtune, 0,0),
1430 : JS_FN("pauseVtune", js_PauseVtune, 0,0),
1431 : JS_FN("resumeVtune", js_ResumeVtune, 0,0),
1432 : #endif
1433 : JS_FS_END
1434 : };
1435 :
1436 : #endif
1437 :
1438 : JS_PUBLIC_API(JSBool)
1439 36041 : JS_DefineProfilingFunctions(JSContext *cx, JSObject *obj)
1440 : {
1441 36041 : assertSameCompartment(cx, obj);
1442 : #ifdef MOZ_PROFILING
1443 : return JS_DefineFunctions(cx, obj, profiling_functions);
1444 : #else
1445 36041 : return true;
1446 : #endif
1447 : }
1448 :
1449 : #ifdef MOZ_CALLGRIND
1450 :
1451 : #include <valgrind/callgrind.h>
1452 :
1453 : JS_FRIEND_API(JSBool)
1454 : js_StartCallgrind()
1455 : {
1456 : JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_START_INSTRUMENTATION);
1457 : JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_ZERO_STATS);
1458 : return true;
1459 : }
1460 :
1461 : JS_FRIEND_API(JSBool)
1462 : js_StopCallgrind()
1463 : {
1464 : JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_STOP_INSTRUMENTATION);
1465 : return true;
1466 : }
1467 :
1468 : JS_FRIEND_API(JSBool)
1469 : js_DumpCallgrind(const char *outfile)
1470 : {
1471 : if (outfile) {
1472 : JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_DUMP_STATS_AT(outfile));
1473 : } else {
1474 : JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_DUMP_STATS);
1475 : }
1476 :
1477 : return true;
1478 : }
1479 :
1480 : #endif /* MOZ_CALLGRIND */
1481 :
1482 : #ifdef MOZ_VTUNE
1483 : #include <VTuneApi.h>
1484 :
1485 : static const char *vtuneErrorMessages[] = {
1486 : "unknown, error #0",
1487 : "invalid 'max samples' field",
1488 : "invalid 'samples per buffer' field",
1489 : "invalid 'sample interval' field",
1490 : "invalid path",
1491 : "sample file in use",
1492 : "invalid 'number of events' field",
1493 : "unknown, error #7",
1494 : "internal error",
1495 : "bad event name",
1496 : "VTStopSampling called without calling VTStartSampling",
1497 : "no events selected for event-based sampling",
1498 : "events selected cannot be run together",
1499 : "no sampling parameters",
1500 : "sample database already exists",
1501 : "sampling already started",
1502 : "time-based sampling not supported",
1503 : "invalid 'sampling parameters size' field",
1504 : "invalid 'event size' field",
1505 : "sampling file already bound",
1506 : "invalid event path",
1507 : "invalid license",
1508 : "invalid 'global options' field",
1509 :
1510 : };
1511 :
1512 : bool
1513 : js_StartVtune(const char *profileName)
1514 : {
1515 : VTUNE_EVENT events[] = {
1516 : { 1000000, 0, 0, 0, "CPU_CLK_UNHALTED.CORE" },
1517 : { 1000000, 0, 0, 0, "INST_RETIRED.ANY" },
1518 : };
1519 :
1520 : U32 n_events = sizeof(events) / sizeof(VTUNE_EVENT);
1521 : char *default_filename = "mozilla-vtune.tb5";
1522 : JSString *str;
1523 : U32 status;
1524 :
1525 : VTUNE_SAMPLING_PARAMS params = {
1526 : sizeof(VTUNE_SAMPLING_PARAMS),
1527 : sizeof(VTUNE_EVENT),
1528 : 0, 0, /* Reserved fields */
1529 : 1, /* Initialize in "paused" state */
1530 : 0, /* Max samples, or 0 for "continuous" */
1531 : 4096, /* Samples per buffer */
1532 : 0.1, /* Sampling interval in ms */
1533 : 1, /* 1 for event-based sampling, 0 for time-based */
1534 :
1535 : n_events,
1536 : events,
1537 : default_filename,
1538 : };
1539 :
1540 : if (profileName) {
1541 : char filename[strlen(profileName) + strlen("-vtune.tb5") + 1];
1542 : snprintf(filename, sizeof(filename), "%s-vtune.tb5", profileName);
1543 : params.tb5Filename = filename;
1544 : }
1545 :
1546 : status = VTStartSampling(¶ms);
1547 :
1548 : if (params.tb5Filename != default_filename)
1549 : Foreground::free_(params.tb5Filename);
1550 :
1551 : if (status != 0) {
1552 : if (status == VTAPI_MULTIPLE_RUNS)
1553 : VTStopSampling(0);
1554 : if (status < sizeof(vtuneErrorMessages))
1555 : UnsafeError("Vtune setup error: %s", vtuneErrorMessages[status]);
1556 : else
1557 : UnsafeError("Vtune setup error: %d", status);
1558 : return false;
1559 : }
1560 : return true;
1561 : }
1562 :
1563 : bool
1564 : js_StopVtune()
1565 : {
1566 : U32 status = VTStopSampling(1);
1567 : if (status) {
1568 : if (status < sizeof(vtuneErrorMessages))
1569 : UnsafeError("Vtune shutdown error: %s", vtuneErrorMessages[status]);
1570 : else
1571 : UnsafeError("Vtune shutdown error: %d", status);
1572 : return false;
1573 : }
1574 : return true;
1575 : }
1576 :
1577 : bool
1578 : js_PauseVtune()
1579 : {
1580 : VTPause();
1581 : return true;
1582 : }
1583 :
1584 : bool
1585 : js_ResumeVtune()
1586 : {
1587 : VTResume();
1588 : return true;
1589 : }
1590 :
1591 : #endif /* MOZ_VTUNE */
1592 :
1593 : JS_PUBLIC_API(void)
1594 0 : JS_DumpBytecode(JSContext *cx, JSScript *script)
1595 : {
1596 : #if defined(DEBUG)
1597 0 : Sprinter sprinter(cx);
1598 0 : if (!sprinter.init())
1599 : return;
1600 :
1601 0 : fprintf(stdout, "--- SCRIPT %s:%d ---\n", script->filename, script->lineno);
1602 0 : js_Disassemble(cx, script, true, &sprinter);
1603 0 : fputs(sprinter.string(), stdout);
1604 0 : fprintf(stdout, "--- END SCRIPT %s:%d ---\n", script->filename, script->lineno);
1605 : #endif
1606 : }
1607 :
1608 : extern JS_PUBLIC_API(void)
1609 0 : JS_DumpPCCounts(JSContext *cx, JSScript *script)
1610 : {
1611 : #if defined(DEBUG)
1612 0 : JS_ASSERT(script->pcCounters);
1613 :
1614 0 : Sprinter sprinter(cx);
1615 0 : if (!sprinter.init())
1616 : return;
1617 :
1618 0 : fprintf(stdout, "--- SCRIPT %s:%d ---\n", script->filename, script->lineno);
1619 0 : js_DumpPCCounts(cx, script, &sprinter);
1620 0 : fputs(sprinter.string(), stdout);
1621 0 : fprintf(stdout, "--- END SCRIPT %s:%d ---\n", script->filename, script->lineno);
1622 : #endif
1623 : }
1624 :
1625 : namespace {
1626 :
1627 : typedef Vector<JSScript *, 0, SystemAllocPolicy> ScriptsToDump;
1628 :
1629 : static void
1630 0 : DumpBytecodeScriptCallback(JSRuntime *rt, void *data, void *thing,
1631 : JSGCTraceKind traceKind, size_t thingSize)
1632 : {
1633 0 : JS_ASSERT(traceKind == JSTRACE_SCRIPT);
1634 0 : JSScript *script = static_cast<JSScript *>(thing);
1635 0 : static_cast<ScriptsToDump *>(data)->append(script);
1636 0 : }
1637 :
1638 : } /* anonymous namespace */
1639 :
1640 : JS_PUBLIC_API(void)
1641 0 : JS_DumpCompartmentBytecode(JSContext *cx)
1642 : {
1643 0 : ScriptsToDump scripts;
1644 0 : IterateCells(cx->runtime, cx->compartment, gc::FINALIZE_SCRIPT, &scripts, DumpBytecodeScriptCallback);
1645 :
1646 0 : for (size_t i = 0; i < scripts.length(); i++)
1647 0 : JS_DumpBytecode(cx, scripts[i]);
1648 0 : }
1649 :
1650 : JS_PUBLIC_API(void)
1651 0 : JS_DumpCompartmentPCCounts(JSContext *cx)
1652 : {
1653 0 : for (CellIter i(cx->compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
1654 0 : JSScript *script = i.get<JSScript>();
1655 0 : if (script->pcCounters)
1656 0 : JS_DumpPCCounts(cx, script);
1657 : }
1658 0 : }
1659 :
1660 : JS_PUBLIC_API(JSObject *)
1661 1160 : JS_UnwrapObject(JSObject *obj)
1662 : {
1663 1160 : return UnwrapObject(obj);
1664 : }
1665 :
1666 : JS_FRIEND_API(JSBool)
1667 0 : js_CallContextDebugHandler(JSContext *cx)
1668 : {
1669 0 : FrameRegsIter iter(cx);
1670 0 : JS_ASSERT(!iter.done());
1671 :
1672 : jsval rval;
1673 0 : switch (js::CallContextDebugHandler(cx, iter.script(), iter.pc(), &rval)) {
1674 : case JSTRAP_ERROR:
1675 0 : JS_ClearPendingException(cx);
1676 0 : return JS_FALSE;
1677 : case JSTRAP_THROW:
1678 0 : JS_SetPendingException(cx, rval);
1679 0 : return JS_FALSE;
1680 : case JSTRAP_RETURN:
1681 : case JSTRAP_CONTINUE:
1682 : default:
1683 0 : return JS_TRUE;
1684 : }
1685 : }
1686 :
|