PageRenderTime 316ms CodeModel.GetById 122ms app.highlight 177ms RepoModel.GetById 1ms app.codeStats 1ms

/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/jsdbgapi.cpp

http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs
C++ | 1954 lines | 1571 code | 241 blank | 142 comment | 304 complexity | 9da1bf018cd02a156e9fd449d3e17c9d MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   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 "jsversion.h"
  52#include "jsdbgapi.h"
  53#include "jsemit.h"
  54#include "jsfun.h"
  55#include "jsgc.h"
  56#include "jsinterp.h"
  57#include "jslock.h"
  58#include "jsobj.h"
  59#include "jsopcode.h"
  60#include "jsparse.h"
  61#include "jsscope.h"
  62#include "jsscript.h"
  63#include "jsstr.h"
  64
  65#include "jsautooplen.h"
  66
  67typedef struct JSTrap {
  68    JSCList         links;
  69    JSScript        *script;
  70    jsbytecode      *pc;
  71    JSOp            op;
  72    JSTrapHandler   handler;
  73    void            *closure;
  74} JSTrap;
  75
  76#define DBG_LOCK(rt)            JS_ACQUIRE_LOCK((rt)->debuggerLock)
  77#define DBG_UNLOCK(rt)          JS_RELEASE_LOCK((rt)->debuggerLock)
  78#define DBG_LOCK_EVAL(rt,expr)  (DBG_LOCK(rt), (expr), DBG_UNLOCK(rt))
  79
  80/*
  81 * NB: FindTrap must be called with rt->debuggerLock acquired.
  82 */
  83static JSTrap *
  84FindTrap(JSRuntime *rt, JSScript *script, jsbytecode *pc)
  85{
  86    JSTrap *trap;
  87
  88    for (trap = (JSTrap *)rt->trapList.next;
  89         &trap->links != &rt->trapList;
  90         trap = (JSTrap *)trap->links.next) {
  91        if (trap->script == script && trap->pc == pc)
  92            return trap;
  93    }
  94    return NULL;
  95}
  96
  97jsbytecode *
  98js_UntrapScriptCode(JSContext *cx, JSScript *script)
  99{
 100    jsbytecode *code;
 101    JSRuntime *rt;
 102    JSTrap *trap;
 103
 104    code = script->code;
 105    rt = cx->runtime;
 106    DBG_LOCK(rt);
 107    for (trap = (JSTrap *)rt->trapList.next;
 108         &trap->links !=
 109                &rt->trapList;
 110         trap = (JSTrap *)trap->links.next) {
 111        if (trap->script == script &&
 112            (size_t)(trap->pc - script->code) < script->length) {
 113            if (code == script->code) {
 114                jssrcnote *sn, *notes;
 115                size_t nbytes;
 116
 117                nbytes = script->length * sizeof(jsbytecode);
 118                notes = SCRIPT_NOTES(script);
 119                for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
 120                    continue;
 121                nbytes += (sn - notes + 1) * sizeof *sn;
 122
 123                code = (jsbytecode *) JS_malloc(cx, nbytes);
 124                if (!code)
 125                    break;
 126                memcpy(code, script->code, nbytes);
 127                JS_CLEAR_GSN_CACHE(cx);
 128            }
 129            code[trap->pc - script->code] = trap->op;
 130        }
 131    }
 132    DBG_UNLOCK(rt);
 133    return code;
 134}
 135
 136JS_PUBLIC_API(JSBool)
 137JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
 138           JSTrapHandler handler, void *closure)
 139{
 140    JSTrap *junk, *trap, *twin;
 141    JSRuntime *rt;
 142    uint32 sample;
 143
 144    JS_ASSERT((JSOp) *pc != JSOP_TRAP);
 145    junk = NULL;
 146    rt = cx->runtime;
 147    DBG_LOCK(rt);
 148    trap = FindTrap(rt, script, pc);
 149    if (trap) {
 150        JS_ASSERT(trap->script == script && trap->pc == pc);
 151        JS_ASSERT(*pc == JSOP_TRAP);
 152    } else {
 153        sample = rt->debuggerMutations;
 154        DBG_UNLOCK(rt);
 155        trap = (JSTrap *) JS_malloc(cx, sizeof *trap);
 156        if (!trap)
 157            return JS_FALSE;
 158        trap->closure = NULL;
 159        if(!js_AddRoot(cx, &trap->closure, "trap->closure")) {
 160            JS_free(cx, trap);
 161            return JS_FALSE;
 162        }
 163        DBG_LOCK(rt);
 164        twin = (rt->debuggerMutations != sample)
 165               ? FindTrap(rt, script, pc)
 166               : NULL;
 167        if (twin) {
 168            junk = trap;
 169            trap = twin;
 170        } else {
 171            JS_APPEND_LINK(&trap->links, &rt->trapList);
 172            ++rt->debuggerMutations;
 173            trap->script = script;
 174            trap->pc = pc;
 175            trap->op = (JSOp)*pc;
 176            *pc = JSOP_TRAP;
 177        }
 178    }
 179    trap->handler = handler;
 180    trap->closure = closure;
 181    DBG_UNLOCK(rt);
 182    if (junk) {
 183        js_RemoveRoot(rt, &junk->closure);
 184        JS_free(cx, junk);
 185    }
 186    return JS_TRUE;
 187}
 188
 189JS_PUBLIC_API(JSOp)
 190JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
 191{
 192    JSRuntime *rt;
 193    JSTrap *trap;
 194    JSOp op;
 195
 196    rt = cx->runtime;
 197    DBG_LOCK(rt);
 198    trap = FindTrap(rt, script, pc);
 199    op = trap ? trap->op : (JSOp) *pc;
 200    DBG_UNLOCK(rt);
 201    return op;
 202}
 203
 204static void
 205DestroyTrapAndUnlock(JSContext *cx, JSTrap *trap)
 206{
 207    ++cx->runtime->debuggerMutations;
 208    JS_REMOVE_LINK(&trap->links);
 209    *trap->pc = (jsbytecode)trap->op;
 210    DBG_UNLOCK(cx->runtime);
 211
 212    js_RemoveRoot(cx->runtime, &trap->closure);
 213    JS_free(cx, trap);
 214}
 215
 216JS_PUBLIC_API(void)
 217JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
 218             JSTrapHandler *handlerp, void **closurep)
 219{
 220    JSTrap *trap;
 221
 222    DBG_LOCK(cx->runtime);
 223    trap = FindTrap(cx->runtime, script, pc);
 224    if (handlerp)
 225        *handlerp = trap ? trap->handler : NULL;
 226    if (closurep)
 227        *closurep = trap ? trap->closure : NULL;
 228    if (trap)
 229        DestroyTrapAndUnlock(cx, trap);
 230    else
 231        DBG_UNLOCK(cx->runtime);
 232}
 233
 234JS_PUBLIC_API(void)
 235JS_ClearScriptTraps(JSContext *cx, JSScript *script)
 236{
 237    JSRuntime *rt;
 238    JSTrap *trap, *next;
 239    uint32 sample;
 240
 241    rt = cx->runtime;
 242    DBG_LOCK(rt);
 243    for (trap = (JSTrap *)rt->trapList.next;
 244         &trap->links != &rt->trapList;
 245         trap = next) {
 246        next = (JSTrap *)trap->links.next;
 247        if (trap->script == script) {
 248            sample = rt->debuggerMutations;
 249            DestroyTrapAndUnlock(cx, trap);
 250            DBG_LOCK(rt);
 251            if (rt->debuggerMutations != sample + 1)
 252                next = (JSTrap *)rt->trapList.next;
 253        }
 254    }
 255    DBG_UNLOCK(rt);
 256}
 257
 258JS_PUBLIC_API(void)
 259JS_ClearAllTraps(JSContext *cx)
 260{
 261    JSRuntime *rt;
 262    JSTrap *trap, *next;
 263    uint32 sample;
 264
 265    rt = cx->runtime;
 266    DBG_LOCK(rt);
 267    for (trap = (JSTrap *)rt->trapList.next;
 268         &trap->links != &rt->trapList;
 269         trap = next) {
 270        next = (JSTrap *)trap->links.next;
 271        sample = rt->debuggerMutations;
 272        DestroyTrapAndUnlock(cx, trap);
 273        DBG_LOCK(rt);
 274        if (rt->debuggerMutations != sample + 1)
 275            next = (JSTrap *)rt->trapList.next;
 276    }
 277    DBG_UNLOCK(rt);
 278}
 279
 280JS_PUBLIC_API(JSTrapStatus)
 281JS_HandleTrap(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval)
 282{
 283    JSTrap *trap;
 284    jsint op;
 285    JSTrapStatus status;
 286
 287    DBG_LOCK(cx->runtime);
 288    trap = FindTrap(cx->runtime, script, pc);
 289    JS_ASSERT(!trap || trap->handler);
 290    if (!trap) {
 291        op = (JSOp) *pc;
 292        DBG_UNLOCK(cx->runtime);
 293
 294        /* Defend against "pc for wrong script" API usage error. */
 295        JS_ASSERT(op != JSOP_TRAP);
 296
 297#ifdef JS_THREADSAFE
 298        /* If the API was abused, we must fail for want of the real op. */
 299        if (op == JSOP_TRAP)
 300            return JSTRAP_ERROR;
 301
 302        /* Assume a race with a debugger thread and try to carry on. */
 303        *rval = INT_TO_JSVAL(op);
 304        return JSTRAP_CONTINUE;
 305#else
 306        /* Always fail if single-threaded (must be an API usage error). */
 307        return JSTRAP_ERROR;
 308#endif
 309    }
 310    DBG_UNLOCK(cx->runtime);
 311
 312    /*
 313     * It's important that we not use 'trap->' after calling the callback --
 314     * the callback might remove the trap!
 315     */
 316    op = (jsint)trap->op;
 317    status = trap->handler(cx, script, pc, rval, trap->closure);
 318    if (status == JSTRAP_CONTINUE) {
 319        /* By convention, return the true op to the interpreter in rval. */
 320        *rval = INT_TO_JSVAL(op);
 321    }
 322    return status;
 323}
 324
 325JS_PUBLIC_API(JSBool)
 326JS_SetInterrupt(JSRuntime *rt, JSTrapHandler handler, void *closure)
 327{
 328    rt->globalDebugHooks.interruptHandler = handler;
 329    rt->globalDebugHooks.interruptHandlerData = closure;
 330    return JS_TRUE;
 331}
 332
 333JS_PUBLIC_API(JSBool)
 334JS_ClearInterrupt(JSRuntime *rt, JSTrapHandler *handlerp, void **closurep)
 335{
 336    if (handlerp)
 337        *handlerp = (JSTrapHandler)rt->globalDebugHooks.interruptHandler;
 338    if (closurep)
 339        *closurep = rt->globalDebugHooks.interruptHandlerData;
 340    rt->globalDebugHooks.interruptHandler = 0;
 341    rt->globalDebugHooks.interruptHandlerData = 0;
 342    return JS_TRUE;
 343}
 344
 345/************************************************************************/
 346
 347typedef struct JSWatchPoint {
 348    JSCList             links;
 349    JSObject            *object;        /* weak link, see js_FinalizeObject */
 350    JSScopeProperty     *sprop;
 351    JSPropertyOp        setter;
 352    JSWatchPointHandler handler;
 353    void                *closure;
 354    uintN               flags;
 355} JSWatchPoint;
 356
 357#define JSWP_LIVE       0x1             /* live because set and not cleared */
 358#define JSWP_HELD       0x2             /* held while running handler/setter */
 359
 360/*
 361 * NB: DropWatchPointAndUnlock releases cx->runtime->debuggerLock in all cases.
 362 */
 363static JSBool
 364DropWatchPointAndUnlock(JSContext *cx, JSWatchPoint *wp, uintN flag)
 365{
 366    JSBool ok, found;
 367    JSScopeProperty *sprop;
 368    JSScope *scope;
 369    JSPropertyOp setter;
 370
 371    ok = JS_TRUE;
 372    wp->flags &= ~flag;
 373    if (wp->flags != 0) {
 374        DBG_UNLOCK(cx->runtime);
 375        return ok;
 376    }
 377
 378    /*
 379     * Remove wp from the list, then if there are no other watchpoints for
 380     * wp->sprop in any scope, restore wp->sprop->setter from wp.
 381     */
 382    ++cx->runtime->debuggerMutations;
 383    JS_REMOVE_LINK(&wp->links);
 384    sprop = wp->sprop;
 385
 386    /*
 387     * Passing null for the scope parameter tells js_GetWatchedSetter to find
 388     * any watch point for sprop, and not to lock or unlock rt->debuggerLock.
 389     * If js_ChangeNativePropertyAttrs fails, propagate failure after removing
 390     * wp->closure's root and freeing wp.
 391     */
 392    setter = js_GetWatchedSetter(cx->runtime, NULL, sprop);
 393    DBG_UNLOCK(cx->runtime);
 394    if (!setter) {
 395        JS_LOCK_OBJ(cx, wp->object);
 396        scope = OBJ_SCOPE(wp->object);
 397        found = (scope->object == wp->object &&
 398                 SCOPE_GET_PROPERTY(scope, sprop->id));
 399        JS_UNLOCK_SCOPE(cx, scope);
 400
 401        /*
 402         * If the property wasn't found on wp->object or didn't exist, then
 403         * someone else has dealt with this sprop, and we don't need to change
 404         * the property attributes.
 405         */
 406        if (found) {
 407            sprop = js_ChangeScopePropertyAttrs(cx, scope, sprop,
 408                                                0, sprop->attrs,
 409                                                sprop->getter,
 410                                                wp->setter);
 411            if (!sprop)
 412                ok = JS_FALSE;
 413        }
 414    }
 415
 416    JS_free(cx, wp);
 417    return ok;
 418}
 419
 420/*
 421 * NB: js_TraceWatchPoints does not acquire cx->runtime->debuggerLock, since
 422 * the debugger should never be racing with the GC (i.e., the debugger must
 423 * respect the request model).
 424 */
 425void
 426js_TraceWatchPoints(JSTracer *trc, JSObject *obj)
 427{
 428    JSRuntime *rt;
 429    JSWatchPoint *wp;
 430
 431    rt = trc->context->runtime;
 432
 433    for (wp = (JSWatchPoint *)rt->watchPointList.next;
 434         &wp->links != &rt->watchPointList;
 435         wp = (JSWatchPoint *)wp->links.next) {
 436        if (wp->object == obj) {
 437            TRACE_SCOPE_PROPERTY(trc, wp->sprop);
 438            if ((wp->sprop->attrs & JSPROP_SETTER) && wp->setter) {
 439                JS_CALL_OBJECT_TRACER(trc, (JSObject *)wp->setter,
 440                                      "wp->setter");
 441            }
 442            JS_SET_TRACING_NAME(trc, "wp->closure");
 443            js_CallValueTracerIfGCThing(trc, (jsval) wp->closure);
 444        }
 445    }
 446}
 447
 448void
 449js_SweepWatchPoints(JSContext *cx)
 450{
 451    JSRuntime *rt;
 452    JSWatchPoint *wp, *next;
 453    uint32 sample;
 454
 455    rt = cx->runtime;
 456    DBG_LOCK(rt);
 457    for (wp = (JSWatchPoint *)rt->watchPointList.next;
 458         &wp->links != &rt->watchPointList;
 459         wp = next) {
 460        next = (JSWatchPoint *)wp->links.next;
 461        if (js_IsAboutToBeFinalized(cx, wp->object)) {
 462            sample = rt->debuggerMutations;
 463
 464            /* Ignore failures. */
 465            DropWatchPointAndUnlock(cx, wp, JSWP_LIVE);
 466            DBG_LOCK(rt);
 467            if (rt->debuggerMutations != sample + 1)
 468                next = (JSWatchPoint *)rt->watchPointList.next;
 469        }
 470    }
 471    DBG_UNLOCK(rt);
 472}
 473
 474
 475
 476/*
 477 * NB: FindWatchPoint must be called with rt->debuggerLock acquired.
 478 */
 479static JSWatchPoint *
 480FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id)
 481{
 482    JSWatchPoint *wp;
 483
 484    for (wp = (JSWatchPoint *)rt->watchPointList.next;
 485         &wp->links != &rt->watchPointList;
 486         wp = (JSWatchPoint *)wp->links.next) {
 487        if (wp->object == scope->object && wp->sprop->id == id)
 488            return wp;
 489    }
 490    return NULL;
 491}
 492
 493JSScopeProperty *
 494js_FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id)
 495{
 496    JSWatchPoint *wp;
 497    JSScopeProperty *sprop;
 498
 499    DBG_LOCK(rt);
 500    wp = FindWatchPoint(rt, scope, id);
 501    sprop = wp ? wp->sprop : NULL;
 502    DBG_UNLOCK(rt);
 503    return sprop;
 504}
 505
 506/*
 507 * Secret handshake with DropWatchPointAndUnlock: if (!scope), we know our
 508 * caller has acquired rt->debuggerLock, so we don't have to.
 509 */
 510JSPropertyOp
 511js_GetWatchedSetter(JSRuntime *rt, JSScope *scope,
 512                    const JSScopeProperty *sprop)
 513{
 514    JSPropertyOp setter;
 515    JSWatchPoint *wp;
 516
 517    setter = NULL;
 518    if (scope)
 519        DBG_LOCK(rt);
 520    for (wp = (JSWatchPoint *)rt->watchPointList.next;
 521         &wp->links != &rt->watchPointList;
 522         wp = (JSWatchPoint *)wp->links.next) {
 523        if ((!scope || wp->object == scope->object) && wp->sprop == sprop) {
 524            setter = wp->setter;
 525            break;
 526        }
 527    }
 528    if (scope)
 529        DBG_UNLOCK(rt);
 530    return setter;
 531}
 532
 533JSBool
 534js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 535{
 536    JSRuntime *rt;
 537    JSWatchPoint *wp;
 538    JSScopeProperty *sprop;
 539    jsval propid, userid;
 540    JSScope *scope;
 541    JSBool ok;
 542
 543    rt = cx->runtime;
 544    DBG_LOCK(rt);
 545    for (wp = (JSWatchPoint *)rt->watchPointList.next;
 546         &wp->links != &rt->watchPointList;
 547         wp = (JSWatchPoint *)wp->links.next) {
 548        sprop = wp->sprop;
 549        if (wp->object == obj && SPROP_USERID(sprop) == id &&
 550            !(wp->flags & JSWP_HELD)) {
 551            wp->flags |= JSWP_HELD;
 552            DBG_UNLOCK(rt);
 553
 554            JS_LOCK_OBJ(cx, obj);
 555            propid = ID_TO_VALUE(sprop->id);
 556            userid = (sprop->flags & SPROP_HAS_SHORTID)
 557                     ? INT_TO_JSVAL(sprop->shortid)
 558                     : propid;
 559            scope = OBJ_SCOPE(obj);
 560            JS_UNLOCK_OBJ(cx, obj);
 561
 562            /* NB: wp is held, so we can safely dereference it still. */
 563            ok = wp->handler(cx, obj, propid,
 564                             SPROP_HAS_VALID_SLOT(sprop, scope)
 565                             ? OBJ_GET_SLOT(cx, obj, sprop->slot)
 566                             : JSVAL_VOID,
 567                             vp, wp->closure);
 568            if (ok) {
 569                /*
 570                 * Create a pseudo-frame for the setter invocation so that any
 571                 * stack-walking security code under the setter will correctly
 572                 * identify the guilty party.  So that the watcher appears to
 573                 * be active to obj_eval and other such code, point frame.pc
 574                 * at the JSOP_STOP at the end of the script.
 575                 *
 576                 * The pseudo-frame is not created for fast natives as they
 577                 * are treated as interpreter frame extensions and always
 578                 * trusted.
 579                 */
 580                JSObject *closure;
 581                JSClass *clasp;
 582                JSFunction *fun;
 583                JSScript *script;
 584                JSBool injectFrame;
 585                uintN nslots;
 586                jsval smallv[5];
 587                jsval *argv;
 588                JSStackFrame frame;
 589                JSFrameRegs regs;
 590
 591                closure = (JSObject *) wp->closure;
 592                clasp = OBJ_GET_CLASS(cx, closure);
 593                if (clasp == &js_FunctionClass) {
 594                    fun = GET_FUNCTION_PRIVATE(cx, closure);
 595                    script = FUN_SCRIPT(fun);
 596                } else if (clasp == &js_ScriptClass) {
 597                    fun = NULL;
 598                    script = (JSScript *) JS_GetPrivate(cx, closure);
 599                } else {
 600                    fun = NULL;
 601                    script = NULL;
 602                }
 603
 604                nslots = 2;
 605                injectFrame = JS_TRUE;
 606                if (fun) {
 607                    nslots += FUN_MINARGS(fun);
 608                    if (!FUN_INTERPRETED(fun)) {
 609                        nslots += fun->u.n.extra;
 610                        injectFrame = !(fun->flags & JSFUN_FAST_NATIVE);
 611                    }
 612                }
 613
 614                if (injectFrame) {
 615                    if (nslots <= JS_ARRAY_LENGTH(smallv)) {
 616                        argv = smallv;
 617                    } else {
 618                        argv = (jsval *) JS_malloc(cx, nslots * sizeof(jsval));
 619                        if (!argv) {
 620                            DBG_LOCK(rt);
 621                            DropWatchPointAndUnlock(cx, wp, JSWP_HELD);
 622                            return JS_FALSE;
 623                        }
 624                    }
 625
 626                    argv[0] = OBJECT_TO_JSVAL(closure);
 627                    argv[1] = JSVAL_NULL;
 628                    memset(argv + 2, 0, (nslots - 2) * sizeof(jsval));
 629
 630                    memset(&frame, 0, sizeof(frame));
 631                    frame.script = script;
 632                    frame.regs = NULL;
 633                    if (script) {
 634                        JS_ASSERT(script->length >= JSOP_STOP_LENGTH);
 635                        regs.pc = script->code + script->length
 636                                  - JSOP_STOP_LENGTH;
 637                        regs.sp = NULL;
 638                        frame.regs = &regs;
 639                    }
 640                    frame.callee = closure;
 641                    frame.fun = fun;
 642                    frame.argv = argv + 2;
 643                    frame.down = cx->fp;
 644                    frame.scopeChain = OBJ_GET_PARENT(cx, closure);
 645
 646                    cx->fp = &frame;
 647                }
 648#ifdef __GNUC__
 649                else
 650                    argv = NULL;    /* suppress bogus gcc warnings */
 651#endif
 652                ok = !wp->setter ||
 653                     ((sprop->attrs & JSPROP_SETTER)
 654                      ? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(wp->setter),
 655                                        1, vp, vp)
 656                      : wp->setter(cx, OBJ_THIS_OBJECT(cx, obj), userid, vp));
 657                if (injectFrame) {
 658                    /* Evil code can cause us to have an arguments object. */
 659                    if (frame.callobj)
 660                        ok &= js_PutCallObject(cx, &frame);
 661                    if (frame.argsobj)
 662                        ok &= js_PutArgsObject(cx, &frame);
 663
 664                    cx->fp = frame.down;
 665                    if (argv != smallv)
 666                        JS_free(cx, argv);
 667                }
 668            }
 669            DBG_LOCK(rt);
 670            return DropWatchPointAndUnlock(cx, wp, JSWP_HELD) && ok;
 671        }
 672    }
 673    DBG_UNLOCK(rt);
 674    return JS_TRUE;
 675}
 676
 677JSBool
 678js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 679                     jsval *rval)
 680{
 681    JSObject *funobj;
 682    JSFunction *wrapper;
 683    jsval userid;
 684
 685    funobj = JSVAL_TO_OBJECT(argv[-2]);
 686    JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass);
 687    wrapper = GET_FUNCTION_PRIVATE(cx, funobj);
 688    userid = ATOM_KEY(wrapper->atom);
 689    *rval = argv[0];
 690    return js_watch_set(cx, obj, userid, rval);
 691}
 692
 693JSPropertyOp
 694js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter)
 695{
 696    JSAtom *atom;
 697    JSFunction *wrapper;
 698
 699    if (!(attrs & JSPROP_SETTER))
 700        return &js_watch_set;   /* & to silence schoolmarmish MSVC */
 701
 702    if (JSID_IS_ATOM(id)) {
 703        atom = JSID_TO_ATOM(id);
 704    } else if (JSID_IS_INT(id)) {
 705        if (!js_ValueToStringId(cx, INT_JSID_TO_JSVAL(id), &id))
 706            return NULL;
 707        atom = JSID_TO_ATOM(id);
 708    } else {
 709        atom = NULL;
 710    }
 711    wrapper = js_NewFunction(cx, NULL, js_watch_set_wrapper, 1, 0,
 712                             OBJ_GET_PARENT(cx, (JSObject *)setter),
 713                             atom);
 714    if (!wrapper)
 715        return NULL;
 716    return (JSPropertyOp) FUN_OBJECT(wrapper);
 717}
 718
 719JS_PUBLIC_API(JSBool)
 720JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval idval,
 721                 JSWatchPointHandler handler, void *closure)
 722{
 723    jsid propid;
 724    JSObject *pobj;
 725    JSProperty *prop;
 726    JSScopeProperty *sprop;
 727    JSRuntime *rt;
 728    JSBool ok;
 729    JSWatchPoint *wp;
 730    JSPropertyOp watcher;
 731
 732    if (!OBJ_IS_NATIVE(obj)) {
 733        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH,
 734                             OBJ_GET_CLASS(cx, obj)->name);
 735        return JS_FALSE;
 736    }
 737
 738    if (JSVAL_IS_INT(idval))
 739        propid = INT_JSVAL_TO_JSID(idval);
 740    else if (!js_ValueToStringId(cx, idval, &propid))
 741        return JS_FALSE;
 742
 743    if (!js_LookupProperty(cx, obj, propid, &pobj, &prop))
 744        return JS_FALSE;
 745    sprop = (JSScopeProperty *) prop;
 746    rt = cx->runtime;
 747    if (!sprop) {
 748        /* Check for a deleted symbol watchpoint, which holds its property. */
 749        sprop = js_FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
 750        if (!sprop) {
 751            /* Make a new property in obj so we can watch for the first set. */
 752            if (!js_DefineProperty(cx, obj, propid, JSVAL_VOID,
 753                                   NULL, NULL, JSPROP_ENUMERATE,
 754                                   &prop)) {
 755                return JS_FALSE;
 756            }
 757            sprop = (JSScopeProperty *) prop;
 758        }
 759    } else if (pobj != obj) {
 760        /* Clone the prototype property so we can watch the right object. */
 761        jsval value;
 762        JSPropertyOp getter, setter;
 763        uintN attrs, flags;
 764        intN shortid;
 765
 766        if (OBJ_IS_NATIVE(pobj)) {
 767            value = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))
 768                    ? LOCKED_OBJ_GET_SLOT(pobj, sprop->slot)
 769                    : JSVAL_VOID;
 770            getter = sprop->getter;
 771            setter = sprop->setter;
 772            attrs = sprop->attrs;
 773            flags = sprop->flags;
 774            shortid = sprop->shortid;
 775        } else {
 776            if (!OBJ_GET_PROPERTY(cx, pobj, propid, &value) ||
 777                !OBJ_GET_ATTRIBUTES(cx, pobj, propid, prop, &attrs)) {
 778                OBJ_DROP_PROPERTY(cx, pobj, prop);
 779                return JS_FALSE;
 780            }
 781            getter = setter = NULL;
 782            flags = 0;
 783            shortid = 0;
 784        }
 785        OBJ_DROP_PROPERTY(cx, pobj, prop);
 786
 787        /* Recall that obj is native, whether or not pobj is native. */
 788        if (!js_DefineNativeProperty(cx, obj, propid, value, getter, setter,
 789                                     attrs, flags, shortid, &prop)) {
 790            return JS_FALSE;
 791        }
 792        sprop = (JSScopeProperty *) prop;
 793    }
 794
 795    /*
 796     * At this point, prop/sprop exists in obj, obj is locked, and we must
 797     * OBJ_DROP_PROPERTY(cx, obj, prop) before returning.
 798     */
 799    ok = JS_TRUE;
 800    DBG_LOCK(rt);
 801    wp = FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
 802    if (!wp) {
 803        DBG_UNLOCK(rt);
 804        watcher = js_WrapWatchedSetter(cx, propid, sprop->attrs, sprop->setter);
 805        if (!watcher) {
 806            ok = JS_FALSE;
 807            goto out;
 808        }
 809
 810        wp = (JSWatchPoint *) JS_malloc(cx, sizeof *wp);
 811        if (!wp) {
 812            ok = JS_FALSE;
 813            goto out;
 814        }
 815        wp->handler = NULL;
 816        wp->closure = NULL;
 817        wp->object = obj;
 818        JS_ASSERT(sprop->setter != js_watch_set || pobj != obj);
 819        wp->setter = sprop->setter;
 820        wp->flags = JSWP_LIVE;
 821
 822        /* XXXbe nest in obj lock here */
 823        sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop, 0, sprop->attrs,
 824                                             sprop->getter, watcher);
 825        if (!sprop) {
 826            /* Self-link so DropWatchPointAndUnlock can JS_REMOVE_LINK it. */
 827            JS_INIT_CLIST(&wp->links);
 828            DBG_LOCK(rt);
 829            DropWatchPointAndUnlock(cx, wp, JSWP_LIVE);
 830            ok = JS_FALSE;
 831            goto out;
 832        }
 833        wp->sprop = sprop;
 834
 835        /*
 836         * Now that wp is fully initialized, append it to rt's wp list.
 837         * Because obj is locked we know that no other thread could have added
 838         * a watchpoint for (obj, propid).
 839         */
 840        DBG_LOCK(rt);
 841        JS_ASSERT(!FindWatchPoint(rt, OBJ_SCOPE(obj), propid));
 842        JS_APPEND_LINK(&wp->links, &rt->watchPointList);
 843        ++rt->debuggerMutations;
 844    }
 845    wp->handler = handler;
 846    wp->closure = closure;
 847    DBG_UNLOCK(rt);
 848
 849out:
 850    OBJ_DROP_PROPERTY(cx, obj, prop);
 851    return ok;
 852}
 853
 854JS_PUBLIC_API(JSBool)
 855JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsval id,
 856                   JSWatchPointHandler *handlerp, void **closurep)
 857{
 858    JSRuntime *rt;
 859    JSWatchPoint *wp;
 860
 861    rt = cx->runtime;
 862    DBG_LOCK(rt);
 863    for (wp = (JSWatchPoint *)rt->watchPointList.next;
 864         &wp->links != &rt->watchPointList;
 865         wp = (JSWatchPoint *)wp->links.next) {
 866        if (wp->object == obj && SPROP_USERID(wp->sprop) == id) {
 867            if (handlerp)
 868                *handlerp = wp->handler;
 869            if (closurep)
 870                *closurep = wp->closure;
 871            return DropWatchPointAndUnlock(cx, wp, JSWP_LIVE);
 872        }
 873    }
 874    DBG_UNLOCK(rt);
 875    if (handlerp)
 876        *handlerp = NULL;
 877    if (closurep)
 878        *closurep = NULL;
 879    return JS_TRUE;
 880}
 881
 882JS_PUBLIC_API(JSBool)
 883JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj)
 884{
 885    JSRuntime *rt;
 886    JSWatchPoint *wp, *next;
 887    uint32 sample;
 888
 889    rt = cx->runtime;
 890    DBG_LOCK(rt);
 891    for (wp = (JSWatchPoint *)rt->watchPointList.next;
 892         &wp->links != &rt->watchPointList;
 893         wp = next) {
 894        next = (JSWatchPoint *)wp->links.next;
 895        if (wp->object == obj) {
 896            sample = rt->debuggerMutations;
 897            if (!DropWatchPointAndUnlock(cx, wp, JSWP_LIVE))
 898                return JS_FALSE;
 899            DBG_LOCK(rt);
 900            if (rt->debuggerMutations != sample + 1)
 901                next = (JSWatchPoint *)rt->watchPointList.next;
 902        }
 903    }
 904    DBG_UNLOCK(rt);
 905    return JS_TRUE;
 906}
 907
 908JS_PUBLIC_API(JSBool)
 909JS_ClearAllWatchPoints(JSContext *cx)
 910{
 911    JSRuntime *rt;
 912    JSWatchPoint *wp, *next;
 913    uint32 sample;
 914
 915    rt = cx->runtime;
 916    DBG_LOCK(rt);
 917    for (wp = (JSWatchPoint *)rt->watchPointList.next;
 918         &wp->links != &rt->watchPointList;
 919         wp = next) {
 920        next = (JSWatchPoint *)wp->links.next;
 921        sample = rt->debuggerMutations;
 922        if (!DropWatchPointAndUnlock(cx, wp, JSWP_LIVE))
 923            return JS_FALSE;
 924        DBG_LOCK(rt);
 925        if (rt->debuggerMutations != sample + 1)
 926            next = (JSWatchPoint *)rt->watchPointList.next;
 927    }
 928    DBG_UNLOCK(rt);
 929    return JS_TRUE;
 930}
 931
 932/************************************************************************/
 933
 934JS_PUBLIC_API(uintN)
 935JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
 936{
 937    return js_PCToLineNumber(cx, script, pc);
 938}
 939
 940JS_PUBLIC_API(jsbytecode *)
 941JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno)
 942{
 943    return js_LineNumberToPC(script, lineno);
 944}
 945
 946JS_PUBLIC_API(JSScript *)
 947JS_GetFunctionScript(JSContext *cx, JSFunction *fun)
 948{
 949    return FUN_SCRIPT(fun);
 950}
 951
 952JS_PUBLIC_API(JSNative)
 953JS_GetFunctionNative(JSContext *cx, JSFunction *fun)
 954{
 955    return FUN_NATIVE(fun);
 956}
 957
 958JS_PUBLIC_API(JSFastNative)
 959JS_GetFunctionFastNative(JSContext *cx, JSFunction *fun)
 960{
 961    return FUN_FAST_NATIVE(fun);
 962}
 963
 964JS_PUBLIC_API(JSPrincipals *)
 965JS_GetScriptPrincipals(JSContext *cx, JSScript *script)
 966{
 967    return script->principals;
 968}
 969
 970/************************************************************************/
 971
 972/*
 973 *  Stack Frame Iterator
 974 */
 975JS_PUBLIC_API(JSStackFrame *)
 976JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
 977{
 978    *iteratorp = (*iteratorp == NULL) ? cx->fp : (*iteratorp)->down;
 979    return *iteratorp;
 980}
 981
 982JS_PUBLIC_API(JSScript *)
 983JS_GetFrameScript(JSContext *cx, JSStackFrame *fp)
 984{
 985    return fp->script;
 986}
 987
 988JS_PUBLIC_API(jsbytecode *)
 989JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
 990{
 991    return fp->regs ? fp->regs->pc : NULL;
 992}
 993
 994JS_PUBLIC_API(JSStackFrame *)
 995JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
 996{
 997    if (!fp)
 998        fp = cx->fp;
 999    while (fp) {
1000        if (fp->script)
1001            return fp;
1002        fp = fp->down;
1003    }
1004    return NULL;
1005}
1006
1007JS_PUBLIC_API(JSPrincipals *)
1008JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp)
1009{
1010    JSSecurityCallbacks *callbacks;
1011
1012    if (fp->fun) {
1013        callbacks = JS_GetSecurityCallbacks(cx);
1014        if (callbacks && callbacks->findObjectPrincipals) {
1015            if (FUN_OBJECT(fp->fun) != fp->callee)
1016                return callbacks->findObjectPrincipals(cx, fp->callee);
1017            /* FALL THROUGH */
1018        }
1019    }
1020    if (fp->script)
1021        return fp->script->principals;
1022    return NULL;
1023}
1024
1025JS_PUBLIC_API(JSPrincipals *)
1026JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller)
1027{
1028    JSPrincipals *principals, *callerPrincipals;
1029    JSSecurityCallbacks *callbacks;
1030
1031    callbacks = JS_GetSecurityCallbacks(cx);
1032    if (callbacks && callbacks->findObjectPrincipals) {
1033        principals = callbacks->findObjectPrincipals(cx, fp->callee);
1034    } else {
1035        principals = NULL;
1036    }
1037    if (!caller)
1038        return principals;
1039    callerPrincipals = JS_StackFramePrincipals(cx, caller);
1040    return (callerPrincipals && principals &&
1041            callerPrincipals->subsume(callerPrincipals, principals))
1042           ? principals
1043           : callerPrincipals;
1044}
1045
1046JS_PUBLIC_API(void *)
1047JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
1048{
1049    if (fp->annotation && fp->script) {
1050        JSPrincipals *principals = JS_StackFramePrincipals(cx, fp);
1051
1052        if (principals && principals->globalPrivilegesEnabled(cx, principals)) {
1053            /*
1054             * Give out an annotation only if privileges have not been revoked
1055             * or disabled globally.
1056             */
1057            return fp->annotation;
1058        }
1059    }
1060
1061    return NULL;
1062}
1063
1064JS_PUBLIC_API(void)
1065JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation)
1066{
1067    fp->annotation = annotation;
1068}
1069
1070JS_PUBLIC_API(void *)
1071JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp)
1072{
1073    JSPrincipals *principals;
1074
1075    principals = JS_StackFramePrincipals(cx, fp);
1076    if (!principals)
1077        return NULL;
1078    return principals->getPrincipalArray(cx, principals);
1079}
1080
1081JS_PUBLIC_API(JSBool)
1082JS_IsNativeFrame(JSContext *cx, JSStackFrame *fp)
1083{
1084    return !fp->script;
1085}
1086
1087/* this is deprecated, use JS_GetFrameScopeChain instead */
1088JS_PUBLIC_API(JSObject *)
1089JS_GetFrameObject(JSContext *cx, JSStackFrame *fp)
1090{
1091    return fp->scopeChain;
1092}
1093
1094JS_PUBLIC_API(JSObject *)
1095JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp)
1096{
1097    /* Force creation of argument and call objects if not yet created */
1098    (void) JS_GetFrameCallObject(cx, fp);
1099    return js_GetScopeChain(cx, fp);
1100}
1101
1102JS_PUBLIC_API(JSObject *)
1103JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp)
1104{
1105    if (! fp->fun)
1106        return NULL;
1107
1108    /* Force creation of argument object if not yet created */
1109    (void) js_GetArgsObject(cx, fp);
1110
1111    /*
1112     * XXX ill-defined: null return here means error was reported, unlike a
1113     *     null returned above or in the #else
1114     */
1115    return js_GetCallObject(cx, fp, NULL);
1116}
1117
1118JS_PUBLIC_API(JSObject *)
1119JS_GetFrameThis(JSContext *cx, JSStackFrame *fp)
1120{
1121    JSStackFrame *afp;
1122
1123    if (fp->flags & JSFRAME_COMPUTED_THIS)
1124        return fp->thisp;
1125
1126    /* js_ComputeThis gets confused if fp != cx->fp, so set it aside. */
1127    if (cx->fp != fp) {
1128        afp = cx->fp;
1129        if (afp) {
1130            afp->dormantNext = cx->dormantFrameChain;
1131            cx->dormantFrameChain = afp;
1132            cx->fp = fp;
1133        }
1134    } else {
1135        afp = NULL;
1136    }
1137
1138    if (!fp->thisp && fp->argv)
1139        fp->thisp = js_ComputeThis(cx, JS_TRUE, fp->argv);
1140
1141    if (afp) {
1142        cx->fp = afp;
1143        cx->dormantFrameChain = afp->dormantNext;
1144        afp->dormantNext = NULL;
1145    }
1146
1147    return fp->thisp;
1148}
1149
1150JS_PUBLIC_API(JSFunction *)
1151JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
1152{
1153    return fp->fun;
1154}
1155
1156JS_PUBLIC_API(JSObject *)
1157JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp)
1158{
1159    if (!fp->fun)
1160        return NULL;
1161
1162    JS_ASSERT(OBJ_GET_CLASS(cx, fp->callee) == &js_FunctionClass);
1163    JS_ASSERT(OBJ_GET_PRIVATE(cx, fp->callee) == fp->fun);
1164    return fp->callee;
1165}
1166
1167JS_PUBLIC_API(JSBool)
1168JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp)
1169{
1170    return (fp->flags & JSFRAME_CONSTRUCTING) != 0;
1171}
1172
1173JS_PUBLIC_API(JSObject *)
1174JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp)
1175{
1176    return fp->callee;
1177}
1178
1179JS_PUBLIC_API(JSBool)
1180JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp)
1181{
1182    return (fp->flags & JSFRAME_DEBUGGER) != 0;
1183}
1184
1185JS_PUBLIC_API(jsval)
1186JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp)
1187{
1188    return fp->rval;
1189}
1190
1191JS_PUBLIC_API(void)
1192JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval)
1193{
1194    fp->rval = rval;
1195}
1196
1197/************************************************************************/
1198
1199JS_PUBLIC_API(const char *)
1200JS_GetScriptFilename(JSContext *cx, JSScript *script)
1201{
1202    return script->filename;
1203}
1204
1205JS_PUBLIC_API(uintN)
1206JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script)
1207{
1208    return script->lineno;
1209}
1210
1211JS_PUBLIC_API(uintN)
1212JS_GetScriptLineExtent(JSContext *cx, JSScript *script)
1213{
1214    return js_GetScriptLineExtent(script);
1215}
1216
1217JS_PUBLIC_API(JSVersion)
1218JS_GetScriptVersion(JSContext *cx, JSScript *script)
1219{
1220    return (JSVersion) (script->version & JSVERSION_MASK);
1221}
1222
1223/***************************************************************************/
1224
1225JS_PUBLIC_API(void)
1226JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata)
1227{
1228    rt->globalDebugHooks.newScriptHook = hook;
1229    rt->globalDebugHooks.newScriptHookData = callerdata;
1230}
1231
1232JS_PUBLIC_API(void)
1233JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook,
1234                        void *callerdata)
1235{
1236    rt->globalDebugHooks.destroyScriptHook = hook;
1237    rt->globalDebugHooks.destroyScriptHookData = callerdata;
1238}
1239
1240/***************************************************************************/
1241
1242JS_PUBLIC_API(JSBool)
1243JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
1244                          const jschar *chars, uintN length,
1245                          const char *filename, uintN lineno,
1246                          jsval *rval)
1247{
1248    JSObject *scobj;
1249    JSScript *script;
1250    JSBool ok;
1251
1252    scobj = JS_GetFrameScopeChain(cx, fp);
1253    if (!scobj)
1254        return JS_FALSE;
1255
1256    script = js_CompileScript(cx, scobj, fp, JS_StackFramePrincipals(cx, fp),
1257                              TCF_COMPILE_N_GO |
1258                              TCF_PUT_STATIC_DEPTH(fp->script->staticDepth + 1),
1259                              chars, length, NULL,
1260                              filename, lineno);
1261    if (!script)
1262        return JS_FALSE;
1263
1264    ok = js_Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL,
1265                    rval);
1266    js_DestroyScript(cx, script);
1267    return ok;
1268}
1269
1270JS_PUBLIC_API(JSBool)
1271JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp,
1272                        const char *bytes, uintN length,
1273                        const char *filename, uintN lineno,
1274                        jsval *rval)
1275{
1276    jschar *chars;
1277    JSBool ok;
1278    size_t len = length;
1279
1280    chars = js_InflateString(cx, bytes, &len);
1281    if (!chars)
1282        return JS_FALSE;
1283    length = (uintN) len;
1284    ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length, filename, lineno,
1285                                   rval);
1286    JS_free(cx, chars);
1287
1288    return ok;
1289}
1290
1291/************************************************************************/
1292
1293/* XXXbe this all needs to be reworked to avoid requiring JSScope types. */
1294
1295JS_PUBLIC_API(JSScopeProperty *)
1296JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp)
1297{
1298    JSScopeProperty *sprop;
1299    JSScope *scope;
1300
1301    sprop = *iteratorp;
1302    scope = OBJ_SCOPE(obj);
1303
1304    /* XXXbe minor(?) incompatibility: iterate in reverse definition order */
1305    if (!sprop) {
1306        sprop = SCOPE_LAST_PROP(scope);
1307    } else {
1308        while ((sprop = sprop->parent) != NULL) {
1309            if (!SCOPE_HAD_MIDDLE_DELETE(scope))
1310                break;
1311            if (SCOPE_HAS_PROPERTY(scope, sprop))
1312                break;
1313        }
1314    }
1315    *iteratorp = sprop;
1316    return sprop;
1317}
1318
1319JS_PUBLIC_API(JSBool)
1320JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
1321                   JSPropertyDesc *pd)
1322{
1323    JSScope *scope;
1324    JSScopeProperty *aprop;
1325    jsval lastException;
1326    JSBool wasThrowing;
1327
1328    pd->id = ID_TO_VALUE(sprop->id);
1329
1330    wasThrowing = cx->throwing;
1331    if (wasThrowing) {
1332        lastException = cx->exception;
1333        if (JSVAL_IS_GCTHING(lastException) &&
1334            !js_AddRoot(cx, &lastException, "lastException")) {
1335                return JS_FALSE;
1336        }
1337        cx->throwing = JS_FALSE;
1338    }
1339
1340    if (!js_GetProperty(cx, obj, sprop->id, &pd->value)) {
1341        if (!cx->throwing) {
1342            pd->flags = JSPD_ERROR;
1343            pd->value = JSVAL_VOID;
1344        } else {
1345            pd->flags = JSPD_EXCEPTION;
1346            pd->value = cx->exception;
1347        }
1348    } else {
1349        pd->flags = 0;
1350    }
1351
1352    cx->throwing = wasThrowing;
1353    if (wasThrowing) {
1354        cx->exception = lastException;
1355        if (JSVAL_IS_GCTHING(lastException))
1356            js_RemoveRoot(cx->runtime, &lastException);
1357    }
1358
1359    pd->flags |= ((sprop->attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0)
1360              | ((sprop->attrs & JSPROP_READONLY)  ? JSPD_READONLY  : 0)
1361              | ((sprop->attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0);
1362    pd->spare = 0;
1363    if (sprop->getter == js_GetCallArg) {
1364        pd->slot = sprop->shortid;
1365        pd->flags |= JSPD_ARGUMENT;
1366    } else if (sprop->getter == js_GetCallVar) {
1367        pd->slot = sprop->shortid;
1368        pd->flags |= JSPD_VARIABLE;
1369    } else {
1370        pd->slot = 0;
1371    }
1372    pd->alias = JSVAL_VOID;
1373    scope = OBJ_SCOPE(obj);
1374    if (SPROP_HAS_VALID_SLOT(sprop, scope)) {
1375        for (aprop = SCOPE_LAST_PROP(scope); aprop; aprop = aprop->parent) {
1376            if (aprop != sprop && aprop->slot == sprop->slot) {
1377                pd->alias = ID_TO_VALUE(aprop->id);
1378                break;
1379            }
1380        }
1381    }
1382    return JS_TRUE;
1383}
1384
1385JS_PUBLIC_API(JSBool)
1386JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda)
1387{
1388    JSClass *clasp;
1389    JSScope *scope;
1390    uint32 i, n;
1391    JSPropertyDesc *pd;
1392    JSScopeProperty *sprop;
1393
1394    clasp = OBJ_GET_CLASS(cx, obj);
1395    if (!OBJ_IS_NATIVE(obj) || (clasp->flags & JSCLASS_NEW_ENUMERATE)) {
1396        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1397                             JSMSG_CANT_DESCRIBE_PROPS, clasp->name);
1398        return JS_FALSE;
1399    }
1400    if (!clasp->enumerate(cx, obj))
1401        return JS_FALSE;
1402
1403    /* have no props, or object's scope has not mutated from that of proto */
1404    scope = OBJ_SCOPE(obj);
1405    if (scope->object != obj || scope->entryCount == 0) {
1406        pda->length = 0;
1407        pda->array = NULL;
1408        return JS_TRUE;
1409    }
1410
1411    n = STOBJ_NSLOTS(obj);
1412    if (n > scope->entryCount)
1413        n = scope->entryCount;
1414    pd = (JSPropertyDesc *) JS_malloc(cx, (size_t)n * sizeof(JSPropertyDesc));
1415    if (!pd)
1416        return JS_FALSE;
1417    i = 0;
1418    for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
1419        if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop))
1420            continue;
1421        if (!js_AddRoot(cx, &pd[i].id, NULL))
1422            goto bad;
1423        if (!js_AddRoot(cx, &pd[i].value, NULL))
1424            goto bad;
1425        if (!JS_GetPropertyDesc(cx, obj, sprop, &pd[i]))
1426            goto bad;
1427        if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL))
1428            goto bad;
1429        if (++i == n)
1430            break;
1431    }
1432    pda->length = i;
1433    pda->array = pd;
1434    return JS_TRUE;
1435
1436bad:
1437    pda->length = i + 1;
1438    pda->array = pd;
1439    JS_PutPropertyDescArray(cx, pda);
1440    return JS_FALSE;
1441}
1442
1443JS_PUBLIC_API(void)
1444JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda)
1445{
1446    JSPropertyDesc *pd;
1447    uint32 i;
1448
1449    pd = pda->array;
1450    for (i = 0; i < pda->length; i++) {
1451        js_RemoveRoot(cx->runtime, &pd[i].id);
1452        js_RemoveRoot(cx->runtime, &pd[i].value);
1453        if (pd[i].flags & JSPD_ALIAS)
1454            js_RemoveRoot(cx->runtime, &pd[i].alias);
1455    }
1456    JS_free(cx, pd);
1457}
1458
1459/************************************************************************/
1460
1461JS_PUBLIC_API(JSBool)
1462JS_SetDebuggerHandler(JSRuntime *rt, JSTrapHandler handler, void *closure)
1463{
1464    rt->globalDebugHooks.debuggerHandler = handler;
1465    rt->globalDebugHooks.debuggerHandlerData = closure;
1466    return JS_TRUE;
1467}
1468
1469JS_PUBLIC_API(JSBool)
1470JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure)
1471{
1472    rt->globalDebugHooks.sourceHandler = handler;
1473    rt->globalDebugHooks.sourceHandlerData = closure;
1474    return JS_TRUE;
1475}
1476
1477JS_PUBLIC_API(JSBool)
1478JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
1479{
1480    rt->globalDebugHooks.executeHook = hook;
1481    rt->globalDebugHooks.executeHookData = closure;
1482    return JS_TRUE;
1483}
1484
1485JS_PUBLIC_API(JSBool)
1486JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
1487{
1488    rt->globalDebugHooks.callHook = hook;
1489    rt->globalDebugHooks.callHookData = closure;
1490    return JS_TRUE;
1491}
1492
1493JS_PUBLIC_API(JSBool)
1494JS_SetObjectHook(JSRuntime *rt, JSObjectHook hook, void *closure)
1495{
1496    rt->globalDebugHooks.objectHook = hook;
1497    rt->globalDebugHooks.objectHookData = closure;
1498    return JS_TRUE;
1499}
1500
1501JS_PUBLIC_API(JSBool)
1502JS_SetThrowHook(JSRuntime *rt, JSTrapHandler hook, void *closure)
1503{
1504    rt->globalDebugHooks.throwHook = hook;
1505    rt->globalDebugHooks.throwHookData = closure;
1506    return JS_TRUE;
1507}
1508
1509JS_PUBLIC_API(JSBool)
1510JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure)
1511{
1512    rt->globalDebugHooks.debugErrorHook = hook;
1513    rt->globalDebugHooks.debugErrorHookData = closure;
1514    return JS_TRUE;
1515}
1516
1517/************************************************************************/
1518
1519JS_PUBLIC_API(size_t)
1520JS_GetObjectTotalSize(JSContext *cx, JSObject *obj)
1521{
1522    size_t nbytes;
1523    JSScope *scope;
1524
1525    nbytes = sizeof *obj;
1526    if (obj->dslots) {
1527        nbytes += ((uint32)obj->dslots[-1] - JS_INITIAL_NSLOTS + 1)
1528                  * sizeof obj->dslots[0];
1529    }
1530    if (OBJ_IS_NATIVE(obj)) {
1531        scope = OBJ_SCOPE(obj);
1532        if (scope->object == obj) {
1533            nbytes += sizeof *scope;
1534            nbytes += SCOPE_CAPACITY(scope) * sizeof(JSScopeProperty *);
1535        }
1536    }
1537    return nbytes;
1538}
1539
1540static size_t
1541GetAtomTotalSize(JSContext *cx, JSAtom *atom)
1542{
1543    size_t nbytes;
1544
1545    nbytes = sizeof(JSAtom *) + sizeof(JSDHashEntryStub);
1546    if (ATOM_IS_STRING(atom)) {
1547        nbytes += sizeof(JSString);
1548        nbytes += (JSFLATSTR_LENGTH(ATOM_TO_STRING(atom)) + 1) * sizeof(jschar);
1549    } else if (ATOM_IS_DOUBLE(atom)) {
1550        nbytes += sizeof(jsdouble);
1551    }
1552    return nbytes;
1553}
1554
1555JS_PUBLIC_API(size_t)
1556JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun)
1557{
1558    size_t nbytes;
1559
1560    nbytes = sizeof *fun;
1561    nbytes += JS_GetObjectTotalSize(cx, FUN_OBJECT(fun));
1562    if (FUN_INTERPRETED(fun))
1563        nbytes += JS_GetScriptTotalSize(cx, fun->u.i.script);
1564    if (fun->atom)
1565        nbytes += GetAtomTotalSize(cx, fun->atom);
1566    return nbytes;
1567}
1568
1569#include "jsemit.h"
1570
1571JS_PUBLIC_API(size_t)
1572JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
1573{
1574    size_t nbytes, pbytes;
1575    jsatomid i;
1576    jssrcnote *sn, *notes;
1577    JSObjectArray *objarray;
1578    JSPrincipals *principals;
1579
1580    nbytes = sizeof *script;
1581    if (script->u.object)
1582        nbytes += JS_GetObjectTotalSize(cx, script->u.object);
1583
1584    nbytes += script->length * sizeof script->code[0];
1585    nbytes += script->atomMap.length * sizeof script->atomMap.vector[0];
1586    for (i = 0; i < script->atomMap.length; i++)
1587        nbytes += GetAtomTotalSize(cx, script->atomMap.vector[i]);
1588
1589    if (script->filename)
1590        nbytes += strlen(script->filename) + 1;
1591
1592    notes = SCRIPT_NOTES(script);
1593    for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
1594        continue;
1595    nbytes += (sn - notes + 1) * sizeof *sn;
1596
1597    if (script->objectsOffset != 0) {
1598        objarray = JS_SCRIPT_OBJECTS(script);
1599        i = objarray->length;
1600        nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
1601        do {
1602            nbytes += JS_GetObjectTotalSize(cx, objarray->vector[--i]);
1603        } while (i != 0);
1604    }
1605
1606    if (script->regexpsOffset != 0) {
1607        objarray = JS_SCRIPT_REGEXPS(script);
1608        i = objarray->length;
1609        nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
1610        do {
1611            nbytes += JS_GetObjectTotalSize(cx, objarray->vector[--i]);
1612        } while (i != 0);
1613    }
1614
1615    if (script->trynotesOffset != 0) {
1616        nbytes += sizeof(JSTryNoteArray) +
1617            JS_SCRIPT_TRYNOTES(script)->length * sizeof(JSTryNote);
1618    }
1619
1620    principals = script->principals;
1621    if (principals) {
1622        JS_ASSERT(principals->refcount);
1623        pbytes = sizeof *principals;
1624        if (principals->refcount > 1)
1625            pbytes = JS_HOWMANY(pbytes, principals->refcount);
1626        nbytes += pbytes;
1627    }
1628
1629    return nbytes;
1630}
1631
1632JS_PUBLIC_API(uint32)
1633JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp)
1634{
1635    if (!fp)
1636        fp = cx->fp;
1637    while (fp) {
1638        if (fp->script)
1639            return JS_GetScriptFilenameFlags(fp->script);
1640        fp = fp->down;
1641    }
1642    return 0;
1643 }
1644
1645JS_PUBLIC_API(uint32)
1646JS_GetScriptFilenameFlags(JSScript *script)
1647{
1648    JS_ASSERT(script);
1649    if (!script->filename)
1650        return JSFILENAME_NULL;
1651    return js_GetScriptFilenameFlags(script->filename);
1652}
1653
1654JS_PUBLIC_API(JSBool)
1655JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags)
1656{
1657    if (!js_SaveScriptFilenameRT(rt, prefix, flags))
1658        return JS_FALSE;
1659    return JS_TRUE;
1660}
1661
1662JS_PUBLIC_API(JSBool)
1663JS_IsSystemObject(JSContext *cx, JSObject *obj)
1664{
1665    return STOBJ_IS_SYSTEM(obj);
1666}
1667
1668JS_PUBLIC_API(JSObject *)
1669JS_NewSystemObject(JSContext *cx, JSClass *clasp, JSObject *proto,
1670                   JSObject *parent, JSBool system)
1671{
1672    JSObject *obj;
1673
1674    obj = js_NewObject(cx, clasp, proto, parent, 0);
1675    if (obj && system)
1676        STOBJ_SET_SYSTEM(obj);
1677    return obj;
1678}
1679
1680/************************************************************************/
1681
1682JS_PUBLIC_API(JSDebugHooks *)
1683JS_GetGlobalDebugHooks(JSRuntime *rt)
1684{
1685    return &rt->globalDebugHooks;
1686}
1687
1688JS_PUBLIC_API(JSDebugHooks *)
1689JS_SetContextDebugHooks(JSContext *cx, JSDebugHooks *hooks)
1690{
1691    JSDebugHooks *old;
1692
1693    JS_ASSERT(hooks);
1694    old = cx->debugHooks;
1695    cx->debugHooks = hooks;
1696    return old;
1697}
1698
1699#ifdef MOZ_SHARK
1700
1701#include <CHUD/CHUD.h>
1702
1703JS_PUBLIC_API(JSBool)
1704JS_StartChudRemote()
1705{
1706    if (chudIsRemoteAccessAcquired() &&
1707        (chudStartRemotePerfMonitor("Mozilla") == chudSuccess)) {
1708        return JS_TRUE;
1709    }
1710
1711    return JS_FALSE;
1712}
1713
1714JS_PUBLIC_API(JSBool)
1715JS_StopChudRemote()
1716{
1717    if (chudIsRemoteAccessAcquired() &&
1718        (chudStopRemotePerfMonitor() == chudSuccess)) {
1719        return JS_TRUE;
1720    }
1721
1722    return JS_FALSE;
1723}
1724
1725JS_PUBLIC_API(JSBool)
1726JS_ConnectShark()
1727{
1728    if (!chudIsInitialized() && (chudInitialize() != chudSuccess))
1729        return JS_FALSE;
1730
1731    if (chudAcquireRemoteAccess() != chudSuccess)
1732        return JS_FALSE;
1733
1734    return JS_TRUE;
1735}
1736
1737JS_PUBLIC_API(JSBool)
1738JS_DisconnectShark()
1739{
1740    if (chudIsRemoteAccessAcquired() && (chudReleaseRemoteAccess() != chudSuccess))
1741        return JS_FALSE;
1742
1743    return JS_TRUE;
1744}
1745
1746JS_FRIEND_API(JSBool)
1747js_StartShark(JSContext *cx, JSObject *obj,
1748              uintN argc, jsval *argv, jsval *rval)
1749{
1750    if (!JS_StartChudRemote()) {
1751        JS_ReportError(cx, "Error starting CHUD.");
1752    }
1753
1754    return JS_TRUE;
1755}
1756
1757JS_FRIEND_API(JSBool)
1758js_StopShark(JSContext *cx, JSObject *obj,
1759             uintN argc, jsval *argv, jsval *rval)
1760{
1761    if (!JS_StopChudRemote()) {
1762        JS_ReportError(cx, "Error stoppiā€¦

Large files files are truncated, but you can click here to view the full file