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