1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sw=4 et tw=78:
3  *
4  * ***** BEGIN LICENSE BLOCK *****
5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is Mozilla Communicator client code, released
18  * March 31, 1998.
19  *
20  * The Initial Developer of the Original Code is
21  * Netscape Communications Corporation.
22  * Portions created by the Initial Developer are Copyright (C) 1998
23  * the Initial Developer. All Rights Reserved.
24  *
25  * Contributor(s):
26  *
27  * Alternatively, the contents of this file may be used under the terms of
28  * either of the GNU General Public License Version 2 or later (the "GPL"),
29  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30  * in which case the provisions of the GPL or the LGPL are applicable instead
31  * of those above. If you wish to allow use of your version of this file only
32  * under the terms of either the GPL or the LGPL, and not to allow others to
33  * use your version of this file under the terms of the MPL, indicate your
34  * decision by deleting the provisions above and replace them with the notice
35  * and other provisions required by the GPL or the LGPL. If you do not delete
36  * the provisions above, a recipient may use your version of this file under
37  * the terms of any one of the MPL, the GPL or the LGPL.
38  *
39  * ***** END LICENSE BLOCK ***** */
40 
41 /*
42  * JS debugging API.
43  */
44 #include "jsstddef.h"
45 #include <string.h>
46 #include "jstypes.h"
47 #include "jsutil.h" /* Added by JSIFY */
48 #include "jsclist.h"
49 #include "jsapi.h"
50 #include "jscntxt.h"
51 #include "jsconfig.h"
52 #include "jsdbgapi.h"
53 #include "jsfun.h"
54 #include "jsgc.h"
55 #include "jsinterp.h"
56 #include "jslock.h"
57 #include "jsobj.h"
58 #include "jsopcode.h"
59 #include "jsscope.h"
60 #include "jsscript.h"
61 #include "jsstr.h"
62 
63 typedef struct JSTrap {
64     JSCList         links;
65     JSScript        *script;
66     jsbytecode      *pc;
67     JSOp            op;
68     JSTrapHandler   handler;
69     void            *closure;
70 } JSTrap;
71 
72 static JSTrap *
FindTrap(JSRuntime * rt,JSScript * script,jsbytecode * pc)73 FindTrap(JSRuntime *rt, JSScript *script, jsbytecode *pc)
74 {
75     JSTrap *trap;
76 
77     for (trap = (JSTrap *)rt->trapList.next;
78          trap != (JSTrap *)&rt->trapList;
79          trap = (JSTrap *)trap->links.next) {
80         if (trap->script == script && trap->pc == pc)
81             return trap;
82     }
83     return NULL;
84 }
85 
86 void
js_PatchOpcode(JSContext * cx,JSScript * script,jsbytecode * pc,JSOp op)87 js_PatchOpcode(JSContext *cx, JSScript *script, jsbytecode *pc, JSOp op)
88 {
89     JSTrap *trap;
90 
91     trap = FindTrap(cx->runtime, script, pc);
92     if (trap)
93         trap->op = op;
94     else
95         *pc = (jsbytecode)op;
96 }
97 
98 JS_PUBLIC_API(JSBool)
JS_SetTrap(JSContext * cx,JSScript * script,jsbytecode * pc,JSTrapHandler handler,void * closure)99 JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
100            JSTrapHandler handler, void *closure)
101 {
102     JSRuntime *rt;
103     JSTrap *trap;
104 
105     rt = cx->runtime;
106     trap = FindTrap(rt, script, pc);
107     if (trap) {
108         JS_ASSERT(trap->script == script && trap->pc == pc);
109         JS_ASSERT(*pc == JSOP_TRAP);
110     } else {
111         trap = (JSTrap *) JS_malloc(cx, sizeof *trap);
112         if (!trap || !js_AddRoot(cx, &trap->closure, "trap->closure")) {
113             if (trap)
114                 JS_free(cx, trap);
115             return JS_FALSE;
116         }
117         JS_APPEND_LINK(&trap->links, &rt->trapList);
118         trap->script = script;
119         trap->pc = pc;
120         trap->op = (JSOp)*pc;
121         *pc = JSOP_TRAP;
122     }
123     trap->handler = handler;
124     trap->closure = closure;
125     return JS_TRUE;
126 }
127 
128 JS_PUBLIC_API(JSOp)
JS_GetTrapOpcode(JSContext * cx,JSScript * script,jsbytecode * pc)129 JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
130 {
131     JSTrap *trap;
132 
133     trap = FindTrap(cx->runtime, script, pc);
134     if (!trap) {
135         JS_ASSERT(0);   /* XXX can't happen */
136         return JSOP_LIMIT;
137     }
138     return trap->op;
139 }
140 
141 static void
DestroyTrap(JSContext * cx,JSTrap * trap)142 DestroyTrap(JSContext *cx, JSTrap *trap)
143 {
144     JS_REMOVE_LINK(&trap->links);
145     *trap->pc = (jsbytecode)trap->op;
146     js_RemoveRoot(cx->runtime, &trap->closure);
147     JS_free(cx, trap);
148 }
149 
150 JS_PUBLIC_API(void)
JS_ClearTrap(JSContext * cx,JSScript * script,jsbytecode * pc,JSTrapHandler * handlerp,void ** closurep)151 JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
152              JSTrapHandler *handlerp, void **closurep)
153 {
154     JSTrap *trap;
155 
156     trap = FindTrap(cx->runtime, script, pc);
157     if (handlerp)
158         *handlerp = trap ? trap->handler : NULL;
159     if (closurep)
160         *closurep = trap ? trap->closure : NULL;
161     if (trap)
162         DestroyTrap(cx, trap);
163 }
164 
165 JS_PUBLIC_API(void)
JS_ClearScriptTraps(JSContext * cx,JSScript * script)166 JS_ClearScriptTraps(JSContext *cx, JSScript *script)
167 {
168     JSRuntime *rt;
169     JSTrap *trap, *next;
170 
171     rt = cx->runtime;
172     for (trap = (JSTrap *)rt->trapList.next;
173          trap != (JSTrap *)&rt->trapList;
174          trap = next) {
175         next = (JSTrap *)trap->links.next;
176         if (trap->script == script)
177             DestroyTrap(cx, trap);
178     }
179 }
180 
181 JS_PUBLIC_API(void)
JS_ClearAllTraps(JSContext * cx)182 JS_ClearAllTraps(JSContext *cx)
183 {
184     JSRuntime *rt;
185     JSTrap *trap, *next;
186 
187     rt = cx->runtime;
188     for (trap = (JSTrap *)rt->trapList.next;
189          trap != (JSTrap *)&rt->trapList;
190          trap = next) {
191         next = (JSTrap *)trap->links.next;
192         DestroyTrap(cx, trap);
193     }
194 }
195 
196 JS_PUBLIC_API(JSTrapStatus)
JS_HandleTrap(JSContext * cx,JSScript * script,jsbytecode * pc,jsval * rval)197 JS_HandleTrap(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval)
198 {
199     JSTrap *trap;
200     JSTrapStatus status;
201     jsint op;
202 
203     trap = FindTrap(cx->runtime, script, pc);
204     if (!trap) {
205         JS_ASSERT(0);   /* XXX can't happen */
206         return JSTRAP_ERROR;
207     }
208     /*
209      * It's important that we not use 'trap->' after calling the callback --
210      * the callback might remove the trap!
211      */
212     op = (jsint)trap->op;
213     status = trap->handler(cx, script, pc, rval, trap->closure);
214     if (status == JSTRAP_CONTINUE) {
215         /* By convention, return the true op to the interpreter in rval. */
216         *rval = INT_TO_JSVAL(op);
217     }
218     return status;
219 }
220 
221 JS_PUBLIC_API(JSBool)
JS_SetInterrupt(JSRuntime * rt,JSTrapHandler handler,void * closure)222 JS_SetInterrupt(JSRuntime *rt, JSTrapHandler handler, void *closure)
223 {
224     rt->interruptHandler = handler;
225     rt->interruptHandlerData = closure;
226     return JS_TRUE;
227 }
228 
229 JS_PUBLIC_API(JSBool)
JS_ClearInterrupt(JSRuntime * rt,JSTrapHandler * handlerp,void ** closurep)230 JS_ClearInterrupt(JSRuntime *rt, JSTrapHandler *handlerp, void **closurep)
231 {
232     if (handlerp)
233         *handlerp = (JSTrapHandler)rt->interruptHandler;
234     if (closurep)
235         *closurep = rt->interruptHandlerData;
236     rt->interruptHandler = 0;
237     rt->interruptHandlerData = 0;
238     return JS_TRUE;
239 }
240 
241 /************************************************************************/
242 
243 typedef struct JSWatchPoint {
244     JSCList             links;
245     JSObject            *object;        /* weak link, see js_FinalizeObject */
246     JSScopeProperty     *sprop;
247     JSPropertyOp        setter;
248     JSWatchPointHandler handler;
249     void                *closure;
250     uintN               flags;
251 } JSWatchPoint;
252 
253 #define JSWP_LIVE       0x1             /* live because set and not cleared */
254 #define JSWP_HELD       0x2             /* held while running handler/setter */
255 
256 static JSBool
DropWatchPoint(JSContext * cx,JSWatchPoint * wp,uintN flag)257 DropWatchPoint(JSContext *cx, JSWatchPoint *wp, uintN flag)
258 {
259     JSBool ok;
260     JSScopeProperty *sprop;
261     JSObject *pobj;
262     JSProperty *prop;
263     JSPropertyOp setter;
264 
265     ok = JS_TRUE;
266     wp->flags &= ~flag;
267     if (wp->flags != 0)
268         return JS_TRUE;
269 
270     /*
271      * Remove wp from the list, then if there are no other watchpoints for
272      * wp->sprop in any scope, restore wp->sprop->setter from wp.
273      */
274     JS_REMOVE_LINK(&wp->links);
275     sprop = wp->sprop;
276 
277     /*
278      * If js_ChangeNativePropertyAttrs fails, propagate failure after removing
279      * wp->closure's root and freeing wp.
280      */
281     setter = js_GetWatchedSetter(cx->runtime, NULL, sprop);
282     if (!setter) {
283         ok = js_LookupProperty(cx, wp->object, sprop->id, &pobj, &prop);
284 
285         /*
286          * If the property wasn't found on wp->object or didn't exist, then
287          * someone else has dealt with this sprop, and we don't need to change
288          * the property attributes.
289          */
290         if (ok && prop) {
291             if (pobj == wp->object) {
292                 JS_ASSERT(OBJ_SCOPE(pobj)->object == pobj);
293 
294                 sprop = js_ChangeScopePropertyAttrs(cx, OBJ_SCOPE(pobj), sprop,
295                                                     0, sprop->attrs,
296                                                     sprop->getter,
297                                                     wp->setter);
298                 if (!sprop)
299                     ok = JS_FALSE;
300             }
301             OBJ_DROP_PROPERTY(cx, pobj, prop);
302         }
303     }
304 
305     js_RemoveRoot(cx->runtime, &wp->closure);
306     JS_free(cx, wp);
307     return ok;
308 }
309 
310 void
js_MarkWatchPoints(JSContext * cx)311 js_MarkWatchPoints(JSContext *cx)
312 {
313     JSRuntime *rt;
314     JSWatchPoint *wp;
315 
316     rt = cx->runtime;
317     for (wp = (JSWatchPoint *)rt->watchPointList.next;
318          wp != (JSWatchPoint *)&rt->watchPointList;
319          wp = (JSWatchPoint *)wp->links.next) {
320         MARK_SCOPE_PROPERTY(cx, wp->sprop);
321         if (wp->sprop->attrs & JSPROP_SETTER)
322             JS_MarkGCThing(cx, wp->setter, "wp->setter", NULL);
323     }
324 }
325 
326 static JSWatchPoint *
FindWatchPoint(JSRuntime * rt,JSScope * scope,jsid id)327 FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id)
328 {
329     JSWatchPoint *wp;
330 
331     for (wp = (JSWatchPoint *)rt->watchPointList.next;
332          wp != (JSWatchPoint *)&rt->watchPointList;
333          wp = (JSWatchPoint *)wp->links.next) {
334         if (wp->object == scope->object && wp->sprop->id == id)
335             return wp;
336     }
337     return NULL;
338 }
339 
340 JSScopeProperty *
js_FindWatchPoint(JSRuntime * rt,JSScope * scope,jsid id)341 js_FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id)
342 {
343     JSWatchPoint *wp;
344 
345     wp = FindWatchPoint(rt, scope, id);
346     if (!wp)
347         return NULL;
348     return wp->sprop;
349 }
350 
351 JSPropertyOp
js_GetWatchedSetter(JSRuntime * rt,JSScope * scope,const JSScopeProperty * sprop)352 js_GetWatchedSetter(JSRuntime *rt, JSScope *scope,
353                     const JSScopeProperty *sprop)
354 {
355     JSWatchPoint *wp;
356 
357     for (wp = (JSWatchPoint *)rt->watchPointList.next;
358          wp != (JSWatchPoint *)&rt->watchPointList;
359          wp = (JSWatchPoint *)wp->links.next) {
360         if ((!scope || wp->object == scope->object) && wp->sprop == sprop)
361             return wp->setter;
362     }
363     return NULL;
364 }
365 
366 JSBool JS_DLL_CALLBACK
js_watch_set(JSContext * cx,JSObject * obj,jsval id,jsval * vp)367 js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
368 {
369     JSRuntime *rt;
370     JSWatchPoint *wp;
371     JSScopeProperty *sprop;
372     jsval propid, userid;
373     JSScope *scope;
374     JSBool ok;
375 
376     rt = cx->runtime;
377     for (wp = (JSWatchPoint *)rt->watchPointList.next;
378          wp != (JSWatchPoint *)&rt->watchPointList;
379          wp = (JSWatchPoint *)wp->links.next) {
380         sprop = wp->sprop;
381         if (wp->object == obj && SPROP_USERID(sprop) == id &&
382             !(wp->flags & JSWP_HELD)) {
383             wp->flags |= JSWP_HELD;
384 
385             JS_LOCK_OBJ(cx, obj);
386             propid = ID_TO_VALUE(sprop->id);
387             userid = (sprop->flags & SPROP_HAS_SHORTID)
388                      ? INT_TO_JSVAL(sprop->shortid)
389                      : propid;
390             scope = OBJ_SCOPE(obj);
391             JS_UNLOCK_OBJ(cx, obj);
392 
393             /* NB: wp is held, so we can safely dereference it still. */
394             ok = wp->handler(cx, obj, propid,
395                              SPROP_HAS_VALID_SLOT(sprop, scope)
396                              ? OBJ_GET_SLOT(cx, obj, sprop->slot)
397                              : JSVAL_VOID,
398                              vp, wp->closure);
399             if (ok) {
400                 /*
401                  * Create a pseudo-frame for the setter invocation so that any
402                  * stack-walking security code under the setter will correctly
403                  * identify the guilty party.  So that the watcher appears to
404                  * be active to obj_eval and other such code, point frame.pc
405                  * at the JSOP_STOP at the end of the script.
406                  */
407                 JSObject *closure;
408                 JSClass *clasp;
409                 JSFunction *fun;
410                 JSScript *script;
411                 uintN nslots;
412                 jsval smallv[5];
413                 jsval *argv;
414                 JSStackFrame frame;
415 
416                 closure = (JSObject *) wp->closure;
417                 clasp = OBJ_GET_CLASS(cx, closure);
418                 if (clasp == &js_FunctionClass) {
419                     fun = (JSFunction *) JS_GetPrivate(cx, closure);
420                     script = FUN_SCRIPT(fun);
421                 } else if (clasp == &js_ScriptClass) {
422                     fun = NULL;
423                     script = (JSScript *) JS_GetPrivate(cx, closure);
424                 } else {
425                     fun = NULL;
426                     script = NULL;
427                 }
428 
429                 nslots = 2;
430                 if (fun) {
431                     nslots += fun->nargs;
432                     if (FUN_NATIVE(fun))
433                         nslots += fun->u.n.extra;
434                 }
435 
436                 if (nslots <= JS_ARRAY_LENGTH(smallv)) {
437                     argv = smallv;
438                 } else {
439                     argv = JS_malloc(cx, nslots * sizeof(jsval));
440                     if (!argv) {
441                         DropWatchPoint(cx, wp, JSWP_HELD);
442                         return JS_FALSE;
443                     }
444                 }
445 
446                 argv[0] = OBJECT_TO_JSVAL(closure);
447                 argv[1] = JSVAL_NULL;
448                 memset(argv + 2, 0, (nslots - 2) * sizeof(jsval));
449 
450                 memset(&frame, 0, sizeof(frame));
451                 frame.script = script;
452                 if (script) {
453                     JS_ASSERT(script->length >= JSOP_STOP_LENGTH);
454                     frame.pc = script->code + script->length
455                              - JSOP_STOP_LENGTH;
456                 }
457                 frame.fun = fun;
458                 frame.argv = argv + 2;
459                 frame.down = cx->fp;
460                 frame.scopeChain = OBJ_GET_PARENT(cx, closure);
461 
462                 cx->fp = &frame;
463                 ok = !wp->setter ||
464                      ((sprop->attrs & JSPROP_SETTER)
465                       ? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(wp->setter),
466                                         1, vp, vp)
467                       : wp->setter(cx, OBJ_THIS_OBJECT(cx, obj), userid, vp));
468                 cx->fp = frame.down;
469                 if (argv != smallv)
470                     JS_free(cx, argv);
471             }
472             return DropWatchPoint(cx, wp, JSWP_HELD) && ok;
473         }
474     }
475     return JS_TRUE;
476 }
477 
478 JSBool JS_DLL_CALLBACK
js_watch_set_wrapper(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)479 js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
480                      jsval *rval)
481 {
482     JSObject *funobj;
483     JSFunction *wrapper;
484     jsval userid;
485 
486     funobj = JSVAL_TO_OBJECT(argv[-2]);
487     JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass);
488     wrapper = (JSFunction *) JS_GetPrivate(cx, funobj);
489     userid = ATOM_KEY(wrapper->atom);
490     *rval = argv[0];
491     return js_watch_set(cx, obj, userid, rval);
492 }
493 
494 JSPropertyOp
js_WrapWatchedSetter(JSContext * cx,jsid id,uintN attrs,JSPropertyOp setter)495 js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter)
496 {
497     JSAtom *atom;
498     JSFunction *wrapper;
499 
500     if (!(attrs & JSPROP_SETTER))
501         return &js_watch_set;   /* & to silence schoolmarmish MSVC */
502 
503     if (JSID_IS_ATOM(id)) {
504         atom = JSID_TO_ATOM(id);
505     } else if (JSID_IS_INT(id)) {
506         atom = js_AtomizeInt(cx, JSID_TO_INT(id), 0);
507         if (!atom)
508             return NULL;
509     } else {
510         atom = NULL;
511     }
512     wrapper = js_NewFunction(cx, NULL, js_watch_set_wrapper, 1, 0,
513                              OBJ_GET_PARENT(cx, (JSObject *)setter),
514                              atom);
515     if (!wrapper)
516         return NULL;
517     return (JSPropertyOp) wrapper->object;
518 }
519 
520 JS_PUBLIC_API(JSBool)
JS_SetWatchPoint(JSContext * cx,JSObject * obj,jsval id,JSWatchPointHandler handler,void * closure)521 JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id,
522                  JSWatchPointHandler handler, void *closure)
523 {
524     JSAtom *atom;
525     jsid propid;
526     JSObject *pobj;
527     JSProperty *prop;
528     JSScopeProperty *sprop;
529     JSRuntime *rt;
530     JSBool ok;
531     JSWatchPoint *wp;
532     JSPropertyOp watcher;
533 
534     if (!OBJ_IS_NATIVE(obj)) {
535         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH,
536                              OBJ_GET_CLASS(cx, obj)->name);
537         return JS_FALSE;
538     }
539 
540     if (JSVAL_IS_INT(id)) {
541         propid = INT_JSVAL_TO_JSID(id);
542         atom = NULL;
543     } else {
544         atom = js_ValueToStringAtom(cx, id);
545         if (!atom)
546             return JS_FALSE;
547         propid = ATOM_TO_JSID(atom);
548     }
549 
550     if (!js_LookupProperty(cx, obj, propid, &pobj, &prop))
551         return JS_FALSE;
552     sprop = (JSScopeProperty *) prop;
553     rt = cx->runtime;
554     if (!sprop) {
555         /* Check for a deleted symbol watchpoint, which holds its property. */
556         sprop = js_FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
557         if (!sprop) {
558             /* Make a new property in obj so we can watch for the first set. */
559             if (!js_DefineProperty(cx, obj, propid, JSVAL_VOID,
560                                    NULL, NULL, JSPROP_ENUMERATE,
561                                    &prop)) {
562                 return JS_FALSE;
563             }
564             sprop = (JSScopeProperty *) prop;
565         }
566     } else if (pobj != obj) {
567         /* Clone the prototype property so we can watch the right object. */
568         jsval value;
569         JSPropertyOp getter, setter;
570         uintN attrs, flags;
571         intN shortid;
572 
573         if (OBJ_IS_NATIVE(pobj)) {
574             value = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))
575                     ? LOCKED_OBJ_GET_SLOT(pobj, sprop->slot)
576                     : JSVAL_VOID;
577             getter = sprop->getter;
578             setter = sprop->setter;
579             attrs = sprop->attrs;
580             flags = sprop->flags;
581             shortid = sprop->shortid;
582         } else {
583             if (!OBJ_GET_PROPERTY(cx, pobj, id, &value) ||
584                 !OBJ_GET_ATTRIBUTES(cx, pobj, id, prop, &attrs)) {
585                 OBJ_DROP_PROPERTY(cx, pobj, prop);
586                 return JS_FALSE;
587             }
588             getter = setter = NULL;
589             flags = 0;
590             shortid = 0;
591         }
592         OBJ_DROP_PROPERTY(cx, pobj, prop);
593 
594         /* Recall that obj is native, whether or not pobj is native. */
595         if (!js_DefineNativeProperty(cx, obj, propid, value, getter, setter,
596                                      attrs, flags, shortid, &prop)) {
597             return JS_FALSE;
598         }
599         sprop = (JSScopeProperty *) prop;
600     }
601 
602     /*
603      * At this point, prop/sprop exists in obj, obj is locked, and we must
604      * OBJ_DROP_PROPERTY(cx, obj, prop) before returning.
605      */
606     ok = JS_TRUE;
607     wp = FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
608     if (!wp) {
609         watcher = js_WrapWatchedSetter(cx, propid, sprop->attrs, sprop->setter);
610         if (!watcher) {
611             ok = JS_FALSE;
612             goto out;
613         }
614 
615         wp = (JSWatchPoint *) JS_malloc(cx, sizeof *wp);
616         if (!wp) {
617             ok = JS_FALSE;
618             goto out;
619         }
620         wp->handler = NULL;
621         wp->closure = NULL;
622         ok = js_AddRoot(cx, &wp->closure, "wp->closure");
623         if (!ok) {
624             JS_free(cx, wp);
625             goto out;
626         }
627         wp->object = obj;
628         JS_ASSERT(sprop->setter != js_watch_set || pobj != obj);
629         wp->setter = sprop->setter;
630         wp->flags = JSWP_LIVE;
631 
632         /* XXXbe nest in obj lock here */
633         sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop, 0, sprop->attrs,
634                                              sprop->getter, watcher);
635         if (!sprop) {
636             /* Self-link so DropWatchPoint can JS_REMOVE_LINK it. */
637             JS_INIT_CLIST(&wp->links);
638             DropWatchPoint(cx, wp, JSWP_LIVE);
639             ok = JS_FALSE;
640             goto out;
641         }
642         wp->sprop = sprop;
643 
644         /*
645          * Now that wp is fully initialized, append it to rt's wp list.
646          * Because obj is locked we know that no other thread could have added
647          * a watchpoint for (obj, propid).
648          */
649         JS_ASSERT(!FindWatchPoint(rt, OBJ_SCOPE(obj), propid));
650         JS_APPEND_LINK(&wp->links, &rt->watchPointList);
651     }
652     wp->handler = handler;
653     wp->closure = closure;
654 
655 out:
656     OBJ_DROP_PROPERTY(cx, obj, prop);
657     return ok;
658 }
659 
660 JS_PUBLIC_API(JSBool)
JS_ClearWatchPoint(JSContext * cx,JSObject * obj,jsval id,JSWatchPointHandler * handlerp,void ** closurep)661 JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsval id,
662                    JSWatchPointHandler *handlerp, void **closurep)
663 {
664     JSRuntime *rt;
665     JSWatchPoint *wp;
666 
667     rt = cx->runtime;
668     for (wp = (JSWatchPoint *)rt->watchPointList.next;
669          wp != (JSWatchPoint *)&rt->watchPointList;
670          wp = (JSWatchPoint *)wp->links.next) {
671         if (wp->object == obj && SPROP_USERID(wp->sprop) == id) {
672             if (handlerp)
673                 *handlerp = wp->handler;
674             if (closurep)
675                 *closurep = wp->closure;
676             return DropWatchPoint(cx, wp, JSWP_LIVE);
677         }
678     }
679     if (handlerp)
680         *handlerp = NULL;
681     if (closurep)
682         *closurep = NULL;
683     return JS_TRUE;
684 }
685 
686 JS_PUBLIC_API(JSBool)
JS_ClearWatchPointsForObject(JSContext * cx,JSObject * obj)687 JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj)
688 {
689     JSRuntime *rt;
690     JSWatchPoint *wp, *next;
691 
692     rt = cx->runtime;
693     for (wp = (JSWatchPoint *)rt->watchPointList.next;
694          wp != (JSWatchPoint *)&rt->watchPointList;
695          wp = next) {
696         next = (JSWatchPoint *)wp->links.next;
697         if (wp->object == obj && !DropWatchPoint(cx, wp, JSWP_LIVE))
698             return JS_FALSE;
699     }
700     return JS_TRUE;
701 }
702 
703 JS_PUBLIC_API(JSBool)
JS_ClearAllWatchPoints(JSContext * cx)704 JS_ClearAllWatchPoints(JSContext *cx)
705 {
706     JSRuntime *rt;
707     JSWatchPoint *wp, *next;
708 
709     rt = cx->runtime;
710     for (wp = (JSWatchPoint *)rt->watchPointList.next;
711          wp != (JSWatchPoint *)&rt->watchPointList;
712          wp = next) {
713         next = (JSWatchPoint *)wp->links.next;
714         if (!DropWatchPoint(cx, wp, JSWP_LIVE))
715             return JS_FALSE;
716     }
717     return JS_TRUE;
718 }
719 
720 /************************************************************************/
721 
722 JS_PUBLIC_API(uintN)
JS_PCToLineNumber(JSContext * cx,JSScript * script,jsbytecode * pc)723 JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
724 {
725     return js_PCToLineNumber(cx, script, pc);
726 }
727 
728 JS_PUBLIC_API(jsbytecode *)
JS_LineNumberToPC(JSContext * cx,JSScript * script,uintN lineno)729 JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno)
730 {
731     return js_LineNumberToPC(script, lineno);
732 }
733 
734 JS_PUBLIC_API(JSScript *)
JS_GetFunctionScript(JSContext * cx,JSFunction * fun)735 JS_GetFunctionScript(JSContext *cx, JSFunction *fun)
736 {
737     return FUN_SCRIPT(fun);
738 }
739 
740 JS_PUBLIC_API(JSNative)
JS_GetFunctionNative(JSContext * cx,JSFunction * fun)741 JS_GetFunctionNative(JSContext *cx, JSFunction *fun)
742 {
743     return FUN_NATIVE(fun);
744 }
745 
746 JS_PUBLIC_API(JSPrincipals *)
JS_GetScriptPrincipals(JSContext * cx,JSScript * script)747 JS_GetScriptPrincipals(JSContext *cx, JSScript *script)
748 {
749     return script->principals;
750 }
751 
752 /************************************************************************/
753 
754 /*
755  *  Stack Frame Iterator
756  */
757 JS_PUBLIC_API(JSStackFrame *)
JS_FrameIterator(JSContext * cx,JSStackFrame ** iteratorp)758 JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
759 {
760     *iteratorp = (*iteratorp == NULL) ? cx->fp : (*iteratorp)->down;
761     return *iteratorp;
762 }
763 
764 JS_PUBLIC_API(JSScript *)
JS_GetFrameScript(JSContext * cx,JSStackFrame * fp)765 JS_GetFrameScript(JSContext *cx, JSStackFrame *fp)
766 {
767     return fp->script;
768 }
769 
770 JS_PUBLIC_API(jsbytecode *)
JS_GetFramePC(JSContext * cx,JSStackFrame * fp)771 JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
772 {
773     return fp->pc;
774 }
775 
776 JS_PUBLIC_API(JSStackFrame *)
JS_GetScriptedCaller(JSContext * cx,JSStackFrame * fp)777 JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
778 {
779     if (!fp)
780         fp = cx->fp;
781     while ((fp = fp->down) != NULL) {
782         if (fp->script)
783             return fp;
784     }
785     return NULL;
786 }
787 
788 JS_PUBLIC_API(JSPrincipals *)
JS_StackFramePrincipals(JSContext * cx,JSStackFrame * fp)789 JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp)
790 {
791     if (fp->fun) {
792         JSRuntime *rt = cx->runtime;
793 
794         if (rt->findObjectPrincipals) {
795             JSObject *callee = JSVAL_TO_OBJECT(fp->argv[-2]);
796 
797             if (fp->fun->object != callee)
798                 return rt->findObjectPrincipals(cx, callee);
799             /* FALL THROUGH */
800         }
801     }
802     if (fp->script)
803         return fp->script->principals;
804     return NULL;
805 }
806 
807 JS_PUBLIC_API(JSPrincipals *)
JS_EvalFramePrincipals(JSContext * cx,JSStackFrame * fp,JSStackFrame * caller)808 JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller)
809 {
810     JSRuntime *rt;
811     JSObject *callee;
812     JSPrincipals *principals, *callerPrincipals;
813 
814     rt = cx->runtime;
815     if (rt->findObjectPrincipals) {
816         callee = JSVAL_TO_OBJECT(fp->argv[-2]);
817         principals = rt->findObjectPrincipals(cx, callee);
818     } else {
819         principals = NULL;
820     }
821     if (!caller)
822         return principals;
823     callerPrincipals = JS_StackFramePrincipals(cx, caller);
824     return (callerPrincipals && principals &&
825             callerPrincipals->subsume(callerPrincipals, principals))
826            ? principals
827            : callerPrincipals;
828 }
829 
830 JS_PUBLIC_API(void *)
JS_GetFrameAnnotation(JSContext * cx,JSStackFrame * fp)831 JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
832 {
833     if (fp->annotation && fp->script) {
834         JSPrincipals *principals = JS_StackFramePrincipals(cx, fp);
835 
836         if (principals && principals->globalPrivilegesEnabled(cx, principals)) {
837             /*
838              * Give out an annotation only if privileges have not been revoked
839              * or disabled globally.
840              */
841             return fp->annotation;
842         }
843     }
844 
845     return NULL;
846 }
847 
848 JS_PUBLIC_API(void)
JS_SetFrameAnnotation(JSContext * cx,JSStackFrame * fp,void * annotation)849 JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation)
850 {
851     fp->annotation = annotation;
852 }
853 
854 JS_PUBLIC_API(void *)
JS_GetFramePrincipalArray(JSContext * cx,JSStackFrame * fp)855 JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp)
856 {
857     JSPrincipals *principals;
858 
859     principals = JS_StackFramePrincipals(cx, fp);
860     if (!principals)
861         return NULL;
862     return principals->getPrincipalArray(cx, principals);
863 }
864 
865 JS_PUBLIC_API(JSBool)
JS_IsNativeFrame(JSContext * cx,JSStackFrame * fp)866 JS_IsNativeFrame(JSContext *cx, JSStackFrame *fp)
867 {
868     return !fp->script;
869 }
870 
871 /* this is deprecated, use JS_GetFrameScopeChain instead */
872 JS_PUBLIC_API(JSObject *)
JS_GetFrameObject(JSContext * cx,JSStackFrame * fp)873 JS_GetFrameObject(JSContext *cx, JSStackFrame *fp)
874 {
875     return fp->scopeChain;
876 }
877 
878 JS_PUBLIC_API(JSObject *)
JS_GetFrameScopeChain(JSContext * cx,JSStackFrame * fp)879 JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp)
880 {
881     /* Force creation of argument and call objects if not yet created */
882     (void) JS_GetFrameCallObject(cx, fp);
883     return js_GetScopeChain(cx, fp);
884 }
885 
886 JS_PUBLIC_API(JSObject *)
JS_GetFrameCallObject(JSContext * cx,JSStackFrame * fp)887 JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp)
888 {
889     if (! fp->fun)
890         return NULL;
891 
892     /* Force creation of argument object if not yet created */
893     (void) js_GetArgsObject(cx, fp);
894 
895     /*
896      * XXX ill-defined: null return here means error was reported, unlike a
897      *     null returned above or in the #else
898      */
899     return js_GetCallObject(cx, fp, NULL);
900 }
901 
902 
903 JS_PUBLIC_API(JSObject *)
JS_GetFrameThis(JSContext * cx,JSStackFrame * fp)904 JS_GetFrameThis(JSContext *cx, JSStackFrame *fp)
905 {
906     return fp->thisp;
907 }
908 
909 JS_PUBLIC_API(JSFunction *)
JS_GetFrameFunction(JSContext * cx,JSStackFrame * fp)910 JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
911 {
912     return fp->fun;
913 }
914 
915 JS_PUBLIC_API(JSObject *)
JS_GetFrameFunctionObject(JSContext * cx,JSStackFrame * fp)916 JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp)
917 {
918     return fp->argv && fp->fun ? JSVAL_TO_OBJECT(fp->argv[-2]) : NULL;
919 }
920 
921 JS_PUBLIC_API(JSBool)
JS_IsConstructorFrame(JSContext * cx,JSStackFrame * fp)922 JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp)
923 {
924     return (fp->flags & JSFRAME_CONSTRUCTING) != 0;
925 }
926 
927 JS_PUBLIC_API(JSObject *)
JS_GetFrameCalleeObject(JSContext * cx,JSStackFrame * fp)928 JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp)
929 {
930     return fp->argv ? JSVAL_TO_OBJECT(fp->argv[-2]) : NULL;
931 }
932 
933 JS_PUBLIC_API(JSBool)
JS_IsDebuggerFrame(JSContext * cx,JSStackFrame * fp)934 JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp)
935 {
936     return (fp->flags & JSFRAME_DEBUGGER) != 0;
937 }
938 
939 JS_PUBLIC_API(jsval)
JS_GetFrameReturnValue(JSContext * cx,JSStackFrame * fp)940 JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp)
941 {
942     return fp->rval;
943 }
944 
945 JS_PUBLIC_API(void)
JS_SetFrameReturnValue(JSContext * cx,JSStackFrame * fp,jsval rval)946 JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval)
947 {
948     fp->rval = rval;
949 }
950 
951 /************************************************************************/
952 
953 JS_PUBLIC_API(const char *)
JS_GetScriptFilename(JSContext * cx,JSScript * script)954 JS_GetScriptFilename(JSContext *cx, JSScript *script)
955 {
956     return script->filename;
957 }
958 
959 JS_PUBLIC_API(uintN)
JS_GetScriptBaseLineNumber(JSContext * cx,JSScript * script)960 JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script)
961 {
962     return script->lineno;
963 }
964 
965 JS_PUBLIC_API(uintN)
JS_GetScriptLineExtent(JSContext * cx,JSScript * script)966 JS_GetScriptLineExtent(JSContext *cx, JSScript *script)
967 {
968     return js_GetScriptLineExtent(script);
969 }
970 
971 JS_PUBLIC_API(JSVersion)
JS_GetScriptVersion(JSContext * cx,JSScript * script)972 JS_GetScriptVersion(JSContext *cx, JSScript *script)
973 {
974     return script->version & JSVERSION_MASK;
975 }
976 
977 /***************************************************************************/
978 
979 JS_PUBLIC_API(void)
JS_SetNewScriptHook(JSRuntime * rt,JSNewScriptHook hook,void * callerdata)980 JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata)
981 {
982     rt->newScriptHook = hook;
983     rt->newScriptHookData = callerdata;
984 }
985 
986 JS_PUBLIC_API(void)
JS_SetDestroyScriptHook(JSRuntime * rt,JSDestroyScriptHook hook,void * callerdata)987 JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook,
988                         void *callerdata)
989 {
990     rt->destroyScriptHook = hook;
991     rt->destroyScriptHookData = callerdata;
992 }
993 
994 /***************************************************************************/
995 
996 JS_PUBLIC_API(JSBool)
JS_EvaluateUCInStackFrame(JSContext * cx,JSStackFrame * fp,const jschar * chars,uintN length,const char * filename,uintN lineno,jsval * rval)997 JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
998                           const jschar *chars, uintN length,
999                           const char *filename, uintN lineno,
1000                           jsval *rval)
1001 {
1002     JSObject *scobj;
1003     uint32 flags, options;
1004     JSScript *script;
1005     JSBool ok;
1006 
1007     scobj = JS_GetFrameScopeChain(cx, fp);
1008     if (!scobj)
1009         return JS_FALSE;
1010 
1011     /*
1012      * XXX Hack around ancient compiler API to propagate the JSFRAME_SPECIAL
1013      * flags to the code generator (see js_EmitTree's TOK_SEMI case).
1014      */
1015     flags = fp->flags;
1016     fp->flags |= JSFRAME_DEBUGGER | JSFRAME_EVAL;
1017     options = cx->options;
1018     cx->options = options | JSOPTION_COMPILE_N_GO;
1019     script = JS_CompileUCScriptForPrincipals(cx, scobj,
1020                                              JS_StackFramePrincipals(cx, fp),
1021                                              chars, length, filename, lineno);
1022     fp->flags = flags;
1023     cx->options = options;
1024     if (!script)
1025         return JS_FALSE;
1026 
1027     ok = js_Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL,
1028                     rval);
1029     js_DestroyScript(cx, script);
1030     return ok;
1031 }
1032 
1033 JS_PUBLIC_API(JSBool)
JS_EvaluateInStackFrame(JSContext * cx,JSStackFrame * fp,const char * bytes,uintN length,const char * filename,uintN lineno,jsval * rval)1034 JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp,
1035                         const char *bytes, uintN length,
1036                         const char *filename, uintN lineno,
1037                         jsval *rval)
1038 {
1039     jschar *chars;
1040     JSBool ok;
1041     size_t len = length;
1042 
1043     chars = js_InflateString(cx, bytes, &len);
1044     if (!chars)
1045         return JS_FALSE;
1046     length = (uintN) len;
1047     ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length, filename, lineno,
1048                                    rval);
1049     JS_free(cx, chars);
1050 
1051     return ok;
1052 }
1053 
1054 /************************************************************************/
1055 
1056 /* XXXbe this all needs to be reworked to avoid requiring JSScope types. */
1057 
1058 JS_PUBLIC_API(JSScopeProperty *)
JS_PropertyIterator(JSObject * obj,JSScopeProperty ** iteratorp)1059 JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp)
1060 {
1061     JSScopeProperty *sprop;
1062     JSScope *scope;
1063 
1064     sprop = *iteratorp;
1065     scope = OBJ_SCOPE(obj);
1066 
1067     /* XXXbe minor(?) incompatibility: iterate in reverse definition order */
1068     if (!sprop) {
1069         sprop = SCOPE_LAST_PROP(scope);
1070     } else {
1071         while ((sprop = sprop->parent) != NULL) {
1072             if (!SCOPE_HAD_MIDDLE_DELETE(scope))
1073                 break;
1074             if (SCOPE_HAS_PROPERTY(scope, sprop))
1075                 break;
1076         }
1077     }
1078     *iteratorp = sprop;
1079     return sprop;
1080 }
1081 
1082 JS_PUBLIC_API(JSBool)
JS_GetPropertyDesc(JSContext * cx,JSObject * obj,JSScopeProperty * sprop,JSPropertyDesc * pd)1083 JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
1084                    JSPropertyDesc *pd)
1085 {
1086     JSPropertyOp getter;
1087     JSScope *scope;
1088     JSScopeProperty *aprop;
1089     jsval lastException;
1090     JSBool wasThrowing;
1091 
1092     pd->id = ID_TO_VALUE(sprop->id);
1093 
1094     wasThrowing = cx->throwing;
1095     if (wasThrowing) {
1096         lastException = cx->exception;
1097         if (JSVAL_IS_GCTHING(lastException) &&
1098             !js_AddRoot(cx, &lastException, "lastException")) {
1099                 return JS_FALSE;
1100         }
1101         cx->throwing = JS_FALSE;
1102     }
1103 
1104     if (!js_GetProperty(cx, obj, sprop->id, &pd->value)) {
1105         if (!cx->throwing) {
1106             pd->flags = JSPD_ERROR;
1107             pd->value = JSVAL_VOID;
1108         } else {
1109             pd->flags = JSPD_EXCEPTION;
1110             pd->value = cx->exception;
1111         }
1112     } else {
1113         pd->flags = 0;
1114     }
1115 
1116     cx->throwing = wasThrowing;
1117     if (wasThrowing) {
1118         cx->exception = lastException;
1119         if (JSVAL_IS_GCTHING(lastException))
1120             js_RemoveRoot(cx->runtime, &lastException);
1121     }
1122 
1123     getter = sprop->getter;
1124     pd->flags |= ((sprop->attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0)
1125               | ((sprop->attrs & JSPROP_READONLY)  ? JSPD_READONLY  : 0)
1126               | ((sprop->attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0)
1127               | ((getter == js_GetCallVariable)    ? JSPD_VARIABLE  : 0)
1128               | ((getter == js_GetArgument)        ? JSPD_ARGUMENT  : 0)
1129               | ((getter == js_GetLocalVariable)   ? JSPD_VARIABLE  : 0);
1130 
1131     /* for Call Object 'real' getter isn't passed in to us */
1132     if (OBJ_GET_CLASS(cx, obj) == &js_CallClass &&
1133         getter == js_CallClass.getProperty) {
1134         /*
1135          * Property of a heavyweight function's variable object having the
1136          * class-default getter.  It's either an argument if permanent, or a
1137          * nested function if impermanent.  Local variables have a special
1138          * getter (js_GetCallVariable, tested above) and setter, and not the
1139          * class default.
1140          */
1141         pd->flags |= (sprop->attrs & JSPROP_PERMANENT)
1142                      ? JSPD_ARGUMENT
1143                      : JSPD_VARIABLE;
1144     }
1145 
1146     pd->spare = 0;
1147     pd->slot = (pd->flags & (JSPD_ARGUMENT | JSPD_VARIABLE))
1148                ? sprop->shortid
1149                : 0;
1150     pd->alias = JSVAL_VOID;
1151     scope = OBJ_SCOPE(obj);
1152     if (SPROP_HAS_VALID_SLOT(sprop, scope)) {
1153         for (aprop = SCOPE_LAST_PROP(scope); aprop; aprop = aprop->parent) {
1154             if (aprop != sprop && aprop->slot == sprop->slot) {
1155                 pd->alias = ID_TO_VALUE(aprop->id);
1156                 break;
1157             }
1158         }
1159     }
1160     return JS_TRUE;
1161 }
1162 
1163 JS_PUBLIC_API(JSBool)
JS_GetPropertyDescArray(JSContext * cx,JSObject * obj,JSPropertyDescArray * pda)1164 JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda)
1165 {
1166     JSClass *clasp;
1167     JSScope *scope;
1168     uint32 i, n;
1169     JSPropertyDesc *pd;
1170     JSScopeProperty *sprop;
1171 
1172     clasp = OBJ_GET_CLASS(cx, obj);
1173     if (!OBJ_IS_NATIVE(obj) || (clasp->flags & JSCLASS_NEW_ENUMERATE)) {
1174         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1175                              JSMSG_CANT_DESCRIBE_PROPS, clasp->name);
1176         return JS_FALSE;
1177     }
1178     if (!clasp->enumerate(cx, obj))
1179         return JS_FALSE;
1180 
1181     /* have no props, or object's scope has not mutated from that of proto */
1182     scope = OBJ_SCOPE(obj);
1183     if (scope->object != obj || scope->entryCount == 0) {
1184         pda->length = 0;
1185         pda->array = NULL;
1186         return JS_TRUE;
1187     }
1188 
1189     n = scope->entryCount;
1190     if (n > scope->map.nslots)
1191         n = scope->map.nslots;
1192     pd = (JSPropertyDesc *) JS_malloc(cx, (size_t)n * sizeof(JSPropertyDesc));
1193     if (!pd)
1194         return JS_FALSE;
1195     i = 0;
1196     for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
1197         if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop))
1198             continue;
1199         if (!js_AddRoot(cx, &pd[i].id, NULL))
1200             goto bad;
1201         if (!js_AddRoot(cx, &pd[i].value, NULL))
1202             goto bad;
1203         if (!JS_GetPropertyDesc(cx, obj, sprop, &pd[i]))
1204             goto bad;
1205         if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL))
1206             goto bad;
1207         if (++i == n)
1208             break;
1209     }
1210     pda->length = i;
1211     pda->array = pd;
1212     return JS_TRUE;
1213 
1214 bad:
1215     pda->length = i + 1;
1216     pda->array = pd;
1217     JS_PutPropertyDescArray(cx, pda);
1218     return JS_FALSE;
1219 }
1220 
1221 JS_PUBLIC_API(void)
JS_PutPropertyDescArray(JSContext * cx,JSPropertyDescArray * pda)1222 JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda)
1223 {
1224     JSPropertyDesc *pd;
1225     uint32 i;
1226 
1227     pd = pda->array;
1228     for (i = 0; i < pda->length; i++) {
1229         js_RemoveRoot(cx->runtime, &pd[i].id);
1230         js_RemoveRoot(cx->runtime, &pd[i].value);
1231         if (pd[i].flags & JSPD_ALIAS)
1232             js_RemoveRoot(cx->runtime, &pd[i].alias);
1233     }
1234     JS_free(cx, pd);
1235 }
1236 
1237 /************************************************************************/
1238 
1239 JS_PUBLIC_API(JSBool)
JS_SetDebuggerHandler(JSRuntime * rt,JSTrapHandler handler,void * closure)1240 JS_SetDebuggerHandler(JSRuntime *rt, JSTrapHandler handler, void *closure)
1241 {
1242     rt->debuggerHandler = handler;
1243     rt->debuggerHandlerData = closure;
1244     return JS_TRUE;
1245 }
1246 
1247 JS_PUBLIC_API(JSBool)
JS_SetSourceHandler(JSRuntime * rt,JSSourceHandler handler,void * closure)1248 JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure)
1249 {
1250     rt->sourceHandler = handler;
1251     rt->sourceHandlerData = closure;
1252     return JS_TRUE;
1253 }
1254 
1255 JS_PUBLIC_API(JSBool)
JS_SetExecuteHook(JSRuntime * rt,JSInterpreterHook hook,void * closure)1256 JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
1257 {
1258     rt->executeHook = hook;
1259     rt->executeHookData = closure;
1260     return JS_TRUE;
1261 }
1262 
1263 JS_PUBLIC_API(JSBool)
JS_SetCallHook(JSRuntime * rt,JSInterpreterHook hook,void * closure)1264 JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
1265 {
1266     rt->callHook = hook;
1267     rt->callHookData = closure;
1268     return JS_TRUE;
1269 }
1270 
1271 JS_PUBLIC_API(JSBool)
JS_SetObjectHook(JSRuntime * rt,JSObjectHook hook,void * closure)1272 JS_SetObjectHook(JSRuntime *rt, JSObjectHook hook, void *closure)
1273 {
1274     rt->objectHook = hook;
1275     rt->objectHookData = closure;
1276     return JS_TRUE;
1277 }
1278 
1279 JS_PUBLIC_API(JSBool)
JS_SetThrowHook(JSRuntime * rt,JSTrapHandler hook,void * closure)1280 JS_SetThrowHook(JSRuntime *rt, JSTrapHandler hook, void *closure)
1281 {
1282     rt->throwHook = hook;
1283     rt->throwHookData = closure;
1284     return JS_TRUE;
1285 }
1286 
1287 JS_PUBLIC_API(JSBool)
JS_SetDebugErrorHook(JSRuntime * rt,JSDebugErrorHook hook,void * closure)1288 JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure)
1289 {
1290     rt->debugErrorHook = hook;
1291     rt->debugErrorHookData = closure;
1292     return JS_TRUE;
1293 }
1294 
1295 /************************************************************************/
1296 
1297 JS_PUBLIC_API(size_t)
JS_GetObjectTotalSize(JSContext * cx,JSObject * obj)1298 JS_GetObjectTotalSize(JSContext *cx, JSObject *obj)
1299 {
1300     size_t nbytes;
1301     JSScope *scope;
1302 
1303     nbytes = sizeof *obj + obj->map->nslots * sizeof obj->slots[0];
1304     if (OBJ_IS_NATIVE(obj)) {
1305         scope = OBJ_SCOPE(obj);
1306         if (scope->object == obj) {
1307             nbytes += sizeof *scope;
1308             nbytes += SCOPE_CAPACITY(scope) * sizeof(JSScopeProperty *);
1309         }
1310     }
1311     return nbytes;
1312 }
1313 
1314 static size_t
GetAtomTotalSize(JSContext * cx,JSAtom * atom)1315 GetAtomTotalSize(JSContext *cx, JSAtom *atom)
1316 {
1317     size_t nbytes;
1318 
1319     nbytes = sizeof *atom;
1320     if (ATOM_IS_STRING(atom)) {
1321         nbytes += sizeof(JSString);
1322         nbytes += (ATOM_TO_STRING(atom)->length + 1) * sizeof(jschar);
1323     } else if (ATOM_IS_DOUBLE(atom)) {
1324         nbytes += sizeof(jsdouble);
1325     } else if (ATOM_IS_OBJECT(atom)) {
1326         nbytes += JS_GetObjectTotalSize(cx, ATOM_TO_OBJECT(atom));
1327     }
1328     return nbytes;
1329 }
1330 
1331 JS_PUBLIC_API(size_t)
JS_GetFunctionTotalSize(JSContext * cx,JSFunction * fun)1332 JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun)
1333 {
1334     size_t nbytes;
1335 
1336     nbytes = sizeof *fun;
1337     if (fun->object)
1338         nbytes += JS_GetObjectTotalSize(cx, fun->object);
1339     if (FUN_INTERPRETED(fun))
1340         nbytes += JS_GetScriptTotalSize(cx, fun->u.i.script);
1341     if (fun->atom)
1342         nbytes += GetAtomTotalSize(cx, fun->atom);
1343     return nbytes;
1344 }
1345 
1346 #include "jsemit.h"
1347 
1348 JS_PUBLIC_API(size_t)
JS_GetScriptTotalSize(JSContext * cx,JSScript * script)1349 JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
1350 {
1351     size_t nbytes, pbytes;
1352     JSObject *obj;
1353     jsatomid i;
1354     jssrcnote *sn, *notes;
1355     JSTryNote *tn, *tnotes;
1356     JSPrincipals *principals;
1357 
1358     nbytes = sizeof *script;
1359     obj = script->object;
1360     if (obj)
1361         nbytes += JS_GetObjectTotalSize(cx, obj);
1362 
1363     nbytes += script->length * sizeof script->code[0];
1364     nbytes += script->atomMap.length * sizeof script->atomMap.vector[0];
1365     for (i = 0; i < script->atomMap.length; i++)
1366         nbytes += GetAtomTotalSize(cx, script->atomMap.vector[i]);
1367 
1368     if (script->filename)
1369         nbytes += strlen(script->filename) + 1;
1370 
1371     notes = SCRIPT_NOTES(script);
1372     for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
1373         continue;
1374     nbytes += (sn - notes + 1) * sizeof *sn;
1375 
1376     tnotes = script->trynotes;
1377     if (tnotes) {
1378         for (tn = tnotes; tn->catchStart; tn++)
1379             continue;
1380         nbytes += (tn - tnotes + 1) * sizeof *tn;
1381     }
1382 
1383     principals = script->principals;
1384     if (principals) {
1385         JS_ASSERT(principals->refcount);
1386         pbytes = sizeof *principals;
1387         if (principals->refcount > 1)
1388             pbytes = JS_HOWMANY(pbytes, principals->refcount);
1389         nbytes += pbytes;
1390     }
1391 
1392     return nbytes;
1393 }
1394 
1395 JS_PUBLIC_API(uint32)
JS_GetTopScriptFilenameFlags(JSContext * cx,JSStackFrame * fp)1396 JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp)
1397 {
1398     if (!fp)
1399         fp = cx->fp;
1400     while (fp) {
1401         if (fp->script) {
1402             return JS_GetScriptFilenameFlags(fp->script);
1403         }
1404         fp = fp->down;
1405     }
1406     return 0;
1407  }
1408 
1409 JS_PUBLIC_API(uint32)
JS_GetScriptFilenameFlags(JSScript * script)1410 JS_GetScriptFilenameFlags(JSScript *script)
1411 {
1412     JS_ASSERT(script);
1413     if (!script->filename)
1414         return JSFILENAME_NULL;
1415     return js_GetScriptFilenameFlags(script->filename);
1416 }
1417 
1418 JS_PUBLIC_API(JSBool)
JS_FlagScriptFilenamePrefix(JSRuntime * rt,const char * prefix,uint32 flags)1419 JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags)
1420 {
1421     if (!js_SaveScriptFilenameRT(rt, prefix, flags))
1422         return JS_FALSE;
1423     return JS_TRUE;
1424 }
1425 
1426 JS_PUBLIC_API(JSBool)
JS_IsSystemObject(JSContext * cx,JSObject * obj)1427 JS_IsSystemObject(JSContext *cx, JSObject *obj)
1428 {
1429     return (*js_GetGCThingFlags(obj) & GCF_SYSTEM) != 0;
1430 }
1431 
1432 JS_PUBLIC_API(void)
JS_FlagSystemObject(JSContext * cx,JSObject * obj)1433 JS_FlagSystemObject(JSContext *cx, JSObject *obj)
1434 {
1435     uint8 *flagp;
1436 
1437     flagp = js_GetGCThingFlags(obj);
1438     *flagp |= GCF_SYSTEM;
1439 }
1440