LCOV - code coverage report
Current view: directory - js/src/vm - ScopeObject.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 433 347 80.1 %
Date: 2012-04-07 Functions: 51 31 60.8 %

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

Generated by: LCOV version 1.7