Code

r11451@tres: ted | 2006-04-17 22:21:33 -0700
[inkscape.git] / src / dom / js / jsdbgapi.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * ***** BEGIN LICENSE BLOCK *****
4  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5  *
6  * The contents of this file are subject to the Mozilla Public License Version
7  * 1.1 (the "License"); you may not use this file except in compliance with
8  * the License. You may obtain a copy of the License at
9  * http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is Mozilla Communicator client code, released
17  * March 31, 1998.
18  *
19  * The Initial Developer of the Original Code is
20  * Netscape Communications Corporation.
21  * Portions created by the Initial Developer are Copyright (C) 1998
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Alternatively, the contents of this file may be used under the terms of
27  * either of the GNU General Public License Version 2 or later (the "GPL"),
28  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29  * in which case the provisions of the GPL or the LGPL are applicable instead
30  * of those above. If you wish to allow use of your version of this file only
31  * under the terms of either the GPL or the LGPL, and not to allow others to
32  * use your version of this file under the terms of the MPL, indicate your
33  * decision by deleting the provisions above and replace them with the notice
34  * and other provisions required by the GPL or the LGPL. If you do not delete
35  * the provisions above, a recipient may use your version of this file under
36  * the terms of any one of the MPL, the GPL or the LGPL.
37  *
38  * ***** END LICENSE BLOCK ***** */
40 /*
41  * JS debugging API.
42  */
43 #include "jsstddef.h"
44 #include <string.h>
45 #include "jstypes.h"
46 #include "jsutil.h" /* Added by JSIFY */
47 #include "jsclist.h"
48 #include "jsapi.h"
49 #include "jscntxt.h"
50 #include "jsconfig.h"
51 #include "jsdbgapi.h"
52 #include "jsfun.h"
53 #include "jsgc.h"
54 #include "jsinterp.h"
55 #include "jslock.h"
56 #include "jsobj.h"
57 #include "jsopcode.h"
58 #include "jsscope.h"
59 #include "jsscript.h"
60 #include "jsstr.h"
62 typedef struct JSTrap {
63     JSCList         links;
64     JSScript        *script;
65     jsbytecode      *pc;
66     JSOp            op;
67     JSTrapHandler   handler;
68     void            *closure;
69 } JSTrap;
71 static JSTrap *
72 FindTrap(JSRuntime *rt, JSScript *script, jsbytecode *pc)
73 {
74     JSTrap *trap;
76     for (trap = (JSTrap *)rt->trapList.next;
77          trap != (JSTrap *)&rt->trapList;
78          trap = (JSTrap *)trap->links.next) {
79         if (trap->script == script && trap->pc == pc)
80             return trap;
81     }
82     return NULL;
83 }
85 void
86 js_PatchOpcode(JSContext *cx, JSScript *script, jsbytecode *pc, JSOp op)
87 {
88     JSTrap *trap;
90     trap = FindTrap(cx->runtime, script, pc);
91     if (trap)
92         trap->op = op;
93     else
94         *pc = (jsbytecode)op;
95 }
97 JS_PUBLIC_API(JSBool)
98 JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
99            JSTrapHandler handler, void *closure)
101     JSRuntime *rt;
102     JSTrap *trap;
104     rt = cx->runtime;
105     trap = FindTrap(rt, script, pc);
106     if (trap) {
107         JS_ASSERT(trap->script == script && trap->pc == pc);
108         JS_ASSERT(*pc == JSOP_TRAP);
109     } else {
110         trap = (JSTrap *) JS_malloc(cx, sizeof *trap);
111         if (!trap || !js_AddRoot(cx, &trap->closure, "trap->closure")) {
112             if (trap)
113                 JS_free(cx, trap);
114             return JS_FALSE;
115         }
116         JS_APPEND_LINK(&trap->links, &rt->trapList);
117         trap->script = script;
118         trap->pc = pc;
119         trap->op = (JSOp)*pc;
120         *pc = JSOP_TRAP;
121     }
122     trap->handler = handler;
123     trap->closure = closure;
124     return JS_TRUE;
127 JS_PUBLIC_API(JSOp)
128 JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
130     JSTrap *trap;
132     trap = FindTrap(cx->runtime, script, pc);
133     if (!trap) {
134         JS_ASSERT(0);   /* XXX can't happen */
135         return JSOP_LIMIT;
136     }
137     return trap->op;
140 static void
141 DestroyTrap(JSContext *cx, JSTrap *trap)
143     JS_REMOVE_LINK(&trap->links);
144     *trap->pc = (jsbytecode)trap->op;
145     js_RemoveRoot(cx->runtime, &trap->closure);
146     JS_free(cx, trap);
149 JS_PUBLIC_API(void)
150 JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
151              JSTrapHandler *handlerp, void **closurep)
153     JSTrap *trap;
155     trap = FindTrap(cx->runtime, script, pc);
156     if (handlerp)
157         *handlerp = trap ? trap->handler : NULL;
158     if (closurep)
159         *closurep = trap ? trap->closure : NULL;
160     if (trap)
161         DestroyTrap(cx, trap);
164 JS_PUBLIC_API(void)
165 JS_ClearScriptTraps(JSContext *cx, JSScript *script)
167     JSRuntime *rt;
168     JSTrap *trap, *next;
170     rt = cx->runtime;
171     for (trap = (JSTrap *)rt->trapList.next;
172          trap != (JSTrap *)&rt->trapList;
173          trap = next) {
174         next = (JSTrap *)trap->links.next;
175         if (trap->script == script)
176             DestroyTrap(cx, trap);
177     }
180 JS_PUBLIC_API(void)
181 JS_ClearAllTraps(JSContext *cx)
183     JSRuntime *rt;
184     JSTrap *trap, *next;
186     rt = cx->runtime;
187     for (trap = (JSTrap *)rt->trapList.next;
188          trap != (JSTrap *)&rt->trapList;
189          trap = next) {
190         next = (JSTrap *)trap->links.next;
191         DestroyTrap(cx, trap);
192     }
195 JS_PUBLIC_API(JSTrapStatus)
196 JS_HandleTrap(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval)
198     JSTrap *trap;
199     JSTrapStatus status;
200     jsint op;
202     trap = FindTrap(cx->runtime, script, pc);
203     if (!trap) {
204         JS_ASSERT(0);   /* XXX can't happen */
205         return JSTRAP_ERROR;
206     }
207     /*
208      * It's important that we not use 'trap->' after calling the callback --
209      * the callback might remove the trap!
210      */
211     op = (jsint)trap->op;
212     status = trap->handler(cx, script, pc, rval, trap->closure);
213     if (status == JSTRAP_CONTINUE) {
214         /* By convention, return the true op to the interpreter in rval. */
215         *rval = INT_TO_JSVAL(op);
216     }
217     return status;
220 JS_PUBLIC_API(JSBool)
221 JS_SetInterrupt(JSRuntime *rt, JSTrapHandler handler, void *closure)
223     rt->interruptHandler = handler;
224     rt->interruptHandlerData = closure;
225     return JS_TRUE;
228 JS_PUBLIC_API(JSBool)
229 JS_ClearInterrupt(JSRuntime *rt, JSTrapHandler *handlerp, void **closurep)
231     if (handlerp)
232         *handlerp = (JSTrapHandler)rt->interruptHandler;
233     if (closurep)
234         *closurep = rt->interruptHandlerData;
235     rt->interruptHandler = 0;
236     rt->interruptHandlerData = 0;
237     return JS_TRUE;
240 /************************************************************************/
242 typedef struct JSWatchPoint {
243     JSCList             links;
244     JSObject            *object;        /* weak link, see js_FinalizeObject */
245     JSScopeProperty     *sprop;
246     JSPropertyOp        setter;
247     JSWatchPointHandler handler;
248     void                *closure;
249     jsrefcount          nrefs;
250 } JSWatchPoint;
252 #define HoldWatchPoint(wp) ((wp)->nrefs++)
254 static JSBool
255 DropWatchPoint(JSContext *cx, JSWatchPoint *wp)
257     JSScopeProperty *sprop;
259     if (--wp->nrefs != 0)
260         return JS_TRUE;
262     /*
263      * Remove wp from the list, then if there are no other watchpoints for
264      * wp->sprop in any scope, restore wp->sprop->setter from wp.
265      */
266     JS_REMOVE_LINK(&wp->links);
267     sprop = wp->sprop;
268     if (!js_GetWatchedSetter(cx->runtime, NULL, sprop)) {
269         sprop = js_ChangeNativePropertyAttrs(cx, wp->object, sprop,
270                                              0, sprop->attrs,
271                                              sprop->getter, wp->setter);
272         if (!sprop)
273             return JS_FALSE;
274     }
275     js_RemoveRoot(cx->runtime, &wp->closure);
276     JS_free(cx, wp);
277     return JS_TRUE;
280 void
281 js_MarkWatchPoints(JSRuntime *rt)
283     JSWatchPoint *wp;
285     for (wp = (JSWatchPoint *)rt->watchPointList.next;
286          wp != (JSWatchPoint *)&rt->watchPointList;
287          wp = (JSWatchPoint *)wp->links.next) {
288         MARK_SCOPE_PROPERTY(wp->sprop);
289     }
292 static JSWatchPoint *
293 FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id)
295     JSWatchPoint *wp;
297     for (wp = (JSWatchPoint *)rt->watchPointList.next;
298          wp != (JSWatchPoint *)&rt->watchPointList;
299          wp = (JSWatchPoint *)wp->links.next) {
300         if (wp->object == scope->object && wp->sprop->id == id)
301             return wp;
302     }
303     return NULL;
306 JSScopeProperty *
307 js_FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id)
309     JSWatchPoint *wp;
311     wp = FindWatchPoint(rt, scope, id);
312     if (!wp)
313         return NULL;
314     return wp->sprop;
317 JSPropertyOp
318 js_GetWatchedSetter(JSRuntime *rt, JSScope *scope,
319                     const JSScopeProperty *sprop)
321     JSWatchPoint *wp;
323     for (wp = (JSWatchPoint *)rt->watchPointList.next;
324          wp != (JSWatchPoint *)&rt->watchPointList;
325          wp = (JSWatchPoint *)wp->links.next) {
326         if ((!scope || wp->object == scope->object) && wp->sprop == sprop)
327             return wp->setter;
328     }
329     return NULL;
332 JSBool JS_DLL_CALLBACK
333 js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
335     JSRuntime *rt;
336     JSWatchPoint *wp;
337     JSScopeProperty *sprop;
338     jsval userid;
339     JSScope *scope;
340     JSBool ok;
342     rt = cx->runtime;
343     for (wp = (JSWatchPoint *)rt->watchPointList.next;
344          wp != (JSWatchPoint *)&rt->watchPointList;
345          wp = (JSWatchPoint *)wp->links.next) {
346         sprop = wp->sprop;
347         if (wp->object == obj && SPROP_USERID(sprop) == id) {
348             JS_LOCK_OBJ(cx, obj);
349             userid = SPROP_USERID(sprop);
350             scope = OBJ_SCOPE(obj);
351             JS_UNLOCK_OBJ(cx, obj);
352             HoldWatchPoint(wp);
353             ok = wp->handler(cx, obj, userid,
354                              SPROP_HAS_VALID_SLOT(sprop, scope)
355                              ? OBJ_GET_SLOT(cx, obj, wp->sprop->slot)
356                              : JSVAL_VOID,
357                              vp, wp->closure);
358             if (ok) {
359                 /*
360                  * Create pseudo-frame for call to setter so that any
361                  * stack-walking security code in the setter will correctly
362                  * identify the guilty party.
363                  */
364                 JSObject *funobj = (JSObject *) wp->closure;
365                 JSFunction *fun = (JSFunction *) JS_GetPrivate(cx, funobj);
366                 JSStackFrame frame;
368                 memset(&frame, 0, sizeof(frame));
369                 frame.script = FUN_SCRIPT(fun);
370                 frame.fun = fun;
371                 frame.down = cx->fp;
372                 cx->fp = &frame;
373                 ok = !wp->setter ||
374                      ((sprop->attrs & JSPROP_SETTER)
375                       ? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(wp->setter),
376                                         1, vp, vp)
377                       : wp->setter(cx, OBJ_THIS_OBJECT(cx, obj), userid, vp));
378                 cx->fp = frame.down;
379             }
380             return DropWatchPoint(cx, wp);
381         }
382     }
383     JS_ASSERT(0);       /* XXX can't happen */
384     return JS_FALSE;
387 JSBool JS_DLL_CALLBACK
388 js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
389                      jsval *rval)
391     JSObject *funobj;
392     JSFunction *wrapper;
393     jsval userid;
395     funobj = JSVAL_TO_OBJECT(argv[-2]);
396     wrapper = (JSFunction *) JS_GetPrivate(cx, funobj);
397     userid = ATOM_KEY(wrapper->atom);
398     *rval = argv[0];
399     return js_watch_set(cx, obj, userid, rval);
402 JSPropertyOp
403 js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter)
405     JSAtom *atom;
406     JSFunction *wrapper;
408     if (!(attrs & JSPROP_SETTER))
409         return &js_watch_set;   /* & to silence schoolmarmish MSVC */
411     if (!JSVAL_IS_INT(id)) {
412         atom = (JSAtom *)id;
413     } else {
414         atom = js_AtomizeInt(cx, JSVAL_TO_INT(id), 0);
415         if (!atom)
416             return NULL;
417     }
418     wrapper = js_NewFunction(cx, NULL, js_watch_set_wrapper, 1, 0,
419                              OBJ_GET_PARENT(cx, (JSObject *)setter),
420                              atom);
421     if (!wrapper)
422         return NULL;
423     return (JSPropertyOp) wrapper->object;
426 JS_PUBLIC_API(JSBool)
427 JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id,
428                  JSWatchPointHandler handler, void *closure)
430     JSAtom *atom;
431     jsid propid;
432     JSObject *pobj;
433     JSProperty *prop;
434     JSScopeProperty *sprop;
435     JSRuntime *rt;
436     JSBool ok;
437     JSWatchPoint *wp;
438     JSPropertyOp watcher;
440     if (!OBJ_IS_NATIVE(obj)) {
441         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH,
442                              OBJ_GET_CLASS(cx, obj)->name);
443         return JS_FALSE;
444     }
446     if (JSVAL_IS_INT(id)) {
447         propid = (jsid)id;
448         atom = NULL;
449     } else {
450         atom = js_ValueToStringAtom(cx, id);
451         if (!atom)
452             return JS_FALSE;
453         propid = (jsid)atom;
454     }
456     if (!js_LookupProperty(cx, obj, propid, &pobj, &prop))
457         return JS_FALSE;
458     sprop = (JSScopeProperty *) prop;
459     rt = cx->runtime;
460     if (!sprop) {
461         /* Check for a deleted symbol watchpoint, which holds its property. */
462         sprop = js_FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
463         if (!sprop) {
464             /* Make a new property in obj so we can watch for the first set. */
465             if (!js_DefineProperty(cx, obj, propid, JSVAL_VOID,
466                                    NULL, NULL, JSPROP_ENUMERATE,
467                                    &prop)) {
468                 return JS_FALSE;
469             }
470             sprop = (JSScopeProperty *) prop;
471         }
472     } else if (pobj != obj) {
473         /* Clone the prototype property so we can watch the right object. */
474         jsval value;
475         JSPropertyOp getter, setter;
476         uintN attrs;
478         if (OBJ_IS_NATIVE(pobj)) {
479             value = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))
480                     ? LOCKED_OBJ_GET_SLOT(pobj, sprop->slot)
481                     : JSVAL_VOID;
482             getter = sprop->getter;
483             setter = sprop->setter;
484             attrs = sprop->attrs;
485         } else {
486             if (!OBJ_GET_PROPERTY(cx, pobj, id, &value)) {
487                 OBJ_DROP_PROPERTY(cx, pobj, prop);
488                 return JS_FALSE;
489             }
490             getter = setter = JS_PropertyStub;
491             attrs = JSPROP_ENUMERATE;
492         }
493         OBJ_DROP_PROPERTY(cx, pobj, prop);
495         if (!js_DefineProperty(cx, obj, propid, value, getter, setter, attrs,
496                                &prop)) {
497             return JS_FALSE;
498         }
499         sprop = (JSScopeProperty *) prop;
500     }
502     /*
503      * At this point, prop/sprop exists in obj, obj is locked, and we must
504      * OBJ_DROP_PROPERTY(cx, obj, prop) before returning.
505      */
506     ok = JS_TRUE;
507     wp = FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
508     if (!wp) {
509         watcher = js_WrapWatchedSetter(cx, propid, sprop->attrs, sprop->setter);
510         if (!watcher) {
511             ok = JS_FALSE;
512             goto out;
513         }
515         wp = (JSWatchPoint *) JS_malloc(cx, sizeof *wp);
516         if (!wp) {
517             ok = JS_FALSE;
518             goto out;
519         }
520         wp->handler = NULL;
521         wp->closure = NULL;
522         ok = js_AddRoot(cx, &wp->closure, "wp->closure");
523         if (!ok) {
524             JS_free(cx, wp);
525             goto out;
526         }
527         JS_APPEND_LINK(&wp->links, &rt->watchPointList);
528         wp->object = obj;
529         wp->sprop = sprop;
530         JS_ASSERT(sprop->setter != js_watch_set);
531         wp->setter = sprop->setter;
532         wp->nrefs = 1;
534         /* XXXbe nest in obj lock here */
535         sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop, 0, sprop->attrs,
536                                              sprop->getter, watcher);
537         if (!sprop) {
538             DropWatchPoint(cx, wp);
539             ok = JS_FALSE;
540             goto out;
541         }
542     }
543     wp->handler = handler;
544     wp->closure = closure;
546 out:
547     OBJ_DROP_PROPERTY(cx, obj, prop);
548     return ok;
551 JS_PUBLIC_API(JSBool)
552 JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsval id,
553                    JSWatchPointHandler *handlerp, void **closurep)
555     JSRuntime *rt;
556     JSWatchPoint *wp;
558     rt = cx->runtime;
559     for (wp = (JSWatchPoint *)rt->watchPointList.next;
560          wp != (JSWatchPoint *)&rt->watchPointList;
561          wp = (JSWatchPoint *)wp->links.next) {
562         if (wp->object == obj && SPROP_USERID(wp->sprop) == id) {
563             if (handlerp)
564                 *handlerp = wp->handler;
565             if (closurep)
566                 *closurep = wp->closure;
567             return DropWatchPoint(cx, wp);
568         }
569     }
570     if (handlerp)
571         *handlerp = NULL;
572     if (closurep)
573         *closurep = NULL;
574     return JS_TRUE;
577 JS_PUBLIC_API(JSBool)
578 JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj)
580     JSRuntime *rt;
581     JSWatchPoint *wp, *next;
583     rt = cx->runtime;
584     for (wp = (JSWatchPoint *)rt->watchPointList.next;
585          wp != (JSWatchPoint *)&rt->watchPointList;
586          wp = next) {
587         next = (JSWatchPoint *)wp->links.next;
588         if (wp->object == obj && !DropWatchPoint(cx, wp))
589             return JS_FALSE;
590     }
591     return JS_TRUE;
594 JS_PUBLIC_API(JSBool)
595 JS_ClearAllWatchPoints(JSContext *cx)
597     JSRuntime *rt;
598     JSWatchPoint *wp, *next;
600     rt = cx->runtime;
601     for (wp = (JSWatchPoint *)rt->watchPointList.next;
602          wp != (JSWatchPoint *)&rt->watchPointList;
603          wp = next) {
604         next = (JSWatchPoint *)wp->links.next;
605         if (!DropWatchPoint(cx, wp))
606             return JS_FALSE;
607     }
608     return JS_TRUE;
611 /************************************************************************/
613 JS_PUBLIC_API(uintN)
614 JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
616     return js_PCToLineNumber(cx, script, pc);
619 JS_PUBLIC_API(jsbytecode *)
620 JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno)
622     return js_LineNumberToPC(script, lineno);
625 JS_PUBLIC_API(JSScript *)
626 JS_GetFunctionScript(JSContext *cx, JSFunction *fun)
628     return FUN_SCRIPT(fun);
631 JS_PUBLIC_API(JSPrincipals *)
632 JS_GetScriptPrincipals(JSContext *cx, JSScript *script)
634     return script->principals;
637 /************************************************************************/
639 /*
640  *  Stack Frame Iterator
641  */
642 JS_PUBLIC_API(JSStackFrame *)
643 JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
645     *iteratorp = (*iteratorp == NULL) ? cx->fp : (*iteratorp)->down;
646     return *iteratorp;
649 JS_PUBLIC_API(JSScript *)
650 JS_GetFrameScript(JSContext *cx, JSStackFrame *fp)
652     return fp->script;
655 JS_PUBLIC_API(jsbytecode *)
656 JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
658     return fp->pc;
661 JS_PUBLIC_API(JSStackFrame *)
662 JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
664     if (!fp)
665         fp = cx->fp;
666     while ((fp = fp->down) != NULL) {
667         if (fp->script)
668             return fp;
669     }
670     return NULL;
673 JS_PUBLIC_API(JSPrincipals *)
674 JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp)
676     if (fp->fun && cx->findObjectPrincipals) {
677         JSObject *callee = JSVAL_TO_OBJECT(fp->argv[-2]);
679         if (fp->fun->object != callee)
680             return cx->findObjectPrincipals(cx, callee);
681         /* FALL THROUGH */
682     }
683     if (fp->script)
684         return fp->script->principals;
685     return NULL;
688 JS_PUBLIC_API(JSPrincipals *)
689 JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller)
691     if (cx->findObjectPrincipals)
692         return cx->findObjectPrincipals(cx, JSVAL_TO_OBJECT(fp->argv[-2]));
693     if (!caller)
694         return NULL;
695     return JS_StackFramePrincipals(cx, caller);
698 JS_PUBLIC_API(void *)
699 JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
701     if (fp->annotation && fp->script) {
702         JSPrincipals *principals = JS_StackFramePrincipals(cx, fp);
704         if (principals && principals->globalPrivilegesEnabled(cx, principals)) {
705             /*
706              * Give out an annotation only if privileges have not been revoked
707              * or disabled globally.
708              */
709             return fp->annotation;
710         }
711     }
713     return NULL;
716 JS_PUBLIC_API(void)
717 JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation)
719     fp->annotation = annotation;
722 JS_PUBLIC_API(void *)
723 JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp)
725     JSPrincipals *principals;
727     principals = JS_StackFramePrincipals(cx, fp);
728     if (!principals)
729         return NULL;
730     return principals->getPrincipalArray(cx, principals);
733 JS_PUBLIC_API(JSBool)
734 JS_IsNativeFrame(JSContext *cx, JSStackFrame *fp)
736     return !fp->script;
739 /* this is deprecated, use JS_GetFrameScopeChain instead */
740 JS_PUBLIC_API(JSObject *)
741 JS_GetFrameObject(JSContext *cx, JSStackFrame *fp)
743     return fp->scopeChain;
746 JS_PUBLIC_API(JSObject *)
747 JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp)
749     /* Force creation of argument and call objects if not yet created */
750     (void) JS_GetFrameCallObject(cx, fp);
751     return fp->scopeChain;
754 JS_PUBLIC_API(JSObject *)
755 JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp)
757     if (! fp->fun)
758         return NULL;
759 #if JS_HAS_ARGS_OBJECT
760     /* Force creation of argument object if not yet created */
761     (void) js_GetArgsObject(cx, fp);
762 #endif
763 #if JS_HAS_CALL_OBJECT
764     /*
765      * XXX ill-defined: null return here means error was reported, unlike a
766      *     null returned above or in the #else
767      */
768     return js_GetCallObject(cx, fp, NULL);
769 #else
770     return NULL;
771 #endif /* JS_HAS_CALL_OBJECT */
775 JS_PUBLIC_API(JSObject *)
776 JS_GetFrameThis(JSContext *cx, JSStackFrame *fp)
778     return fp->thisp;
781 JS_PUBLIC_API(JSFunction *)
782 JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
784     return fp->fun;
787 JS_PUBLIC_API(JSObject *)
788 JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp)
790     return fp->argv && fp->fun ? JSVAL_TO_OBJECT(fp->argv[-2]) : NULL;
793 JS_PUBLIC_API(JSBool)
794 JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp)
796     return (fp->flags & JSFRAME_CONSTRUCTING) != 0;
799 JS_PUBLIC_API(JSBool)
800 JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp)
802     return (fp->flags & JSFRAME_DEBUGGER) != 0;
805 JS_PUBLIC_API(jsval)
806 JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp)
808     return fp->rval;
811 JS_PUBLIC_API(void)
812 JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval)
814     fp->rval = rval;
817 /************************************************************************/
819 JS_PUBLIC_API(const char *)
820 JS_GetScriptFilename(JSContext *cx, JSScript *script)
822     return script->filename;
825 JS_PUBLIC_API(uintN)
826 JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script)
828     return script->lineno;
831 JS_PUBLIC_API(uintN)
832 JS_GetScriptLineExtent(JSContext *cx, JSScript *script)
834     return js_GetScriptLineExtent(script);
837 JS_PUBLIC_API(JSVersion)
838 JS_GetScriptVersion(JSContext *cx, JSScript *script)
840     return script->version;
843 /***************************************************************************/
845 JS_PUBLIC_API(void)
846 JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata)
848     rt->newScriptHook = hook;
849     rt->newScriptHookData = callerdata;
852 JS_PUBLIC_API(void)
853 JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook,
854                         void *callerdata)
856     rt->destroyScriptHook = hook;
857     rt->destroyScriptHookData = callerdata;
860 /***************************************************************************/
862 JS_PUBLIC_API(JSBool)
863 JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
864                           const jschar *bytes, uintN length,
865                           const char *filename, uintN lineno,
866                           jsval *rval)
868     uint32 flags;
869     JSScript *script;
870     JSBool ok;
872     /*
873      * XXX Hack around ancient compiler API to propagate the JSFRAME_SPECIAL
874      * flags to the code generator (see js_EmitTree's TOK_SEMI case).
875      */
876     flags = fp->flags;
877     fp->flags |= JSFRAME_DEBUGGER | JSFRAME_EVAL;
878     script = JS_CompileUCScriptForPrincipals(cx, fp->scopeChain,
879                                              JS_StackFramePrincipals(cx, fp),
880                                              bytes, length, filename, lineno);
881     fp->flags = flags;
882     if (!script)
883         return JS_FALSE;
885     ok = js_Execute(cx, fp->scopeChain, script, fp,
886                     JSFRAME_DEBUGGER | JSFRAME_EVAL, rval);
887     js_DestroyScript(cx, script);
888     return ok;
891 JS_PUBLIC_API(JSBool)
892 JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp,
893                         const char *bytes, uintN length,
894                         const char *filename, uintN lineno,
895                         jsval *rval)
897     jschar *chars;
898     JSBool ok;
900     chars = js_InflateString(cx, bytes, length);
901     if (!chars)
902         return JS_FALSE;
903     ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length, filename, lineno,
904                                    rval);
905     JS_free(cx, chars);
907     return ok;
910 /************************************************************************/
912 /* XXXbe this all needs to be reworked to avoid requiring JSScope types. */
914 JS_PUBLIC_API(JSScopeProperty *)
915 JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp)
917     JSScopeProperty *sprop;
918     JSScope *scope;
920     sprop = *iteratorp;
921     scope = OBJ_SCOPE(obj);
923     /* XXXbe minor(?) incompatibility: iterate in reverse definition order */
924     if (!sprop) {
925         sprop = SCOPE_LAST_PROP(scope);
926     } else {
927         while ((sprop = sprop->parent) != NULL) {
928             if (!SCOPE_HAD_MIDDLE_DELETE(scope))
929                 break;
930             if (SCOPE_HAS_PROPERTY(scope, sprop))
931                 break;
932         }
933     }
934     *iteratorp = sprop;
935     return sprop;
938 JS_PUBLIC_API(JSBool)
939 JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
940                    JSPropertyDesc *pd)
942     JSPropertyOp getter;
943     JSScope *scope;
944     JSScopeProperty *aprop;
945     jsval lastException;
946     JSBool wasThrowing;
948     pd->id = ID_TO_VALUE(sprop->id);
950     wasThrowing = cx->throwing;
951     if (wasThrowing) {
952         lastException = cx->exception;
953         if (JSVAL_IS_GCTHING(lastException) &&
954             !js_AddRoot(cx, &lastException, "lastException")) {
955                 return JS_FALSE;
956         }
957         cx->throwing = JS_FALSE;
958     }
960     if (!js_GetProperty(cx, obj, sprop->id, &pd->value)) {
961         if (!cx->throwing) {
962             pd->flags = JSPD_ERROR;
963             pd->value = JSVAL_VOID;
964         } else {
965             pd->flags = JSPD_EXCEPTION;
966             pd->value = cx->exception;
967         }
968     } else {
969         pd->flags = 0;
970     }
972     cx->throwing = wasThrowing;
973     if (wasThrowing) {
974         cx->exception = lastException;
975         if (JSVAL_IS_GCTHING(lastException))
976             js_RemoveRoot(cx->runtime, &lastException);
977     }
979     getter = sprop->getter;
980     pd->flags |= ((sprop->attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0)
981               | ((sprop->attrs & JSPROP_READONLY)  ? JSPD_READONLY  : 0)
982               | ((sprop->attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0)
983 #if JS_HAS_CALL_OBJECT
984               | ((getter == js_GetCallVariable)    ? JSPD_VARIABLE  : 0)
985 #endif /* JS_HAS_CALL_OBJECT */
986               | ((getter == js_GetArgument)        ? JSPD_ARGUMENT  : 0)
987               | ((getter == js_GetLocalVariable)   ? JSPD_VARIABLE  : 0);
988 #if JS_HAS_CALL_OBJECT
989     /* for Call Object 'real' getter isn't passed in to us */
990     if (OBJ_GET_CLASS(cx, obj) == &js_CallClass &&
991         getter == js_CallClass.getProperty) {
992         /*
993          * Property of a heavyweight function's variable object having the
994          * class-default getter.  It's either an argument if permanent, or a
995          * nested function if impermanent.  Local variables have a special
996          * getter (js_GetCallVariable, tested above) and setter, and not the
997          * class default.
998          */
999         pd->flags |= (sprop->attrs & JSPROP_PERMANENT)
1000                      ? JSPD_ARGUMENT
1001                      : JSPD_VARIABLE;
1002     }
1003 #endif /* JS_HAS_CALL_OBJECT */
1004     pd->spare = 0;
1005     pd->slot = (pd->flags & (JSPD_ARGUMENT | JSPD_VARIABLE))
1006                ? sprop->shortid
1007                : 0;
1008     pd->alias = JSVAL_VOID;
1009     scope = OBJ_SCOPE(obj);
1010     if (SPROP_HAS_VALID_SLOT(sprop, scope)) {
1011         for (aprop = SCOPE_LAST_PROP(scope); aprop; aprop = aprop->parent) {
1012             if (aprop != sprop && aprop->slot == sprop->slot) {
1013                 pd->alias = ID_TO_VALUE(aprop->id);
1014                 break;
1015             }
1016         }
1017     }
1018     return JS_TRUE;
1021 JS_PUBLIC_API(JSBool)
1022 JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda)
1024     JSClass *clasp;
1025     JSScope *scope;
1026     uint32 i, n;
1027     JSPropertyDesc *pd;
1028     JSScopeProperty *sprop;
1030     clasp = OBJ_GET_CLASS(cx, obj);
1031     if (!OBJ_IS_NATIVE(obj) || (clasp->flags & JSCLASS_NEW_ENUMERATE)) {
1032         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1033                              JSMSG_CANT_DESCRIBE_PROPS, clasp->name);
1034         return JS_FALSE;
1035     }
1036     if (!clasp->enumerate(cx, obj))
1037         return JS_FALSE;
1039     /* have no props, or object's scope has not mutated from that of proto */
1040     scope = OBJ_SCOPE(obj);
1041     if (scope->object != obj || scope->entryCount == 0) {
1042         pda->length = 0;
1043         pda->array = NULL;
1044         return JS_TRUE;
1045     }
1047     n = scope->entryCount;
1048     if (n > scope->map.nslots)
1049         n = scope->map.nslots;
1050     pd = (JSPropertyDesc *) JS_malloc(cx, (size_t)n * sizeof(JSPropertyDesc));
1051     if (!pd)
1052         return JS_FALSE;
1053     i = 0;
1054     for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
1055         if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop))
1056             continue;
1057         if (!js_AddRoot(cx, &pd[i].id, NULL))
1058             goto bad;
1059         if (!js_AddRoot(cx, &pd[i].value, NULL))
1060             goto bad;
1061         if (!JS_GetPropertyDesc(cx, obj, sprop, &pd[i]))
1062             goto bad;
1063         if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL))
1064             goto bad;
1065         if (++i == n)
1066             break;
1067     }
1068     pda->length = i;
1069     pda->array = pd;
1070     return JS_TRUE;
1072 bad:
1073     pda->length = i + 1;
1074     pda->array = pd;
1075     JS_PutPropertyDescArray(cx, pda);
1076     return JS_FALSE;
1079 JS_PUBLIC_API(void)
1080 JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda)
1082     JSPropertyDesc *pd;
1083     uint32 i;
1085     pd = pda->array;
1086     for (i = 0; i < pda->length; i++) {
1087         js_RemoveRoot(cx->runtime, &pd[i].id);
1088         js_RemoveRoot(cx->runtime, &pd[i].value);
1089         if (pd[i].flags & JSPD_ALIAS)
1090             js_RemoveRoot(cx->runtime, &pd[i].alias);
1091     }
1092     JS_free(cx, pd);
1095 /************************************************************************/
1097 JS_PUBLIC_API(JSBool)
1098 JS_SetDebuggerHandler(JSRuntime *rt, JSTrapHandler handler, void *closure)
1100     rt->debuggerHandler = handler;
1101     rt->debuggerHandlerData = closure;
1102     return JS_TRUE;
1105 JS_PUBLIC_API(JSBool)
1106 JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure)
1108     rt->sourceHandler = handler;
1109     rt->sourceHandlerData = closure;
1110     return JS_TRUE;
1113 JS_PUBLIC_API(JSBool)
1114 JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
1116     rt->executeHook = hook;
1117     rt->executeHookData = closure;
1118     return JS_TRUE;
1121 JS_PUBLIC_API(JSBool)
1122 JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
1124     rt->callHook = hook;
1125     rt->callHookData = closure;
1126     return JS_TRUE;
1129 JS_PUBLIC_API(JSBool)
1130 JS_SetObjectHook(JSRuntime *rt, JSObjectHook hook, void *closure)
1132     rt->objectHook = hook;
1133     rt->objectHookData = closure;
1134     return JS_TRUE;
1137 JS_PUBLIC_API(JSBool)
1138 JS_SetThrowHook(JSRuntime *rt, JSTrapHandler hook, void *closure)
1140     rt->throwHook = hook;
1141     rt->throwHookData = closure;
1142     return JS_TRUE;
1145 JS_PUBLIC_API(JSBool)
1146 JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure)
1148     rt->debugErrorHook = hook;
1149     rt->debugErrorHookData = closure;
1150     return JS_TRUE;
1153 /************************************************************************/
1155 JS_PUBLIC_API(size_t)
1156 JS_GetObjectTotalSize(JSContext *cx, JSObject *obj)
1158     size_t nbytes;
1159     JSScope *scope;
1161     nbytes = sizeof *obj + obj->map->nslots * sizeof obj->slots[0];
1162     if (OBJ_IS_NATIVE(obj)) {
1163         scope = OBJ_SCOPE(obj);
1164         if (scope->object == obj) {
1165             nbytes += sizeof *scope;
1166             nbytes += SCOPE_CAPACITY(scope) * sizeof(JSScopeProperty *);
1167         }
1168     }
1169     return nbytes;
1172 static size_t
1173 GetAtomTotalSize(JSContext *cx, JSAtom *atom)
1175     size_t nbytes;
1177     nbytes = sizeof *atom;
1178     if (ATOM_IS_STRING(atom)) {
1179         nbytes += sizeof(JSString);
1180         nbytes += (ATOM_TO_STRING(atom)->length + 1) * sizeof(jschar);
1181     } else if (ATOM_IS_DOUBLE(atom)) {
1182         nbytes += sizeof(jsdouble);
1183     } else if (ATOM_IS_OBJECT(atom)) {
1184         nbytes += JS_GetObjectTotalSize(cx, ATOM_TO_OBJECT(atom));
1185     }
1186     return nbytes;
1189 JS_PUBLIC_API(size_t)
1190 JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun)
1192     size_t nbytes, obytes;
1193     JSObject *obj;
1194     JSAtom *atom;
1196     nbytes = sizeof *fun;
1197     JS_ASSERT(fun->nrefs);
1198     obj = fun->object;
1199     if (obj) {
1200         obytes = JS_GetObjectTotalSize(cx, obj);
1201         if (fun->nrefs > 1)
1202             obytes = JS_HOWMANY(obytes, fun->nrefs);
1203         nbytes += obytes;
1204     }
1205     if (fun->interpreted)
1206         nbytes += JS_GetScriptTotalSize(cx, fun->u.script);
1207     atom = fun->atom;
1208     if (atom)
1209         nbytes += GetAtomTotalSize(cx, atom);
1210     return nbytes;
1213 #include "jsemit.h"
1215 JS_PUBLIC_API(size_t)
1216 JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
1218     size_t nbytes, pbytes;
1219     JSObject *obj;
1220     jsatomid i;
1221     jssrcnote *sn, *notes;
1222     JSTryNote *tn, *tnotes;
1223     JSPrincipals *principals;
1225     nbytes = sizeof *script;
1226     obj = script->object;
1227     if (obj)
1228         nbytes += JS_GetObjectTotalSize(cx, obj);
1230     nbytes += script->length * sizeof script->code[0];
1231     nbytes += script->atomMap.length * sizeof script->atomMap.vector[0];
1232     for (i = 0; i < script->atomMap.length; i++)
1233         nbytes += GetAtomTotalSize(cx, script->atomMap.vector[i]);
1235     if (script->filename)
1236         nbytes += strlen(script->filename) + 1;
1238     notes = SCRIPT_NOTES(script);
1239     for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
1240         continue;
1241     nbytes += (sn - notes + 1) * sizeof *sn;
1243     tnotes = script->trynotes;
1244     if (tnotes) {
1245         for (tn = tnotes; tn->catchStart; tn++)
1246             continue;
1247         nbytes += (tn - tnotes + 1) * sizeof *tn;
1248     }
1250     principals = script->principals;
1251     if (principals) {
1252         JS_ASSERT(principals->refcount);
1253         pbytes = sizeof *principals;
1254         if (principals->refcount > 1)
1255             pbytes = JS_HOWMANY(pbytes, principals->refcount);
1256         nbytes += pbytes;
1257     }
1259     return nbytes;