home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / js / src / jsdbgapi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  16.8 KB  |  698 lines

  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*
  20.  * JS debugging API.
  21.  */
  22. #include <string.h>
  23. #include "prtypes.h"
  24. #include "prlog.h"
  25. #include "prclist.h"
  26. #include "jsapi.h"
  27. #include "jsdbgapi.h"
  28. #include "jsgc.h"
  29. #include "jsinterp.h"
  30. #include "jsobj.h"
  31. #include "jsopcode.h"
  32. #include "jsscope.h"
  33. #include "jsscript.h"
  34. #include "jsstr.h"
  35. #include "jscntxt.h"
  36. #include "jsfun.h"
  37.  
  38. typedef struct JSTrap {
  39.     PRCList         links;
  40.     JSScript        *script;
  41.     jsbytecode      *pc;
  42.     JSOp            op;
  43.     JSTrapHandler   handler;
  44.     void            *closure;
  45. } JSTrap;
  46.  
  47. static JSTrap *
  48. FindTrap(JSRuntime *rt, JSScript *script, jsbytecode *pc)
  49. {
  50.     JSTrap *trap;
  51.  
  52.     for (trap = (JSTrap *)rt->trapList.next;
  53.      trap != (JSTrap *)&rt->trapList;
  54.      trap = (JSTrap *)trap->links.next) {
  55.     if (trap->script == script && trap->pc == pc)
  56.         return trap;
  57.     }
  58.     return NULL;
  59. }
  60.  
  61. void
  62. js_PatchOpcode(JSContext *cx, JSScript *script, jsbytecode *pc, JSOp op)
  63. {
  64.     JSTrap *trap;
  65.  
  66.     trap = FindTrap(cx->runtime, script, pc);
  67.     if (trap)
  68.     trap->op = op;
  69.     else
  70.     *pc = (jsbytecode)op;
  71. }
  72.  
  73. PR_IMPLEMENT(JSBool)
  74. JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
  75.        JSTrapHandler handler, void *closure)
  76. {
  77.     JSRuntime *rt;
  78.     JSTrap *trap;
  79.  
  80.     rt = cx->runtime;
  81.     trap = FindTrap(rt, script, pc);
  82.     if (trap) {
  83.     /* Restore opcode at pc so it can be saved again. */
  84.     *pc = (jsbytecode)trap->op;
  85.     } else {
  86.     trap = JS_malloc(cx, sizeof *trap);
  87.     if (!trap || !js_AddRoot(cx, &trap->closure)) {
  88.         if (trap)
  89.         JS_free(cx, trap);
  90.         return JS_FALSE;
  91.     }
  92.     }
  93.     PR_APPEND_LINK(&trap->links, &rt->trapList);
  94.     trap->script = script;
  95.     trap->pc = pc;
  96.     trap->op = *pc;
  97.     trap->handler = handler;
  98.     trap->closure = closure;
  99.     *pc = JSOP_TRAP;
  100.     return JS_TRUE;
  101. }
  102.  
  103. PR_IMPLEMENT(JSOp)
  104. JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
  105. {
  106.     JSTrap *trap;
  107.  
  108.     trap = FindTrap(cx->runtime, script, pc);
  109.     if (!trap) {
  110.     PR_ASSERT(0);    /* XXX can't happen */
  111.     return JSOP_LIMIT;
  112.     }
  113.     return trap->op;
  114. }
  115.  
  116. static void
  117. DestroyTrap(JSContext *cx, JSTrap *trap)
  118. {
  119.     PR_REMOVE_LINK(&trap->links);
  120.     *trap->pc = (jsbytecode)trap->op;
  121.     js_RemoveRoot(cx, &trap->closure);
  122.     JS_free(cx, trap);
  123. }
  124.  
  125. PR_IMPLEMENT(void)
  126. JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
  127.          JSTrapHandler *handlerp, void **closurep)
  128. {
  129.     JSTrap *trap;
  130.  
  131.     trap = FindTrap(cx->runtime, script, pc);
  132.     if (handlerp)
  133.     *handlerp = trap ? trap->handler : NULL;
  134.     if (closurep)
  135.     *closurep = trap ? trap->closure : NULL;
  136.     if (trap)
  137.     DestroyTrap(cx, trap);
  138. }
  139.  
  140. PR_IMPLEMENT(void)
  141. JS_ClearScriptTraps(JSContext *cx, JSScript *script)
  142. {
  143.     JSRuntime *rt;
  144.     JSTrap *trap, *next;
  145.  
  146.     rt = cx->runtime;
  147.     for (trap = (JSTrap *)rt->trapList.next;
  148.      trap != (JSTrap *)&rt->trapList;
  149.      trap = next) {
  150.     next = (JSTrap *)trap->links.next;
  151.     if (trap->script == script)
  152.         DestroyTrap(cx, trap);
  153.     }
  154. }
  155.  
  156. PR_IMPLEMENT(void)
  157. JS_ClearAllTraps(JSContext *cx)
  158. {
  159.     JSRuntime *rt;
  160.     JSTrap *trap, *next;
  161.  
  162.     rt = cx->runtime;
  163.     for (trap = (JSTrap *)rt->trapList.next;
  164.      trap != (JSTrap *)&rt->trapList;
  165.      trap = next) {
  166.     next = (JSTrap *)trap->links.next;
  167.     DestroyTrap(cx, trap);
  168.     }
  169. }
  170.  
  171. PR_IMPLEMENT(JSTrapStatus)
  172. JS_HandleTrap(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval)
  173. {
  174.     JSTrap *trap;
  175.     JSTrapStatus status;
  176.  
  177.     trap = FindTrap(cx->runtime, script, pc);
  178.     if (!trap) {
  179.     PR_ASSERT(0);    /* XXX can't happen */
  180.     return JSTRAP_ERROR;
  181.     }
  182.     status = trap->handler(cx, script, pc, rval, trap->closure);
  183.     if (status == JSTRAP_CONTINUE) {
  184.     /* By convention, return the true op to the interpreter in rval. */
  185.     *rval = INT_TO_JSVAL((jsint)trap->op);
  186.     }
  187.     return status;
  188. }
  189.  
  190. PR_IMPLEMENT(JSBool)
  191. JS_SetInterrupt(JSRuntime *rt, JSTrapHandler handler, void *closure)
  192. {
  193.     rt->interruptHandler = handler;
  194.     rt->interruptHandlerData = closure;
  195.     return JS_TRUE;
  196. }
  197.  
  198. PR_IMPLEMENT(JSBool)
  199. JS_ClearInterrupt(JSRuntime *rt, JSTrapHandler *handlerp, void **closurep)
  200. {
  201.     if (handlerp)
  202.     *handlerp = rt->interruptHandler;
  203.     if (closurep)
  204.     *closurep = rt->interruptHandlerData;
  205.     rt->interruptHandler = 0;
  206.     rt->interruptHandlerData = 0;
  207.     return JS_TRUE;
  208. }
  209.  
  210.  
  211. typedef struct JSWatchPoint {
  212.     PRCList             links;
  213.     JSObject            *object;    /* weak link, see js_FinalizeObject */
  214.     jsval               userid;
  215.     JSProperty          *prop;
  216.     JSPropertyOp        setter;
  217.     JSWatchPointHandler handler;
  218.     void                *closure;
  219.     jsrefcount          nrefs;
  220. } JSWatchPoint;
  221.  
  222. #define HoldWatchPoint(wp) ((wp)->nrefs++)
  223.  
  224. static void
  225. DropWatchPoint(JSContext *cx, JSWatchPoint *wp)
  226. {
  227.     if (--wp->nrefs != 0)
  228.     return;
  229.     wp->prop->setter = wp->setter;
  230.     js_DropProperty(cx, wp->prop);
  231.     PR_REMOVE_LINK(&wp->links);
  232.     js_RemoveRoot(cx, &wp->closure);
  233.     JS_free(cx, wp);
  234. }
  235.  
  236. static JSWatchPoint *
  237. FindWatchPoint(JSRuntime *rt, JSObject *obj, jsval userid)
  238. {
  239.     JSWatchPoint *wp;
  240.  
  241.     for (wp = (JSWatchPoint *)rt->watchPointList.next;
  242.      wp != (JSWatchPoint *)&rt->watchPointList;
  243.      wp = (JSWatchPoint *)wp->links.next) {
  244.     if (wp->object == obj && wp->userid == userid)
  245.         return wp;
  246.     }
  247.     return NULL;
  248. }
  249.  
  250. JSProperty *
  251. js_FindWatchPoint(JSRuntime *rt, JSObject *obj, jsval userid)
  252. {
  253.     JSWatchPoint *wp;
  254.  
  255.     wp = FindWatchPoint(rt, obj, userid);
  256.     if (!wp)
  257.     return NULL;
  258.     return wp->prop;
  259. }
  260.  
  261. JSBool PR_CALLBACK
  262. js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  263. {
  264.     JSRuntime *rt;
  265.     JSWatchPoint *wp;
  266.     JSProperty *prop;
  267.     JSSymbol *sym;
  268.     jsval symid, value;
  269.     JSScope *scope;
  270.     JSAtom *atom;
  271.     JSBool ok;
  272.  
  273.     rt = cx->runtime;
  274.     for (wp = (JSWatchPoint *)rt->watchPointList.next;
  275.      wp != (JSWatchPoint *)&rt->watchPointList;
  276.      wp = (JSWatchPoint *)wp->links.next) {
  277.     prop = wp->prop;
  278.     if (wp->object == obj && prop->id == id) {
  279.         sym = prop->symbols;
  280.         if (!sym) {
  281.         symid = wp->userid;
  282.         atom = NULL;
  283.         if (JSVAL_IS_STRING(symid)) {
  284.             atom = js_ValueToStringAtom(cx, symid);
  285.             if (!atom)
  286.             return JS_FALSE;
  287.             symid = (jsval)atom;
  288.         }
  289.         scope = (JSScope *) obj->map;
  290.         ok = obj->map->clasp->addProperty(cx, obj, prop->id, &value) &&
  291.              scope->ops->add(cx, scope, symid, prop);
  292.         if (atom)
  293.             js_DropAtom(cx, atom);
  294.         if (!ok)
  295.             return JS_FALSE;
  296.         sym = prop->symbols;
  297.         }
  298.         HoldWatchPoint(wp);
  299.         ok = wp->handler(cx, obj, js_IdToValue(sym_id(sym)),
  300.                  obj->slots[wp->prop->slot], vp, wp->closure);
  301.         if (ok)
  302.         ok = wp->setter(cx, obj, id, vp);
  303.         DropWatchPoint(cx, wp);
  304.         return ok;
  305.     }
  306.     }
  307.     PR_ASSERT(0);    /* XXX can't happen */
  308.     return JS_FALSE;
  309. }
  310.  
  311. PR_IMPLEMENT(JSBool)
  312. JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id,
  313.          JSWatchPointHandler handler, void *closure)
  314. {
  315.     JSAtom *atom;
  316.     jsval symid;
  317.     JSProperty *prop;
  318.     JSRuntime *rt;
  319.     JSWatchPoint *wp;
  320.  
  321.     if (JSVAL_IS_INT(id)) {
  322.     symid = id;
  323.     atom = NULL;
  324.     } else {
  325.     atom = js_ValueToStringAtom(cx, id);
  326.     if (!atom)
  327.         return JS_FALSE;
  328.     symid = (jsval)atom;
  329.     }
  330.  
  331.     if (!js_LookupProperty(cx, obj, symid, &obj, &prop))
  332.     return JS_FALSE;
  333.     rt = cx->runtime;
  334.     if (!prop) {
  335.     /* Check for a deleted symbol watchpoint, which holds its property. */
  336.     prop = js_FindWatchPoint(rt, obj, id);
  337.     if (!prop) {
  338.         /* Make a new property in obj so we can watch for the first set. */
  339.         prop = js_DefineProperty(cx, obj, symid, JSVAL_VOID, NULL, NULL, 0);
  340.     }
  341.     } else if (prop->object != obj) {
  342.     /* Clone the prototype property so we can watch the right object. */
  343.     prop = js_DefineProperty(cx, obj, symid,
  344.                  prop->object->slots[prop->slot],
  345.                  prop->getter, prop->setter, prop->flags);
  346.     }
  347.     if (atom)
  348.     js_DropAtom(cx, atom);
  349.     if (!prop)
  350.     return JS_FALSE;
  351.  
  352.     wp = FindWatchPoint(rt, obj, id);
  353.     if (!wp) {
  354.     wp = JS_malloc(cx, sizeof *wp);
  355.     if (!wp)
  356.         return JS_FALSE;
  357.     if (!js_AddRoot(cx, &wp->closure)) {
  358.         JS_free(cx, wp);
  359.         return JS_FALSE;
  360.     }
  361.     PR_APPEND_LINK(&wp->links, &rt->watchPointList);
  362.     wp->object = obj;
  363.     wp->userid = id;
  364.     wp->prop = js_HoldProperty(cx, prop);
  365.     wp->setter = prop->setter;
  366.     prop->setter = js_watch_set;
  367.     wp->nrefs = 1;
  368.     }
  369.     wp->handler = handler;
  370.     wp->closure = closure;
  371.     return JS_TRUE;
  372. }
  373.  
  374. PR_IMPLEMENT(void)
  375. JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsval id,
  376.            JSWatchPointHandler *handlerp, void **closurep)
  377. {
  378.     JSRuntime *rt;
  379.     JSWatchPoint *wp;
  380.  
  381.     rt = cx->runtime;
  382.     for (wp = (JSWatchPoint *)rt->watchPointList.next;
  383.      wp != (JSWatchPoint *)&rt->watchPointList;
  384.      wp = (JSWatchPoint *)wp->links.next) {
  385.     if (wp->object == obj && wp->userid == id) {
  386.         if (handlerp)
  387.         *handlerp = wp->handler;
  388.         if (closurep)
  389.         *closurep = wp->closure;
  390.         DropWatchPoint(cx, wp);
  391.         return;
  392.     }
  393.     }
  394.     if (handlerp)
  395.     *handlerp = NULL;
  396.     if (closurep)
  397.     *closurep = NULL;
  398. }
  399.  
  400. PR_IMPLEMENT(void)
  401. JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj)
  402. {
  403.     JSRuntime *rt;
  404.     JSWatchPoint *wp, *next;
  405.  
  406.     rt = cx->runtime;
  407.     for (wp = (JSWatchPoint *)rt->watchPointList.next;
  408.      wp != (JSWatchPoint *)&rt->watchPointList;
  409.      wp = next) {
  410.     next = (JSWatchPoint *)wp->links.next;
  411.     if (wp->object == obj)
  412.         DropWatchPoint(cx, wp);
  413.     }
  414. }
  415.  
  416. PR_IMPLEMENT(void)
  417. JS_ClearAllWatchPoints(JSContext *cx)
  418. {
  419.     JSRuntime *rt;
  420.     JSWatchPoint *wp, *next;
  421.  
  422.     rt = cx->runtime;
  423.     for (wp = (JSWatchPoint *)rt->watchPointList.next;
  424.      wp != (JSWatchPoint *)&rt->watchPointList;
  425.      wp = next) {
  426.     next = (JSWatchPoint *)wp->links.next;
  427.     DropWatchPoint(cx, wp);
  428.     }
  429. }
  430.  
  431. PR_IMPLEMENT(uintN)
  432. JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
  433. {
  434.     return js_PCToLineNumber(script, pc);
  435. }
  436.  
  437. PR_IMPLEMENT(jsbytecode *)
  438. JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno)
  439. {
  440.     return js_LineNumberToPC(script, lineno);
  441. }
  442.  
  443. PR_IMPLEMENT(JSScript *)
  444. JS_GetFunctionScript(JSContext *cx, JSFunction *fun)
  445. {
  446.     return fun->script;
  447. }
  448.  
  449. PR_IMPLEMENT(JSPrincipals *)
  450. JS_GetScriptPrincipals(JSContext *cx, JSScript *script)
  451. {
  452.     return script->principals;
  453. }
  454.  
  455.  
  456. /*
  457.  *  Stack Frame Iterator
  458.  */
  459. PR_IMPLEMENT(JSStackFrame *)
  460. JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
  461. {
  462.     *iteratorp = (*iteratorp == NULL) ? cx->fp : (*iteratorp)->down;
  463.     return *iteratorp;
  464. }
  465.  
  466. PR_IMPLEMENT(JSScript *)
  467. JS_GetFrameScript(JSContext *cx, JSStackFrame *fp)
  468. {
  469.     return fp->script;
  470. }
  471.  
  472. PR_IMPLEMENT(jsbytecode *)
  473. JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
  474. {
  475.     return fp->pc;
  476. }
  477.  
  478. PR_IMPLEMENT(void *)
  479. JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
  480. {
  481.     if (fp->annotation) {
  482.     JSPrincipals *principals = fp->script
  483.         ? fp->script->principals
  484.         : NULL;
  485.  
  486.     if (principals == NULL)
  487.         return NULL;
  488.  
  489.     if (principals->globalPrivilegesEnabled(cx, principals)) {
  490.         /*
  491.          * Only give out an annotation if privileges have not
  492.          * been revoked globally.
  493.          */
  494.         return fp->annotation;
  495.     }
  496.     }
  497.  
  498.     return NULL;
  499. }
  500.  
  501. PR_IMPLEMENT(void)
  502. JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation)
  503. {
  504.     fp->annotation = annotation;
  505. }
  506.  
  507. PR_IMPLEMENT(void *)
  508. JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp)
  509. {
  510.     JSPrincipals *principals = fp->script
  511.     ? fp->script->principals
  512.     : NULL;
  513.  
  514.     return principals
  515.     ? principals->getPrincipalArray(cx, principals)
  516.     : NULL;
  517. }
  518.  
  519. PR_IMPLEMENT(JSBool)
  520. JS_IsNativeFrame(JSContext *cx, JSStackFrame *fp)
  521. {
  522.     return fp->fun && fp->fun->call;
  523. }
  524.  
  525. PR_IMPLEMENT(JSObject *)
  526. JS_GetFrameObject(JSContext *cx, JSStackFrame *fp)
  527. {
  528.     return fp->scopeChain;
  529. }
  530.  
  531. PR_IMPLEMENT(JSObject *)
  532. JS_GetFrameThis(JSContext *cx, JSStackFrame *fp)
  533. {
  534.     return fp->thisp;
  535. }
  536.  
  537. PR_IMPLEMENT(JSFunction *)
  538. JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
  539. {
  540.     return fp->fun;
  541. }
  542.  
  543. /************************************************************************/
  544.  
  545. PR_IMPLEMENT(const char *)
  546. JS_GetScriptFilename(JSContext *cx, JSScript *script)
  547. {
  548.     return script->filename;
  549. }
  550.  
  551. PR_IMPLEMENT(uintN)
  552. JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script)
  553. {
  554.     return script->lineno;
  555. }
  556.  
  557. PR_IMPLEMENT(uintN)
  558. JS_GetScriptLineExtent(JSContext *cx, JSScript *script)
  559. {
  560.     return js_GetScriptLineExtent(script);
  561. }
  562.  
  563. /***************************************************************************/
  564.  
  565. PR_IMPLEMENT(void)
  566. JS_SetNewScriptHookProc(JSRuntime *rt, JSNewScriptHookProc hookproc,
  567.             void *callerdata)
  568. {
  569.     rt->newScriptHookProcData = callerdata;
  570.     rt->newScriptHookProc = hookproc;
  571. }
  572.  
  573. PR_IMPLEMENT(void)
  574. JS_SetDestroyScriptHookProc(JSRuntime *rt, JSDestroyScriptHookProc hookproc,
  575.                 void *callerdata)
  576. {
  577.     rt->destroyScriptHookProcData = callerdata;
  578.     rt->destroyScriptHookProc = hookproc;
  579. }
  580.  
  581. /***************************************************************************/
  582.  
  583. PR_IMPLEMENT(JSBool)
  584. JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp,
  585.             const char *bytes, uintN length,
  586.             const char *filename, uintN lineno,
  587.             jsval *rval)
  588. {
  589.     JSScript *script;
  590.     JSBool ok;
  591.  
  592.     script = JS_CompileScriptForPrincipals(cx, fp->scopeChain,
  593.                        fp->script ? fp->script->principals
  594.                               : NULL,
  595.                        bytes, length, filename, lineno);
  596.     if (!script)
  597.     return JS_FALSE;
  598.     ok = js_Execute(cx, fp->scopeChain, script, fp, rval);
  599.     JS_DestroyScript(cx, script);
  600.     return ok;
  601. }
  602.  
  603. /************************************************************************/
  604.  
  605. PR_IMPLEMENT(JSProperty *)
  606. JS_PropertyIterator(JSObject *obj, JSProperty **iteratorp)
  607. {
  608.     JSProperty *prop;
  609.  
  610.     prop = *iteratorp;
  611.     prop = (prop == NULL) ? obj->map->props : prop->next;
  612.     *iteratorp = prop;
  613.     return prop;
  614. }
  615.  
  616. PR_IMPLEMENT(JSBool)
  617. JS_GetPropertyDesc(JSContext *cx, JSProperty *prop, JSPropertyDesc *pd)
  618. {
  619.     JSSymbol *sym;
  620.  
  621.     sym = prop->symbols;
  622.     pd->id = sym ? js_IdToValue(sym_id(sym)) : JSVAL_VOID;
  623.     pd->value = prop->object->slots[prop->slot];
  624.     pd->flags = ((prop->flags & JSPROP_ENUMERATE)      ? JSPD_ENUMERATE : 0)
  625.           | ((prop->flags & JSPROP_READONLY)       ? JSPD_READONLY  : 0)
  626.           | ((prop->flags & JSPROP_PERMANENT)      ? JSPD_PERMANENT : 0)
  627.           | ((prop->getter == js_GetArgument)      ? JSPD_ARGUMENT  : 0)
  628.           | ((prop->getter == js_GetLocalVariable) ? JSPD_VARIABLE  : 0);
  629.     pd->spare = 0;
  630.     pd->slot = (prop->flags & (JSPD_ARGUMENT | JSPD_VARIABLE))
  631.            ? JSVAL_TO_INT(prop->id)
  632.            : 0;
  633.     if (!sym || !sym->next || (prop->flags & (JSPD_ARGUMENT | JSPD_VARIABLE))) {
  634.     pd->alias = JSVAL_VOID;
  635.     } else {
  636.     pd->alias = js_IdToValue(sym_id(sym->next));
  637.     pd->flags |= JSPD_ALIAS;
  638.     }
  639.     return JS_TRUE;
  640. }
  641.  
  642. PR_IMPLEMENT(JSBool)
  643. JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda)
  644. {
  645.     JSScope *scope;
  646.     uint32 i, n;
  647.     JSPropertyDesc *pd;
  648.     JSProperty *prop;
  649.  
  650.     if (!obj->map->clasp->enumerate(cx, obj))
  651.     return JS_FALSE;
  652.     scope = (JSScope *)obj->map;
  653.     if (scope->object != obj) {
  654.     pda->length = 0;
  655.     pda->array = NULL;
  656.     return JS_TRUE;
  657.     }
  658.     n = scope->map.freeslot;
  659.     pd = JS_malloc(cx, (size_t)n * sizeof(JSPropertyDesc));
  660.     if (!pd)
  661.     return JS_FALSE;
  662.     i = 0;
  663.     for (prop = scope->map.props; prop; prop = prop->next) {
  664.     if (!js_AddRoot(cx, &pd[i].id) || !js_AddRoot(cx, &pd[i].value))
  665.         goto bad;
  666.     JS_GetPropertyDesc(cx, prop, &pd[i]);
  667.     if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias))
  668.         goto bad;
  669.     if (++i == n)
  670.         break;
  671.     }
  672.     pda->length = i;
  673.     pda->array = pd;
  674.     return JS_TRUE;
  675.  
  676. bad:
  677.     pda->length = i + 1;
  678.     pda->array = pd;
  679.     JS_PutPropertyDescArray(cx, pda);
  680.     return JS_FALSE;
  681. }
  682.  
  683. PR_IMPLEMENT(void)
  684. JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda)
  685. {
  686.     JSPropertyDesc *pd;
  687.     uint32 i;
  688.  
  689.     pd = pda->array;
  690.     for (i = 0; i < pda->length; i++) {
  691.     js_RemoveRoot(cx, &pd[i].id);
  692.     js_RemoveRoot(cx, &pd[i].value);
  693.     if (pd[i].flags & JSPD_ALIAS)
  694.         js_RemoveRoot(cx, &pd[i].alias);
  695.     }
  696.     JS_free(cx, pd);
  697. }
  698.