LCOV - app.info - js/src/vm/ScopeObject.cpp

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