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

Annotation of /trunk/js/jsdbgapi.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 332 - (hide annotations)
Thu Oct 23 19:03:33 2008 UTC (11 years, 5 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 siliconforks 332 /* -*- 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