/[jscoverage]/trunk/js/jsdbgapi.cpp
ViewVC logotype

Contents of /trunk/js/jsdbgapi.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 332 - (show annotations)
Thu Oct 23 19:03:33 2008 UTC (10 years, 10 months ago) by siliconforks
File size: 54960 byte(s)
Add SpiderMonkey from Firefox 3.1b1.

The following directories and files were removed:
correct/, correct.js
liveconnect/
nanojit/
t/
v8/
vprof/
xpconnect/
all JavaScript files (Y.js, call.js, if.js, math-partial-sums.js, md5.js, perfect.js, trace-test.js, trace.js)


1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=78:
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 *
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
38 *
39 * ***** END LICENSE BLOCK ***** */
40
41 /*
42 * JS debugging API.
43 */
44 #include "jsstddef.h"
45 #include <string.h>
46 #include "jstypes.h"
47 #include "jsutil.h" /* Added by JSIFY */
48 #include "jsclist.h"
49 #include "jsapi.h"
50 #include "jscntxt.h"
51 #include "jsversion.h"
52 #include "jsdbgapi.h"
53 #include "jsemit.h"
54 #include "jsfun.h"
55 #include "jsgc.h"
56 #include "jsinterp.h"
57 #include "jslock.h"
58 #include "jsobj.h"
59 #include "jsopcode.h"
60 #include "jsparse.h"
61 #include "jsscope.h"
62 #include "jsscript.h"
63 #include "jsstr.h"
64
65 #include "jsautooplen.h"
66
67 typedef struct JSTrap {
68 JSCList links;
69 JSScript *script;
70 jsbytecode *pc;
71 JSOp op;
72 JSTrapHandler handler;
73 void *closure;
74 } JSTrap;
75
76 #define DBG_LOCK(rt) JS_ACQUIRE_LOCK((rt)->debuggerLock)
77 #define DBG_UNLOCK(rt) JS_RELEASE_LOCK((rt)->debuggerLock)
78 #define DBG_LOCK_EVAL(rt,expr) (DBG_LOCK(rt), (expr), DBG_UNLOCK(rt))
79
80 /*
81 * NB: FindTrap must be called with rt->debuggerLock acquired.
82 */
83 static JSTrap *
84 FindTrap(JSRuntime *rt, JSScript *script, jsbytecode *pc)
85 {
86 JSTrap *trap;
87
88 for (trap = (JSTrap *)rt->trapList.next;
89 &trap->links != &rt->trapList;
90 trap = (JSTrap *)trap->links.next) {
91 if (trap->script == script && trap->pc == pc)
92 return trap;
93 }
94 return NULL;
95 }
96
97 jsbytecode *
98 js_UntrapScriptCode(JSContext *cx, JSScript *script)
99 {
100 jsbytecode *code;
101 JSRuntime *rt;
102 JSTrap *trap;
103
104 code = script->code;
105 rt = cx->runtime;
106 DBG_LOCK(rt);
107 for (trap = (JSTrap *)rt->trapList.next;
108 &trap->links !=
109 &rt->trapList;
110 trap = (JSTrap *)trap->links.next) {
111 if (trap->script == script &&
112 (size_t)(trap->pc - script->code) < script->length) {
113 if (code == script->code) {
114 jssrcnote *sn, *notes;
115 size_t nbytes;
116
117 nbytes = script->length * sizeof(jsbytecode);
118 notes = SCRIPT_NOTES(script);
119 for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
120 continue;
121 nbytes += (sn - notes + 1) * sizeof *sn;
122
123 code = (jsbytecode *) JS_malloc(cx, nbytes);
124 if (!code)
125 break;
126 memcpy(code, script->code, nbytes);
127 JS_CLEAR_GSN_CACHE(cx);
128 }
129 code[trap->pc - script->code] = trap->op;
130 }
131 }
132 DBG_UNLOCK(rt);
133 return code;
134 }
135
136 JS_PUBLIC_API(JSBool)
137 JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
138 JSTrapHandler handler, void *closure)
139 {
140 JSTrap *junk, *trap, *twin;
141 JSRuntime *rt;
142 uint32 sample;
143
144 JS_ASSERT((JSOp) *pc != JSOP_TRAP);
145 junk = NULL;
146 rt = cx->runtime;
147 DBG_LOCK(rt);
148 trap = FindTrap(rt, script, pc);
149 if (trap) {
150 JS_ASSERT(trap->script == script && trap->pc == pc);
151 JS_ASSERT(*pc == JSOP_TRAP);
152 } else {
153 sample = rt->debuggerMutations;
154 DBG_UNLOCK(rt);
155 trap = (JSTrap *) JS_malloc(cx, sizeof *trap);
156 if (!trap)
157 return JS_FALSE;
158 trap->closure = NULL;
159 if(!js_AddRoot(cx, &trap->closure, "trap->closure")) {
160 JS_free(cx, trap);
161 return JS_FALSE;
162 }
163 DBG_LOCK(rt);
164 twin = (rt->debuggerMutations != sample)
165 ? FindTrap(rt, script, pc)
166 : NULL;
167 if (twin) {
168 junk = trap;
169 trap = twin;
170 } else {
171 JS_APPEND_LINK(&trap->links, &rt->trapList);
172 ++rt->debuggerMutations;
173 trap->script = script;
174 trap->pc = pc;
175 trap->op = (JSOp)*pc;
176 *pc = JSOP_TRAP;
177 }
178 }
179 trap->handler = handler;
180 trap->closure = closure;
181 DBG_UNLOCK(rt);
182 if (junk) {
183 js_RemoveRoot(rt, &junk->closure);
184 JS_free(cx, junk);
185 }
186 return JS_TRUE;
187 }
188
189 JS_PUBLIC_API(JSOp)
190 JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
191 {
192 JSRuntime *rt;
193 JSTrap *trap;
194 JSOp op;
195
196 rt = cx->runtime;
197 DBG_LOCK(rt);
198 trap = FindTrap(rt, script, pc);
199 op = trap ? trap->op : (JSOp) *pc;
200 DBG_UNLOCK(rt);
201 return op;
202 }
203
204 static void
205 DestroyTrapAndUnlock(JSContext *cx, JSTrap *trap)
206 {
207 ++cx->runtime->debuggerMutations;
208 JS_REMOVE_LINK(&trap->links);
209 *trap->pc = (jsbytecode)trap->op;
210 DBG_UNLOCK(cx->runtime);
211
212 js_RemoveRoot(cx->runtime, &trap->closure);
213 JS_free(cx, trap);
214 }
215
216 JS_PUBLIC_API(void)
217 JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
218 JSTrapHandler *handlerp, void **closurep)
219 {
220 JSTrap *trap;
221
222 DBG_LOCK(cx->runtime);
223 trap = FindTrap(cx->runtime, script, pc);
224 if (handlerp)
225 *handlerp = trap ? trap->handler : NULL;
226 if (closurep)
227 *closurep = trap ? trap->closure : NULL;
228 if (trap)
229 DestroyTrapAndUnlock(cx, trap);
230 else
231 DBG_UNLOCK(cx->runtime);
232 }
233
234 JS_PUBLIC_API(void)
235 JS_ClearScriptTraps(JSContext *cx, JSScript *script)
236 {
237 JSRuntime *rt;
238 JSTrap *trap, *next;
239 uint32 sample;
240
241 rt = cx->runtime;
242 DBG_LOCK(rt);
243 for (trap = (JSTrap *)rt->trapList.next;
244 &trap->links != &rt->trapList;
245 trap = next) {
246 next = (JSTrap *)trap->links.next;
247 if (trap->script == script) {
248 sample = rt->debuggerMutations;
249 DestroyTrapAndUnlock(cx, trap);
250 DBG_LOCK(rt);
251 if (rt->debuggerMutations != sample + 1)
252 next = (JSTrap *)rt->trapList.next;
253 }
254 }
255 DBG_UNLOCK(rt);
256 }
257
258 JS_PUBLIC_API(void)
259 JS_ClearAllTraps(JSContext *cx)
260 {
261 JSRuntime *rt;
262 JSTrap *trap, *next;
263 uint32 sample;
264
265 rt = cx->runtime;
266 DBG_LOCK(rt);
267 for (trap = (JSTrap *)rt->trapList.next;
268 &trap->links != &rt->trapList;
269 trap = next) {
270 next = (JSTrap *)trap->links.next;
271 sample = rt->debuggerMutations;
272 DestroyTrapAndUnlock(cx, trap);
273 DBG_LOCK(rt);
274 if (rt->debuggerMutations != sample + 1)
275 next = (JSTrap *)rt->trapList.next;
276 }
277 DBG_UNLOCK(rt);
278 }
279
280 JS_PUBLIC_API(JSTrapStatus)
281 JS_HandleTrap(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval)
282 {
283 JSTrap *trap;
284 jsint op;
285 JSTrapStatus status;
286
287 DBG_LOCK(cx->runtime);
288 trap = FindTrap(cx->runtime, script, pc);
289 JS_ASSERT(!trap || trap->handler);
290 if (!trap) {
291 op = (JSOp) *pc;
292 DBG_UNLOCK(cx->runtime);
293
294 /* Defend against "pc for wrong script" API usage error. */
295 JS_ASSERT(op != JSOP_TRAP);
296
297 #ifdef JS_THREADSAFE
298 /* If the API was abused, we must fail for want of the real op. */
299 if (op == JSOP_TRAP)
300 return JSTRAP_ERROR;
301
302 /* Assume a race with a debugger thread and try to carry on. */
303 *rval = INT_TO_JSVAL(op);
304 return JSTRAP_CONTINUE;
305 #else
306 /* Always fail if single-threaded (must be an API usage error). */
307 return JSTRAP_ERROR;
308 #endif
309 }
310 DBG_UNLOCK(cx->runtime);
311
312 /*
313 * It's important that we not use 'trap->' after calling the callback --
314 * the callback might remove the trap!
315 */
316 op = (jsint)trap->op;
317 status = trap->handler(cx, script, pc, rval, trap->closure);
318 if (status == JSTRAP_CONTINUE) {
319 /* By convention, return the true op to the interpreter in rval. */
320 *rval = INT_TO_JSVAL(op);
321 }
322 return status;
323 }
324
325 JS_PUBLIC_API(JSBool)
326 JS_SetInterrupt(JSRuntime *rt, JSTrapHandler handler, void *closure)
327 {
328 rt->globalDebugHooks.interruptHandler = handler;
329 rt->globalDebugHooks.interruptHandlerData = closure;
330 return JS_TRUE;
331 }
332
333 JS_PUBLIC_API(JSBool)
334 JS_ClearInterrupt(JSRuntime *rt, JSTrapHandler *handlerp, void **closurep)
335 {
336 if (handlerp)
337 *handlerp = (JSTrapHandler)rt->globalDebugHooks.interruptHandler;
338 if (closurep)
339 *closurep = rt->globalDebugHooks.interruptHandlerData;
340 rt->globalDebugHooks.interruptHandler = 0;
341 rt->globalDebugHooks.interruptHandlerData = 0;
342 return JS_TRUE;
343 }
344
345 /************************************************************************/
346
347 typedef struct JSWatchPoint {
348 JSCList links;
349 JSObject *object; /* weak link, see js_FinalizeObject */
350 JSScopeProperty *sprop;
351 JSPropertyOp setter;
352 JSWatchPointHandler handler;
353 void *closure;
354 uintN flags;
355 } JSWatchPoint;
356
357 #define JSWP_LIVE 0x1 /* live because set and not cleared */
358 #define JSWP_HELD 0x2 /* held while running handler/setter */
359
360 /*
361 * NB: DropWatchPointAndUnlock releases cx->runtime->debuggerLock in all cases.
362 */
363 static JSBool
364 DropWatchPointAndUnlock(JSContext *cx, JSWatchPoint *wp, uintN flag)
365 {
366 JSBool ok, found;
367 JSScopeProperty *sprop;
368 JSScope *scope;
369 JSPropertyOp setter;
370
371 ok = JS_TRUE;
372 wp->flags &= ~flag;
373 if (wp->flags != 0) {
374 DBG_UNLOCK(cx->runtime);
375 return ok;
376 }
377
378 /*
379 * Remove wp from the list, then if there are no other watchpoints for
380 * wp->sprop in any scope, restore wp->sprop->setter from wp.
381 */
382 ++cx->runtime->debuggerMutations;
383 JS_REMOVE_LINK(&wp->links);
384 sprop = wp->sprop;
385
386 /*
387 * Passing null for the scope parameter tells js_GetWatchedSetter to find
388 * any watch point for sprop, and not to lock or unlock rt->debuggerLock.
389 * If js_ChangeNativePropertyAttrs fails, propagate failure after removing
390 * wp->closure's root and freeing wp.
391 */
392 setter = js_GetWatchedSetter(cx->runtime, NULL, sprop);
393 DBG_UNLOCK(cx->runtime);
394 if (!setter) {
395 JS_LOCK_OBJ(cx, wp->object);
396 scope = OBJ_SCOPE(wp->object);
397 found = (scope->object == wp->object &&
398 SCOPE_GET_PROPERTY(scope, sprop->id));
399 JS_UNLOCK_SCOPE(cx, scope);
400
401 /*
402 * If the property wasn't found on wp->object or didn't exist, then
403 * someone else has dealt with this sprop, and we don't need to change
404 * the property attributes.
405 */
406 if (found) {
407 sprop = js_ChangeScopePropertyAttrs(cx, scope, sprop,
408 0, sprop->attrs,
409 sprop->getter,
410 wp->setter);
411 if (!sprop)
412 ok = JS_FALSE;
413 }
414 }
415
416 JS_free(cx, wp);
417 return ok;
418 }
419
420 /*
421 * NB: js_TraceWatchPoints does not acquire cx->runtime->debuggerLock, since
422 * the debugger should never be racing with the GC (i.e., the debugger must
423 * respect the request model).
424 */
425 void
426 js_TraceWatchPoints(JSTracer *trc, JSObject *obj)
427 {
428 JSRuntime *rt;
429 JSWatchPoint *wp;
430
431 rt = trc->context->runtime;
432
433 for (wp = (JSWatchPoint *)rt->watchPointList.next;
434 &wp->links != &rt->watchPointList;
435 wp = (JSWatchPoint *)wp->links.next) {
436 if (wp->object == obj) {
437 TRACE_SCOPE_PROPERTY(trc, wp->sprop);
438 if ((wp->sprop->attrs & JSPROP_SETTER) && wp->setter) {
439 JS_CALL_OBJECT_TRACER(trc, (JSObject *)wp->setter,
440 "wp->setter");
441 }
442 JS_SET_TRACING_NAME(trc, "wp->closure");
443 js_CallValueTracerIfGCThing(trc, (jsval) wp->closure);
444 }
445 }
446 }
447
448 void
449 js_SweepWatchPoints(JSContext *cx)
450 {
451 JSRuntime *rt;
452 JSWatchPoint *wp, *next;
453 uint32 sample;
454
455 rt = cx->runtime;
456 DBG_LOCK(rt);
457 for (wp = (JSWatchPoint *)rt->watchPointList.next;
458 &wp->links != &rt->watchPointList;
459 wp = next) {
460 next = (JSWatchPoint *)wp->links.next;
461 if (js_IsAboutToBeFinalized(cx, wp->object)) {
462 sample = rt->debuggerMutations;
463
464 /* Ignore failures. */
465 DropWatchPointAndUnlock(cx, wp, JSWP_LIVE);
466 DBG_LOCK(rt);
467 if (rt->debuggerMutations != sample + 1)
468 next = (JSWatchPoint *)rt->watchPointList.next;
469 }
470 }
471 DBG_UNLOCK(rt);
472 }
473
474
475
476 /*
477 * NB: FindWatchPoint must be called with rt->debuggerLock acquired.
478 */
479 static JSWatchPoint *
480 FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id)
481 {
482 JSWatchPoint *wp;
483
484 for (wp = (JSWatchPoint *)rt->watchPointList.next;
485 &wp->links != &rt->watchPointList;
486 wp = (JSWatchPoint *)wp->links.next) {
487 if (wp->object == scope->object && wp->sprop->id == id)
488 return wp;
489 }
490 return NULL;
491 }
492
493 JSScopeProperty *
494 js_FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id)
495 {
496 JSWatchPoint *wp;
497 JSScopeProperty *sprop;
498
499 DBG_LOCK(rt);
500 wp = FindWatchPoint(rt, scope, id);
501 sprop = wp ? wp->sprop : NULL;
502 DBG_UNLOCK(rt);
503 return sprop;
504 }
505
506 /*
507 * Secret handshake with DropWatchPointAndUnlock: if (!scope), we know our
508 * caller has acquired rt->debuggerLock, so we don't have to.
509 */
510 JSPropertyOp
511 js_GetWatchedSetter(JSRuntime *rt, JSScope *scope,
512 const JSScopeProperty *sprop)
513 {
514 JSPropertyOp setter;
515 JSWatchPoint *wp;
516
517 setter = NULL;
518 if (scope)
519 DBG_LOCK(rt);
520 for (wp = (JSWatchPoint *)rt->watchPointList.next;
521 &wp->links != &rt->watchPointList;
522 wp = (JSWatchPoint *)wp->links.next) {
523 if ((!scope || wp->object == scope->object) && wp->sprop == sprop) {
524 setter = wp->setter;
525 break;
526 }
527 }
528 if (scope)
529 DBG_UNLOCK(rt);
530 return setter;
531 }
532
533 JSBool
534 js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
535 {
536 JSRuntime *rt;
537 JSWatchPoint *wp;
538 JSScopeProperty *sprop;
539 jsval propid, userid;
540 JSScope *scope;
541 JSBool ok;
542
543 rt = cx->runtime;
544 DBG_LOCK(rt);
545 for (wp = (JSWatchPoint *)rt->watchPointList.next;
546 &wp->links != &rt->watchPointList;
547 wp = (JSWatchPoint *)wp->links.next) {
548 sprop = wp->sprop;
549 if (wp->object == obj && SPROP_USERID(sprop) == id &&
550 !(wp->flags & JSWP_HELD)) {
551 wp->flags |= JSWP_HELD;
552 DBG_UNLOCK(rt);
553
554 JS_LOCK_OBJ(cx, obj);
555 propid = ID_TO_VALUE(sprop->id);
556 userid = (sprop->flags & SPROP_HAS_SHORTID)
557 ? INT_TO_JSVAL(sprop->shortid)
558 : propid;
559 scope = OBJ_SCOPE(obj);
560 JS_UNLOCK_OBJ(cx, obj);
561
562 /* NB: wp is held, so we can safely dereference it still. */
563 ok = wp->handler(cx, obj, propid,
564 SPROP_HAS_VALID_SLOT(sprop, scope)
565 ? OBJ_GET_SLOT(cx, obj, sprop->slot)
566 : JSVAL_VOID,
567 vp, wp->closure);
568 if (ok) {
569 /*
570 * Create a pseudo-frame for the setter invocation so that any
571 * stack-walking security code under the setter will correctly
572 * identify the guilty party. So that the watcher appears to
573 * be active to obj_eval and other such code, point frame.pc
574 * at the JSOP_STOP at the end of the script.
575 *
576 * The pseudo-frame is not created for fast natives as they
577 * are treated as interpreter frame extensions and always
578 * trusted.
579 */
580 JSObject *closure;
581 JSClass *clasp;
582 JSFunction *fun;
583 JSScript *script;
584 JSBool injectFrame;
585 uintN nslots;
586 jsval smallv[5];
587 jsval *argv;
588 JSStackFrame frame;
589 JSFrameRegs regs;
590
591 closure = (JSObject *) wp->closure;
592 clasp = OBJ_GET_CLASS(cx, closure);
593 if (clasp == &js_FunctionClass) {
594 fun = GET_FUNCTION_PRIVATE(cx, closure);
595 script = FUN_SCRIPT(fun);
596 } else if (clasp == &js_ScriptClass) {
597 fun = NULL;
598 script = (JSScript *) JS_GetPrivate(cx, closure);
599 } else {
600 fun = NULL;
601 script = NULL;
602 }
603
604 nslots = 2;
605 injectFrame = JS_TRUE;
606 if (fun) {
607 nslots += FUN_MINARGS(fun);
608 if (!FUN_INTERPRETED(fun)) {
609 nslots += fun->u.n.extra;
610 injectFrame = !(fun->flags & JSFUN_FAST_NATIVE);
611 }
612 }
613
614 if (injectFrame) {
615 if (nslots <= JS_ARRAY_LENGTH(smallv)) {
616 argv = smallv;
617 } else {
618 argv = (jsval *) JS_malloc(cx, nslots * sizeof(jsval));
619 if (!argv) {
620 DBG_LOCK(rt);
621 DropWatchPointAndUnlock(cx, wp, JSWP_HELD);
622 return JS_FALSE;
623 }
624 }
625
626 argv[0] = OBJECT_TO_JSVAL(closure);
627 argv[1] = JSVAL_NULL;
628 memset(argv + 2, 0, (nslots - 2) * sizeof(jsval));
629
630 memset(&frame, 0, sizeof(frame));
631 frame.script = script;
632 frame.regs = NULL;
633 if (script) {
634 JS_ASSERT(script->length >= JSOP_STOP_LENGTH);
635 regs.pc = script->code + script->length
636 - JSOP_STOP_LENGTH;
637 regs.sp = NULL;
638 frame.regs = &regs;
639 }
640 frame.callee = closure;
641 frame.fun = fun;
642 frame.argv = argv + 2;
643 frame.down = cx->fp;
644 frame.scopeChain = OBJ_GET_PARENT(cx, closure);
645
646 cx->fp = &frame;
647 }
648 #ifdef __GNUC__
649 else
650 argv = NULL; /* suppress bogus gcc warnings */
651 #endif
652 ok = !wp->setter ||
653 ((sprop->attrs & JSPROP_SETTER)
654 ? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(wp->setter),
655 1, vp, vp)
656 : wp->setter(cx, OBJ_THIS_OBJECT(cx, obj), userid, vp));
657 if (injectFrame) {
658 /* Evil code can cause us to have an arguments object. */
659 if (frame.callobj)
660 ok &= js_PutCallObject(cx, &frame);
661 if (frame.argsobj)
662 ok &= js_PutArgsObject(cx, &frame);
663
664 cx->fp = frame.down;
665 if (argv != smallv)
666 JS_free(cx, argv);
667 }
668 }
669 DBG_LOCK(rt);
670 return DropWatchPointAndUnlock(cx, wp, JSWP_HELD) && ok;
671 }
672 }
673 DBG_UNLOCK(rt);
674 return JS_TRUE;
675 }
676
677 JSBool
678 js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
679 jsval *rval)
680 {
681 JSObject *funobj;
682 JSFunction *wrapper;
683 jsval userid;
684
685 funobj = JSVAL_TO_OBJECT(argv[-2]);
686 JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass);
687 wrapper = GET_FUNCTION_PRIVATE(cx, funobj);
688 userid = ATOM_KEY(wrapper->atom);
689 *rval = argv[0];
690 return js_watch_set(cx, obj, userid, rval);
691 }
692
693 JSPropertyOp
694 js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter)
695 {
696 JSAtom *atom;
697 JSFunction *wrapper;
698
699 if (!(attrs & JSPROP_SETTER))
700 return &js_watch_set; /* & to silence schoolmarmish MSVC */
701
702 if (JSID_IS_ATOM(id)) {
703 atom = JSID_TO_ATOM(id);
704 } else if (JSID_IS_INT(id)) {
705 if (!js_ValueToStringId(cx, INT_JSID_TO_JSVAL(id), &id))
706 return NULL;
707 atom = JSID_TO_ATOM(id);
708 } else {
709 atom = NULL;
710 }
711 wrapper = js_NewFunction(cx, NULL, js_watch_set_wrapper, 1, 0,
712 OBJ_GET_PARENT(cx, (JSObject *)setter),
713 atom);
714 if (!wrapper)
715 return NULL;
716 return (JSPropertyOp) FUN_OBJECT(wrapper);
717 }
718
719 JS_PUBLIC_API(JSBool)
720 JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval idval,
721 JSWatchPointHandler handler, void *closure)
722 {
723 jsid propid;
724 JSObject *pobj;
725 JSProperty *prop;
726 JSScopeProperty *sprop;
727 JSRuntime *rt;
728 JSBool ok;
729 JSWatchPoint *wp;
730 JSPropertyOp watcher;
731
732 if (!OBJ_IS_NATIVE(obj)) {
733 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH,
734 OBJ_GET_CLASS(cx, obj)->name);
735 return JS_FALSE;
736 }
737
738 if (JSVAL_IS_INT(idval))
739 propid = INT_JSVAL_TO_JSID(idval);
740 else if (!js_ValueToStringId(cx, idval, &propid))
741 return JS_FALSE;
742
743 if (!js_LookupProperty(cx, obj, propid, &pobj, &prop))
744 return JS_FALSE;
745 sprop = (JSScopeProperty *) prop;
746 rt = cx->runtime;
747 if (!sprop) {
748 /* Check for a deleted symbol watchpoint, which holds its property. */
749 sprop = js_FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
750 if (!sprop) {
751 /* Make a new property in obj so we can watch for the first set. */
752 if (!js_DefineProperty(cx, obj, propid, JSVAL_VOID,
753 NULL, NULL, JSPROP_ENUMERATE,
754 &prop)) {
755 return JS_FALSE;
756 }
757 sprop = (JSScopeProperty *) prop;
758 }
759 } else if (pobj != obj) {
760 /* Clone the prototype property so we can watch the right object. */
761 jsval value;
762 JSPropertyOp getter, setter;
763 uintN attrs, flags;
764 intN shortid;
765
766 if (OBJ_IS_NATIVE(pobj)) {
767 value = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))
768 ? LOCKED_OBJ_GET_SLOT(pobj, sprop->slot)
769 : JSVAL_VOID;
770 getter = sprop->getter;
771 setter = sprop->setter;
772 attrs = sprop->attrs;
773 flags = sprop->flags;
774 shortid = sprop->shortid;
775 } else {
776 if (!OBJ_GET_PROPERTY(cx, pobj, propid, &value) ||
777 !OBJ_GET_ATTRIBUTES(cx, pobj, propid, prop, &attrs)) {
778 OBJ_DROP_PROPERTY(cx, pobj, prop);
779 return JS_FALSE;
780 }
781 getter = setter = NULL;
782 flags = 0;
783 shortid = 0;
784 }
785 OBJ_DROP_PROPERTY(cx, pobj, prop);
786
787 /* Recall that obj is native, whether or not pobj is native. */
788 if (!js_DefineNativeProperty(cx, obj, propid, value, getter, setter,
789 attrs, flags, shortid, &prop)) {
790 return JS_FALSE;
791 }
792 sprop = (JSScopeProperty *) prop;
793 }
794
795 /*
796 * At this point, prop/sprop exists in obj, obj is locked, and we must
797 * OBJ_DROP_PROPERTY(cx, obj, prop) before returning.
798 */
799 ok = JS_TRUE;
800 DBG_LOCK(rt);
801 wp = FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
802 if (!wp) {
803 DBG_UNLOCK(rt);
804 watcher = js_WrapWatchedSetter(cx, propid, sprop->attrs, sprop->setter);
805 if (!watcher) {
806 ok = JS_FALSE;
807 goto out;
808 }
809
810 wp = (JSWatchPoint *) JS_malloc(cx, sizeof *wp);
811 if (!wp) {
812 ok = JS_FALSE;
813 goto out;
814 }
815 wp->handler = NULL;
816 wp->closure = NULL;
817 wp->object = obj;
818 JS_ASSERT(sprop->setter != js_watch_set || pobj != obj);
819 wp->setter = sprop->setter;
820 wp->flags = JSWP_LIVE;
821
822 /* XXXbe nest in obj lock here */
823 sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop, 0, sprop->attrs,
824 sprop->getter, watcher);
825 if (!sprop) {
826 /* Self-link so DropWatchPointAndUnlock can JS_REMOVE_LINK it. */
827 JS_INIT_CLIST(&wp->links);
828 DBG_LOCK(rt);
829 DropWatchPointAndUnlock(cx, wp, JSWP_LIVE);
830 ok = JS_FALSE;
831 goto out;
832 }
833 wp->sprop = sprop;
834
835 /*
836 * Now that wp is fully initialized, append it to rt's wp list.
837 * Because obj is locked we know that no other thread could have added
838 * a watchpoint for (obj, propid).
839 */
840 DBG_LOCK(rt);
841 JS_ASSERT(!FindWatchPoint(rt, OBJ_SCOPE(obj), propid));
842 JS_APPEND_LINK(&wp->links, &rt->watchPointList);
843 ++rt->debuggerMutations;
844 }
845 wp->handler = handler;
846 wp->closure = closure;
847 DBG_UNLOCK(rt);
848
849 out:
850 OBJ_DROP_PROPERTY(cx, obj, prop);
851 return ok;
852 }
853
854 JS_PUBLIC_API(JSBool)
855 JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsval id,
856 JSWatchPointHandler *handlerp, void **closurep)
857 {
858 JSRuntime *rt;
859 JSWatchPoint *wp;
860
861 rt = cx->runtime;
862 DBG_LOCK(rt);
863 for (wp = (JSWatchPoint *)rt->watchPointList.next;
864 &wp->links != &rt->watchPointList;
865 wp = (JSWatchPoint *)wp->links.next) {
866 if (wp->object == obj && SPROP_USERID(wp->sprop) == id) {
867 if (handlerp)
868 *handlerp = wp->handler;
869 if (closurep)
870 *closurep = wp->closure;
871 return DropWatchPointAndUnlock(cx, wp, JSWP_LIVE);
872 }
873 }
874 DBG_UNLOCK(rt);
875 if (handlerp)
876 *handlerp = NULL;
877 if (closurep)
878 *closurep = NULL;
879 return JS_TRUE;
880 }
881
882 JS_PUBLIC_API(JSBool)
883 JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj)
884 {
885 JSRuntime *rt;
886 JSWatchPoint *wp, *next;
887 uint32 sample;
888
889 rt = cx->runtime;
890 DBG_LOCK(rt);
891 for (wp = (JSWatchPoint *)rt->watchPointList.next;
892 &wp->links != &rt->watchPointList;
893 wp = next) {
894 next = (JSWatchPoint *)wp->links.next;
895 if (wp->object == obj) {
896 sample = rt->debuggerMutations;
897 if (!DropWatchPointAndUnlock(cx, wp, JSWP_LIVE))
898 return JS_FALSE;
899 DBG_LOCK(rt);
900 if (rt->debuggerMutations != sample + 1)
901 next = (JSWatchPoint *)rt->watchPointList.next;
902 }
903 }
904 DBG_UNLOCK(rt);
905 return JS_TRUE;
906 }
907
908 JS_PUBLIC_API(JSBool)
909 JS_ClearAllWatchPoints(JSContext *cx)
910 {
911 JSRuntime *rt;
912 JSWatchPoint *wp, *next;
913 uint32 sample;
914
915 rt = cx->runtime;
916 DBG_LOCK(rt);
917 for (wp = (JSWatchPoint *)rt->watchPointList.next;
918 &wp->links != &rt->watchPointList;
919 wp = next) {
920 next = (JSWatchPoint *)wp->links.next;
921 sample = rt->debuggerMutations;
922 if (!DropWatchPointAndUnlock(cx, wp, JSWP_LIVE))
923 return JS_FALSE;
924 DBG_LOCK(rt);
925 if (rt->debuggerMutations != sample + 1)
926 next = (JSWatchPoint *)rt->watchPointList.next;
927 }
928 DBG_UNLOCK(rt);
929 return JS_TRUE;
930 }
931
932 /************************************************************************/
933
934 JS_PUBLIC_API(uintN)
935 JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
936 {
937 return js_PCToLineNumber(cx, script, pc);
938 }
939
940 JS_PUBLIC_API(jsbytecode *)
941 JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno)
942 {
943 return js_LineNumberToPC(script, lineno);
944 }
945
946 JS_PUBLIC_API(JSScript *)
947 JS_GetFunctionScript(JSContext *cx, JSFunction *fun)
948 {
949 return FUN_SCRIPT(fun);
950 }
951
952 JS_PUBLIC_API(JSNative)
953 JS_GetFunctionNative(JSContext *cx, JSFunction *fun)
954 {
955 return FUN_NATIVE(fun);
956 }
957
958 JS_PUBLIC_API(JSFastNative)
959 JS_GetFunctionFastNative(JSContext *cx, JSFunction *fun)
960 {
961 return FUN_FAST_NATIVE(fun);
962 }
963
964 JS_PUBLIC_API(JSPrincipals *)
965 JS_GetScriptPrincipals(JSContext *cx, JSScript *script)
966 {
967 return script->principals;
968 }
969
970 /************************************************************************/
971
972 /*
973 * Stack Frame Iterator
974 */
975 JS_PUBLIC_API(JSStackFrame *)
976 JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
977 {
978 *iteratorp = (*iteratorp == NULL) ? cx->fp : (*iteratorp)->down;
979 return *iteratorp;
980 }
981
982 JS_PUBLIC_API(JSScript *)
983 JS_GetFrameScript(JSContext *cx, JSStackFrame *fp)
984 {
985 return fp->script;
986 }
987
988 JS_PUBLIC_API(jsbytecode *)
989 JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
990 {
991 return fp->regs ? fp->regs->pc : NULL;
992 }
993
994 JS_PUBLIC_API(JSStackFrame *)
995 JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
996 {
997 if (!fp)
998 fp = cx->fp;
999 while (fp) {
1000 if (fp->script)
1001 return fp;
1002 fp = fp->down;
1003 }
1004 return NULL;
1005 }
1006
1007 JS_PUBLIC_API(JSPrincipals *)
1008 JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp)
1009 {
1010 JSSecurityCallbacks *callbacks;
1011
1012 if (fp->fun) {
1013 callbacks = JS_GetSecurityCallbacks(cx);
1014 if (callbacks && callbacks->findObjectPrincipals) {
1015 if (FUN_OBJECT(fp->fun) != fp->callee)
1016 return callbacks->findObjectPrincipals(cx, fp->callee);
1017 /* FALL THROUGH */
1018 }
1019 }
1020 if (fp->script)
1021 return fp->script->principals;
1022 return NULL;
1023 }
1024
1025 JS_PUBLIC_API(JSPrincipals *)
1026 JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller)
1027 {
1028 JSPrincipals *principals, *callerPrincipals;
1029 JSSecurityCallbacks *callbacks;
1030
1031 callbacks = JS_GetSecurityCallbacks(cx);
1032 if (callbacks && callbacks->findObjectPrincipals) {
1033 principals = callbacks->findObjectPrincipals(cx, fp->callee);
1034 } else {
1035 principals = NULL;
1036 }
1037 if (!caller)
1038 return principals;
1039 callerPrincipals = JS_StackFramePrincipals(cx, caller);
1040 return (callerPrincipals && principals &&
1041 callerPrincipals->subsume(callerPrincipals, principals))
1042 ? principals
1043 : callerPrincipals;
1044 }
1045
1046 JS_PUBLIC_API(void *)
1047 JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
1048 {
1049 if (fp->annotation && fp->script) {
1050 JSPrincipals *principals = JS_StackFramePrincipals(cx, fp);
1051
1052 if (principals && principals->globalPrivilegesEnabled(cx, principals)) {
1053 /*
1054 * Give out an annotation only if privileges have not been revoked
1055 * or disabled globally.
1056 */
1057 return fp->annotation;
1058 }
1059 }
1060
1061 return NULL;
1062 }
1063
1064 JS_PUBLIC_API(void)
1065 JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation)
1066 {
1067 fp->annotation = annotation;
1068 }
1069
1070 JS_PUBLIC_API(void *)
1071 JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp)
1072 {
1073 JSPrincipals *principals;
1074
1075 principals = JS_StackFramePrincipals(cx, fp);
1076 if (!principals)
1077 return NULL;
1078 return principals->getPrincipalArray(cx, principals);
1079 }
1080
1081 JS_PUBLIC_API(JSBool)
1082 JS_IsNativeFrame(JSContext *cx, JSStackFrame *fp)
1083 {
1084 return !fp->script;
1085 }
1086
1087 /* this is deprecated, use JS_GetFrameScopeChain instead */
1088 JS_PUBLIC_API(JSObject *)
1089 JS_GetFrameObject(JSContext *cx, JSStackFrame *fp)
1090 {
1091 return fp->scopeChain;
1092 }
1093
1094 JS_PUBLIC_API(JSObject *)
1095 JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp)
1096 {
1097 /* Force creation of argument and call objects if not yet created */
1098 (void) JS_GetFrameCallObject(cx, fp);
1099 return js_GetScopeChain(cx, fp);
1100 }
1101
1102 JS_PUBLIC_API(JSObject *)
1103 JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp)
1104 {
1105 if (! fp->fun)
1106 return NULL;
1107
1108 /* Force creation of argument object if not yet created */
1109 (void) js_GetArgsObject(cx, fp);
1110
1111 /*
1112 * XXX ill-defined: null return here means error was reported, unlike a
1113 * null returned above or in the #else
1114 */
1115 return js_GetCallObject(cx, fp, NULL);
1116 }
1117
1118 JS_PUBLIC_API(JSObject *)
1119 JS_GetFrameThis(JSContext *cx, JSStackFrame *fp)
1120 {
1121 JSStackFrame *afp;
1122
1123 if (fp->flags & JSFRAME_COMPUTED_THIS)
1124 return fp->thisp;
1125
1126 /* js_ComputeThis gets confused if fp != cx->fp, so set it aside. */
1127 if (cx->fp != fp) {
1128 afp = cx->fp;
1129 if (afp) {
1130 afp->dormantNext = cx->dormantFrameChain;
1131 cx->dormantFrameChain = afp;
1132 cx->fp = fp;
1133 }
1134 } else {
1135 afp = NULL;
1136 }
1137
1138 if (!fp->thisp && fp->argv)
1139 fp->thisp = js_ComputeThis(cx, JS_TRUE, fp->argv);
1140
1141 if (afp) {
1142 cx->fp = afp;
1143 cx->dormantFrameChain = afp->dormantNext;
1144 afp->dormantNext = NULL;
1145 }
1146
1147 return fp->thisp;
1148 }
1149
1150 JS_PUBLIC_API(JSFunction *)
1151 JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
1152 {
1153 return fp->fun;
1154 }
1155
1156 JS_PUBLIC_API(JSObject *)
1157 JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp)
1158 {
1159 if (!fp->fun)
1160 return NULL;
1161
1162 JS_ASSERT(OBJ_GET_CLASS(cx, fp->callee) == &js_FunctionClass);
1163 JS_ASSERT(OBJ_GET_PRIVATE(cx, fp->callee) == fp->fun);
1164 return fp->callee;
1165 }
1166
1167 JS_PUBLIC_API(JSBool)
1168 JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp)
1169 {
1170 return (fp->flags & JSFRAME_CONSTRUCTING) != 0;
1171 }
1172
1173 JS_PUBLIC_API(JSObject *)
1174 JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp)
1175 {
1176 return fp->callee;
1177 }
1178
1179 JS_PUBLIC_API(JSBool)
1180 JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp)
1181 {
1182 return (fp->flags & JSFRAME_DEBUGGER) != 0;
1183 }
1184
1185 JS_PUBLIC_API(jsval)
1186 JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp)
1187 {
1188 return fp->rval;
1189 }
1190
1191 JS_PUBLIC_API(void)
1192 JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval)
1193 {
1194 fp->rval = rval;
1195 }
1196
1197 /************************************************************************/
1198
1199 JS_PUBLIC_API(const char *)
1200 JS_GetScriptFilename(JSContext *cx, JSScript *script)
1201 {
1202 return script->filename;
1203 }
1204
1205 JS_PUBLIC_API(uintN)
1206 JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script)
1207 {
1208 return script->lineno;
1209 }
1210
1211 JS_PUBLIC_API(uintN)
1212 JS_GetScriptLineExtent(JSContext *cx, JSScript *script)
1213 {
1214 return js_GetScriptLineExtent(script);
1215 }
1216
1217 JS_PUBLIC_API(JSVersion)
1218 JS_GetScriptVersion(JSContext *cx, JSScript *script)
1219 {
1220 return (JSVersion) (script->version & JSVERSION_MASK);
1221 }
1222
1223 /***************************************************************************/
1224
1225 JS_PUBLIC_API(void)
1226 JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata)
1227 {
1228 rt->globalDebugHooks.newScriptHook = hook;
1229 rt->globalDebugHooks.newScriptHookData = callerdata;
1230 }
1231
1232 JS_PUBLIC_API(void)
1233 JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook,
1234 void *callerdata)
1235 {
1236 rt->globalDebugHooks.destroyScriptHook = hook;
1237 rt->globalDebugHooks.destroyScriptHookData = callerdata;
1238 }
1239
1240 /***************************************************************************/
1241
1242 JS_PUBLIC_API(JSBool)
1243 JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
1244 const jschar *chars, uintN length,
1245 const char *filename, uintN lineno,
1246 jsval *rval)
1247 {
1248 JSObject *scobj;
1249 JSScript *script;
1250 JSBool ok;
1251
1252 scobj = JS_GetFrameScopeChain(cx, fp);
1253 if (!scobj)
1254 return JS_FALSE;
1255
1256 script = js_CompileScript(cx, scobj, fp, JS_StackFramePrincipals(cx, fp),
1257 TCF_COMPILE_N_GO |
1258 TCF_PUT_STATIC_DEPTH(fp->script->staticDepth + 1),
1259 chars, length, NULL,
1260 filename, lineno);
1261 if (!script)
1262 return JS_FALSE;
1263
1264 ok = js_Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL,
1265 rval);
1266 js_DestroyScript(cx, script);
1267 return ok;
1268 }
1269
1270 JS_PUBLIC_API(JSBool)
1271 JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp,
1272 const char *bytes, uintN length,
1273 const char *filename, uintN lineno,
1274 jsval *rval)
1275 {
1276 jschar *chars;
1277 JSBool ok;
1278 size_t len = length;
1279
1280 chars = js_InflateString(cx, bytes, &len);
1281 if (!chars)
1282 return JS_FALSE;
1283 length = (uintN) len;
1284 ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length, filename, lineno,
1285 rval);
1286 JS_free(cx, chars);
1287
1288 return ok;
1289 }
1290
1291 /************************************************************************/
1292
1293 /* XXXbe this all needs to be reworked to avoid requiring JSScope types. */
1294
1295 JS_PUBLIC_API(JSScopeProperty *)
1296 JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp)
1297 {
1298 JSScopeProperty *sprop;
1299 JSScope *scope;
1300
1301 sprop = *iteratorp;
1302 scope = OBJ_SCOPE(obj);
1303
1304 /* XXXbe minor(?) incompatibility: iterate in reverse definition order */
1305 if (!sprop) {
1306 sprop = SCOPE_LAST_PROP(scope);
1307 } else {
1308 while ((sprop = sprop->parent) != NULL) {
1309 if (!SCOPE_HAD_MIDDLE_DELETE(scope))
1310 break;
1311 if (SCOPE_HAS_PROPERTY(scope, sprop))
1312 break;
1313 }
1314 }
1315 *iteratorp = sprop;
1316 return sprop;
1317 }
1318
1319 JS_PUBLIC_API(JSBool)
1320 JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
1321 JSPropertyDesc *pd)
1322 {
1323 JSScope *scope;
1324 JSScopeProperty *aprop;
1325 jsval lastException;
1326 JSBool wasThrowing;
1327
1328 pd->id = ID_TO_VALUE(sprop->id);
1329
1330 wasThrowing = cx->throwing;
1331 if (wasThrowing) {
1332 lastException = cx->exception;
1333 if (JSVAL_IS_GCTHING(lastException) &&
1334 !js_AddRoot(cx, &lastException, "lastException")) {
1335 return JS_FALSE;
1336 }
1337 cx->throwing = JS_FALSE;
1338 }
1339
1340 if (!js_GetProperty(cx, obj, sprop->id, &pd->value)) {
1341 if (!cx->throwing) {
1342 pd->flags = JSPD_ERROR;
1343 pd->value = JSVAL_VOID;
1344 } else {
1345 pd->flags = JSPD_EXCEPTION;
1346 pd->value = cx->exception;
1347 }
1348 } else {
1349 pd->flags = 0;
1350 }
1351
1352 cx->throwing = wasThrowing;
1353 if (wasThrowing) {
1354 cx->exception = lastException;
1355 if (JSVAL_IS_GCTHING(lastException))
1356 js_RemoveRoot(cx->runtime, &lastException);
1357 }
1358
1359 pd->flags |= ((sprop->attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0)
1360 | ((sprop->attrs & JSPROP_READONLY) ? JSPD_READONLY : 0)
1361 | ((sprop->attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0);
1362 pd->spare = 0;
1363 if (sprop->getter == js_GetCallArg) {
1364 pd->slot = sprop->shortid;
1365 pd->flags |= JSPD_ARGUMENT;
1366 } else if (sprop->getter == js_GetCallVar) {
1367 pd->slot = sprop->shortid;
1368 pd->flags |= JSPD_VARIABLE;
1369 } else {
1370 pd->slot = 0;
1371 }
1372 pd->alias = JSVAL_VOID;
1373 scope = OBJ_SCOPE(obj);
1374 if (SPROP_HAS_VALID_SLOT(sprop, scope)) {
1375 for (aprop = SCOPE_LAST_PROP(scope); aprop; aprop = aprop->parent) {
1376 if (aprop != sprop && aprop->slot == sprop->slot) {
1377 pd->alias = ID_TO_VALUE(aprop->id);
1378 break;
1379 }
1380 }
1381 }
1382 return JS_TRUE;
1383 }
1384
1385 JS_PUBLIC_API(JSBool)
1386 JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda)
1387 {
1388 JSClass *clasp;
1389 JSScope *scope;
1390 uint32 i, n;
1391 JSPropertyDesc *pd;
1392 JSScopeProperty *sprop;
1393
1394 clasp = OBJ_GET_CLASS(cx, obj);
1395 if (!OBJ_IS_NATIVE(obj) || (clasp->flags & JSCLASS_NEW_ENUMERATE)) {
1396 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1397 JSMSG_CANT_DESCRIBE_PROPS, clasp->name);
1398 return JS_FALSE;
1399 }
1400 if (!clasp->enumerate(cx, obj))
1401 return JS_FALSE;
1402
1403 /* have no props, or object's scope has not mutated from that of proto */
1404 scope = OBJ_SCOPE(obj);
1405 if (scope->object != obj || scope->entryCount == 0) {
1406 pda->length = 0;
1407 pda->array = NULL;
1408 return JS_TRUE;
1409 }
1410
1411 n = STOBJ_NSLOTS(obj);
1412 if (n > scope->entryCount)
1413 n = scope->entryCount;
1414 pd = (JSPropertyDesc *) JS_malloc(cx, (size_t)n * sizeof(JSPropertyDesc));
1415 if (!pd)
1416 return JS_FALSE;
1417 i = 0;
1418 for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
1419 if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop))
1420 continue;
1421 if (!js_AddRoot(cx, &pd[i].id, NULL))
1422 goto bad;
1423 if (!js_AddRoot(cx, &pd[i].value, NULL))
1424 goto bad;
1425 if (!JS_GetPropertyDesc(cx, obj, sprop, &pd[i]))
1426 goto bad;
1427 if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL))
1428 goto bad;
1429 if (++i == n)
1430 break;
1431 }
1432 pda->length = i;
1433 pda->array = pd;
1434 return JS_TRUE;
1435
1436 bad:
1437 pda->length = i + 1;
1438 pda->array = pd;
1439 JS_PutPropertyDescArray(cx, pda);
1440 return JS_FALSE;
1441 }
1442
1443 JS_PUBLIC_API(void)
1444 JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda)
1445 {
1446 JSPropertyDesc *pd;
1447 uint32 i;
1448
1449 pd = pda->array;
1450 for (i = 0; i < pda->length; i++) {
1451 js_RemoveRoot(cx->runtime, &pd[i].id);
1452 js_RemoveRoot(cx->runtime, &pd[i].value);
1453 if (pd[i].flags & JSPD_ALIAS)
1454 js_RemoveRoot(cx->runtime, &pd[i].alias);
1455 }
1456 JS_free(cx, pd);
1457 }
1458
1459 /************************************************************************/
1460
1461 JS_PUBLIC_API(JSBool)
1462 JS_SetDebuggerHandler(JSRuntime *rt, JSTrapHandler handler, void *closure)
1463 {
1464 rt->globalDebugHooks.debuggerHandler = handler;
1465 rt->globalDebugHooks.debuggerHandlerData = closure;
1466 return JS_TRUE;
1467 }
1468
1469 JS_PUBLIC_API(JSBool)
1470 JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure)
1471 {
1472 rt->globalDebugHooks.sourceHandler = handler;
1473 rt->globalDebugHooks.sourceHandlerData = closure;
1474 return JS_TRUE;
1475 }
1476
1477 JS_PUBLIC_API(JSBool)
1478 JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
1479 {
1480 rt->globalDebugHooks.executeHook = hook;
1481 rt->globalDebugHooks.executeHookData = closure;
1482 return JS_TRUE;
1483 }
1484
1485 JS_PUBLIC_API(JSBool)
1486 JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
1487 {
1488 rt->globalDebugHooks.callHook = hook;
1489 rt->globalDebugHooks.callHookData = closure;
1490 return JS_TRUE;
1491 }
1492
1493 JS_PUBLIC_API(JSBool)
1494 JS_SetObjectHook(JSRuntime *rt, JSObjectHook hook, void *closure)
1495 {
1496 rt->globalDebugHooks.objectHook = hook;
1497 rt->globalDebugHooks.objectHookData = closure;
1498 return JS_TRUE;
1499 }
1500
1501 JS_PUBLIC_API(JSBool)
1502 JS_SetThrowHook(JSRuntime *rt, JSTrapHandler hook, void *closure)
1503 {
1504 rt->globalDebugHooks.throwHook = hook;
1505 rt->globalDebugHooks.throwHookData = closure;
1506 return JS_TRUE;
1507 }
1508
1509 JS_PUBLIC_API(JSBool)
1510 JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure)
1511 {
1512 rt->globalDebugHooks.debugErrorHook = hook;
1513 rt->globalDebugHooks.debugErrorHookData = closure;
1514 return JS_TRUE;
1515 }
1516
1517 /************************************************************************/
1518
1519 JS_PUBLIC_API(size_t)
1520 JS_GetObjectTotalSize(JSContext *cx, JSObject *obj)
1521 {
1522 size_t nbytes;
1523 JSScope *scope;
1524
1525 nbytes = sizeof *obj;
1526 if (obj->dslots) {
1527 nbytes += ((uint32)obj->dslots[-1] - JS_INITIAL_NSLOTS + 1)
1528 * sizeof obj->dslots[0];
1529 }
1530 if (OBJ_IS_NATIVE(obj)) {
1531 scope = OBJ_SCOPE(obj);
1532 if (scope->object == obj) {
1533 nbytes += sizeof *scope;
1534 nbytes += SCOPE_CAPACITY(scope) * sizeof(JSScopeProperty *);
1535 }
1536 }
1537 return nbytes;
1538 }
1539
1540 static size_t
1541 GetAtomTotalSize(JSContext *cx, JSAtom *atom)
1542 {
1543 size_t nbytes;
1544
1545 nbytes = sizeof(JSAtom *) + sizeof(JSDHashEntryStub);
1546 if (ATOM_IS_STRING(atom)) {
1547 nbytes += sizeof(JSString);
1548 nbytes += (JSFLATSTR_LENGTH(ATOM_TO_STRING(atom)) + 1) * sizeof(jschar);
1549 } else if (ATOM_IS_DOUBLE(atom)) {
1550 nbytes += sizeof(jsdouble);
1551 }
1552 return nbytes;
1553 }
1554
1555 JS_PUBLIC_API(size_t)
1556 JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun)
1557 {
1558 size_t nbytes;
1559
1560 nbytes = sizeof *fun;
1561 nbytes += JS_GetObjectTotalSize(cx, FUN_OBJECT(fun));
1562 if (FUN_INTERPRETED(fun))
1563 nbytes += JS_GetScriptTotalSize(cx, fun->u.i.script);
1564 if (fun->atom)
1565 nbytes += GetAtomTotalSize(cx, fun->atom);
1566 return nbytes;
1567 }
1568
1569 #include "jsemit.h"
1570
1571 JS_PUBLIC_API(size_t)
1572 JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
1573 {
1574 size_t nbytes, pbytes;
1575 jsatomid i;
1576 jssrcnote *sn, *notes;
1577 JSObjectArray *objarray;
1578 JSPrincipals *principals;
1579
1580 nbytes = sizeof *script;
1581 if (script->u.object)
1582 nbytes += JS_GetObjectTotalSize(cx, script->u.object);
1583
1584 nbytes += script->length * sizeof script->code[0];
1585 nbytes += script->atomMap.length * sizeof script->atomMap.vector[0];
1586 for (i = 0; i < script->atomMap.length; i++)
1587 nbytes += GetAtomTotalSize(cx, script->atomMap.vector[i]);
1588
1589 if (script->filename)
1590 nbytes += strlen(script->filename) + 1;
1591
1592 notes = SCRIPT_NOTES(script);
1593 for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
1594 continue;
1595 nbytes += (sn - notes + 1) * sizeof *sn;
1596
1597 if (script->objectsOffset != 0) {
1598 objarray = JS_SCRIPT_OBJECTS(script);
1599 i = objarray->length;
1600 nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
1601 do {
1602 nbytes += JS_GetObjectTotalSize(cx, objarray->vector[--i]);
1603 } while (i != 0);
1604 }
1605
1606 if (script->regexpsOffset != 0) {
1607 objarray = JS_SCRIPT_REGEXPS(script);
1608 i = objarray->length;
1609 nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
1610 do {
1611 nbytes += JS_GetObjectTotalSize(cx, objarray->vector[--i]);
1612 } while (i != 0);
1613 }
1614
1615 if (script->trynotesOffset != 0) {
1616 nbytes += sizeof(JSTryNoteArray) +
1617 JS_SCRIPT_TRYNOTES(script)->length * sizeof(JSTryNote);
1618 }
1619
1620 principals = script->principals;
1621 if (principals) {
1622 JS_ASSERT(principals->refcount);
1623 pbytes = sizeof *principals;
1624 if (principals->refcount > 1)
1625 pbytes = JS_HOWMANY(pbytes, principals->refcount);
1626 nbytes += pbytes;
1627 }
1628
1629 return nbytes;
1630 }
1631
1632 JS_PUBLIC_API(uint32)
1633 JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp)
1634 {
1635 if (!fp)
1636 fp = cx->fp;
1637 while (fp) {
1638 if (fp->script)
1639 return JS_GetScriptFilenameFlags(fp->script);
1640 fp = fp->down;
1641 }
1642 return 0;
1643 }
1644
1645 JS_PUBLIC_API(uint32)
1646 JS_GetScriptFilenameFlags(JSScript *script)
1647 {
1648 JS_ASSERT(script);
1649 if (!script->filename)
1650 return JSFILENAME_NULL;
1651 return js_GetScriptFilenameFlags(script->filename);
1652 }
1653
1654 JS_PUBLIC_API(JSBool)
1655 JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags)
1656 {
1657 if (!js_SaveScriptFilenameRT(rt, prefix, flags))
1658 return JS_FALSE;
1659 return JS_TRUE;
1660 }
1661
1662 JS_PUBLIC_API(JSBool)
1663 JS_IsSystemObject(JSContext *cx, JSObject *obj)
1664 {
1665 return STOBJ_IS_SYSTEM(obj);
1666 }
1667
1668 JS_PUBLIC_API(JSObject *)
1669 JS_NewSystemObject(JSContext *cx, JSClass *clasp, JSObject *proto,
1670 JSObject *parent, JSBool system)
1671 {
1672 JSObject *obj;
1673
1674 obj = js_NewObject(cx, clasp, proto, parent, 0);
1675 if (obj && system)
1676 STOBJ_SET_SYSTEM(obj);
1677 return obj;
1678 }
1679
1680 /************************************************************************/
1681
1682 JS_PUBLIC_API(JSDebugHooks *)
1683 JS_GetGlobalDebugHooks(JSRuntime *rt)
1684 {
1685 return &rt->globalDebugHooks;
1686 }
1687
1688 JS_PUBLIC_API(JSDebugHooks *)
1689 JS_SetContextDebugHooks(JSContext *cx, JSDebugHooks *hooks)
1690 {
1691 JSDebugHooks *old;
1692
1693 JS_ASSERT(hooks);
1694 old = cx->debugHooks;
1695 cx->debugHooks = hooks;
1696 return old;
1697 }
1698
1699 #ifdef MOZ_SHARK
1700
1701 #include <CHUD/CHUD.h>
1702
1703 JS_PUBLIC_API(JSBool)
1704 JS_StartChudRemote()
1705 {
1706 if (chudIsRemoteAccessAcquired() &&
1707 (chudStartRemotePerfMonitor("Mozilla") == chudSuccess)) {
1708 return JS_TRUE;
1709 }
1710
1711 return JS_FALSE;
1712 }
1713
1714 JS_PUBLIC_API(JSBool)
1715 JS_StopChudRemote()
1716 {
1717 if (chudIsRemoteAccessAcquired() &&
1718 (chudStopRemotePerfMonitor() == chudSuccess)) {
1719 return JS_TRUE;
1720 }
1721
1722 return JS_FALSE;
1723 }
1724
1725 JS_PUBLIC_API(JSBool)
1726 JS_ConnectShark()
1727 {
1728 if (!chudIsInitialized() && (chudInitialize() != chudSuccess))
1729 return JS_FALSE;
1730
1731 if (chudAcquireRemoteAccess() != chudSuccess)
1732 return JS_FALSE;
1733
1734 return JS_TRUE;
1735 }
1736
1737 JS_PUBLIC_API(JSBool)
1738 JS_DisconnectShark()
1739 {
1740 if (chudIsRemoteAccessAcquired() && (chudReleaseRemoteAccess() != chudSuccess))
1741 return JS_FALSE;
1742
1743 return JS_TRUE;
1744 }
1745
1746 JS_FRIEND_API(JSBool)
1747 js_StartShark(JSContext *cx, JSObject *obj,
1748 uintN argc, jsval *argv, jsval *rval)
1749 {
1750 if (!JS_StartChudRemote()) {
1751 JS_ReportError(cx, "Error starting CHUD.");
1752 }
1753
1754 return JS_TRUE;
1755 }
1756
1757 JS_FRIEND_API(JSBool)
1758 js_StopShark(JSContext *cx, JSObject *obj,
1759 uintN argc, jsval *argv, jsval *rval)
1760 {
1761 if (!JS_StopChudRemote()) {
1762 JS_ReportError(cx, "Error stopping CHUD.");
1763 }
1764
1765 return JS_TRUE;
1766 }
1767
1768 JS_FRIEND_API(JSBool)
1769 js_ConnectShark(JSContext *cx, JSObject *obj,
1770 uintN argc, jsval *argv, jsval *rval)
1771 {
1772 if (!JS_ConnectShark()) {
1773 JS_ReportError(cx, "Error connecting to Shark.");
1774 }
1775
1776 return JS_TRUE;
1777 }
1778
1779 JS_FRIEND_API(JSBool)
1780 js_DisconnectShark(JSContext *cx, JSObject *obj,
1781 uintN argc, jsval *argv, jsval *rval)
1782 {
1783 if (!JS_DisconnectShark()) {
1784 JS_ReportError(cx, "Error disconnecting from Shark.");
1785 }
1786
1787 return JS_TRUE;
1788 }
1789
1790 #endif /* MOZ_SHARK */
1791
1792 #ifdef MOZ_CALLGRIND
1793
1794 #include <valgrind/callgrind.h>
1795
1796 JS_FRIEND_API(JSBool)
1797 js_StartCallgrind(JSContext *cx, JSObject *obj,
1798 uintN argc, jsval *argv, jsval *rval)
1799 {
1800 CALLGRIND_START_INSTRUMENTATION;
1801 CALLGRIND_ZERO_STATS;
1802 return JS_TRUE;
1803 }
1804
1805 JS_FRIEND_API(JSBool)
1806 js_StopCallgrind(JSContext *cx, JSObject *obj,
1807 uintN argc, jsval *argv, jsval *rval)
1808 {
1809 CALLGRIND_STOP_INSTRUMENTATION;
1810 return JS_TRUE;
1811 }
1812
1813 JS_FRIEND_API(JSBool)
1814 js_DumpCallgrind(JSContext *cx, JSObject *obj,
1815 uintN argc, jsval *argv, jsval *rval)
1816 {
1817 JSString *str;
1818 char *cstr;
1819
1820 if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
1821 str = JSVAL_TO_STRING(argv[0]);
1822 cstr = js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
1823 if (cstr) {
1824 CALLGRIND_DUMP_STATS_AT(cstr);
1825 JS_free(cx, cstr);
1826 return JS_TRUE;
1827 }
1828 }
1829 CALLGRIND_DUMP_STATS;
1830
1831 return JS_TRUE;
1832 }
1833
1834 #endif /* MOZ_CALLGRIND */
1835
1836 #ifdef MOZ_VTUNE
1837 #include <VTuneApi.h>
1838
1839 static const char *vtuneErrorMessages[] = {
1840 "unknown, error #0",
1841 "invalid 'max samples' field",
1842 "invalid 'samples per buffer' field",
1843 "invalid 'sample interval' field",
1844 "invalid path",
1845 "sample file in use",
1846 "invalid 'number of events' field",
1847 "unknown, error #7",
1848 "internal error",
1849 "bad event name",
1850 "VTStopSampling called without calling VTStartSampling",
1851 "no events selected for event-based sampling",
1852 "events selected cannot be run together",
1853 "no sampling parameters",
1854 "sample database already exists",
1855 "sampling already started",
1856 "time-based sampling not supported",
1857 "invalid 'sampling parameters size' field",
1858 "invalid 'event size' field",
1859 "sampling file already bound",
1860 "invalid event path",
1861 "invalid license",
1862 "invalid 'global options' field",
1863
1864 };
1865
1866 JS_FRIEND_API(JSBool)
1867 js_StartVtune(JSContext *cx, JSObject *obj,
1868 uintN argc, jsval *argv, jsval *rval)
1869 {
1870 VTUNE_EVENT events[] = {
1871 { 1000000, 0, 0, 0, "CPU_CLK_UNHALTED.CORE" },
1872 { 1000000, 0, 0, 0, "INST_RETIRED.ANY" },
1873 };
1874
1875 U32 n_events = sizeof(events) / sizeof(VTUNE_EVENT);
1876 char *default_filename = "mozilla-vtune.tb5";
1877 JSString *str;
1878 U32 status;
1879
1880 VTUNE_SAMPLING_PARAMS params = {
1881 sizeof(VTUNE_SAMPLING_PARAMS),
1882 sizeof(VTUNE_EVENT),
1883 0, 0, /* Reserved fields */
1884 1, /* Initialize in "paused" state */
1885 0, /* Max samples, or 0 for "continuous" */
1886 4096, /* Samples per buffer */
1887 0.1, /* Sampling interval in ms */
1888 1, /* 1 for event-based sampling, 0 for time-based */
1889
1890 n_events,
1891 events,
1892 default_filename,
1893 };
1894
1895 if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
1896 str = JSVAL_TO_STRING(argv[0]);
1897 params.tb5Filename = js_DeflateString(cx,
1898 JSSTRING_CHARS(str),
1899 JSSTRING_LENGTH(str));
1900 }
1901
1902 status = VTStartSampling(&params);
1903
1904 if (params.tb5Filename != default_filename)
1905 JS_free(cx, params.tb5Filename);
1906
1907 if (status != 0) {
1908 if (status == VTAPI_MULTIPLE_RUNS)
1909 VTStopSampling(0);
1910 if (status < sizeof(vtuneErrorMessages))
1911 JS_ReportError(cx, "Vtune setup error: %s",
1912 vtuneErrorMessages[status]);
1913 else
1914 JS_ReportError(cx, "Vtune setup error: %d",
1915 status);
1916 return JS_FALSE;
1917 }
1918 return JS_TRUE;
1919 }
1920
1921 JS_FRIEND_API(JSBool)
1922 js_StopVtune(JSContext *cx, JSObject *obj,
1923 uintN argc, jsval *argv, jsval *rval)
1924 {
1925 U32 status = VTStopSampling(1);
1926 if (status) {
1927 if (status < sizeof(vtuneErrorMessages))
1928 JS_ReportError(cx, "Vtune shutdown error: %s",
1929 vtuneErrorMessages[status]);
1930 else
1931 JS_ReportError(cx, "Vtune shutdown error: %d",
1932 status);
1933 return JS_FALSE;
1934 }
1935 return JS_TRUE;
1936 }
1937
1938 JS_FRIEND_API(JSBool)
1939 js_PauseVtune(JSContext *cx, JSObject *obj,
1940 uintN argc, jsval *argv, jsval *rval)
1941 {
1942 VTPause();
1943 return JS_TRUE;
1944 }
1945
1946 JS_FRIEND_API(JSBool)
1947 js_ResumeVtune(JSContext *cx, JSObject *obj,
1948 uintN argc, jsval *argv, jsval *rval)
1949 {
1950 VTResume();
1951 return JS_TRUE;
1952 }
1953
1954 #endif /* MOZ_VTUNE */

  ViewVC Help
Powered by ViewVC 1.1.24