LCOV - code coverage report
Current view: directory - js/src/vm - ScopeObject.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 437 348 79.6 %
Date: 2012-06-02 Functions: 50 29 58.0 %

       1                 : /* -*- Mode: C++; tab-width: 6; 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 SpiderMonkey call object code.
      18                 :  *
      19                 :  * The Initial Developer of the Original Code is
      20                 :  * the Mozilla Foundation.
      21                 :  * Portions created by the Initial Developer are Copyright (C) 2011
      22                 :  * the Initial Developer. All Rights Reserved.
      23                 :  *
      24                 :  * Contributor(s):
      25                 :  *   Paul Biggar <pbiggar@mozilla.com> (original author)
      26                 :  *   Luke Wagner <luke@mozilla.com>
      27                 :  *
      28                 :  * Alternatively, the contents of this file may be used under the terms of
      29                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      30                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      31                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      32                 :  * of those above. If you wish to allow use of your version of this file only
      33                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      34                 :  * use your version of this file under the terms of the MPL, indicate your
      35                 :  * decision by deleting the provisions above and replace them with the notice
      36                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      37                 :  * the provisions above, a recipient may use your version of this file under
      38                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      39                 :  *
      40                 :  * ***** END LICENSE BLOCK ***** */
      41                 : 
      42                 : #include "jscompartment.h"
      43                 : #include "jsiter.h"
      44                 : #include "jsscope.h"
      45                 : #if JS_HAS_XDR
      46                 : #include "jsxdrapi.h"
      47                 : #endif
      48                 : 
      49                 : #include "GlobalObject.h"
      50                 : #include "ScopeObject.h"
      51                 : 
      52                 : #include "jsatominlines.h"
      53                 : #include "jsobjinlines.h"
      54                 : 
      55                 : #include "ScopeObject-inl.h"
      56                 : 
      57                 : using namespace js;
      58                 : using namespace js::types;
      59                 : 
      60                 : void
      61          702948 : js_PutCallObject(StackFrame *fp)
      62                 : {
      63          702948 :     CallObject &callobj = fp->callObj().asCall();
      64          702948 :     JS_ASSERT(callobj.maybeStackFrame() == fp);
      65          702948 :     JS_ASSERT_IF(fp->isEvalFrame(), fp->isStrictEvalFrame());
      66          702948 :     JS_ASSERT(fp->isEvalFrame() == callobj.isForEval());
      67                 : 
      68                 :     /* Get the arguments object to snapshot fp's actual argument values. */
      69          702948 :     if (fp->hasArgsObj()) {
      70            9729 :         if (callobj.arguments().isMagic(JS_UNASSIGNED_ARGUMENTS))
      71            9711 :             callobj.setArguments(ObjectValue(fp->argsObj()));
      72            9729 :         js_PutArgsObject(fp);
      73                 :     }
      74                 : 
      75          702948 :     JSScript *script = fp->script();
      76          702948 :     Bindings &bindings = script->bindings;
      77                 : 
      78          702948 :     if (callobj.isForEval()) {
      79            1908 :         JS_ASSERT(script->strictModeCode);
      80            1908 :         JS_ASSERT(bindings.countArgs() == 0);
      81                 : 
      82                 :         /* This could be optimized as below, but keep it simple for now. */
      83            1908 :         callobj.copyValues(0, NULL, bindings.countVars(), fp->slots());
      84                 :     } else {
      85          701040 :         JSFunction *fun = fp->fun();
      86          701040 :         JS_ASSERT(script == callobj.getCalleeFunction()->script());
      87          701040 :         JS_ASSERT(script == fun->script());
      88                 : 
      89          701040 :         unsigned n = bindings.countArgsAndVars();
      90          701040 :         if (n > 0) {
      91          464113 :             uint32_t nvars = bindings.countVars();
      92          464113 :             uint32_t nargs = bindings.countArgs();
      93          464113 :             JS_ASSERT(fun->nargs == nargs);
      94          464113 :             JS_ASSERT(nvars + nargs == n);
      95                 : 
      96          464113 :             JSScript *script = fun->script();
      97          464113 :             if (script->usesEval
      98                 : #ifdef JS_METHODJIT
      99                 :                 || script->debugMode
     100                 : #endif
     101                 :                 ) {
     102           86684 :                 callobj.copyValues(nargs, fp->formalArgs(), nvars, fp->slots());
     103                 :             } else {
     104                 :                 /*
     105                 :                  * For each arg & var that is closed over, copy it from the stack
     106                 :                  * into the call object. We use initArg/VarUnchecked because,
     107                 :                  * when you call a getter on a call object, js_NativeGetInline
     108                 :                  * caches the return value in the slot, so we can't assert that
     109                 :                  * it's undefined.
     110                 :                  */
     111          377429 :                 uint32_t nclosed = script->nClosedArgs;
     112          812649 :                 for (uint32_t i = 0; i < nclosed; i++) {
     113          435220 :                     uint32_t e = script->getClosedArg(i);
     114                 : #ifdef JS_GC_ZEAL
     115          435220 :                     callobj.setArg(e, fp->formalArg(e));
     116                 : #else
     117                 :                     callobj.initArgUnchecked(e, fp->formalArg(e));
     118                 : #endif
     119                 :                 }
     120                 : 
     121          377429 :                 nclosed = script->nClosedVars;
     122          609148 :                 for (uint32_t i = 0; i < nclosed; i++) {
     123          231719 :                     uint32_t e = script->getClosedVar(i);
     124                 : #ifdef JS_GC_ZEAL
     125          231719 :                     callobj.setVar(e, fp->slots()[e]);
     126                 : #else
     127                 :                     callobj.initVarUnchecked(e, fp->slots()[e]);
     128                 : #endif
     129                 :                 }
     130                 :             }
     131                 : 
     132                 :             /*
     133                 :              * Update the args and vars for the active call if this is an outer
     134                 :              * function in a script nesting.
     135                 :              */
     136          464113 :             types::TypeScriptNesting *nesting = script->nesting();
     137          464113 :             if (nesting && script->isOuterFunction) {
     138          100667 :                 nesting->argArray = callobj.argArray();
     139          100667 :                 nesting->varArray = callobj.varArray();
     140                 :             }
     141                 :         }
     142                 : 
     143                 :         /* Clear private pointers to fp, which is about to go away. */
     144          701040 :         if (js_IsNamedLambda(fun)) {
     145           41167 :             JSObject &env = callobj.enclosingScope();
     146           41167 :             JS_ASSERT(env.asDeclEnv().maybeStackFrame() == fp);
     147           41167 :             env.setPrivate(NULL);
     148                 :         }
     149                 :     }
     150                 : 
     151          702948 :     callobj.setStackFrame(NULL);
     152          702948 : }
     153                 : 
     154                 : /*
     155                 :  * Construct a call object for the given bindings.  If this is a call object
     156                 :  * for a function invocation, callee should be the function being called.
     157                 :  * Otherwise it must be a call object for eval of strict mode code, and callee
     158                 :  * must be null.
     159                 :  */
     160                 : CallObject *
     161          703452 : CallObject::create(JSContext *cx, JSScript *script, JSObject &enclosing, JSObject *callee)
     162                 : {
     163         1406904 :     RootedVarShape shape(cx);
     164          703452 :     shape = script->bindings.callObjectShape(cx);
     165          703452 :     if (shape == NULL)
     166               0 :         return NULL;
     167                 : 
     168          703452 :     gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots() + 1);
     169                 : 
     170         1406904 :     RootedVarTypeObject type(cx);
     171                 : 
     172          703452 :     type = cx->compartment->getEmptyType(cx);
     173          703452 :     if (!type)
     174               0 :         return NULL;
     175                 : 
     176                 :     HeapSlot *slots;
     177          703452 :     if (!PreallocateObjectDynamicSlots(cx, shape, &slots))
     178               0 :         return NULL;
     179                 : 
     180          703452 :     JSObject *obj = JSObject::create(cx, kind, shape, type, slots);
     181          703452 :     if (!obj)
     182               0 :         return NULL;
     183                 : 
     184                 :     /*
     185                 :      * Update the parent for bindings associated with non-compileAndGo scripts,
     186                 :      * whose call objects do not have a consistent global variable and need
     187                 :      * to be updated dynamically.
     188                 :      */
     189          703452 :     JSObject &global = enclosing.global();
     190          703452 :     if (&global != obj->getParent()) {
     191          277123 :         JS_ASSERT(obj->getParent() == NULL);
     192          277123 :         if (!obj->setParent(cx, &global))
     193               0 :             return NULL;
     194                 :     }
     195                 : 
     196                 : #ifdef DEBUG
     197          703452 :     JS_ASSERT(!obj->inDictionaryMode());
     198          703640 :     for (Shape::Range r = obj->lastProperty(); !r.empty(); r.popFront()) {
     199          464373 :         const Shape &s = r.front();
     200          464373 :         if (s.hasSlot()) {
     201          464185 :             JS_ASSERT(s.slot() + 1 == obj->slotSpan());
     202          464185 :             break;
     203                 :         }
     204                 :     }
     205                 : #endif
     206                 : 
     207          703452 :     if (!obj->asScope().setEnclosingScope(cx, enclosing))
     208               0 :         return NULL;
     209                 : 
     210          703452 :     JS_ASSERT_IF(callee, callee->isFunction());
     211          703452 :     obj->initFixedSlot(CALLEE_SLOT, ObjectOrNullValue(callee));
     212          703452 :     obj->initFixedSlot(ARGUMENTS_SLOT, MagicValue(JS_UNASSIGNED_ARGUMENTS));
     213                 : 
     214                 :     /*
     215                 :      * If |bindings| is for a function that has extensible parents, that means
     216                 :      * its Call should have its own shape; see BaseShape::extensibleParents.
     217                 :      */
     218          703452 :     if (obj->lastProperty()->extensibleParents() && !obj->generateOwnShape(cx))
     219               0 :         return NULL;
     220                 : 
     221          703452 :     return &obj->asCall();
     222                 : }
     223                 : 
     224                 : CallObject *
     225          701544 : CallObject::createForFunction(JSContext *cx, StackFrame *fp)
     226                 : {
     227          701544 :     JS_ASSERT(fp->isNonEvalFunctionFrame());
     228          701544 :     JS_ASSERT(!fp->hasCallObj());
     229                 : 
     230          701544 :     JSObject *scopeChain = &fp->scopeChain();
     231         2380995 :     JS_ASSERT_IF(scopeChain->isWith() || scopeChain->isBlock() || scopeChain->isCall(),
     232         2380995 :                  scopeChain->getPrivate() != fp);
     233                 : 
     234                 :     /*
     235                 :      * For a named function expression Call's parent points to an environment
     236                 :      * object holding function's name.
     237                 :      */
     238          701544 :     if (JSAtom *lambdaName = CallObjectLambdaName(fp->fun())) {
     239           41527 :         scopeChain = DeclEnvObject::create(cx, fp);
     240           41527 :         if (!scopeChain)
     241               0 :             return NULL;
     242                 : 
     243           41527 :         if (!DefineNativeProperty(cx, scopeChain, ATOM_TO_JSID(lambdaName),
     244           41527 :                                   ObjectValue(fp->callee()), NULL, NULL,
     245           41527 :                                   JSPROP_PERMANENT | JSPROP_READONLY, 0, 0)) {
     246               0 :             return NULL;
     247                 :         }
     248                 :     }
     249                 : 
     250          701544 :     CallObject *callobj = create(cx, fp->script(), *scopeChain, &fp->callee());
     251          701544 :     if (!callobj)
     252               0 :         return NULL;
     253                 : 
     254          701544 :     callobj->setStackFrame(fp);
     255          701544 :     fp->setScopeChainWithOwnCallObj(*callobj);
     256          701544 :     return callobj;
     257                 : }
     258                 : 
     259                 : CallObject *
     260            1908 : CallObject::createForStrictEval(JSContext *cx, StackFrame *fp)
     261                 : {
     262            1908 :     CallObject *callobj = create(cx, fp->script(), fp->scopeChain(), NULL);
     263            1908 :     if (!callobj)
     264               0 :         return NULL;
     265                 : 
     266            1908 :     callobj->setStackFrame(fp);
     267            1908 :     fp->setScopeChainWithOwnCallObj(*callobj);
     268            1908 :     return callobj;
     269                 : }
     270                 : 
     271                 : JSBool
     272            1381 : CallObject::getArgumentsOp(JSContext *cx, JSObject *obj, jsid id, Value *vp)
     273                 : {
     274            1381 :     CallObject &callobj = obj->asCall();
     275                 : 
     276            1381 :     StackFrame *fp = callobj.maybeStackFrame();
     277            1381 :     if (fp && callobj.arguments().isMagic(JS_UNASSIGNED_ARGUMENTS)) {
     278            1318 :         JSObject *argsobj = js_GetArgsObject(cx, fp);
     279            1318 :         if (!argsobj)
     280               0 :             return false;
     281            1318 :         vp->setObject(*argsobj);
     282                 :     } else {
     283                 :         /* Nested functions cannot get the 'arguments' of enclosing scopes. */
     284              63 :         JS_ASSERT(!callobj.arguments().isMagic(JS_UNASSIGNED_ARGUMENTS));
     285              63 :         *vp = callobj.arguments();
     286                 :     }
     287            1381 :     return true;
     288                 : }
     289                 : 
     290                 : JSBool
     291              63 : CallObject::setArgumentsOp(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
     292                 : {
     293                 :     /* Nested functions cannot set the 'arguments' of enclosing scopes. */
     294              63 :     JS_ASSERT(obj->asCall().maybeStackFrame());
     295              63 :     obj->asCall().setArguments(*vp);
     296              63 :     return true;
     297                 : }
     298                 : 
     299                 : JSBool
     300          682324 : CallObject::getArgOp(JSContext *cx, JSObject *obj, jsid id, Value *vp)
     301                 : {
     302          682324 :     CallObject &callobj = obj->asCall();
     303          682324 :     JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
     304          682324 :     unsigned i = (uint16_t) JSID_TO_INT(id);
     305                 : 
     306          682324 :     if (StackFrame *fp = callobj.maybeStackFrame())
     307          559279 :         *vp = fp->formalArg(i);
     308                 :     else
     309          123045 :         *vp = callobj.arg(i);
     310          682324 :     return true;
     311                 : }
     312                 : 
     313                 : JSBool
     314            3392 : CallObject::setArgOp(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
     315                 : {
     316            3392 :     CallObject &callobj = obj->asCall();
     317            3392 :     JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
     318            3392 :     unsigned i = (uint16_t) JSID_TO_INT(id);
     319                 : 
     320            3392 :     if (StackFrame *fp = callobj.maybeStackFrame())
     321            2593 :         fp->formalArg(i) = *vp;
     322                 :     else
     323             799 :         callobj.setArg(i, *vp);
     324                 : 
     325            3392 :     JSFunction *fun = callobj.getCalleeFunction();
     326            3392 :     JSScript *script = fun->script();
     327            3392 :     if (!script->ensureHasTypes(cx))
     328               0 :         return false;
     329                 : 
     330            3392 :     TypeScript::SetArgument(cx, script, i, *vp);
     331                 : 
     332            3392 :     return true;
     333                 : }
     334                 : 
     335                 : JSBool
     336             176 : CallObject::getUpvarOp(JSContext *cx, JSObject *obj, jsid id, Value *vp)
     337                 : {
     338             176 :     CallObject &callobj = obj->asCall();
     339             176 :     JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
     340             176 :     unsigned i = (uint16_t) JSID_TO_INT(id);
     341                 : 
     342             176 :     *vp = callobj.getCallee()->toFunction()->getFlatClosureUpvar(i);
     343             176 :     return true;
     344                 : }
     345                 : 
     346                 : JSBool
     347               0 : CallObject::setUpvarOp(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
     348                 : {
     349               0 :     CallObject &callobj = obj->asCall();
     350               0 :     JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
     351               0 :     unsigned i = (uint16_t) JSID_TO_INT(id);
     352                 : 
     353               0 :     callobj.getCallee()->toFunction()->setFlatClosureUpvar(i, *vp);
     354               0 :     return true;
     355                 : }
     356                 : 
     357                 : JSBool
     358          736119 : CallObject::getVarOp(JSContext *cx, JSObject *obj, jsid id, Value *vp)
     359                 : {
     360          736119 :     CallObject &callobj = obj->asCall();
     361          736119 :     JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
     362          736119 :     unsigned i = (uint16_t) JSID_TO_INT(id);
     363                 : 
     364          736119 :     if (StackFrame *fp = callobj.maybeStackFrame())
     365          636369 :         *vp = fp->varSlot(i);
     366                 :     else
     367           99750 :         *vp = callobj.var(i);
     368          736119 :     return true;
     369                 : }
     370                 : 
     371                 : JSBool
     372           37339 : CallObject::setVarOp(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
     373                 : {
     374           37339 :     CallObject &callobj = obj->asCall();
     375                 : 
     376           37339 :     JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
     377           37339 :     unsigned i = (uint16_t) JSID_TO_INT(id);
     378                 : 
     379           37339 :     if (StackFrame *fp = callobj.maybeStackFrame())
     380           33687 :         fp->varSlot(i) = *vp;
     381                 :     else
     382            3652 :         callobj.setVar(i, *vp);
     383                 : 
     384           37339 :     JSFunction *fun = callobj.getCalleeFunction();
     385           37339 :     JSScript *script = fun->script();
     386           37339 :     if (!script->ensureHasTypes(cx))
     387               0 :         return false;
     388                 : 
     389           37339 :     TypeScript::SetLocal(cx, script, i, *vp);
     390                 : 
     391           37339 :     return true;
     392                 : }
     393                 : 
     394                 : static JSBool
     395         1583602 : call_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags, JSObject **objp)
     396                 : {
     397         1583602 :     JS_ASSERT(!obj->getProto());
     398                 : 
     399         1583602 :     if (!JSID_IS_ATOM(id))
     400             144 :         return true;
     401                 : 
     402         1583458 :     JSObject *callee = obj->asCall().getCallee();
     403                 : #ifdef DEBUG
     404         1583458 :     if (callee) {
     405         1581739 :         JSScript *script = callee->toFunction()->script();
     406         1581739 :         JS_ASSERT(!script->bindings.hasBinding(cx, JSID_TO_ATOM(id)));
     407                 :     }
     408                 : #endif
     409                 : 
     410                 :     /*
     411                 :      * Resolve arguments so that we never store a particular Call object's
     412                 :      * arguments object reference in a Call prototype's |arguments| slot.
     413                 :      *
     414                 :      * Include JSPROP_ENUMERATE for consistency with all other Call object
     415                 :      * properties; see js::Bindings::add and js::Interpret's JSOP_DEFFUN
     416                 :      * rebinding-Call-property logic.
     417                 :      */
     418         1583458 :     if (callee && id == ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom)) {
     419             873 :         if (!DefineNativeProperty(cx, obj, id, UndefinedValue(),
     420                 :                                   CallObject::getArgumentsOp, CallObject::setArgumentsOp,
     421                 :                                   JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE,
     422             873 :                                   0, 0, DNP_DONT_PURGE)) {
     423               0 :             return false;
     424                 :         }
     425             873 :         *objp = obj;
     426             873 :         return true;
     427                 :     }
     428                 : 
     429                 :     /* Control flow reaches here only if id was not resolved. */
     430         1582585 :     return true;
     431                 : }
     432                 : 
     433                 : static void
     434          421338 : call_trace(JSTracer *trc, JSObject *obj)
     435                 : {
     436          421338 :     JS_ASSERT(obj->isCall());
     437                 : 
     438                 :     /* Mark any generator frame, as for arguments objects. */
     439                 : #if JS_HAS_GENERATORS
     440          421338 :     StackFrame *fp = (StackFrame *) obj->getPrivate();
     441          421338 :     if (fp && fp->isFloatingGenerator())
     442             133 :         MarkObject(trc, &js_FloatingFrameToGenerator(fp)->obj, "generator object");
     443                 : #endif
     444          421338 : }
     445                 : 
     446                 : JS_PUBLIC_DATA(Class) js::CallClass = {
     447                 :     "Call",
     448                 :     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     449                 :     JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS) |
     450                 :     JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS,
     451                 :     JS_PropertyStub,         /* addProperty */
     452                 :     JS_PropertyStub,         /* delProperty */
     453                 :     JS_PropertyStub,         /* getProperty */
     454                 :     JS_StrictPropertyStub,   /* setProperty */
     455                 :     JS_EnumerateStub,
     456                 :     (JSResolveOp)call_resolve,
     457                 :     NULL,                    /* convert: Leave it NULL so we notice if calls ever escape */
     458                 :     NULL,                    /* finalize */
     459                 :     NULL,                    /* checkAccess */
     460                 :     NULL,                    /* call        */
     461                 :     NULL,                    /* construct   */
     462                 :     NULL,                    /* hasInstance */
     463                 :     call_trace
     464                 : };
     465                 : 
     466                 : Class js::DeclEnvClass = {
     467                 :     js_Object_str,
     468                 :     JSCLASS_HAS_PRIVATE |
     469                 :     JSCLASS_HAS_RESERVED_SLOTS(DeclEnvObject::RESERVED_SLOTS) |
     470                 :     JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
     471                 :     JS_PropertyStub,         /* addProperty */
     472                 :     JS_PropertyStub,         /* delProperty */
     473                 :     JS_PropertyStub,         /* getProperty */
     474                 :     JS_StrictPropertyStub,   /* setProperty */
     475                 :     JS_EnumerateStub,
     476                 :     JS_ResolveStub,
     477                 :     JS_ConvertStub
     478                 : };
     479                 : 
     480                 : DeclEnvObject *
     481           41527 : DeclEnvObject::create(JSContext *cx, StackFrame *fp)
     482                 : {
     483           83054 :     RootedVarTypeObject type(cx);
     484           41527 :     type = cx->compartment->getEmptyType(cx);
     485           41527 :     if (!type)
     486               0 :         return NULL;
     487                 : 
     488           83054 :     RootedVarShape emptyDeclEnvShape(cx);
     489                 :     emptyDeclEnvShape = EmptyShape::getInitialShape(cx, &DeclEnvClass, NULL,
     490           41527 :                                                     &fp->scopeChain().global(),
     491           41527 :                                                     FINALIZE_KIND);
     492           41527 :     if (!emptyDeclEnvShape)
     493               0 :         return NULL;
     494                 : 
     495           41527 :     JSObject *obj = JSObject::create(cx, FINALIZE_KIND, emptyDeclEnvShape, type, NULL);
     496           41527 :     if (!obj)
     497               0 :         return NULL;
     498                 : 
     499           41527 :     obj->setPrivate(fp);
     500           41527 :     if (!obj->asScope().setEnclosingScope(cx, fp->scopeChain()))
     501               0 :         return NULL;
     502                 : 
     503           41527 :     return &obj->asDeclEnv();
     504                 : }
     505                 : 
     506                 : WithObject *
     507            1791 : WithObject::create(JSContext *cx, StackFrame *fp, JSObject &proto, JSObject &enclosing,
     508                 :                    uint32_t depth)
     509                 : {
     510            3582 :     RootedVarTypeObject type(cx);
     511            1791 :     type = proto.getNewType(cx);
     512            1791 :     if (!type)
     513               0 :         return NULL;
     514                 : 
     515            3582 :     RootedVarShape emptyWithShape(cx);
     516                 :     emptyWithShape = EmptyShape::getInitialShape(cx, &WithClass, &proto,
     517            1791 :                                                  &enclosing.global(), FINALIZE_KIND);
     518            1791 :     if (!emptyWithShape)
     519               0 :         return NULL;
     520                 : 
     521            1791 :     JSObject *obj = JSObject::create(cx, FINALIZE_KIND, emptyWithShape, type, NULL);
     522            1791 :     if (!obj)
     523               0 :         return NULL;
     524                 : 
     525            1791 :     if (!obj->asScope().setEnclosingScope(cx, enclosing))
     526               0 :         return NULL;
     527                 : 
     528            1791 :     obj->setReservedSlot(DEPTH_SLOT, PrivateUint32Value(depth));
     529            1791 :     obj->setPrivate(js_FloatingFrameIfGenerator(cx, fp));
     530                 : 
     531            1791 :     JSObject *thisp = proto.thisObject(cx);
     532            1791 :     if (!thisp)
     533               0 :         return NULL;
     534                 : 
     535            1791 :     obj->setFixedSlot(THIS_SLOT, ObjectValue(*thisp));
     536                 : 
     537            1791 :     return &obj->asWith();
     538                 : }
     539                 : 
     540                 : static JSBool
     541            3195 : with_LookupGeneric(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, JSProperty **propp)
     542                 : {
     543                 :     /* Fixes bug 463997 */
     544            3195 :     unsigned flags = cx->resolveFlags;
     545            3195 :     if (flags == RESOLVE_INFER)
     546            3195 :         flags = js_InferFlags(cx, flags);
     547            3195 :     flags |= JSRESOLVE_WITH;
     548            6390 :     JSAutoResolveFlags rf(cx, flags);
     549            3195 :     return obj->asWith().object().lookupGeneric(cx, id, objp, propp);
     550                 : }
     551                 : 
     552                 : static JSBool
     553               0 : with_LookupProperty(JSContext *cx, JSObject *obj, PropertyName *name, JSObject **objp, JSProperty **propp)
     554                 : {
     555               0 :     return with_LookupGeneric(cx, obj, ATOM_TO_JSID(name), objp, propp);
     556                 : }
     557                 : 
     558                 : static JSBool
     559               0 : with_LookupElement(JSContext *cx, JSObject *obj, uint32_t index, JSObject **objp,
     560                 :                    JSProperty **propp)
     561                 : {
     562                 :     jsid id;
     563               0 :     if (!IndexToId(cx, index, &id))
     564               0 :         return false;
     565               0 :     return with_LookupGeneric(cx, obj, id, objp, propp);
     566                 : }
     567                 : 
     568                 : static JSBool
     569               0 : with_LookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid, JSObject **objp, JSProperty **propp)
     570                 : {
     571               0 :     return with_LookupGeneric(cx, obj, SPECIALID_TO_JSID(sid), objp, propp);
     572                 : }
     573                 : 
     574                 : static JSBool
     575              27 : with_GetGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
     576                 : {
     577              27 :     return obj->asWith().object().getGeneric(cx, id, vp);
     578                 : }
     579                 : 
     580                 : static JSBool
     581               0 : with_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, PropertyName *name, Value *vp)
     582                 : {
     583               0 :     return with_GetGeneric(cx, obj, receiver, ATOM_TO_JSID(name), vp);
     584                 : }
     585                 : 
     586                 : static JSBool
     587               0 : with_GetElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, Value *vp)
     588                 : {
     589                 :     jsid id;
     590               0 :     if (!IndexToId(cx, index, &id))
     591               0 :         return false;
     592               0 :     return with_GetGeneric(cx, obj, receiver, id, vp);
     593                 : }
     594                 : 
     595                 : static JSBool
     596               0 : with_GetSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid, Value *vp)
     597                 : {
     598               0 :     return with_GetGeneric(cx, obj, receiver, SPECIALID_TO_JSID(sid), vp);
     599                 : }
     600                 : 
     601                 : static JSBool
     602              63 : with_SetGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
     603                 : {
     604              63 :     return obj->asWith().object().setGeneric(cx, id, vp, strict);
     605                 : }
     606                 : 
     607                 : static JSBool
     608               0 : with_SetProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict)
     609                 : {
     610               0 :     return obj->asWith().object().setProperty(cx, name, vp, strict);
     611                 : }
     612                 : 
     613                 : static JSBool
     614               0 : with_SetElement(JSContext *cx, JSObject *obj, uint32_t index, Value *vp, JSBool strict)
     615                 : {
     616               0 :     return obj->asWith().object().setElement(cx, index, vp, strict);
     617                 : }
     618                 : 
     619                 : static JSBool
     620               0 : with_SetSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict)
     621                 : {
     622               0 :     return obj->asWith().object().setSpecial(cx, sid, vp, strict);
     623                 : }
     624                 : 
     625                 : static JSBool
     626               0 : with_GetGenericAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp)
     627                 : {
     628               0 :     return obj->asWith().object().getGenericAttributes(cx, id, attrsp);
     629                 : }
     630                 : 
     631                 : static JSBool
     632               0 : with_GetPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, unsigned *attrsp)
     633                 : {
     634               0 :     return obj->asWith().object().getPropertyAttributes(cx, name, attrsp);
     635                 : }
     636                 : 
     637                 : static JSBool
     638               0 : with_GetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *attrsp)
     639                 : {
     640               0 :     return obj->asWith().object().getElementAttributes(cx, index, attrsp);
     641                 : }
     642                 : 
     643                 : static JSBool
     644               0 : with_GetSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, unsigned *attrsp)
     645                 : {
     646               0 :     return obj->asWith().object().getSpecialAttributes(cx, sid, attrsp);
     647                 : }
     648                 : 
     649                 : static JSBool
     650               0 : with_SetGenericAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp)
     651                 : {
     652               0 :     return obj->asWith().object().setGenericAttributes(cx, id, attrsp);
     653                 : }
     654                 : 
     655                 : static JSBool
     656               0 : with_SetPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, unsigned *attrsp)
     657                 : {
     658               0 :     return obj->asWith().object().setPropertyAttributes(cx, name, attrsp);
     659                 : }
     660                 : 
     661                 : static JSBool
     662               0 : with_SetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *attrsp)
     663                 : {
     664               0 :     return obj->asWith().object().setElementAttributes(cx, index, attrsp);
     665                 : }
     666                 : 
     667                 : static JSBool
     668               0 : with_SetSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, unsigned *attrsp)
     669                 : {
     670               0 :     return obj->asWith().object().setSpecialAttributes(cx, sid, attrsp);
     671                 : }
     672                 : 
     673                 : static JSBool
     674               9 : with_DeleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict)
     675                 : {
     676               9 :     return obj->asWith().object().deleteProperty(cx, name, rval, strict);
     677                 : }
     678                 : 
     679                 : static JSBool
     680               0 : with_DeleteElement(JSContext *cx, JSObject *obj, uint32_t index, Value *rval, JSBool strict)
     681                 : {
     682               0 :     return obj->asWith().object().deleteElement(cx, index, rval, strict);
     683                 : }
     684                 : 
     685                 : static JSBool
     686               0 : with_DeleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict)
     687                 : {
     688               0 :     return obj->asWith().object().deleteSpecial(cx, sid, rval, strict);
     689                 : }
     690                 : 
     691                 : static JSBool
     692              54 : with_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
     693                 :                Value *statep, jsid *idp)
     694                 : {
     695              54 :     return obj->asWith().object().enumerate(cx, enum_op, statep, idp);
     696                 : }
     697                 : 
     698                 : static JSType
     699               0 : with_TypeOf(JSContext *cx, JSObject *obj)
     700                 : {
     701               0 :     return JSTYPE_OBJECT;
     702                 : }
     703                 : 
     704                 : static JSObject *
     705              18 : with_ThisObject(JSContext *cx, JSObject *obj)
     706                 : {
     707              18 :     return &obj->asWith().withThis();
     708                 : }
     709                 : 
     710                 : Class js::WithClass = {
     711                 :     "With",
     712                 :     JSCLASS_HAS_PRIVATE |
     713                 :     JSCLASS_HAS_RESERVED_SLOTS(WithObject::RESERVED_SLOTS) |
     714                 :     JSCLASS_IS_ANONYMOUS,
     715                 :     JS_PropertyStub,         /* addProperty */
     716                 :     JS_PropertyStub,         /* delProperty */
     717                 :     JS_PropertyStub,         /* getProperty */
     718                 :     JS_StrictPropertyStub,   /* setProperty */
     719                 :     JS_EnumerateStub,
     720                 :     JS_ResolveStub,
     721                 :     JS_ConvertStub,
     722                 :     NULL,                    /* finalize */
     723                 :     NULL,                    /* checkAccess */
     724                 :     NULL,                    /* call        */
     725                 :     NULL,                    /* construct   */
     726                 :     NULL,                    /* hasInstance */
     727                 :     NULL,                    /* trace       */
     728                 :     JS_NULL_CLASS_EXT,
     729                 :     {
     730                 :         with_LookupGeneric,
     731                 :         with_LookupProperty,
     732                 :         with_LookupElement,
     733                 :         with_LookupSpecial,
     734                 :         NULL,             /* defineGeneric */
     735                 :         NULL,             /* defineProperty */
     736                 :         NULL,             /* defineElement */
     737                 :         NULL,             /* defineSpecial */
     738                 :         with_GetGeneric,
     739                 :         with_GetProperty,
     740                 :         with_GetElement,
     741                 :         NULL,             /* getElementIfPresent */
     742                 :         with_GetSpecial,
     743                 :         with_SetGeneric,
     744                 :         with_SetProperty,
     745                 :         with_SetElement,
     746                 :         with_SetSpecial,
     747                 :         with_GetGenericAttributes,
     748                 :         with_GetPropertyAttributes,
     749                 :         with_GetElementAttributes,
     750                 :         with_GetSpecialAttributes,
     751                 :         with_SetGenericAttributes,
     752                 :         with_SetPropertyAttributes,
     753                 :         with_SetElementAttributes,
     754                 :         with_SetSpecialAttributes,
     755                 :         with_DeleteProperty,
     756                 :         with_DeleteElement,
     757                 :         with_DeleteSpecial,
     758                 :         with_Enumerate,
     759                 :         with_TypeOf,
     760                 :         NULL,             /* fix   */
     761                 :         with_ThisObject,
     762                 :         NULL,             /* clear */
     763                 :     }
     764                 : };
     765                 : 
     766                 : ClonedBlockObject *
     767           18638 : ClonedBlockObject::create(JSContext *cx, StaticBlockObject &block, StackFrame *fp)
     768                 : {
     769           37276 :     RootedVarTypeObject type(cx);
     770           18638 :     type = block.getNewType(cx);
     771           18638 :     if (!type)
     772               0 :         return NULL;
     773                 : 
     774                 :     HeapSlot *slots;
     775           18638 :     if (!PreallocateObjectDynamicSlots(cx, block.lastProperty(), &slots))
     776               0 :         return NULL;
     777                 : 
     778           37276 :     RootedVarShape shape(cx);
     779           18638 :     shape = block.lastProperty();
     780                 : 
     781           18638 :     JSObject *obj = JSObject::create(cx, FINALIZE_KIND, shape, type, slots);
     782           18638 :     if (!obj)
     783               0 :         return NULL;
     784                 : 
     785                 :     /* Set the parent if necessary, as for call objects. */
     786           18638 :     JSObject &global = fp->scopeChain().global();
     787           18638 :     if (&global != obj->getParent()) {
     788           18638 :         JS_ASSERT(obj->getParent() == NULL);
     789           18638 :         if (!obj->setParent(cx, &global))
     790               0 :             return NULL;
     791                 :     }
     792                 : 
     793           18638 :     JS_ASSERT(!obj->inDictionaryMode());
     794           18638 :     JS_ASSERT(obj->slotSpan() >= block.slotCount() + RESERVED_SLOTS);
     795                 : 
     796           18638 :     obj->setReservedSlot(DEPTH_SLOT, PrivateUint32Value(block.stackDepth()));
     797           18638 :     obj->setPrivate(js_FloatingFrameIfGenerator(cx, fp));
     798                 : 
     799           18638 :     if (obj->lastProperty()->extensibleParents() && !obj->generateOwnShape(cx))
     800               0 :         return NULL;
     801                 : 
     802           18638 :     return &obj->asClonedBlock();
     803                 : }
     804                 : 
     805                 : void
     806           18620 : ClonedBlockObject::put(JSContext *cx)
     807                 : {
     808           18620 :     StackFrame *fp = cx->fp();
     809           18620 :     JS_ASSERT(maybeStackFrame() == js_FloatingFrameIfGenerator(cx, fp));
     810                 : 
     811           18620 :     uint32_t count = slotCount();
     812           18620 :     uint32_t depth = stackDepth();
     813                 : 
     814                 :     /* The block and its locals must be on the current stack for GC safety. */
     815           18620 :     JS_ASSERT(depth <= uint32_t(cx->regs().sp - fp->base()));
     816           18620 :     JS_ASSERT(count <= uint32_t(cx->regs().sp - fp->base() - depth));
     817                 : 
     818                 :     /* See comments in CheckDestructuring in frontend/Parser.cpp. */
     819           18620 :     JS_ASSERT(count >= 1);
     820                 : 
     821           18620 :     copySlotRange(RESERVED_SLOTS, fp->base() + depth, count);
     822                 : 
     823                 :     /* We must clear the private slot even with errors. */
     824           18620 :     setPrivate(NULL);
     825           18620 :     fp->setScopeChainNoCallObj(enclosingScope());
     826           18620 : }
     827                 : 
     828                 : static JSBool
     829          569486 : block_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
     830                 : {
     831                 :     /*
     832                 :      * Block objects are never exposed to script, and the engine handles them
     833                 :      * with care. So unlike other getters, this one can assert (rather than
     834                 :      * check) certain invariants about obj.
     835                 :      */
     836          569486 :     ClonedBlockObject &block = obj->asClonedBlock();
     837          569486 :     unsigned index = (unsigned) JSID_TO_INT(id);
     838          569486 :     JS_ASSERT(index < block.slotCount());
     839                 : 
     840          569486 :     if (StackFrame *fp = block.maybeStackFrame()) {
     841          550148 :         fp = js_LiveFrameIfGenerator(fp);
     842          550148 :         index += fp->numFixed() + block.stackDepth();
     843          550148 :         JS_ASSERT(index < fp->numSlots());
     844          550148 :         *vp = fp->slots()[index];
     845          550148 :         return true;
     846                 :     }
     847                 : 
     848                 :     /* Values are in slots immediately following the class-reserved ones. */
     849           19338 :     JS_ASSERT(block.closedSlot(index) == *vp);
     850           19338 :     return true;
     851                 : }
     852                 : 
     853                 : static JSBool
     854             953 : block_setProperty(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
     855                 : {
     856             953 :     ClonedBlockObject &block = obj->asClonedBlock();
     857             953 :     unsigned index = (unsigned) JSID_TO_INT(id);
     858             953 :     JS_ASSERT(index < block.slotCount());
     859                 : 
     860             953 :     if (StackFrame *fp = block.maybeStackFrame()) {
     861             915 :         fp = js_LiveFrameIfGenerator(fp);
     862             915 :         index += fp->numFixed() + block.stackDepth();
     863             915 :         JS_ASSERT(index < fp->numSlots());
     864             915 :         fp->slots()[index] = *vp;
     865             915 :         return true;
     866                 :     }
     867                 : 
     868                 :     /*
     869                 :      * The value in *vp will be written back to the slot in obj that was
     870                 :      * allocated when this let binding was defined.
     871                 :      */
     872              38 :     return true;
     873                 : }
     874                 : 
     875                 : StaticBlockObject *
     876          562850 : StaticBlockObject::create(JSContext *cx)
     877                 : {
     878         1125700 :     RootedVarTypeObject type(cx);
     879          562850 :     type = cx->compartment->getEmptyType(cx);
     880          562850 :     if (!type)
     881               0 :         return NULL;
     882                 : 
     883         1125700 :     RootedVarShape emptyBlockShape(cx);
     884          562850 :     emptyBlockShape = EmptyShape::getInitialShape(cx, &BlockClass, NULL, NULL, FINALIZE_KIND);
     885          562850 :     if (!emptyBlockShape)
     886               0 :         return NULL;
     887                 : 
     888          562850 :     JSObject *obj = JSObject::create(cx, FINALIZE_KIND, emptyBlockShape, type, NULL);
     889          562850 :     if (!obj)
     890               0 :         return NULL;
     891                 : 
     892          562850 :     return &obj->asStaticBlock();
     893                 : }
     894                 : 
     895                 : const Shape *
     896          892471 : StaticBlockObject::addVar(JSContext *cx, jsid id, int index, bool *redeclared)
     897                 : {
     898          892471 :     JS_ASSERT(JSID_IS_ATOM(id) || (JSID_IS_INT(id) && JSID_TO_INT(id) == index));
     899                 : 
     900          892471 :     *redeclared = false;
     901                 : 
     902                 :     /* Inline JSObject::addProperty in order to trap the redefinition case. */
     903                 :     Shape **spp;
     904          892471 :     if (Shape::search(cx, lastProperty(), id, &spp, true)) {
     905             171 :         *redeclared = true;
     906             171 :         return NULL;
     907                 :     }
     908                 : 
     909                 :     /*
     910                 :      * Don't convert this object to dictionary mode so that we can clone the
     911                 :      * block's shape later.
     912                 :      */
     913          892300 :     uint32_t slot = JSSLOT_FREE(&BlockClass) + index;
     914                 :     return addPropertyInternal(cx, id, block_getProperty, block_setProperty,
     915                 :                                slot, JSPROP_ENUMERATE | JSPROP_PERMANENT,
     916                 :                                Shape::HAS_SHORTID, index, spp,
     917          892300 :                                /* allowDictionary = */ false);
     918                 : }
     919                 : 
     920                 : Class js::BlockClass = {
     921                 :     "Block",
     922                 :     JSCLASS_HAS_PRIVATE |
     923                 :     JSCLASS_HAS_RESERVED_SLOTS(BlockObject::RESERVED_SLOTS) |
     924                 :     JSCLASS_IS_ANONYMOUS,
     925                 :     JS_PropertyStub,         /* addProperty */
     926                 :     JS_PropertyStub,         /* delProperty */
     927                 :     JS_PropertyStub,         /* getProperty */
     928                 :     JS_StrictPropertyStub,   /* setProperty */
     929                 :     JS_EnumerateStub,
     930                 :     JS_ResolveStub,
     931                 :     JS_ConvertStub
     932                 : };
     933                 : 
     934                 : #if JS_HAS_XDR
     935                 : 
     936                 : #define NO_PARENT_INDEX UINT32_MAX
     937                 : 
     938                 : static uint32_t
     939          246235 : FindObjectIndex(JSObjectArray *array, JSObject *obj)
     940                 : {
     941                 :     size_t i;
     942                 : 
     943          246235 :     if (array) {
     944          246235 :         i = array->length;
     945         1149761 :         do {
     946                 : 
     947         1218830 :             if (array->vector[--i] == obj)
     948           69069 :                 return i;
     949                 :         } while (i != 0);
     950                 :     }
     951                 : 
     952          177166 :     return NO_PARENT_INDEX;
     953                 : }
     954                 : 
     955                 : bool
     956          359775 : js::XDRStaticBlockObject(JSXDRState *xdr, JSScript *script, StaticBlockObject **objp)
     957                 : {
     958          359775 :     JSContext *cx = xdr->cx;
     959                 : 
     960          359775 :     StaticBlockObject *obj = NULL;
     961          359775 :     uint32_t parentId = 0;
     962          359775 :     uint32_t count = 0;
     963          359775 :     uint32_t depthAndCount = 0;
     964          359775 :     if (xdr->mode == JSXDR_ENCODE) {
     965          246235 :         obj = *objp;
     966          246235 :         parentId = JSScript::isValidOffset(script->objectsOffset)
     967          246235 :                    ? FindObjectIndex(script->objects(), obj->enclosingBlock())
     968          492470 :                    : NO_PARENT_INDEX;
     969          246235 :         uint32_t depth = obj->stackDepth();
     970          246235 :         JS_ASSERT(depth <= UINT16_MAX);
     971          246235 :         count = obj->slotCount();
     972          246235 :         JS_ASSERT(count <= UINT16_MAX);
     973          246235 :         depthAndCount = (depth << 16) | uint16_t(count);
     974                 :     }
     975                 : 
     976                 :     /* First, XDR the parent atomid. */
     977          359775 :     if (!JS_XDRUint32(xdr, &parentId))
     978               0 :         return false;
     979                 : 
     980          359775 :     if (xdr->mode == JSXDR_DECODE) {
     981          113540 :         obj = StaticBlockObject::create(cx);
     982          113540 :         if (!obj)
     983               0 :             return false;
     984          113540 :         *objp = obj;
     985                 : 
     986                 :         /*
     987                 :          * If there's a parent id, then get the parent out of our script's
     988                 :          * object array. We know that we XDR block object in outer-to-inner
     989                 :          * order, which means that getting the parent now will work.
     990                 :          */
     991                 :         obj->setEnclosingBlock(parentId == NO_PARENT_INDEX
     992                 :                                ? NULL
     993          113540 :                                : &script->getObject(parentId)->asStaticBlock());
     994                 :     }
     995                 : 
     996          719550 :     AutoObjectRooter tvr(cx, obj);
     997                 : 
     998          359775 :     if (!JS_XDRUint32(xdr, &depthAndCount))
     999               0 :         return false;
    1000                 : 
    1001          359775 :     if (xdr->mode == JSXDR_DECODE) {
    1002          113540 :         uint32_t depth = uint16_t(depthAndCount >> 16);
    1003          113540 :         count = uint16_t(depthAndCount);
    1004          113540 :         obj->setStackDepth(depth);
    1005                 : 
    1006                 :         /*
    1007                 :          * XDR the block object's properties. We know that there are 'count'
    1008                 :          * properties to XDR, stored as id/shortid pairs.
    1009                 :          */
    1010          250075 :         for (unsigned i = 0; i < count; i++) {
    1011                 :             JSAtom *atom;
    1012          136535 :             if (!js_XDRAtom(xdr, &atom))
    1013               0 :                 return false;
    1014                 : 
    1015                 :             /* The empty string indicates an int id. */
    1016                 :             jsid id = atom != cx->runtime->emptyString
    1017          136058 :                       ? ATOM_TO_JSID(atom)
    1018          272593 :                       : INT_TO_JSID(i);
    1019                 : 
    1020                 :             bool redeclared;
    1021          136535 :             if (!obj->addVar(cx, id, i, &redeclared)) {
    1022               0 :                 JS_ASSERT(!redeclared);
    1023               0 :                 return false;
    1024                 :             }
    1025                 :         }
    1026                 :     } else {
    1027          492470 :         AutoShapeVector shapes(cx);
    1028          246235 :         shapes.growBy(count);
    1029                 : 
    1030          548522 :         for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) {
    1031          302287 :             const Shape *shape = &r.front();
    1032          302287 :             shapes[shape->shortid()] = shape;
    1033                 :         }
    1034                 : 
    1035                 :         /*
    1036                 :          * XDR the block object's properties. We know that there are 'count'
    1037                 :          * properties to XDR, stored as id/shortid pairs.
    1038                 :          */
    1039          548522 :         for (unsigned i = 0; i < count; i++) {
    1040          302287 :             const Shape *shape = shapes[i];
    1041          302287 :             JS_ASSERT(shape->getter() == block_getProperty);
    1042          302287 :             JS_ASSERT(unsigned(shape->shortid()) == i);
    1043                 : 
    1044          302287 :             jsid propid = shape->propid();
    1045          302287 :             JS_ASSERT(JSID_IS_ATOM(propid) || JSID_IS_INT(propid));
    1046                 : 
    1047                 :             /* The empty string indicates an int id. */
    1048          302287 :             JSAtom *atom = JSID_IS_ATOM(propid)
    1049                 :                            ? JSID_TO_ATOM(propid)
    1050          302287 :                            : cx->runtime->emptyString;
    1051                 : 
    1052          302287 :             if (!js_XDRAtom(xdr, &atom))
    1053               0 :                 return false;
    1054                 :         }
    1055                 :     }
    1056          359775 :     return true;
    1057                 : }
    1058                 : 
    1059                 : #endif  /* JS_HAS_XDR */

Generated by: LCOV version 1.7