Back to index

lightning-sunbird  0.9+nobinonly
jsdbgapi.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  * vim: set ts=8 sw=4 et tw=78:
00003  *
00004  * ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is Mozilla Communicator client code, released
00018  * March 31, 1998.
00019  *
00020  * The Initial Developer of the Original Code is
00021  * Netscape Communications Corporation.
00022  * Portions created by the Initial Developer are Copyright (C) 1998
00023  * the Initial Developer. All Rights Reserved.
00024  *
00025  * Contributor(s):
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 /*
00042  * JS debugging API.
00043  */
00044 #include "jsstddef.h"
00045 #include <string.h>
00046 #include "jstypes.h"
00047 #include "jsutil.h" /* Added by JSIFY */
00048 #include "jsclist.h"
00049 #include "jsapi.h"
00050 #include "jscntxt.h"
00051 #include "jsconfig.h"
00052 #include "jsdbgapi.h"
00053 #include "jsfun.h"
00054 #include "jsgc.h"
00055 #include "jsinterp.h"
00056 #include "jslock.h"
00057 #include "jsobj.h"
00058 #include "jsopcode.h"
00059 #include "jsscope.h"
00060 #include "jsscript.h"
00061 #include "jsstr.h"
00062 
00063 typedef struct JSTrap {
00064     JSCList         links;
00065     JSScript        *script;
00066     jsbytecode      *pc;
00067     JSOp            op;
00068     JSTrapHandler   handler;
00069     void            *closure;
00070 } JSTrap;
00071 
00072 static JSTrap *
00073 FindTrap(JSRuntime *rt, JSScript *script, jsbytecode *pc)
00074 {
00075     JSTrap *trap;
00076 
00077     for (trap = (JSTrap *)rt->trapList.next;
00078          trap != (JSTrap *)&rt->trapList;
00079          trap = (JSTrap *)trap->links.next) {
00080         if (trap->script == script && trap->pc == pc)
00081             return trap;
00082     }
00083     return NULL;
00084 }
00085 
00086 void
00087 js_PatchOpcode(JSContext *cx, JSScript *script, jsbytecode *pc, JSOp op)
00088 {
00089     JSTrap *trap;
00090 
00091     trap = FindTrap(cx->runtime, script, pc);
00092     if (trap)
00093         trap->op = op;
00094     else
00095         *pc = (jsbytecode)op;
00096 }
00097 
00098 JS_PUBLIC_API(JSBool)
00099 JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
00100            JSTrapHandler handler, void *closure)
00101 {
00102     JSRuntime *rt;
00103     JSTrap *trap;
00104 
00105     rt = cx->runtime;
00106     trap = FindTrap(rt, script, pc);
00107     if (trap) {
00108         JS_ASSERT(trap->script == script && trap->pc == pc);
00109         JS_ASSERT(*pc == JSOP_TRAP);
00110     } else {
00111         trap = (JSTrap *) JS_malloc(cx, sizeof *trap);
00112         if (!trap || !js_AddRoot(cx, &trap->closure, "trap->closure")) {
00113             if (trap)
00114                 JS_free(cx, trap);
00115             return JS_FALSE;
00116         }
00117         JS_APPEND_LINK(&trap->links, &rt->trapList);
00118         trap->script = script;
00119         trap->pc = pc;
00120         trap->op = (JSOp)*pc;
00121         *pc = JSOP_TRAP;
00122     }
00123     trap->handler = handler;
00124     trap->closure = closure;
00125     return JS_TRUE;
00126 }
00127 
00128 JS_PUBLIC_API(JSOp)
00129 JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
00130 {
00131     JSTrap *trap;
00132 
00133     trap = FindTrap(cx->runtime, script, pc);
00134     if (!trap) {
00135         JS_ASSERT(0);   /* XXX can't happen */
00136         return JSOP_LIMIT;
00137     }
00138     return trap->op;
00139 }
00140 
00141 static void
00142 DestroyTrap(JSContext *cx, JSTrap *trap)
00143 {
00144     JS_REMOVE_LINK(&trap->links);
00145     *trap->pc = (jsbytecode)trap->op;
00146     js_RemoveRoot(cx->runtime, &trap->closure);
00147     JS_free(cx, trap);
00148 }
00149 
00150 JS_PUBLIC_API(void)
00151 JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
00152              JSTrapHandler *handlerp, void **closurep)
00153 {
00154     JSTrap *trap;
00155 
00156     trap = FindTrap(cx->runtime, script, pc);
00157     if (handlerp)
00158         *handlerp = trap ? trap->handler : NULL;
00159     if (closurep)
00160         *closurep = trap ? trap->closure : NULL;
00161     if (trap)
00162         DestroyTrap(cx, trap);
00163 }
00164 
00165 JS_PUBLIC_API(void)
00166 JS_ClearScriptTraps(JSContext *cx, JSScript *script)
00167 {
00168     JSRuntime *rt;
00169     JSTrap *trap, *next;
00170 
00171     rt = cx->runtime;
00172     for (trap = (JSTrap *)rt->trapList.next;
00173          trap != (JSTrap *)&rt->trapList;
00174          trap = next) {
00175         next = (JSTrap *)trap->links.next;
00176         if (trap->script == script)
00177             DestroyTrap(cx, trap);
00178     }
00179 }
00180 
00181 JS_PUBLIC_API(void)
00182 JS_ClearAllTraps(JSContext *cx)
00183 {
00184     JSRuntime *rt;
00185     JSTrap *trap, *next;
00186 
00187     rt = cx->runtime;
00188     for (trap = (JSTrap *)rt->trapList.next;
00189          trap != (JSTrap *)&rt->trapList;
00190          trap = next) {
00191         next = (JSTrap *)trap->links.next;
00192         DestroyTrap(cx, trap);
00193     }
00194 }
00195 
00196 JS_PUBLIC_API(JSTrapStatus)
00197 JS_HandleTrap(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval)
00198 {
00199     JSTrap *trap;
00200     JSTrapStatus status;
00201     jsint op;
00202 
00203     trap = FindTrap(cx->runtime, script, pc);
00204     if (!trap) {
00205         JS_ASSERT(0);   /* XXX can't happen */
00206         return JSTRAP_ERROR;
00207     }
00208     /*
00209      * It's important that we not use 'trap->' after calling the callback --
00210      * the callback might remove the trap!
00211      */
00212     op = (jsint)trap->op;
00213     status = trap->handler(cx, script, pc, rval, trap->closure);
00214     if (status == JSTRAP_CONTINUE) {
00215         /* By convention, return the true op to the interpreter in rval. */
00216         *rval = INT_TO_JSVAL(op);
00217     }
00218     return status;
00219 }
00220 
00221 JS_PUBLIC_API(JSBool)
00222 JS_SetInterrupt(JSRuntime *rt, JSTrapHandler handler, void *closure)
00223 {
00224     rt->interruptHandler = handler;
00225     rt->interruptHandlerData = closure;
00226     return JS_TRUE;
00227 }
00228 
00229 JS_PUBLIC_API(JSBool)
00230 JS_ClearInterrupt(JSRuntime *rt, JSTrapHandler *handlerp, void **closurep)
00231 {
00232     if (handlerp)
00233         *handlerp = (JSTrapHandler)rt->interruptHandler;
00234     if (closurep)
00235         *closurep = rt->interruptHandlerData;
00236     rt->interruptHandler = 0;
00237     rt->interruptHandlerData = 0;
00238     return JS_TRUE;
00239 }
00240 
00241 /************************************************************************/
00242 
00243 typedef struct JSWatchPoint {
00244     JSCList             links;
00245     JSObject            *object;        /* weak link, see js_FinalizeObject */
00246     JSScopeProperty     *sprop;
00247     JSPropertyOp        setter;
00248     JSWatchPointHandler handler;
00249     void                *closure;
00250     uintN               flags;
00251 } JSWatchPoint;
00252 
00253 #define JSWP_LIVE       0x1             /* live because set and not cleared */
00254 #define JSWP_HELD       0x2             /* held while running handler/setter */
00255 
00256 static JSBool
00257 DropWatchPoint(JSContext *cx, JSWatchPoint *wp, uintN flag)
00258 {
00259     JSBool ok;
00260     JSScopeProperty *sprop;
00261     JSObject *pobj;
00262     JSProperty *prop;
00263     JSPropertyOp setter;
00264 
00265     ok = JS_TRUE;
00266     wp->flags &= ~flag;
00267     if (wp->flags != 0)
00268         return JS_TRUE;
00269 
00270     /*
00271      * Remove wp from the list, then if there are no other watchpoints for
00272      * wp->sprop in any scope, restore wp->sprop->setter from wp.
00273      */
00274     JS_REMOVE_LINK(&wp->links);
00275     sprop = wp->sprop;
00276 
00277     /*
00278      * If js_ChangeNativePropertyAttrs fails, propagate failure after removing
00279      * wp->closure's root and freeing wp.
00280      */
00281     setter = js_GetWatchedSetter(cx->runtime, NULL, sprop);
00282     if (!setter) {
00283         ok = js_LookupProperty(cx, wp->object, sprop->id, &pobj, &prop);
00284 
00285         /*
00286          * If the property wasn't found on wp->object or didn't exist, then
00287          * someone else has dealt with this sprop, and we don't need to change
00288          * the property attributes.
00289          */
00290         if (ok && prop) {
00291             if (pobj == wp->object) {
00292                 JS_ASSERT(OBJ_SCOPE(pobj)->object == pobj);
00293 
00294                 sprop = js_ChangeScopePropertyAttrs(cx, OBJ_SCOPE(pobj), sprop,
00295                                                     0, sprop->attrs,
00296                                                     sprop->getter,
00297                                                     wp->setter);
00298                 if (!sprop)
00299                     ok = JS_FALSE;
00300             }
00301             OBJ_DROP_PROPERTY(cx, pobj, prop);
00302         }
00303     }
00304 
00305     js_RemoveRoot(cx->runtime, &wp->closure);
00306     JS_free(cx, wp);
00307     return ok;
00308 }
00309 
00310 void
00311 js_MarkWatchPoints(JSContext *cx)
00312 {
00313     JSRuntime *rt;
00314     JSWatchPoint *wp;
00315 
00316     rt = cx->runtime;
00317     for (wp = (JSWatchPoint *)rt->watchPointList.next;
00318          wp != (JSWatchPoint *)&rt->watchPointList;
00319          wp = (JSWatchPoint *)wp->links.next) {
00320         MARK_SCOPE_PROPERTY(cx, wp->sprop);
00321         if (wp->sprop->attrs & JSPROP_SETTER)
00322             JS_MarkGCThing(cx, wp->setter, "wp->setter", NULL);
00323     }
00324 }
00325 
00326 static JSWatchPoint *
00327 FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id)
00328 {
00329     JSWatchPoint *wp;
00330 
00331     for (wp = (JSWatchPoint *)rt->watchPointList.next;
00332          wp != (JSWatchPoint *)&rt->watchPointList;
00333          wp = (JSWatchPoint *)wp->links.next) {
00334         if (wp->object == scope->object && wp->sprop->id == id)
00335             return wp;
00336     }
00337     return NULL;
00338 }
00339 
00340 JSScopeProperty *
00341 js_FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id)
00342 {
00343     JSWatchPoint *wp;
00344 
00345     wp = FindWatchPoint(rt, scope, id);
00346     if (!wp)
00347         return NULL;
00348     return wp->sprop;
00349 }
00350 
00351 JSPropertyOp
00352 js_GetWatchedSetter(JSRuntime *rt, JSScope *scope,
00353                     const JSScopeProperty *sprop)
00354 {
00355     JSWatchPoint *wp;
00356 
00357     for (wp = (JSWatchPoint *)rt->watchPointList.next;
00358          wp != (JSWatchPoint *)&rt->watchPointList;
00359          wp = (JSWatchPoint *)wp->links.next) {
00360         if ((!scope || wp->object == scope->object) && wp->sprop == sprop)
00361             return wp->setter;
00362     }
00363     return NULL;
00364 }
00365 
00366 JSBool JS_DLL_CALLBACK
00367 js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
00368 {
00369     JSRuntime *rt;
00370     JSWatchPoint *wp;
00371     JSScopeProperty *sprop;
00372     jsval propid, userid;
00373     JSScope *scope;
00374     JSBool ok;
00375 
00376     rt = cx->runtime;
00377     for (wp = (JSWatchPoint *)rt->watchPointList.next;
00378          wp != (JSWatchPoint *)&rt->watchPointList;
00379          wp = (JSWatchPoint *)wp->links.next) {
00380         sprop = wp->sprop;
00381         if (wp->object == obj && SPROP_USERID(sprop) == id &&
00382             !(wp->flags & JSWP_HELD)) {
00383             wp->flags |= JSWP_HELD;
00384 
00385             JS_LOCK_OBJ(cx, obj);
00386             propid = ID_TO_VALUE(sprop->id);
00387             userid = (sprop->flags & SPROP_HAS_SHORTID)
00388                      ? INT_TO_JSVAL(sprop->shortid)
00389                      : propid;
00390             scope = OBJ_SCOPE(obj);
00391             JS_UNLOCK_OBJ(cx, obj);
00392 
00393             /* NB: wp is held, so we can safely dereference it still. */
00394             ok = wp->handler(cx, obj, propid,
00395                              SPROP_HAS_VALID_SLOT(sprop, scope)
00396                              ? OBJ_GET_SLOT(cx, obj, sprop->slot)
00397                              : JSVAL_VOID,
00398                              vp, wp->closure);
00399             if (ok) {
00400                 /*
00401                  * Create a pseudo-frame for the setter invocation so that any
00402                  * stack-walking security code under the setter will correctly
00403                  * identify the guilty party.  So that the watcher appears to
00404                  * be active to obj_eval and other such code, point frame.pc
00405                  * at the JSOP_STOP at the end of the script.
00406                  */
00407                 JSObject *closure;
00408                 JSClass *clasp;
00409                 JSFunction *fun;
00410                 JSScript *script;
00411                 uintN nslots;
00412                 jsval smallv[5];
00413                 jsval *argv;
00414                 JSStackFrame frame;
00415 
00416                 closure = (JSObject *) wp->closure;
00417                 clasp = OBJ_GET_CLASS(cx, closure);
00418                 if (clasp == &js_FunctionClass) {
00419                     fun = (JSFunction *) JS_GetPrivate(cx, closure);
00420                     script = FUN_SCRIPT(fun);
00421                 } else if (clasp == &js_ScriptClass) {
00422                     fun = NULL;
00423                     script = (JSScript *) JS_GetPrivate(cx, closure);
00424                 } else {
00425                     fun = NULL;
00426                     script = NULL;
00427                 }
00428 
00429                 nslots = 2;
00430                 if (fun) {
00431                     nslots += fun->nargs;
00432                     if (FUN_NATIVE(fun))
00433                         nslots += fun->u.n.extra;
00434                 }
00435 
00436                 if (nslots <= JS_ARRAY_LENGTH(smallv)) {
00437                     argv = smallv;
00438                 } else {
00439                     argv = JS_malloc(cx, nslots * sizeof(jsval));
00440                     if (!argv) {
00441                         DropWatchPoint(cx, wp, JSWP_HELD);
00442                         return JS_FALSE;
00443                     }
00444                 }
00445 
00446                 argv[0] = OBJECT_TO_JSVAL(closure);
00447                 argv[1] = JSVAL_NULL;
00448                 memset(argv + 2, 0, (nslots - 2) * sizeof(jsval));
00449 
00450                 memset(&frame, 0, sizeof(frame));
00451                 frame.script = script;
00452                 if (script) {
00453                     JS_ASSERT(script->length >= JSOP_STOP_LENGTH);
00454                     frame.pc = script->code + script->length
00455                              - JSOP_STOP_LENGTH;
00456                 }
00457                 frame.callee = closure;
00458                 frame.fun = fun;
00459                 frame.argv = argv + 2;
00460                 frame.down = cx->fp;
00461                 frame.scopeChain = OBJ_GET_PARENT(cx, closure);
00462 
00463                 cx->fp = &frame;
00464                 ok = !wp->setter ||
00465                      ((sprop->attrs & JSPROP_SETTER)
00466                       ? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(wp->setter),
00467                                         1, vp, vp)
00468                       : wp->setter(cx, OBJ_THIS_OBJECT(cx, obj), userid, vp));
00469 
00470                 /* Evil code can cause us to have an arguments object. */
00471                 if (frame.callobj)
00472                     ok &= js_PutCallObject(cx, &frame);
00473                 if (frame.argsobj)
00474                     ok &= js_PutArgsObject(cx, &frame);
00475 
00476                 cx->fp = frame.down;
00477                 if (argv != smallv)
00478                     JS_free(cx, argv);
00479             }
00480             return DropWatchPoint(cx, wp, JSWP_HELD) && ok;
00481         }
00482     }
00483     return JS_TRUE;
00484 }
00485 
00486 JSBool JS_DLL_CALLBACK
00487 js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
00488                      jsval *rval)
00489 {
00490     JSObject *funobj;
00491     JSFunction *wrapper;
00492     jsval userid;
00493 
00494     funobj = JSVAL_TO_OBJECT(argv[-2]);
00495     JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass);
00496     wrapper = (JSFunction *) JS_GetPrivate(cx, funobj);
00497     userid = ATOM_KEY(wrapper->atom);
00498     *rval = argv[0];
00499     return js_watch_set(cx, obj, userid, rval);
00500 }
00501 
00502 JSPropertyOp
00503 js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter)
00504 {
00505     JSAtom *atom;
00506     JSFunction *wrapper;
00507 
00508     if (!(attrs & JSPROP_SETTER))
00509         return &js_watch_set;   /* & to silence schoolmarmish MSVC */
00510 
00511     if (JSID_IS_ATOM(id)) {
00512         atom = JSID_TO_ATOM(id);
00513     } else if (JSID_IS_INT(id)) {
00514         atom = js_AtomizeInt(cx, JSID_TO_INT(id), 0);
00515         if (!atom)
00516             return NULL;
00517     } else {
00518         atom = NULL;
00519     }
00520     wrapper = js_NewFunction(cx, NULL, js_watch_set_wrapper, 1, 0,
00521                              OBJ_GET_PARENT(cx, (JSObject *)setter),
00522                              atom);
00523     if (!wrapper)
00524         return NULL;
00525     return (JSPropertyOp) wrapper->object;
00526 }
00527 
00528 JS_PUBLIC_API(JSBool)
00529 JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id,
00530                  JSWatchPointHandler handler, void *closure)
00531 {
00532     JSAtom *atom;
00533     jsid propid;
00534     JSObject *pobj;
00535     JSProperty *prop;
00536     JSScopeProperty *sprop;
00537     JSRuntime *rt;
00538     JSBool ok;
00539     JSWatchPoint *wp;
00540     JSPropertyOp watcher;
00541 
00542     if (!OBJ_IS_NATIVE(obj)) {
00543         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH,
00544                              OBJ_GET_CLASS(cx, obj)->name);
00545         return JS_FALSE;
00546     }
00547 
00548     if (JSVAL_IS_INT(id)) {
00549         propid = INT_JSVAL_TO_JSID(id);
00550         atom = NULL;
00551     } else {
00552         atom = js_ValueToStringAtom(cx, id);
00553         if (!atom)
00554             return JS_FALSE;
00555         propid = ATOM_TO_JSID(atom);
00556     }
00557 
00558     if (!js_LookupProperty(cx, obj, propid, &pobj, &prop))
00559         return JS_FALSE;
00560     sprop = (JSScopeProperty *) prop;
00561     rt = cx->runtime;
00562     if (!sprop) {
00563         /* Check for a deleted symbol watchpoint, which holds its property. */
00564         sprop = js_FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
00565         if (!sprop) {
00566             /* Make a new property in obj so we can watch for the first set. */
00567             if (!js_DefineProperty(cx, obj, propid, JSVAL_VOID,
00568                                    NULL, NULL, JSPROP_ENUMERATE,
00569                                    &prop)) {
00570                 return JS_FALSE;
00571             }
00572             sprop = (JSScopeProperty *) prop;
00573         }
00574     } else if (pobj != obj) {
00575         /* Clone the prototype property so we can watch the right object. */
00576         jsval value;
00577         JSPropertyOp getter, setter;
00578         uintN attrs, flags;
00579         intN shortid;
00580 
00581         if (OBJ_IS_NATIVE(pobj)) {
00582             value = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))
00583                     ? LOCKED_OBJ_GET_SLOT(pobj, sprop->slot)
00584                     : JSVAL_VOID;
00585             getter = sprop->getter;
00586             setter = sprop->setter;
00587             attrs = sprop->attrs;
00588             flags = sprop->flags;
00589             shortid = sprop->shortid;
00590         } else {
00591             if (!OBJ_GET_PROPERTY(cx, pobj, id, &value) ||
00592                 !OBJ_GET_ATTRIBUTES(cx, pobj, id, prop, &attrs)) {
00593                 OBJ_DROP_PROPERTY(cx, pobj, prop);
00594                 return JS_FALSE;
00595             }
00596             getter = setter = NULL;
00597             flags = 0;
00598             shortid = 0;
00599         }
00600         OBJ_DROP_PROPERTY(cx, pobj, prop);
00601 
00602         /* Recall that obj is native, whether or not pobj is native. */
00603         if (!js_DefineNativeProperty(cx, obj, propid, value, getter, setter,
00604                                      attrs, flags, shortid, &prop)) {
00605             return JS_FALSE;
00606         }
00607         sprop = (JSScopeProperty *) prop;
00608     }
00609 
00610     /*
00611      * At this point, prop/sprop exists in obj, obj is locked, and we must
00612      * OBJ_DROP_PROPERTY(cx, obj, prop) before returning.
00613      */
00614     ok = JS_TRUE;
00615     wp = FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
00616     if (!wp) {
00617         watcher = js_WrapWatchedSetter(cx, propid, sprop->attrs, sprop->setter);
00618         if (!watcher) {
00619             ok = JS_FALSE;
00620             goto out;
00621         }
00622 
00623         wp = (JSWatchPoint *) JS_malloc(cx, sizeof *wp);
00624         if (!wp) {
00625             ok = JS_FALSE;
00626             goto out;
00627         }
00628         wp->handler = NULL;
00629         wp->closure = NULL;
00630         ok = js_AddRoot(cx, &wp->closure, "wp->closure");
00631         if (!ok) {
00632             JS_free(cx, wp);
00633             goto out;
00634         }
00635         wp->object = obj;
00636         JS_ASSERT(sprop->setter != js_watch_set || pobj != obj);
00637         wp->setter = sprop->setter;
00638         wp->flags = JSWP_LIVE;
00639 
00640         /* XXXbe nest in obj lock here */
00641         sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop, 0, sprop->attrs,
00642                                              sprop->getter, watcher);
00643         if (!sprop) {
00644             /* Self-link so DropWatchPoint can JS_REMOVE_LINK it. */
00645             JS_INIT_CLIST(&wp->links);
00646             DropWatchPoint(cx, wp, JSWP_LIVE);
00647             ok = JS_FALSE;
00648             goto out;
00649         }
00650         wp->sprop = sprop;
00651 
00652         /*
00653          * Now that wp is fully initialized, append it to rt's wp list.
00654          * Because obj is locked we know that no other thread could have added
00655          * a watchpoint for (obj, propid).
00656          */
00657         JS_ASSERT(!FindWatchPoint(rt, OBJ_SCOPE(obj), propid));
00658         JS_APPEND_LINK(&wp->links, &rt->watchPointList);
00659     }
00660     wp->handler = handler;
00661     wp->closure = closure;
00662 
00663 out:
00664     OBJ_DROP_PROPERTY(cx, obj, prop);
00665     return ok;
00666 }
00667 
00668 JS_PUBLIC_API(JSBool)
00669 JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsval id,
00670                    JSWatchPointHandler *handlerp, void **closurep)
00671 {
00672     JSRuntime *rt;
00673     JSWatchPoint *wp;
00674 
00675     rt = cx->runtime;
00676     for (wp = (JSWatchPoint *)rt->watchPointList.next;
00677          wp != (JSWatchPoint *)&rt->watchPointList;
00678          wp = (JSWatchPoint *)wp->links.next) {
00679         if (wp->object == obj && SPROP_USERID(wp->sprop) == id) {
00680             if (handlerp)
00681                 *handlerp = wp->handler;
00682             if (closurep)
00683                 *closurep = wp->closure;
00684             return DropWatchPoint(cx, wp, JSWP_LIVE);
00685         }
00686     }
00687     if (handlerp)
00688         *handlerp = NULL;
00689     if (closurep)
00690         *closurep = NULL;
00691     return JS_TRUE;
00692 }
00693 
00694 JS_PUBLIC_API(JSBool)
00695 JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj)
00696 {
00697     JSRuntime *rt;
00698     JSWatchPoint *wp, *next;
00699 
00700     rt = cx->runtime;
00701     for (wp = (JSWatchPoint *)rt->watchPointList.next;
00702          wp != (JSWatchPoint *)&rt->watchPointList;
00703          wp = next) {
00704         next = (JSWatchPoint *)wp->links.next;
00705         if (wp->object == obj && !DropWatchPoint(cx, wp, JSWP_LIVE))
00706             return JS_FALSE;
00707     }
00708     return JS_TRUE;
00709 }
00710 
00711 JS_PUBLIC_API(JSBool)
00712 JS_ClearAllWatchPoints(JSContext *cx)
00713 {
00714     JSRuntime *rt;
00715     JSWatchPoint *wp, *next;
00716 
00717     rt = cx->runtime;
00718     for (wp = (JSWatchPoint *)rt->watchPointList.next;
00719          wp != (JSWatchPoint *)&rt->watchPointList;
00720          wp = next) {
00721         next = (JSWatchPoint *)wp->links.next;
00722         if (!DropWatchPoint(cx, wp, JSWP_LIVE))
00723             return JS_FALSE;
00724     }
00725     return JS_TRUE;
00726 }
00727 
00728 /************************************************************************/
00729 
00730 JS_PUBLIC_API(uintN)
00731 JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
00732 {
00733     return js_PCToLineNumber(cx, script, pc);
00734 }
00735 
00736 JS_PUBLIC_API(jsbytecode *)
00737 JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno)
00738 {
00739     return js_LineNumberToPC(script, lineno);
00740 }
00741 
00742 JS_PUBLIC_API(JSScript *)
00743 JS_GetFunctionScript(JSContext *cx, JSFunction *fun)
00744 {
00745     return FUN_SCRIPT(fun);
00746 }
00747 
00748 JS_PUBLIC_API(JSNative)
00749 JS_GetFunctionNative(JSContext *cx, JSFunction *fun)
00750 {
00751     return FUN_NATIVE(fun);
00752 }
00753 
00754 JS_PUBLIC_API(JSPrincipals *)
00755 JS_GetScriptPrincipals(JSContext *cx, JSScript *script)
00756 {
00757     return script->principals;
00758 }
00759 
00760 /************************************************************************/
00761 
00762 /*
00763  *  Stack Frame Iterator
00764  */
00765 JS_PUBLIC_API(JSStackFrame *)
00766 JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
00767 {
00768     *iteratorp = (*iteratorp == NULL) ? cx->fp : (*iteratorp)->down;
00769     return *iteratorp;
00770 }
00771 
00772 JS_PUBLIC_API(JSScript *)
00773 JS_GetFrameScript(JSContext *cx, JSStackFrame *fp)
00774 {
00775     return fp->script;
00776 }
00777 
00778 JS_PUBLIC_API(jsbytecode *)
00779 JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
00780 {
00781     return fp->pc;
00782 }
00783 
00784 JS_PUBLIC_API(JSStackFrame *)
00785 JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
00786 {
00787     if (!fp)
00788         fp = cx->fp;
00789     while ((fp = fp->down) != NULL) {
00790         if (fp->script)
00791             return fp;
00792     }
00793     return NULL;
00794 }
00795 
00796 JS_PUBLIC_API(JSPrincipals *)
00797 JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp)
00798 {
00799     if (fp->fun) {
00800         JSRuntime *rt = cx->runtime;
00801 
00802         if (rt->findObjectPrincipals) {
00803             JSObject *callee = JSVAL_TO_OBJECT(fp->argv[-2]);
00804 
00805             if (fp->fun->object != callee)
00806                 return rt->findObjectPrincipals(cx, callee);
00807             /* FALL THROUGH */
00808         }
00809     }
00810     if (fp->script)
00811         return fp->script->principals;
00812     return NULL;
00813 }
00814 
00815 JS_PUBLIC_API(JSPrincipals *)
00816 JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller)
00817 {
00818     JSRuntime *rt;
00819     JSObject *callee;
00820     JSPrincipals *principals, *callerPrincipals;
00821 
00822     rt = cx->runtime;
00823     if (rt->findObjectPrincipals) {
00824         callee = JSVAL_TO_OBJECT(fp->argv[-2]);
00825         principals = rt->findObjectPrincipals(cx, callee);
00826     } else {
00827         principals = NULL;
00828     }
00829     if (!caller)
00830         return principals;
00831     callerPrincipals = JS_StackFramePrincipals(cx, caller);
00832     return (callerPrincipals && principals &&
00833             callerPrincipals->subsume(callerPrincipals, principals))
00834            ? principals
00835            : callerPrincipals;
00836 }
00837 
00838 JS_PUBLIC_API(void *)
00839 JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
00840 {
00841     if (fp->annotation && fp->script) {
00842         JSPrincipals *principals = JS_StackFramePrincipals(cx, fp);
00843 
00844         if (principals && principals->globalPrivilegesEnabled(cx, principals)) {
00845             /*
00846              * Give out an annotation only if privileges have not been revoked
00847              * or disabled globally.
00848              */
00849             return fp->annotation;
00850         }
00851     }
00852 
00853     return NULL;
00854 }
00855 
00856 JS_PUBLIC_API(void)
00857 JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation)
00858 {
00859     fp->annotation = annotation;
00860 }
00861 
00862 JS_PUBLIC_API(void *)
00863 JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp)
00864 {
00865     JSPrincipals *principals;
00866 
00867     principals = JS_StackFramePrincipals(cx, fp);
00868     if (!principals)
00869         return NULL;
00870     return principals->getPrincipalArray(cx, principals);
00871 }
00872 
00873 JS_PUBLIC_API(JSBool)
00874 JS_IsNativeFrame(JSContext *cx, JSStackFrame *fp)
00875 {
00876     return !fp->script;
00877 }
00878 
00879 /* this is deprecated, use JS_GetFrameScopeChain instead */
00880 JS_PUBLIC_API(JSObject *)
00881 JS_GetFrameObject(JSContext *cx, JSStackFrame *fp)
00882 {
00883     return fp->scopeChain;
00884 }
00885 
00886 JS_PUBLIC_API(JSObject *)
00887 JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp)
00888 {
00889     /* Force creation of argument and call objects if not yet created */
00890     (void) JS_GetFrameCallObject(cx, fp);
00891     return js_GetScopeChain(cx, fp);
00892 }
00893 
00894 JS_PUBLIC_API(JSObject *)
00895 JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp)
00896 {
00897     if (! fp->fun)
00898         return NULL;
00899 
00900     /* Force creation of argument object if not yet created */
00901     (void) js_GetArgsObject(cx, fp);
00902 
00903     /*
00904      * XXX ill-defined: null return here means error was reported, unlike a
00905      *     null returned above or in the #else
00906      */
00907     return js_GetCallObject(cx, fp, NULL);
00908 }
00909 
00910 
00911 JS_PUBLIC_API(JSObject *)
00912 JS_GetFrameThis(JSContext *cx, JSStackFrame *fp)
00913 {
00914     return fp->thisp;
00915 }
00916 
00917 JS_PUBLIC_API(JSFunction *)
00918 JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
00919 {
00920     return fp->fun;
00921 }
00922 
00923 JS_PUBLIC_API(JSObject *)
00924 JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp)
00925 {
00926     return fp->argv && fp->fun ? JSVAL_TO_OBJECT(fp->argv[-2]) : NULL;
00927 }
00928 
00929 JS_PUBLIC_API(JSBool)
00930 JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp)
00931 {
00932     return (fp->flags & JSFRAME_CONSTRUCTING) != 0;
00933 }
00934 
00935 JS_PUBLIC_API(JSObject *)
00936 JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp)
00937 {
00938     return fp->argv ? JSVAL_TO_OBJECT(fp->argv[-2]) : NULL;
00939 }
00940 
00941 JS_PUBLIC_API(JSBool)
00942 JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp)
00943 {
00944     return (fp->flags & JSFRAME_DEBUGGER) != 0;
00945 }
00946 
00947 JS_PUBLIC_API(jsval)
00948 JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp)
00949 {
00950     return fp->rval;
00951 }
00952 
00953 JS_PUBLIC_API(void)
00954 JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval)
00955 {
00956     fp->rval = rval;
00957 }
00958 
00959 /************************************************************************/
00960 
00961 JS_PUBLIC_API(const char *)
00962 JS_GetScriptFilename(JSContext *cx, JSScript *script)
00963 {
00964     return script->filename;
00965 }
00966 
00967 JS_PUBLIC_API(uintN)
00968 JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script)
00969 {
00970     return script->lineno;
00971 }
00972 
00973 JS_PUBLIC_API(uintN)
00974 JS_GetScriptLineExtent(JSContext *cx, JSScript *script)
00975 {
00976     return js_GetScriptLineExtent(script);
00977 }
00978 
00979 JS_PUBLIC_API(JSVersion)
00980 JS_GetScriptVersion(JSContext *cx, JSScript *script)
00981 {
00982     return script->version & JSVERSION_MASK;
00983 }
00984 
00985 /***************************************************************************/
00986 
00987 JS_PUBLIC_API(void)
00988 JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata)
00989 {
00990     rt->newScriptHook = hook;
00991     rt->newScriptHookData = callerdata;
00992 }
00993 
00994 JS_PUBLIC_API(void)
00995 JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook,
00996                         void *callerdata)
00997 {
00998     rt->destroyScriptHook = hook;
00999     rt->destroyScriptHookData = callerdata;
01000 }
01001 
01002 /***************************************************************************/
01003 
01004 JS_PUBLIC_API(JSBool)
01005 JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
01006                           const jschar *chars, uintN length,
01007                           const char *filename, uintN lineno,
01008                           jsval *rval)
01009 {
01010     JSObject *scobj;
01011     uint32 flags, options;
01012     JSScript *script;
01013     JSBool ok;
01014 
01015     scobj = JS_GetFrameScopeChain(cx, fp);
01016     if (!scobj)
01017         return JS_FALSE;
01018 
01019     /*
01020      * XXX Hack around ancient compiler API to propagate the JSFRAME_SPECIAL
01021      * flags to the code generator (see js_EmitTree's TOK_SEMI case).
01022      */
01023     flags = fp->flags;
01024     fp->flags |= JSFRAME_DEBUGGER | JSFRAME_EVAL;
01025     options = cx->options;
01026     cx->options = options | JSOPTION_COMPILE_N_GO;
01027     script = JS_CompileUCScriptForPrincipals(cx, scobj,
01028                                              JS_StackFramePrincipals(cx, fp),
01029                                              chars, length, filename, lineno);
01030     fp->flags = flags;
01031     cx->options = options;
01032     if (!script)
01033         return JS_FALSE;
01034 
01035     ok = js_Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL,
01036                     rval);
01037     js_DestroyScript(cx, script);
01038     return ok;
01039 }
01040 
01041 JS_PUBLIC_API(JSBool)
01042 JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp,
01043                         const char *bytes, uintN length,
01044                         const char *filename, uintN lineno,
01045                         jsval *rval)
01046 {
01047     jschar *chars;
01048     JSBool ok;
01049     size_t len = length;
01050 
01051     chars = js_InflateString(cx, bytes, &len);
01052     if (!chars)
01053         return JS_FALSE;
01054     length = (uintN) len;
01055     ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length, filename, lineno,
01056                                    rval);
01057     JS_free(cx, chars);
01058 
01059     return ok;
01060 }
01061 
01062 /************************************************************************/
01063 
01064 /* XXXbe this all needs to be reworked to avoid requiring JSScope types. */
01065 
01066 JS_PUBLIC_API(JSScopeProperty *)
01067 JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp)
01068 {
01069     JSScopeProperty *sprop;
01070     JSScope *scope;
01071 
01072     sprop = *iteratorp;
01073     scope = OBJ_SCOPE(obj);
01074 
01075     /* XXXbe minor(?) incompatibility: iterate in reverse definition order */
01076     if (!sprop) {
01077         sprop = SCOPE_LAST_PROP(scope);
01078     } else {
01079         while ((sprop = sprop->parent) != NULL) {
01080             if (!SCOPE_HAD_MIDDLE_DELETE(scope))
01081                 break;
01082             if (SCOPE_HAS_PROPERTY(scope, sprop))
01083                 break;
01084         }
01085     }
01086     *iteratorp = sprop;
01087     return sprop;
01088 }
01089 
01090 JS_PUBLIC_API(JSBool)
01091 JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
01092                    JSPropertyDesc *pd)
01093 {
01094     JSPropertyOp getter;
01095     JSScope *scope;
01096     JSScopeProperty *aprop;
01097     jsval lastException;
01098     JSBool wasThrowing;
01099 
01100     pd->id = ID_TO_VALUE(sprop->id);
01101 
01102     wasThrowing = cx->throwing;
01103     if (wasThrowing) {
01104         lastException = cx->exception;
01105         if (JSVAL_IS_GCTHING(lastException) &&
01106             !js_AddRoot(cx, &lastException, "lastException")) {
01107                 return JS_FALSE;
01108         }
01109         cx->throwing = JS_FALSE;
01110     }
01111 
01112     if (!js_GetProperty(cx, obj, sprop->id, &pd->value)) {
01113         if (!cx->throwing) {
01114             pd->flags = JSPD_ERROR;
01115             pd->value = JSVAL_VOID;
01116         } else {
01117             pd->flags = JSPD_EXCEPTION;
01118             pd->value = cx->exception;
01119         }
01120     } else {
01121         pd->flags = 0;
01122     }
01123 
01124     cx->throwing = wasThrowing;
01125     if (wasThrowing) {
01126         cx->exception = lastException;
01127         if (JSVAL_IS_GCTHING(lastException))
01128             js_RemoveRoot(cx->runtime, &lastException);
01129     }
01130 
01131     getter = sprop->getter;
01132     pd->flags |= ((sprop->attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0)
01133               | ((sprop->attrs & JSPROP_READONLY)  ? JSPD_READONLY  : 0)
01134               | ((sprop->attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0)
01135               | ((getter == js_GetCallVariable)    ? JSPD_VARIABLE  : 0)
01136               | ((getter == js_GetArgument)        ? JSPD_ARGUMENT  : 0)
01137               | ((getter == js_GetLocalVariable)   ? JSPD_VARIABLE  : 0);
01138 
01139     /* for Call Object 'real' getter isn't passed in to us */
01140     if (OBJ_GET_CLASS(cx, obj) == &js_CallClass &&
01141         getter == js_CallClass.getProperty) {
01142         /*
01143          * Property of a heavyweight function's variable object having the
01144          * class-default getter.  It's either an argument if permanent, or a
01145          * nested function if impermanent.  Local variables have a special
01146          * getter (js_GetCallVariable, tested above) and setter, and not the
01147          * class default.
01148          */
01149         pd->flags |= (sprop->attrs & JSPROP_PERMANENT)
01150                      ? JSPD_ARGUMENT
01151                      : JSPD_VARIABLE;
01152     }
01153 
01154     pd->spare = 0;
01155     pd->slot = (pd->flags & (JSPD_ARGUMENT | JSPD_VARIABLE))
01156                ? sprop->shortid
01157                : 0;
01158     pd->alias = JSVAL_VOID;
01159     scope = OBJ_SCOPE(obj);
01160     if (SPROP_HAS_VALID_SLOT(sprop, scope)) {
01161         for (aprop = SCOPE_LAST_PROP(scope); aprop; aprop = aprop->parent) {
01162             if (aprop != sprop && aprop->slot == sprop->slot) {
01163                 pd->alias = ID_TO_VALUE(aprop->id);
01164                 break;
01165             }
01166         }
01167     }
01168     return JS_TRUE;
01169 }
01170 
01171 JS_PUBLIC_API(JSBool)
01172 JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda)
01173 {
01174     JSClass *clasp;
01175     JSScope *scope;
01176     uint32 i, n;
01177     JSPropertyDesc *pd;
01178     JSScopeProperty *sprop;
01179 
01180     clasp = OBJ_GET_CLASS(cx, obj);
01181     if (!OBJ_IS_NATIVE(obj) || (clasp->flags & JSCLASS_NEW_ENUMERATE)) {
01182         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
01183                              JSMSG_CANT_DESCRIBE_PROPS, clasp->name);
01184         return JS_FALSE;
01185     }
01186     if (!clasp->enumerate(cx, obj))
01187         return JS_FALSE;
01188 
01189     /* have no props, or object's scope has not mutated from that of proto */
01190     scope = OBJ_SCOPE(obj);
01191     if (scope->object != obj || scope->entryCount == 0) {
01192         pda->length = 0;
01193         pda->array = NULL;
01194         return JS_TRUE;
01195     }
01196 
01197     n = scope->entryCount;
01198     if (n > scope->map.nslots)
01199         n = scope->map.nslots;
01200     pd = (JSPropertyDesc *) JS_malloc(cx, (size_t)n * sizeof(JSPropertyDesc));
01201     if (!pd)
01202         return JS_FALSE;
01203     i = 0;
01204     for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
01205         if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop))
01206             continue;
01207         if (!js_AddRoot(cx, &pd[i].id, NULL))
01208             goto bad;
01209         if (!js_AddRoot(cx, &pd[i].value, NULL))
01210             goto bad;
01211         if (!JS_GetPropertyDesc(cx, obj, sprop, &pd[i]))
01212             goto bad;
01213         if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL))
01214             goto bad;
01215         if (++i == n)
01216             break;
01217     }
01218     pda->length = i;
01219     pda->array = pd;
01220     return JS_TRUE;
01221 
01222 bad:
01223     pda->length = i + 1;
01224     pda->array = pd;
01225     JS_PutPropertyDescArray(cx, pda);
01226     return JS_FALSE;
01227 }
01228 
01229 JS_PUBLIC_API(void)
01230 JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda)
01231 {
01232     JSPropertyDesc *pd;
01233     uint32 i;
01234 
01235     pd = pda->array;
01236     for (i = 0; i < pda->length; i++) {
01237         js_RemoveRoot(cx->runtime, &pd[i].id);
01238         js_RemoveRoot(cx->runtime, &pd[i].value);
01239         if (pd[i].flags & JSPD_ALIAS)
01240             js_RemoveRoot(cx->runtime, &pd[i].alias);
01241     }
01242     JS_free(cx, pd);
01243 }
01244 
01245 /************************************************************************/
01246 
01247 JS_PUBLIC_API(JSBool)
01248 JS_SetDebuggerHandler(JSRuntime *rt, JSTrapHandler handler, void *closure)
01249 {
01250     rt->debuggerHandler = handler;
01251     rt->debuggerHandlerData = closure;
01252     return JS_TRUE;
01253 }
01254 
01255 JS_PUBLIC_API(JSBool)
01256 JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure)
01257 {
01258     rt->sourceHandler = handler;
01259     rt->sourceHandlerData = closure;
01260     return JS_TRUE;
01261 }
01262 
01263 JS_PUBLIC_API(JSBool)
01264 JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
01265 {
01266     rt->executeHook = hook;
01267     rt->executeHookData = closure;
01268     return JS_TRUE;
01269 }
01270 
01271 JS_PUBLIC_API(JSBool)
01272 JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
01273 {
01274     rt->callHook = hook;
01275     rt->callHookData = closure;
01276     return JS_TRUE;
01277 }
01278 
01279 JS_PUBLIC_API(JSBool)
01280 JS_SetObjectHook(JSRuntime *rt, JSObjectHook hook, void *closure)
01281 {
01282     rt->objectHook = hook;
01283     rt->objectHookData = closure;
01284     return JS_TRUE;
01285 }
01286 
01287 JS_PUBLIC_API(JSBool)
01288 JS_SetThrowHook(JSRuntime *rt, JSTrapHandler hook, void *closure)
01289 {
01290     rt->throwHook = hook;
01291     rt->throwHookData = closure;
01292     return JS_TRUE;
01293 }
01294 
01295 JS_PUBLIC_API(JSBool)
01296 JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure)
01297 {
01298     rt->debugErrorHook = hook;
01299     rt->debugErrorHookData = closure;
01300     return JS_TRUE;
01301 }
01302 
01303 /************************************************************************/
01304 
01305 JS_PUBLIC_API(size_t)
01306 JS_GetObjectTotalSize(JSContext *cx, JSObject *obj)
01307 {
01308     size_t nbytes;
01309     JSScope *scope;
01310 
01311     nbytes = sizeof *obj + obj->map->nslots * sizeof obj->slots[0];
01312     if (OBJ_IS_NATIVE(obj)) {
01313         scope = OBJ_SCOPE(obj);
01314         if (scope->object == obj) {
01315             nbytes += sizeof *scope;
01316             nbytes += SCOPE_CAPACITY(scope) * sizeof(JSScopeProperty *);
01317         }
01318     }
01319     return nbytes;
01320 }
01321 
01322 static size_t
01323 GetAtomTotalSize(JSContext *cx, JSAtom *atom)
01324 {
01325     size_t nbytes;
01326 
01327     nbytes = sizeof *atom;
01328     if (ATOM_IS_STRING(atom)) {
01329         nbytes += sizeof(JSString);
01330         nbytes += (ATOM_TO_STRING(atom)->length + 1) * sizeof(jschar);
01331     } else if (ATOM_IS_DOUBLE(atom)) {
01332         nbytes += sizeof(jsdouble);
01333     } else if (ATOM_IS_OBJECT(atom)) {
01334         nbytes += JS_GetObjectTotalSize(cx, ATOM_TO_OBJECT(atom));
01335     }
01336     return nbytes;
01337 }
01338 
01339 JS_PUBLIC_API(size_t)
01340 JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun)
01341 {
01342     size_t nbytes;
01343 
01344     nbytes = sizeof *fun;
01345     if (fun->object)
01346         nbytes += JS_GetObjectTotalSize(cx, fun->object);
01347     if (FUN_INTERPRETED(fun))
01348         nbytes += JS_GetScriptTotalSize(cx, fun->u.i.script);
01349     if (fun->atom)
01350         nbytes += GetAtomTotalSize(cx, fun->atom);
01351     return nbytes;
01352 }
01353 
01354 #include "jsemit.h"
01355 
01356 JS_PUBLIC_API(size_t)
01357 JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
01358 {
01359     size_t nbytes, pbytes;
01360     JSObject *obj;
01361     jsatomid i;
01362     jssrcnote *sn, *notes;
01363     JSTryNote *tn, *tnotes;
01364     JSPrincipals *principals;
01365 
01366     nbytes = sizeof *script;
01367     obj = script->object;
01368     if (obj)
01369         nbytes += JS_GetObjectTotalSize(cx, obj);
01370 
01371     nbytes += script->length * sizeof script->code[0];
01372     nbytes += script->atomMap.length * sizeof script->atomMap.vector[0];
01373     for (i = 0; i < script->atomMap.length; i++)
01374         nbytes += GetAtomTotalSize(cx, script->atomMap.vector[i]);
01375 
01376     if (script->filename)
01377         nbytes += strlen(script->filename) + 1;
01378 
01379     notes = SCRIPT_NOTES(script);
01380     for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
01381         continue;
01382     nbytes += (sn - notes + 1) * sizeof *sn;
01383 
01384     tnotes = script->trynotes;
01385     if (tnotes) {
01386         for (tn = tnotes; tn->catchStart; tn++)
01387             continue;
01388         nbytes += (tn - tnotes + 1) * sizeof *tn;
01389     }
01390 
01391     principals = script->principals;
01392     if (principals) {
01393         JS_ASSERT(principals->refcount);
01394         pbytes = sizeof *principals;
01395         if (principals->refcount > 1)
01396             pbytes = JS_HOWMANY(pbytes, principals->refcount);
01397         nbytes += pbytes;
01398     }
01399 
01400     return nbytes;
01401 }
01402 
01403 JS_PUBLIC_API(uint32)
01404 JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp)
01405 {
01406     if (!fp)
01407         fp = cx->fp;
01408     while (fp) {
01409         if (fp->script) {
01410             return JS_GetScriptFilenameFlags(fp->script);
01411         }
01412         fp = fp->down;
01413     }
01414     return 0;
01415  }
01416 
01417 JS_PUBLIC_API(uint32)
01418 JS_GetScriptFilenameFlags(JSScript *script)
01419 {
01420     JS_ASSERT(script);
01421     if (!script->filename)
01422         return JSFILENAME_NULL;
01423     return js_GetScriptFilenameFlags(script->filename);
01424 }
01425 
01426 JS_PUBLIC_API(JSBool)
01427 JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags)
01428 {
01429     if (!js_SaveScriptFilenameRT(rt, prefix, flags))
01430         return JS_FALSE;
01431     return JS_TRUE;
01432 }
01433 
01434 JS_PUBLIC_API(JSBool)
01435 JS_IsSystemObject(JSContext *cx, JSObject *obj)
01436 {
01437     return (*js_GetGCThingFlags(obj) & GCF_SYSTEM) != 0;
01438 }
01439 
01440 JS_PUBLIC_API(void)
01441 JS_FlagSystemObject(JSContext *cx, JSObject *obj)
01442 {
01443     uint8 *flagp;
01444 
01445     flagp = js_GetGCThingFlags(obj);
01446     *flagp |= GCF_SYSTEM;
01447 }