LCOV - code coverage report
Current view: directory - js/src - jsobj.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 3092 2126 68.8 %
Date: 2012-06-02 Functions: 198 175 88.4 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=8 sw=4 et tw=79:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is Mozilla Communicator client code, released
      18                 :  * March 31, 1998.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  * Netscape Communications Corporation.
      22                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      23                 :  * the Initial Developer. All Rights Reserved.
      24                 :  *
      25                 :  * Contributor(s):
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : /*
      42                 :  * JS object implementation.
      43                 :  */
      44                 : #include <stdlib.h>
      45                 : #include <string.h>
      46                 : 
      47                 : #include "mozilla/Util.h"
      48                 : 
      49                 : #include "jstypes.h"
      50                 : #include "jsutil.h"
      51                 : #include "jshash.h"
      52                 : #include "jsdhash.h"
      53                 : #include "jsprf.h"
      54                 : #include "jsapi.h"
      55                 : #include "jsarray.h"
      56                 : #include "jsatom.h"
      57                 : #include "jsbool.h"
      58                 : #include "jscntxt.h"
      59                 : #include "jsversion.h"
      60                 : #include "jsfun.h"
      61                 : #include "jsgc.h"
      62                 : #include "jsgcmark.h"
      63                 : #include "jsinterp.h"
      64                 : #include "jsiter.h"
      65                 : #include "jslock.h"
      66                 : #include "jsnum.h"
      67                 : #include "jsobj.h"
      68                 : #include "jsonparser.h"
      69                 : #include "jsopcode.h"
      70                 : #include "jsprobes.h"
      71                 : #include "jsproxy.h"
      72                 : #include "jsscope.h"
      73                 : #include "jsscript.h"
      74                 : #include "jsstr.h"
      75                 : #include "jsdbgapi.h"
      76                 : #include "json.h"
      77                 : #include "jswatchpoint.h"
      78                 : #include "jswrapper.h"
      79                 : 
      80                 : #include "builtin/MapObject.h"
      81                 : #include "frontend/BytecodeCompiler.h"
      82                 : #include "frontend/BytecodeEmitter.h"
      83                 : #include "frontend/Parser.h"
      84                 : #include "js/MemoryMetrics.h"
      85                 : 
      86                 : #include "jsarrayinlines.h"
      87                 : #include "jsatominlines.h"
      88                 : #include "jsinterpinlines.h"
      89                 : #include "jsobjinlines.h"
      90                 : #include "jsscopeinlines.h"
      91                 : #include "jsscriptinlines.h"
      92                 : 
      93                 : #include "vm/MethodGuard-inl.h"
      94                 : #include "vm/StringBuffer-inl.h"
      95                 : 
      96                 : #if JS_HAS_XML_SUPPORT
      97                 : #include "jsxml.h"
      98                 : #endif
      99                 : 
     100                 : #if JS_HAS_XDR
     101                 : #include "jsxdrapi.h"
     102                 : #endif
     103                 : 
     104                 : #include "jsautooplen.h"
     105                 : 
     106                 : using namespace mozilla;
     107                 : using namespace js;
     108                 : using namespace js::gc;
     109                 : using namespace js::types;
     110                 : 
     111                 : JS_STATIC_ASSERT(int32_t((JSObject::NELEMENTS_LIMIT - 1) * sizeof(Value)) == int64_t((JSObject::NELEMENTS_LIMIT - 1) * sizeof(Value)));
     112                 : 
     113                 : Class js::ObjectClass = {
     114                 :     js_Object_str,
     115                 :     JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
     116                 :     JS_PropertyStub,         /* addProperty */
     117                 :     JS_PropertyStub,         /* delProperty */
     118                 :     JS_PropertyStub,         /* getProperty */
     119                 :     JS_StrictPropertyStub,   /* setProperty */
     120                 :     JS_EnumerateStub,
     121                 :     JS_ResolveStub,
     122                 :     JS_ConvertStub
     123                 : };
     124                 : 
     125                 : JS_FRIEND_API(JSObject *)
     126         6924829 : JS_ObjectToInnerObject(JSContext *cx, JSObject *obj)
     127                 : {
     128         6924829 :     if (!obj) {
     129               0 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
     130               0 :         return NULL;
     131                 :     }
     132         6924829 :     OBJ_TO_INNER_OBJECT(cx, obj);
     133         6924829 :     return obj;
     134                 : }
     135                 : 
     136                 : JS_FRIEND_API(JSObject *)
     137         3947421 : JS_ObjectToOuterObject(JSContext *cx, JSObject *obj)
     138                 : {
     139         3947421 :     OBJ_TO_OUTER_OBJECT(cx, obj);
     140         3947421 :     return obj;
     141                 : }
     142                 : 
     143                 : #if JS_HAS_OBJ_PROTO_PROP
     144                 : 
     145                 : static JSBool
     146                 : obj_getProto(JSContext *cx, JSObject *obj, jsid id, Value *vp);
     147                 : 
     148                 : static JSBool
     149                 : obj_setProto(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp);
     150                 : 
     151                 : JSPropertySpec object_props[] = {
     152                 :     {js_proto_str, 0, JSPROP_PERMANENT|JSPROP_SHARED, obj_getProto, obj_setProto},
     153                 :     {0,0,0,0,0}
     154                 : };
     155                 : 
     156                 : static JSBool
     157            1455 : obj_getProto(JSContext *cx, JSObject *obj, jsid id, Value *vp)
     158                 : {
     159                 :     /* Let CheckAccess get the slot's value, based on the access mode. */
     160                 :     unsigned attrs;
     161            1455 :     id = ATOM_TO_JSID(cx->runtime->atomState.protoAtom);
     162            1455 :     return CheckAccess(cx, obj, id, JSACC_PROTO, vp, &attrs);
     163                 : }
     164                 : 
     165                 : size_t sSetProtoCalled = 0;
     166                 : 
     167                 : static JSBool
     168           15025 : obj_setProto(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
     169                 : {
     170           15025 :     if (!cx->runningWithTrustedPrincipals())
     171             855 :         ++sSetProtoCalled;
     172                 : 
     173                 :     /* ECMAScript 5 8.6.2 forbids changing [[Prototype]] if not [[Extensible]]. */
     174           15025 :     if (!obj->isExtensible()) {
     175               0 :         obj->reportNotExtensible(cx);
     176               0 :         return false;
     177                 :     }
     178                 : 
     179           15025 :     if (!vp->isObjectOrNull())
     180             144 :         return true;
     181                 : 
     182           14881 :     JSObject *pobj = vp->toObjectOrNull();
     183                 :     unsigned attrs;
     184           14881 :     id = ATOM_TO_JSID(cx->runtime->atomState.protoAtom);
     185           14881 :     if (!CheckAccess(cx, obj, id, JSAccessMode(JSACC_PROTO|JSACC_WRITE), vp, &attrs))
     186               0 :         return false;
     187                 : 
     188           14881 :     return SetProto(cx, obj, pobj, true);
     189                 : }
     190                 : 
     191                 : #else  /* !JS_HAS_OBJ_PROTO_PROP */
     192                 : 
     193                 : #define object_props NULL
     194                 : 
     195                 : #endif /* !JS_HAS_OBJ_PROTO_PROP */
     196                 : 
     197                 : static bool
     198            2408 : MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap, JSSharpInfo *value)
     199                 : {
     200            2408 :     JS_CHECK_RECURSION(cx, return NULL);
     201                 : 
     202                 :     JSIdArray *ida;
     203                 : 
     204            2408 :     JSSharpObjectMap *map = &cx->sharpObjectMap;
     205            2408 :     JS_ASSERT(map->depth >= 1);
     206            2408 :     JSSharpInfo sharpid;
     207            2408 :     JSSharpTable::Ptr p = map->table.lookup(obj);
     208            2408 :     if (!p) {
     209            2407 :         if (!map->table.put(obj, sharpid))
     210               0 :             return false;
     211                 : 
     212            2407 :         ida = JS_Enumerate(cx, obj);
     213            2407 :         if (!ida)
     214               0 :             return false;
     215                 : 
     216            2407 :         bool ok = true;
     217            5242 :         for (int i = 0, length = ida->length; i < length; i++) {
     218            2835 :             jsid id = ida->vector[i];
     219                 :             JSObject *obj2;
     220                 :             JSProperty *prop;
     221            2835 :             ok = obj->lookupGeneric(cx, id, &obj2, &prop);
     222            2835 :             if (!ok)
     223               0 :                 break;
     224            2835 :             if (!prop)
     225               0 :                 continue;
     226                 :             bool hasGetter, hasSetter;
     227            5670 :             AutoValueRooter v(cx);
     228            5670 :             AutoValueRooter setter(cx);
     229            2835 :             if (obj2->isNative()) {
     230            1741 :                 const Shape *shape = (Shape *) prop;
     231            1741 :                 hasGetter = shape->hasGetterValue();
     232            1741 :                 hasSetter = shape->hasSetterValue();
     233            1741 :                 if (hasGetter)
     234               2 :                     v.set(shape->getterValue());
     235            1741 :                 if (hasSetter)
     236               1 :                     setter.set(shape->setterValue());
     237                 :             } else {
     238            1094 :                 hasGetter = hasSetter = false;
     239                 :             }
     240            2835 :             if (hasSetter) {
     241                 :                 /* Mark the getter, then set val to setter. */
     242               1 :                 if (hasGetter && v.value().isObject()) {
     243               1 :                     ok = MarkSharpObjects(cx, &v.value().toObject(), NULL, NULL);
     244               1 :                     if (!ok)
     245                 :                         break;
     246                 :                 }
     247               1 :                 v.set(setter.value());
     248            2834 :             } else if (!hasGetter) {
     249            2833 :                 ok = obj->getGeneric(cx, id, v.addr());
     250            2833 :                 if (!ok)
     251                 :                     break;
     252                 :             }
     253            2835 :             if (v.value().isObject() && !MarkSharpObjects(cx, &v.value().toObject(), NULL, NULL)) {
     254               0 :                 ok = false;
     255                 :                 break;
     256                 :             }
     257                 :         }
     258            2407 :         if (!ok || !idap)
     259            1588 :             JS_DestroyIdArray(cx, ida);
     260            2407 :         if (!ok)
     261               0 :             return false;
     262                 :     } else {
     263               1 :         if (!p->value.hasGen && !p->value.isSharp) {
     264               1 :             p->value.hasGen = true;
     265                 :         }
     266               1 :         sharpid = p->value;
     267               1 :         ida = NULL;
     268                 :     }
     269            2408 :     if (idap)
     270             819 :         *idap = ida;
     271            2408 :     if (value)
     272             819 :         *value = sharpid;
     273            2408 :     return true;
     274                 : }
     275                 : 
     276                 : bool
     277             871 : js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap, bool *alreadySeen, bool *isSharp)
     278                 : {
     279             871 :     if (!JS_CHECK_OPERATION_LIMIT(cx))
     280               0 :         return false;
     281                 : 
     282             871 :     *alreadySeen = false;
     283                 : 
     284             871 :     JSSharpObjectMap *map = &cx->sharpObjectMap;
     285                 : 
     286             871 :     JS_ASSERT_IF(map->depth == 0, map->table.count() == 0);
     287             871 :     JS_ASSERT_IF(map->table.count() == 0, map->depth == 0);
     288                 : 
     289             871 :     JSSharpTable::Ptr p;
     290             871 :     JSSharpInfo sharpid;
     291             871 :     JSIdArray *ida = NULL;
     292                 : 
     293                 :     /* From this point the control must flow either through out: or bad:. */
     294             871 :     if (map->depth == 0) {
     295             819 :         JS_KEEP_ATOMS(cx->runtime);
     296                 : 
     297                 :         /*
     298                 :          * Although MarkSharpObjects tries to avoid invoking getters,
     299                 :          * it ends up doing so anyway under some circumstances; for
     300                 :          * example, if a wrapped object has getters, the wrapper will
     301                 :          * prevent MarkSharpObjects from recognizing them as such.
     302                 :          * This could lead to js_LeaveSharpObject being called while
     303                 :          * MarkSharpObjects is still working.
     304                 :          *
     305                 :          * Increment map->depth while we call MarkSharpObjects, to
     306                 :          * ensure that such a call doesn't free the hash table we're
     307                 :          * still using.
     308                 :          */
     309             819 :         map->depth = 1;
     310             819 :         bool success = MarkSharpObjects(cx, obj, &ida, &sharpid);
     311             819 :         JS_ASSERT(map->depth == 1);
     312             819 :         map->depth = 0;
     313             819 :         if (!success)
     314               0 :             goto bad;
     315             819 :         JS_ASSERT(!sharpid.isSharp);
     316             819 :         if (!idap) {
     317             261 :             JS_DestroyIdArray(cx, ida);
     318             261 :             ida = NULL;
     319                 :         }
     320                 :     } else {
     321                 :         /*
     322                 :          * It's possible that the value of a property has changed from the
     323                 :          * first time the object's properties are traversed (when the property
     324                 :          * ids are entered into the hash table) to the second (when they are
     325                 :          * converted to strings), i.e., the JSObject::getProperty() call is not
     326                 :          * idempotent.
     327                 :          */
     328              52 :         p = map->table.lookup(obj);
     329              52 :         if (!p) {
     330               9 :             if (!map->table.put(obj, sharpid))
     331               0 :                 goto bad;
     332               9 :             goto out;
     333                 :         }
     334              43 :         sharpid = p->value;
     335                 :     }
     336                 : 
     337             862 :     if (sharpid.isSharp || sharpid.hasGen)
     338               0 :         *alreadySeen = true;
     339                 : 
     340                 : out:
     341             871 :     if (!sharpid.isSharp) {
     342             871 :         if (idap && !ida) {
     343              40 :             ida = JS_Enumerate(cx, obj);
     344              40 :             if (!ida)
     345               0 :                 goto bad;
     346                 :         }
     347             871 :         map->depth++;
     348                 :     }
     349                 : 
     350             871 :     if (idap)
     351             598 :         *idap = ida;
     352             871 :     *isSharp = sharpid.isSharp;
     353             871 :     return true;
     354                 : 
     355                 : bad:
     356                 :     /* Clean up the sharpObjectMap table on outermost error. */
     357               0 :     if (map->depth == 0) {
     358               0 :         JS_UNKEEP_ATOMS(cx->runtime);
     359               0 :         map->sharpgen = 0;
     360               0 :         map->table.clear();
     361                 :     }
     362               0 :     return false;
     363                 : }
     364                 : 
     365                 : void
     366             871 : js_LeaveSharpObject(JSContext *cx, JSIdArray **idap)
     367                 : {
     368             871 :     JSSharpObjectMap *map = &cx->sharpObjectMap;
     369             871 :     JS_ASSERT(map->depth > 0);
     370             871 :     if (--map->depth == 0) {
     371             819 :         JS_UNKEEP_ATOMS(cx->runtime);
     372             819 :         map->sharpgen = 0;
     373             819 :         map->table.clear();
     374                 :     }
     375             871 :     if (idap) {
     376             598 :         if (JSIdArray *ida = *idap) {
     377             598 :             JS_DestroyIdArray(cx, ida);
     378             598 :             *idap = NULL;
     379                 :         }
     380                 :     }
     381             871 : }
     382                 : 
     383                 : void
     384               3 : js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map)
     385                 : {
     386               3 :     JS_ASSERT(map->depth > 0);
     387                 : 
     388                 :     /*
     389                 :      * During recursive calls to MarkSharpObjects a non-native object or
     390                 :      * object with a custom getProperty method can potentially return an
     391                 :      * unrooted value or even cut from the object graph an argument of one of
     392                 :      * MarkSharpObjects recursive invocations. So we must protect map->table
     393                 :      * entries against GC.
     394                 :      *
     395                 :      * We can not simply use JSTempValueRooter to mark the obj argument of
     396                 :      * MarkSharpObjects during recursion as we have to protect *all* entries
     397                 :      * in JSSharpObjectMap including those that contains otherwise unreachable
     398                 :      * objects just allocated through custom getProperty. Otherwise newer
     399                 :      * allocations can re-use the address of an object stored in the hashtable
     400                 :      * confusing js_EnterSharpObject. So to address the problem we simply
     401                 :      * mark all objects from map->table.
     402                 :      *
     403                 :      * An alternative "proper" solution is to use JSTempValueRooter in
     404                 :      * MarkSharpObjects with code to remove during finalization entries
     405                 :      * with otherwise unreachable objects. But this is way too complex
     406                 :      * to justify spending efforts.
     407                 :      */
     408              12 :     for (JSSharpTable::Range r = map->table.all(); !r.empty(); r.popFront()) {
     409               9 :         JSObject *tmp = r.front().key;
     410               9 :         MarkObjectRoot(trc, &tmp, "sharp table entry");
     411               9 :         JS_ASSERT(tmp == r.front().key);
     412                 :     }
     413               3 : }
     414                 : 
     415                 : #if JS_HAS_TOSOURCE
     416                 : static JSBool
     417             598 : obj_toSource(JSContext *cx, unsigned argc, Value *vp)
     418                 : {
     419             598 :     bool comma = false;
     420                 :     const jschar *vchars;
     421                 :     size_t vlength;
     422                 :     Value *val;
     423                 :     JSString *gsop[2];
     424                 : 
     425             598 :     JS_CHECK_RECURSION(cx, return JS_FALSE);
     426                 : 
     427                 :     Value localroot[4];
     428             598 :     PodArrayZero(localroot);
     429            1196 :     AutoArrayRooter tvr(cx, ArrayLength(localroot), localroot);
     430                 : 
     431                 :     /* If outermost, we need parentheses to be an expression, not a block. */
     432             598 :     bool outermost = (cx->sharpObjectMap.depth == 0);
     433                 : 
     434             598 :     JSObject *obj = ToObject(cx, &vp[1]);
     435             598 :     if (!obj)
     436               0 :         return false;
     437                 : 
     438                 :     JSIdArray *ida;
     439             598 :     bool alreadySeen = false;
     440             598 :     bool isSharp = false;
     441             598 :     if (!js_EnterSharpObject(cx, obj, &ida, &alreadySeen, &isSharp))
     442               0 :         return false;
     443                 : 
     444             598 :     if (!ida) {
     445                 :         /*
     446                 :          * We've already seen obj, so don't serialize it again (particularly as
     447                 :          * we might recur in the process): just serialize an empty object.
     448                 :          */
     449               0 :         JS_ASSERT(alreadySeen);
     450               0 :         JSString *str = js_NewStringCopyZ(cx, "{}");
     451               0 :         if (!str)
     452               0 :             return false;
     453               0 :         vp->setString(str);
     454               0 :         return true;
     455                 :     }
     456                 : 
     457             598 :     JS_ASSERT(!isSharp);
     458             598 :     if (alreadySeen) {
     459               0 :         JSSharpTable::Ptr p = cx->sharpObjectMap.table.lookup(obj);
     460               0 :         JS_ASSERT(p);
     461               0 :         JS_ASSERT(!p->value.isSharp);
     462               0 :         p->value.isSharp = true;
     463                 :     }
     464                 : 
     465                 :     /* Automatically call js_LeaveSharpObject when we leave this frame. */
     466                 :     class AutoLeaveSharpObject {
     467                 :         JSContext *cx;
     468                 :         JSIdArray *ida;
     469                 :       public:
     470             598 :         AutoLeaveSharpObject(JSContext *cx, JSIdArray *ida) : cx(cx), ida(ida) {}
     471             598 :         ~AutoLeaveSharpObject() {
     472             598 :             js_LeaveSharpObject(cx, &ida);
     473             598 :         }
     474            1196 :     } autoLeaveSharpObject(cx, ida);
     475                 : 
     476            1196 :     StringBuffer buf(cx);
     477             598 :     if (outermost && !buf.append('('))
     478               0 :         return false;
     479             598 :     if (!buf.append('{'))
     480               0 :         return false;
     481                 : 
     482                 :     /*
     483                 :      * We have four local roots for cooked and raw value GC safety.  Hoist the
     484                 :      * "localroot + 2" out of the loop using the val local, which refers to
     485                 :      * the raw (unconverted, "uncooked") values.
     486                 :      */
     487             598 :     val = localroot + 2;
     488                 : 
     489            2292 :     for (int i = 0; i < ida->length; i++) {
     490                 :         /* Get strings for id and value and GC-root them via vp. */
     491            1712 :         jsid id = ida->vector[i];
     492                 :         JSLinearString *idstr;
     493                 : 
     494                 :         JSObject *obj2;
     495                 :         JSProperty *prop;
     496            1712 :         if (!obj->lookupGeneric(cx, id, &obj2, &prop))
     497               0 :             return false;
     498                 : 
     499                 :         /*
     500                 :          * Convert id to a value and then to a string.  Decide early whether we
     501                 :          * prefer get/set or old getter/setter syntax.
     502                 :          */
     503            1712 :         JSString *s = ToString(cx, IdToValue(id));
     504            1712 :         if (!s || !(idstr = s->ensureLinear(cx)))
     505               0 :             return false;
     506                 : 
     507            1712 :         int valcnt = 0;
     508            1712 :         if (prop) {
     509            1712 :             bool doGet = true;
     510            1712 :             if (obj2->isNative()) {
     511            1712 :                 const Shape *shape = (Shape *) prop;
     512            1712 :                 unsigned attrs = shape->attributes();
     513            1712 :                 if (attrs & JSPROP_GETTER) {
     514               0 :                     doGet = false;
     515               0 :                     val[valcnt] = shape->getterValue();
     516               0 :                     gsop[valcnt] = cx->runtime->atomState.getAtom;
     517               0 :                     valcnt++;
     518                 :                 }
     519            1712 :                 if (attrs & JSPROP_SETTER) {
     520               0 :                     doGet = false;
     521               0 :                     val[valcnt] = shape->setterValue();
     522               0 :                     gsop[valcnt] = cx->runtime->atomState.setAtom;
     523               0 :                     valcnt++;
     524                 :                 }
     525                 :             }
     526            1712 :             if (doGet) {
     527            1712 :                 valcnt = 1;
     528            1712 :                 gsop[0] = NULL;
     529            1712 :                 if (!obj->getGeneric(cx, id, &val[0]))
     530               0 :                     return false;
     531                 :             }
     532                 :         }
     533                 : 
     534                 :         /*
     535                 :          * If id is a string that's not an identifier, or if it's a negative
     536                 :          * integer, then it must be quoted.
     537                 :          */
     538            3434 :         if (JSID_IS_ATOM(id)
     539            1702 :             ? !IsIdentifier(idstr)
     540              20 :             : (!JSID_IS_INT(id) || JSID_TO_INT(id) < 0)) {
     541               0 :             s = js_QuoteString(cx, idstr, jschar('\''));
     542               0 :             if (!s || !(idstr = s->ensureLinear(cx)))
     543               0 :                 return false;
     544                 :         }
     545                 : 
     546            3406 :         for (int j = 0; j < valcnt; j++) {
     547                 :             /*
     548                 :              * Censor an accessor descriptor getter or setter part if it's
     549                 :              * undefined.
     550                 :              */
     551            1712 :             if (gsop[j] && val[j].isUndefined())
     552               0 :                 continue;
     553                 : 
     554                 :             /* Convert val[j] to its canonical source form. */
     555            1712 :             JSString *valstr = js_ValueToSource(cx, val[j]);
     556            1712 :             if (!valstr)
     557              18 :                 return false;
     558            1694 :             localroot[j].setString(valstr);             /* local root */
     559            1694 :             vchars = valstr->getChars(cx);
     560            1694 :             if (!vchars)
     561               0 :                 return false;
     562            1694 :             vlength = valstr->length();
     563                 : 
     564                 :             /*
     565                 :              * Remove '(function ' from the beginning of valstr and ')' from the
     566                 :              * end so that we can put "get" in front of the function definition.
     567                 :              */
     568            1694 :             if (gsop[j] && IsFunctionObject(val[j])) {
     569               0 :                 const jschar *start = vchars;
     570               0 :                 const jschar *end = vchars + vlength;
     571                 : 
     572               0 :                 uint8_t parenChomp = 0;
     573               0 :                 if (vchars[0] == '(') {
     574               0 :                     vchars++;
     575               0 :                     parenChomp = 1;
     576                 :                 }
     577                 : 
     578                 :                 /* Try to jump "function" keyword. */
     579               0 :                 if (vchars)
     580               0 :                     vchars = js_strchr_limit(vchars, ' ', end);
     581                 : 
     582                 :                 /*
     583                 :                  * Jump over the function's name: it can't be encoded as part
     584                 :                  * of an ECMA getter or setter.
     585                 :                  */
     586               0 :                 if (vchars)
     587               0 :                     vchars = js_strchr_limit(vchars, '(', end);
     588                 : 
     589               0 :                 if (vchars) {
     590               0 :                     if (*vchars == ' ')
     591               0 :                         vchars++;
     592               0 :                     vlength = end - vchars - parenChomp;
     593                 :                 } else {
     594               0 :                     gsop[j] = NULL;
     595               0 :                     vchars = start;
     596                 :                 }
     597                 :             }
     598                 : 
     599            1694 :             if (comma && !buf.append(", "))
     600               0 :                 return false;
     601            1694 :             comma = true;
     602                 : 
     603            1694 :             if (gsop[j])
     604               0 :                 if (!buf.append(gsop[j]) || !buf.append(' '))
     605               0 :                     return false;
     606                 : 
     607            1694 :             if (!buf.append(idstr))
     608               0 :                 return false;
     609            1694 :             if (!buf.append(gsop[j] ? ' ' : ':'))
     610               0 :                 return false;
     611                 : 
     612            1694 :             if (!buf.append(vchars, vlength))
     613               0 :                 return false;
     614                 :         }
     615                 :     }
     616                 : 
     617             580 :     if (!buf.append('}'))
     618               0 :         return false;
     619             580 :     if (outermost && !buf.append(')'))
     620               0 :         return false;
     621                 : 
     622             580 :     JSString *str = buf.finishString();
     623             580 :     if (!str)
     624               0 :         return false;
     625             580 :     vp->setString(str);
     626             580 :     return true;
     627                 : }
     628                 : #endif /* JS_HAS_TOSOURCE */
     629                 : 
     630                 : namespace js {
     631                 : 
     632                 : JSString *
     633           49459 : obj_toStringHelper(JSContext *cx, JSObject *obj)
     634                 : {
     635           49459 :     if (obj->isProxy())
     636            1948 :         return Proxy::obj_toString(cx, obj);
     637                 : 
     638           95022 :     StringBuffer sb(cx);
     639           47511 :     const char *className = obj->getClass()->name;
     640           95022 :     if (!sb.append("[object ") || !sb.appendInflated(className, strlen(className)) || 
     641           47511 :         !sb.append("]"))
     642                 :     {
     643               0 :         return NULL;
     644                 :     }
     645           47511 :     return sb.finishString();
     646                 : }
     647                 : 
     648                 : JSObject *
     649            4110 : NonNullObject(JSContext *cx, const Value &v)
     650                 : {
     651            4110 :     if (v.isPrimitive()) {
     652             162 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
     653             162 :         return NULL;
     654                 :     }
     655            3948 :     return &v.toObject();
     656                 : }
     657                 : 
     658                 : const char *
     659            2276 : InformalValueTypeName(const Value &v)
     660                 : {
     661            2276 :     if (v.isObject())
     662            2114 :         return v.toObject().getClass()->name;
     663             162 :     if (v.isString())
     664               0 :         return "string";
     665             162 :     if (v.isNumber())
     666               0 :         return "number";
     667             162 :     if (v.isBoolean())
     668               0 :         return "boolean";
     669             162 :     if (v.isNull())
     670              72 :         return "null";
     671              90 :     if (v.isUndefined())
     672              90 :         return "undefined";
     673               0 :     return "value";
     674                 : }
     675                 : 
     676                 : } /* namespace js */
     677                 : 
     678                 : /* ES5 15.2.4.2.  Note steps 1 and 2 are errata. */
     679                 : static JSBool
     680           47515 : obj_toString(JSContext *cx, unsigned argc, Value *vp)
     681                 : {
     682           47515 :     Value &thisv = vp[1];
     683                 : 
     684                 :     /* Step 1. */
     685           47515 :     if (thisv.isUndefined()) {
     686               0 :         vp->setString(cx->runtime->atomState.objectUndefinedAtom);
     687               0 :         return true;
     688                 :     }
     689                 : 
     690                 :     /* Step 2. */
     691           47515 :     if (thisv.isNull()) {
     692               0 :         vp->setString(cx->runtime->atomState.objectNullAtom);
     693               0 :         return true;
     694                 :     }
     695                 : 
     696                 :     /* Step 3. */
     697           47515 :     JSObject *obj = ToObject(cx, &thisv);
     698           47515 :     if (!obj)
     699               0 :         return false;
     700                 : 
     701                 :     /* Steps 4-5. */
     702           47515 :     JSString *str = js::obj_toStringHelper(cx, obj);
     703           47515 :     if (!str)
     704               0 :         return false;
     705           47515 :     vp->setString(str);
     706           47515 :     return true;
     707                 : }
     708                 : 
     709                 : /* ES5 15.2.4.3. */
     710                 : static JSBool
     711               9 : obj_toLocaleString(JSContext *cx, unsigned argc, Value *vp)
     712                 : {
     713               9 :     JS_CHECK_RECURSION(cx, return false);
     714                 : 
     715                 :     /* Step 1. */
     716               9 :     JSObject *obj = ToObject(cx, &vp[1]);
     717               9 :     if (!obj)
     718               0 :         return false;
     719                 : 
     720                 :     /* Steps 2-4. */
     721               9 :     return obj->callMethod(cx, ATOM_TO_JSID(cx->runtime->atomState.toStringAtom), 0, NULL, vp);
     722                 : }
     723                 : 
     724                 : static JSBool
     725          370621 : obj_valueOf(JSContext *cx, unsigned argc, Value *vp)
     726                 : {
     727          370621 :     JSObject *obj = ToObject(cx, &vp[1]);
     728          370621 :     if (!obj)
     729               0 :         return false;
     730          370621 :     vp->setObject(*obj);
     731          370621 :     return true;
     732                 : }
     733                 : 
     734                 : /* We should be able to assert this for *any* fp->scopeChain(). */
     735                 : static void
     736           97904 : AssertInnerizedScopeChain(JSContext *cx, JSObject &scopeobj)
     737                 : {
     738                 : #ifdef DEBUG
     739          298215 :     for (JSObject *o = &scopeobj; o; o = o->enclosingScope()) {
     740          200311 :         if (JSObjectOp op = o->getClass()->ext.innerObject)
     741               0 :             JS_ASSERT(op(cx, o) == o);
     742                 :     }
     743                 : #endif
     744           97904 : }
     745                 : 
     746                 : #ifndef EVAL_CACHE_CHAIN_LIMIT
     747                 : # define EVAL_CACHE_CHAIN_LIMIT 4
     748                 : #endif
     749                 : 
     750                 : static inline JSScript **
     751           93099 : EvalCacheHash(JSContext *cx, JSLinearString *str)
     752                 : {
     753           93099 :     const jschar *s = str->chars();
     754           93099 :     size_t n = str->length();
     755                 : 
     756           93099 :     if (n > 100)
     757            5859 :         n = 100;
     758                 :     uint32_t h;
     759         1778187 :     for (h = 0; n; s++, n--)
     760         1685088 :         h = JS_ROTATE_LEFT32(h, 4) ^ *s;
     761                 : 
     762           93099 :     h *= JS_GOLDEN_RATIO;
     763           93099 :     h >>= 32 - JS_EVAL_CACHE_SHIFT;
     764           93099 :     return &cx->compartment->evalCache[h];
     765                 : }
     766                 : 
     767                 : static JS_ALWAYS_INLINE JSScript *
     768           78265 : EvalCacheLookup(JSContext *cx, JSLinearString *str, StackFrame *caller, unsigned staticLevel,
     769                 :                 JSPrincipals *principals, JSObject &scopeobj, JSScript **bucket)
     770                 : {
     771                 :     /*
     772                 :      * Cache local eval scripts indexed by source qualified by scope.
     773                 :      *
     774                 :      * An eval cache entry should never be considered a hit unless its
     775                 :      * strictness matches that of the new eval code. The existing code takes
     776                 :      * care of this, because hits are qualified by the function from which
     777                 :      * eval was called, whose strictness doesn't change. (We don't cache evals
     778                 :      * in eval code, so the calling function corresponds to the calling script,
     779                 :      * and its strictness never varies.) Scripts produced by calls to eval from
     780                 :      * global code aren't cached.
     781                 :      *
     782                 :      * FIXME bug 620141: Qualify hits by calling script rather than function.
     783                 :      * Then we wouldn't need the unintuitive !isEvalFrame() hack in EvalKernel
     784                 :      * to avoid caching nested evals in functions (thus potentially mismatching
     785                 :      * on strict mode), and we could cache evals in global code if desired.
     786                 :      */
     787           78265 :     unsigned count = 0;
     788           78265 :     JSScript **scriptp = bucket;
     789                 : 
     790           78265 :     JSVersion version = cx->findVersion();
     791                 :     JSScript *script;
     792           78265 :     JSSubsumePrincipalsOp subsume = cx->runtime->securityCallbacks->subsumePrincipals;
     793          205614 :     while ((script = *scriptp) != NULL) {
     794          354469 :         if (script->savedCallerFun &&
     795                 :             script->staticLevel == staticLevel &&
     796          117751 :             script->getVersion() == version &&
     797          117751 :             !script->hasSingletons &&
     798                 :             (!subsume || script->principals == principals ||
     799               0 :              (subsume(principals, script->principals) &&
     800               0 :               subsume(script->principals, principals)))) {
     801                 :             /*
     802                 :              * Get the prior (cache-filling) eval's saved caller function.
     803                 :              * See frontend::CompileScript.
     804                 :              */
     805           99017 :             JSFunction *fun = script->getCallerFunction();
     806                 : 
     807           99017 :             if (fun == caller->fun()) {
     808                 :                 /*
     809                 :                  * Get the source string passed for safekeeping in the atom map
     810                 :                  * by the prior eval to frontend::CompileScript.
     811                 :                  */
     812           97045 :                 JSAtom *src = script->atoms[0];
     813                 : 
     814           97045 :                 if (src == str || EqualStrings(src, str)) {
     815                 :                     /*
     816                 :                      * Source matches. Make sure there are no inner objects
     817                 :                      * which might use the wrong parent and/or call scope by
     818                 :                      * reusing the previous eval's script. Skip the script's
     819                 :                      * first object, which entrains the eval's scope.
     820                 :                      */
     821           69227 :                     JS_ASSERT(script->objects()->length >= 1);
     822          128013 :                     if (script->objects()->length == 1 &&
     823           58786 :                         !JSScript::isValidOffset(script->regexpsOffset)) {
     824           58786 :                         JS_ASSERT(staticLevel == script->staticLevel);
     825           58786 :                         *scriptp = script->evalHashLink();
     826           58786 :                         script->evalHashLink() = NULL;
     827           58786 :                         return script;
     828                 :                     }
     829                 :                 }
     830                 :             }
     831                 :         }
     832                 : 
     833           60181 :         if (++count == EVAL_CACHE_CHAIN_LIMIT)
     834           11097 :             return NULL;
     835           49084 :         scriptp = &script->evalHashLink();
     836                 :     }
     837            8382 :     return NULL;
     838                 : }
     839                 : 
     840                 : /*
     841                 :  * There are two things we want to do with each script executed in EvalKernel:
     842                 :  *  1. notify jsdbgapi about script creation/destruction
     843                 :  *  2. add the script to the eval cache when EvalKernel is finished
     844                 :  *
     845                 :  * NB: Although the eval cache keeps a script alive wrt to the JS engine, from
     846                 :  * a jsdbgapi user's perspective, we want each eval() to create and destroy a
     847                 :  * script. This hides implementation details and means we don't have to deal
     848                 :  * with calls to JS_GetScriptObject for scripts in the eval cache (currently,
     849                 :  * script->object aliases script->evalHashLink()).
     850                 :  */
     851                 : class EvalScriptGuard
     852                 : {
     853                 :     JSContext *cx_;
     854                 :     JSLinearString *str_;
     855                 :     JSScript **bucket_;
     856                 :     JSScript *script_;
     857                 : 
     858                 :   public:
     859           93099 :     EvalScriptGuard(JSContext *cx, JSLinearString *str)
     860                 :       : cx_(cx),
     861                 :         str_(str),
     862           93099 :         script_(NULL) {
     863           93099 :         bucket_ = EvalCacheHash(cx, str);
     864           93099 :     }
     865                 : 
     866           93099 :     ~EvalScriptGuard() {
     867           93099 :         if (script_) {
     868           92874 :             js_CallDestroyScriptHook(cx_, script_);
     869           92874 :             script_->isActiveEval = false;
     870           92874 :             script_->isCachedEval = true;
     871           92874 :             script_->evalHashLink() = *bucket_;
     872           92874 :             *bucket_ = script_;
     873                 :         }
     874           93099 :     }
     875                 : 
     876           78265 :     void lookupInEvalCache(StackFrame *caller, unsigned staticLevel,
     877                 :                            JSPrincipals *principals, JSObject &scopeobj) {
     878           78265 :         if (JSScript *found = EvalCacheLookup(cx_, str_, caller, staticLevel,
     879           78265 :                                               principals, scopeobj, bucket_)) {
     880           58786 :             js_CallNewScriptHook(cx_, found, NULL);
     881           58786 :             script_ = found;
     882           58786 :             script_->isCachedEval = false;
     883           58786 :             script_->isActiveEval = true;
     884                 :         }
     885           78265 :     }
     886                 : 
     887           34088 :     void setNewScript(JSScript *script) {
     888                 :         /* NewScriptFromEmitter has already called js_CallNewScriptHook. */
     889           34088 :         JS_ASSERT(!script_ && script);
     890           34088 :         script_ = script;
     891           34088 :         script_->isActiveEval = true;
     892           34088 :     }
     893                 : 
     894           93099 :     bool foundScript() {
     895           93099 :         return !!script_;
     896                 :     }
     897                 : 
     898           92874 :     JSScript *script() const {
     899           92874 :         JS_ASSERT(script_);
     900           92874 :         return script_;
     901                 :     }
     902                 : };
     903                 : 
     904                 : /* Define subset of ExecuteType so that casting performs the injection. */
     905                 : enum EvalType { DIRECT_EVAL = EXECUTE_DIRECT_EVAL, INDIRECT_EVAL = EXECUTE_INDIRECT_EVAL };
     906                 : 
     907                 : /*
     908                 :  * Common code implementing direct and indirect eval.
     909                 :  *
     910                 :  * Evaluate call.argv[2], if it is a string, in the context of the given calling
     911                 :  * frame, with the provided scope chain, with the semantics of either a direct
     912                 :  * or indirect eval (see ES5 10.4.2).  If this is an indirect eval, scopeobj
     913                 :  * must be a global object.
     914                 :  *
     915                 :  * On success, store the completion value in call.rval and return true.
     916                 :  */
     917                 : static bool
     918           97904 : EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, StackFrame *caller,
     919                 :            JSObject &scopeobj)
     920                 : {
     921           97904 :     JS_ASSERT((evalType == INDIRECT_EVAL) == (caller == NULL));
     922           97904 :     AssertInnerizedScopeChain(cx, scopeobj);
     923                 : 
     924           97904 :     if (!scopeobj.global().isRuntimeCodeGenEnabled(cx)) {
     925               0 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CSP_BLOCKED_EVAL);
     926               0 :         return false;
     927                 :     }
     928                 : 
     929                 :     /* ES5 15.1.2.1 step 1. */
     930           97904 :     if (args.length() < 1) {
     931            2555 :         args.rval().setUndefined();
     932            2555 :         return true;
     933                 :     }
     934           95349 :     if (!args[0].isString()) {
     935             225 :         args.rval() = args[0];
     936             225 :         return true;
     937                 :     }
     938           95124 :     JSString *str = args[0].toString();
     939                 : 
     940                 :     /* ES5 15.1.2.1 steps 2-8. */
     941                 : 
     942                 :     /*
     943                 :      * Per ES5, indirect eval runs in the global scope. (eval is specified this
     944                 :      * way so that the compiler can make assumptions about what bindings may or
     945                 :      * may not exist in the current frame if it doesn't see 'eval'.)
     946                 :      */
     947                 :     unsigned staticLevel;
     948                 :     Value thisv;
     949           95124 :     if (evalType == DIRECT_EVAL) {
     950           81286 :         staticLevel = caller->script()->staticLevel + 1;
     951                 : 
     952                 :         /*
     953                 :          * Direct calls to eval are supposed to see the caller's |this|. If we
     954                 :          * haven't wrapped that yet, do so now, before we make a copy of it for
     955                 :          * the eval code to use.
     956                 :          */
     957           81286 :         if (!ComputeThis(cx, caller))
     958               0 :             return false;
     959           81286 :         thisv = caller->thisValue();
     960                 : 
     961                 : #ifdef DEBUG
     962           81286 :         jsbytecode *callerPC = caller->pcQuadratic(cx);
     963           81286 :         JS_ASSERT(callerPC && JSOp(*callerPC) == JSOP_EVAL);
     964                 : #endif
     965                 :     } else {
     966           13838 :         JS_ASSERT(args.callee().global() == scopeobj);
     967           13838 :         staticLevel = 0;
     968                 : 
     969                 :         /* Use the global as 'this', modulo outerization. */
     970           13838 :         JSObject *thisobj = scopeobj.thisObject(cx);
     971           13838 :         if (!thisobj)
     972               0 :             return false;
     973           13838 :         thisv = ObjectValue(*thisobj);
     974                 :     }
     975                 : 
     976           95124 :     JSLinearString *linearStr = str->ensureLinear(cx);
     977           95124 :     if (!linearStr)
     978               0 :         return false;
     979           95124 :     const jschar *chars = linearStr->chars();
     980           95124 :     size_t length = linearStr->length();
     981                 : 
     982                 :     /*
     983                 :      * If the eval string starts with '(' or '[' and ends with ')' or ']', it may be JSON.
     984                 :      * Try the JSON parser first because it's much faster.  If the eval string
     985                 :      * isn't JSON, JSON parsing will probably fail quickly, so little time
     986                 :      * will be lost.
     987                 :      *
     988                 :      * Don't use the JSON parser if the caller is strict mode code, because in
     989                 :      * strict mode object literals must not have repeated properties, and the
     990                 :      * JSON parser cheerfully (and correctly) accepts them.  If you're parsing
     991                 :      * JSON with eval and using strict mode, you deserve to be slow.
     992                 :      */
     993          297787 :     if (length > 2 &&
     994           97663 :         ((chars[0] == '[' && chars[length - 1] == ']') ||
     995          100164 :         (chars[0] == '(' && chars[length - 1] == ')')) &&
     996            4836 :          (!caller || !caller->script()->strictModeCode))
     997                 :     {
     998                 :         /*
     999                 :          * Remarkably, JavaScript syntax is not a superset of JSON syntax:
    1000                 :          * strings in JavaScript cannot contain the Unicode line and paragraph
    1001                 :          * terminator characters U+2028 and U+2029, but strings in JSON can.
    1002                 :          * Rather than force the JSON parser to handle this quirk when used by
    1003                 :          * eval, we simply don't use the JSON parser when either character
    1004                 :          * appears in the provided string.  See bug 657367.
    1005                 :          */
    1006         1683305 :         for (const jschar *cp = &chars[1], *end = &chars[length - 2]; ; cp++) {
    1007         1683305 :             if (*cp == 0x2028 || *cp == 0x2029)
    1008               0 :                 break;
    1009                 : 
    1010         1683305 :             if (cp == end) {
    1011            4988 :                 bool isArray = (chars[0] == '[');
    1012                 :                 JSONParser parser(cx, isArray ? chars : chars + 1, isArray ? length : length - 2,
    1013            4988 :                                   JSONParser::StrictJSON, JSONParser::NoError);
    1014                 :                 Value tmp;
    1015            4988 :                 if (!parser.parse(&tmp))
    1016               0 :                     return false;
    1017            4988 :                 if (tmp.isUndefined())
    1018            2963 :                     break;
    1019            2025 :                 args.rval() = tmp;
    1020            2025 :                 return true;
    1021                 :             }
    1022                 :         }
    1023                 :     }
    1024                 : 
    1025          186198 :     EvalScriptGuard esg(cx, linearStr);
    1026                 : 
    1027           93099 :     JSPrincipals *principals = PrincipalsForCompiledCode(args, cx);
    1028                 : 
    1029           93099 :     if (evalType == DIRECT_EVAL && caller->isNonEvalFunctionFrame())
    1030           78265 :         esg.lookupInEvalCache(caller, staticLevel, principals, scopeobj);
    1031                 : 
    1032           93099 :     if (!esg.foundScript()) {
    1033                 :         unsigned lineno;
    1034                 :         const char *filename;
    1035                 :         JSPrincipals *originPrincipals;
    1036                 :         CurrentScriptFileLineOrigin(cx, &filename, &lineno, &originPrincipals,
    1037                 :                                     evalType == DIRECT_EVAL ? CALLED_FROM_JSOP_EVAL
    1038           34313 :                                                             : NOT_CALLED_FROM_JSOP_EVAL);
    1039           34313 :         uint32_t tcflags = TCF_COMPILE_N_GO | TCF_COMPILE_FOR_EVAL;
    1040                 :         JSScript *compiled = frontend::CompileScript(cx, &scopeobj, caller,
    1041                 :                                                      principals, originPrincipals,
    1042                 :                                                      tcflags, chars, length, filename,
    1043                 :                                                      lineno, cx->findVersion(), linearStr,
    1044           34313 :                                                      staticLevel);
    1045           34313 :         if (!compiled)
    1046             225 :             return false;
    1047                 : 
    1048           34088 :         esg.setNewScript(compiled);
    1049                 :     }
    1050                 : 
    1051                 :     return ExecuteKernel(cx, esg.script(), scopeobj, thisv, ExecuteType(evalType),
    1052           92874 :                          NULL /* evalInFrame */, &args.rval());
    1053                 : }
    1054                 : 
    1055                 : /*
    1056                 :  * We once supported a second argument to eval to use as the scope chain
    1057                 :  * when evaluating the code string.  Warn when such uses are seen so that
    1058                 :  * authors will know that support for eval(s, o) has been removed.
    1059                 :  */
    1060                 : static inline bool
    1061           97904 : WarnOnTooManyArgs(JSContext *cx, const CallArgs &args)
    1062                 : {
    1063           97904 :     if (args.length() > 1) {
    1064              99 :         if (JSScript *script = cx->stack.currentScript()) {
    1065              90 :             if (!script->warnedAboutTwoArgumentEval) {
    1066                 :                 static const char TWO_ARGUMENT_WARNING[] =
    1067                 :                     "Support for eval(code, scopeObject) has been removed. "
    1068                 :                     "Use |with (scopeObject) eval(code);| instead.";
    1069              63 :                 if (!JS_ReportWarning(cx, TWO_ARGUMENT_WARNING))
    1070               0 :                     return false;
    1071              63 :                 script->warnedAboutTwoArgumentEval = true;
    1072                 :             }
    1073                 :         } else {
    1074                 :             /*
    1075                 :              * In the case of an indirect call without a caller frame, avoid a
    1076                 :              * potential warning-flood by doing nothing.
    1077                 :              */
    1078                 :         }
    1079                 :     }
    1080                 : 
    1081           97904 :     return true;
    1082                 : }
    1083                 : 
    1084                 : namespace js {
    1085                 : 
    1086                 : /*
    1087                 :  * ES5 15.1.2.1.
    1088                 :  *
    1089                 :  * NB: This method handles only indirect eval.
    1090                 :  */
    1091                 : JSBool
    1092           13838 : eval(JSContext *cx, unsigned argc, Value *vp)
    1093                 : {
    1094           13838 :     CallArgs args = CallArgsFromVp(argc, vp);
    1095           13838 :     return WarnOnTooManyArgs(cx, args) &&
    1096           13838 :            EvalKernel(cx, args, INDIRECT_EVAL, NULL, args.callee().global());
    1097                 : }
    1098                 : 
    1099                 : bool
    1100           84066 : DirectEval(JSContext *cx, const CallArgs &args)
    1101                 : {
    1102                 :     /* Direct eval can assume it was called from an interpreted frame. */
    1103           84066 :     StackFrame *caller = cx->fp();
    1104           84066 :     JS_ASSERT(caller->isScriptFrame());
    1105           84066 :     JS_ASSERT(IsBuiltinEvalForScope(&caller->scopeChain(), args.calleev()));
    1106           84066 :     JS_ASSERT(JSOp(*cx->regs().pc) == JSOP_EVAL);
    1107                 : 
    1108          168132 :     AutoFunctionCallProbe callProbe(cx, args.callee().toFunction(), caller->script());
    1109                 : 
    1110           84066 :     JSObject *scopeChain = GetScopeChain(cx, caller);
    1111           84066 :     if (!scopeChain)
    1112               0 :         return false;
    1113                 : 
    1114           84066 :     if (!WarnOnTooManyArgs(cx, args))
    1115               0 :         return false;
    1116                 : 
    1117           84066 :     return EvalKernel(cx, args, DIRECT_EVAL, caller, *scopeChain);
    1118                 : }
    1119                 : 
    1120                 : bool
    1121          168159 : IsBuiltinEvalForScope(JSObject *scopeChain, const Value &v)
    1122                 : {
    1123          168159 :     return scopeChain->global().getOriginalEval() == v;
    1124                 : }
    1125                 : 
    1126                 : bool
    1127          103553 : IsAnyBuiltinEval(JSFunction *fun)
    1128                 : {
    1129          103553 :     return fun->maybeNative() == eval;
    1130                 : }
    1131                 : 
    1132                 : JSPrincipals *
    1133          103513 : PrincipalsForCompiledCode(const CallReceiver &call, JSContext *cx)
    1134                 : {
    1135          113927 :     JS_ASSERT(IsAnyBuiltinEval(call.callee().toFunction()) ||
    1136          113927 :               IsBuiltinFunctionConstructor(call.callee().toFunction()));
    1137                 : 
    1138                 :     /*
    1139                 :      * To compute the principals of the compiled eval/Function code, we simply
    1140                 :      * use the callee's principals. To see why the caller's principals are
    1141                 :      * ignored, consider first that, in the capability-model we assume, the
    1142                 :      * high-privileged eval/Function should never have escaped to the
    1143                 :      * low-privileged caller. (For the Mozilla embedding, this is brute-enforced
    1144                 :      * by explicit filtering by wrappers.) Thus, the caller's privileges should
    1145                 :      * subsume the callee's.
    1146                 :      *
    1147                 :      * In the converse situation, where the callee has lower privileges than the
    1148                 :      * caller, we might initially guess that the caller would want to retain
    1149                 :      * their higher privileges in the generated code. However, since the
    1150                 :      * compiled code will be run with the callee's scope chain, this would make
    1151                 :      * fp->script()->compartment() != fp->compartment().
    1152                 :      */
    1153                 : 
    1154          103513 :     return call.callee().principals(cx);
    1155                 : }
    1156                 : 
    1157                 : }  /* namespace js */
    1158                 : 
    1159                 : #if JS_HAS_OBJ_WATCHPOINT
    1160                 : 
    1161                 : static JSBool
    1162            3783 : obj_watch_handler(JSContext *cx, JSObject *obj, jsid id, jsval old,
    1163                 :                   jsval *nvp, void *closure)
    1164                 : {
    1165            3783 :     JSObject *callable = (JSObject *) closure;
    1166            3783 :     if (JSSubsumePrincipalsOp subsume = cx->runtime->securityCallbacks->subsumePrincipals) {
    1167               0 :         if (JSPrincipals *watcher = callable->principals(cx)) {
    1168               0 :             if (JSObject *scopeChain = cx->stack.currentScriptedScopeChain()) {
    1169               0 :                 if (JSPrincipals *subject = scopeChain->principals(cx)) {
    1170               0 :                     if (!subsume(watcher, subject)) {
    1171                 :                         /* Silently don't call the watch handler. */
    1172               0 :                         return true;
    1173                 :                     }
    1174                 :                 }
    1175                 :             }
    1176                 :         }
    1177                 :     }
    1178                 : 
    1179                 :     /* Avoid recursion on (obj, id) already being watched on cx. */
    1180            7566 :     AutoResolving resolving(cx, obj, id, AutoResolving::WATCH);
    1181            3783 :     if (resolving.alreadyStarted())
    1182               0 :         return true;
    1183                 : 
    1184            3783 :     Value argv[] = { IdToValue(id), old, *nvp };
    1185            3783 :     return Invoke(cx, ObjectValue(*obj), ObjectOrNullValue(callable), ArrayLength(argv), argv, nvp);
    1186                 : }
    1187                 : 
    1188                 : static JSBool
    1189            3639 : obj_watch(JSContext *cx, unsigned argc, Value *vp)
    1190                 : {
    1191            3639 :     if (argc <= 1) {
    1192               0 :         js_ReportMissingArg(cx, *vp, 1);
    1193               0 :         return false;
    1194                 :     }
    1195                 : 
    1196            3639 :     JSObject *callable = js_ValueToCallableObject(cx, &vp[3], 0);
    1197            3639 :     if (!callable)
    1198               9 :         return false;
    1199                 : 
    1200                 :     jsid propid;
    1201            3630 :     if (!ValueToId(cx, vp[2], &propid))
    1202               0 :         return false;
    1203                 : 
    1204            3630 :     JSObject *obj = ToObject(cx, &vp[1]);
    1205            3630 :     if (!obj)
    1206               0 :         return false;
    1207                 : 
    1208                 :     Value tmp;
    1209                 :     unsigned attrs;
    1210            3630 :     if (!CheckAccess(cx, obj, propid, JSACC_WATCH, &tmp, &attrs))
    1211               0 :         return false;
    1212                 : 
    1213            3630 :     vp->setUndefined();
    1214                 : 
    1215            3630 :     if (obj->isDenseArray() && !obj->makeDenseArraySlow(cx))
    1216               0 :         return false;
    1217            3630 :     return JS_SetWatchPoint(cx, obj, propid, obj_watch_handler, callable);
    1218                 : }
    1219                 : 
    1220                 : static JSBool
    1221             945 : obj_unwatch(JSContext *cx, unsigned argc, Value *vp)
    1222                 : {
    1223             945 :     JSObject *obj = ToObject(cx, &vp[1]);
    1224             945 :     if (!obj)
    1225               0 :         return false;
    1226             945 :     vp->setUndefined();
    1227                 :     jsid id;
    1228             945 :     if (argc != 0) {
    1229               9 :         if (!ValueToId(cx, vp[2], &id))
    1230               0 :             return false;
    1231                 :     } else {
    1232             936 :         id = JSID_VOID;
    1233                 :     }
    1234             945 :     return JS_ClearWatchPoint(cx, obj, id, NULL, NULL);
    1235                 : }
    1236                 : 
    1237                 : #endif /* JS_HAS_OBJ_WATCHPOINT */
    1238                 : 
    1239                 : /*
    1240                 :  * Prototype and property query methods, to complement the 'in' and
    1241                 :  * 'instanceof' operators.
    1242                 :  */
    1243                 : 
    1244                 : /* Proposed ECMA 15.2.4.5. */
    1245                 : static JSBool
    1246           92508 : obj_hasOwnProperty(JSContext *cx, unsigned argc, Value *vp)
    1247                 : {
    1248           92508 :     JSObject *obj = ToObject(cx, &vp[1]);
    1249           92508 :     if (!obj)
    1250               0 :         return false;
    1251           92508 :     return js_HasOwnPropertyHelper(cx, obj->getOps()->lookupGeneric, argc, vp);
    1252                 : }
    1253                 : 
    1254                 : JSBool
    1255           92508 : js_HasOwnPropertyHelper(JSContext *cx, LookupGenericOp lookup, unsigned argc,
    1256                 :                         Value *vp)
    1257                 : {
    1258                 :     jsid id;
    1259           92508 :     if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id))
    1260               0 :         return JS_FALSE;
    1261                 : 
    1262           92508 :     JSObject *obj = ToObject(cx, &vp[1]);
    1263           92508 :     if (!obj)
    1264               0 :         return false;
    1265                 :     JSObject *obj2;
    1266                 :     JSProperty *prop;
    1267           92508 :     if (obj->isProxy()) {
    1268                 :         bool has;
    1269               0 :         if (!Proxy::hasOwn(cx, obj, id, &has))
    1270               0 :             return false;
    1271               0 :         vp->setBoolean(has);
    1272               0 :         return true;
    1273                 :     }
    1274           92508 :     if (!js_HasOwnProperty(cx, lookup, obj, id, &obj2, &prop))
    1275               0 :         return JS_FALSE;
    1276           92508 :     vp->setBoolean(!!prop);
    1277           92508 :     return JS_TRUE;
    1278                 : }
    1279                 : 
    1280                 : JSBool
    1281          699910 : js_HasOwnProperty(JSContext *cx, LookupGenericOp lookup, JSObject *obj, jsid id,
    1282                 :                   JSObject **objp, JSProperty **propp)
    1283                 : {
    1284         1399820 :     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING);
    1285          699910 :     if (!(lookup ? lookup : js_LookupProperty)(cx, obj, id, objp, propp))
    1286               0 :         return false;
    1287          699910 :     if (!*propp)
    1288          577735 :         return true;
    1289                 : 
    1290          122175 :     if (*objp == obj)
    1291           98738 :         return true;
    1292                 : 
    1293           23437 :     JSObject *outer = NULL;
    1294           23437 :     if (JSObjectOp op = (*objp)->getClass()->ext.outerObject) {
    1295               0 :         outer = op(cx, *objp);
    1296               0 :         if (!outer)
    1297               0 :             return false;
    1298                 :     }
    1299                 : 
    1300           23437 :     if (outer != *objp)
    1301           23437 :         *propp = NULL;
    1302           23437 :     return true;
    1303                 : }
    1304                 : 
    1305                 : /* ES5 15.2.4.6. */
    1306                 : static JSBool
    1307               0 : obj_isPrototypeOf(JSContext *cx, unsigned argc, Value *vp)
    1308                 : {
    1309                 :     /* Step 1. */
    1310               0 :     if (argc < 1 || !vp[2].isObject()) {
    1311               0 :         vp->setBoolean(false);
    1312               0 :         return true;
    1313                 :     }
    1314                 : 
    1315                 :     /* Step 2. */
    1316               0 :     JSObject *obj = ToObject(cx, &vp[1]);
    1317               0 :     if (!obj)
    1318               0 :         return false;
    1319                 : 
    1320                 :     /* Step 3. */
    1321               0 :     vp->setBoolean(js_IsDelegate(cx, obj, vp[2]));
    1322               0 :     return true;
    1323                 : }
    1324                 : 
    1325                 : /* ES5 15.2.4.7. */
    1326                 : static JSBool
    1327              21 : obj_propertyIsEnumerable(JSContext *cx, unsigned argc, Value *vp)
    1328                 : {
    1329                 :     /* Step 1. */
    1330                 :     jsid id;
    1331              21 :     if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id))
    1332               0 :         return false;
    1333                 : 
    1334                 :     /* Step 2. */
    1335              21 :     JSObject *obj = ToObject(cx, &vp[1]);
    1336              21 :     if (!obj)
    1337               9 :         return false;
    1338                 : 
    1339                 :     /* Steps 3-5. */
    1340              12 :     return js_PropertyIsEnumerable(cx, obj, id, vp);
    1341                 : }
    1342                 : 
    1343                 : JSBool
    1344              12 : js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, Value *vp)
    1345                 : {
    1346                 :     JSObject *pobj;
    1347                 :     JSProperty *prop;
    1348              12 :     if (!obj->lookupGeneric(cx, id, &pobj, &prop))
    1349               0 :         return false;
    1350                 : 
    1351              12 :     if (!prop) {
    1352               0 :         vp->setBoolean(false);
    1353               0 :         return true;
    1354                 :     }
    1355                 : 
    1356                 :     /*
    1357                 :      * ECMA spec botch: return false unless hasOwnProperty. Leaving "own" out
    1358                 :      * of propertyIsEnumerable's name was a mistake.
    1359                 :      */
    1360              12 :     if (pobj != obj) {
    1361               0 :         vp->setBoolean(false);
    1362               0 :         return true;
    1363                 :     }
    1364                 : 
    1365                 :     unsigned attrs;
    1366              12 :     if (!pobj->getGenericAttributes(cx, id, &attrs))
    1367               0 :         return false;
    1368                 : 
    1369              12 :     vp->setBoolean((attrs & JSPROP_ENUMERATE) != 0);
    1370              12 :     return true;
    1371                 : }
    1372                 : 
    1373                 : #if OLD_GETTER_SETTER_METHODS
    1374                 : 
    1375                 : const char js_defineGetter_str[] = "__defineGetter__";
    1376                 : const char js_defineSetter_str[] = "__defineSetter__";
    1377                 : const char js_lookupGetter_str[] = "__lookupGetter__";
    1378                 : const char js_lookupSetter_str[] = "__lookupSetter__";
    1379                 : 
    1380                 : enum DefineType { Getter, Setter };
    1381                 : 
    1382                 : template<DefineType Type>
    1383                 : static bool
    1384          297480 : DefineAccessor(JSContext *cx, unsigned argc, Value *vp)
    1385                 : {
    1386          297480 :     CallArgs args = CallArgsFromVp(argc, vp);
    1387          297480 :     if (!BoxNonStrictThis(cx, args))
    1388               0 :         return false;
    1389                 : 
    1390          297480 :     if (args.length() < 2 || !js_IsCallable(args[1])) {
    1391               9 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
    1392                 :                              JSMSG_BAD_GETTER_OR_SETTER,
    1393                 :                              Type == Getter ? js_getter_str : js_setter_str);
    1394               9 :         return false;
    1395                 :     }
    1396                 : 
    1397                 :     jsid id;
    1398          297471 :     if (!ValueToId(cx, args[0], &id))
    1399               0 :         return false;
    1400                 : 
    1401          297471 :     JSObject *descObj = NewBuiltinClassInstance(cx, &ObjectClass);
    1402          297471 :     if (!descObj)
    1403               0 :         return false;
    1404                 : 
    1405          297471 :     JSAtomState &state = cx->runtime->atomState;
    1406                 :     /* enumerable: true */
    1407          297471 :     if (!descObj->defineProperty(cx, state.enumerableAtom, BooleanValue(true)))
    1408               0 :         return false;
    1409                 : 
    1410                 :     /* configurable: true */
    1411          297471 :     if (!descObj->defineProperty(cx, state.configurableAtom, BooleanValue(true)))
    1412               0 :         return false;
    1413                 : 
    1414                 :     /* enumerable: true */
    1415          297471 :     PropertyName *acc = (Type == Getter) ? state.getAtom : state.setAtom;
    1416          297471 :     if (!descObj->defineProperty(cx, acc, args[1]))
    1417               0 :         return false;
    1418                 : 
    1419                 :     JSBool dummy;
    1420          297471 :     if (!js_DefineOwnProperty(cx, &args.thisv().toObject(), id, ObjectValue(*descObj), &dummy))
    1421               0 :         return false;
    1422          297471 :     args.rval().setUndefined();
    1423          297471 :     return true;
    1424                 : }
    1425                 : 
    1426                 : JS_FRIEND_API(JSBool)
    1427          280948 : js::obj_defineGetter(JSContext *cx, unsigned argc, Value *vp)
    1428                 : {
    1429          280948 :     return DefineAccessor<Getter>(cx, argc, vp);
    1430                 : }
    1431                 : 
    1432                 : JS_FRIEND_API(JSBool)
    1433           16532 : js::obj_defineSetter(JSContext *cx, unsigned argc, Value *vp)
    1434                 : {
    1435           16532 :     return DefineAccessor<Setter>(cx, argc, vp);
    1436                 : }
    1437                 : 
    1438                 : static JSBool
    1439           26980 : obj_lookupGetter(JSContext *cx, unsigned argc, Value *vp)
    1440                 : {
    1441                 :     jsid id;
    1442           26980 :     if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id))
    1443               0 :         return JS_FALSE;
    1444           26980 :     JSObject *obj = ToObject(cx, &vp[1]);
    1445           26980 :     if (!obj)
    1446               0 :         return JS_FALSE;
    1447                 :     JSObject *pobj;
    1448                 :     JSProperty *prop;
    1449           26980 :     if (!obj->lookupGeneric(cx, id, &pobj, &prop))
    1450               0 :         return JS_FALSE;
    1451           26980 :     vp->setUndefined();
    1452           26980 :     if (prop) {
    1453           24572 :         if (pobj->isNative()) {
    1454           24572 :             Shape *shape = (Shape *) prop;
    1455           24572 :             if (shape->hasGetterValue())
    1456           12870 :                 *vp = shape->getterValue();
    1457                 :         }
    1458                 :     }
    1459           26980 :     return JS_TRUE;
    1460                 : }
    1461                 : 
    1462                 : static JSBool
    1463           19195 : obj_lookupSetter(JSContext *cx, unsigned argc, Value *vp)
    1464                 : {
    1465                 :     jsid id;
    1466           19195 :     if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id))
    1467               0 :         return JS_FALSE;
    1468           19195 :     JSObject *obj = ToObject(cx, &vp[1]);
    1469           19195 :     if (!obj)
    1470               0 :         return JS_FALSE;
    1471                 :     JSObject *pobj;
    1472                 :     JSProperty *prop;
    1473           19195 :     if (!obj->lookupGeneric(cx, id, &pobj, &prop))
    1474               0 :         return JS_FALSE;
    1475           19195 :     vp->setUndefined();
    1476           19195 :     if (prop) {
    1477           19195 :         if (pobj->isNative()) {
    1478           19195 :             Shape *shape = (Shape *) prop;
    1479           19195 :             if (shape->hasSetterValue())
    1480            4972 :                 *vp = shape->setterValue();
    1481                 :         }
    1482                 :     }
    1483           19195 :     return JS_TRUE;
    1484                 : }
    1485                 : #endif /* OLD_GETTER_SETTER_METHODS */
    1486                 : 
    1487                 : JSBool
    1488             706 : obj_getPrototypeOf(JSContext *cx, unsigned argc, Value *vp)
    1489                 : {
    1490             706 :     if (argc == 0) {
    1491               0 :         js_ReportMissingArg(cx, *vp, 0);
    1492               0 :         return JS_FALSE;
    1493                 :     }
    1494                 : 
    1495             706 :     if (vp[2].isPrimitive()) {
    1496               9 :         char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, vp[2], NULL);
    1497               9 :         if (!bytes)
    1498               0 :             return JS_FALSE;
    1499                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
    1500               9 :                              JSMSG_UNEXPECTED_TYPE, bytes, "not an object");
    1501               9 :         JS_free(cx, bytes);
    1502               9 :         return JS_FALSE;
    1503                 :     }
    1504                 : 
    1505             697 :     JSObject *obj = &vp[2].toObject();
    1506                 :     unsigned attrs;
    1507             697 :     return CheckAccess(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.protoAtom),
    1508             697 :                        JSACC_PROTO, vp, &attrs);
    1509                 : }
    1510                 : 
    1511                 : namespace js {
    1512                 : 
    1513                 : bool
    1514           14430 : NewPropertyDescriptorObject(JSContext *cx, const PropertyDescriptor *desc, Value *vp)
    1515                 : {
    1516           14430 :     if (!desc->obj) {
    1517             440 :         vp->setUndefined();
    1518             440 :         return true;
    1519                 :     }
    1520                 : 
    1521                 :     /* We have our own property, so start creating the descriptor. */
    1522           13990 :     PropDesc d;
    1523           13990 :     d.initFromPropertyDescriptor(*desc);
    1524           13990 :     if (!d.makeObject(cx))
    1525               0 :         return false;
    1526           13990 :     *vp = d.pd;
    1527           13990 :     return true;
    1528                 : }
    1529                 : 
    1530                 : void
    1531           13990 : PropDesc::initFromPropertyDescriptor(const PropertyDescriptor &desc)
    1532                 : {
    1533           13990 :     pd.setUndefined();
    1534           13990 :     attrs = uint8_t(desc.attrs);
    1535           13990 :     JS_ASSERT_IF(attrs & JSPROP_READONLY, !(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
    1536           13990 :     if (desc.attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
    1537            2344 :         hasGet = true;
    1538                 :         get = ((desc.attrs & JSPROP_GETTER) && desc.getter)
    1539            2335 :               ? CastAsObjectJsval(desc.getter)
    1540            4679 :               : UndefinedValue();
    1541            2344 :         hasSet = true;
    1542                 :         set = ((desc.attrs & JSPROP_SETTER) && desc.setter)
    1543              63 :               ? CastAsObjectJsval(desc.setter)
    1544            2407 :               : UndefinedValue();
    1545            2344 :         hasValue = false;
    1546            2344 :         value.setUndefined();
    1547            2344 :         hasWritable = false;
    1548                 :     } else {
    1549           11646 :         hasGet = false;
    1550           11646 :         get.setUndefined();
    1551           11646 :         hasSet = false;
    1552           11646 :         set.setUndefined();
    1553           11646 :         hasValue = true;
    1554           11646 :         value = desc.value;
    1555           11646 :         hasWritable = true;
    1556                 :     }
    1557           13990 :     hasEnumerable = true;
    1558           13990 :     hasConfigurable = true;
    1559           13990 : }
    1560                 : 
    1561                 : bool
    1562           13999 : PropDesc::makeObject(JSContext *cx)
    1563                 : {
    1564           13999 :     JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass);
    1565           13999 :     if (!obj)
    1566               0 :         return false;
    1567                 : 
    1568           13999 :     const JSAtomState &atomState = cx->runtime->atomState;
    1569           69995 :     if ((hasConfigurable &&
    1570                 :          !obj->defineProperty(cx, atomState.configurableAtom,
    1571           13999 :                               BooleanValue((attrs & JSPROP_PERMANENT) == 0))) ||
    1572                 :         (hasEnumerable &&
    1573                 :          !obj->defineProperty(cx, atomState.enumerableAtom,
    1574           13999 :                               BooleanValue((attrs & JSPROP_ENUMERATE) != 0))) ||
    1575                 :         (hasGet &&
    1576            2344 :          !obj->defineProperty(cx, atomState.getAtom, get)) ||
    1577                 :         (hasSet &&
    1578            2344 :          !obj->defineProperty(cx, atomState.setAtom, set)) ||
    1579                 :         (hasValue &&
    1580           11655 :          !obj->defineProperty(cx, atomState.valueAtom, value)) ||
    1581                 :         (hasWritable &&
    1582                 :          !obj->defineProperty(cx, atomState.writableAtom,
    1583           11655 :                               BooleanValue((attrs & JSPROP_READONLY) == 0))))
    1584                 :     {
    1585               0 :         return false;
    1586                 :     }
    1587                 : 
    1588           13999 :     pd.setObject(*obj);
    1589           13999 :     return true;
    1590                 : }
    1591                 : 
    1592                 : bool
    1593           12667 : GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, PropertyDescriptor *desc)
    1594                 : {
    1595           12667 :     if (obj->isProxy())
    1596              45 :         return Proxy::getOwnPropertyDescriptor(cx, obj, id, false, desc);
    1597                 : 
    1598                 :     JSObject *pobj;
    1599                 :     JSProperty *prop;
    1600           12622 :     if (!js_HasOwnProperty(cx, obj->getOps()->lookupGeneric, obj, id, &pobj, &prop))
    1601               0 :         return false;
    1602           12622 :     if (!prop) {
    1603             440 :         desc->obj = NULL;
    1604             440 :         return true;
    1605                 :     }
    1606                 : 
    1607           12182 :     bool doGet = true;
    1608           12182 :     if (pobj->isNative()) {
    1609           12047 :         Shape *shape = (Shape *) prop;
    1610           12047 :         desc->attrs = shape->attributes();
    1611           12047 :         if (desc->attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
    1612             574 :             doGet = false;
    1613             574 :             if (desc->attrs & JSPROP_GETTER)
    1614             574 :                 desc->getter = CastAsPropertyOp(shape->getterObject());
    1615             574 :             if (desc->attrs & JSPROP_SETTER)
    1616              63 :                 desc->setter = CastAsStrictPropertyOp(shape->setterObject());
    1617                 :         }
    1618                 :     } else {
    1619             135 :         if (!pobj->getGenericAttributes(cx, id, &desc->attrs))
    1620               0 :             return false;
    1621                 :     }
    1622                 : 
    1623           12182 :     if (doGet && !obj->getGeneric(cx, id, &desc->value))
    1624               0 :         return false;
    1625                 : 
    1626           12182 :     desc->obj = obj;
    1627           12182 :     return true;
    1628                 : }
    1629                 : 
    1630                 : bool
    1631           11825 : GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, Value *vp)
    1632                 : {
    1633           23650 :     AutoPropertyDescriptorRooter desc(cx);
    1634           11825 :     return GetOwnPropertyDescriptor(cx, obj, id, &desc) &&
    1635           11825 :            NewPropertyDescriptorObject(cx, &desc, vp);
    1636                 : }
    1637                 : 
    1638                 : }
    1639                 : 
    1640                 : static bool
    1641          315007 : GetFirstArgumentAsObject(JSContext *cx, unsigned argc, Value *vp, const char *method, JSObject **objp)
    1642                 : {
    1643          315007 :     if (argc == 0) {
    1644                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
    1645               0 :                              method, "0", "s");
    1646               0 :         return false;
    1647                 :     }
    1648                 : 
    1649          315007 :     const Value &v = vp[2];
    1650          315007 :     if (!v.isObject()) {
    1651              36 :         char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL);
    1652              36 :         if (!bytes)
    1653               0 :             return false;
    1654                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
    1655              36 :                              bytes, "not an object");
    1656              36 :         JS_free(cx, bytes);
    1657              36 :         return false;
    1658                 :     }
    1659                 : 
    1660          314971 :     *objp = &v.toObject();
    1661          314971 :     return true;
    1662                 : }
    1663                 : 
    1664                 : static JSBool
    1665           11825 : obj_getOwnPropertyDescriptor(JSContext *cx, unsigned argc, Value *vp)
    1666                 : {
    1667                 :     JSObject *obj;
    1668           11825 :     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.getOwnPropertyDescriptor", &obj))
    1669               0 :         return JS_FALSE;
    1670           23650 :     AutoIdRooter nameidr(cx);
    1671           11825 :     if (!ValueToId(cx, argc >= 2 ? vp[3] : UndefinedValue(), nameidr.addr()))
    1672               0 :         return JS_FALSE;
    1673           11825 :     return GetOwnPropertyDescriptor(cx, obj, nameidr.id(), vp);
    1674                 : }
    1675                 : 
    1676                 : static JSBool
    1677            1500 : obj_keys(JSContext *cx, unsigned argc, Value *vp)
    1678                 : {
    1679                 :     JSObject *obj;
    1680            1500 :     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.keys", &obj))
    1681               0 :         return false;
    1682                 : 
    1683            3000 :     AutoIdVector props(cx);
    1684            1500 :     if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props))
    1685               0 :         return false;
    1686                 : 
    1687            3000 :     AutoValueVector vals(cx);
    1688            1500 :     if (!vals.reserve(props.length()))
    1689               0 :         return false;
    1690           17305 :     for (size_t i = 0, len = props.length(); i < len; i++) {
    1691           15805 :         jsid id = props[i];
    1692           15805 :         if (JSID_IS_STRING(id)) {
    1693           15337 :             vals.infallibleAppend(StringValue(JSID_TO_STRING(id)));
    1694             468 :         } else if (JSID_IS_INT(id)) {
    1695             468 :             JSString *str = js_IntToString(cx, JSID_TO_INT(id));
    1696             468 :             if (!str)
    1697               0 :                 return false;
    1698             468 :             vals.infallibleAppend(StringValue(str));
    1699                 :         } else {
    1700               0 :             JS_ASSERT(JSID_IS_OBJECT(id));
    1701                 :         }
    1702                 :     }
    1703                 : 
    1704            1500 :     JS_ASSERT(props.length() <= UINT32_MAX);
    1705            1500 :     JSObject *aobj = NewDenseCopiedArray(cx, uint32_t(vals.length()), vals.begin());
    1706            1500 :     if (!aobj)
    1707               0 :         return false;
    1708            1500 :     vp->setObject(*aobj);
    1709                 : 
    1710            1500 :     return true;
    1711                 : }
    1712                 : 
    1713                 : static bool
    1714         3586014 : HasProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, bool *foundp)
    1715                 : {
    1716         3586014 :     if (!obj->hasProperty(cx, id, foundp, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING))
    1717               0 :         return false;
    1718         3586014 :     if (!*foundp) {
    1719         2087335 :         vp->setUndefined();
    1720         2087335 :         return true;
    1721                 :     }
    1722                 : 
    1723                 :     /*
    1724                 :      * We must go through the method read barrier in case id is 'get' or 'set'.
    1725                 :      * There is no obvious way to defer cloning a joined function object whose
    1726                 :      * identity will be used by DefinePropertyOnObject, e.g., or reflected via
    1727                 :      * js::GetOwnPropertyDescriptor, as the getter or setter callable object.
    1728                 :      */
    1729         1498679 :     return !!obj->getGeneric(cx, id, vp);
    1730                 : }
    1731                 : 
    1732          611659 : PropDesc::PropDesc()
    1733                 :   : pd(UndefinedValue()),
    1734                 :     value(UndefinedValue()),
    1735                 :     get(UndefinedValue()),
    1736                 :     set(UndefinedValue()),
    1737                 :     attrs(0),
    1738                 :     hasGet(false),
    1739                 :     hasSet(false),
    1740                 :     hasValue(false),
    1741                 :     hasWritable(false),
    1742                 :     hasEnumerable(false),
    1743          611659 :     hasConfigurable(false)
    1744                 : {
    1745          611659 : }
    1746                 : 
    1747                 : bool
    1748          597669 : PropDesc::initialize(JSContext *cx, const Value &origval, bool checkAccessors)
    1749                 : {
    1750          597669 :     Value v = origval;
    1751                 : 
    1752                 :     /* 8.10.5 step 1 */
    1753          597669 :     if (v.isPrimitive()) {
    1754               0 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
    1755               0 :         return false;
    1756                 :     }
    1757          597669 :     JSObject *desc = &v.toObject();
    1758                 : 
    1759                 :     /* Make a copy of the descriptor. We might need it later. */
    1760          597669 :     pd = v;
    1761                 : 
    1762                 :     /* Start with the proper defaults. */
    1763          597669 :     attrs = JSPROP_PERMANENT | JSPROP_READONLY;
    1764                 : 
    1765                 :     bool found;
    1766                 : 
    1767                 :     /* 8.10.5 step 3 */
    1768                 : #ifdef __GNUC__ /* quell GCC overwarning */
    1769          597669 :     found = false;
    1770                 : #endif
    1771          597669 :     if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.enumerableAtom), &v, &found))
    1772               0 :         return false;
    1773          597669 :     if (found) {
    1774          596139 :         hasEnumerable = JS_TRUE;
    1775          596139 :         if (js_ValueToBoolean(v))
    1776          592634 :             attrs |= JSPROP_ENUMERATE;
    1777                 :     }
    1778                 : 
    1779                 :     /* 8.10.5 step 4 */
    1780          597669 :     if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.configurableAtom), &v, &found))
    1781               0 :         return false;
    1782          597669 :     if (found) {
    1783          301200 :         hasConfigurable = JS_TRUE;
    1784          301200 :         if (js_ValueToBoolean(v))
    1785          297680 :             attrs &= ~JSPROP_PERMANENT;
    1786                 :     }
    1787                 : 
    1788                 :     /* 8.10.5 step 5 */
    1789          597669 :     if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.valueAtom), &v, &found))
    1790               0 :         return false;
    1791          597669 :     if (found) {
    1792             858 :         hasValue = true;
    1793             858 :         value = v;
    1794                 :     }
    1795                 : 
    1796                 :     /* 8.10.6 step 6 */
    1797          597669 :     if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.writableAtom), &v, &found))
    1798               0 :         return false;
    1799          597669 :     if (found) {
    1800             247 :         hasWritable = JS_TRUE;
    1801             247 :         if (js_ValueToBoolean(v))
    1802             142 :             attrs &= ~JSPROP_READONLY;
    1803                 :     }
    1804                 : 
    1805                 :     /* 8.10.7 step 7 */
    1806          597669 :     if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.getAtom), &v, &found))
    1807               0 :         return false;
    1808          597669 :     if (found) {
    1809          579801 :         hasGet = true;
    1810          579801 :         get = v;
    1811          579801 :         attrs |= JSPROP_GETTER | JSPROP_SHARED;
    1812          579801 :         attrs &= ~JSPROP_READONLY;
    1813          579801 :         if (checkAccessors && !checkGetter(cx))
    1814               0 :             return false;
    1815                 :     }
    1816                 : 
    1817                 :     /* 8.10.7 step 8 */
    1818          597669 :     if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.setAtom), &v, &found))
    1819               0 :         return false;
    1820          597669 :     if (found) {
    1821           20434 :         hasSet = true;
    1822           20434 :         set = v;
    1823           20434 :         attrs |= JSPROP_SETTER | JSPROP_SHARED;
    1824           20434 :         attrs &= ~JSPROP_READONLY;
    1825           20434 :         if (checkAccessors && !checkSetter(cx))
    1826               0 :             return false;
    1827                 :     }
    1828                 : 
    1829                 :     /* 8.10.7 step 9 */
    1830          597669 :     if ((hasGet || hasSet) && (hasValue || hasWritable)) {
    1831               0 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INVALID_DESCRIPTOR);
    1832               0 :         return false;
    1833                 :     }
    1834                 : 
    1835          597669 :     JS_ASSERT_IF(attrs & JSPROP_READONLY, !(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
    1836                 : 
    1837          597669 :     return true;
    1838                 : }
    1839                 : 
    1840                 : static JSBool
    1841              27 : Reject(JSContext *cx, unsigned errorNumber, bool throwError, jsid id, bool *rval)
    1842                 : {
    1843              27 :     if (throwError) {
    1844                 :         jsid idstr;
    1845              27 :         if (!js_ValueToStringId(cx, IdToValue(id), &idstr))
    1846               0 :            return JS_FALSE;
    1847              54 :         JSAutoByteString bytes(cx, JSID_TO_STRING(idstr));
    1848              27 :         if (!bytes)
    1849               0 :             return JS_FALSE;
    1850              27 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber, bytes.ptr());
    1851              27 :         return JS_FALSE;
    1852                 :     }
    1853                 : 
    1854               0 :     *rval = false;
    1855               0 :     return JS_TRUE;
    1856                 : }
    1857                 : 
    1858                 : static JSBool
    1859               0 : Reject(JSContext *cx, JSObject *obj, unsigned errorNumber, bool throwError, bool *rval)
    1860                 : {
    1861               0 :     if (throwError) {
    1862               0 :         if (js_ErrorFormatString[errorNumber].argCount == 1) {
    1863                 :             js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber,
    1864                 :                                      JSDVG_IGNORE_STACK, ObjectValue(*obj),
    1865               0 :                                      NULL, NULL, NULL);
    1866                 :         } else {
    1867               0 :             JS_ASSERT(js_ErrorFormatString[errorNumber].argCount == 0);
    1868               0 :             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber);
    1869                 :         }
    1870               0 :         return JS_FALSE;
    1871                 :     }
    1872                 : 
    1873               0 :     *rval = false;
    1874               0 :     return JS_TRUE;
    1875                 : }
    1876                 : 
    1877                 : static JSBool
    1878          593996 : DefinePropertyOnObject(JSContext *cx, JSObject *obj, const jsid &id, const PropDesc &desc,
    1879                 :                        bool throwError, bool *rval)
    1880                 : {
    1881                 :     /* 8.12.9 step 1. */
    1882                 :     JSProperty *current;
    1883                 :     JSObject *obj2;
    1884          593996 :     JS_ASSERT(!obj->getOps()->lookupGeneric);
    1885          593996 :     if (!js_HasOwnProperty(cx, NULL, obj, id, &obj2, &current))
    1886               0 :         return JS_FALSE;
    1887                 : 
    1888          593996 :     JS_ASSERT(!obj->getOps()->defineProperty);
    1889                 : 
    1890                 :     /* 8.12.9 steps 2-4. */
    1891          593996 :     if (!current) {
    1892          576982 :         if (!obj->isExtensible())
    1893               0 :             return Reject(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
    1894                 : 
    1895          576982 :         *rval = true;
    1896                 : 
    1897          576982 :         if (desc.isGenericDescriptor() || desc.isDataDescriptor()) {
    1898             537 :             JS_ASSERT(!obj->getOps()->defineProperty);
    1899                 :             return js_DefineProperty(cx, obj, id, &desc.value,
    1900             537 :                                      JS_PropertyStub, JS_StrictPropertyStub, desc.attrs);
    1901                 :         }
    1902                 : 
    1903          576445 :         JS_ASSERT(desc.isAccessorDescriptor());
    1904                 : 
    1905                 :         /*
    1906                 :          * Getters and setters are just like watchpoints from an access
    1907                 :          * control point of view.
    1908                 :          */
    1909                 :         Value dummy;
    1910                 :         unsigned dummyAttrs;
    1911          576445 :         if (!CheckAccess(cx, obj, id, JSACC_WATCH, &dummy, &dummyAttrs))
    1912               0 :             return JS_FALSE;
    1913                 : 
    1914          576445 :         Value tmp = UndefinedValue();
    1915                 :         return js_DefineProperty(cx, obj, id, &tmp,
    1916          576445 :                                  desc.getter(), desc.setter(), desc.attrs);
    1917                 :     }
    1918                 : 
    1919                 :     /* 8.12.9 steps 5-6 (note 5 is merely a special case of 6). */
    1920           17014 :     Value v = UndefinedValue();
    1921                 : 
    1922           17014 :     JS_ASSERT(obj == obj2);
    1923                 : 
    1924           17014 :     const Shape *shape = reinterpret_cast<Shape *>(current);
    1925                 :     do {
    1926           17014 :         if (desc.isAccessorDescriptor()) {
    1927           16627 :             if (!shape->isAccessorDescriptor())
    1928             348 :                 break;
    1929                 : 
    1930           16279 :             if (desc.hasGet) {
    1931                 :                 bool same;
    1932              35 :                 if (!SameValue(cx, desc.getterValue(), shape->getterOrUndefined(), &same))
    1933               0 :                     return false;
    1934              35 :                 if (!same)
    1935              29 :                     break;
    1936                 :             }
    1937                 : 
    1938           16250 :             if (desc.hasSet) {
    1939                 :                 bool same;
    1940           16244 :                 if (!SameValue(cx, desc.setterValue(), shape->setterOrUndefined(), &same))
    1941               0 :                     return false;
    1942           16244 :                 if (!same)
    1943           16244 :                     break;
    1944                 :             }
    1945                 :         } else {
    1946                 :             /*
    1947                 :              * Determine the current value of the property once, if the current
    1948                 :              * value might actually need to be used or preserved later.  NB: we
    1949                 :              * guard on whether the current property is a data descriptor to
    1950                 :              * avoid calling a getter; we won't need the value if it's not a
    1951                 :              * data descriptor.
    1952                 :              */
    1953             387 :             if (shape->isDataDescriptor()) {
    1954                 :                 /*
    1955                 :                  * We must rule out a non-configurable js::PropertyOp-guarded
    1956                 :                  * property becoming a writable unguarded data property, since
    1957                 :                  * such a property can have its value changed to one the getter
    1958                 :                  * and setter preclude.
    1959                 :                  *
    1960                 :                  * A desc lacking writable but with value is a data descriptor
    1961                 :                  * and we must reject it as if it had writable: true if current
    1962                 :                  * is writable.
    1963                 :                  */
    1964             459 :                 if (!shape->configurable() &&
    1965              90 :                     (!shape->hasDefaultGetter() || !shape->hasDefaultSetter()) &&
    1966               0 :                     desc.isDataDescriptor() &&
    1967               0 :                     (desc.hasWritable ? desc.writable() : shape->writable()))
    1968                 :                 {
    1969               0 :                     return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, id, rval);
    1970                 :                 }
    1971                 : 
    1972             369 :                 if (!js_NativeGet(cx, obj, obj2, shape, JSGET_NO_METHOD_BARRIER, &v))
    1973               0 :                     return JS_FALSE;
    1974                 :             }
    1975                 : 
    1976             387 :             if (desc.isDataDescriptor()) {
    1977             360 :                 if (!shape->isDataDescriptor())
    1978               9 :                     break;
    1979                 : 
    1980                 :                 bool same;
    1981             351 :                 if (desc.hasValue) {
    1982             324 :                     if (!SameValue(cx, desc.value, v, &same))
    1983               0 :                         return false;
    1984             324 :                     if (!same) {
    1985                 :                         /*
    1986                 :                          * Insist that a non-configurable js::PropertyOp data
    1987                 :                          * property is frozen at exactly the last-got value.
    1988                 :                          *
    1989                 :                          * Duplicate the first part of the big conjunction that
    1990                 :                          * we tested above, rather than add a local bool flag.
    1991                 :                          * Likewise, don't try to keep shape->writable() in a
    1992                 :                          * flag we veto from true to false for non-configurable
    1993                 :                          * PropertyOp-based data properties and test before the
    1994                 :                          * SameValue check later on in order to re-use that "if
    1995                 :                          * (!SameValue) Reject" logic.
    1996                 :                          *
    1997                 :                          * This function is large and complex enough that it
    1998                 :                          * seems best to repeat a small bit of code and return
    1999                 :                          * Reject(...) ASAP, instead of being clever.
    2000                 :                          */
    2001             378 :                         if (!shape->configurable() &&
    2002              54 :                             (!shape->hasDefaultGetter() || !shape->hasDefaultSetter()))
    2003                 :                         {
    2004               0 :                             return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, id, rval);
    2005                 :                         }
    2006             324 :                         break;
    2007                 :                     }
    2008                 :                 }
    2009              27 :                 if (desc.hasWritable && desc.writable() != shape->writable())
    2010              27 :                     break;
    2011                 :             } else {
    2012                 :                 /* The only fields in desc will be handled below. */
    2013              27 :                 JS_ASSERT(desc.isGenericDescriptor());
    2014                 :             }
    2015                 :         }
    2016                 : 
    2017              33 :         if (desc.hasConfigurable && desc.configurable() != shape->configurable())
    2018              18 :             break;
    2019              15 :         if (desc.hasEnumerable && desc.enumerable() != shape->enumerable())
    2020               9 :             break;
    2021                 : 
    2022                 :         /* The conditions imposed by step 5 or step 6 apply. */
    2023               6 :         *rval = true;
    2024               6 :         return JS_TRUE;
    2025                 :     } while (0);
    2026                 : 
    2027                 :     /* 8.12.9 step 7. */
    2028           17008 :     if (!shape->configurable()) {
    2029                 :         /*
    2030                 :          * Since [[Configurable]] defaults to false, we don't need to check
    2031                 :          * whether it was specified.  We can't do likewise for [[Enumerable]]
    2032                 :          * because its putative value is used in a comparison -- a comparison
    2033                 :          * whose result must always be false per spec if the [[Enumerable]]
    2034                 :          * field is not present.  Perfectly pellucid logic, eh?
    2035                 :          */
    2036              45 :         JS_ASSERT_IF(!desc.hasConfigurable, !desc.configurable());
    2037              45 :         if (desc.configurable() ||
    2038               0 :             (desc.hasEnumerable && desc.enumerable() != shape->enumerable())) {
    2039               0 :             return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, id, rval);
    2040                 :         }
    2041                 :     }
    2042                 : 
    2043           17008 :     bool callDelProperty = false;
    2044                 : 
    2045           17008 :     if (desc.isGenericDescriptor()) {
    2046                 :         /* 8.12.9 step 8, no validation required */
    2047           16981 :     } else if (desc.isDataDescriptor() != shape->isDataDescriptor()) {
    2048                 :         /* 8.12.9 step 9. */
    2049             357 :         if (!shape->configurable())
    2050               0 :             return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, id, rval);
    2051           16624 :     } else if (desc.isDataDescriptor()) {
    2052                 :         /* 8.12.9 step 10. */
    2053             351 :         JS_ASSERT(shape->isDataDescriptor());
    2054             351 :         if (!shape->configurable() && !shape->writable()) {
    2055              27 :             if (desc.hasWritable && desc.writable())
    2056               0 :                 return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, id, rval);
    2057              27 :             if (desc.hasValue) {
    2058                 :                 bool same;
    2059              27 :                 if (!SameValue(cx, desc.value, v, &same))
    2060               0 :                     return false;
    2061              27 :                 if (!same)
    2062              27 :                     return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, id, rval);
    2063                 :             }
    2064                 :         }
    2065                 : 
    2066             324 :         callDelProperty = !shape->hasDefaultGetter() || !shape->hasDefaultSetter();
    2067                 :     } else {
    2068                 :         /* 8.12.9 step 11. */
    2069           16273 :         JS_ASSERT(desc.isAccessorDescriptor() && shape->isAccessorDescriptor());
    2070           16273 :         if (!shape->configurable()) {
    2071               0 :             if (desc.hasSet) {
    2072                 :                 bool same;
    2073               0 :                 if (!SameValue(cx, desc.setterValue(), shape->setterOrUndefined(), &same))
    2074               0 :                     return false;
    2075               0 :                 if (!same)
    2076               0 :                     return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, id, rval);
    2077                 :             }
    2078                 : 
    2079               0 :             if (desc.hasGet) {
    2080                 :                 bool same;
    2081               0 :                 if (!SameValue(cx, desc.getterValue(), shape->getterOrUndefined(), &same))
    2082               0 :                     return false;
    2083               0 :                 if (!same)
    2084               0 :                     return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, id, rval);
    2085                 :             }
    2086                 :         }
    2087                 :     }
    2088                 : 
    2089                 :     /* 8.12.9 step 12. */
    2090                 :     unsigned attrs;
    2091                 :     PropertyOp getter;
    2092                 :     StrictPropertyOp setter;
    2093           16981 :     if (desc.isGenericDescriptor()) {
    2094              27 :         unsigned changed = 0;
    2095              27 :         if (desc.hasConfigurable)
    2096              18 :             changed |= JSPROP_PERMANENT;
    2097              27 :         if (desc.hasEnumerable)
    2098               9 :             changed |= JSPROP_ENUMERATE;
    2099                 : 
    2100              27 :         attrs = (shape->attributes() & ~changed) | (desc.attrs & changed);
    2101              27 :         if (shape->isMethod()) {
    2102               0 :             JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
    2103               0 :             getter = JS_PropertyStub;
    2104               0 :             setter = JS_StrictPropertyStub;
    2105                 :         } else {
    2106              27 :             getter = shape->getter();
    2107              27 :             setter = shape->setter();
    2108                 :         }
    2109           16954 :     } else if (desc.isDataDescriptor()) {
    2110             333 :         unsigned unchanged = 0;
    2111             333 :         if (!desc.hasConfigurable)
    2112             333 :             unchanged |= JSPROP_PERMANENT;
    2113             333 :         if (!desc.hasEnumerable)
    2114             315 :             unchanged |= JSPROP_ENUMERATE;
    2115                 :         /* Watch out for accessor -> data transformations here. */
    2116             333 :         if (!desc.hasWritable && shape->isDataDescriptor())
    2117             279 :             unchanged |= JSPROP_READONLY;
    2118                 : 
    2119             333 :         if (desc.hasValue)
    2120             306 :             v = desc.value;
    2121             333 :         attrs = (desc.attrs & ~unchanged) | (shape->attributes() & unchanged);
    2122             333 :         getter = JS_PropertyStub;
    2123             333 :         setter = JS_StrictPropertyStub;
    2124                 :     } else {
    2125           16621 :         JS_ASSERT(desc.isAccessorDescriptor());
    2126                 : 
    2127                 :         /*
    2128                 :          * Getters and setters are just like watchpoints from an access
    2129                 :          * control point of view.
    2130                 :          */
    2131                 :         Value dummy;
    2132           16621 :         if (!CheckAccess(cx, obj2, id, JSACC_WATCH, &dummy, &attrs))
    2133               0 :              return JS_FALSE;
    2134                 : 
    2135           16621 :         JS_ASSERT_IF(shape->isMethod(), !(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
    2136                 : 
    2137                 :         /* 8.12.9 step 12. */
    2138           16621 :         unsigned changed = 0;
    2139           16621 :         if (desc.hasConfigurable)
    2140           16594 :             changed |= JSPROP_PERMANENT;
    2141           16621 :         if (desc.hasEnumerable)
    2142           16585 :             changed |= JSPROP_ENUMERATE;
    2143           16621 :         if (desc.hasGet)
    2144             332 :             changed |= JSPROP_GETTER | JSPROP_SHARED | JSPROP_READONLY;
    2145           16621 :         if (desc.hasSet)
    2146           16289 :             changed |= JSPROP_SETTER | JSPROP_SHARED | JSPROP_READONLY;
    2147                 : 
    2148           16621 :         attrs = (desc.attrs & changed) | (shape->attributes() & ~changed);
    2149           16621 :         if (desc.hasGet) {
    2150             332 :             getter = desc.getter();
    2151                 :         } else {
    2152           32767 :             getter = (shape->isMethod() || (shape->hasDefaultGetter() && !shape->hasGetterValue()))
    2153                 :                      ? JS_PropertyStub
    2154           32767 :                      : shape->getter();
    2155                 :         }
    2156           16621 :         if (desc.hasSet) {
    2157           16289 :             setter = desc.setter();
    2158                 :         } else {
    2159             663 :             setter = (shape->hasDefaultSetter() && !shape->hasSetterValue())
    2160                 :                      ? JS_StrictPropertyStub
    2161             663 :                      : shape->setter();
    2162                 :         }
    2163                 :     }
    2164                 : 
    2165           16981 :     *rval = true;
    2166                 : 
    2167                 :     /*
    2168                 :      * Since "data" properties implemented using native C functions may rely on
    2169                 :      * side effects during setting, we must make them aware that they have been
    2170                 :      * "assigned"; deleting the property before redefining it does the trick.
    2171                 :      * See bug 539766, where we ran into problems when we redefined
    2172                 :      * arguments.length without making the property aware that its value had
    2173                 :      * been changed (which would have happened if we had deleted it before
    2174                 :      * redefining it or we had invoked its setter to change its value).
    2175                 :      */
    2176           16981 :     if (callDelProperty) {
    2177              18 :         Value dummy = UndefinedValue();
    2178              18 :         if (!CallJSPropertyOp(cx, obj2->getClass()->delProperty, obj2, id, &dummy))
    2179               0 :             return false;
    2180                 :     }
    2181                 : 
    2182           16981 :     return js_DefineProperty(cx, obj, id, &v, getter, setter, attrs);
    2183                 : }
    2184                 : 
    2185                 : static JSBool
    2186             241 : DefinePropertyOnArray(JSContext *cx, JSObject *obj, const jsid &id, const PropDesc &desc,
    2187                 :                       bool throwError, bool *rval)
    2188                 : {
    2189                 :     /*
    2190                 :      * We probably should optimize dense array property definitions where
    2191                 :      * the descriptor describes a traditional array property (enumerable,
    2192                 :      * configurable, writable, numeric index or length without altering its
    2193                 :      * attributes).  Such definitions are probably unlikely, so we don't bother
    2194                 :      * for now.
    2195                 :      */
    2196             241 :     if (obj->isDenseArray() && !obj->makeDenseArraySlow(cx))
    2197               0 :         return JS_FALSE;
    2198                 : 
    2199             241 :     uint32_t oldLen = obj->getArrayLength();
    2200                 : 
    2201             241 :     if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
    2202                 :         /*
    2203                 :          * Our optimization of storage of the length property of arrays makes
    2204                 :          * it very difficult to properly implement defining the property.  For
    2205                 :          * now simply throw an exception (NB: not merely Reject) on any attempt
    2206                 :          * to define the "length" property, rather than attempting to implement
    2207                 :          * some difficult-for-authors-to-grasp subset of that functionality.
    2208                 :          */
    2209               9 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_DEFINE_ARRAY_LENGTH);
    2210               9 :         return JS_FALSE;
    2211                 :     }
    2212                 : 
    2213                 :     uint32_t index;
    2214             232 :     if (js_IdIsIndex(id, &index)) {
    2215                 :         /*
    2216                 :         // Disabled until we support defining "length":
    2217                 :         if (index >= oldLen && lengthPropertyNotWritable())
    2218                 :             return ThrowTypeError(cx, JSMSG_CANT_APPEND_TO_ARRAY);
    2219                 :          */
    2220             232 :         if (!DefinePropertyOnObject(cx, obj, id, desc, false, rval))
    2221               0 :             return JS_FALSE;
    2222             232 :         if (!*rval)
    2223               0 :             return Reject(cx, obj, JSMSG_CANT_DEFINE_ARRAY_INDEX, throwError, rval);
    2224                 : 
    2225             232 :         if (index >= oldLen) {
    2226              89 :             JS_ASSERT(index != UINT32_MAX);
    2227              89 :             obj->setArrayLength(cx, index + 1);
    2228                 :         }
    2229                 : 
    2230             232 :         *rval = true;
    2231             232 :         return JS_TRUE;
    2232                 :     }
    2233                 : 
    2234               0 :     return DefinePropertyOnObject(cx, obj, id, desc, throwError, rval);
    2235                 : }
    2236                 : 
    2237                 : namespace js {
    2238                 : 
    2239                 : bool
    2240          595809 : DefineProperty(JSContext *cx, JSObject *obj, const jsid &id, const PropDesc &desc, bool throwError,
    2241                 :                bool *rval)
    2242                 : {
    2243          595809 :     if (obj->isArray())
    2244             241 :         return DefinePropertyOnArray(cx, obj, id, desc, throwError, rval);
    2245                 : 
    2246          595568 :     if (obj->getOps()->lookupGeneric) {
    2247            1804 :         if (obj->isProxy())
    2248            1804 :             return Proxy::defineProperty(cx, obj, id, desc.pd);
    2249               0 :         return Reject(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
    2250                 :     }
    2251                 : 
    2252          593764 :     return DefinePropertyOnObject(cx, obj, id, desc, throwError, rval);
    2253                 : }
    2254                 : 
    2255                 : } /* namespace js */
    2256                 : 
    2257                 : JSBool
    2258          595249 : js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, const Value &descriptor, JSBool *bp)
    2259                 : {
    2260         1190498 :     AutoPropDescArrayRooter descs(cx);
    2261          595249 :     PropDesc *desc = descs.append();
    2262          595249 :     if (!desc || !desc->initialize(cx, descriptor))
    2263               0 :         return false;
    2264                 : 
    2265                 :     bool rval;
    2266          595249 :     if (!DefineProperty(cx, obj, id, *desc, true, &rval))
    2267            1768 :         return false;
    2268          593481 :     *bp = !!rval;
    2269          593481 :     return true;
    2270                 : }
    2271                 : 
    2272                 : /* ES5 15.2.3.6: Object.defineProperty(O, P, Attributes) */
    2273                 : static JSBool
    2274          297805 : obj_defineProperty(JSContext *cx, unsigned argc, Value *vp)
    2275                 : {
    2276                 :     JSObject *obj;
    2277          297805 :     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperty", &obj))
    2278              27 :         return false;
    2279                 : 
    2280                 :     jsid id;
    2281          297778 :     if (!ValueToId(cx, argc >= 2 ? vp[3] : UndefinedValue(), &id))
    2282               0 :         return JS_FALSE;
    2283                 : 
    2284          297778 :     const Value descval = argc >= 3 ? vp[4] : UndefinedValue();
    2285                 : 
    2286                 :     JSBool junk;
    2287          297778 :     if (!js_DefineOwnProperty(cx, obj, id, descval, &junk))
    2288            1768 :         return false;
    2289                 : 
    2290          296010 :     vp->setObject(*obj);
    2291          296010 :     return true;
    2292                 : }
    2293                 : 
    2294                 : namespace js {
    2295                 : 
    2296                 : bool
    2297             304 : ReadPropertyDescriptors(JSContext *cx, JSObject *props, bool checkAccessors,
    2298                 :                         AutoIdVector *ids, AutoPropDescArrayRooter *descs)
    2299                 : {
    2300             304 :     if (!GetPropertyNames(cx, props, JSITER_OWNONLY, ids))
    2301               0 :         return false;
    2302                 : 
    2303             738 :     for (size_t i = 0, len = ids->length(); i < len; i++) {
    2304             434 :         jsid id = (*ids)[i];
    2305             434 :         PropDesc* desc = descs->append();
    2306                 :         Value v;
    2307             434 :         if (!desc || !props->getGeneric(cx, id, &v) || !desc->initialize(cx, v, checkAccessors))
    2308               0 :             return false;
    2309                 :     }
    2310             304 :     return true;
    2311                 : }
    2312                 : 
    2313                 : } /* namespace js */
    2314                 : 
    2315                 : static bool
    2316             214 : DefineProperties(JSContext *cx, JSObject *obj, JSObject *props)
    2317                 : {
    2318             428 :     AutoIdVector ids(cx);
    2319             428 :     AutoPropDescArrayRooter descs(cx);
    2320             214 :     if (!ReadPropertyDescriptors(cx, props, true, &ids, &descs))
    2321               0 :         return false;
    2322                 : 
    2323                 :     bool dummy;
    2324             522 :     for (size_t i = 0, len = ids.length(); i < len; i++) {
    2325             317 :         if (!DefineProperty(cx, obj, ids[i], descs[i], true, &dummy))
    2326               9 :             return false;
    2327                 :     }
    2328                 : 
    2329             205 :     return true;
    2330                 : }
    2331                 : 
    2332                 : extern JSBool
    2333              36 : js_PopulateObject(JSContext *cx, JSObject *newborn, JSObject *props)
    2334                 : {
    2335              36 :     return DefineProperties(cx, newborn, props);
    2336                 : }
    2337                 : 
    2338                 : /* ES5 15.2.3.7: Object.defineProperties(O, Properties) */
    2339                 : static JSBool
    2340              81 : obj_defineProperties(JSContext *cx, unsigned argc, Value *vp)
    2341                 : {
    2342                 :     /* Steps 1 and 7. */
    2343                 :     JSObject *obj;
    2344              81 :     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperties", &obj))
    2345               0 :         return false;
    2346              81 :     vp->setObject(*obj);
    2347                 : 
    2348                 :     /* Step 2. */
    2349              81 :     if (argc < 2) {
    2350                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
    2351               0 :                              "Object.defineProperties", "0", "s");
    2352               0 :         return false;
    2353                 :     }
    2354              81 :     JSObject *props = ToObject(cx, &vp[3]);
    2355              81 :     if (!props)
    2356               0 :         return false;
    2357                 : 
    2358                 :     /* Steps 3-6. */
    2359              81 :     return DefineProperties(cx, obj, props);
    2360                 : }
    2361                 : 
    2362                 : /* ES5 15.2.3.5: Object.create(O [, Properties]) */
    2363                 : static JSBool
    2364             442 : obj_create(JSContext *cx, unsigned argc, Value *vp)
    2365                 : {
    2366             442 :     if (argc == 0) {
    2367                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
    2368               0 :                              "Object.create", "0", "s");
    2369               0 :         return false;
    2370                 :     }
    2371                 : 
    2372             442 :     CallArgs args = CallArgsFromVp(argc, vp);
    2373             442 :     const Value &v = args[0];
    2374             442 :     if (!v.isObjectOrNull()) {
    2375              27 :         char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL);
    2376              27 :         if (!bytes)
    2377               0 :             return false;
    2378                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
    2379              27 :                              bytes, "not an object or null");
    2380              27 :         JS_free(cx, bytes);
    2381              27 :         return false;
    2382                 :     }
    2383                 : 
    2384             415 :     JSObject *proto = v.toObjectOrNull();
    2385             415 :     if (proto && proto->isXML()) {
    2386               0 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_XML_PROTO_FORBIDDEN);
    2387               0 :         return false;
    2388                 :     }
    2389                 : 
    2390                 :     /*
    2391                 :      * Use the callee's global as the parent of the new object to avoid dynamic
    2392                 :      * scoping (i.e., using the caller's global).
    2393                 :      */
    2394             415 :     JSObject *obj = NewObjectWithGivenProto(cx, &ObjectClass, proto, &args.callee().global());
    2395             415 :     if (!obj)
    2396               0 :         return false;
    2397                 : 
    2398                 :     /* Don't track types or array-ness for objects created here. */
    2399             415 :     MarkTypeObjectUnknownProperties(cx, obj->type());
    2400                 : 
    2401                 :     /* 15.2.3.5 step 4. */
    2402             415 :     if (args.hasDefined(1)) {
    2403              97 :         if (args[1].isPrimitive()) {
    2404               0 :             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
    2405               0 :             return false;
    2406                 :         }
    2407                 : 
    2408              97 :         if (!DefineProperties(cx, obj, &args[1].toObject()))
    2409               0 :             return false;
    2410                 :     }
    2411                 : 
    2412                 :     /* 5. Return obj. */
    2413             415 :     args.rval().setObject(*obj);
    2414             415 :     return true;
    2415                 : }
    2416                 : 
    2417                 : static JSBool
    2418             828 : obj_getOwnPropertyNames(JSContext *cx, unsigned argc, Value *vp)
    2419                 : {
    2420                 :     JSObject *obj;
    2421             828 :     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.getOwnPropertyNames", &obj))
    2422               0 :         return false;
    2423                 : 
    2424            1656 :     AutoIdVector keys(cx);
    2425             828 :     if (!GetPropertyNames(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &keys))
    2426               0 :         return false;
    2427                 : 
    2428            1656 :     AutoValueVector vals(cx);
    2429             828 :     if (!vals.resize(keys.length()))
    2430               0 :         return false;
    2431                 : 
    2432           14562 :     for (size_t i = 0, len = keys.length(); i < len; i++) {
    2433           13734 :          jsid id = keys[i];
    2434           13734 :          if (JSID_IS_INT(id)) {
    2435             261 :              JSString *str = js_IntToString(cx, JSID_TO_INT(id));
    2436             261 :              if (!str)
    2437               0 :                  return false;
    2438             261 :              vals[i].setString(str);
    2439           13473 :          } else if (JSID_IS_ATOM(id)) {
    2440           13473 :              vals[i].setString(JSID_TO_STRING(id));
    2441                 :          } else {
    2442               0 :              vals[i].setObject(*JSID_TO_OBJECT(id));
    2443                 :          }
    2444                 :     }
    2445                 : 
    2446             828 :     JSObject *aobj = NewDenseCopiedArray(cx, vals.length(), vals.begin());
    2447             828 :     if (!aobj)
    2448               0 :         return false;
    2449                 : 
    2450             828 :     vp->setObject(*aobj);
    2451             828 :     return true;
    2452                 : }
    2453                 : 
    2454                 : static JSBool
    2455             846 : obj_isExtensible(JSContext *cx, unsigned argc, Value *vp)
    2456                 : {
    2457                 :     JSObject *obj;
    2458             846 :     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.isExtensible", &obj))
    2459               0 :         return false;
    2460                 : 
    2461             846 :     vp->setBoolean(obj->isExtensible());
    2462             846 :     return true;
    2463                 : }
    2464                 : 
    2465                 : static JSBool
    2466              81 : obj_preventExtensions(JSContext *cx, unsigned argc, Value *vp)
    2467                 : {
    2468                 :     JSObject *obj;
    2469              81 :     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.preventExtensions", &obj))
    2470               0 :         return false;
    2471                 : 
    2472              81 :     vp->setObject(*obj);
    2473              81 :     if (!obj->isExtensible())
    2474               0 :         return true;
    2475                 : 
    2476             162 :     AutoIdVector props(cx);
    2477              81 :     return obj->preventExtensions(cx, &props);
    2478                 : }
    2479                 : 
    2480                 : /* static */ inline unsigned
    2481         3722414 : JSObject::getSealedOrFrozenAttributes(unsigned attrs, ImmutabilityType it)
    2482                 : {
    2483                 :     /* Make all attributes permanent; if freezing, make data attributes read-only. */
    2484         3722414 :     if (it == FREEZE && !(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
    2485         3714660 :         return JSPROP_PERMANENT | JSPROP_READONLY;
    2486            7754 :     return JSPROP_PERMANENT;
    2487                 : }
    2488                 : 
    2489                 : bool
    2490         1223582 : JSObject::sealOrFreeze(JSContext *cx, ImmutabilityType it)
    2491                 : {
    2492         1223582 :     assertSameCompartment(cx, this);
    2493         1223582 :     JS_ASSERT(it == SEAL || it == FREEZE);
    2494                 : 
    2495         2447164 :     RootedVarObject self(cx, this);
    2496                 : 
    2497         2447164 :     AutoIdVector props(cx);
    2498         1223582 :     if (isExtensible()) {
    2499         1223150 :         if (!preventExtensions(cx, &props))
    2500               0 :             return false;
    2501                 :     } else {
    2502             432 :         if (!GetPropertyNames(cx, this, JSITER_HIDDEN | JSITER_OWNONLY, &props))
    2503               0 :             return false;
    2504                 :     }
    2505                 : 
    2506                 :     /* preventExtensions must slowify dense arrays, so we can assign to holes without checks. */
    2507         1223582 :     JS_ASSERT(!self->isDenseArray());
    2508                 : 
    2509         1223582 :     if (isNative() && !inDictionaryMode()) {
    2510                 :         /*
    2511                 :          * Seal/freeze non-dictionary objects by constructing a new shape
    2512                 :          * hierarchy mirroring the original one, which can be shared if many
    2513                 :          * objects with the same structure are sealed/frozen. If we use the
    2514                 :          * generic path below then any non-empty object will be converted to
    2515                 :          * dictionary mode.
    2516                 :          */
    2517         1210354 :         Shape *last = EmptyShape::getInitialShape(cx, self->getClass(),
    2518         1210354 :                                                   self->getProto(),
    2519                 :                                                   self->getParent(),
    2520         1210354 :                                                   self->getAllocKind(),
    2521         4841416 :                                                   self->lastProperty()->getObjectFlags());
    2522         1210354 :         if (!last)
    2523               0 :             return false;
    2524                 : 
    2525                 :         /* Get an in order list of the shapes in this object. */
    2526         2420708 :         AutoShapeVector shapes(cx);
    2527         4852926 :         for (Shape::Range r = self->lastProperty()->all(); !r.empty(); r.popFront()) {
    2528         3642572 :             if (!shapes.append(&r.front()))
    2529               0 :                 return false;
    2530                 :         }
    2531         1210354 :         Reverse(shapes.begin(), shapes.end());
    2532                 : 
    2533         4852926 :         for (size_t i = 0; i < shapes.length(); i++) {
    2534         3642572 :             StackShape child(shapes[i]);
    2535         3642572 :             child.attrs |= getSealedOrFrozenAttributes(child.attrs, it);
    2536                 : 
    2537         3642572 :             if (!JSID_IS_EMPTY(child.propid))
    2538         3642572 :                 MarkTypePropertyConfigured(cx, self, child.propid);
    2539                 : 
    2540         3642572 :             last = JS_PROPERTY_TREE(cx).getChild(cx, last, self->numFixedSlots(), child);
    2541         3642572 :             if (!last)
    2542               0 :                 return NULL;
    2543                 :         }
    2544                 : 
    2545         1210354 :         JS_ASSERT(self->lastProperty()->slotSpan() == last->slotSpan());
    2546         1210354 :         JS_ALWAYS_TRUE(setLastProperty(cx, last));
    2547                 :     } else {
    2548           93070 :         for (size_t i = 0; i < props.length(); i++) {
    2549           79842 :             jsid id = props[i];
    2550                 : 
    2551                 :             unsigned attrs;
    2552           79842 :             if (!self->getGenericAttributes(cx, id, &attrs))
    2553               0 :                 return false;
    2554                 : 
    2555           79842 :             unsigned new_attrs = getSealedOrFrozenAttributes(attrs, it);
    2556                 : 
    2557                 :             /* If we already have the attributes we need, skip the setAttributes call. */
    2558           79842 :             if ((attrs | new_attrs) == attrs)
    2559           39217 :                 continue;
    2560                 : 
    2561           40625 :             attrs |= new_attrs;
    2562           40625 :             if (!self->setGenericAttributes(cx, id, &attrs))
    2563               0 :                 return false;
    2564                 :         }
    2565                 :     }
    2566                 : 
    2567         1223582 :     return true;
    2568                 : }
    2569                 : 
    2570                 : bool
    2571            1139 : JSObject::isSealedOrFrozen(JSContext *cx, ImmutabilityType it, bool *resultp)
    2572                 : {
    2573            1139 :     if (isExtensible()) {
    2574             252 :         *resultp = false;
    2575             252 :         return true;
    2576                 :     }
    2577                 : 
    2578            1774 :     AutoIdVector props(cx);
    2579             887 :     if (!GetPropertyNames(cx, this, JSITER_HIDDEN | JSITER_OWNONLY, &props))
    2580               0 :         return false;
    2581                 : 
    2582           11694 :     for (size_t i = 0, len = props.length(); i < len; i++) {
    2583           11041 :         jsid id = props[i];
    2584                 : 
    2585                 :         unsigned attrs;
    2586           11041 :         if (!getGenericAttributes(cx, id, &attrs))
    2587               0 :             return false;
    2588                 : 
    2589                 :         /*
    2590                 :          * If the property is configurable, this object is neither sealed nor
    2591                 :          * frozen. If the property is a writable data property, this object is
    2592                 :          * not frozen.
    2593                 :          */
    2594           15269 :         if (!(attrs & JSPROP_PERMANENT) ||
    2595            4228 :             (it == FREEZE && !(attrs & (JSPROP_READONLY | JSPROP_GETTER | JSPROP_SETTER))))
    2596                 :         {
    2597             234 :             *resultp = false;
    2598             234 :             return true;
    2599                 :         }
    2600                 :     }
    2601                 : 
    2602                 :     /* All properties checked out. This object is sealed/frozen. */
    2603             653 :     *resultp = true;
    2604             653 :     return true;
    2605                 : }
    2606                 : 
    2607                 : static JSBool
    2608            1145 : obj_freeze(JSContext *cx, unsigned argc, Value *vp)
    2609                 : {
    2610                 :     JSObject *obj;
    2611            1145 :     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.freeze", &obj))
    2612               0 :         return false;
    2613                 : 
    2614            1145 :     vp->setObject(*obj);
    2615                 : 
    2616            1145 :     return obj->freeze(cx);
    2617                 : }
    2618                 : 
    2619                 : static JSBool
    2620             329 : obj_isFrozen(JSContext *cx, unsigned argc, Value *vp)
    2621                 : {
    2622                 :     JSObject *obj;
    2623             329 :     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.preventExtensions", &obj))
    2624               9 :         return false;
    2625                 : 
    2626                 :     bool frozen;
    2627             320 :     if (!obj->isFrozen(cx, &frozen))
    2628               0 :         return false;
    2629             320 :     vp->setBoolean(frozen);
    2630             320 :     return true;
    2631                 : }
    2632                 : 
    2633                 : static JSBool
    2634             252 : obj_seal(JSContext *cx, unsigned argc, Value *vp)
    2635                 : {
    2636                 :     JSObject *obj;
    2637             252 :     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.seal", &obj))
    2638               0 :         return false;
    2639                 : 
    2640             252 :     vp->setObject(*obj);
    2641                 : 
    2642             252 :     return obj->seal(cx);
    2643                 : }
    2644                 : 
    2645                 : static JSBool
    2646             315 : obj_isSealed(JSContext *cx, unsigned argc, Value *vp)
    2647                 : {
    2648                 :     JSObject *obj;
    2649             315 :     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.isSealed", &obj))
    2650               0 :         return false;
    2651                 : 
    2652                 :     bool sealed;
    2653             315 :     if (!obj->isSealed(cx, &sealed))
    2654               0 :         return false;
    2655             315 :     vp->setBoolean(sealed);
    2656             315 :     return true;
    2657                 : }
    2658                 : 
    2659                 : #if JS_HAS_OBJ_WATCHPOINT
    2660                 : const char js_watch_str[] = "watch";
    2661                 : const char js_unwatch_str[] = "unwatch";
    2662                 : #endif
    2663                 : const char js_hasOwnProperty_str[] = "hasOwnProperty";
    2664                 : const char js_isPrototypeOf_str[] = "isPrototypeOf";
    2665                 : const char js_propertyIsEnumerable_str[] = "propertyIsEnumerable";
    2666                 : 
    2667                 : JSFunctionSpec object_methods[] = {
    2668                 : #if JS_HAS_TOSOURCE
    2669                 :     JS_FN(js_toSource_str,             obj_toSource,                0,0),
    2670                 : #endif
    2671                 :     JS_FN(js_toString_str,             obj_toString,                0,0),
    2672                 :     JS_FN(js_toLocaleString_str,       obj_toLocaleString,          0,0),
    2673                 :     JS_FN(js_valueOf_str,              obj_valueOf,                 0,0),
    2674                 : #if JS_HAS_OBJ_WATCHPOINT
    2675                 :     JS_FN(js_watch_str,                obj_watch,                   2,0),
    2676                 :     JS_FN(js_unwatch_str,              obj_unwatch,                 1,0),
    2677                 : #endif
    2678                 :     JS_FN(js_hasOwnProperty_str,       obj_hasOwnProperty,          1,0),
    2679                 :     JS_FN(js_isPrototypeOf_str,        obj_isPrototypeOf,           1,0),
    2680                 :     JS_FN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable,    1,0),
    2681                 : #if OLD_GETTER_SETTER_METHODS
    2682                 :     JS_FN(js_defineGetter_str,         js::obj_defineGetter,        2,0),
    2683                 :     JS_FN(js_defineSetter_str,         js::obj_defineSetter,        2,0),
    2684                 :     JS_FN(js_lookupGetter_str,         obj_lookupGetter,            1,0),
    2685                 :     JS_FN(js_lookupSetter_str,         obj_lookupSetter,            1,0),
    2686                 : #endif
    2687                 :     JS_FS_END
    2688                 : };
    2689                 : 
    2690                 : JSFunctionSpec object_static_methods[] = {
    2691                 :     JS_FN("getPrototypeOf",            obj_getPrototypeOf,          1,0),
    2692                 :     JS_FN("getOwnPropertyDescriptor",  obj_getOwnPropertyDescriptor,2,0),
    2693                 :     JS_FN("keys",                      obj_keys,                    1,0),
    2694                 :     JS_FN("defineProperty",            obj_defineProperty,          3,0),
    2695                 :     JS_FN("defineProperties",          obj_defineProperties,        2,0),
    2696                 :     JS_FN("create",                    obj_create,                  2,0),
    2697                 :     JS_FN("getOwnPropertyNames",       obj_getOwnPropertyNames,     1,0),
    2698                 :     JS_FN("isExtensible",              obj_isExtensible,            1,0),
    2699                 :     JS_FN("preventExtensions",         obj_preventExtensions,       1,0),
    2700                 :     JS_FN("freeze",                    obj_freeze,                  1,0),
    2701                 :     JS_FN("isFrozen",                  obj_isFrozen,                1,0),
    2702                 :     JS_FN("seal",                      obj_seal,                    1,0),
    2703                 :     JS_FN("isSealed",                  obj_isSealed,                1,0),
    2704                 :     JS_FS_END
    2705                 : };
    2706                 : 
    2707                 : JSBool
    2708            4006 : js_Object(JSContext *cx, unsigned argc, Value *vp)
    2709                 : {
    2710                 :     JSObject *obj;
    2711            4006 :     if (argc == 0) {
    2712                 :         /* Trigger logic below to construct a blank object. */
    2713            3637 :         obj = NULL;
    2714                 :     } else {
    2715                 :         /* If argv[0] is null or undefined, obj comes back null. */
    2716             369 :         if (!js_ValueToObjectOrNull(cx, vp[2], &obj))
    2717               0 :             return JS_FALSE;
    2718                 :     }
    2719            4006 :     if (!obj) {
    2720                 :         /* Make an object whether this was called with 'new' or not. */
    2721            3637 :         JS_ASSERT(!argc || vp[2].isNull() || vp[2].isUndefined());
    2722            3637 :         gc::AllocKind kind = NewObjectGCKind(cx, &ObjectClass);
    2723            3637 :         obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
    2724            3637 :         if (!obj)
    2725               0 :             return JS_FALSE;
    2726            3637 :         TypeObject *type = GetTypeCallerInitObject(cx, JSProto_Object);
    2727            3637 :         if (!type)
    2728               0 :             return JS_FALSE;
    2729            3637 :         obj->setType(type);
    2730                 :     }
    2731            4006 :     vp->setObject(*obj);
    2732            4006 :     return JS_TRUE;
    2733                 : }
    2734                 : 
    2735                 : static inline JSObject *
    2736         8844619 : NewObject(JSContext *cx, Class *clasp, types::TypeObject *type, JSObject *parent,
    2737                 :           gc::AllocKind kind)
    2738                 : {
    2739         8844619 :     JS_ASSERT(clasp != &ArrayClass);
    2740               0 :     JS_ASSERT_IF(clasp == &FunctionClass,
    2741         8844619 :                  kind == JSFunction::FinalizeKind || kind == JSFunction::ExtendedFinalizeKind);
    2742                 : 
    2743        17689238 :     RootTypeObject typeRoot(cx, &type);
    2744                 : 
    2745        17689238 :     RootedVarShape shape(cx);
    2746         8844619 :     shape = EmptyShape::getInitialShape(cx, clasp, type->proto, parent, kind);
    2747         8844619 :     if (!shape)
    2748               0 :         return NULL;
    2749                 : 
    2750                 :     HeapSlot *slots;
    2751         8844619 :     if (!PreallocateObjectDynamicSlots(cx, shape, &slots))
    2752               0 :         return NULL;
    2753                 : 
    2754         8844619 :     JSObject *obj = JSObject::create(cx, kind, shape, typeRoot, slots);
    2755         8844619 :     if (!obj)
    2756               0 :         return NULL;
    2757                 : 
    2758                 :     /*
    2759                 :      * This will cancel an already-running incremental GC from doing any more
    2760                 :      * slices, and it will prevent any future incremental GCs.
    2761                 :      */
    2762         8844619 :     if (clasp->trace && !(clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS))
    2763               0 :         cx->runtime->gcIncrementalEnabled = false;
    2764                 : 
    2765         8844619 :     Probes::createObject(cx, obj);
    2766         8844619 :     return obj;
    2767                 : }
    2768                 : 
    2769                 : JSObject *
    2770         4290181 : js::NewObjectWithGivenProto(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
    2771                 :                             gc::AllocKind kind)
    2772                 : {
    2773         4290181 :     if (CanBeFinalizedInBackground(kind, clasp))
    2774          843816 :         kind = GetBackgroundAllocKind(kind);
    2775                 : 
    2776         4290181 :     NewObjectCache &cache = cx->compartment->newObjectCache;
    2777                 : 
    2778         4290181 :     NewObjectCache::EntryIndex entry = -1;
    2779         4290181 :     if (proto && (!parent || parent == proto->getParent()) && !proto->isGlobal()) {
    2780         4028512 :         if (cache.lookupProto(clasp, proto, kind, &entry))
    2781         3269421 :             return cache.newObjectFromHit(cx, entry);
    2782                 :     }
    2783                 : 
    2784         2041520 :     RootObject protoRoot(cx, &proto);
    2785         2041520 :     RootObject parentRoot(cx, &parent);
    2786                 : 
    2787         1020760 :     types::TypeObject *type = proto ? proto->getNewType(cx) : cx->compartment->getEmptyType(cx);
    2788         1020760 :     if (!type)
    2789               0 :         return NULL;
    2790                 : 
    2791                 :     /*
    2792                 :      * Default parent to the parent of the prototype, which was set from
    2793                 :      * the parent of the prototype's constructor.
    2794                 :      */
    2795         1020760 :     if (!parent && proto)
    2796           28208 :         parent = proto->getParent();
    2797                 : 
    2798         1020760 :     JSObject *obj = NewObject(cx, clasp, type, parent, kind);
    2799         1020760 :     if (!obj)
    2800               0 :         return NULL;
    2801                 : 
    2802         1020760 :     if (entry != -1 && !obj->hasDynamicSlots())
    2803          759091 :         cache.fillProto(entry, clasp, proto, kind, obj);
    2804                 : 
    2805         1020760 :     return obj;
    2806                 : }
    2807                 : 
    2808                 : JSObject *
    2809        31051111 : js::NewObjectWithClassProto(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
    2810                 :                             gc::AllocKind kind)
    2811                 : {
    2812        31051111 :     if (proto)
    2813         3238437 :         return NewObjectWithGivenProto(cx, clasp, proto, parent, kind);
    2814                 : 
    2815        27812674 :     if (CanBeFinalizedInBackground(kind, clasp))
    2816         6440513 :         kind = GetBackgroundAllocKind(kind);
    2817                 : 
    2818        27812674 :     if (!parent)
    2819        13957198 :         parent = GetCurrentGlobal(cx);
    2820                 : 
    2821                 :     /*
    2822                 :      * Use the object cache, except for classes without a cached proto key.
    2823                 :      * On these objects, FindProto will do a dynamic property lookup to get
    2824                 :      * global[className].prototype, where changes to either the className or
    2825                 :      * prototype property would render the cached lookup incorrect. For classes
    2826                 :      * with a proto key, the prototype created during class initialization is
    2827                 :      * stored in an immutable slot on the global (except for ClearScope, which
    2828                 :      * will flush the new object cache).
    2829                 :      */
    2830        27812674 :     JSProtoKey protoKey = GetClassProtoKey(clasp);
    2831                 : 
    2832        27812674 :     NewObjectCache &cache = cx->compartment->newObjectCache;
    2833                 : 
    2834        27812674 :     NewObjectCache::EntryIndex entry = -1;
    2835        27812674 :     if (parent->isGlobal() && protoKey != JSProto_Null) {
    2836        20417209 :         if (cache.lookupGlobal(clasp, &parent->asGlobal(), kind, &entry))
    2837        20060930 :             return cache.newObjectFromHit(cx, entry);
    2838                 :     }
    2839                 : 
    2840        15503488 :     RootObject parentRoot(cx, &parent);
    2841                 : 
    2842         7751744 :     if (!FindProto(cx, clasp, parentRoot, &proto))
    2843               0 :         return NULL;
    2844                 : 
    2845         7751744 :     types::TypeObject *type = proto->getNewType(cx);
    2846         7751744 :     if (!type)
    2847               0 :         return NULL;
    2848                 : 
    2849         7751744 :     JSObject *obj = NewObject(cx, clasp, type, parent, kind);
    2850         7751744 :     if (!obj)
    2851               0 :         return NULL;
    2852                 : 
    2853         7751744 :     if (entry != -1 && !obj->hasDynamicSlots())
    2854          356279 :         cache.fillGlobal(entry, clasp, &parent->asGlobal(), kind, obj);
    2855                 : 
    2856         7751744 :     return obj;
    2857                 : }
    2858                 : 
    2859                 : JSObject *
    2860         2658510 : js::NewObjectWithType(JSContext *cx, types::TypeObject *type, JSObject *parent, gc::AllocKind kind)
    2861                 : {
    2862         2658510 :     JS_ASSERT(type->proto->hasNewType(type));
    2863         2658510 :     JS_ASSERT(parent);
    2864                 : 
    2865         2658510 :     if (CanBeFinalizedInBackground(kind, &ObjectClass))
    2866         2658510 :         kind = GetBackgroundAllocKind(kind);
    2867                 : 
    2868         2658510 :     NewObjectCache &cache = cx->compartment->newObjectCache;
    2869                 : 
    2870         2658510 :     NewObjectCache::EntryIndex entry = -1;
    2871         2658510 :     if (parent == type->proto->getParent()) {
    2872         2658063 :         if (cache.lookupType(&ObjectClass, type, kind, &entry))
    2873         2586395 :             return cache.newObjectFromHit(cx, entry);
    2874                 :     }
    2875                 : 
    2876           72115 :     JSObject *obj = NewObject(cx, &ObjectClass, type, parent, kind);
    2877           72115 :     if (!obj)
    2878               0 :         return NULL;
    2879                 : 
    2880           72115 :     if (entry != -1 && !obj->hasDynamicSlots())
    2881           71668 :         cache.fillType(entry, &ObjectClass, type, kind, obj);
    2882                 : 
    2883           72115 :     return obj;
    2884                 : }
    2885                 : 
    2886                 : JSObject *
    2887             597 : js::NewReshapedObject(JSContext *cx, TypeObject *type, JSObject *parent,
    2888                 :                       gc::AllocKind kind, const Shape *shape)
    2889                 : {
    2890             597 :     JSObject *res = NewObjectWithType(cx, type, parent, kind);
    2891             597 :     if (!res)
    2892               0 :         return NULL;
    2893                 : 
    2894             597 :     if (shape->isEmptyShape())
    2895               0 :         return res;
    2896                 : 
    2897                 :     /* Get all the ids in the object, in order. */
    2898            1194 :     js::AutoIdVector ids(cx);
    2899            1628 :     for (unsigned i = 0; i <= shape->slot(); i++) {
    2900            1031 :         if (!ids.append(JSID_VOID))
    2901               0 :             return NULL;
    2902                 :     }
    2903             597 :     const js::Shape *nshape = shape;
    2904            2225 :     while (!nshape->isEmptyShape()) {
    2905            1031 :         ids[nshape->slot()] = nshape->propid();
    2906            1031 :         nshape = nshape->previous();
    2907                 :     }
    2908                 : 
    2909                 :     /* Construct the new shape. */
    2910            1628 :     for (unsigned i = 0; i < ids.length(); i++) {
    2911            2062 :         if (!DefineNativeProperty(cx, res, ids[i], js::UndefinedValue(), NULL, NULL,
    2912            2062 :                                   JSPROP_ENUMERATE, 0, 0, DNP_SKIP_TYPE)) {
    2913               0 :             return NULL;
    2914                 :         }
    2915                 :     }
    2916             597 :     JS_ASSERT(!res->inDictionaryMode());
    2917                 : 
    2918             597 :     return res;
    2919                 : }
    2920                 : 
    2921                 : JSObject*
    2922              37 : js_CreateThis(JSContext *cx, JSObject *callee)
    2923                 : {
    2924              37 :     Class *clasp = callee->getClass();
    2925                 : 
    2926              37 :     Class *newclasp = &ObjectClass;
    2927              37 :     if (clasp == &FunctionClass) {
    2928              18 :         JSFunction *fun = callee->toFunction();
    2929              18 :         if (fun->isNative() && fun->u.n.clasp)
    2930              18 :             newclasp = fun->u.n.clasp;
    2931                 :     }
    2932                 : 
    2933                 :     Value protov;
    2934              37 :     if (!callee->getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &protov))
    2935               0 :         return NULL;
    2936                 : 
    2937              37 :     JSObject *proto = protov.isObjectOrNull() ? protov.toObjectOrNull() : NULL;
    2938              37 :     JSObject *parent = callee->getParent();
    2939              37 :     gc::AllocKind kind = NewObjectGCKind(cx, newclasp);
    2940              37 :     return NewObjectWithClassProto(cx, newclasp, proto, parent, kind);
    2941                 : }
    2942                 : 
    2943                 : static inline JSObject *
    2944         2657913 : CreateThisForFunctionWithType(JSContext *cx, types::TypeObject *type, JSObject *parent)
    2945                 : {
    2946         2657913 :     if (type->newScript) {
    2947                 :         /*
    2948                 :          * Make an object with the type's associated finalize kind and shape,
    2949                 :          * which reflects any properties that will definitely be added to the
    2950                 :          * object before it is read from.
    2951                 :          */
    2952          349841 :         gc::AllocKind kind = type->newScript->allocKind;
    2953          349841 :         JSObject *res = NewObjectWithType(cx, type, parent, kind);
    2954          349841 :         if (res)
    2955          349841 :             JS_ALWAYS_TRUE(res->setLastProperty(cx, (Shape *) type->newScript->shape.get()));
    2956          349841 :         return res;
    2957                 :     }
    2958                 : 
    2959         2308072 :     gc::AllocKind kind = NewObjectGCKind(cx, &ObjectClass);
    2960         2308072 :     return NewObjectWithType(cx, type, parent, kind);
    2961                 : }
    2962                 : 
    2963                 : JSObject *
    2964         2658003 : js_CreateThisForFunctionWithProto(JSContext *cx, JSObject *callee, JSObject *proto)
    2965                 : {
    2966                 :     JSObject *res;
    2967                 : 
    2968         2658003 :     if (proto) {
    2969         2657913 :         types::TypeObject *type = proto->getNewType(cx, callee->toFunction());
    2970         2657913 :         if (!type)
    2971               0 :             return NULL;
    2972         2657913 :         res = CreateThisForFunctionWithType(cx, type, callee->getParent());
    2973                 :     } else {
    2974              90 :         gc::AllocKind kind = NewObjectGCKind(cx, &ObjectClass);
    2975              90 :         res = NewObjectWithClassProto(cx, &ObjectClass, proto, callee->getParent(), kind);
    2976                 :     }
    2977                 : 
    2978         2658003 :     if (res && cx->typeInferenceEnabled())
    2979          780622 :         TypeScript::SetThis(cx, callee->toFunction()->script(), types::Type::ObjectType(res));
    2980                 : 
    2981         2658003 :     return res;
    2982                 : }
    2983                 : 
    2984                 : JSObject *
    2985          996775 : js_CreateThisForFunction(JSContext *cx, JSObject *callee, bool newType)
    2986                 : {
    2987                 :     Value protov;
    2988          996775 :     if (!callee->getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &protov))
    2989               0 :         return NULL;
    2990                 :     JSObject *proto;
    2991          996775 :     if (protov.isObject())
    2992          996725 :         proto = &protov.toObject();
    2993                 :     else
    2994              50 :         proto = NULL;
    2995          996775 :     JSObject *obj = js_CreateThisForFunctionWithProto(cx, callee, proto);
    2996                 : 
    2997          996775 :     if (obj && newType) {
    2998                 :         /*
    2999                 :          * Reshape the object and give it a (lazily instantiated) singleton
    3000                 :          * type before passing it as the 'this' value for the call.
    3001                 :          */
    3002              10 :         obj->clear(cx);
    3003              10 :         if (!obj->setSingletonType(cx))
    3004               0 :             return NULL;
    3005                 : 
    3006              10 :         JSScript *calleeScript = callee->toFunction()->script();
    3007              10 :         TypeScript::SetThis(cx, calleeScript, types::Type::ObjectType(obj));
    3008                 :     }
    3009                 : 
    3010          996775 :     return obj;
    3011                 : }
    3012                 : 
    3013                 : /*
    3014                 :  * Given pc pointing after a property accessing bytecode, return true if the
    3015                 :  * access is "object-detecting" in the sense used by web scripts, e.g., when
    3016                 :  * checking whether document.all is defined.
    3017                 :  */
    3018                 : static bool
    3019         3182503 : Detecting(JSContext *cx, jsbytecode *pc)
    3020                 : {
    3021                 :     /* General case: a branch or equality op follows the access. */
    3022         3182503 :     JSOp op = JSOp(*pc);
    3023         3182503 :     if (js_CodeSpec[op].format & JOF_DETECTING)
    3024          413805 :         return true;
    3025                 : 
    3026                 :     JSAtom *atom;
    3027                 : 
    3028         2768698 :     JSScript *script = cx->stack.currentScript();
    3029         2768698 :     jsbytecode *endpc = script->code + script->length;
    3030         2768698 :     JS_ASSERT(script->code <= pc && pc < endpc);
    3031                 : 
    3032         2768698 :     if (op == JSOP_NULL) {
    3033                 :         /*
    3034                 :          * Special case #1: handle (document.all == null).  Don't sweat
    3035                 :          * about JS1.2's revision of the equality operators here.
    3036                 :          */
    3037             567 :         if (++pc < endpc) {
    3038             567 :             op = JSOp(*pc);
    3039             567 :             return op == JSOP_EQ || op == JSOP_NE;
    3040                 :         }
    3041               0 :         return false;
    3042                 :     }
    3043                 : 
    3044         2768131 :     if (op == JSOP_GETGNAME || op == JSOP_NAME) {
    3045                 :         /*
    3046                 :          * Special case #2: handle (document.all == undefined).  Don't worry
    3047                 :          * about a local variable named |undefined| shadowing the immutable
    3048                 :          * global binding...because, really?
    3049                 :          */
    3050          204814 :         atom = script->getAtom(GET_UINT32_INDEX(pc));
    3051          205960 :         if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID] &&
    3052            1146 :             (pc += js_CodeSpec[op].length) < endpc) {
    3053            1146 :             op = JSOp(*pc);
    3054            1146 :             return op == JSOP_EQ || op == JSOP_NE || op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
    3055                 :         }
    3056                 :     }
    3057                 : 
    3058         2766985 :     return false;
    3059                 : }
    3060                 : 
    3061                 : /*
    3062                 :  * Infer lookup flags from the currently executing bytecode. This does
    3063                 :  * not attempt to infer JSRESOLVE_WITH, because the current bytecode
    3064                 :  * does not indicate whether we are in a with statement. Return defaultFlags
    3065                 :  * if a currently executing bytecode cannot be determined.
    3066                 :  */
    3067                 : unsigned
    3068         3372368 : js_InferFlags(JSContext *cx, unsigned defaultFlags)
    3069                 : {
    3070                 :     const JSCodeSpec *cs;
    3071                 :     uint32_t format;
    3072         3372368 :     unsigned flags = 0;
    3073                 : 
    3074                 :     jsbytecode *pc;
    3075         3372368 :     JSScript *script = cx->stack.currentScript(&pc);
    3076         3372368 :     if (!script || !pc)
    3077            7500 :         return defaultFlags;
    3078                 : 
    3079         3364868 :     cs = &js_CodeSpec[*pc];
    3080         3364868 :     format = cs->format;
    3081         3364868 :     if (JOF_MODE(format) != JOF_NAME)
    3082         1812870 :         flags |= JSRESOLVE_QUALIFIED;
    3083         3364868 :     if (format & JOF_SET) {
    3084          276136 :         flags |= JSRESOLVE_ASSIGNING;
    3085         3088732 :     } else if (cs->length >= 0) {
    3086         3088732 :         pc += cs->length;
    3087         3088732 :         if (pc < script->code + script->length && Detecting(cx, pc))
    3088          321066 :             flags |= JSRESOLVE_DETECTING;
    3089                 :     }
    3090         3364868 :     if (format & JOF_DECLARING)
    3091          486177 :         flags |= JSRESOLVE_DECLARING;
    3092         3364868 :     return flags;
    3093                 : }
    3094                 : 
    3095                 : JSBool
    3096         3840334 : JSObject::nonNativeSetProperty(JSContext *cx, jsid id, js::Value *vp, JSBool strict)
    3097                 : {
    3098         3840334 :     if (JS_UNLIKELY(watched())) {
    3099               0 :         id = js_CheckForStringIndex(id);
    3100               0 :         WatchpointMap *wpmap = cx->compartment->watchpointMap;
    3101               0 :         if (wpmap && !wpmap->triggerWatchpoint(cx, this, id, vp))
    3102               0 :             return false;
    3103                 :     }
    3104         3840334 :     return getOps()->setGeneric(cx, this, id, vp, strict);
    3105                 : }
    3106                 : 
    3107                 : JSBool
    3108        13549124 : JSObject::nonNativeSetElement(JSContext *cx, uint32_t index, js::Value *vp, JSBool strict)
    3109                 : {
    3110        13549124 :     if (JS_UNLIKELY(watched())) {
    3111                 :         jsid id;
    3112               0 :         if (!IndexToId(cx, index, &id))
    3113               0 :             return false;
    3114               0 :         JS_ASSERT(id == js_CheckForStringIndex(id));
    3115               0 :         WatchpointMap *wpmap = cx->compartment->watchpointMap;
    3116               0 :         if (wpmap && !wpmap->triggerWatchpoint(cx, this, id, vp))
    3117               0 :             return false;
    3118                 :     }
    3119        13549124 :     return getOps()->setElement(cx, this, index, vp, strict);
    3120                 : }
    3121                 : 
    3122                 : bool
    3123           26852 : JSObject::deleteByValue(JSContext *cx, const Value &property, Value *rval, bool strict)
    3124                 : {
    3125                 :     uint32_t index;
    3126           26852 :     if (IsDefinitelyIndex(property, &index))
    3127            6014 :         return deleteElement(cx, index, rval, strict);
    3128                 : 
    3129           20838 :     Value propval = property;
    3130           20838 :     SpecialId sid;
    3131           20838 :     if (ValueIsSpecial(this, &propval, &sid, cx))
    3132               0 :         return deleteSpecial(cx, sid, rval, strict);
    3133                 : 
    3134                 :     JSAtom *name;
    3135           20838 :     if (!js_ValueToAtom(cx, propval, &name))
    3136               0 :         return false;
    3137                 : 
    3138           20838 :     if (name->isIndex(&index))
    3139              36 :         return deleteElement(cx, index, rval, false);
    3140                 : 
    3141           20802 :     return deleteProperty(cx, name->asPropertyName(), rval, false);
    3142                 : }
    3143                 : 
    3144                 : JS_FRIEND_API(bool)
    3145               0 : JS_CopyPropertiesFrom(JSContext *cx, JSObject *target, JSObject *obj)
    3146                 : {
    3147                 :     // If we're not native, then we cannot copy properties.
    3148               0 :     JS_ASSERT(target->isNative() == obj->isNative());
    3149               0 :     if (!target->isNative())
    3150               0 :         return true;
    3151                 : 
    3152               0 :     AutoShapeVector shapes(cx);
    3153               0 :     for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) {
    3154               0 :         if (!shapes.append(&r.front()))
    3155               0 :             return false;
    3156                 :     }
    3157                 : 
    3158               0 :     size_t n = shapes.length();
    3159               0 :     while (n > 0) {
    3160               0 :         const Shape *shape = shapes[--n];
    3161               0 :         unsigned attrs = shape->attributes();
    3162               0 :         PropertyOp getter = shape->getter();
    3163               0 :         if ((attrs & JSPROP_GETTER) && !cx->compartment->wrap(cx, &getter))
    3164               0 :             return false;
    3165               0 :         StrictPropertyOp setter = shape->setter();
    3166               0 :         if ((attrs & JSPROP_SETTER) && !cx->compartment->wrap(cx, &setter))
    3167               0 :             return false;
    3168               0 :         Value v = shape->hasSlot() ? obj->getSlot(shape->slot()) : UndefinedValue();
    3169               0 :         if (!cx->compartment->wrap(cx, &v))
    3170               0 :             return false;
    3171               0 :         if (!target->defineGeneric(cx, shape->propid(), v, getter, setter, attrs))
    3172               0 :             return false;
    3173                 :     }
    3174               0 :     return true;
    3175                 : }
    3176                 : 
    3177                 : static bool
    3178               0 : CopySlots(JSContext *cx, JSObject *from, JSObject *to)
    3179                 : {
    3180               0 :     JS_ASSERT(!from->isNative() && !to->isNative());
    3181               0 :     JS_ASSERT(from->getClass() == to->getClass());
    3182                 : 
    3183               0 :     size_t n = 0;
    3184               0 :     if (from->isWrapper() &&
    3185               0 :         (Wrapper::wrapperHandler(from)->flags() & Wrapper::CROSS_COMPARTMENT)) {
    3186               0 :         to->setSlot(0, from->getSlot(0));
    3187               0 :         to->setSlot(1, from->getSlot(1));
    3188               0 :         n = 2;
    3189                 :     }
    3190                 : 
    3191               0 :     size_t span = JSCLASS_RESERVED_SLOTS(from->getClass());
    3192               0 :     for (; n < span; ++n) {
    3193               0 :         Value v = from->getSlot(n);
    3194               0 :         if (!cx->compartment->wrap(cx, &v))
    3195               0 :             return false;
    3196               0 :         to->setSlot(n, v);
    3197                 :     }
    3198               0 :     return true;
    3199                 : }
    3200                 : 
    3201                 : JS_FRIEND_API(JSObject *)
    3202               0 : JS_CloneObject(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent)
    3203                 : {
    3204                 :     /*
    3205                 :      * We can only clone native objects and proxies. Dense arrays are slowified if
    3206                 :      * we try to clone them.
    3207                 :      */
    3208               0 :     if (!obj->isNative()) {
    3209               0 :         if (obj->isDenseArray()) {
    3210               0 :             if (!obj->makeDenseArraySlow(cx))
    3211               0 :                 return NULL;
    3212               0 :         } else if (!obj->isProxy()) {
    3213                 :             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
    3214               0 :                                  JSMSG_CANT_CLONE_OBJECT);
    3215               0 :             return NULL;
    3216                 :         }
    3217                 :     }
    3218               0 :     JSObject *clone = NewObjectWithGivenProto(cx, obj->getClass(), proto, parent, obj->getAllocKind());
    3219               0 :     if (!clone)
    3220               0 :         return NULL;
    3221               0 :     if (obj->isNative()) {
    3222               0 :         if (clone->isFunction() && (obj->compartment() != clone->compartment())) {
    3223                 :             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
    3224               0 :                                  JSMSG_CANT_CLONE_OBJECT);
    3225               0 :             return NULL;
    3226                 :         }
    3227                 : 
    3228               0 :         if (obj->hasPrivate())
    3229               0 :             clone->setPrivate(obj->getPrivate());
    3230                 :     } else {
    3231               0 :         JS_ASSERT(obj->isProxy());
    3232               0 :         if (!CopySlots(cx, obj, clone))
    3233               0 :             return NULL;
    3234                 :     }
    3235                 : 
    3236               0 :     return clone;
    3237                 : }
    3238                 : 
    3239                 : struct JSObject::TradeGutsReserved {
    3240                 :     JSContext *cx;
    3241                 :     Vector<Value> avals;
    3242                 :     Vector<Value> bvals;
    3243                 :     int newafixed;
    3244                 :     int newbfixed;
    3245                 :     Shape *newashape;
    3246                 :     Shape *newbshape;
    3247                 :     HeapSlot *newaslots;
    3248                 :     HeapSlot *newbslots;
    3249                 : 
    3250              40 :     TradeGutsReserved(JSContext *cx)
    3251                 :         : cx(cx), avals(cx), bvals(cx),
    3252                 :           newafixed(0), newbfixed(0),
    3253                 :           newashape(NULL), newbshape(NULL),
    3254              40 :           newaslots(NULL), newbslots(NULL)
    3255              40 :     {}
    3256                 : 
    3257              40 :     ~TradeGutsReserved()
    3258              40 :     {
    3259              40 :         if (newaslots)
    3260               0 :             cx->free_(newaslots);
    3261              40 :         if (newbslots)
    3262               0 :             cx->free_(newbslots);
    3263              40 :     }
    3264                 : };
    3265                 : 
    3266                 : bool
    3267              40 : JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b,
    3268                 :                               TradeGutsReserved &reserved)
    3269                 : {
    3270                 :     /*
    3271                 :      * When performing multiple swaps between objects which may have different
    3272                 :      * numbers of fixed slots, we reserve all space ahead of time so that the
    3273                 :      * swaps can be performed infallibly.
    3274                 :      */
    3275                 : 
    3276              40 :     if (a->sizeOfThis() == b->sizeOfThis())
    3277              40 :         return true;
    3278                 : 
    3279                 :     /*
    3280                 :      * If either object is native, it needs a new shape to preserve the
    3281                 :      * invariant that objects with the same shape have the same number of
    3282                 :      * inline slots. The fixed slots will be updated in place during TradeGuts.
    3283                 :      * Non-native objects need to be reshaped according to the new count.
    3284                 :      */
    3285               0 :     if (a->isNative()) {
    3286               0 :         if (!a->generateOwnShape(cx))
    3287               0 :             return false;
    3288                 :     } else {
    3289                 :         reserved.newbshape = EmptyShape::getInitialShape(cx, a->getClass(),
    3290                 :                                                          a->getProto(), a->getParent(),
    3291               0 :                                                          b->getAllocKind());
    3292               0 :         if (!reserved.newbshape)
    3293               0 :             return false;
    3294                 :     }
    3295               0 :     if (b->isNative()) {
    3296               0 :         if (!b->generateOwnShape(cx))
    3297               0 :             return false;
    3298                 :     } else {
    3299                 :         reserved.newashape = EmptyShape::getInitialShape(cx, b->getClass(),
    3300                 :                                                          b->getProto(), b->getParent(),
    3301               0 :                                                          a->getAllocKind());
    3302               0 :         if (!reserved.newashape)
    3303               0 :             return false;
    3304                 :     }
    3305                 : 
    3306                 :     /* The avals/bvals vectors hold all original values from the objects. */
    3307                 : 
    3308               0 :     if (!reserved.avals.reserve(a->slotSpan()))
    3309               0 :         return false;
    3310               0 :     if (!reserved.bvals.reserve(b->slotSpan()))
    3311               0 :         return false;
    3312                 : 
    3313               0 :     JS_ASSERT(a->elements == emptyObjectElements);
    3314               0 :     JS_ASSERT(b->elements == emptyObjectElements);
    3315                 : 
    3316                 :     /*
    3317                 :      * The newafixed/newbfixed hold the number of fixed slots in the objects
    3318                 :      * after the swap. Adjust these counts according to whether the objects
    3319                 :      * use their last fixed slot for storing private data.
    3320                 :      */
    3321                 : 
    3322               0 :     reserved.newafixed = a->numFixedSlots();
    3323               0 :     reserved.newbfixed = b->numFixedSlots();
    3324                 : 
    3325               0 :     if (a->hasPrivate()) {
    3326               0 :         reserved.newafixed++;
    3327               0 :         reserved.newbfixed--;
    3328                 :     }
    3329               0 :     if (b->hasPrivate()) {
    3330               0 :         reserved.newbfixed++;
    3331               0 :         reserved.newafixed--;
    3332                 :     }
    3333                 : 
    3334               0 :     JS_ASSERT(reserved.newafixed >= 0);
    3335               0 :     JS_ASSERT(reserved.newbfixed >= 0);
    3336                 : 
    3337                 :     /*
    3338                 :      * The newaslots/newbslots arrays hold any dynamic slots for the objects
    3339                 :      * if they do not have enough fixed slots to accomodate the slots in the
    3340                 :      * other object.
    3341                 :      */
    3342                 : 
    3343               0 :     unsigned adynamic = dynamicSlotsCount(reserved.newafixed, b->slotSpan());
    3344               0 :     unsigned bdynamic = dynamicSlotsCount(reserved.newbfixed, a->slotSpan());
    3345                 : 
    3346               0 :     if (adynamic) {
    3347               0 :         reserved.newaslots = (HeapSlot *) cx->malloc_(sizeof(HeapSlot) * adynamic);
    3348               0 :         if (!reserved.newaslots)
    3349               0 :             return false;
    3350               0 :         Debug_SetSlotRangeToCrashOnTouch(reserved.newaslots, adynamic);
    3351                 :     }
    3352               0 :     if (bdynamic) {
    3353               0 :         reserved.newbslots = (HeapSlot *) cx->malloc_(sizeof(HeapSlot) * bdynamic);
    3354               0 :         if (!reserved.newbslots)
    3355               0 :             return false;
    3356               0 :         Debug_SetSlotRangeToCrashOnTouch(reserved.newbslots, bdynamic);
    3357                 :     }
    3358                 : 
    3359               0 :     return true;
    3360                 : }
    3361                 : 
    3362                 : void
    3363              40 : JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &reserved)
    3364                 : {
    3365              40 :     JS_ASSERT(a->compartment() == b->compartment());
    3366              40 :     JS_ASSERT(a->isFunction() == b->isFunction());
    3367                 : 
    3368                 :     /* Don't try to swap a JSFunction for a plain function JSObject. */
    3369              40 :     JS_ASSERT_IF(a->isFunction(), a->sizeOfThis() == b->sizeOfThis());
    3370                 : 
    3371                 :     /*
    3372                 :      * Regexp guts are more complicated -- we would need to migrate the
    3373                 :      * refcounted JIT code blob for them across compartments instead of just
    3374                 :      * swapping guts.
    3375                 :      */
    3376              40 :     JS_ASSERT(!a->isRegExp() && !b->isRegExp());
    3377                 : 
    3378                 :     /*
    3379                 :      * Callers should not try to swap dense arrays or ArrayBuffer objects,
    3380                 :      * these use a different slot representation from other objects.
    3381                 :      */
    3382              40 :     JS_ASSERT(!a->isDenseArray() && !b->isDenseArray());
    3383              40 :     JS_ASSERT(!a->isArrayBuffer() && !b->isArrayBuffer());
    3384                 : 
    3385                 : #ifdef JSGC_INCREMENTAL
    3386                 :     /*
    3387                 :      * We need a write barrier here. If |a| was marked and |b| was not, then
    3388                 :      * after the swap, |b|'s guts would never be marked. The write barrier
    3389                 :      * solves this.
    3390                 :      */
    3391              40 :     JSCompartment *comp = a->compartment();
    3392              40 :     if (comp->needsBarrier()) {
    3393               0 :         MarkChildren(comp->barrierTracer(), a);
    3394               0 :         MarkChildren(comp->barrierTracer(), b);
    3395                 :     }
    3396                 : #endif
    3397                 : 
    3398                 :     /* Trade the guts of the objects. */
    3399              40 :     const size_t size = a->sizeOfThis();
    3400              40 :     if (size == b->sizeOfThis()) {
    3401                 :         /*
    3402                 :          * If the objects are the same size, then we make no assumptions about
    3403                 :          * whether they have dynamically allocated slots and instead just copy
    3404                 :          * them over wholesale.
    3405                 :          */
    3406                 :         char tmp[tl::Max<sizeof(JSFunction), sizeof(JSObject_Slots16)>::result];
    3407              40 :         JS_ASSERT(size <= sizeof(tmp));
    3408                 : 
    3409              40 :         js_memcpy(tmp, a, size);
    3410              40 :         js_memcpy(a, b, size);
    3411              40 :         js_memcpy(b, tmp, size);
    3412                 : 
    3413                 : #ifdef JSGC_GENERATIONAL
    3414                 :         /*
    3415                 :          * Trigger post barriers for fixed slots. JSObject bits are barriered
    3416                 :          * below, in common with the other case.
    3417                 :          */
    3418                 :         JSCompartment *comp = cx->compartment;
    3419                 :         for (size_t i = 0; i < a->numFixedSlots(); ++i) {
    3420                 :             HeapSlot::writeBarrierPost(comp, a, i);
    3421                 :             HeapSlot::writeBarrierPost(comp, b, i);
    3422                 :         }
    3423                 : #endif
    3424                 :     } else {
    3425                 :         /*
    3426                 :          * If the objects are of differing sizes, use the space we reserved
    3427                 :          * earlier to save the slots from each object and then copy them into
    3428                 :          * the new layout for the other object.
    3429                 :          */
    3430                 : 
    3431               0 :         unsigned acap = a->slotSpan();
    3432               0 :         unsigned bcap = b->slotSpan();
    3433                 : 
    3434               0 :         for (size_t i = 0; i < acap; i++)
    3435               0 :             reserved.avals.infallibleAppend(a->getSlot(i));
    3436                 : 
    3437               0 :         for (size_t i = 0; i < bcap; i++)
    3438               0 :             reserved.bvals.infallibleAppend(b->getSlot(i));
    3439                 : 
    3440                 :         /* Done with the dynamic slots. */
    3441               0 :         if (a->hasDynamicSlots())
    3442               0 :             cx->free_(a->slots);
    3443               0 :         if (b->hasDynamicSlots())
    3444               0 :             cx->free_(b->slots);
    3445                 : 
    3446               0 :         void *apriv = a->hasPrivate() ? a->getPrivate() : NULL;
    3447               0 :         void *bpriv = b->hasPrivate() ? b->getPrivate() : NULL;
    3448                 : 
    3449                 :         char tmp[sizeof(JSObject)];
    3450               0 :         js_memcpy(&tmp, a, sizeof tmp);
    3451               0 :         js_memcpy(a, b, sizeof tmp);
    3452               0 :         js_memcpy(b, &tmp, sizeof tmp);
    3453                 : 
    3454               0 :         if (a->isNative())
    3455               0 :             a->shape_->setNumFixedSlots(reserved.newafixed);
    3456                 :         else
    3457               0 :             a->shape_ = reserved.newashape;
    3458                 : 
    3459               0 :         a->slots = reserved.newaslots;
    3460               0 :         a->initSlotRange(0, reserved.bvals.begin(), bcap);
    3461               0 :         if (a->hasPrivate())
    3462               0 :             a->initPrivate(bpriv);
    3463                 : 
    3464               0 :         if (b->isNative())
    3465               0 :             b->shape_->setNumFixedSlots(reserved.newbfixed);
    3466                 :         else
    3467               0 :             b->shape_ = reserved.newbshape;
    3468                 : 
    3469               0 :         b->slots = reserved.newbslots;
    3470               0 :         b->initSlotRange(0, reserved.avals.begin(), acap);
    3471               0 :         if (b->hasPrivate())
    3472               0 :             b->initPrivate(apriv);
    3473                 : 
    3474                 :         /* Make sure the destructor for reserved doesn't free the slots. */
    3475               0 :         reserved.newaslots = NULL;
    3476               0 :         reserved.newbslots = NULL;
    3477                 :     }
    3478                 : 
    3479                 : #ifdef JSGC_GENERATIONAL
    3480                 :     Shape::writeBarrierPost(a->shape_, &a->shape_);
    3481                 :     Shape::writeBarrierPost(b->shape_, &b->shape_);
    3482                 :     types::TypeObject::writeBarrierPost(a->type_, &a->type_);
    3483                 :     types::TypeObject::writeBarrierPost(b->type_, &b->type_);
    3484                 : #endif
    3485                 : 
    3486              40 :     if (a->inDictionaryMode())
    3487               0 :         a->lastProperty()->listp = &a->shape_;
    3488              40 :     if (b->inDictionaryMode())
    3489               0 :         b->lastProperty()->listp = &b->shape_;
    3490              40 : }
    3491                 : 
    3492                 : /*
    3493                 :  * Use this method with extreme caution. It trades the guts of two objects and updates
    3494                 :  * scope ownership. This operation is not thread-safe, just as fast array to slow array
    3495                 :  * transitions are inherently not thread-safe. Don't perform a swap operation on objects
    3496                 :  * shared across threads or, or bad things will happen. You have been warned.
    3497                 :  */
    3498                 : bool
    3499              40 : JSObject::swap(JSContext *cx, JSObject *other)
    3500                 : {
    3501              40 :     if (this->compartment() == other->compartment()) {
    3502              80 :         TradeGutsReserved reserved(cx);
    3503              40 :         if (!ReserveForTradeGuts(cx, this, other, reserved))
    3504               0 :             return false;
    3505              40 :         TradeGuts(cx, this, other, reserved);
    3506              40 :         return true;
    3507                 :     }
    3508                 : 
    3509                 :     JSObject *thisClone;
    3510                 :     JSObject *otherClone;
    3511                 :     {
    3512               0 :         AutoCompartment ac(cx, other);
    3513               0 :         if (!ac.enter())
    3514               0 :             return false;
    3515               0 :         thisClone = JS_CloneObject(cx, this, other->getProto(), other->getParent());
    3516               0 :         if (!thisClone || !JS_CopyPropertiesFrom(cx, thisClone, this))
    3517               0 :             return false;
    3518                 :     }
    3519                 :     {
    3520               0 :         AutoCompartment ac(cx, this);
    3521               0 :         if (!ac.enter())
    3522               0 :             return false;
    3523               0 :         otherClone = JS_CloneObject(cx, other, other->getProto(), other->getParent());
    3524               0 :         if (!otherClone || !JS_CopyPropertiesFrom(cx, otherClone, other))
    3525               0 :             return false;
    3526                 :     }
    3527                 : 
    3528               0 :     TradeGutsReserved reservedThis(cx);
    3529               0 :     TradeGutsReserved reservedOther(cx);
    3530                 : 
    3531               0 :     if (!ReserveForTradeGuts(cx, this, otherClone, reservedThis) ||
    3532               0 :         !ReserveForTradeGuts(cx, other, thisClone, reservedOther)) {
    3533               0 :         return false;
    3534                 :     }
    3535                 : 
    3536               0 :     TradeGuts(cx, this, otherClone, reservedThis);
    3537               0 :     TradeGuts(cx, other, thisClone, reservedOther);
    3538                 : 
    3539               0 :     return true;
    3540                 : }
    3541                 : 
    3542                 : static bool
    3543          202823 : DefineStandardSlot(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom,
    3544                 :                    const Value &v, uint32_t attrs, bool &named)
    3545                 : {
    3546          202823 :     jsid id = ATOM_TO_JSID(atom);
    3547                 : 
    3548          202823 :     if (key != JSProto_Null) {
    3549                 :         /*
    3550                 :          * Initializing an actual standard class on a global object. If the
    3551                 :          * property is not yet present, force it into a new one bound to a
    3552                 :          * reserved slot. Otherwise, go through the normal property path.
    3553                 :          */
    3554               0 :         JS_ASSERT(obj->isGlobal());
    3555               0 :         JS_ASSERT(obj->isNative());
    3556                 : 
    3557               0 :         const Shape *shape = obj->nativeLookup(cx, id);
    3558               0 :         if (!shape) {
    3559               0 :             uint32_t slot = 2 * JSProto_LIMIT + key;
    3560               0 :             obj->setReservedSlot(slot, v);
    3561               0 :             if (!obj->addProperty(cx, id, JS_PropertyStub, JS_StrictPropertyStub, slot, attrs, 0, 0))
    3562               0 :                 return false;
    3563               0 :             AddTypePropertyId(cx, obj, id, v);
    3564                 : 
    3565               0 :             named = true;
    3566               0 :             return true;
    3567                 :         }
    3568                 :     }
    3569                 : 
    3570          202823 :     named = obj->defineGeneric(cx, id, v, JS_PropertyStub, JS_StrictPropertyStub, attrs);
    3571          202823 :     return named;
    3572                 : }
    3573                 : 
    3574                 : namespace js {
    3575                 : 
    3576                 : static void
    3577               0 : SetClassObject(JSObject *obj, JSProtoKey key, JSObject *cobj, JSObject *proto)
    3578                 : {
    3579               0 :     JS_ASSERT(!obj->getParent());
    3580               0 :     if (!obj->isGlobal())
    3581               0 :         return;
    3582                 : 
    3583               0 :     obj->setReservedSlot(key, ObjectOrNullValue(cobj));
    3584               0 :     obj->setReservedSlot(JSProto_LIMIT + key, ObjectOrNullValue(proto));
    3585                 : }
    3586                 : 
    3587                 : static void
    3588               0 : ClearClassObject(JSContext *cx, JSObject *obj, JSProtoKey key)
    3589                 : {
    3590               0 :     JS_ASSERT(!obj->getParent());
    3591               0 :     if (!obj->isGlobal())
    3592               0 :         return;
    3593                 : 
    3594               0 :     obj->setSlot(key, UndefinedValue());
    3595               0 :     obj->setSlot(JSProto_LIMIT + key, UndefinedValue());
    3596                 : }
    3597                 : 
    3598                 : JSObject *
    3599          202823 : DefineConstructorAndPrototype(JSContext *cx, HandleObject obj, JSProtoKey key, HandleAtom atom,
    3600                 :                               JSObject *protoProto, Class *clasp,
    3601                 :                               Native constructor, unsigned nargs,
    3602                 :                               JSPropertySpec *ps, JSFunctionSpec *fs,
    3603                 :                               JSPropertySpec *static_ps, JSFunctionSpec *static_fs,
    3604                 :                               JSObject **ctorp, AllocKind ctorKind)
    3605                 : {
    3606                 :     /*
    3607                 :      * Create a prototype object for this class.
    3608                 :      *
    3609                 :      * FIXME: lazy standard (built-in) class initialization and even older
    3610                 :      * eager boostrapping code rely on all of these properties:
    3611                 :      *
    3612                 :      * 1. NewObject attempting to compute a default prototype object when
    3613                 :      *    passed null for proto; and
    3614                 :      *
    3615                 :      * 2. NewObject tolerating no default prototype (null proto slot value)
    3616                 :      *    due to this js_InitClass call coming from js_InitFunctionClass on an
    3617                 :      *    otherwise-uninitialized global.
    3618                 :      *
    3619                 :      * 3. NewObject allocating a JSFunction-sized GC-thing when clasp is
    3620                 :      *    &FunctionClass, not a JSObject-sized (smaller) GC-thing.
    3621                 :      *
    3622                 :      * The JS_NewObjectForGivenProto and JS_NewObject APIs also allow clasp to
    3623                 :      * be &FunctionClass (we could break compatibility easily). But fixing
    3624                 :      * (3) is not enough without addressing the bootstrapping dependency on (1)
    3625                 :      * and (2).
    3626                 :      */
    3627                 : 
    3628                 :     /*
    3629                 :      * Create the prototype object.  (GlobalObject::createBlankPrototype isn't
    3630                 :      * used because it parents the prototype object to the global and because
    3631                 :      * it uses WithProto::Given.  FIXME: Undo dependencies on this parentage
    3632                 :      * [which already needs to happen for bug 638316], figure out nicer
    3633                 :      * semantics for null-protoProto, and use createBlankPrototype.)
    3634                 :      */
    3635          405646 :     RootedVarObject proto(cx);
    3636          202823 :     proto = NewObjectWithClassProto(cx, clasp, protoProto, obj);
    3637          202823 :     if (!proto)
    3638               0 :         return NULL;
    3639                 : 
    3640          202823 :     if (!proto->setSingletonType(cx))
    3641               0 :         return NULL;
    3642                 : 
    3643          202823 :     if (clasp == &ArrayClass && !proto->makeDenseArraySlow(cx))
    3644               0 :         return NULL;
    3645                 : 
    3646                 :     /* After this point, control must exit via label bad or out. */
    3647          405646 :     RootedVarObject ctor(cx);
    3648          202823 :     bool named = false;
    3649          202823 :     bool cached = false;
    3650          202823 :     if (!constructor) {
    3651                 :         /*
    3652                 :          * Lacking a constructor, name the prototype (e.g., Math) unless this
    3653                 :          * class (a) is anonymous, i.e. for internal use only; (b) the class
    3654                 :          * of obj (the global object) is has a reserved slot indexed by key;
    3655                 :          * and (c) key is not the null key.
    3656                 :          */
    3657               2 :         if (!(clasp->flags & JSCLASS_IS_ANONYMOUS) || !obj->isGlobal() || key == JSProto_Null) {
    3658                 :             uint32_t attrs = (clasp->flags & JSCLASS_IS_ANONYMOUS)
    3659                 :                            ? JSPROP_READONLY | JSPROP_PERMANENT
    3660               2 :                            : 0;
    3661               2 :             if (!DefineStandardSlot(cx, obj, key, atom, ObjectValue(*proto), attrs, named))
    3662               0 :                 goto bad;
    3663                 :         }
    3664                 : 
    3665               2 :         ctor = proto;
    3666                 :     } else {
    3667                 :         /*
    3668                 :          * Create the constructor, not using GlobalObject::createConstructor
    3669                 :          * because the constructor currently must have |obj| as its parent.
    3670                 :          * (FIXME: remove this dependency on the exact identity of the parent,
    3671                 :          * perhaps as part of bug 638316.)
    3672                 :          */
    3673          405642 :         RootedVarFunction fun(cx);
    3674                 :         fun = js_NewFunction(cx, NULL, constructor, nargs, JSFUN_CONSTRUCTOR, obj, atom,
    3675          202821 :                              ctorKind);
    3676          202821 :         if (!fun)
    3677                 :             goto bad;
    3678          202821 :         fun->setConstructorClass(clasp);
    3679                 : 
    3680                 :         /*
    3681                 :          * Set the class object early for standard class constructors. Type
    3682                 :          * inference may need to access these, and js_GetClassPrototype will
    3683                 :          * fail if it tries to do a reentrant reconstruction of the class.
    3684                 :          */
    3685          202821 :         if (key != JSProto_Null) {
    3686               0 :             SetClassObject(obj, key, fun, proto);
    3687               0 :             cached = true;
    3688                 :         }
    3689                 : 
    3690          405642 :         AutoValueRooter tvr2(cx, ObjectValue(*fun));
    3691          202821 :         if (!DefineStandardSlot(cx, obj, key, atom, tvr2.value(), 0, named))
    3692                 :             goto bad;
    3693                 : 
    3694                 :         /*
    3695                 :          * Optionally construct the prototype object, before the class has
    3696                 :          * been fully initialized.  Allow the ctor to replace proto with a
    3697                 :          * different object, as is done for operator new -- and as at least
    3698                 :          * XML support requires.
    3699                 :          */
    3700          202821 :         ctor = fun;
    3701          202821 :         if (!LinkConstructorAndPrototype(cx, ctor, proto))
    3702                 :             goto bad;
    3703                 : 
    3704                 :         /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */
    3705          202821 :         if (ctor->getClass() == clasp && !ctor->splicePrototype(cx, proto))
    3706                 :             goto bad;
    3707                 :     }
    3708                 : 
    3709          608467 :     if (!DefinePropertiesAndBrand(cx, proto, ps, fs) ||
    3710          405644 :         (ctor != proto && !DefinePropertiesAndBrand(cx, ctor, static_ps, static_fs)))
    3711                 :     {
    3712               0 :         goto bad;
    3713                 :     }
    3714                 : 
    3715          202823 :     if (clasp->flags & (JSCLASS_FREEZE_PROTO|JSCLASS_FREEZE_CTOR)) {
    3716               0 :         JS_ASSERT_IF(ctor == proto, !(clasp->flags & JSCLASS_FREEZE_CTOR));
    3717               0 :         if (proto && (clasp->flags & JSCLASS_FREEZE_PROTO) && !proto->freeze(cx))
    3718               0 :             goto bad;
    3719               0 :         if (ctor && (clasp->flags & JSCLASS_FREEZE_CTOR) && !ctor->freeze(cx))
    3720               0 :             goto bad;
    3721                 :     }
    3722                 : 
    3723                 :     /* If this is a standard class, cache its prototype. */
    3724          202823 :     if (!cached && key != JSProto_Null)
    3725               0 :         SetClassObject(obj, key, ctor, proto);
    3726                 : 
    3727          202823 :     if (ctorp)
    3728           22873 :         *ctorp = ctor;
    3729          202823 :     return proto;
    3730                 : 
    3731                 : bad:
    3732               0 :     if (named) {
    3733                 :         Value rval;
    3734               0 :         obj->deleteByValue(cx, StringValue(atom), &rval, false);
    3735                 :     }
    3736               0 :     if (cached)
    3737               0 :         ClearClassObject(cx, obj, key);
    3738               0 :     return NULL;
    3739                 : }
    3740                 : 
    3741                 : /*
    3742                 :  * Lazy standard classes need a way to indicate if they have been initialized.
    3743                 :  * Otherwise, when we delete them, we might accidentally recreate them via a
    3744                 :  * lazy initialization. We use the presence of a ctor or proto in the
    3745                 :  * globalObject's slot to indicate that they've been constructed, but this only
    3746                 :  * works for classes which have a proto and ctor. Classes which don't have one
    3747                 :  * can call MarkStandardClassInitializedNoProto(), and we can always check
    3748                 :  * whether a class is initialized by calling IsStandardClassResolved().
    3749                 :  */
    3750                 : bool
    3751         2758058 : IsStandardClassResolved(JSObject *obj, js::Class *clasp)
    3752                 : {
    3753         2758058 :     JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp);
    3754                 : 
    3755                 :     /* If the constructor is undefined, then it hasn't been initialized. */
    3756         2758058 :     return (obj->getReservedSlot(key) != UndefinedValue());
    3757                 : }
    3758                 : 
    3759                 : void
    3760           11056 : MarkStandardClassInitializedNoProto(JSObject *obj, js::Class *clasp)
    3761                 : {
    3762           11056 :     JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp);
    3763                 : 
    3764                 :     /*
    3765                 :      * We use True so that it's obvious what we're doing (instead of, say,
    3766                 :      * Null, which might be miscontrued as an error in setting Undefined).
    3767                 :      */
    3768           11056 :     if (obj->getReservedSlot(key) == UndefinedValue())
    3769            6617 :         obj->setSlot(key, BooleanValue(true));
    3770           11056 : }
    3771                 : 
    3772                 : }
    3773                 : 
    3774                 : JSObject *
    3775          202823 : js_InitClass(JSContext *cx, HandleObject obj, JSObject *protoProto,
    3776                 :              Class *clasp, Native constructor, unsigned nargs,
    3777                 :              JSPropertySpec *ps, JSFunctionSpec *fs,
    3778                 :              JSPropertySpec *static_ps, JSFunctionSpec *static_fs,
    3779                 :              JSObject **ctorp, AllocKind ctorKind)
    3780                 : {
    3781          405646 :     RootObject rootProto(cx, &protoProto);
    3782                 : 
    3783          405646 :     RootedVarAtom atom(cx);
    3784          202823 :     atom = js_Atomize(cx, clasp->name, strlen(clasp->name));
    3785          202823 :     if (!atom)
    3786               0 :         return NULL;
    3787                 : 
    3788                 :     /*
    3789                 :      * All instances of the class will inherit properties from the prototype
    3790                 :      * object we are about to create (in DefineConstructorAndPrototype), which
    3791                 :      * in turn will inherit from protoProto.
    3792                 :      *
    3793                 :      * When initializing a standard class (other than Object), if protoProto is
    3794                 :      * null, default to the Object prototype object. The engine's internal uses
    3795                 :      * of js_InitClass depend on this nicety. Note that in
    3796                 :      * js_InitFunctionAndObjectClasses, we specially hack the resolving table
    3797                 :      * and then depend on js_GetClassPrototype here leaving protoProto NULL and
    3798                 :      * returning true.
    3799                 :      */
    3800          202823 :     JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp);
    3801          202823 :     if (key != JSProto_Null &&
    3802               0 :         !protoProto &&
    3803               0 :         !js_GetClassPrototype(cx, obj, JSProto_Object, &protoProto)) {
    3804               0 :         return NULL;
    3805                 :     }
    3806                 : 
    3807                 :     return DefineConstructorAndPrototype(cx, obj, key, atom, protoProto, clasp, constructor, nargs,
    3808          202823 :                                          ps, fs, static_ps, static_fs, ctorp, ctorKind);
    3809                 : }
    3810                 : 
    3811                 : void
    3812            5488 : JSObject::initSlotRange(size_t start, const Value *vector, size_t length)
    3813                 : {
    3814            5488 :     JSCompartment *comp = compartment();
    3815                 :     HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
    3816            5488 :     getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
    3817            5488 :     for (HeapSlot *sp = fixedStart; sp != fixedEnd; sp++)
    3818               0 :         sp->init(comp, this, start++, *vector++);
    3819            9783 :     for (HeapSlot *sp = slotsStart; sp != slotsEnd; sp++)
    3820            4295 :         sp->init(comp, this, start++, *vector++);
    3821            5488 : }
    3822                 : 
    3823                 : void
    3824          195804 : JSObject::copySlotRange(size_t start, const Value *vector, size_t length)
    3825                 : {
    3826          195804 :     JSCompartment *comp = compartment();
    3827                 :     HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
    3828          195804 :     getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
    3829          545256 :     for (HeapSlot *sp = fixedStart; sp != fixedEnd; sp++)
    3830          349452 :         sp->set(comp, this, start++, *vector++);
    3831          854730 :     for (HeapSlot *sp = slotsStart; sp != slotsEnd; sp++)
    3832          658926 :         sp->set(comp, this, start++, *vector++);
    3833          195804 : }
    3834                 : 
    3835                 : inline void
    3836            2542 : JSObject::invalidateSlotRange(size_t start, size_t length)
    3837                 : {
    3838                 : #ifdef DEBUG
    3839            2542 :     JS_ASSERT(!isDenseArray());
    3840                 : 
    3841                 :     HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
    3842            2542 :     getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
    3843            2542 :     Debug_SetSlotRangeToCrashOnTouch(fixedStart, fixedEnd);
    3844            2542 :     Debug_SetSlotRangeToCrashOnTouch(slotsStart, slotsEnd);
    3845                 : #endif /* DEBUG */
    3846            2542 : }
    3847                 : 
    3848                 : inline bool
    3849        30645493 : JSObject::updateSlotsForSpan(JSContext *cx, size_t oldSpan, size_t newSpan)
    3850                 : {
    3851        30645493 :     JS_ASSERT(oldSpan != newSpan);
    3852                 : 
    3853        30645493 :     size_t oldCount = dynamicSlotsCount(numFixedSlots(), oldSpan);
    3854        30645493 :     size_t newCount = dynamicSlotsCount(numFixedSlots(), newSpan);
    3855                 : 
    3856        30645493 :     if (oldSpan < newSpan) {
    3857        30642951 :         if (oldCount < newCount && !growSlots(cx, oldCount, newCount))
    3858               0 :             return false;
    3859                 : 
    3860        30642951 :         if (newSpan == oldSpan + 1)
    3861        27721180 :             initSlotUnchecked(oldSpan, UndefinedValue());
    3862                 :         else
    3863         2921771 :             initializeSlotRange(oldSpan, newSpan - oldSpan);
    3864                 :     } else {
    3865                 :         /* Trigger write barriers on the old slots before reallocating. */
    3866            2542 :         prepareSlotRangeForOverwrite(newSpan, oldSpan);
    3867            2542 :         invalidateSlotRange(newSpan, oldSpan - newSpan);
    3868                 : 
    3869            2542 :         if (oldCount > newCount)
    3870              58 :             shrinkSlots(cx, oldCount, newCount);
    3871                 :     }
    3872                 : 
    3873        30645493 :     return true;
    3874                 : }
    3875                 : 
    3876                 : bool
    3877        41663641 : JSObject::setLastProperty(JSContext *cx, const js::Shape *shape)
    3878                 : {
    3879        41663641 :     JS_ASSERT(!inDictionaryMode());
    3880        41663641 :     JS_ASSERT(!shape->inDictionary());
    3881        41663641 :     JS_ASSERT(shape->compartment() == compartment());
    3882        41663641 :     JS_ASSERT(shape->numFixedSlots() == numFixedSlots());
    3883                 : 
    3884        41663641 :     size_t oldSpan = lastProperty()->slotSpan();
    3885        41663641 :     size_t newSpan = shape->slotSpan();
    3886                 : 
    3887        41663641 :     if (oldSpan == newSpan) {
    3888        14154063 :         shape_ = const_cast<js::Shape *>(shape);
    3889        14154063 :         return true;
    3890                 :     }
    3891                 : 
    3892        27509578 :     if (!updateSlotsForSpan(cx, oldSpan, newSpan))
    3893               0 :         return false;
    3894                 : 
    3895        27509578 :     shape_ = const_cast<js::Shape *>(shape);
    3896        27509578 :     return true;
    3897                 : }
    3898                 : 
    3899                 : bool
    3900         3135915 : JSObject::setSlotSpan(JSContext *cx, uint32_t span)
    3901                 : {
    3902         3135915 :     JS_ASSERT(inDictionaryMode());
    3903         3135915 :     js::BaseShape *base = lastProperty()->base();
    3904                 : 
    3905         3135915 :     size_t oldSpan = base->slotSpan();
    3906                 : 
    3907         3135915 :     if (oldSpan == span)
    3908               0 :         return true;
    3909                 : 
    3910         3135915 :     if (!updateSlotsForSpan(cx, oldSpan, span))
    3911               0 :         return false;
    3912                 : 
    3913         3135915 :     base->setSlotSpan(span);
    3914         3135915 :     return true;
    3915                 : }
    3916                 : 
    3917                 : bool
    3918         6002296 : JSObject::growSlots(JSContext *cx, uint32_t oldCount, uint32_t newCount)
    3919                 : {
    3920         6002296 :     JS_ASSERT(newCount > oldCount);
    3921         6002296 :     JS_ASSERT(newCount >= SLOT_CAPACITY_MIN);
    3922         6002296 :     JS_ASSERT(!isDenseArray());
    3923                 : 
    3924                 :     /*
    3925                 :      * Slots are only allocated for call objects when new properties are
    3926                 :      * added to them, which can only happen while the call is still on the
    3927                 :      * stack (and an eval, DEFFUN, etc. happens). We thus do not need to
    3928                 :      * worry about updating any active outer function args/vars.
    3929                 :      */
    3930         6002296 :     JS_ASSERT_IF(isCall(), asCall().maybeStackFrame() != NULL);
    3931                 : 
    3932                 :     /*
    3933                 :      * Slot capacities are determined by the span of allocated objects. Due to
    3934                 :      * the limited number of bits to store shape slots, object growth is
    3935                 :      * throttled well before the slot capacity can overflow.
    3936                 :      */
    3937         6002296 :     JS_ASSERT(newCount < NELEMENTS_LIMIT);
    3938                 : 
    3939         6002296 :     size_t oldSize = Probes::objectResizeActive() ? computedSizeOfThisSlotsElements() : 0;
    3940         6002296 :     size_t newSize = oldSize + (newCount - oldCount) * sizeof(Value);
    3941                 : 
    3942                 :     /*
    3943                 :      * If we are allocating slots for an object whose type is always created
    3944                 :      * by calling 'new' on a particular script, bump the GC kind for that
    3945                 :      * type to give these objects a larger number of fixed slots when future
    3946                 :      * objects are constructed.
    3947                 :      */
    3948         6002296 :     if (!hasLazyType() && !oldCount && type()->newScript) {
    3949              22 :         gc::AllocKind kind = type()->newScript->allocKind;
    3950              22 :         unsigned newScriptSlots = gc::GetGCKindSlots(kind);
    3951              22 :         if (newScriptSlots == numFixedSlots() && gc::TryIncrementAllocKind(&kind)) {
    3952                 :             JSObject *obj = NewReshapedObject(cx, type(), getParent(), kind,
    3953              17 :                                               type()->newScript->shape);
    3954              17 :             if (!obj)
    3955               0 :                 return false;
    3956                 : 
    3957              17 :             type()->newScript->allocKind = kind;
    3958              17 :             type()->newScript->shape = obj->lastProperty();
    3959              17 :             type()->markStateChange(cx);
    3960                 :         }
    3961                 :     }
    3962                 : 
    3963         6002296 :     if (!oldCount) {
    3964         5276477 :         slots = (HeapSlot *) cx->malloc_(newCount * sizeof(HeapSlot));
    3965         5276477 :         if (!slots)
    3966               0 :             return false;
    3967         5276477 :         Debug_SetSlotRangeToCrashOnTouch(slots, newCount);
    3968         5276477 :         if (Probes::objectResizeActive())
    3969               0 :             Probes::resizeObject(cx, this, oldSize, newSize);
    3970         5276477 :         return true;
    3971                 :     }
    3972                 : 
    3973                 :     HeapSlot *newslots = (HeapSlot*) cx->realloc_(slots, oldCount * sizeof(HeapSlot),
    3974          725819 :                                                   newCount * sizeof(HeapSlot));
    3975          725819 :     if (!newslots)
    3976               0 :         return false;  /* Leave slots at its old size. */
    3977                 : 
    3978          725819 :     bool changed = slots != newslots;
    3979          725819 :     slots = newslots;
    3980                 : 
    3981          725819 :     Debug_SetSlotRangeToCrashOnTouch(slots + oldCount, newCount - oldCount);
    3982                 : 
    3983                 :     /* Changes in the slots of global objects can trigger recompilation. */
    3984          725819 :     if (changed && isGlobal())
    3985           38570 :         types::MarkObjectStateChange(cx, this);
    3986                 : 
    3987          725819 :     if (Probes::objectResizeActive())
    3988               0 :         Probes::resizeObject(cx, this, oldSize, newSize);
    3989                 : 
    3990          725819 :     return true;
    3991                 : }
    3992                 : 
    3993                 : void
    3994              58 : JSObject::shrinkSlots(JSContext *cx, uint32_t oldCount, uint32_t newCount)
    3995                 : {
    3996              58 :     JS_ASSERT(newCount < oldCount);
    3997              58 :     JS_ASSERT(!isDenseArray());
    3998                 : 
    3999                 :     /*
    4000                 :      * Refuse to shrink slots for call objects. This only happens in a very
    4001                 :      * obscure situation (deleting names introduced by a direct 'eval') and
    4002                 :      * allowing the slots pointer to change may require updating pointers in
    4003                 :      * the function's active args/vars information.
    4004                 :      */
    4005              58 :     if (isCall())
    4006               0 :         return;
    4007                 : 
    4008              58 :     size_t oldSize = Probes::objectResizeActive() ? computedSizeOfThisSlotsElements() : 0;
    4009              58 :     size_t newSize = oldSize - (oldCount - newCount) * sizeof(Value);
    4010                 : 
    4011              58 :     if (newCount == 0) {
    4012              58 :         cx->free_(slots);
    4013              58 :         slots = NULL;
    4014              58 :         if (Probes::objectResizeActive())
    4015               0 :             Probes::resizeObject(cx, this, oldSize, newSize);
    4016              58 :         return;
    4017                 :     }
    4018                 : 
    4019               0 :     JS_ASSERT(newCount >= SLOT_CAPACITY_MIN);
    4020                 : 
    4021               0 :     HeapSlot *newslots = (HeapSlot *) cx->realloc_(slots, newCount * sizeof(HeapSlot));
    4022               0 :     if (!newslots)
    4023               0 :         return;  /* Leave slots at its old size. */
    4024                 : 
    4025               0 :     bool changed = slots != newslots;
    4026               0 :     slots = newslots;
    4027                 : 
    4028                 :     /* Watch for changes in global object slots, as for growSlots. */
    4029               0 :     if (changed && isGlobal())
    4030               0 :         types::MarkObjectStateChange(cx, this);
    4031                 : 
    4032               0 :     if (Probes::objectResizeActive())
    4033               0 :         Probes::resizeObject(cx, this, oldSize, newSize);
    4034                 : }
    4035                 : 
    4036                 : bool
    4037          304451 : JSObject::growElements(JSContext *cx, unsigned newcap)
    4038                 : {
    4039          304451 :     JS_ASSERT(isDenseArray());
    4040                 : 
    4041                 :     /*
    4042                 :      * When an object with CAPACITY_DOUBLING_MAX or fewer elements needs to
    4043                 :      * grow, double its capacity, to add N elements in amortized O(N) time.
    4044                 :      *
    4045                 :      * Above this limit, grow by 12.5% each time. Speed is still amortized
    4046                 :      * O(N), with a higher constant factor, and we waste less space.
    4047                 :      */
    4048                 :     static const size_t CAPACITY_DOUBLING_MAX = 1024 * 1024;
    4049                 :     static const size_t CAPACITY_CHUNK = CAPACITY_DOUBLING_MAX / sizeof(Value);
    4050                 : 
    4051          304451 :     uint32_t oldcap = getDenseArrayCapacity();
    4052          304451 :     JS_ASSERT(oldcap <= newcap);
    4053                 : 
    4054          304451 :     size_t oldSize = Probes::objectResizeActive() ? computedSizeOfThisSlotsElements() : 0;
    4055                 : 
    4056                 :     uint32_t nextsize = (oldcap <= CAPACITY_DOUBLING_MAX)
    4057                 :                       ? oldcap * 2
    4058          304451 :                       : oldcap + (oldcap >> 3);
    4059                 : 
    4060          304451 :     uint32_t actualCapacity = JS_MAX(newcap, nextsize);
    4061          304451 :     if (actualCapacity >= CAPACITY_CHUNK)
    4062              39 :         actualCapacity = JS_ROUNDUP(actualCapacity, CAPACITY_CHUNK);
    4063          304412 :     else if (actualCapacity < SLOT_CAPACITY_MIN)
    4064            8288 :         actualCapacity = SLOT_CAPACITY_MIN;
    4065                 : 
    4066                 :     /* Don't let nelements get close to wrapping around uint32_t. */
    4067          304451 :     if (actualCapacity >= NELEMENTS_LIMIT || actualCapacity < oldcap || actualCapacity < newcap) {
    4068               0 :         JS_ReportOutOfMemory(cx);
    4069               0 :         return false;
    4070                 :     }
    4071                 : 
    4072          304451 :     uint32_t initlen = getDenseArrayInitializedLength();
    4073          304451 :     uint32_t newAllocated = actualCapacity + ObjectElements::VALUES_PER_HEADER;
    4074                 : 
    4075                 :     ObjectElements *newheader;
    4076          304451 :     if (hasDynamicElements()) {
    4077          101967 :         uint32_t oldAllocated = oldcap + ObjectElements::VALUES_PER_HEADER;
    4078                 :         newheader = (ObjectElements *)
    4079          101967 :             cx->realloc_(getElementsHeader(), oldAllocated * sizeof(Value),
    4080          203934 :                          newAllocated * sizeof(Value));
    4081          101967 :         if (!newheader)
    4082               0 :             return false;  /* Leave elements as its old size. */
    4083                 :     } else {
    4084          202484 :         newheader = (ObjectElements *) cx->malloc_(newAllocated * sizeof(Value));
    4085          202484 :         if (!newheader)
    4086               0 :             return false;  /* Ditto. */
    4087          202484 :         js_memcpy(newheader, getElementsHeader(),
    4088          404968 :                   (ObjectElements::VALUES_PER_HEADER + initlen) * sizeof(Value));
    4089                 :     }
    4090                 : 
    4091          304451 :     newheader->capacity = actualCapacity;
    4092          304451 :     elements = newheader->elements();
    4093                 : 
    4094          304451 :     Debug_SetSlotRangeToCrashOnTouch(elements + initlen, actualCapacity - initlen);
    4095                 : 
    4096          304451 :     if (Probes::objectResizeActive())
    4097               0 :         Probes::resizeObject(cx, this, oldSize, computedSizeOfThisSlotsElements());
    4098                 : 
    4099          304451 :     return true;
    4100                 : }
    4101                 : 
    4102                 : void
    4103           53698 : JSObject::shrinkElements(JSContext *cx, unsigned newcap)
    4104                 : {
    4105           53698 :     JS_ASSERT(isDenseArray());
    4106                 : 
    4107           53698 :     uint32_t oldcap = getDenseArrayCapacity();
    4108           53698 :     JS_ASSERT(newcap <= oldcap);
    4109                 : 
    4110           53698 :     size_t oldSize = Probes::objectResizeActive() ? computedSizeOfThisSlotsElements() : 0;
    4111                 : 
    4112                 :     /* Don't shrink elements below the minimum capacity. */
    4113           53698 :     if (oldcap <= SLOT_CAPACITY_MIN || !hasDynamicElements())
    4114           11281 :         return;
    4115                 : 
    4116           42417 :     newcap = Max(newcap, SLOT_CAPACITY_MIN);
    4117                 : 
    4118           42417 :     uint32_t newAllocated = newcap + ObjectElements::VALUES_PER_HEADER;
    4119                 : 
    4120                 :     ObjectElements *newheader = (ObjectElements *)
    4121           42417 :         cx->realloc_(getElementsHeader(), newAllocated * sizeof(Value));
    4122           42417 :     if (!newheader)
    4123               0 :         return;  /* Leave elements at its old size. */
    4124                 : 
    4125           42417 :     newheader->capacity = newcap;
    4126           42417 :     elements = newheader->elements();
    4127                 : 
    4128           42417 :     if (Probes::objectResizeActive())
    4129               0 :         Probes::resizeObject(cx, this, oldSize, computedSizeOfThisSlotsElements());
    4130                 : }
    4131                 : 
    4132                 : #ifdef DEBUG
    4133                 : bool
    4134       742308194 : JSObject::slotInRange(unsigned slot, SentinelAllowed sentinel) const
    4135                 : {
    4136       742308194 :     size_t capacity = numFixedSlots() + numDynamicSlots();
    4137       742308193 :     if (sentinel == SENTINEL_ALLOWED)
    4138       190432606 :         return slot <= capacity;
    4139       551875587 :     return slot < capacity;
    4140                 : }
    4141                 : #endif /* DEBUG */
    4142                 : 
    4143                 : static JSObject *
    4144               0 : js_InitNullClass(JSContext *cx, JSObject *obj)
    4145                 : {
    4146               0 :     JS_ASSERT(0);
    4147               0 :     return NULL;
    4148                 : }
    4149                 : 
    4150                 : #define JS_PROTO(name,code,init) extern JSObject *init(JSContext *, JSObject *);
    4151                 : #include "jsproto.tbl"
    4152                 : #undef JS_PROTO
    4153                 : 
    4154                 : static JSObjectOp lazy_prototype_init[JSProto_LIMIT] = {
    4155                 : #define JS_PROTO(name,code,init) init,
    4156                 : #include "jsproto.tbl"
    4157                 : #undef JS_PROTO
    4158                 : };
    4159                 : 
    4160                 : namespace js {
    4161                 : 
    4162                 : bool
    4163           51196 : SetProto(JSContext *cx, JSObject *obj, JSObject *proto, bool checkForCycles)
    4164                 : {
    4165           51196 :     JS_ASSERT_IF(!checkForCycles, obj != proto);
    4166           51196 :     JS_ASSERT(obj->isExtensible());
    4167                 : 
    4168           51196 :     if (proto && proto->isXML()) {
    4169               0 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_XML_PROTO_FORBIDDEN);
    4170               0 :         return false;
    4171                 :     }
    4172                 : 
    4173                 :     /*
    4174                 :      * Regenerate shapes for all of the scopes along the old prototype chain,
    4175                 :      * in case any entries were filled by looking up through obj. Stop when a
    4176                 :      * non-native object is found, prototype lookups will not be cached across
    4177                 :      * these.
    4178                 :      *
    4179                 :      * How this shape change is done is very delicate; the change can be made
    4180                 :      * either by marking the object's prototype as uncacheable (such that the
    4181                 :      * property cache and JIT'ed ICs cannot assume the shape determines the
    4182                 :      * prototype) or by just generating a new shape for the object. Choosing
    4183                 :      * the former is bad if the object is on the prototype chain of other
    4184                 :      * objects, as the uncacheable prototype can inhibit iterator caches on
    4185                 :      * those objects and slow down prototype accesses. Choosing the latter is
    4186                 :      * bad if there are many similar objects to this one which will have their
    4187                 :      * prototype mutated, as the generateOwnShape forces the object into
    4188                 :      * dictionary mode and similar property lineages will be repeatedly cloned.
    4189                 :      *
    4190                 :      * :XXX: bug 707717 make this code less brittle.
    4191                 :      */
    4192           51196 :     JSObject *oldproto = obj;
    4193          227960 :     while (oldproto && oldproto->isNative()) {
    4194          125568 :         if (oldproto->hasSingletonType()) {
    4195           38485 :             if (!oldproto->generateOwnShape(cx))
    4196               0 :                 return false;
    4197                 :         } else {
    4198           87083 :             if (!oldproto->setUncacheableProto(cx))
    4199               0 :                 return false;
    4200                 :         }
    4201          125568 :         oldproto = oldproto->getProto();
    4202                 :     }
    4203                 : 
    4204           51196 :     if (checkForCycles) {
    4205           48378 :         for (JSObject *obj2 = proto; obj2; obj2 = obj2->getProto()) {
    4206           33497 :             if (obj2 == obj) {
    4207                 :                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CYCLIC_VALUE,
    4208               0 :                                      js_proto_str);
    4209               0 :                 return false;
    4210                 :             }
    4211                 :         }
    4212                 :     }
    4213                 : 
    4214           51196 :     if (obj->hasSingletonType()) {
    4215                 :         /*
    4216                 :          * Just splice the prototype, but mark the properties as unknown for
    4217                 :          * consistent behavior.
    4218                 :          */
    4219           12850 :         if (!obj->splicePrototype(cx, proto))
    4220               0 :             return false;
    4221           12850 :         MarkTypeObjectUnknownProperties(cx, obj->type());
    4222           12850 :         return true;
    4223                 :     }
    4224                 : 
    4225           38346 :     if (proto && !proto->setNewTypeUnknown(cx))
    4226               0 :         return false;
    4227                 : 
    4228                 :     TypeObject *type = proto
    4229                 :         ? proto->getNewType(cx, NULL)
    4230           38346 :         : cx->compartment->getEmptyType(cx);
    4231           38346 :     if (!type)
    4232               0 :         return false;
    4233                 : 
    4234                 :     /*
    4235                 :      * Setting __proto__ on an object that has escaped and may be referenced by
    4236                 :      * other heap objects can only be done if the properties of both objects
    4237                 :      * are unknown. Type sets containing this object will contain the original
    4238                 :      * type but not the new type of the object, so we need to go and scan the
    4239                 :      * entire compartment for type sets which have these objects and mark them
    4240                 :      * as containing generic objects.
    4241                 :      */
    4242           38346 :     MarkTypeObjectUnknownProperties(cx, obj->type(), true);
    4243           38346 :     MarkTypeObjectUnknownProperties(cx, type, true);
    4244                 : 
    4245           38346 :     obj->setType(type);
    4246           38346 :     return true;
    4247                 : }
    4248                 : 
    4249                 : }
    4250                 : 
    4251                 : JSBool
    4252          104249 : js_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key,
    4253                 :                   JSObject **objp)
    4254                 : {
    4255          208498 :     RootObject objRoot(cx, &obj);
    4256                 : 
    4257          104249 :     obj = &obj->global();
    4258          104249 :     if (!obj->isGlobal()) {
    4259               0 :         *objp = NULL;
    4260               0 :         return true;
    4261                 :     }
    4262                 : 
    4263          104249 :     Value v = obj->getReservedSlot(key);
    4264          104249 :     if (v.isObject()) {
    4265           17538 :         *objp = &v.toObject();
    4266           17538 :         return true;
    4267                 :     }
    4268                 : 
    4269          173422 :     AutoResolving resolving(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.classAtoms[key]));
    4270           86711 :     if (resolving.alreadyStarted()) {
    4271                 :         /* Already caching id in obj -- suppress recursion. */
    4272           10397 :         *objp = NULL;
    4273           10397 :         return true;
    4274                 :     }
    4275                 : 
    4276           76314 :     JSObject *cobj = NULL;
    4277           76314 :     if (JSObjectOp init = lazy_prototype_init[key]) {
    4278           76314 :         if (!init(cx, obj))
    4279               0 :             return false;
    4280           76314 :         v = obj->getReservedSlot(key);
    4281           76314 :         if (v.isObject())
    4282           74382 :             cobj = &v.toObject();
    4283                 :     }
    4284                 : 
    4285           76314 :     *objp = cobj;
    4286           76314 :     return true;
    4287                 : }
    4288                 : 
    4289                 : JSBool
    4290          362065 : js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey,
    4291                 :                    Value *vp, Class *clasp)
    4292                 : {
    4293                 :     JSObject *cobj, *pobj;
    4294                 :     jsid id;
    4295                 :     JSProperty *prop;
    4296                 :     const Shape *shape;
    4297                 : 
    4298          724130 :     RootedVarObject obj(cx);
    4299                 : 
    4300          362065 :     if (start) {
    4301          341925 :         obj = &start->global();
    4302          341925 :         OBJ_TO_INNER_OBJECT(cx, *obj.address());
    4303                 :     } else {
    4304           20140 :         obj = GetGlobalForScopeChain(cx);
    4305                 :     }
    4306          362065 :     if (!obj)
    4307               0 :         return false;
    4308                 : 
    4309          362065 :     if (protoKey != JSProto_Null) {
    4310           96603 :         JS_ASSERT(JSProto_Null < protoKey);
    4311           96603 :         JS_ASSERT(protoKey < JSProto_LIMIT);
    4312           96603 :         if (!js_GetClassObject(cx, obj, protoKey, &cobj))
    4313               0 :             return false;
    4314           96603 :         if (cobj) {
    4315           88054 :             vp->setObject(*cobj);
    4316           88054 :             return JS_TRUE;
    4317                 :         }
    4318            8549 :         id = ATOM_TO_JSID(cx->runtime->atomState.classAtoms[protoKey]);
    4319                 :     } else {
    4320          265462 :         JSAtom *atom = js_Atomize(cx, clasp->name, strlen(clasp->name));
    4321          265462 :         if (!atom)
    4322               0 :             return false;
    4323          265462 :         id = ATOM_TO_JSID(atom);
    4324                 :     }
    4325                 : 
    4326          274011 :     JS_ASSERT(obj->isNative());
    4327          274011 :     if (!LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_CLASSNAME, &pobj, &prop))
    4328               0 :         return false;
    4329          274011 :     Value v = UndefinedValue();
    4330          274011 :     if (prop && pobj->isNative()) {
    4331            3168 :         shape = (Shape *) prop;
    4332            3168 :         if (shape->hasSlot()) {
    4333            3168 :             v = pobj->nativeGetSlot(shape->slot());
    4334            3168 :             if (v.isPrimitive())
    4335               0 :                 v.setUndefined();
    4336                 :         }
    4337                 :     }
    4338          274011 :     *vp = v;
    4339          274011 :     return true;
    4340                 : }
    4341                 : 
    4342                 : bool
    4343        25306741 : JSObject::allocSlot(JSContext *cx, uint32_t *slotp)
    4344                 : {
    4345        25306741 :     uint32_t slot = slotSpan();
    4346        25306741 :     JS_ASSERT(slot >= JSSLOT_FREE(getClass()));
    4347                 : 
    4348                 :     /*
    4349                 :      * If this object is in dictionary mode, try to pull a free slot from the
    4350                 :      * property table's slot-number freelist.
    4351                 :      */
    4352        25306741 :     if (inDictionaryMode()) {
    4353         2073970 :         PropertyTable &table = lastProperty()->table();
    4354         2073970 :         uint32_t last = table.freelist;
    4355         2073970 :         if (last != SHAPE_INVALID_SLOT) {
    4356                 : #ifdef DEBUG
    4357           11331 :             JS_ASSERT(last < slot);
    4358           11331 :             uint32_t next = getSlot(last).toPrivateUint32();
    4359           11331 :             JS_ASSERT_IF(next != SHAPE_INVALID_SLOT, next < slot);
    4360                 : #endif
    4361                 : 
    4362           11331 :             *slotp = last;
    4363                 : 
    4364           11331 :             const Value &vref = getSlot(last);
    4365           11331 :             table.freelist = vref.toPrivateUint32();
    4366           11331 :             setSlot(last, UndefinedValue());
    4367           11331 :             return true;
    4368                 :         }
    4369                 :     }
    4370                 : 
    4371        25295410 :     if (slot >= SHAPE_MAXIMUM_SLOT) {
    4372               0 :         js_ReportOutOfMemory(cx);
    4373               0 :         return false;
    4374                 :     }
    4375                 : 
    4376        25295410 :     *slotp = slot;
    4377                 : 
    4378        25295410 :     if (inDictionaryMode() && !setSlotSpan(cx, slot + 1))
    4379               0 :         return false;
    4380                 : 
    4381        25295410 :     return true;
    4382                 : }
    4383                 : 
    4384                 : void
    4385          448137 : JSObject::freeSlot(JSContext *cx, uint32_t slot)
    4386                 : {
    4387          448137 :     JS_ASSERT(slot < slotSpan());
    4388                 : 
    4389          448137 :     if (inDictionaryMode()) {
    4390          445694 :         uint32_t &last = lastProperty()->table().freelist;
    4391                 : 
    4392                 :         /* Can't afford to check the whole freelist, but let's check the head. */
    4393          445694 :         JS_ASSERT_IF(last != SHAPE_INVALID_SLOT, last < slotSpan() && last != slot);
    4394                 : 
    4395                 :         /*
    4396                 :          * Place all freed slots other than reserved slots (bug 595230) on the
    4397                 :          * dictionary's free list.
    4398                 :          */
    4399          445694 :         if (JSSLOT_FREE(getClass()) <= slot) {
    4400          388042 :             JS_ASSERT_IF(last != SHAPE_INVALID_SLOT, last < slotSpan());
    4401          388042 :             setSlot(slot, PrivateUint32Value(last));
    4402          388042 :             last = slot;
    4403          388042 :             return;
    4404                 :         }
    4405                 :     }
    4406           60095 :     setSlot(slot, UndefinedValue());
    4407                 : }
    4408                 : 
    4409                 : static bool
    4410         1135217 : PurgeProtoChain(JSContext *cx, JSObject *obj, jsid id)
    4411                 : {
    4412                 :     const Shape *shape;
    4413                 : 
    4414         2270434 :     RootObject objRoot(cx, &obj);
    4415         2270434 :     RootId idRoot(cx, &id);
    4416                 : 
    4417         2736785 :     while (obj) {
    4418          582343 :         if (!obj->isNative()) {
    4419              20 :             obj = obj->getProto();
    4420              20 :             continue;
    4421                 :         }
    4422          582323 :         shape = obj->nativeLookup(cx, id);
    4423          582323 :         if (shape) {
    4424          115992 :             if (!obj->shadowingShapeChange(cx, *shape))
    4425               0 :                 return false;
    4426                 : 
    4427          115992 :             obj->shadowingShapeChange(cx, *shape);
    4428          115992 :             return true;
    4429                 :         }
    4430          466331 :         obj = obj->getProto();
    4431                 :     }
    4432                 : 
    4433         1019225 :     return true;
    4434                 : }
    4435                 : 
    4436                 : bool
    4437         1135076 : js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id)
    4438                 : {
    4439         2270152 :     RootObject objRoot(cx, &obj);
    4440         2270152 :     RootId idRoot(cx, &id);
    4441                 : 
    4442         1135076 :     JS_ASSERT(obj->isDelegate());
    4443         1135076 :     PurgeProtoChain(cx, obj->getProto(), id);
    4444                 : 
    4445                 :     /*
    4446                 :      * We must purge the scope chain only for Call objects as they are the only
    4447                 :      * kind of cacheable non-global object that can gain properties after outer
    4448                 :      * properties with the same names have been cached or traced. Call objects
    4449                 :      * may gain such properties via eval introducing new vars; see bug 490364.
    4450                 :      */
    4451         1135076 :     if (obj->isCall()) {
    4452             335 :         while ((obj = obj->enclosingScope()) != NULL) {
    4453             141 :             if (!PurgeProtoChain(cx, obj, id))
    4454               0 :                 return false;
    4455                 :         }
    4456                 :     }
    4457                 : 
    4458         1135076 :     return true;
    4459                 : }
    4460                 : 
    4461                 : Shape *
    4462              18 : js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
    4463                 :                      PropertyOp getter, StrictPropertyOp setter, uint32_t slot,
    4464                 :                      unsigned attrs, unsigned flags, int shortid)
    4465                 : {
    4466              18 :     JS_ASSERT(!(flags & Shape::METHOD));
    4467                 : 
    4468                 :     /* Convert string indices to integers if appropriate. */
    4469              18 :     id = js_CheckForStringIndex(id);
    4470                 : 
    4471                 :     /*
    4472                 :      * Purge the property cache of now-shadowed id in obj's scope chain. Do
    4473                 :      * this optimistically (assuming no failure below) before locking obj, so
    4474                 :      * we can lock the shadowed scope.
    4475                 :      */
    4476              18 :     if (!js_PurgeScopeChain(cx, obj, id))
    4477               0 :         return NULL;
    4478                 : 
    4479              18 :     return obj->putProperty(cx, id, getter, setter, slot, attrs, flags, shortid);
    4480                 : }
    4481                 : 
    4482                 : Shape *
    4483           40625 : js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj,
    4484                 :                              Shape *shape, unsigned attrs, unsigned mask,
    4485                 :                              PropertyOp getter, StrictPropertyOp setter)
    4486                 : {
    4487                 :     /*
    4488                 :      * Check for freezing an object with shape-memoized methods here, on a
    4489                 :      * shape-by-shape basis.
    4490                 :      */
    4491           40625 :     if ((attrs & JSPROP_READONLY) && shape->isMethod()) {
    4492               0 :         Value v = ObjectValue(*obj->nativeGetMethod(shape));
    4493                 : 
    4494               0 :         shape = obj->methodReadBarrier(cx, *shape, &v);
    4495               0 :         if (!shape)
    4496               0 :             return NULL;
    4497                 :     }
    4498                 : 
    4499           40625 :     return obj->changeProperty(cx, shape, attrs, mask, getter, setter);
    4500                 : }
    4501                 : 
    4502                 : JSBool
    4503        19102925 : js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
    4504                 :                   PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
    4505                 : {
    4506        19102925 :     return !!DefineNativeProperty(cx, obj, id, *value, getter, setter, attrs, 0, 0);
    4507                 : }
    4508                 : 
    4509                 : JSBool
    4510         1607268 : js_DefineElement(JSContext *cx, JSObject *obj, uint32_t index, const Value *value,
    4511                 :                  PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
    4512                 : {
    4513                 :     jsid id;
    4514         1607268 :     if (!IndexToId(cx, index, &id))
    4515               0 :         return false;
    4516         1607268 :     return !!DefineNativeProperty(cx, obj, id, *value, getter, setter, attrs, 0, 0);
    4517                 : }
    4518                 : 
    4519                 : /*
    4520                 :  * Backward compatibility requires allowing addProperty hooks to mutate the
    4521                 :  * nominal initial value of a slotful property, while GC safety wants that
    4522                 :  * value to be stored before the call-out through the hook.  Optimize to do
    4523                 :  * both while saving cycles for classes that stub their addProperty hook.
    4524                 :  */
    4525                 : static inline bool
    4526        40462300 : CallAddPropertyHook(JSContext *cx, Class *clasp, JSObject *obj, const Shape *shape, Value *vp)
    4527                 : {
    4528        40462300 :     if (clasp->addProperty != JS_PropertyStub) {
    4529         4570579 :         Value nominal = *vp;
    4530                 : 
    4531         4570579 :         if (!CallJSPropertyOp(cx, clasp->addProperty, obj, shape->propid(), vp))
    4532               2 :             return false;
    4533         4570577 :         if (*vp != nominal) {
    4534               0 :             if (shape->hasSlot())
    4535               0 :                 obj->nativeSetSlotWithType(cx, shape, *vp);
    4536                 :         }
    4537                 :     }
    4538        40462298 :     return true;
    4539                 : }
    4540                 : 
    4541                 : namespace js {
    4542                 : 
    4543                 : const Shape *
    4544        36788638 : DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &value_,
    4545                 :                      PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
    4546                 :                      unsigned flags, int shortid, unsigned defineHow /* = 0 */)
    4547                 : {
    4548               0 :     JS_ASSERT((defineHow & ~(DNP_CACHE_RESULT | DNP_DONT_PURGE |
    4549        36788638 :                              DNP_SET_METHOD | DNP_SKIP_TYPE)) == 0);
    4550                 : 
    4551        73577276 :     RootObject objRoot(cx, &obj);
    4552        73577276 :     RootId idRoot(cx, &id);
    4553                 : 
    4554                 :     /*
    4555                 :      * Make a local copy of value, in case a method barrier needs to update the
    4556                 :      * value to define, and just so addProperty can mutate its inout parameter.
    4557                 :      */
    4558        73577276 :     RootedVarValue value(cx);
    4559        36788638 :     value = value_;
    4560                 : 
    4561                 :     /* Convert string indices to integers if appropriate. */
    4562        36788638 :     id = js_CheckForStringIndex(id);
    4563                 : 
    4564                 :     /*
    4565                 :      * If defining a getter or setter, we must check for its counterpart and
    4566                 :      * update the attributes and property ops.  A getter or setter is really
    4567                 :      * only half of a property.
    4568                 :      */
    4569        36788638 :     Shape *shape = NULL;
    4570        36788638 :     if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
    4571                 :         JSObject *pobj;
    4572                 :         JSProperty *prop;
    4573                 : 
    4574                 :         /* Type information for getter/setter properties is unknown. */
    4575         2425130 :         AddTypePropertyId(cx, obj, id, types::Type::UnknownType());
    4576         2425130 :         MarkTypePropertyConfigured(cx, obj, id);
    4577                 : 
    4578                 :         /*
    4579                 :          * If we are defining a getter whose setter was already defined, or
    4580                 :          * vice versa, finish the job via obj->changeProperty, and refresh the
    4581                 :          * property cache line for (obj, id) to map shape.
    4582                 :          */
    4583         2425130 :         if (!js_LookupProperty(cx, obj, id, &pobj, &prop))
    4584               0 :             return NULL;
    4585         2425130 :         if (prop && pobj == obj) {
    4586           30010 :             shape = (Shape *) prop;
    4587           30010 :             if (shape->isAccessorDescriptor()) {
    4588                 :                 shape = obj->changeProperty(cx, shape, attrs,
    4589                 :                                             JSPROP_GETTER | JSPROP_SETTER,
    4590                 :                                             (attrs & JSPROP_GETTER)
    4591                 :                                             ? getter
    4592                 :                                             : shape->getter(),
    4593                 :                                             (attrs & JSPROP_SETTER)
    4594                 :                                             ? setter
    4595           29662 :                                             : shape->setter());
    4596           29662 :                 if (!shape)
    4597               0 :                     return NULL;
    4598                 :             } else {
    4599             348 :                 shape = NULL;
    4600                 :             }
    4601                 :         }
    4602                 :     }
    4603                 : 
    4604                 :     /*
    4605                 :      * Purge the property cache of any properties named by id that are about
    4606                 :      * to be shadowed in obj's scope chain unless it is known a priori that it
    4607                 :      * is not possible. We do this before locking obj to avoid nesting locks.
    4608                 :      */
    4609        36788638 :     if (!(defineHow & DNP_DONT_PURGE)) {
    4610        36787765 :         if (!js_PurgeScopeChain(cx, obj, id))
    4611               0 :             return NULL;
    4612                 :     }
    4613                 : 
    4614                 :     /* Use the object's class getter and setter by default. */
    4615        36788638 :     Class *clasp = obj->getClass();
    4616        36788638 :     if (!(defineHow & DNP_SET_METHOD)) {
    4617        36788638 :         if (!getter && !(attrs & JSPROP_GETTER))
    4618         6371213 :             getter = clasp->getProperty;
    4619        36788638 :         if (!setter && !(attrs & JSPROP_SETTER))
    4620        17675300 :             setter = clasp->setProperty;
    4621                 :     }
    4622                 : 
    4623        60001582 :     if (((defineHow & DNP_SET_METHOD) || getter == JS_PropertyStub) &&
    4624        23212944 :         !(defineHow & DNP_SKIP_TYPE)) {
    4625                 :         /*
    4626                 :          * Type information for normal native properties should reflect the
    4627                 :          * initial value of the property.
    4628                 :          */
    4629        23142974 :         AddTypePropertyId(cx, obj, id, value);
    4630        23142974 :         if (attrs & JSPROP_READONLY)
    4631         9342632 :             MarkTypePropertyConfigured(cx, obj, id);
    4632                 :     }
    4633                 : 
    4634        36788638 :     if (!shape) {
    4635                 :         /* Add a new property, or replace an existing one of the same id. */
    4636        36758976 :         if (defineHow & DNP_SET_METHOD) {
    4637               0 :             JS_ASSERT(clasp == &ObjectClass);
    4638               0 :             JS_ASSERT(IsFunctionObject(value));
    4639               0 :             JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
    4640               0 :             JS_ASSERT(!getter && !setter);
    4641                 : 
    4642               0 :             JSObject *funobj = &value.raw().toObject();
    4643               0 :             if (!funobj->toFunction()->isClonedMethod())
    4644               0 :                 flags |= Shape::METHOD;
    4645                 :         }
    4646                 : 
    4647        36758976 :         if (const Shape *existingShape = obj->nativeLookup(cx, id)) {
    4648         2339149 :             if (existingShape->isMethod() &&
    4649               0 :                 ObjectValue(*obj->nativeGetMethod(existingShape)) == value)
    4650                 :             {
    4651                 :                 /*
    4652                 :                  * Redefining an existing shape-memoized method object without
    4653                 :                  * changing the property's value, perhaps to change attributes.
    4654                 :                  * Clone now via the method read barrier.
    4655                 :                  */
    4656               0 :                 if (!obj->methodReadBarrier(cx, *existingShape, value.address()))
    4657               0 :                     return NULL;
    4658                 :             }
    4659                 :         }
    4660                 : 
    4661                 :         shape = obj->putProperty(cx, id, getter, setter, SHAPE_INVALID_SLOT,
    4662        36758976 :                                  attrs, flags, shortid);
    4663        36758976 :         if (!shape)
    4664               0 :             return NULL;
    4665                 :     }
    4666                 : 
    4667                 :     /* Store valueCopy before calling addProperty, in case the latter GC's. */
    4668        36788638 :     if (shape->hasSlot())
    4669        23949944 :         obj->nativeSetSlot(shape->slot(), value);
    4670                 : 
    4671        36788638 :     if (!CallAddPropertyHook(cx, clasp, obj, shape, value.address())) {
    4672               0 :         obj->removeProperty(cx, id);
    4673               0 :         return NULL;
    4674                 :     }
    4675                 : 
    4676        36788638 :     return shape;
    4677                 : }
    4678                 : 
    4679                 : } /* namespace js */
    4680                 : 
    4681                 : /*
    4682                 :  * Call obj's resolve hook.
    4683                 :  *
    4684                 :  * cx, start, id, and flags are the parameters initially passed to the ongoing
    4685                 :  * lookup; objp and propp are its out parameters. obj is an object along
    4686                 :  * start's prototype chain.
    4687                 :  *
    4688                 :  * There are four possible outcomes:
    4689                 :  *
    4690                 :  *   - On failure, report an error or exception and return false.
    4691                 :  *
    4692                 :  *   - If we are already resolving a property of *curobjp, set *recursedp = true,
    4693                 :  *     and return true.
    4694                 :  *
    4695                 :  *   - If the resolve hook finds or defines the sought property, set *objp and
    4696                 :  *     *propp appropriately, set *recursedp = false, and return true.
    4697                 :  *
    4698                 :  *   - Otherwise no property was resolved. Set *propp = NULL and *recursedp = false
    4699                 :  *     and return true.
    4700                 :  */
    4701                 : static JSBool
    4702         9911440 : CallResolveOp(JSContext *cx, JSObject *start, HandleObject obj, HandleId id, unsigned flags,
    4703                 :               JSObject **objp, JSProperty **propp, bool *recursedp)
    4704                 : {
    4705         9911440 :     Class *clasp = obj->getClass();
    4706         9911440 :     JSResolveOp resolve = clasp->resolve;
    4707                 : 
    4708                 :     /*
    4709                 :      * Avoid recursion on (obj, id) already being resolved on cx.
    4710                 :      *
    4711                 :      * Once we have successfully added an entry for (obj, key) to
    4712                 :      * cx->resolvingTable, control must go through cleanup: before
    4713                 :      * returning.  But note that JS_DHASH_ADD may find an existing
    4714                 :      * entry, in which case we bail to suppress runaway recursion.
    4715                 :      */
    4716        19822880 :     AutoResolving resolving(cx, obj, id);
    4717         9911440 :     if (resolving.alreadyStarted()) {
    4718                 :         /* Already resolving id in obj -- suppress recursion. */
    4719         1029648 :         *recursedp = true;
    4720         1029648 :         return true;
    4721                 :     }
    4722         8881792 :     *recursedp = false;
    4723                 : 
    4724         8881792 :     *propp = NULL;
    4725                 : 
    4726         8881792 :     if (clasp->flags & JSCLASS_NEW_RESOLVE) {
    4727         6066714 :         JSNewResolveOp newresolve = reinterpret_cast<JSNewResolveOp>(resolve);
    4728         6066714 :         if (flags == RESOLVE_INFER)
    4729         3369173 :             flags = js_InferFlags(cx, 0);
    4730                 : 
    4731        12133428 :         RootedVarObject obj2(cx);
    4732         6066714 :         obj2 = (clasp->flags & JSCLASS_NEW_RESOLVE_GETS_START) ? start : NULL;
    4733         6066714 :         if (!newresolve(cx, obj, id, flags, obj2.address()))
    4734               0 :             return false;
    4735                 : 
    4736                 :         /*
    4737                 :          * We trust the new style resolve hook to set obj2 to NULL when
    4738                 :          * the id cannot be resolved. But, when obj2 is not null, we do
    4739                 :          * not assume that id must exist and do full nativeLookup for
    4740                 :          * compatibility.
    4741                 :          */
    4742         6066714 :         if (!obj2)
    4743         4750393 :             return true;
    4744                 : 
    4745         1316321 :         if (!obj2->isNative()) {
    4746                 :             /* Whoops, newresolve handed back a foreign obj2. */
    4747               0 :             JS_ASSERT(obj2 != obj);
    4748               0 :             return obj2->lookupGeneric(cx, id, objp, propp);
    4749                 :         }
    4750         7383035 :         obj = obj2;
    4751                 :     } else {
    4752         2815078 :         if (!resolve(cx, obj, id))
    4753               0 :             return false;
    4754                 :     }
    4755                 : 
    4756         4131399 :     if (!obj->nativeEmpty()) {
    4757         3127957 :         if (const Shape *shape = obj->nativeLookup(cx, id)) {
    4758         3010254 :             *objp = obj;
    4759         3010254 :             *propp = (JSProperty *) shape;
    4760                 :         }
    4761                 :     }
    4762                 : 
    4763         4131399 :     return true;
    4764                 : }
    4765                 : 
    4766                 : static JS_ALWAYS_INLINE bool
    4767        92695624 : LookupPropertyWithFlagsInline(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
    4768                 :                               JSObject **objp, JSProperty **propp)
    4769                 : {
    4770                 :     /* We should not get string indices which aren't already integers here. */
    4771        92695624 :     JS_ASSERT(id == js_CheckForStringIndex(id));
    4772                 : 
    4773       185391248 :     RootObject objRoot(cx, &obj);
    4774       185391248 :     RootId idRoot(cx, &id);
    4775                 : 
    4776                 :     /* Search scopes starting with obj and following the prototype link. */
    4777        92695624 :     JSObject *start = obj;
    4778        21619730 :     while (true) {
    4779       114315354 :         const Shape *shape = obj->nativeLookup(cx, id);
    4780       114315354 :         if (shape) {
    4781        74615018 :             *objp = obj;
    4782        74615018 :             *propp = (JSProperty *) shape;
    4783        74615018 :             return true;
    4784                 :         }
    4785                 : 
    4786                 :         /* Try obj's class resolve hook if id was not found in obj's scope. */
    4787        39700336 :         if (obj->getClass()->resolve != JS_ResolveStub) {
    4788                 :             bool recursed;
    4789         9911440 :             if (!CallResolveOp(cx, start, objRoot, idRoot, flags, objp, propp, &recursed))
    4790               0 :                 return false;
    4791         9911440 :             if (recursed)
    4792         1029648 :                 break;
    4793         8881792 :             if (*propp) {
    4794                 :                 /*
    4795                 :                  * For stats we do not recalculate protoIndex even if it was
    4796                 :                  * resolved on some other object.
    4797                 :                  */
    4798         3010254 :                 return true;
    4799                 :             }
    4800                 :         }
    4801                 : 
    4802        35660434 :         JSObject *proto = obj->getProto();
    4803        35660434 :         if (!proto)
    4804        14039970 :             break;
    4805        21620464 :         if (!proto->isNative()) {
    4806             734 :             if (!proto->lookupGeneric(cx, id, objp, propp))
    4807               0 :                 return false;
    4808                 : #ifdef DEBUG
    4809                 :             /*
    4810                 :              * Non-native objects must have either non-native lookup results,
    4811                 :              * or else native results from the non-native's prototype chain.
    4812                 :              *
    4813                 :              * See StackFrame::getValidCalleeObject, where we depend on this
    4814                 :              * fact to force a prototype-delegated joined method accessed via
    4815                 :              * arguments.callee through the delegating |this| object's method
    4816                 :              * read barrier.
    4817                 :              */
    4818             734 :             if (*propp && (*objp)->isNative()) {
    4819             194 :                 while ((proto = proto->getProto()) != *objp)
    4820              20 :                     JS_ASSERT(proto);
    4821                 :             }
    4822                 : #endif
    4823             734 :             return true;
    4824                 :         }
    4825                 : 
    4826        21619730 :         obj = proto;
    4827                 :     }
    4828                 : 
    4829        15069618 :     *objp = NULL;
    4830        15069618 :     *propp = NULL;
    4831        15069618 :     return true;
    4832                 : }
    4833                 : 
    4834                 : JS_FRIEND_API(JSBool)
    4835        11596912 : js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
    4836                 :                   JSProperty **propp)
    4837                 : {
    4838                 :     /* Convert string indices to integers if appropriate. */
    4839        11596912 :     id = js_CheckForStringIndex(id);
    4840                 : 
    4841        11596912 :     return LookupPropertyWithFlagsInline(cx, obj, id, cx->resolveFlags, objp, propp);
    4842                 : }
    4843                 : 
    4844                 : JS_FRIEND_API(JSBool)
    4845               0 : js_LookupElement(JSContext *cx, JSObject *obj, uint32_t index, JSObject **objp, JSProperty **propp)
    4846                 : {
    4847                 :     jsid id;
    4848               0 :     if (!IndexToId(cx, index, &id))
    4849               0 :         return false;
    4850                 : 
    4851               0 :     return LookupPropertyWithFlagsInline(cx, obj, id, cx->resolveFlags, objp, propp);
    4852                 : }
    4853                 : 
    4854                 : bool
    4855        31908484 : js::LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
    4856                 :                             JSObject **objp, JSProperty **propp)
    4857                 : {
    4858                 :     /* Convert string indices to integers if appropriate. */
    4859        31908484 :     id = js_CheckForStringIndex(id);
    4860                 : 
    4861        31908484 :     return LookupPropertyWithFlagsInline(cx, obj, id, flags, objp, propp);
    4862                 : }
    4863                 : 
    4864                 : bool
    4865        11074255 : js::FindPropertyHelper(JSContext *cx, PropertyName *name, bool cacheResult, JSObject *scopeChain,
    4866                 :                        JSObject **objp, JSObject **pobjp, JSProperty **propp)
    4867                 : {
    4868        11074255 :     jsid id = ATOM_TO_JSID(name);
    4869                 :     JSObject *obj, *parent, *pobj;
    4870                 :     int scopeIndex;
    4871                 :     JSProperty *prop;
    4872                 : 
    4873                 :     /* Scan entries on the scope chain that we can cache across. */
    4874        11074255 :     obj = scopeChain;
    4875        11074255 :     parent = obj->enclosingScope();
    4876        23731338 :     for (scopeIndex = 0;
    4877                 :          parent
    4878                 :          ? IsCacheableNonGlobalScope(obj)
    4879        10636498 :          : !obj->getOps()->lookupProperty;
    4880                 :          ++scopeIndex) {
    4881        13042870 :         if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &prop))
    4882               0 :             return false;
    4883                 : 
    4884        13042870 :         if (prop) {
    4885                 : #ifdef DEBUG
    4886        10867956 :             if (parent) {
    4887          385787 :                 JS_ASSERT(pobj->isNative());
    4888          385787 :                 JS_ASSERT(pobj->getClass() == obj->getClass());
    4889          385787 :                 if (obj->isBlock()) {
    4890                 :                     /*
    4891                 :                      * A block instance on the scope chain is immutable and
    4892                 :                      * shares its shape with the compile-time prototype. Thus
    4893                 :                      * we cannot find any property on the prototype.
    4894                 :                      */
    4895           28508 :                     JS_ASSERT(pobj->isClonedBlock());
    4896                 :                 } else {
    4897                 :                     /* Call and DeclEnvClass objects have no prototypes. */
    4898          357279 :                     JS_ASSERT(!obj->getProto());
    4899                 :                 }
    4900          385787 :                 JS_ASSERT(pobj == obj);
    4901                 :             } else {
    4902        10482169 :                 JS_ASSERT(obj->isNative());
    4903                 :             }
    4904                 : #endif
    4905                 : 
    4906                 :             /*
    4907                 :              * We must check if pobj is native as a global object can have
    4908                 :              * non-native prototype.
    4909                 :              */
    4910        10867956 :             if (cacheResult && pobj->isNative()) {
    4911                 :                 JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, pobj,
    4912         7470150 :                                            (Shape *) prop);
    4913                 :             }
    4914                 : 
    4915        10867956 :             goto out;
    4916                 :         }
    4917                 : 
    4918         2174914 :         if (!parent) {
    4919          154329 :             pobj = NULL;
    4920          154329 :             goto out;
    4921                 :         }
    4922         2020585 :         obj = parent;
    4923         2020585 :         parent = obj->enclosingScope();
    4924                 :     }
    4925                 : 
    4926           49025 :     for (;;) {
    4927          100995 :         if (!obj->lookupGeneric(cx, id, &pobj, &prop))
    4928               0 :             return false;
    4929          100995 :         if (prop)
    4930           51943 :             goto out;
    4931                 : 
    4932                 :         /*
    4933                 :          * We conservatively assume that a resolve hook could mutate the scope
    4934                 :          * chain during JSObject::lookupGeneric. So we read parent here again.
    4935                 :          */
    4936           49052 :         parent = obj->enclosingScope();
    4937           49052 :         if (!parent) {
    4938              27 :             pobj = NULL;
    4939              27 :             break;
    4940                 :         }
    4941           49025 :         obj = parent;
    4942                 :     }
    4943                 : 
    4944                 :   out:
    4945        11074255 :     JS_ASSERT(!!pobj == !!prop);
    4946        11074255 :     *objp = obj;
    4947        11074255 :     *pobjp = pobj;
    4948        11074255 :     *propp = prop;
    4949        11074255 :     return true;
    4950                 : }
    4951                 : 
    4952                 : /*
    4953                 :  * On return, if |*pobjp| is a native object, then |*propp| is a |Shape *|.
    4954                 :  * Otherwise, its type and meaning depends on the host object's implementation.
    4955                 :  */
    4956                 : bool
    4957          181735 : js::FindProperty(JSContext *cx, PropertyName *name, JSObject *scopeChain,
    4958                 :                  JSObject **objp, JSObject **pobjp, JSProperty **propp)
    4959                 : {
    4960          181735 :     return !!FindPropertyHelper(cx, name, false, scopeChain, objp, pobjp, propp);
    4961                 : }
    4962                 : 
    4963                 : JSObject *
    4964           60080 : js::FindIdentifierBase(JSContext *cx, JSObject *scopeChain, PropertyName *name)
    4965                 : {
    4966                 :     /*
    4967                 :      * This function should not be called for a global object or from the
    4968                 :      * trace and should have a valid cache entry for native scopeChain.
    4969                 :      */
    4970           60080 :     JS_ASSERT(scopeChain->enclosingScope() != NULL);
    4971                 : 
    4972           60080 :     JSObject *obj = scopeChain;
    4973                 : 
    4974                 :     /*
    4975                 :      * Loop over cacheable objects on the scope chain until we find a
    4976                 :      * property. We also stop when we reach the global object skipping any
    4977                 :      * farther checks or lookups. For details see the JSOP_BINDNAME case of
    4978                 :      * js_Interpret.
    4979                 :      *
    4980                 :      * The test order here matters because IsCacheableNonGlobalScope
    4981                 :      * must not be passed a global object (i.e. one with null parent).
    4982                 :      */
    4983          265600 :     for (int scopeIndex = 0;
    4984          171386 :          obj->isGlobal() || IsCacheableNonGlobalScope(obj);
    4985                 :          scopeIndex++) {
    4986                 :         JSObject *pobj;
    4987                 :         JSProperty *prop;
    4988           93070 :         if (!LookupPropertyWithFlags(cx, obj, name, cx->resolveFlags, &pobj, &prop))
    4989               0 :             return NULL;
    4990           93070 :         if (prop) {
    4991           58498 :             if (!pobj->isNative()) {
    4992               0 :                 JS_ASSERT(obj->isGlobal());
    4993               0 :                 return obj;
    4994                 :             }
    4995           58498 :             JS_ASSERT_IF(obj->isScope(), pobj->getClass() == obj->getClass());
    4996           58498 :             JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, pobj, (Shape *) prop);
    4997           58498 :             return obj;
    4998                 :         }
    4999                 : 
    5000           34572 :         JSObject *parent = obj->enclosingScope();
    5001           34572 :         if (!parent)
    5002             438 :             return obj;
    5003           34134 :         obj = parent;
    5004                 :     }
    5005                 : 
    5006                 :     /* Loop until we find a property or reach the global object. */
    5007             693 :     do {
    5008                 :         JSObject *pobj;
    5009                 :         JSProperty *prop;
    5010            1504 :         if (!obj->lookupProperty(cx, name, &pobj, &prop))
    5011               0 :             return NULL;
    5012            1504 :         if (prop)
    5013             811 :             break;
    5014                 : 
    5015                 :         /*
    5016                 :          * We conservatively assume that a resolve hook could mutate the scope
    5017                 :          * chain during JSObject::lookupGeneric. So we must check if parent is
    5018                 :          * not null here even if it wasn't before the lookup.
    5019                 :          */
    5020             693 :         JSObject *parent = obj->enclosingScope();
    5021             693 :         if (!parent)
    5022               0 :             break;
    5023             693 :         obj = parent;
    5024             693 :     } while (!obj->isGlobal());
    5025            1144 :     return obj;
    5026                 : }
    5027                 : 
    5028                 : static JS_ALWAYS_INLINE JSBool
    5029        50518653 : js_NativeGetInline(JSContext *cx, JSObject *receiver, JSObject *obj, JSObject *pobj,
    5030                 :                    const Shape *shape, unsigned getHow, Value *vp)
    5031                 : {
    5032        50518653 :     JS_ASSERT(pobj->isNative());
    5033                 : 
    5034        50518653 :     if (shape->hasSlot()) {
    5035        47268117 :         *vp = pobj->nativeGetSlot(shape->slot());
    5036        47268117 :         JS_ASSERT(!vp->isMagic());
    5037       121469136 :         JS_ASSERT_IF(!pobj->hasSingletonType() && shape->hasDefaultGetterOrIsMethod(),
    5038       121469136 :                      js::types::TypeHasProperty(cx, pobj->type(), shape->propid(), *vp));
    5039                 :     } else {
    5040         3250536 :         vp->setUndefined();
    5041                 :     }
    5042        50518653 :     if (shape->hasDefaultGetter())
    5043        45205428 :         return true;
    5044                 : 
    5045         5313225 :     if (JS_UNLIKELY(shape->isMethod()) && (getHow & JSGET_NO_METHOD_BARRIER))
    5046               0 :         return true;
    5047                 : 
    5048                 :     jsbytecode *pc;
    5049         5313225 :     JSScript *script = cx->stack.currentScript(&pc);
    5050         5313225 :     if (script && script->hasAnalysis()) {
    5051         5274167 :         analyze::Bytecode *code = script->analysis()->maybeCode(pc);
    5052         5274167 :         if (code)
    5053         5274167 :             code->accessGetter = true;
    5054                 :     }
    5055                 : 
    5056         5313225 :     if (!shape->get(cx, receiver, obj, pobj, vp))
    5057            3915 :         return false;
    5058                 : 
    5059                 :     /* Update slotful shapes according to the value produced by the getter. */
    5060         5309310 :     if (shape->hasSlot() && pobj->nativeContains(cx, *shape)) {
    5061                 :         /* Method shapes were removed by methodReadBarrier under shape->get(). */
    5062         2062860 :         JS_ASSERT(!shape->isMethod());
    5063         2062860 :         pobj->nativeSetSlot(shape->slot(), *vp);
    5064                 :     }
    5065                 : 
    5066         5309310 :     return true;
    5067                 : }
    5068                 : 
    5069                 : JSBool
    5070         2997218 : js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, const Shape *shape, unsigned getHow,
    5071                 :              Value *vp)
    5072                 : {
    5073         2997218 :     return js_NativeGetInline(cx, obj, obj, pobj, shape, getHow, vp);
    5074                 : }
    5075                 : 
    5076                 : JSBool
    5077        17790361 : js_NativeSet(JSContext *cx, JSObject *obj, const Shape *shape, bool added, bool strict, Value *vp)
    5078                 : {
    5079        17790361 :     AddTypePropertyId(cx, obj, shape->propid(), *vp);
    5080                 : 
    5081        17790361 :     JS_ASSERT(obj->isNative());
    5082                 : 
    5083        17790361 :     if (shape->hasSlot()) {
    5084        17672727 :         uint32_t slot = shape->slot();
    5085                 : 
    5086                 :         /* If shape has a stub setter, just store *vp. */
    5087        17672727 :         if (shape->hasDefaultSetter()) {
    5088        17491383 :             if (!added) {
    5089        13825354 :                 if (shape->isMethod() && !obj->methodShapeChange(cx, *shape))
    5090               0 :                     return false;
    5091                 :             }
    5092        17491383 :             obj->nativeSetSlot(slot, *vp);
    5093        17491383 :             return true;
    5094                 :         }
    5095                 :     } else {
    5096                 :         /*
    5097                 :          * Allow API consumers to create shared properties with stub setters.
    5098                 :          * Such properties effectively function as data descriptors which are
    5099                 :          * not writable, so attempting to set such a property should do nothing
    5100                 :          * or throw if we're in strict mode.
    5101                 :          */
    5102          117634 :         if (!shape->hasGetterValue() && shape->hasDefaultSetter())
    5103               2 :             return js_ReportGetterOnlyAssignment(cx);
    5104                 :     }
    5105                 : 
    5106          298976 :     int32_t sample = cx->runtime->propertyRemovals;
    5107          298976 :     if (!shape->set(cx, obj, strict, vp))
    5108             294 :         return false;
    5109                 : 
    5110                 :     /*
    5111                 :      * Update any slot for the shape with the value produced by the setter,
    5112                 :      * unless the setter deleted the shape.
    5113                 :      */
    5114          480025 :     if (shape->hasSlot() &&
    5115          181343 :         (JS_LIKELY(cx->runtime->propertyRemovals == sample) ||
    5116               0 :          obj->nativeContains(cx, *shape))) {
    5117          181343 :         obj->setSlot(shape->slot(), *vp);
    5118                 :     }
    5119                 : 
    5120          298682 :     return true;
    5121                 : }
    5122                 : 
    5123                 : static JS_ALWAYS_INLINE JSBool
    5124        49190228 : js_GetPropertyHelperInline(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id,
    5125                 :                            uint32_t getHow, Value *vp)
    5126                 : {
    5127                 :     JSObject *aobj, *obj2;
    5128                 :     JSProperty *prop;
    5129                 :     const Shape *shape;
    5130                 : 
    5131                 :     /* Convert string indices to integers if appropriate. */
    5132        49190228 :     id = js_CheckForStringIndex(id);
    5133                 : 
    5134        49190228 :     aobj = js_GetProtoIfDenseArray(obj);
    5135                 :     /* This call site is hot -- use the always-inlined variant of LookupPropertyWithFlags(). */
    5136        49190228 :     if (!LookupPropertyWithFlagsInline(cx, aobj, id, cx->resolveFlags, &obj2, &prop))
    5137               0 :         return false;
    5138                 : 
    5139        49190228 :     if (!prop) {
    5140         1668348 :         vp->setUndefined();
    5141                 : 
    5142         1668348 :         if (!CallJSPropertyOp(cx, obj->getClass()->getProperty, obj, id, vp))
    5143               3 :             return JS_FALSE;
    5144                 : 
    5145                 :         /* Record non-undefined values produced by the class getter hook. */
    5146         1668345 :         if (!vp->isUndefined())
    5147          224590 :             AddTypePropertyId(cx, obj, id, *vp);
    5148                 : 
    5149                 :         /*
    5150                 :          * Give a strict warning if foo.bar is evaluated by a script for an
    5151                 :          * object foo with no property named 'bar'.
    5152                 :          */
    5153                 :         jsbytecode *pc;
    5154         1668345 :         if (vp->isUndefined() && ((pc = js_GetCurrentBytecodePC(cx)) != NULL)) {
    5155         1438593 :             JSOp op = (JSOp) *pc;
    5156                 : 
    5157         1438593 :             if (op == JSOP_GETXPROP) {
    5158                 :                 /* Undefined property during a name lookup, report an error. */
    5159               0 :                 JSAutoByteString printable;
    5160               0 :                 if (js_ValueToPrintable(cx, IdToValue(id), &printable))
    5161               0 :                     js_ReportIsNotDefined(cx, printable.ptr());
    5162               0 :                 return false;
    5163                 :             }
    5164                 : 
    5165         1755345 :             if (!cx->hasStrictOption() ||
    5166          316752 :                 cx->stack.currentScript()->warnedAboutUndefinedProp ||
    5167                 :                 (op != JSOP_GETPROP && op != JSOP_GETELEM)) {
    5168         1344607 :                 return JS_TRUE;
    5169                 :             }
    5170                 : 
    5171                 :             /*
    5172                 :              * XXX do not warn about missing __iterator__ as the function
    5173                 :              * may be called from JS_GetMethodById. See bug 355145.
    5174                 :              */
    5175           93986 :             if (JSID_IS_ATOM(id, cx->runtime->atomState.iteratorAtom))
    5176               0 :                 return JS_TRUE;
    5177                 : 
    5178                 :             /* Do not warn about tests like (obj[prop] == undefined). */
    5179           93986 :             if (cx->resolveFlags == RESOLVE_INFER) {
    5180           93960 :                 pc += js_CodeSpec[op].length;
    5181           93960 :                 if (Detecting(cx, pc))
    5182           93530 :                     return JS_TRUE;
    5183              26 :             } else if (cx->resolveFlags & JSRESOLVE_DETECTING) {
    5184               0 :                 return JS_TRUE;
    5185                 :             }
    5186                 : 
    5187             456 :             unsigned flags = JSREPORT_WARNING | JSREPORT_STRICT;
    5188             456 :             cx->stack.currentScript()->warnedAboutUndefinedProp = true;
    5189                 : 
    5190                 :             /* Ok, bad undefined property reference: whine about it. */
    5191             456 :             if (!js_ReportValueErrorFlags(cx, flags, JSMSG_UNDEFINED_PROP,
    5192                 :                                           JSDVG_IGNORE_STACK, IdToValue(id),
    5193             456 :                                           NULL, NULL, NULL))
    5194                 :             {
    5195               0 :                 return false;
    5196                 :             }
    5197                 :         }
    5198          230208 :         return JS_TRUE;
    5199                 :     }
    5200                 : 
    5201        47521880 :     if (!obj2->isNative()) {
    5202             445 :         return obj2->isProxy()
    5203              58 :                ? Proxy::get(cx, obj2, receiver, id, vp)
    5204             503 :                : obj2->getGeneric(cx, id, vp);
    5205                 :     }
    5206                 : 
    5207        47521435 :     shape = (Shape *) prop;
    5208                 : 
    5209        47521435 :     if (getHow & JSGET_CACHE_RESULT)
    5210        10563268 :         JS_PROPERTY_CACHE(cx).fill(cx, aobj, 0, obj2, shape);
    5211                 : 
    5212                 :     /* This call site is hot -- use the always-inlined variant of js_NativeGet(). */
    5213        47521435 :     if (!js_NativeGetInline(cx, receiver, obj, obj2, shape, getHow, vp))
    5214             522 :         return JS_FALSE;
    5215                 : 
    5216        47520913 :     return JS_TRUE;
    5217                 : }
    5218                 : 
    5219                 : bool
    5220        12744180 : js::GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uint32_t getHow, Value *vp)
    5221                 : {
    5222        12744180 :     return !!js_GetPropertyHelperInline(cx, obj, obj, id, getHow, vp);
    5223                 : }
    5224                 : 
    5225                 : JSBool
    5226        36446048 : js_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
    5227                 : {
    5228                 :     /* This call site is hot -- use the always-inlined variant of js_GetPropertyHelper(). */
    5229        36446048 :     return js_GetPropertyHelperInline(cx, obj, receiver, id, JSGET_METHOD_BARRIER, vp);
    5230                 : }
    5231                 : 
    5232                 : JSBool
    5233               0 : js_GetElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, Value *vp)
    5234                 : {
    5235                 :     jsid id;
    5236               0 :     if (!IndexToId(cx, index, &id))
    5237               0 :         return false;
    5238                 : 
    5239                 :     /* This call site is hot -- use the always-inlined variant of js_GetPropertyHelper(). */
    5240               0 :     return js_GetPropertyHelperInline(cx, obj, receiver, id, JSGET_METHOD_BARRIER, vp);
    5241                 : }
    5242                 : 
    5243                 : JSBool
    5244               4 : js::GetPropertyDefault(JSContext *cx, JSObject *obj, jsid id, const Value &def, Value *vp)
    5245                 : {
    5246                 :     JSProperty *prop;
    5247                 :     JSObject *obj2;
    5248               4 :     if (!LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
    5249               0 :         return false;
    5250                 : 
    5251               4 :     if (!prop) {
    5252               2 :         *vp = def;
    5253               2 :         return true;
    5254                 :     }
    5255                 : 
    5256               2 :     return js_GetProperty(cx, obj2, id, vp);
    5257                 : }
    5258                 : 
    5259                 : JSBool
    5260         2252150 : js_GetMethod(JSContext *cx, JSObject *obj, jsid id, unsigned getHow, Value *vp)
    5261                 : {
    5262         4504300 :     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
    5263                 : 
    5264         2252150 :     GenericIdOp op = obj->getOps()->getGeneric;
    5265         2252150 :     if (!op) {
    5266                 : #if JS_HAS_XML_SUPPORT
    5267         1942342 :         JS_ASSERT(!obj->isXML());
    5268                 : #endif
    5269         1942342 :         return GetPropertyHelper(cx, obj, id, getHow, vp);
    5270                 :     }
    5271                 : #if JS_HAS_XML_SUPPORT
    5272          309808 :     if (obj->isXML())
    5273              99 :         return js_GetXMLMethod(cx, obj, id, vp);
    5274                 : #endif
    5275          309709 :     return op(cx, obj, obj, id, vp);
    5276                 : }
    5277                 : 
    5278                 : JS_FRIEND_API(bool)
    5279            2936 : js::CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname)
    5280                 : {
    5281            2936 :     StackFrame *const fp = js_GetTopStackFrame(cx, FRAME_EXPAND_ALL);
    5282            2936 :     if (!fp)
    5283               0 :         return true;
    5284                 : 
    5285                 :     /* If neither cx nor the code is strict, then no check is needed. */
    5286            5863 :     if (!(fp->isScriptFrame() && fp->script()->strictModeCode) &&
    5287            2927 :         !cx->hasStrictOption()) {
    5288            1458 :         return true;
    5289                 :     }
    5290                 : 
    5291            2956 :     JSAutoByteString bytes(cx, propname);
    5292            1478 :     return !!bytes &&
    5293                 :            JS_ReportErrorFlagsAndNumber(cx,
    5294                 :                                         (JSREPORT_WARNING | JSREPORT_STRICT
    5295                 :                                          | JSREPORT_STRICT_MODE_ERROR),
    5296                 :                                         js_GetErrorMessage, NULL,
    5297            1478 :                                         JSMSG_UNDECLARED_VAR, bytes.ptr());
    5298                 : }
    5299                 : 
    5300                 : static bool
    5301              15 : ReportReadOnly(JSContext *cx, jsid id, unsigned report)
    5302                 : {
    5303                 :     return js_ReportValueErrorFlags(cx, report, JSMSG_READ_ONLY,
    5304                 :                                     JSDVG_IGNORE_STACK, IdToValue(id), NULL,
    5305              15 :                                     NULL, NULL);
    5306                 : }
    5307                 : 
    5308                 : bool
    5309               9 : JSObject::reportNotConfigurable(JSContext *cx, jsid id, unsigned report)
    5310                 : {
    5311                 :     return js_ReportValueErrorFlags(cx, report, JSMSG_CANT_DELETE,
    5312                 :                                     JSDVG_IGNORE_STACK, IdToValue(id), NULL,
    5313               9 :                                     NULL, NULL);
    5314                 : }
    5315                 : 
    5316                 : bool
    5317              13 : JSObject::reportNotExtensible(JSContext *cx, unsigned report)
    5318                 : {
    5319                 :     return js_ReportValueErrorFlags(cx, report, JSMSG_OBJECT_NOT_EXTENSIBLE,
    5320                 :                                     JSDVG_IGNORE_STACK, ObjectValue(*this),
    5321              13 :                                     NULL, NULL, NULL);
    5322                 : }
    5323                 : 
    5324                 : bool
    5325               9 : JSObject::callMethod(JSContext *cx, jsid id, unsigned argc, Value *argv, Value *vp)
    5326                 : {
    5327                 :     Value fval;
    5328               9 :     return js_GetMethod(cx, this, id, JSGET_NO_METHOD_BARRIER, &fval) &&
    5329               9 :            Invoke(cx, ObjectValue(*this), fval, argc, argv, vp);
    5330                 : }
    5331                 : 
    5332                 : static bool
    5333               0 : CloneFunctionForSetMethod(JSContext *cx, Value *vp)
    5334                 : {
    5335               0 :     JSFunction *fun = vp->toObject().toFunction();
    5336                 : 
    5337                 :     /* Clone the fun unless it already has been. */
    5338               0 :     if (!fun->isClonedMethod()) {
    5339               0 :         fun = CloneFunctionObject(cx, fun);
    5340               0 :         if (!fun)
    5341               0 :             return false;
    5342               0 :         vp->setObject(*fun);
    5343                 :     }
    5344               0 :     return true;
    5345                 : }
    5346                 : 
    5347                 : JSBool
    5348        17763502 : js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, unsigned defineHow,
    5349                 :                      Value *vp, JSBool strict)
    5350                 : {
    5351                 :     JSObject *pobj;
    5352                 :     JSProperty *prop;
    5353                 :     const Shape *shape;
    5354                 :     unsigned attrs, flags;
    5355                 :     int shortid;
    5356                 :     Class *clasp;
    5357                 :     PropertyOp getter;
    5358                 :     StrictPropertyOp setter;
    5359                 :     bool added;
    5360                 : 
    5361        17763502 :     JS_ASSERT((defineHow & ~(DNP_CACHE_RESULT | DNP_SET_METHOD | DNP_UNQUALIFIED)) == 0);
    5362                 : 
    5363                 :     /* Convert string indices to integers if appropriate. */
    5364        17763502 :     id = js_CheckForStringIndex(id);
    5365                 : 
    5366        17763502 :     if (JS_UNLIKELY(obj->watched())) {
    5367                 :         /* Fire watchpoints, if any. */
    5368            4397 :         WatchpointMap *wpmap = cx->compartment->watchpointMap;
    5369            4397 :         if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, vp))
    5370            2820 :             return false;
    5371                 : 
    5372                 :         /* A watchpoint handler may set *vp to a non-function value. */
    5373            1577 :         defineHow &= ~DNP_SET_METHOD;
    5374                 :     }
    5375                 : 
    5376        17760682 :     if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &prop))
    5377               0 :         return false;
    5378        17760682 :     if (prop) {
    5379        14723542 :         if (!pobj->isNative()) {
    5380              18 :             if (pobj->isProxy()) {
    5381               0 :                 AutoPropertyDescriptorRooter pd(cx);
    5382               0 :                 if (!Proxy::getPropertyDescriptor(cx, pobj, id, true, &pd))
    5383               0 :                     return false;
    5384                 : 
    5385               0 :                 if ((pd.attrs & (JSPROP_SHARED | JSPROP_SHADOWABLE)) == JSPROP_SHARED) {
    5386               0 :                     return !pd.setter ||
    5387               0 :                            CallSetter(cx, obj, id, pd.setter, pd.attrs, pd.shortid, strict, vp);
    5388                 :                 }
    5389                 : 
    5390               0 :                 if (pd.attrs & JSPROP_READONLY) {
    5391               0 :                     if (strict)
    5392               0 :                         return ReportReadOnly(cx, id, JSREPORT_ERROR);
    5393               0 :                     if (cx->hasStrictOption())
    5394               0 :                         return ReportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING);
    5395               0 :                     return true;
    5396                 :                 }
    5397                 :             }
    5398                 : 
    5399              18 :             prop = NULL;
    5400                 :         }
    5401                 :     } else {
    5402                 :         /* We should never add properties to lexical blocks.  */
    5403         3037140 :         JS_ASSERT(!obj->isBlock());
    5404                 : 
    5405         3040076 :         if (obj->isGlobal() &&
    5406                 :             (defineHow & DNP_UNQUALIFIED) &&
    5407            2936 :             !js::CheckUndeclaredVarAssignment(cx, JSID_TO_STRING(id))) {
    5408               9 :             return JS_FALSE;
    5409                 :         }
    5410                 :     }
    5411        17760673 :     shape = (Shape *) prop;
    5412                 : 
    5413                 :     /*
    5414                 :      * Now either shape is null, meaning id was not found in obj or one of its
    5415                 :      * prototypes; or shape is non-null, meaning id was found directly in pobj.
    5416                 :      */
    5417        17760673 :     attrs = JSPROP_ENUMERATE;
    5418        17760673 :     flags = 0;
    5419        17760673 :     shortid = 0;
    5420        17760673 :     clasp = obj->getClass();
    5421        17760673 :     getter = clasp->getProperty;
    5422        17760673 :     setter = clasp->setProperty;
    5423                 : 
    5424        17760673 :     if (shape) {
    5425                 :         /* ES5 8.12.4 [[Put]] step 2. */
    5426        14723524 :         if (shape->isAccessorDescriptor()) {
    5427          130783 :             if (shape->hasDefaultSetter())
    5428            1076 :                 return js_ReportGetterOnlyAssignment(cx);
    5429                 :         } else {
    5430        14592741 :             JS_ASSERT(shape->isDataDescriptor());
    5431                 : 
    5432        14592741 :             if (!shape->writable()) {
    5433                 :                 /* Error in strict mode code, warn with strict option, otherwise do nothing. */
    5434             888 :                 if (strict)
    5435               9 :                     return ReportReadOnly(cx, id, JSREPORT_ERROR);
    5436             879 :                 if (cx->hasStrictOption())
    5437               6 :                     return ReportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING);
    5438             873 :                 return JS_TRUE;
    5439                 :             }
    5440                 :         }
    5441                 : 
    5442        14721560 :         attrs = shape->attributes();
    5443        14721560 :         if (pobj != obj) {
    5444                 :             /*
    5445                 :              * We found id in a prototype object: prepare to share or shadow.
    5446                 :              */
    5447          692530 :             if (!shape->shadowable()) {
    5448           56013 :                 if (defineHow & DNP_SET_METHOD) {
    5449               0 :                     JS_ASSERT(!shape->isMethod());
    5450               0 :                     if (!CloneFunctionForSetMethod(cx, vp))
    5451               0 :                         return false;
    5452                 :                 }
    5453                 : 
    5454           56013 :                 if (defineHow & DNP_CACHE_RESULT)
    5455           41300 :                     JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, pobj, shape);
    5456                 : 
    5457           56013 :                 if (shape->hasDefaultSetter() && !shape->hasGetterValue())
    5458               0 :                     return JS_TRUE;
    5459                 : 
    5460           56013 :                 return shape->set(cx, obj, strict, vp);
    5461                 :             }
    5462                 : 
    5463                 :             /*
    5464                 :              * Preserve attrs except JSPROP_SHARED, getter, and setter when
    5465                 :              * shadowing any property that has no slot (is shared). We must
    5466                 :              * clear the shared attribute for the shadowing shape so that the
    5467                 :              * property in obj that it defines has a slot to retain the value
    5468                 :              * being set, in case the setter simply cannot operate on instances
    5469                 :              * of obj's class by storing the value in some class-specific
    5470                 :              * location.
    5471                 :              *
    5472                 :              * A subset of slotless shared properties is the set of properties
    5473                 :              * with shortids, which must be preserved too. An old API requires
    5474                 :              * that the property's getter and setter receive the shortid, not
    5475                 :              * id, when they are called on the shadowing property that we are
    5476                 :              * about to create in obj.
    5477                 :              */
    5478          636517 :             if (!shape->hasSlot()) {
    5479               0 :                 defineHow &= ~DNP_SET_METHOD;
    5480               0 :                 if (shape->hasShortID()) {
    5481               0 :                     flags = Shape::HAS_SHORTID;
    5482               0 :                     shortid = shape->shortid();
    5483                 :                 }
    5484               0 :                 attrs &= ~JSPROP_SHARED;
    5485               0 :                 getter = shape->getter();
    5486               0 :                 setter = shape->setter();
    5487                 :             } else {
    5488                 :                 /* Restore attrs to the ECMA default for new properties. */
    5489          636517 :                 attrs = JSPROP_ENUMERATE;
    5490                 :             }
    5491                 : 
    5492                 :             /*
    5493                 :              * Forget we found the proto-property now that we've copied any
    5494                 :              * needed member values.
    5495                 :              */
    5496          636517 :             shape = NULL;
    5497                 :         }
    5498                 : 
    5499        14665547 :         if (shape && (defineHow & DNP_SET_METHOD)) {
    5500                 :             /*
    5501                 :              * JSOP_SETMETHOD is assigning to an existing own property. If it
    5502                 :              * is an identical method property, do nothing. Otherwise downgrade
    5503                 :              * to ordinary assignment. Either way, do not fill the property
    5504                 :              * cache, as the interpreter has no fast path for these unusual
    5505                 :              * cases.
    5506                 :              */
    5507               0 :             if (shape->isMethod()) {
    5508               0 :                 if (obj->nativeGetMethod(shape) == &vp->toObject())
    5509               0 :                     return true;
    5510               0 :                 shape = obj->methodShapeChange(cx, *shape);
    5511               0 :                 if (!shape)
    5512               0 :                     return false;
    5513                 :             }
    5514               0 :             if (!CloneFunctionForSetMethod(cx, vp))
    5515               0 :                 return false;
    5516               0 :             return js_NativeSet(cx, obj, shape, false, strict, vp);
    5517                 :         }
    5518                 :     }
    5519                 : 
    5520        17702696 :     added = false;
    5521        17702696 :     if (!shape) {
    5522         3673666 :         if (!obj->isExtensible()) {
    5523                 :             /* Error in strict mode code, warn with strict option, otherwise do nothing. */
    5524               4 :             if (strict)
    5525               1 :                 return obj->reportNotExtensible(cx);
    5526               3 :             if (cx->hasStrictOption())
    5527               3 :                 return obj->reportNotExtensible(cx, JSREPORT_STRICT | JSREPORT_WARNING);
    5528               0 :             return JS_TRUE;
    5529                 :         }
    5530                 : 
    5531                 :         /*
    5532                 :          * Purge the property cache of now-shadowed id in obj's scope chain.
    5533                 :          * Do this early, before locking obj to avoid nesting locks.
    5534                 :          */
    5535         3673662 :         if (!js_PurgeScopeChain(cx, obj, id))
    5536               0 :             return JS_FALSE;
    5537                 : 
    5538                 :         /*
    5539                 :          * Check for Object class here to avoid defining a method on a class
    5540                 :          * with magic resolve, addProperty, getProperty, etc. hooks.
    5541                 :          */
    5542         3673662 :         if ((defineHow & DNP_SET_METHOD) && obj->canHaveMethodBarrier()) {
    5543               0 :             JS_ASSERT(IsFunctionObject(*vp));
    5544               0 :             JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
    5545                 : 
    5546               0 :             JSObject *funobj = &vp->toObject();
    5547               0 :             if (!funobj->toFunction()->isClonedMethod())
    5548               0 :                 flags |= Shape::METHOD;
    5549                 :         }
    5550                 : 
    5551                 :         shape = obj->putProperty(cx, id, getter, setter, SHAPE_INVALID_SLOT,
    5552         3673662 :                                  attrs, flags, shortid);
    5553         3673662 :         if (!shape)
    5554               0 :             return JS_FALSE;
    5555                 : 
    5556                 :         /*
    5557                 :          * Initialize the new property value (passed to setter) to undefined.
    5558                 :          * Note that we store before calling addProperty, to match the order
    5559                 :          * in DefineNativeProperty.
    5560                 :          */
    5561         3673662 :         if (shape->hasSlot())
    5562         3673662 :             obj->nativeSetSlot(shape->slot(), UndefinedValue());
    5563                 : 
    5564                 :         /* XXXbe called with obj locked */
    5565         3673662 :         if (!CallAddPropertyHook(cx, clasp, obj, shape, vp)) {
    5566               2 :             obj->removeProperty(cx, id);
    5567               2 :             return JS_FALSE;
    5568                 :         }
    5569         3673660 :         added = true;
    5570                 :     }
    5571                 : 
    5572        17702690 :     if ((defineHow & DNP_CACHE_RESULT) && !added)
    5573          650563 :         JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, obj, shape);
    5574                 : 
    5575        17702690 :     return js_NativeSet(cx, obj, shape, added, strict, vp);
    5576                 : }
    5577                 : 
    5578                 : JSBool
    5579               1 : js_SetElementHelper(JSContext *cx, JSObject *obj, uint32_t index, unsigned defineHow,
    5580                 :                     Value *vp, JSBool strict)
    5581                 : {
    5582                 :     jsid id;
    5583               1 :     if (!IndexToId(cx, index, &id))
    5584               0 :         return false;
    5585               1 :     return js_SetPropertyHelper(cx, obj, id, defineHow, vp, strict);
    5586                 : }
    5587                 : 
    5588                 : JSBool
    5589           92112 : js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp)
    5590                 : {
    5591                 :     JSProperty *prop;
    5592           92112 :     if (!js_LookupProperty(cx, obj, id, &obj, &prop))
    5593               0 :         return false;
    5594           92112 :     if (!prop) {
    5595               0 :         *attrsp = 0;
    5596               0 :         return true;
    5597                 :     }
    5598           92112 :     if (!obj->isNative())
    5599               0 :         return obj->getGenericAttributes(cx, id, attrsp);
    5600                 : 
    5601           92112 :     const Shape *shape = (Shape *)prop;
    5602           92112 :     *attrsp = shape->attributes();
    5603           92112 :     return true;
    5604                 : }
    5605                 : 
    5606                 : JSBool
    5607               0 : js_GetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *attrsp)
    5608                 : {
    5609                 :     JSProperty *prop;
    5610               0 :     if (!js_LookupElement(cx, obj, index, &obj, &prop))
    5611               0 :         return false;
    5612               0 :     if (!prop) {
    5613               0 :         *attrsp = 0;
    5614               0 :         return true;
    5615                 :     }
    5616               0 :     if (!obj->isNative())
    5617               0 :         return obj->getElementAttributes(cx, index, attrsp);
    5618                 : 
    5619               0 :     const Shape *shape = (Shape *)prop;
    5620               0 :     *attrsp = shape->attributes();
    5621               0 :     return true;
    5622                 : }
    5623                 : 
    5624                 : JSBool
    5625           40625 : js_SetNativeAttributes(JSContext *cx, JSObject *obj, Shape *shape, unsigned attrs)
    5626                 : {
    5627           40625 :     JS_ASSERT(obj->isNative());
    5628                 :     return !!js_ChangeNativePropertyAttrs(cx, obj, shape, attrs, 0,
    5629           40625 :                                           shape->getter(), shape->setter());
    5630                 : }
    5631                 : 
    5632                 : JSBool
    5633           40625 : js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp)
    5634                 : {
    5635                 :     JSProperty *prop;
    5636           40625 :     if (!js_LookupProperty(cx, obj, id, &obj, &prop))
    5637               0 :         return false;
    5638           40625 :     if (!prop)
    5639               0 :         return true;
    5640           40625 :     return obj->isNative()
    5641           40625 :            ? js_SetNativeAttributes(cx, obj, (Shape *) prop, *attrsp)
    5642           81250 :            : obj->setGenericAttributes(cx, id, attrsp);
    5643                 : }
    5644                 : 
    5645                 : JSBool
    5646               0 : js_SetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *attrsp)
    5647                 : {
    5648                 :     JSProperty *prop;
    5649               0 :     if (!js_LookupElement(cx, obj, index, &obj, &prop))
    5650               0 :         return false;
    5651               0 :     if (!prop)
    5652               0 :         return true;
    5653               0 :     return obj->isNative()
    5654               0 :            ? js_SetNativeAttributes(cx, obj, (Shape *) prop, *attrsp)
    5655               0 :            : obj->setElementAttributes(cx, index, attrsp);
    5656                 : }
    5657                 : 
    5658                 : JSBool
    5659          245979 : js_DeleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
    5660                 : {
    5661                 :     JSObject *proto;
    5662                 :     JSProperty *prop;
    5663                 :     const Shape *shape;
    5664                 : 
    5665          245979 :     rval->setBoolean(true);
    5666                 : 
    5667                 :     /* Convert string indices to integers if appropriate. */
    5668          245979 :     id = js_CheckForStringIndex(id);
    5669                 : 
    5670          245979 :     if (!js_LookupProperty(cx, obj, id, &proto, &prop))
    5671               0 :         return false;
    5672          245979 :     if (!prop || proto != obj) {
    5673                 :         /*
    5674                 :          * If no property, or the property comes from a prototype, call the
    5675                 :          * class's delProperty hook, passing rval as the result parameter.
    5676                 :          */
    5677          194287 :         return CallJSPropertyOp(cx, obj->getClass()->delProperty, obj, id, rval);
    5678                 :     }
    5679                 : 
    5680           51692 :     shape = (Shape *)prop;
    5681           51692 :     if (!shape->configurable()) {
    5682              27 :         if (strict)
    5683               9 :             return obj->reportNotConfigurable(cx, id);
    5684              18 :         rval->setBoolean(false);
    5685              18 :         return true;
    5686                 :     }
    5687                 : 
    5688           51665 :     if (shape->hasSlot()) {
    5689           21124 :         const Value &v = obj->nativeGetSlot(shape->slot());
    5690           21124 :         GCPoke(cx->runtime, v);
    5691                 : 
    5692                 :         /*
    5693                 :          * Delete is rare enough that we can take the hit of checking for an
    5694                 :          * active cloned method function object that must be homed to a callee
    5695                 :          * slot on the active stack frame before this delete completes, in case
    5696                 :          * someone saved the clone and checks it against foo.caller for a foo
    5697                 :          * called from the active method.
    5698                 :          *
    5699                 :          * We do not check suspended frames. They can't be reached via caller,
    5700                 :          * so the only way they could have the method's joined function object
    5701                 :          * as callee is through an API abusage. We break any such edge case.
    5702                 :          */
    5703                 :         JSFunction *fun;
    5704           21124 :         if (IsFunctionObject(v, &fun) && fun->isClonedMethod()) {
    5705               0 :             for (StackFrame *fp = cx->maybefp(); fp; fp = fp->prev()) {
    5706               0 :                 if (fp->isFunctionFrame() &&
    5707               0 :                     fp->fun()->script() == fun->script() &&
    5708               0 :                     fp->thisValue().isObject())
    5709                 :                 {
    5710               0 :                     JSObject *tmp = &fp->thisValue().toObject();
    5711               0 :                     do {
    5712               0 :                         if (tmp == obj) {
    5713               0 :                             fp->overwriteCallee(*fun);
    5714               0 :                             break;
    5715                 :                         }
    5716               0 :                     } while ((tmp = tmp->getProto()) != NULL);
    5717                 :                 }
    5718                 :             }
    5719                 :         }
    5720                 :     }
    5721                 : 
    5722           51665 :     if (!CallJSPropertyOp(cx, obj->getClass()->delProperty, obj, shape->getUserId(), rval))
    5723               0 :         return false;
    5724           51665 :     if (rval->isFalse())
    5725               0 :         return true;
    5726                 : 
    5727           51665 :     return obj->removeProperty(cx, id) && js_SuppressDeletedProperty(cx, obj, id);
    5728                 : }
    5729                 : 
    5730                 : JSBool
    5731           48293 : js_DeleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict)
    5732                 : {
    5733           48293 :     return js_DeleteGeneric(cx, obj, ATOM_TO_JSID(name), rval, strict);
    5734                 : }
    5735                 : 
    5736                 : JSBool
    5737          197245 : js_DeleteElement(JSContext *cx, JSObject *obj, uint32_t index, Value *rval, JSBool strict)
    5738                 : {
    5739                 :     jsid id;
    5740          197245 :     if (!IndexToId(cx, index, &id))
    5741               0 :         return false;
    5742          197245 :     return js_DeleteGeneric(cx, obj, id, rval, strict);
    5743                 : }
    5744                 : 
    5745                 : JSBool
    5746               0 : js_DeleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict)
    5747                 : {
    5748               0 :     return js_DeleteGeneric(cx, obj, SPECIALID_TO_JSID(sid), rval, strict);
    5749                 : }
    5750                 : 
    5751                 : namespace js {
    5752                 : 
    5753                 : bool
    5754          372046 : HasDataProperty(JSContext *cx, JSObject *obj, jsid methodid, Value *vp)
    5755                 : {
    5756          372046 :     if (const Shape *shape = obj->nativeLookup(cx, methodid)) {
    5757          186032 :         if (shape->hasDefaultGetterOrIsMethod() && shape->hasSlot()) {
    5758          186014 :             *vp = obj->nativeGetSlot(shape->slot());
    5759          186014 :             return true;
    5760                 :         }
    5761                 :     }
    5762                 : 
    5763          186032 :     return false;
    5764                 : }
    5765                 : 
    5766                 : /*
    5767                 :  * Gets |obj[id]|.  If that value's not callable, returns true and stores a
    5768                 :  * non-primitive value in *vp.  If it's callable, calls it with no arguments
    5769                 :  * and |obj| as |this|, returning the result in *vp.
    5770                 :  *
    5771                 :  * This is a mini-abstraction for ES5 8.12.8 [[DefaultValue]], either steps 1-2
    5772                 :  * or steps 3-4.
    5773                 :  */
    5774                 : static bool
    5775         1130697 : MaybeCallMethod(JSContext *cx, JSObject *obj, jsid id, Value *vp)
    5776                 : {
    5777         1130697 :     if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, vp))
    5778             135 :         return false;
    5779         1130562 :     if (!js_IsCallable(*vp)) {
    5780           20259 :         *vp = ObjectValue(*obj);
    5781           20259 :         return true;
    5782                 :     }
    5783         1110303 :     return Invoke(cx, ObjectValue(*obj), *vp, 0, NULL, vp);
    5784                 : }
    5785                 : 
    5786                 : JSBool
    5787          922009 : DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp)
    5788                 : {
    5789          922009 :     JS_ASSERT(hint == JSTYPE_NUMBER || hint == JSTYPE_STRING || hint == JSTYPE_VOID);
    5790          922009 :     JS_ASSERT(!obj->isXML());
    5791                 : 
    5792          922009 :     Class *clasp = obj->getClass();
    5793          922009 :     if (hint == JSTYPE_STRING) {
    5794                 :         /* Optimize (new String(...)).toString(). */
    5795           52680 :         if (clasp == &StringClass &&
    5796                 :             ClassMethodIsNative(cx, obj,
    5797                 :                                  &StringClass,
    5798             657 :                                  ATOM_TO_JSID(cx->runtime->atomState.toStringAtom),
    5799             657 :                                  js_str_toString)) {
    5800             657 :             *vp = StringValue(obj->asString().unbox());
    5801             657 :             return true;
    5802                 :         }
    5803                 : 
    5804           51366 :         if (!MaybeCallMethod(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.toStringAtom), vp))
    5805            5430 :             return false;
    5806           45936 :         if (vp->isPrimitive())
    5807           45387 :             return true;
    5808                 : 
    5809             549 :         if (!MaybeCallMethod(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom), vp))
    5810               0 :             return false;
    5811             549 :         if (vp->isPrimitive())
    5812             540 :             return true;
    5813                 :     } else {
    5814                 :         /* Optimize (new String(...)).valueOf(). */
    5815         1052583 :         if ((clasp == &StringClass &&
    5816                 :              ClassMethodIsNative(cx, obj, &StringClass,
    5817          180863 :                                  ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom),
    5818          180863 :                                  js_str_toString)) ||
    5819                 :             (clasp == &NumberClass &&
    5820                 :              ClassMethodIsNative(cx, obj, &NumberClass,
    5821            1734 :                                  ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom),
    5822            1734 :                                  js_num_valueOf))) {
    5823          182579 :             *vp = obj->isString()
    5824          180845 :                   ? StringValue(obj->asString().unbox())
    5825          363424 :                   : NumberValue(obj->asNumber().unbox());
    5826          182579 :             return true;
    5827                 :         }
    5828                 : 
    5829          687407 :         if (!MaybeCallMethod(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom), vp))
    5830              18 :             return false;
    5831          687389 :         if (vp->isPrimitive())
    5832          296014 :             return true;
    5833                 : 
    5834          391375 :         if (!MaybeCallMethod(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.toStringAtom), vp))
    5835              27 :             return false;
    5836          391348 :         if (vp->isPrimitive())
    5837          391276 :             return true;
    5838                 :     }
    5839                 : 
    5840                 :     /* Avoid recursive death when decompiling in js_ReportValueError. */
    5841                 :     JSString *str;
    5842              81 :     if (hint == JSTYPE_STRING) {
    5843               9 :         str = JS_InternString(cx, clasp->name);
    5844               9 :         if (!str)
    5845               0 :             return false;
    5846                 :     } else {
    5847              72 :         str = NULL;
    5848                 :     }
    5849                 : 
    5850              81 :     js_ReportValueError2(cx, JSMSG_CANT_CONVERT_TO, JSDVG_SEARCH_STACK, ObjectValue(*obj), str,
    5851              81 :                          (hint == JSTYPE_VOID) ? "primitive type" : JS_TYPE_STR(hint));
    5852              81 :     return false;
    5853                 : }
    5854                 : 
    5855                 : } /* namespace js */
    5856                 : 
    5857                 : JS_FRIEND_API(JSBool)
    5858             330 : JS_EnumerateState(JSContext *cx, JSObject *obj, JSIterateOp enum_op, Value *statep, jsid *idp)
    5859                 : {
    5860                 :     /* If the class has a custom JSCLASS_NEW_ENUMERATE hook, call it. */
    5861             330 :     Class *clasp = obj->getClass();
    5862             330 :     JSEnumerateOp enumerate = clasp->enumerate;
    5863             330 :     if (clasp->flags & JSCLASS_NEW_ENUMERATE) {
    5864               0 :         JS_ASSERT(enumerate != JS_EnumerateStub);
    5865               0 :         return ((JSNewEnumerateOp) enumerate)(cx, obj, enum_op, statep, idp);
    5866                 :     }
    5867                 : 
    5868             330 :     if (!enumerate(cx, obj))
    5869               0 :         return false;
    5870                 : 
    5871                 :     /* Tell InitNativeIterator to treat us like a native object. */
    5872             330 :     JS_ASSERT(enum_op == JSENUMERATE_INIT || enum_op == JSENUMERATE_INIT_ALL);
    5873             330 :     statep->setMagic(JS_NATIVE_ENUMERATE);
    5874             330 :     return true;
    5875                 : }
    5876                 : 
    5877                 : namespace js {
    5878                 : 
    5879                 : JSBool
    5880          687434 : CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
    5881                 :             Value *vp, unsigned *attrsp)
    5882                 : {
    5883                 :     JSBool writing;
    5884                 :     JSObject *pobj;
    5885                 :     JSProperty *prop;
    5886                 :     const Shape *shape;
    5887                 : 
    5888         1374868 :     while (JS_UNLIKELY(obj->isWith()))
    5889               0 :         obj = obj->getProto();
    5890                 : 
    5891          687434 :     writing = (mode & JSACC_WRITE) != 0;
    5892          687434 :     switch (mode & JSACC_TYPEMASK) {
    5893                 :       case JSACC_PROTO:
    5894           17033 :         pobj = obj;
    5895           17033 :         if (!writing)
    5896            2152 :             vp->setObjectOrNull(obj->getProto());
    5897           17033 :         *attrsp = JSPROP_PERMANENT;
    5898           17033 :         break;
    5899                 : 
    5900                 :       case JSACC_PARENT:
    5901               0 :         JS_ASSERT(!writing);
    5902               0 :         pobj = obj;
    5903               0 :         vp->setObject(*obj->getParent());
    5904               0 :         *attrsp = JSPROP_READONLY | JSPROP_PERMANENT;
    5905               0 :         break;
    5906                 : 
    5907                 :       default:
    5908          670401 :         if (!obj->lookupGeneric(cx, id, &pobj, &prop))
    5909               0 :             return JS_FALSE;
    5910          670401 :         if (!prop) {
    5911          638253 :             if (!writing)
    5912          638253 :                 vp->setUndefined();
    5913          638253 :             *attrsp = 0;
    5914          638253 :             pobj = obj;
    5915          638253 :             break;
    5916                 :         }
    5917                 : 
    5918           32148 :         if (!pobj->isNative()) {
    5919               0 :             if (!writing) {
    5920               0 :                     vp->setUndefined();
    5921               0 :                 *attrsp = 0;
    5922                 :             }
    5923               0 :             break;
    5924                 :         }
    5925                 : 
    5926           32148 :         shape = (Shape *)prop;
    5927           32148 :         *attrsp = shape->attributes();
    5928           32148 :         if (!writing) {
    5929           32148 :             if (shape->hasSlot())
    5930             915 :                 *vp = pobj->nativeGetSlot(shape->slot());
    5931                 :             else
    5932           31233 :                 vp->setUndefined();
    5933                 :         }
    5934                 :     }
    5935                 : 
    5936          687434 :     JS_ASSERT_IF(*attrsp & JSPROP_READONLY, !(*attrsp & (JSPROP_GETTER | JSPROP_SETTER)));
    5937                 : 
    5938                 :     /*
    5939                 :      * If obj's class has a stub (null) checkAccess hook, use the per-runtime
    5940                 :      * checkObjectAccess callback, if configured.
    5941                 :      *
    5942                 :      * We don't want to require all classes to supply a checkAccess hook; we
    5943                 :      * need that hook only for certain classes used when precompiling scripts
    5944                 :      * and functions ("brutal sharing").  But for general safety of built-in
    5945                 :      * magic properties like __proto__, we route all access checks, even for
    5946                 :      * classes that stub out checkAccess, through the global checkObjectAccess
    5947                 :      * hook.  This covers precompilation-based sharing and (possibly
    5948                 :      * unintended) runtime sharing across trust boundaries.
    5949                 :      */
    5950          687434 :     JSCheckAccessOp check = pobj->getClass()->checkAccess;
    5951          687434 :     if (!check)
    5952          687434 :         check = cx->runtime->securityCallbacks->checkObjectAccess;
    5953          687434 :     return !check || check(cx, pobj, id, mode, vp);
    5954                 : }
    5955                 : 
    5956                 : }
    5957                 : 
    5958                 : JSType
    5959         6979281 : js_TypeOf(JSContext *cx, JSObject *obj)
    5960                 : {
    5961         6979281 :     return obj->isCallable() ? JSTYPE_FUNCTION : JSTYPE_OBJECT;
    5962                 : }
    5963                 : 
    5964                 : bool
    5965         1060687 : js_IsDelegate(JSContext *cx, JSObject *obj, const Value &v)
    5966                 : {
    5967         1060687 :     if (v.isPrimitive())
    5968          262122 :         return false;
    5969          798565 :     JSObject *obj2 = &v.toObject();
    5970         1600195 :     while ((obj2 = obj2->getProto()) != NULL) {
    5971          800215 :         if (obj2 == obj)
    5972          797150 :             return true;
    5973                 :     }
    5974            1415 :     return false;
    5975                 : }
    5976                 : 
    5977                 : bool
    5978          344418 : js::FindClassPrototype(JSContext *cx, JSObject *scopeobj, JSProtoKey protoKey,
    5979                 :                        JSObject **protop, Class *clasp)
    5980                 : {
    5981                 :     Value v;
    5982          344418 :     if (!js_FindClassObject(cx, scopeobj, protoKey, &v, clasp))
    5983               0 :         return false;
    5984                 : 
    5985          344418 :     if (IsFunctionObject(v)) {
    5986           70407 :         JSObject *ctor = &v.toObject();
    5987           70407 :         if (!ctor->getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &v))
    5988               0 :             return false;
    5989                 :     }
    5990                 : 
    5991          344418 :     *protop = v.isObject() ? &v.toObject() : NULL;
    5992          344418 :     return true;
    5993                 : }
    5994                 : 
    5995                 : /*
    5996                 :  * The first part of this function has been hand-expanded and optimized into
    5997                 :  * NewBuiltinClassInstance in jsobjinlines.h.
    5998                 :  */
    5999                 : JSBool
    6000         9831100 : js_GetClassPrototype(JSContext *cx, JSObject *scopeobj, JSProtoKey protoKey,
    6001                 :                      JSObject **protop, Class *clasp)
    6002                 : {
    6003         9831100 :     JS_ASSERT(JSProto_Null <= protoKey);
    6004         9831100 :     JS_ASSERT(protoKey < JSProto_LIMIT);
    6005                 : 
    6006         9831100 :     if (protoKey != JSProto_Null) {
    6007                 :         GlobalObject *global;
    6008         9565638 :         if (scopeobj) {
    6009         7921856 :             global = &scopeobj->global();
    6010                 :         } else {
    6011         1643782 :             global = GetCurrentGlobal(cx);
    6012         1643782 :             if (!global) {
    6013               0 :                 *protop = NULL;
    6014               0 :                 return true;
    6015                 :             }
    6016                 :         }
    6017         9565638 :         const Value &v = global->getReservedSlot(JSProto_LIMIT + protoKey);
    6018         9565638 :         if (v.isObject()) {
    6019         9486682 :             *protop = &v.toObject();
    6020         9486682 :             return true;
    6021                 :         }
    6022                 :     }
    6023                 : 
    6024          344418 :     return FindClassPrototype(cx, scopeobj, protoKey, protop, clasp);
    6025                 : }
    6026                 : 
    6027                 : JSObject *
    6028         5063951 : PrimitiveToObject(JSContext *cx, const Value &v)
    6029                 : {
    6030         5063951 :     if (v.isString())
    6031         4801288 :         return StringObject::create(cx, v.toString());
    6032          262663 :     if (v.isNumber())
    6033          256351 :         return NumberObject::create(cx, v.toNumber());
    6034                 : 
    6035            6312 :     JS_ASSERT(v.isBoolean());
    6036            6312 :     return BooleanObject::create(cx, v.toBoolean());
    6037                 : }
    6038                 : 
    6039                 : JSBool
    6040             479 : js_PrimitiveToObject(JSContext *cx, Value *vp)
    6041                 : {
    6042             479 :     JSObject *obj = PrimitiveToObject(cx, *vp);
    6043             479 :     if (!obj)
    6044               0 :         return false;
    6045                 : 
    6046             479 :     vp->setObject(*obj);
    6047             479 :     return true;
    6048                 : }
    6049                 : 
    6050                 : JSBool
    6051         5156600 : js_ValueToObjectOrNull(JSContext *cx, const Value &v, JSObject **objp)
    6052                 : {
    6053                 :     JSObject *obj;
    6054                 : 
    6055         5156600 :     if (v.isObjectOrNull()) {
    6056           93154 :         obj = v.toObjectOrNull();
    6057         5063446 :     } else if (v.isUndefined()) {
    6058            1267 :         obj = NULL;
    6059                 :     } else {
    6060         5062179 :         obj = PrimitiveToObject(cx, v);
    6061         5062179 :         if (!obj)
    6062               0 :             return false;
    6063                 :     }
    6064         5156600 :     *objp = obj;
    6065         5156600 :     return true;
    6066                 : }
    6067                 : 
    6068                 : namespace js {
    6069                 : 
    6070                 : /* Callers must handle the already-object case . */
    6071                 : JSObject *
    6072            1313 : ToObjectSlow(JSContext *cx, Value *vp)
    6073                 : {
    6074            1313 :     JS_ASSERT(!vp->isMagic());
    6075            1313 :     JS_ASSERT(!vp->isObject());
    6076                 : 
    6077            1313 :     if (vp->isNullOrUndefined()) {
    6078                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO,
    6079              20 :                             vp->isNull() ? "null" : "undefined", "object");
    6080              20 :         return NULL;
    6081                 :     }
    6082                 : 
    6083            1293 :     JSObject *obj = PrimitiveToObject(cx, *vp);
    6084            1293 :     if (obj)
    6085            1293 :         vp->setObject(*obj);
    6086            1293 :     return obj;
    6087                 : }
    6088                 : 
    6089                 : }
    6090                 : 
    6091                 : JSObject *
    6092         5040340 : js_ValueToNonNullObject(JSContext *cx, const Value &v)
    6093                 : {
    6094                 :     JSObject *obj;
    6095                 : 
    6096         5040340 :     if (!js_ValueToObjectOrNull(cx, v, &obj))
    6097               0 :         return NULL;
    6098         5040340 :     if (!obj)
    6099             742 :         js_ReportIsNullOrUndefined(cx, JSDVG_SEARCH_STACK, v, NULL);
    6100         5040340 :     return obj;
    6101                 : }
    6102                 : 
    6103                 : #ifdef DEBUG
    6104                 : void
    6105          359079 : js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
    6106                 : {
    6107          359079 :     JS_ASSERT(trc->debugPrinter == js_PrintObjectSlotName);
    6108                 : 
    6109          359079 :     JSObject *obj = (JSObject *)trc->debugPrintArg;
    6110          359079 :     uint32_t slot = uint32_t(trc->debugPrintIndex);
    6111                 : 
    6112                 :     const Shape *shape;
    6113          359079 :     if (obj->isNative()) {
    6114          359079 :         shape = obj->lastProperty();
    6115         5357688 :         while (shape && (!shape->hasSlot() || shape->slot() != slot))
    6116         4639530 :             shape = shape->previous();
    6117                 :     } else {
    6118               0 :         shape = NULL;
    6119                 :     }
    6120                 : 
    6121          359079 :     if (!shape) {
    6122           74520 :         const char *slotname = NULL;
    6123           74520 :         if (obj->isGlobal()) {
    6124                 : #define JS_PROTO(name,code,init)                                              \
    6125                 :     if ((code) == slot) { slotname = js_##name##_str; goto found; }
    6126                 : #include "jsproto.tbl"
    6127                 : #undef JS_PROTO
    6128                 :         }
    6129                 :       found:
    6130           74520 :         if (slotname)
    6131            2160 :             JS_snprintf(buf, bufsize, "CLASS_OBJECT(%s)", slotname);
    6132                 :         else
    6133           72360 :             JS_snprintf(buf, bufsize, "**UNKNOWN SLOT %ld**", (long)slot);
    6134                 :     } else {
    6135          284559 :         jsid propid = shape->propid();
    6136          284559 :         if (JSID_IS_INT(propid)) {
    6137               0 :             JS_snprintf(buf, bufsize, "%ld", (long)JSID_TO_INT(propid));
    6138          284559 :         } else if (JSID_IS_ATOM(propid)) {
    6139          284559 :             PutEscapedString(buf, bufsize, JSID_TO_ATOM(propid), 0);
    6140                 :         } else {
    6141               0 :             JS_snprintf(buf, bufsize, "**FINALIZED ATOM KEY**");
    6142                 :         }
    6143                 :     }
    6144          359079 : }
    6145                 : #endif
    6146                 : 
    6147                 : static const Shape *
    6148          447433 : LastConfigurableShape(JSObject *obj)
    6149                 : {
    6150         9528990 :     for (Shape::Range r(obj->lastProperty()->all()); !r.empty(); r.popFront()) {
    6151         9515772 :         const Shape *shape = &r.front();
    6152         9515772 :         if (shape->configurable())
    6153          434215 :             return shape;
    6154                 :     }
    6155           13218 :     return NULL;
    6156                 : }
    6157                 : 
    6158                 : bool
    6159          447433 : js_ClearNative(JSContext *cx, JSObject *obj)
    6160                 : {
    6161                 :     /* Remove all configurable properties from obj. */
    6162          881648 :     while (const Shape *shape = LastConfigurableShape(obj)) {
    6163          434215 :         if (!obj->removeProperty(cx, shape->propid()))
    6164               0 :             return false;
    6165                 :     }
    6166                 : 
    6167                 :     /* Set all remaining writable plain data properties to undefined. */
    6168          494550 :     for (Shape::Range r(obj->lastProperty()->all()); !r.empty(); r.popFront()) {
    6169          481332 :         const Shape *shape = &r.front();
    6170         1556168 :         if (shape->isDataDescriptor() &&
    6171          481332 :             shape->writable() &&
    6172          296752 :             shape->hasDefaultSetter() &&
    6173          296752 :             shape->hasSlot()) {
    6174          296752 :             obj->nativeSetSlot(shape->slot(), UndefinedValue());
    6175                 :         }
    6176                 :     }
    6177           13218 :     return true;
    6178                 : }
    6179                 : 
    6180                 : JSBool
    6181            1090 : js_ReportGetterOnlyAssignment(JSContext *cx)
    6182                 : {
    6183                 :     return JS_ReportErrorFlagsAndNumber(cx,
    6184                 :                                         JSREPORT_WARNING | JSREPORT_STRICT |
    6185                 :                                         JSREPORT_STRICT_MODE_ERROR,
    6186                 :                                         js_GetErrorMessage, NULL,
    6187            1090 :                                         JSMSG_GETTER_ONLY);
    6188                 : }
    6189                 : 
    6190                 : JS_FRIEND_API(JSBool)
    6191               0 : js_GetterOnlyPropertyStub(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
    6192                 : {
    6193               0 :     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_GETTER_ONLY);
    6194               0 :     return JS_FALSE;
    6195                 : }
    6196                 : 
    6197                 : #ifdef DEBUG
    6198                 : 
    6199                 : /*
    6200                 :  * Routines to print out values during debugging.  These are FRIEND_API to help
    6201                 :  * the debugger find them and to support temporarily hacking js_Dump* calls
    6202                 :  * into other code.
    6203                 :  */
    6204                 : 
    6205                 : void
    6206               0 : dumpValue(const Value &v)
    6207                 : {
    6208               0 :     if (v.isNull())
    6209               0 :         fprintf(stderr, "null");
    6210               0 :     else if (v.isUndefined())
    6211               0 :         fprintf(stderr, "undefined");
    6212               0 :     else if (v.isInt32())
    6213               0 :         fprintf(stderr, "%d", v.toInt32());
    6214               0 :     else if (v.isDouble())
    6215               0 :         fprintf(stderr, "%g", v.toDouble());
    6216               0 :     else if (v.isString())
    6217               0 :         v.toString()->dump();
    6218               0 :     else if (v.isObject() && v.toObject().isFunction()) {
    6219               0 :         JSFunction *fun = v.toObject().toFunction();
    6220               0 :         if (fun->atom) {
    6221               0 :             fputs("<function ", stderr);
    6222               0 :             FileEscapedString(stderr, fun->atom, 0);
    6223                 :         } else {
    6224               0 :             fputs("<unnamed function", stderr);
    6225                 :         }
    6226               0 :         if (fun->isInterpreted()) {
    6227               0 :             JSScript *script = fun->script();
    6228                 :             fprintf(stderr, " (%s:%u)",
    6229               0 :                     script->filename ? script->filename : "", script->lineno);
    6230                 :         }
    6231               0 :         fprintf(stderr, " at %p>", (void *) fun);
    6232               0 :     } else if (v.isObject()) {
    6233               0 :         JSObject *obj = &v.toObject();
    6234               0 :         Class *clasp = obj->getClass();
    6235                 :         fprintf(stderr, "<%s%s at %p>",
    6236                 :                 clasp->name,
    6237                 :                 (clasp == &ObjectClass) ? "" : " object",
    6238               0 :                 (void *) obj);
    6239               0 :     } else if (v.isBoolean()) {
    6240               0 :         if (v.toBoolean())
    6241               0 :             fprintf(stderr, "true");
    6242                 :         else
    6243               0 :             fprintf(stderr, "false");
    6244               0 :     } else if (v.isMagic()) {
    6245               0 :         fprintf(stderr, "<invalid");
    6246                 : #ifdef DEBUG
    6247               0 :         switch (v.whyMagic()) {
    6248               0 :           case JS_ARRAY_HOLE:        fprintf(stderr, " array hole");         break;
    6249               0 :           case JS_ARGS_HOLE:         fprintf(stderr, " args hole");          break;
    6250               0 :           case JS_NATIVE_ENUMERATE:  fprintf(stderr, " native enumeration"); break;
    6251               0 :           case JS_NO_ITER_VALUE:     fprintf(stderr, " no iter value");      break;
    6252               0 :           case JS_GENERATOR_CLOSING: fprintf(stderr, " generator closing");  break;
    6253               0 :           default:                   fprintf(stderr, " ?!");                 break;
    6254                 :         }
    6255                 : #endif
    6256               0 :         fprintf(stderr, ">");
    6257                 :     } else {
    6258               0 :         fprintf(stderr, "unexpected value");
    6259                 :     }
    6260               0 : }
    6261                 : 
    6262                 : JS_FRIEND_API(void)
    6263               0 : js_DumpValue(const Value &val)
    6264                 : {
    6265               0 :     dumpValue(val);
    6266               0 :     fputc('\n', stderr);
    6267               0 : }
    6268                 : 
    6269                 : JS_FRIEND_API(void)
    6270               0 : js_DumpId(jsid id)
    6271                 : {
    6272               0 :     fprintf(stderr, "jsid %p = ", (void *) JSID_BITS(id));
    6273               0 :     dumpValue(IdToValue(id));
    6274               0 :     fputc('\n', stderr);
    6275               0 : }
    6276                 : 
    6277                 : static void
    6278               0 : DumpProperty(JSObject *obj, const Shape &shape)
    6279                 : {
    6280               0 :     jsid id = shape.propid();
    6281               0 :     uint8_t attrs = shape.attributes();
    6282                 : 
    6283               0 :     fprintf(stderr, "    ((Shape *) %p) ", (void *) &shape);
    6284               0 :     if (attrs & JSPROP_ENUMERATE) fprintf(stderr, "enumerate ");
    6285               0 :     if (attrs & JSPROP_READONLY) fprintf(stderr, "readonly ");
    6286               0 :     if (attrs & JSPROP_PERMANENT) fprintf(stderr, "permanent ");
    6287               0 :     if (attrs & JSPROP_SHARED) fprintf(stderr, "shared ");
    6288               0 :     if (shape.isMethod()) fprintf(stderr, "method ");
    6289                 : 
    6290               0 :     if (shape.hasGetterValue())
    6291               0 :         fprintf(stderr, "getterValue=%p ", (void *) shape.getterObject());
    6292               0 :     else if (!shape.hasDefaultGetter())
    6293               0 :         fprintf(stderr, "getterOp=%p ", JS_FUNC_TO_DATA_PTR(void *, shape.getterOp()));
    6294                 : 
    6295               0 :     if (shape.hasSetterValue())
    6296               0 :         fprintf(stderr, "setterValue=%p ", (void *) shape.setterObject());
    6297               0 :     else if (!shape.hasDefaultSetter())
    6298               0 :         fprintf(stderr, "setterOp=%p ", JS_FUNC_TO_DATA_PTR(void *, shape.setterOp()));
    6299                 : 
    6300               0 :     if (JSID_IS_ATOM(id))
    6301               0 :         JSID_TO_STRING(id)->dump();
    6302               0 :     else if (JSID_IS_INT(id))
    6303               0 :         fprintf(stderr, "%d", (int) JSID_TO_INT(id));
    6304                 :     else
    6305               0 :         fprintf(stderr, "unknown jsid %p", (void *) JSID_BITS(id));
    6306                 : 
    6307               0 :     uint32_t slot = shape.hasSlot() ? shape.maybeSlot() : SHAPE_INVALID_SLOT;
    6308               0 :     fprintf(stderr, ": slot %d", slot);
    6309               0 :     if (shape.hasSlot()) {
    6310               0 :         fprintf(stderr, " = ");
    6311               0 :         dumpValue(obj->getSlot(slot));
    6312               0 :     } else if (slot != SHAPE_INVALID_SLOT) {
    6313               0 :         fprintf(stderr, " (INVALID!)");
    6314                 :     }
    6315               0 :     fprintf(stderr, "\n");
    6316               0 : }
    6317                 : 
    6318                 : void
    6319               0 : JSObject::dump()
    6320                 : {
    6321               0 :     JSObject *obj = this;
    6322               0 :     fprintf(stderr, "object %p\n", (void *) obj);
    6323               0 :     Class *clasp = obj->getClass();
    6324               0 :     fprintf(stderr, "class %p %s\n", (void *)clasp, clasp->name);
    6325                 : 
    6326               0 :     fprintf(stderr, "flags:");
    6327               0 :     if (obj->isDelegate()) fprintf(stderr, " delegate");
    6328               0 :     if (obj->isSystem()) fprintf(stderr, " system");
    6329               0 :     if (!obj->isExtensible()) fprintf(stderr, " not_extensible");
    6330               0 :     if (obj->isIndexed()) fprintf(stderr, " indexed");
    6331                 : 
    6332               0 :     if (obj->isNative()) {
    6333               0 :         if (obj->inDictionaryMode())
    6334               0 :             fprintf(stderr, " inDictionaryMode");
    6335               0 :         if (obj->hasPropertyTable())
    6336               0 :             fprintf(stderr, " hasPropertyTable");
    6337                 :     }
    6338               0 :     fprintf(stderr, "\n");
    6339                 : 
    6340               0 :     if (obj->isDenseArray()) {
    6341               0 :         unsigned slots = obj->getDenseArrayInitializedLength();
    6342               0 :         fprintf(stderr, "elements\n");
    6343               0 :         for (unsigned i = 0; i < slots; i++) {
    6344               0 :             fprintf(stderr, " %3d: ", i);
    6345               0 :             dumpValue(obj->getDenseArrayElement(i));
    6346               0 :             fprintf(stderr, "\n");
    6347               0 :             fflush(stderr);
    6348                 :         }
    6349               0 :         return;
    6350                 :     }
    6351                 : 
    6352               0 :     fprintf(stderr, "proto ");
    6353               0 :     dumpValue(ObjectOrNullValue(obj->getProto()));
    6354               0 :     fputc('\n', stderr);
    6355                 : 
    6356               0 :     fprintf(stderr, "parent ");
    6357               0 :     dumpValue(ObjectOrNullValue(obj->getParent()));
    6358               0 :     fputc('\n', stderr);
    6359                 : 
    6360               0 :     if (clasp->flags & JSCLASS_HAS_PRIVATE)
    6361               0 :         fprintf(stderr, "private %p\n", obj->getPrivate());
    6362                 : 
    6363               0 :     if (!obj->isNative())
    6364               0 :         fprintf(stderr, "not native\n");
    6365                 : 
    6366               0 :     unsigned reservedEnd = JSCLASS_RESERVED_SLOTS(clasp);
    6367               0 :     unsigned slots = obj->slotSpan();
    6368               0 :     unsigned stop = obj->isNative() ? reservedEnd : slots;
    6369               0 :     if (stop > 0)
    6370               0 :         fprintf(stderr, obj->isNative() ? "reserved slots:\n" : "slots:\n");
    6371               0 :     for (unsigned i = 0; i < stop; i++) {
    6372               0 :         fprintf(stderr, " %3d ", i);
    6373               0 :         if (i < reservedEnd)
    6374               0 :             fprintf(stderr, "(reserved) ");
    6375               0 :         fprintf(stderr, "= ");
    6376               0 :         dumpValue(obj->getSlot(i));
    6377               0 :         fputc('\n', stderr);
    6378                 :     }
    6379                 : 
    6380               0 :     if (obj->isNative()) {
    6381               0 :         fprintf(stderr, "properties:\n");
    6382               0 :         Vector<const Shape *, 8, SystemAllocPolicy> props;
    6383               0 :         for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront())
    6384               0 :             props.append(&r.front());
    6385               0 :         for (size_t i = props.length(); i-- != 0;)
    6386               0 :             DumpProperty(obj, *props[i]);
    6387                 :     }
    6388               0 :     fputc('\n', stderr);
    6389                 : }
    6390                 : 
    6391                 : static void
    6392               0 : MaybeDumpObject(const char *name, JSObject *obj)
    6393                 : {
    6394               0 :     if (obj) {
    6395               0 :         fprintf(stderr, "  %s: ", name);
    6396               0 :         dumpValue(ObjectValue(*obj));
    6397               0 :         fputc('\n', stderr);
    6398                 :     }
    6399               0 : }
    6400                 : 
    6401                 : static void
    6402               0 : MaybeDumpValue(const char *name, const Value &v)
    6403                 : {
    6404               0 :     if (!v.isNull()) {
    6405               0 :         fprintf(stderr, "  %s: ", name);
    6406               0 :         dumpValue(v);
    6407               0 :         fputc('\n', stderr);
    6408                 :     }
    6409               0 : }
    6410                 : 
    6411                 : JS_FRIEND_API(void)
    6412               0 : js_DumpStackFrame(JSContext *cx, StackFrame *start)
    6413                 : {
    6414                 :     /* This should only called during live debugging. */
    6415               0 :     FrameRegsIter i(cx, StackIter::GO_THROUGH_SAVED);
    6416               0 :     if (!start) {
    6417               0 :         if (i.done()) {
    6418               0 :             fprintf(stderr, "no stack for cx = %p\n", (void*) cx);
    6419               0 :             return;
    6420                 :         }
    6421                 :     } else {
    6422               0 :         while (!i.done() && i.fp() != start)
    6423               0 :             ++i;
    6424                 : 
    6425               0 :         if (i.done()) {
    6426                 :             fprintf(stderr, "fp = %p not found in cx = %p\n",
    6427               0 :                     (void *)start, (void *)cx);
    6428               0 :             return;
    6429                 :         }
    6430                 :     }
    6431                 : 
    6432               0 :     for (; !i.done(); ++i) {
    6433               0 :         StackFrame *const fp = i.fp();
    6434                 : 
    6435               0 :         fprintf(stderr, "StackFrame at %p\n", (void *) fp);
    6436               0 :         if (fp->isFunctionFrame()) {
    6437               0 :             fprintf(stderr, "callee fun: ");
    6438               0 :             dumpValue(ObjectValue(fp->callee()));
    6439                 :         } else {
    6440               0 :             fprintf(stderr, "global frame, no callee");
    6441                 :         }
    6442               0 :         fputc('\n', stderr);
    6443                 : 
    6444               0 :         if (fp->isScriptFrame()) {
    6445                 :             fprintf(stderr, "file %s line %u\n",
    6446               0 :                     fp->script()->filename, (unsigned) fp->script()->lineno);
    6447                 :         }
    6448                 : 
    6449               0 :         if (jsbytecode *pc = i.pc()) {
    6450               0 :             if (!fp->isScriptFrame()) {
    6451               0 :                 fprintf(stderr, "*** pc && !script, skipping frame\n\n");
    6452               0 :                 continue;
    6453                 :             }
    6454               0 :             fprintf(stderr, "  pc = %p\n", pc);
    6455               0 :             fprintf(stderr, "  current op: %s\n", js_CodeName[*pc]);
    6456                 :         }
    6457               0 :         Value *sp = i.sp();
    6458               0 :         fprintf(stderr, "  slots: %p\n", (void *) fp->slots());
    6459               0 :         fprintf(stderr, "  sp:    %p = slots + %u\n", (void *) sp, (unsigned) (sp - fp->slots()));
    6460               0 :         if (sp - fp->slots() < 10000) { // sanity
    6461               0 :             for (Value *p = fp->slots(); p < sp; p++) {
    6462               0 :                 fprintf(stderr, "    %p: ", (void *) p);
    6463               0 :                 dumpValue(*p);
    6464               0 :                 fputc('\n', stderr);
    6465                 :             }
    6466                 :         }
    6467               0 :         if (fp->hasArgs()) {
    6468               0 :             fprintf(stderr, "  actuals: %p (%u) ", (void *) fp->actualArgs(), (unsigned) fp->numActualArgs());
    6469               0 :             fprintf(stderr, "  formals: %p (%u)\n", (void *) fp->formalArgs(), (unsigned) fp->numFormalArgs());
    6470                 :         }
    6471               0 :         if (fp->hasCallObj()) {
    6472               0 :             fprintf(stderr, "  has call obj: ");
    6473               0 :             dumpValue(ObjectValue(fp->callObj()));
    6474               0 :             fprintf(stderr, "\n");
    6475                 :         }
    6476               0 :         MaybeDumpObject("argsobj", fp->maybeArgsObj());
    6477               0 :         MaybeDumpObject("blockChain", fp->maybeBlockChain());
    6478               0 :         if (!fp->isDummyFrame()) {
    6479               0 :             MaybeDumpValue("this", fp->thisValue());
    6480               0 :             fprintf(stderr, "  rval: ");
    6481               0 :             dumpValue(fp->returnValue());
    6482                 :         } else {
    6483               0 :             fprintf(stderr, "dummy frame");
    6484                 :         }
    6485               0 :         fputc('\n', stderr);
    6486                 : 
    6487               0 :         fprintf(stderr, "  flags:");
    6488               0 :         if (fp->isConstructing())
    6489               0 :             fprintf(stderr, " constructing");
    6490               0 :         if (fp->isDebuggerFrame())
    6491               0 :             fprintf(stderr, " debugger");
    6492               0 :         if (fp->isEvalFrame())
    6493               0 :             fprintf(stderr, " eval");
    6494               0 :         if (fp->isYielding())
    6495               0 :             fprintf(stderr, " yielding");
    6496               0 :         if (fp->isGeneratorFrame())
    6497               0 :             fprintf(stderr, " generator");
    6498               0 :         fputc('\n', stderr);
    6499                 : 
    6500               0 :         fprintf(stderr, "  scopeChain: (JSObject *) %p\n", (void *) &fp->scopeChain());
    6501                 : 
    6502               0 :         fputc('\n', stderr);
    6503                 :     }
    6504                 : }
    6505                 : 
    6506                 : #endif /* DEBUG */
    6507                 : 

Generated by: LCOV version 1.7