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