LCOV - app.info - js/src/jsobj.cpp

LCOV - code coverage report
| Current view: | directory - js/src - jsobj.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 3092 | 2156 | 69.7 %
| Date: | 2012-04-21 | Functions: | 198 | 176 | 88.9 %

           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         7545741 : JS_ObjectToInnerObject(JSContext *cx, JSObject *obj)
         127                 : {
         128         7545741 :     if (!obj) {
         129               0 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
         130               0 :         return NULL;
         131                 :     }
         132         7545741 :     OBJ_TO_INNER_OBJECT(cx, obj);
         133         7545741 :     return obj;
         134                 : }
         135                 :
         136                 : JS_FRIEND_API(JSObject *)
         137         4107656 : JS_ObjectToOuterObject(JSContext *cx, JSObject *obj)
         138                 : {
         139         4107656 :     OBJ_TO_OUTER_OBJECT(cx, obj);
         140         4107656 :     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           15061 : obj_setProto(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
         169                 : {
         170           15061 :     if (!cx->runningWithTrustedPrincipals())
         171             855 :         ++sSetProtoCalled;
         172                 :
         173                 :     /* ECMAScript 5 8.6.2 forbids changing [[Prototype]] if not [[Extensible]]. */
         174           15061 :     if (!obj->isExtensible()) {
         175               0 :         obj->reportNotExtensible(cx);
         176               0 :         return false;
         177                 :     }
         178                 :
         179           15061 :     if (!vp->isObjectOrNull())
         180             144 :         return true;
         181                 :
         182           14917 :     JSObject *pobj = vp->toObjectOrNull();
         183                 :     unsigned attrs;
         184           14917 :     id = ATOM_TO_JSID(cx->runtime->atomState.protoAtom);
         185           14917 :     if (!CheckAccess(cx, obj, id, JSAccessMode(JSACC_PROTO|JSACC_WRITE), vp, &attrs))
         186               0 :         return false;
         187                 :
         188           14917 :     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           49469 : obj_toStringHelper(JSContext *cx, JSObject *obj)
         634                 : {
         635           49469 :     if (obj->isProxy())
         636            1948 :         return Proxy::obj_toString(cx, obj);
         637                 :
         638           95042 :     StringBuffer sb(cx);
         639           47521 :     const char *className = obj->getClass()->name;
         640           95042 :     if (!sb.append("[object ") || !sb.appendInflated(className, strlen(className)) ||
         641           47521 :         !sb.append("]"))
         642                 :     {
         643               0 :         return NULL;
         644                 :     }
         645           47521 :     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           47525 : obj_toString(JSContext *cx, unsigned argc, Value *vp)
         681                 : {
         682           47525 :     Value &thisv = vp[1];
         683                 :
         684                 :     /* Step 1. */
         685           47525 :     if (thisv.isUndefined()) {
         686               0 :         vp->setString(cx->runtime->atomState.objectUndefinedAtom);
         687               0 :         return true;
         688                 :     }
         689                 :
         690                 :     /* Step 2. */
         691           47525 :     if (thisv.isNull()) {
         692               0 :         vp->setString(cx->runtime->atomState.objectNullAtom);
         693               0 :         return true;
         694                 :     }
         695                 :
         696                 :     /* Step 3. */
         697           47525 :     JSObject *obj = ToObject(cx, &thisv);
         698           47525 :     if (!obj)
         699               0 :         return false;
         700                 :
         701                 :     /* Steps 4-5. */
         702           47525 :     JSString *str = js::obj_toStringHelper(cx, obj);
         703           47525 :     if (!str)
         704               0 :         return false;
         705           47525 :     vp->setString(str);
         706           47525 :     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          370536 : obj_valueOf(JSContext *cx, unsigned argc, Value *vp)
         726                 : {
         727          370536 :     JSObject *obj = ToObject(cx, &vp[1]);
         728          370536 :     if (!obj)
         729               0 :         return false;
         730          370536 :     vp->setObject(*obj);
         731          370536 :     return true;
         732                 : }
         733                 :
         734                 : /* We should be able to assert this for *any* fp->scopeChain(). */
         735                 : static void
         736           97710 : AssertInnerizedScopeChain(JSContext *cx, JSObject &scopeobj)
         737                 : {
         738                 : #ifdef DEBUG
         739          297642 :     for (JSObject *o = &scopeobj; o; o = o->enclosingScope()) {
         740          199932 :         if (JSObjectOp op = o->getClass()->ext.innerObject)
         741               0 :             JS_ASSERT(op(cx, o) == o);
         742                 :     }
         743                 : #endif
         744           97710 : }
         745                 :
         746                 : #ifndef EVAL_CACHE_CHAIN_LIMIT
         747                 : # define EVAL_CACHE_CHAIN_LIMIT 4
         748                 : #endif
         749                 :
         750                 : static inline JSScript **
         751           92896 : EvalCacheHash(JSContext *cx, JSLinearString *str)
         752                 : {
         753           92896 :     const jschar *s = str->chars();
         754           92896 :     size_t n = str->length();
         755                 :
         756           92896 :     if (n > 100)
         757            5773 :         n = 100;
         758                 :     uint32_t h;
         759         1762954 :     for (h = 0; n; s++, n--)
         760         1670058 :         h = JS_ROTATE_LEFT32(h, 4) ^ *s;
         761                 :
         762           92896 :     h *= JS_GOLDEN_RATIO;
         763           92896 :     h >>= 32 - JS_EVAL_CACHE_SHIFT;
         764           92896 :     return &cx->compartment->evalCache[h];
         765                 : }
         766                 :
         767                 : static JS_ALWAYS_INLINE JSScript *
         768           78062 : 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           78062 :     unsigned count = 0;
         788           78062 :     JSScript **scriptp = bucket;
         789                 :
         790           78062 :     JSVersion version = cx->findVersion();
         791                 :     JSScript *script;
         792           78062 :     JSSubsumePrincipalsOp subsume = cx->runtime->securityCallbacks->subsumePrincipals;
         793          204992 :     while ((script = *scriptp) != NULL) {
         794          353644 :         if (script->savedCallerFun &&
         795                 :             script->staticLevel == staticLevel &&
         796          117476 :             script->getVersion() == version &&
         797          117476 :             !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           98742 :             JSFunction *fun = script->getCallerFunction();
         806                 :
         807           98742 :             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           96770 :                 JSAtom *src = script->atoms[0];
         813                 :
         814           96770 :                 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           69185 :                     JS_ASSERT(script->objects()->length >= 1);
         822          127929 :                     if (script->objects()->length == 1 &&
         823           58744 :                         !JSScript::isValidOffset(script->regexpsOffset)) {
         824           58744 :                         JS_ASSERT(staticLevel == script->staticLevel);
         825           58744 :                         *scriptp = script->evalHashLink();
         826           58744 :                         script->evalHashLink() = NULL;
         827           58744 :                         return script;
         828                 :                     }
         829                 :                 }
         830                 :             }
         831                 :         }
         832                 :
         833           59948 :         if (++count == EVAL_CACHE_CHAIN_LIMIT)
         834           11080 :             return NULL;
         835           48868 :         scriptp = &script->evalHashLink();
         836                 :     }
         837            8238 :     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           92896 :     EvalScriptGuard(JSContext *cx, JSLinearString *str)
         860                 :       : cx_(cx),
         861                 :         str_(str),
         862           92896 :         script_(NULL) {
         863           92896 :         bucket_ = EvalCacheHash(cx, str);
         864           92896 :     }
         865                 :
         866           92896 :     ~EvalScriptGuard() {
         867           92896 :         if (script_) {
         868           92671 :             js_CallDestroyScriptHook(cx_, script_);
         869           92671 :             script_->isActiveEval = false;
         870           92671 :             script_->isCachedEval = true;
         871           92671 :             script_->evalHashLink() = *bucket_;
         872           92671 :             *bucket_ = script_;
         873                 :         }
         874           92896 :     }
         875                 :
         876           78062 :     void lookupInEvalCache(StackFrame *caller, unsigned staticLevel,
         877                 :                            JSPrincipals *principals, JSObject &scopeobj) {
         878           78062 :         if (JSScript *found = EvalCacheLookup(cx_, str_, caller, staticLevel,
         879           78062 :                                               principals, scopeobj, bucket_)) {
         880           58744 :             js_CallNewScriptHook(cx_, found, NULL);
         881           58744 :             script_ = found;
         882           58744 :             script_->isCachedEval = false;
         883           58744 :             script_->isActiveEval = true;
         884                 :         }
         885           78062 :     }
         886                 :
         887           33927 :     void setNewScript(JSScript *script) {
         888                 :         /* NewScriptFromEmitter has already called js_CallNewScriptHook. */
         889           33927 :         JS_ASSERT(!script_ && script);
         890           33927 :         script_ = script;
         891           33927 :         script_->isActiveEval = true;
         892           33927 :     }
         893                 :
         894           92896 :     bool foundScript() {
         895           92896 :         return !!script_;
         896                 :     }
         897                 :
         898           92671 :     JSScript *script() const {
         899           92671 :         JS_ASSERT(script_);
         900           92671 :         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           97710 : EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, StackFrame *caller,
         919                 :            JSObject &scopeobj)
         920                 : {
         921           97710 :     JS_ASSERT((evalType == INDIRECT_EVAL) == (caller == NULL));
         922           97710 :     AssertInnerizedScopeChain(cx, scopeobj);
         923                 :
         924           97710 :     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           97710 :     if (args.length() < 1) {
         931            2564 :         args.rval().setUndefined();
         932            2564 :         return true;
         933                 :     }
         934           95146 :     if (!args[0].isString()) {
         935             225 :         args.rval() = args[0];
         936             225 :         return true;
         937                 :     }
         938           94921 :     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           94921 :     if (evalType == DIRECT_EVAL) {
         950           81083 :         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           81083 :         if (!ComputeThis(cx, caller))
         958               0 :             return false;
         959           81083 :         thisv = caller->thisValue();
         960                 :
         961                 : #ifdef DEBUG
         962           81083 :         jsbytecode *callerPC = caller->pcQuadratic(cx);
         963           81083 :         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           94921 :     JSLinearString *linearStr = str->ensureLinear(cx);
         977           94921 :     if (!linearStr)
         978               0 :         return false;
         979           94921 :     const jschar *chars = linearStr->chars();
         980           94921 :     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          297157 :     if (length > 2 &&
         994           97460 :         ((chars[0] == '[' && chars[length - 1] == ']') ||
         995           99949 :         (chars[0] == '(' && chars[length - 1] == ')')) &&
         996            4827 :          (!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         1681347 :         for (const jschar *cp = &chars[1], *end = &chars[length - 2]; ; cp++) {
        1007         1681347 :             if (*cp == 0x2028 || *cp == 0x2029)
        1008               0 :                 break;
        1009                 :
        1010         1681347 :             if (cp == end) {
        1011            4979 :                 bool isArray = (chars[0] == '[');
        1012                 :                 JSONParser parser(cx, isArray ? chars : chars + 1, isArray ? length : length - 2,
        1013            4979 :                                   JSONParser::StrictJSON, JSONParser::NoError);
        1014                 :                 Value tmp;
        1015            4979 :                 if (!parser.parse(&tmp))
        1016               0 :                     return false;
        1017            4979 :                 if (tmp.isUndefined())
        1018            2954 :                     break;
        1019            2025 :                 args.rval() = tmp;
        1020            2025 :                 return true;
        1021                 :             }
        1022                 :         }
        1023                 :     }
        1024                 :
        1025          185792 :     EvalScriptGuard esg(cx, linearStr);
        1026                 :
        1027           92896 :     JSPrincipals *principals = PrincipalsForCompiledCode(args, cx);
        1028                 :
        1029           92896 :     if (evalType == DIRECT_EVAL && caller->isNonEvalFunctionFrame())
        1030           78062 :         esg.lookupInEvalCache(caller, staticLevel, principals, scopeobj);
        1031                 :
        1032           92896 :     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           34152 :                                                             : NOT_CALLED_FROM_JSOP_EVAL);
        1039           34152 :         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           34152 :                                                      staticLevel);
        1045           34152 :         if (!compiled)
        1046             225 :             return false;
        1047                 :
        1048           33927 :         esg.setNewScript(compiled);
        1049                 :     }
        1050                 :
        1051                 :     return ExecuteKernel(cx, esg.script(), scopeobj, thisv, ExecuteType(evalType),
        1052           92671 :                          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           97710 : WarnOnTooManyArgs(JSContext *cx, const CallArgs &args)
        1062                 : {
        1063           97710 :     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           97710 :     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           83872 : DirectEval(JSContext *cx, const CallArgs &args)
        1101                 : {
        1102                 :     /* Direct eval can assume it was called from an interpreted frame. */
        1103           83872 :     StackFrame *caller = cx->fp();
        1104           83872 :     JS_ASSERT(caller->isScriptFrame());
        1105           83872 :     JS_ASSERT(IsBuiltinEvalForScope(&caller->scopeChain(), args.calleev()));
        1106           83872 :     JS_ASSERT(JSOp(*cx->regs().pc) == JSOP_EVAL);
        1107                 :
        1108          167744 :     AutoFunctionCallProbe callProbe(cx, args.callee().toFunction(), caller->script());
        1109                 :
        1110           83872 :     JSObject *scopeChain = GetScopeChain(cx, caller);
        1111           83872 :     if (!scopeChain)
        1112               0 :         return false;
        1113                 :
        1114           83872 :     if (!WarnOnTooManyArgs(cx, args))
        1115               0 :         return false;
        1116                 :
        1117           83872 :     return EvalKernel(cx, args, DIRECT_EVAL, caller, *scopeChain);
        1118                 : }
        1119                 :
        1120                 : bool
        1121          167771 : IsBuiltinEvalForScope(JSObject *scopeChain, const Value &v)
        1122                 : {
        1123          167771 :     return scopeChain->global().getOriginalEval() == v;
        1124                 : }
        1125                 :
        1126                 : bool
        1127          103350 : IsAnyBuiltinEval(JSFunction *fun)
        1128                 : {
        1129          103350 :     return fun->maybeNative() == eval;
        1130                 : }
        1131                 :
        1132                 : JSPrincipals *
        1133          103310 : PrincipalsForCompiledCode(const CallReceiver &call, JSContext *cx)
        1134                 : {
        1135          113724 :     JS_ASSERT(IsAnyBuiltinEval(call.callee().toFunction()) ||
        1136          113724 :               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          103310 :     return call.callee().principals(cx);
        1155                 : }
        1156                 :
        1157                 : }  /* namespace js */
        1158                 :
        1159                 : #if JS_HAS_OBJ_WATCHPOINT
        1160                 :
        1161                 : static JSBool
        1162            3785 : obj_watch_handler(JSContext *cx, JSObject *obj, jsid id, jsval old,
        1163                 :                   jsval *nvp, void *closure)
        1164                 : {
        1165            3785 :     JSObject *callable = (JSObject *) closure;
        1166            3785 :     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            7570 :     AutoResolving resolving(cx, obj, id, AutoResolving::WATCH);
        1181            3785 :     if (resolving.alreadyStarted())
        1182               0 :         return true;
        1183                 :
        1184            3785 :     Value argv[] = { IdToValue(id), old, *nvp };
        1185            3785 :     return Invoke(cx, ObjectValue(*obj), ObjectOrNullValue(callable), ArrayLength(argv), argv, nvp);
        1186                 : }
        1187                 :
        1188                 : static JSBool
        1189            3641 : obj_watch(JSContext *cx, unsigned argc, Value *vp)
        1190                 : {
        1191            3641 :     if (argc <= 1) {
        1192               0 :         js_ReportMissingArg(cx, *vp, 1);
        1193               0 :         return false;
        1194                 :     }
        1195                 :
        1196            3641 :     JSObject *callable = js_ValueToCallableObject(cx, &vp[3], 0);
        1197            3641 :     if (!callable)
        1198               9 :         return false;
        1199                 :
        1200                 :     jsid propid;
        1201            3632 :     if (!ValueToId(cx, vp[2], &propid))
        1202               0 :         return false;
        1203                 :
        1204            3632 :     JSObject *obj = ToObject(cx, &vp[1]);
        1205            3632 :     if (!obj)
        1206               0 :         return false;
        1207                 :
        1208                 :     Value tmp;
        1209                 :     unsigned attrs;
        1210            3632 :     if (!CheckAccess(cx, obj, propid, JSACC_WATCH, &tmp, &attrs))
        1211               0 :         return false;
        1212                 :
        1213            3632 :     vp->setUndefined();
        1214                 :
        1215            3632 :     if (obj->isDenseArray() && !obj->makeDenseArraySlow(cx))
        1216               0 :         return false;
        1217            3632 :     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          699813 : js_HasOwnProperty(JSContext *cx, LookupGenericOp lookup, JSObject *obj, jsid id,
        1282                 :                   JSObject **objp, JSProperty **propp)
        1283                 : {
        1284         1399626 :     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING);
        1285          699813 :     if (!(lookup ? lookup : js_LookupProperty)(cx, obj, id, objp, propp))
        1286               0 :         return false;
        1287          699813 :     if (!*propp)
        1288          577638 :         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          297383 : DefineAccessor(JSContext *cx, unsigned argc, Value *vp)
        1385                 : {
        1386          297383 :     CallArgs args = CallArgsFromVp(argc, vp);
        1387          297383 :     if (!BoxNonStrictThis(cx, args))
        1388               0 :         return false;
        1389                 :
        1390          297383 :     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          297374 :     if (!ValueToId(cx, args[0], &id))
        1399               0 :         return false;
        1400                 :
        1401          297374 :     JSObject *descObj = NewBuiltinClassInstance(cx, &ObjectClass);
        1402          297374 :     if (!descObj)
        1403               0 :         return false;
        1404                 :
        1405          297374 :     JSAtomState &state = cx->runtime->atomState;
        1406                 :     /* enumerable: true */
        1407          297374 :     if (!descObj->defineProperty(cx, state.enumerableAtom, BooleanValue(true)))
        1408               0 :         return false;
        1409                 :
        1410                 :     /* configurable: true */
        1411          297374 :     if (!descObj->defineProperty(cx, state.configurableAtom, BooleanValue(true)))
        1412               0 :         return false;
        1413                 :
        1414                 :     /* enumerable: true */
        1415          297374 :     PropertyName *acc = (Type == Getter) ? state.getAtom : state.setAtom;
        1416          297374 :     if (!descObj->defineProperty(cx, acc, args[1]))
        1417               0 :         return false;
        1418                 :
        1419                 :     JSBool dummy;
        1420          297374 :     if (!js_DefineOwnProperty(cx, &args.thisv().toObject(), id, ObjectValue(*descObj), &dummy))
        1421               0 :         return false;
        1422          297374 :     args.rval().setUndefined();
        1423          297374 :     return true;
        1424                 : }
        1425                 :
        1426                 : JS_FRIEND_API(JSBool)
        1427          280851 : js::obj_defineGetter(JSContext *cx, unsigned argc, Value *vp)
        1428                 : {
        1429          280851 :     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           14432 : NewPropertyDescriptorObject(JSContext *cx, const PropertyDescriptor *desc, Value *vp)
        1515                 : {
        1516           14432 :     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           13992 :     PropDesc d;
        1523           13992 :     d.initFromPropertyDescriptor(*desc);
        1524           13992 :     if (!d.makeObject(cx))
        1525               0 :         return false;
        1526           13992 :     *vp = d.pd;
        1527           13992 :     return true;
        1528                 : }
        1529                 :
        1530                 : void
        1531           13992 : PropDesc::initFromPropertyDescriptor(const PropertyDescriptor &desc)
        1532                 : {
        1533           13992 :     pd.setUndefined();
        1534           13992 :     attrs = uint8_t(desc.attrs);
        1535           13992 :     JS_ASSERT_IF(attrs & JSPROP_READONLY, !(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
        1536           13992 :     if (desc.attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
        1537            2346 :         hasGet = true;
        1538                 :         get = ((desc.attrs & JSPROP_GETTER) && desc.getter)
        1539            2337 :               ? CastAsObjectJsval(desc.getter)
        1540            4683 :               : UndefinedValue();
        1541            2346 :         hasSet = true;
        1542                 :         set = ((desc.attrs & JSPROP_SETTER) && desc.setter)
        1543              63 :               ? CastAsObjectJsval(desc.setter)
        1544            2409 :               : UndefinedValue();
        1545            2346 :         hasValue = false;
        1546            2346 :         value.setUndefined();
        1547            2346 :         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           13992 :     hasEnumerable = true;
        1558           13992 :     hasConfigurable = true;
        1559           13992 : }
        1560                 :
        1561                 : bool
        1562           14001 : PropDesc::makeObject(JSContext *cx)
        1563                 : {
        1564           14001 :     JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass);
        1565           14001 :     if (!obj)
        1566               0 :         return false;
        1567                 :
        1568           14001 :     const JSAtomState &atomState = cx->runtime->atomState;
        1569           70005 :     if ((hasConfigurable &&
        1570                 :          !obj->defineProperty(cx, atomState.configurableAtom,
        1571           14001 :                               BooleanValue((attrs & JSPROP_PERMANENT) == 0))) ||
        1572                 :         (hasEnumerable &&
        1573                 :          !obj->defineProperty(cx, atomState.enumerableAtom,
        1574           14001 :                               BooleanValue((attrs & JSPROP_ENUMERATE) != 0))) ||
        1575                 :         (hasGet &&
        1576            2346 :          !obj->defineProperty(cx, atomState.getAtom, get)) ||
        1577                 :         (hasSet &&
        1578            2346 :          !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           14001 :     pd.setObject(*obj);
        1589           14001 :     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          315009 : GetFirstArgumentAsObject(JSContext *cx, unsigned argc, Value *vp, const char *method, JSObject **objp)
        1642                 : {
        1643          315009 :     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          315009 :     const Value &v = vp[2];
        1650          315009 :     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          314973 :     *objp = &v.toObject();
        1661          314973 :     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         3585438 : HasProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, bool *foundp)
        1715                 : {
        1716         3585438 :     if (!obj->hasProperty(cx, id, foundp, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING))
        1717               0 :         return false;
        1718         3585438 :     if (!*foundp) {
        1719         2087046 :         vp->setUndefined();
        1720         2087046 :         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         1498392 :     return !!obj->getGeneric(cx, id, vp);
        1730                 : }
        1731                 :
        1732          611565 : 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          611565 :     hasConfigurable(false)
        1744                 : {
        1745          611565 : }
        1746                 :
        1747                 : bool
        1748          597573 : PropDesc::initialize(JSContext *cx, const Value &origval, bool checkAccessors)
        1749                 : {
        1750          597573 :     Value v = origval;
        1751                 :
        1752                 :     /* 8.10.5 step 1 */
        1753          597573 :     if (v.isPrimitive()) {
        1754               0 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
        1755               0 :         return false;
        1756                 :     }
        1757          597573 :     JSObject *desc = &v.toObject();
        1758                 :
        1759                 :     /* Make a copy of the descriptor. We might need it later. */
        1760          597573 :     pd = v;
        1761                 :
        1762                 :     /* Start with the proper defaults. */
        1763          597573 :     attrs = JSPROP_PERMANENT | JSPROP_READONLY;
        1764                 :
        1765                 :     bool found;
        1766                 :
        1767                 :     /* 8.10.5 step 3 */
        1768                 : #ifdef __GNUC__ /* quell GCC overwarning */
        1769          597573 :     found = false;
        1770                 : #endif
        1771          597573 :     if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.enumerableAtom), &v, &found))
        1772               0 :         return false;
        1773          597573 :     if (found) {
        1774          596043 :         hasEnumerable = JS_TRUE;
        1775          596043 :         if (js_ValueToBoolean(v))
        1776          592537 :             attrs |= JSPROP_ENUMERATE;
        1777                 :     }
        1778                 :
        1779                 :     /* 8.10.5 step 4 */
        1780          597573 :     if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.configurableAtom), &v, &found))
        1781               0 :         return false;
        1782          597573 :     if (found) {
        1783          301104 :         hasConfigurable = JS_TRUE;
        1784          301104 :         if (js_ValueToBoolean(v))
        1785          297583 :             attrs &= ~JSPROP_PERMANENT;
        1786                 :     }
        1787                 :
        1788                 :     /* 8.10.5 step 5 */
        1789          597573 :     if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.valueAtom), &v, &found))
        1790               0 :         return false;
        1791          597573 :     if (found) {
        1792             858 :         hasValue = true;
        1793             858 :         value = v;
        1794                 :     }
        1795                 :
        1796                 :     /* 8.10.6 step 6 */
        1797          597573 :     if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.writableAtom), &v, &found))
        1798               0 :         return false;
        1799          597573 :     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          597573 :     if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.getAtom), &v, &found))
        1807               0 :         return false;
        1808          597573 :     if (found) {
        1809          579705 :         hasGet = true;
        1810          579705 :         get = v;
        1811          579705 :         attrs |= JSPROP_GETTER | JSPROP_SHARED;
        1812          579705 :         attrs &= ~JSPROP_READONLY;
        1813          579705 :         if (checkAccessors && !checkGetter(cx))
        1814               0 :             return false;
        1815                 :     }
        1816                 :
        1817                 :     /* 8.10.7 step 8 */
        1818          597573 :     if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.setAtom), &v, &found))
        1819               0 :         return false;
        1820          597573 :     if (found) {
        1821           20435 :         hasSet = true;
        1822           20435 :         set = v;
        1823           20435 :         attrs |= JSPROP_SETTER | JSPROP_SHARED;
        1824           20435 :         attrs &= ~JSPROP_READONLY;
        1825           20435 :         if (checkAccessors && !checkSetter(cx))
        1826               0 :             return false;
        1827                 :     }
        1828                 :
        1829                 :     /* 8.10.7 step 9 */
        1830          597573 :     if ((hasGet || hasSet) && (hasValue || hasWritable)) {
        1831               0 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INVALID_DESCRIPTOR);
        1832               0 :         return false;
        1833                 :     }
        1834                 :
        1835          597573 :     JS_ASSERT_IF(attrs & JSPROP_READONLY, !(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
        1836                 :
        1837          597573 :     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          593899 : 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          593899 :     JS_ASSERT(!obj->getOps()->lookupGeneric);
        1885          593899 :     if (!js_HasOwnProperty(cx, NULL, obj, id, &obj2, &current))
        1886               0 :         return JS_FALSE;
        1887                 :
        1888          593899 :     JS_ASSERT(!obj->getOps()->defineProperty);
        1889                 :
        1890                 :     /* 8.12.9 steps 2-4. */
        1891          593899 :     if (!current) {
        1892          576885 :         if (!obj->isExtensible())
        1893               0 :             return Reject(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
        1894                 :
        1895          576885 :         *rval = true;
        1896                 :
        1897          576885 :         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          576348 :         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          576348 :         if (!CheckAccess(cx, obj, id, JSACC_WATCH, &dummy, &dummyAttrs))
        1912               0 :             return JS_FALSE;
        1913                 :
        1914          576348 :         Value tmp = UndefinedValue();
        1915                 :         return js_DefineProperty(cx, obj, id, &tmp,
        1916          576348 :                                  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          595714 : DefineProperty(JSContext *cx, JSObject *obj, const jsid &id, const PropDesc &desc, bool throwError,
        2241                 :                bool *rval)
        2242                 : {
        2243          595714 :     if (obj->isArray())
        2244             241 :         return DefinePropertyOnArray(cx, obj, id, desc, throwError, rval);
        2245                 :
        2246          595473 :     if (obj->getOps()->lookupGeneric) {
        2247            1806 :         if (obj->isProxy())
        2248            1806 :             return Proxy::defineProperty(cx, obj, id, desc.pd);
        2249               0 :         return Reject(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
        2250                 :     }
        2251                 :
        2252          593667 :     return DefinePropertyOnObject(cx, obj, id, desc, throwError, rval);
        2253                 : }
        2254                 :
        2255                 : } /* namespace js */
        2256                 :
        2257                 : JSBool
        2258          595154 : js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, const Value &descriptor, JSBool *bp)
        2259                 : {
        2260         1190308 :     AutoPropDescArrayRooter descs(cx);
        2261          595154 :     PropDesc *desc = descs.append();
        2262          595154 :     if (!desc || !desc->initialize(cx, descriptor))
        2263               0 :         return false;
        2264                 :
        2265                 :     bool rval;
        2266          595154 :     if (!DefineProperty(cx, obj, id, *desc, true, &rval))
        2267            1770 :         return false;
        2268          593384 :     *bp = !!rval;
        2269          593384 :     return true;
        2270                 : }
        2271                 :
        2272                 : /* ES5 15.2.3.6: Object.defineProperty(O, P, Attributes) */
        2273                 : static JSBool
        2274          297807 : obj_defineProperty(JSContext *cx, unsigned argc, Value *vp)
        2275                 : {
        2276                 :     JSObject *obj;
        2277          297807 :     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperty", &obj))
        2278              27 :         return false;
        2279                 :
        2280                 :     jsid id;
        2281          297780 :     if (!ValueToId(cx, argc >= 2 ? vp[3] : UndefinedValue(), &id))
        2282               0 :         return JS_FALSE;
        2283                 :
        2284          297780 :     const Value descval = argc >= 3 ? vp[4] : UndefinedValue();
        2285                 :
        2286                 :     JSBool junk;
        2287          297780 :     if (!js_DefineOwnProperty(cx, obj, id, descval, &junk))
        2288            1770 :         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         3722002 : JSObject::getSealedOrFrozenAttributes(unsigned attrs, ImmutabilityType it)
        2482                 : {
        2483                 :     /* Make all attributes permanent; if freezing, make data attributes read-only. */
        2484         3722002 :     if (it == FREEZE && !(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
        2485         3714248 :         return JSPROP_PERMANENT | JSPROP_READONLY;
        2486            7754 :     return JSPROP_PERMANENT;
        2487                 : }
        2488                 :
        2489                 : bool
        2490         1223466 : JSObject::sealOrFreeze(JSContext *cx, ImmutabilityType it)
        2491                 : {
        2492         1223466 :     assertSameCompartment(cx, this);
        2493         1223466 :     JS_ASSERT(it == SEAL || it == FREEZE);
        2494                 :
        2495         2446932 :     RootedVarObject self(cx, this);
        2496                 :
        2497         2446932 :     AutoIdVector props(cx);
        2498         1223466 :     if (isExtensible()) {
        2499         1223034 :         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         1223466 :     JS_ASSERT(!self->isDenseArray());
        2508                 :
        2509         1223466 :     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         1210241 :         Shape *last = EmptyShape::getInitialShape(cx, self->getClass(),
        2518         1210241 :                                                   self->getProto(),
        2519                 :                                                   self->getParent(),
        2520         1210241 :                                                   self->getAllocKind(),
        2521         4840964 :                                                   self->lastProperty()->getObjectFlags());
        2522         1210241 :         if (!last)
        2523               0 :             return false;
        2524                 :
        2525                 :         /* Get an in order list of the shapes in this object. */
        2526         2420482 :         AutoShapeVector shapes(cx);
        2527         4852444 :         for (Shape::Range r = self->lastProperty()->all(); !r.empty(); r.popFront()) {
        2528         3642203 :             if (!shapes.append(&r.front()))
        2529               0 :                 return false;
        2530                 :         }
        2531         1210241 :         Reverse(shapes.begin(), shapes.end());
        2532                 :
        2533         4852444 :         for (size_t i = 0; i < shapes.length(); i++) {
        2534         3642203 :             StackShape child(shapes[i]);
        2535         3642203 :             child.attrs |= getSealedOrFrozenAttributes(child.attrs, it);
        2536                 :
        2537         3642203 :             if (!JSID_IS_EMPTY(child.propid))
        2538         3642203 :                 MarkTypePropertyConfigured(cx, self, child.propid);
        2539                 :
        2540         3642203 :             last = JS_PROPERTY_TREE(cx).getChild(cx, last, self->numFixedSlots(), child);
        2541         3642203 :             if (!last)
        2542               0 :                 return NULL;
        2543                 :         }
        2544                 :
        2545         1210241 :         JS_ASSERT(self->lastProperty()->slotSpan() == last->slotSpan());
        2546         1210241 :         JS_ALWAYS_TRUE(setLastProperty(cx, last));
        2547                 :     } else {
        2548           93024 :         for (size_t i = 0; i < props.length(); i++) {
        2549           79799 :             jsid id = props[i];
        2550                 :
        2551                 :             unsigned attrs;
        2552           79799 :             if (!self->getGenericAttributes(cx, id, &attrs))
        2553               0 :                 return false;
        2554                 :
        2555           79799 :             unsigned new_attrs = getSealedOrFrozenAttributes(attrs, it);
        2556                 :
        2557                 :             /* If we already have the attributes we need, skip the setAttributes call. */
        2558           79799 :             if ((attrs | new_attrs) == attrs)
        2559           39210 :                 continue;
        2560                 :
        2561           40589 :             attrs |= new_attrs;
        2562           40589 :             if (!self->setGenericAttributes(cx, id, &attrs))
        2563               0 :                 return false;
        2564                 :         }
        2565                 :     }
        2566                 :
        2567         1223466 :     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         8885269 : NewObject(JSContext *cx, Class *clasp, types::TypeObject *type, JSObject *parent,
        2737                 :           gc::AllocKind kind)
        2738                 : {
        2739         8885269 :     JS_ASSERT(clasp != &ArrayClass);
        2740               0 :     JS_ASSERT_IF(clasp == &FunctionClass,
        2741         8885269 :                  kind == JSFunction::FinalizeKind || kind == JSFunction::ExtendedFinalizeKind);
        2742                 :
        2743        17770538 :     RootTypeObject typeRoot(cx, &type);
        2744                 :
        2745        17770538 :     RootedVarShape shape(cx);
        2746         8885269 :     shape = EmptyShape::getInitialShape(cx, clasp, type->proto, parent, kind);
        2747         8885269 :     if (!shape)
        2748               0 :         return NULL;
        2749                 :
        2750                 :     HeapSlot *slots;
        2751         8885269 :     if (!PreallocateObjectDynamicSlots(cx, shape, &slots))
        2752               0 :         return NULL;
        2753                 :
        2754         8885269 :     JSObject *obj = JSObject::create(cx, kind, shape, typeRoot, slots);
        2755         8885269 :     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         8885269 :     if (clasp->trace && !(clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS))
        2763               0 :         cx->runtime->gcIncrementalEnabled = false;
        2764                 :
        2765         8885269 :     Probes::createObject(cx, obj);
        2766         8885269 :     return obj;
        2767                 : }
        2768                 :
        2769                 : JSObject *
        2770         4306705 : js::NewObjectWithGivenProto(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
        2771                 :                             gc::AllocKind kind)
        2772                 : {
        2773         4306705 :     if (CanBeFinalizedInBackground(kind, clasp))
        2774          876193 :         kind = GetBackgroundAllocKind(kind);
        2775                 :
        2776         4306705 :     NewObjectCache &cache = cx->compartment->newObjectCache;
        2777                 :
        2778         4306705 :     NewObjectCache::EntryIndex entry = -1;
        2779         4306705 :     if (proto && (!parent || parent == proto->getParent()) && !proto->isGlobal()) {
        2780         4045318 :         if (cache.lookupProto(clasp, proto, kind, &entry))
        2781         3270723 :             return cache.newObjectFromHit(cx, entry);
        2782                 :     }
        2783                 :
        2784         2071964 :     RootObject protoRoot(cx, &proto);
        2785         2071964 :     RootObject parentRoot(cx, &parent);
        2786                 :
        2787         1035982 :     types::TypeObject *type = proto ? proto->getNewType(cx) : cx->compartment->getEmptyType(cx);
        2788         1035982 :     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         1035982 :     if (!parent && proto)
        2796           25450 :         parent = proto->getParent();
        2797                 :
        2798         1035982 :     JSObject *obj = NewObject(cx, clasp, type, parent, kind);
        2799         1035982 :     if (!obj)
        2800               0 :         return NULL;
        2801                 :
        2802         1035982 :     if (entry != -1 && !obj->hasDynamicSlots())
        2803          774595 :         cache.fillProto(entry, clasp, proto, kind, obj);
        2804                 :
        2805         1035982 :     return obj;
        2806                 : }
        2807                 :
        2808                 : JSObject *
        2809        31043056 : js::NewObjectWithClassProto(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
        2810                 :                             gc::AllocKind kind)
        2811                 : {
        2812        31043056 :     if (proto)
        2813         3223096 :         return NewObjectWithGivenProto(cx, clasp, proto, parent, kind);
        2814                 :
        2815        27819960 :     if (CanBeFinalizedInBackground(kind, clasp))
        2816         6455732 :         kind = GetBackgroundAllocKind(kind);
        2817                 :
        2818        27819960 :     if (!parent)
        2819        13963334 :         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        27819960 :     JSProtoKey protoKey = GetClassProtoKey(clasp);
        2831                 :
        2832        27819960 :     NewObjectCache &cache = cx->compartment->newObjectCache;
        2833                 :
        2834        27819960 :     NewObjectCache::EntryIndex entry = -1;
        2835        27819960 :     if (parent->isGlobal() && protoKey != JSProto_Null) {
        2836        20454936 :         if (cache.lookupGlobal(clasp, &parent->asGlobal(), kind, &entry))
        2837        20073663 :             return cache.newObjectFromHit(cx, entry);
        2838                 :     }
        2839                 :
        2840        15492594 :     RootObject parentRoot(cx, &parent);
        2841                 :
        2842         7746297 :     if (!FindProto(cx, clasp, parentRoot, &proto))
        2843               0 :         return NULL;
        2844                 :
        2845         7746297 :     types::TypeObject *type = proto->getNewType(cx);
        2846         7746297 :     if (!type)
        2847               0 :         return NULL;
        2848                 :
        2849         7746297 :     JSObject *obj = NewObject(cx, clasp, type, parent, kind);
        2850         7746297 :     if (!obj)
        2851               0 :         return NULL;
        2852                 :
        2853         7746297 :     if (entry != -1 && !obj->hasDynamicSlots())
        2854          381273 :         cache.fillGlobal(entry, clasp, &parent->asGlobal(), kind, obj);
        2855                 :
        2856         7746297 :     return obj;
        2857                 : }
        2858                 :
        2859                 : JSObject *
        2860         2644669 : js::NewObjectWithType(JSContext *cx, types::TypeObject *type, JSObject *parent, gc::AllocKind kind)
        2861                 : {
        2862         2644669 :     JS_ASSERT(type->proto->hasNewType(type));
        2863         2644669 :     JS_ASSERT(parent);
        2864                 :
        2865         2644669 :     if (CanBeFinalizedInBackground(kind, &ObjectClass))
        2866         2644669 :         kind = GetBackgroundAllocKind(kind);
        2867                 :
        2868         2644669 :     NewObjectCache &cache = cx->compartment->newObjectCache;
        2869                 :
        2870         2644669 :     NewObjectCache::EntryIndex entry = -1;
        2871         2644669 :     if (parent == type->proto->getParent()) {
        2872         2644222 :         if (cache.lookupType(&ObjectClass, type, kind, &entry))
        2873         2541679 :             return cache.newObjectFromHit(cx, entry);
        2874                 :     }
        2875                 :
        2876          102990 :     JSObject *obj = NewObject(cx, &ObjectClass, type, parent, kind);
        2877          102990 :     if (!obj)
        2878               0 :         return NULL;
        2879                 :
        2880          102990 :     if (entry != -1 && !obj->hasDynamicSlots())
        2881          102543 :         cache.fillType(entry, &ObjectClass, type, kind, obj);
        2882                 :
        2883          102990 :     return obj;
        2884                 : }
        2885                 :
        2886                 : JSObject *
        2887             587 : js::NewReshapedObject(JSContext *cx, TypeObject *type, JSObject *parent,
        2888                 :                       gc::AllocKind kind, const Shape *shape)
        2889                 : {
        2890             587 :     JSObject *res = NewObjectWithType(cx, type, parent, kind);
        2891             587 :     if (!res)
        2892               0 :         return NULL;
        2893                 :
        2894             587 :     if (shape->isEmptyShape())
        2895               0 :         return res;
        2896                 :
        2897                 :     /* Get all the ids in the object, in order. */
        2898            1174 :     js::AutoIdVector ids(cx);
        2899            1583 :     for (unsigned i = 0; i <= shape->slot(); i++) {
        2900             996 :         if (!ids.append(JSID_VOID))
        2901               0 :             return NULL;
        2902                 :     }
        2903             587 :     const js::Shape *nshape = shape;
        2904            2170 :     while (!nshape->isEmptyShape()) {
        2905             996 :         ids[nshape->slot()] = nshape->propid();
        2906             996 :         nshape = nshape->previous();
        2907                 :     }
        2908                 :
        2909                 :     /* Construct the new shape. */
        2910            1583 :     for (unsigned i = 0; i < ids.length(); i++) {
        2911            1992 :         if (!DefineNativeProperty(cx, res, ids[i], js::UndefinedValue(), NULL, NULL,
        2912            1992 :                                   JSPROP_ENUMERATE, 0, 0, DNP_SKIP_TYPE)) {
        2913               0 :             return NULL;
        2914                 :         }
        2915                 :     }
        2916             587 :     JS_ASSERT(!res->inDictionaryMode());
        2917                 :
        2918             587 :     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         2644082 : CreateThisForFunctionWithType(JSContext *cx, types::TypeObject *type, JSObject *parent)
        2945                 : {
        2946         2644082 :     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          349745 :         gc::AllocKind kind = type->newScript->allocKind;
        2953          349745 :         JSObject *res = NewObjectWithType(cx, type, parent, kind);
        2954          349745 :         if (res)
        2955          349745 :             JS_ALWAYS_TRUE(res->setLastProperty(cx, (Shape *) type->newScript->shape.get()));
        2956          349745 :         return res;
        2957                 :     }
        2958                 :
        2959         2294337 :     gc::AllocKind kind = NewObjectGCKind(cx, &ObjectClass);
        2960         2294337 :     return NewObjectWithType(cx, type, parent, kind);
        2961                 : }
        2962                 :
        2963                 : JSObject *
        2964         2644172 : js_CreateThisForFunctionWithProto(JSContext *cx, JSObject *callee, JSObject *proto)
        2965                 : {
        2966                 :     JSObject *res;
        2967                 :
        2968         2644172 :     if (proto) {
        2969         2644082 :         types::TypeObject *type = proto->getNewType(cx, callee->toFunction());
        2970         2644082 :         if (!type)
        2971               0 :             return NULL;
        2972         2644082 :         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         2644172 :     if (res && cx->typeInferenceEnabled())
        2979          780620 :         TypeScript::SetThis(cx, callee->toFunction()->script(), types::Type::ObjectType(res));
        2980                 :
        2981         2644172 :     return res;
        2982                 : }
        2983                 :
        2984                 : JSObject *
        2985          982953 : js_CreateThisForFunction(JSContext *cx, JSObject *callee, bool newType)
        2986                 : {
        2987                 :     Value protov;
        2988          982953 :     if (!callee->getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &protov))
        2989               0 :         return NULL;
        2990                 :     JSObject *proto;
        2991          982953 :     if (protov.isObject())
        2992          982903 :         proto = &protov.toObject();
        2993                 :     else
        2994              50 :         proto = NULL;
        2995          982953 :     JSObject *obj = js_CreateThisForFunctionWithProto(cx, callee, proto);
        2996                 :
        2997          982953 :     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          982953 :     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         3221829 : Detecting(JSContext *cx, jsbytecode *pc)
        3020                 : {
        3021                 :     /* General case: a branch or equality op follows the access. */
        3022         3221829 :     JSOp op = JSOp(*pc);
        3023         3221829 :     if (js_CodeSpec[op].format & JOF_DETECTING)
        3024          457636 :         return true;
        3025                 :
        3026                 :     JSAtom *atom;
        3027                 :
        3028         2764193 :     JSScript *script = cx->stack.currentScript();
        3029         2764193 :     jsbytecode *endpc = script->code + script->length;
        3030         2764193 :     JS_ASSERT(script->code <= pc && pc < endpc);
        3031                 :
        3032         2764193 :     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         2763626 :     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          204646 :         atom = script->getAtom(GET_UINT32_INDEX(pc));
        3051          205793 :         if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID] &&
        3052            1147 :             (pc += js_CodeSpec[op].length) < endpc) {
        3053            1147 :             op = JSOp(*pc);
        3054            1147 :             return op == JSOP_EQ || op == JSOP_NE || op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
        3055                 :         }
        3056                 :     }
        3057                 :
        3058         2762479 :     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         3411227 : js_InferFlags(JSContext *cx, unsigned defaultFlags)
        3069                 : {
        3070                 :     const JSCodeSpec *cs;
        3071                 :     uint32_t format;
        3072         3411227 :     unsigned flags = 0;
        3073                 :
        3074                 :     jsbytecode *pc;
        3075         3411227 :     JSScript *script = cx->stack.currentScript(&pc);
        3076         3411227 :     if (!script || !pc)
        3077            7503 :         return defaultFlags;
        3078                 :
        3079         3403724 :     cs = &js_CodeSpec[*pc];
        3080         3403724 :     format = cs->format;
        3081         3403724 :     if (JOF_MODE(format) != JOF_NAME)
        3082         1808933 :         flags |= JSRESOLVE_QUALIFIED;
        3083         3403724 :     if (format & JOF_SET) {
        3084          275598 :         flags |= JSRESOLVE_ASSIGNING;
        3085         3128126 :     } else if (cs->length >= 0) {
        3086         3128126 :         pc += cs->length;
        3087         3128126 :         if (pc < script->code + script->length && Detecting(cx, pc))
        3088          364969 :             flags |= JSRESOLVE_DETECTING;
        3089                 :     }
        3090         3403724 :     if (format & JOF_DECLARING)
        3091          484727 :         flags |= JSRESOLVE_DECLARING;
        3092         3403724 :     return flags;
        3093                 : }
        3094                 :
        3095                 : JSBool
        3096         3834926 : JSObject::nonNativeSetProperty(JSContext *cx, jsid id, js::Value *vp, JSBool strict)
        3097                 : {
        3098         3834926 :     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         3834926 :     return getOps()->setGeneric(cx, this, id, vp, strict);
        3105                 : }
        3106                 :
        3107                 : JSBool
        3108        13562025 : JSObject::nonNativeSetElement(JSContext *cx, uint32_t index, js::Value *vp, JSBool strict)
        3109                 : {
        3110        13562025 :     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        13562025 :     return getOps()->setElement(cx, this, index, vp, strict);
        3120                 : }
        3121                 :
        3122                 : bool
        3123           26717 : JSObject::deleteByValue(JSContext *cx, const Value &property, Value *rval, bool strict)
        3124                 : {
        3125                 :     uint32_t index;
        3126           26717 :     if (IsDefinitelyIndex(property, &index))
        3127            6027 :         return deleteElement(cx, index, rval, strict);
        3128                 :
        3129           20690 :     Value propval = property;
        3130           20690 :     SpecialId sid;
        3131           20690 :     if (ValueIsSpecial(this, &propval, &sid, cx))
        3132               0 :         return deleteSpecial(cx, sid, rval, strict);
        3133                 :
        3134                 :     JSAtom *name;
        3135           20690 :     if (!js_ValueToAtom(cx, propval, &name))
        3136               0 :         return false;
        3137                 :
        3138           20690 :     if (name->isIndex(&index))
        3139              36 :         return deleteElement(cx, index, rval, false);
        3140                 :
        3141           20654 :     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          202812 : DefineStandardSlot(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom,
        3544                 :                    const Value &v, uint32_t attrs, bool &named)
        3545                 : {
        3546          202812 :     jsid id = ATOM_TO_JSID(atom);
        3547                 :
        3548          202812 :     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          202812 :     named = obj->defineGeneric(cx, id, v, JS_PropertyStub, JS_StrictPropertyStub, attrs);
        3571          202812 :     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          202812 : 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          405624 :     RootedVarObject proto(cx);
        3636          202812 :     proto = NewObjectWithClassProto(cx, clasp, protoProto, obj);
        3637          202812 :     if (!proto)
        3638               0 :         return NULL;
        3639                 :
        3640          202812 :     if (!proto->setSingletonType(cx))
        3641               0 :         return NULL;
        3642                 :
        3643          202812 :     if (clasp == &ArrayClass && !proto->makeDenseArraySlow(cx))
        3644               0 :         return NULL;
        3645                 :
        3646                 :     /* After this point, control must exit via label bad or out. */
        3647          405624 :     RootedVarObject ctor(cx);
        3648          202812 :     bool named = false;
        3649          202812 :     bool cached = false;
        3650          202812 :     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          405620 :         RootedVarFunction fun(cx);
        3674                 :         fun = js_NewFunction(cx, NULL, constructor, nargs, JSFUN_CONSTRUCTOR, obj, atom,
        3675          202810 :                              ctorKind);
        3676          202810 :         if (!fun)
        3677                 :             goto bad;
        3678          202810 :         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          202810 :         if (key != JSProto_Null) {
        3686               0 :             SetClassObject(obj, key, fun, proto);
        3687               0 :             cached = true;
        3688                 :         }
        3689                 :
        3690          405620 :         AutoValueRooter tvr2(cx, ObjectValue(*fun));
        3691          202810 :         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          202810 :         ctor = fun;
        3701          202810 :         if (!LinkConstructorAndPrototype(cx, ctor, proto))
        3702                 :             goto bad;
        3703                 :
        3704                 :         /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */
        3705          202810 :         if (ctor->getClass() == clasp && !ctor->splicePrototype(cx, proto))
        3706                 :             goto bad;
        3707                 :     }
        3708                 :
        3709          608434 :     if (!DefinePropertiesAndBrand(cx, proto, ps, fs) ||
        3710          405622 :         (ctor != proto && !DefinePropertiesAndBrand(cx, ctor, static_ps, static_fs)))
        3711                 :     {
        3712               0 :         goto bad;
        3713                 :     }
        3714                 :
        3715          202812 :     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          202812 :     if (!cached && key != JSProto_Null)
        3725               0 :         SetClassObject(obj, key, ctor, proto);
        3726                 :
        3727          202812 :     if (ctorp)
        3728           22872 :         *ctorp = ctor;
        3729          202812 :     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         2758050 : IsStandardClassResolved(JSObject *obj, js::Class *clasp)
        3752                 : {
        3753         2758050 :     JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp);
        3754                 :
        3755                 :     /* If the constructor is undefined, then it hasn't been initialized. */
        3756         2758050 :     return (obj->getReservedSlot(key) != UndefinedValue());
        3757                 : }
        3758                 :
        3759                 : void
        3760           11028 : MarkStandardClassInitializedNoProto(JSObject *obj, js::Class *clasp)
        3761                 : {
        3762           11028 :     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           11028 :     if (obj->getReservedSlot(key) == UndefinedValue())
        3769            6606 :         obj->setSlot(key, BooleanValue(true));
        3770           11028 : }
        3771                 :
        3772                 : }
        3773                 :
        3774                 : JSObject *
        3775          202812 : 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          405624 :     RootObject rootProto(cx, &protoProto);
        3782                 :
        3783          405624 :     RootedVarAtom atom(cx);
        3784          202812 :     atom = js_Atomize(cx, clasp->name, strlen(clasp->name));
        3785          202812 :     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          202812 :     JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp);
        3801          202812 :     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          202812 :                                          ps, fs, static_ps, static_fs, ctorp, ctorKind);
        3809                 : }
        3810                 :
        3811                 : void
        3812            5487 : JSObject::initSlotRange(size_t start, const Value *vector, size_t length)
        3813                 : {
        3814            5487 :     JSCompartment *comp = compartment();
        3815                 :     HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
        3816            5487 :     getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
        3817            5487 :     for (HeapSlot *sp = fixedStart; sp != fixedEnd; sp++)
        3818               0 :         sp->init(comp, this, start++, *vector++);
        3819            9782 :     for (HeapSlot *sp = slotsStart; sp != slotsEnd; sp++)
        3820            4295 :         sp->init(comp, this, start++, *vector++);
        3821            5487 : }
        3822                 :
        3823                 : void
        3824          195346 : JSObject::copySlotRange(size_t start, const Value *vector, size_t length)
        3825                 : {
        3826          195346 :     JSCompartment *comp = compartment();
        3827                 :     HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
        3828          195346 :     getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
        3829          544207 :     for (HeapSlot *sp = fixedStart; sp != fixedEnd; sp++)
        3830          348861 :         sp->set(comp, this, start++, *vector++);
        3831          854302 :     for (HeapSlot *sp = slotsStart; sp != slotsEnd; sp++)
        3832          658956 :         sp->set(comp, this, start++, *vector++);
        3833          195346 : }
        3834                 :
        3835                 : inline void
        3836            2566 : JSObject::invalidateSlotRange(size_t start, size_t length)
        3837                 : {
        3838                 : #ifdef DEBUG
        3839            2566 :     JS_ASSERT(!isDenseArray());
        3840                 :
        3841                 :     HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
        3842            2566 :     getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
        3843            2566 :     Debug_SetSlotRangeToCrashOnTouch(fixedStart, fixedEnd);
        3844            2566 :     Debug_SetSlotRangeToCrashOnTouch(slotsStart, slotsEnd);
        3845                 : #endif /* DEBUG */
        3846            2566 : }
        3847                 :
        3848                 : inline bool
        3849        30465286 : JSObject::updateSlotsForSpan(JSContext *cx, size_t oldSpan, size_t newSpan)
        3850                 : {
        3851        30465286 :     JS_ASSERT(oldSpan != newSpan);
        3852                 :
        3853        30465286 :     size_t oldCount = dynamicSlotsCount(numFixedSlots(), oldSpan);
        3854        30465286 :     size_t newCount = dynamicSlotsCount(numFixedSlots(), newSpan);
        3855                 :
        3856        30465286 :     if (oldSpan < newSpan) {
        3857        30462720 :         if (oldCount < newCount && !growSlots(cx, oldCount, newCount))
        3858               0 :             return false;
        3859                 :
        3860        30462720 :         if (newSpan == oldSpan + 1)
        3861        27541869 :             initSlotUnchecked(oldSpan, UndefinedValue());
        3862                 :         else
        3863         2920851 :             initializeSlotRange(oldSpan, newSpan - oldSpan);
        3864                 :     } else {
        3865                 :         /* Trigger write barriers on the old slots before reallocating. */
        3866            2566 :         prepareSlotRangeForOverwrite(newSpan, oldSpan);
        3867            2566 :         invalidateSlotRange(newSpan, oldSpan - newSpan);
        3868                 :
        3869            2566 :         if (oldCount > newCount)
        3870              59 :             shrinkSlots(cx, oldCount, newCount);
        3871                 :     }
        3872                 :
        3873        30465286 :     return true;
        3874                 : }
        3875                 :
        3876                 : bool
        3877        41480452 : JSObject::setLastProperty(JSContext *cx, const js::Shape *shape)
        3878                 : {
        3879        41480452 :     JS_ASSERT(!inDictionaryMode());
        3880        41480452 :     JS_ASSERT(!shape->inDictionary());
        3881        41480452 :     JS_ASSERT(shape->compartment() == compartment());
        3882        41480452 :     JS_ASSERT(shape->numFixedSlots() == numFixedSlots());
        3883                 :
        3884        41480452 :     size_t oldSpan = lastProperty()->slotSpan();
        3885        41480452 :     size_t newSpan = shape->slotSpan();
        3886                 :
        3887        41480452 :     if (oldSpan == newSpan) {
        3888        14148310 :         shape_ = const_cast<js::Shape *>(shape);
        3889        14148310 :         return true;
        3890                 :     }
        3891                 :
        3892        27332142 :     if (!updateSlotsForSpan(cx, oldSpan, newSpan))
        3893               0 :         return false;
        3894                 :
        3895        27332142 :     shape_ = const_cast<js::Shape *>(shape);
        3896        27332142 :     return true;
        3897                 : }
        3898                 :
        3899                 : bool
        3900         3133144 : JSObject::setSlotSpan(JSContext *cx, uint32_t span)
        3901                 : {
        3902         3133144 :     JS_ASSERT(inDictionaryMode());
        3903         3133144 :     js::BaseShape *base = lastProperty()->base();
        3904                 :
        3905         3133144 :     size_t oldSpan = base->slotSpan();
        3906                 :
        3907         3133144 :     if (oldSpan == span)
        3908               0 :         return true;
        3909                 :
        3910         3133144 :     if (!updateSlotsForSpan(cx, oldSpan, span))
        3911               0 :         return false;
        3912                 :
        3913         3133144 :     base->setSlotSpan(span);
        3914         3133144 :     return true;
        3915                 : }
        3916                 :
        3917                 : bool
        3918         5961467 : JSObject::growSlots(JSContext *cx, uint32_t oldCount, uint32_t newCount)
        3919                 : {
        3920         5961467 :     JS_ASSERT(newCount > oldCount);
        3921         5961467 :     JS_ASSERT(newCount >= SLOT_CAPACITY_MIN);
        3922         5961467 :     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         5961467 :     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         5961467 :     JS_ASSERT(newCount < NELEMENTS_LIMIT);
        3938                 :
        3939         5961467 :     size_t oldSize = Probes::objectResizeActive() ? computedSizeOfThisSlotsElements() : 0;
        3940         5961467 :     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         5961467 :     if (!hasLazyType() && !oldCount && type()->newScript) {
        3949              27 :         gc::AllocKind kind = type()->newScript->allocKind;
        3950              27 :         unsigned newScriptSlots = gc::GetGCKindSlots(kind);
        3951              27 :         if (newScriptSlots == numFixedSlots() && gc::TryIncrementAllocKind(&kind)) {
        3952                 :             JSObject *obj = NewReshapedObject(cx, type(), getParent(), kind,
        3953              22 :                                               type()->newScript->shape);
        3954              22 :             if (!obj)
        3955               0 :                 return false;
        3956                 :
        3957              22 :             type()->newScript->allocKind = kind;
        3958              22 :             type()->newScript->shape = obj->lastProperty();
        3959              22 :             type()->markStateChange(cx);
        3960                 :         }
        3961                 :     }
        3962                 :
        3963         5961467 :     if (!oldCount) {
        3964         5237240 :         slots = (HeapSlot *) cx->malloc_(newCount * sizeof(HeapSlot));
        3965         5237240 :         if (!slots)
        3966               0 :             return false;
        3967         5237240 :         Debug_SetSlotRangeToCrashOnTouch(slots, newCount);
        3968         5237240 :         if (Probes::objectResizeActive())
        3969               0 :             Probes::resizeObject(cx, this, oldSize, newSize);
        3970         5237240 :         return true;
        3971                 :     }
        3972                 :
        3973                 :     HeapSlot *newslots = (HeapSlot*) cx->realloc_(slots, oldCount * sizeof(HeapSlot),
        3974          724227 :                                                   newCount * sizeof(HeapSlot));
        3975          724227 :     if (!newslots)
        3976               0 :         return false;  /* Leave slots at its old size. */
        3977                 :
        3978          724227 :     bool changed = slots != newslots;
        3979          724227 :     slots = newslots;
        3980                 :
        3981          724227 :     Debug_SetSlotRangeToCrashOnTouch(slots + oldCount, newCount - oldCount);
        3982                 :
        3983                 :     /* Changes in the slots of global objects can trigger recompilation. */
        3984          724227 :     if (changed && isGlobal())
        3985           38523 :         types::MarkObjectStateChange(cx, this);
        3986                 :
        3987          724227 :     if (Probes::objectResizeActive())
        3988               0 :         Probes::resizeObject(cx, this, oldSize, newSize);
        3989                 :
        3990          724227 :     return true;
        3991                 : }
        3992                 :
        3993                 : void
        3994              59 : JSObject::shrinkSlots(JSContext *cx, uint32_t oldCount, uint32_t newCount)
        3995                 : {
        3996              59 :     JS_ASSERT(newCount < oldCount);
        3997              59 :     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              59 :     if (isCall())
        4006               0 :         return;
        4007                 :
        4008              59 :     size_t oldSize = Probes::objectResizeActive() ? computedSizeOfThisSlotsElements() : 0;
        4009              59 :     size_t newSize = oldSize - (oldCount - newCount) * sizeof(Value);
        4010                 :
        4011              59 :     if (newCount == 0) {
        4012              59 :         cx->free_(slots);
        4013              59 :         slots = NULL;
        4014              59 :         if (Probes::objectResizeActive())
        4015               0 :             Probes::resizeObject(cx, this, oldSize, newSize);
        4016              59 :         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          303536 : JSObject::growElements(JSContext *cx, unsigned newcap)
        4038                 : {
        4039          303536 :     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          303536 :     uint32_t oldcap = getDenseArrayCapacity();
        4052          303536 :     JS_ASSERT(oldcap <= newcap);
        4053                 :
        4054          303536 :     size_t oldSize = Probes::objectResizeActive() ? computedSizeOfThisSlotsElements() : 0;
        4055                 :
        4056                 :     uint32_t nextsize = (oldcap <= CAPACITY_DOUBLING_MAX)
        4057                 :                       ? oldcap * 2
        4058          303536 :                       : oldcap + (oldcap >> 3);
        4059                 :
        4060          303536 :     uint32_t actualCapacity = JS_MAX(newcap, nextsize);
        4061          303536 :     if (actualCapacity >= CAPACITY_CHUNK)
        4062              39 :         actualCapacity = JS_ROUNDUP(actualCapacity, CAPACITY_CHUNK);
        4063          303497 :     else if (actualCapacity < SLOT_CAPACITY_MIN)
        4064            8072 :         actualCapacity = SLOT_CAPACITY_MIN;
        4065                 :
        4066                 :     /* Don't let nelements get close to wrapping around uint32_t. */
        4067          303536 :     if (actualCapacity >= NELEMENTS_LIMIT || actualCapacity < oldcap || actualCapacity < newcap) {
        4068               0 :         JS_ReportOutOfMemory(cx);
        4069               0 :         return false;
        4070                 :     }
        4071                 :
        4072          303536 :     uint32_t initlen = getDenseArrayInitializedLength();
        4073          303536 :     uint32_t newAllocated = actualCapacity + ObjectElements::VALUES_PER_HEADER;
        4074                 :
        4075                 :     ObjectElements *newheader;
        4076          303536 :     if (hasDynamicElements()) {
        4077          101395 :         uint32_t oldAllocated = oldcap + ObjectElements::VALUES_PER_HEADER;
        4078                 :         newheader = (ObjectElements *)
        4079          101395 :             cx->realloc_(getElementsHeader(), oldAllocated * sizeof(Value),
        4080          202790 :                          newAllocated * sizeof(Value));
        4081          101395 :         if (!newheader)
        4082               0 :             return false;  /* Leave elements as its old size. */
        4083                 :     } else {
        4084          202141 :         newheader = (ObjectElements *) cx->malloc_(newAllocated * sizeof(Value));
        4085          202141 :         if (!newheader)
        4086               0 :             return false;  /* Ditto. */
        4087          202141 :         js_memcpy(newheader, getElementsHeader(),
        4088          404282 :                   (ObjectElements::VALUES_PER_HEADER + initlen) * sizeof(Value));
        4089                 :     }
        4090                 :
        4091          303536 :     newheader->capacity = actualCapacity;
        4092          303536 :     elements = newheader->elements();
        4093                 :
        4094          303536 :     Debug_SetSlotRangeToCrashOnTouch(elements + initlen, actualCapacity - initlen);
        4095                 :
        4096          303536 :     if (Probes::objectResizeActive())
        4097               0 :         Probes::resizeObject(cx, this, oldSize, computedSizeOfThisSlotsElements());
        4098                 :
        4099          303536 :     return true;
        4100                 : }
        4101                 :
        4102                 : void
        4103           53862 : JSObject::shrinkElements(JSContext *cx, unsigned newcap)
        4104                 : {
        4105           53862 :     JS_ASSERT(isDenseArray());
        4106                 :
        4107           53862 :     uint32_t oldcap = getDenseArrayCapacity();
        4108           53862 :     JS_ASSERT(newcap <= oldcap);
        4109                 :
        4110           53862 :     size_t oldSize = Probes::objectResizeActive() ? computedSizeOfThisSlotsElements() : 0;
        4111                 :
        4112                 :     /* Don't shrink elements below the minimum capacity. */
        4113           53862 :     if (oldcap <= SLOT_CAPACITY_MIN || !hasDynamicElements())
        4114           11377 :         return;
        4115                 :
        4116           42485 :     newcap = Max(newcap, SLOT_CAPACITY_MIN);
        4117                 :
        4118           42485 :     uint32_t newAllocated = newcap + ObjectElements::VALUES_PER_HEADER;
        4119                 :
        4120                 :     ObjectElements *newheader = (ObjectElements *)
        4121           42485 :         cx->realloc_(getElementsHeader(), newAllocated * sizeof(Value));
        4122           42485 :     if (!newheader)
        4123               0 :         return;  /* Leave elements at its old size. */
        4124                 :
        4125           42485 :     newheader->capacity = newcap;
        4126           42485 :     elements = newheader->elements();
        4127                 :
        4128           42485 :     if (Probes::objectResizeActive())
        4129               0 :         Probes::resizeObject(cx, this, oldSize, computedSizeOfThisSlotsElements());
        4130                 : }
        4131                 :
        4132                 : #ifdef DEBUG
        4133                 : bool
        4134       740261006 : JSObject::slotInRange(unsigned slot, SentinelAllowed sentinel) const
        4135                 : {
        4136       740261006 :     size_t capacity = numFixedSlots() + numDynamicSlots();
        4137       740261006 :     if (sentinel == SENTINEL_ALLOWED)
        4138       189914467 :         return slot <= capacity;
        4139       550346539 :     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           51185 : SetProto(JSContext *cx, JSObject *obj, JSObject *proto, bool checkForCycles)
        4164                 : {
        4165           51185 :     JS_ASSERT_IF(!checkForCycles, obj != proto);
        4166           51185 :     JS_ASSERT(obj->isExtensible());
        4167                 :
        4168           51185 :     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           51185 :     JSObject *oldproto = obj;
        4193          227914 :     while (oldproto && oldproto->isNative()) {
        4194          125544 :         if (oldproto->hasSingletonType()) {
        4195           38482 :             if (!oldproto->generateOwnShape(cx))
        4196               0 :                 return false;
        4197                 :         } else {
        4198           87062 :             if (!oldproto->setUncacheableProto(cx))
        4199               0 :                 return false;
        4200                 :         }
        4201          125544 :         oldproto = oldproto->getProto();
        4202                 :     }
        4203                 :
        4204           51185 :     if (checkForCycles) {
        4205           48530 :         for (JSObject *obj2 = proto; obj2; obj2 = obj2->getProto()) {
        4206           33613 :             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           51185 :     if (obj->hasSingletonType()) {
        4215                 :         /*
        4216                 :          * Just splice the prototype, but mark the properties as unknown for
        4217                 :          * consistent behavior.
        4218                 :          */
        4219           12849 :         if (!obj->splicePrototype(cx, proto))
        4220               0 :             return false;
        4221           12849 :         MarkTypeObjectUnknownProperties(cx, obj->type());
        4222           12849 :         return true;
        4223                 :     }
        4224                 :
        4225           38336 :     if (proto && !proto->setNewTypeUnknown(cx))
        4226               0 :         return false;
        4227                 :
        4228                 :     TypeObject *type = proto
        4229                 :         ? proto->getNewType(cx, NULL)
        4230           38336 :         : cx->compartment->getEmptyType(cx);
        4231           38336 :     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           38336 :     MarkTypeObjectUnknownProperties(cx, obj->type(), true);
        4243           38336 :     MarkTypeObjectUnknownProperties(cx, type, true);
        4244                 :
        4245           38336 :     obj->setType(type);
        4246           38336 :     return true;
        4247                 : }
        4248                 :
        4249                 : }
        4250                 :
        4251                 : JSBool
        4252          104038 : js_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key,
        4253                 :                   JSObject **objp)
        4254                 : {
        4255          208076 :     RootObject objRoot(cx, &obj);
        4256                 :
        4257          104038 :     obj = &obj->global();
        4258          104038 :     if (!obj->isGlobal()) {
        4259               0 :         *objp = NULL;
        4260               0 :         return true;
        4261                 :     }
        4262                 :
        4263          104038 :     Value v = obj->getReservedSlot(key);
        4264          104038 :     if (v.isObject()) {
        4265           17464 :         *objp = &v.toObject();
        4266           17464 :         return true;
        4267                 :     }
        4268                 :
        4269          173148 :     AutoResolving resolving(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.classAtoms[key]));
        4270           86574 :     if (resolving.alreadyStarted()) {
        4271                 :         /* Already caching id in obj -- suppress recursion. */
        4272           10377 :         *objp = NULL;
        4273           10377 :         return true;
        4274                 :     }
        4275                 :
        4276           76197 :     JSObject *cobj = NULL;
        4277           76197 :     if (JSObjectOp init = lazy_prototype_init[key]) {
        4278           76197 :         if (!init(cx, obj))
        4279               0 :             return false;
        4280           76197 :         v = obj->getReservedSlot(key);
        4281           76197 :         if (v.isObject())
        4282           74277 :             cobj = &v.toObject();
        4283                 :     }
        4284                 :
        4285           76197 :     *objp = cobj;
        4286           76197 :     return true;
        4287                 : }
        4288                 :
        4289                 : JSBool
        4290          361830 : 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          723660 :     RootedVarObject obj(cx);
        4299                 :
        4300          361830 :     if (start) {
        4301          341763 :         obj = &start->global();
        4302          341763 :         OBJ_TO_INNER_OBJECT(cx, *obj.address());
        4303                 :     } else {
        4304           20067 :         obj = GetGlobalForScopeChain(cx);
        4305                 :     }
        4306          361830 :     if (!obj)
        4307               0 :         return false;
        4308                 :
        4309          361830 :     if (protoKey != JSProto_Null) {
        4310           96410 :         JS_ASSERT(JSProto_Null < protoKey);
        4311           96410 :         JS_ASSERT(protoKey < JSProto_LIMIT);
        4312           96410 :         if (!js_GetClassObject(cx, obj, protoKey, &cobj))
        4313               0 :             return false;
        4314           96410 :         if (cobj) {
        4315           87884 :             vp->setObject(*cobj);
        4316           87884 :             return JS_TRUE;
        4317                 :         }
        4318            8526 :         id = ATOM_TO_JSID(cx->runtime->atomState.classAtoms[protoKey]);
        4319                 :     } else {
        4320          265420 :         JSAtom *atom = js_Atomize(cx, clasp->name, strlen(clasp->name));
        4321          265420 :         if (!atom)
        4322               0 :             return false;
        4323          265420 :         id = ATOM_TO_JSID(atom);
        4324                 :     }
        4325                 :
        4326          273946 :     JS_ASSERT(obj->isNative());
        4327          273946 :     if (!LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_CLASSNAME, &pobj, &prop))
        4328               0 :         return false;
        4329          273946 :     Value v = UndefinedValue();
        4330          273946 :     if (prop && pobj->isNative()) {
        4331            3156 :         shape = (Shape *) prop;
        4332            3156 :         if (shape->hasSlot()) {
        4333            3156 :             v = pobj->nativeGetSlot(shape->slot());
        4334            3156 :             if (v.isPrimitive())
        4335               0 :                 v.setUndefined();
        4336                 :         }
        4337                 :     }
        4338          273946 :     *vp = v;
        4339          273946 :     return true;
        4340                 : }
        4341                 :
        4342                 : bool
        4343        25140945 : JSObject::allocSlot(JSContext *cx, uint32_t *slotp)
        4344                 : {
        4345        25140945 :     uint32_t slot = slotSpan();
        4346        25140945 :     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        25140945 :     if (inDictionaryMode()) {
        4353         2075073 :         PropertyTable &table = lastProperty()->table();
        4354         2075073 :         uint32_t last = table.freelist;
        4355         2075073 :         if (last != SHAPE_INVALID_SLOT) {
        4356                 : #ifdef DEBUG
        4357           11351 :             JS_ASSERT(last < slot);
        4358           11351 :             uint32_t next = getSlot(last).toPrivateUint32();
        4359           11351 :             JS_ASSERT_IF(next != SHAPE_INVALID_SLOT, next < slot);
        4360                 : #endif
        4361                 :
        4362           11351 :             *slotp = last;
        4363                 :
        4364           11351 :             const Value &vref = getSlot(last);
        4365           11351 :             table.freelist = vref.toPrivateUint32();
        4366           11351 :             setSlot(last, UndefinedValue());
        4367           11351 :             return true;
        4368                 :         }
        4369                 :     }
        4370                 :
        4371        25129594 :     if (slot >= SHAPE_MAXIMUM_SLOT) {
        4372               0 :         js_ReportOutOfMemory(cx);
        4373               0 :         return false;
        4374                 :     }
        4375                 :
        4376        25129594 :     *slotp = slot;
        4377                 :
        4378        25129594 :     if (inDictionaryMode() && !setSlotSpan(cx, slot + 1))
        4379               0 :         return false;
        4380                 :
        4381        25129594 :     return true;
        4382                 : }
        4383                 :
        4384                 : void
        4385          447074 : JSObject::freeSlot(JSContext *cx, uint32_t slot)
        4386                 : {
        4387          447074 :     JS_ASSERT(slot < slotSpan());
        4388                 :
        4389          447074 :     if (inDictionaryMode()) {
        4390          444607 :         uint32_t &last = lastProperty()->table().freelist;
        4391                 :
        4392                 :         /* Can't afford to check the whole freelist, but let's check the head. */
        4393          444607 :         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          444607 :         if (JSSLOT_FREE(getClass()) <= slot) {
        4400          387149 :             JS_ASSERT_IF(last != SHAPE_INVALID_SLOT, last < slotSpan());
        4401          387149 :             setSlot(slot, PrivateUint32Value(last));
        4402          387149 :             last = slot;
        4403          387149 :             return;
        4404                 :         }
        4405                 :     }
        4406           59925 :     setSlot(slot, UndefinedValue());
        4407                 : }
        4408                 :
        4409                 : static bool
        4410         1133446 : PurgeProtoChain(JSContext *cx, JSObject *obj, jsid id)
        4411                 : {
        4412                 :     const Shape *shape;
        4413                 :
        4414         2266892 :     RootObject objRoot(cx, &obj);
        4415         2266892 :     RootId idRoot(cx, &id);
        4416                 :
        4417         2733157 :     while (obj) {
        4418          582002 :         if (!obj->isNative()) {
        4419              20 :             obj = obj->getProto();
        4420              20 :             continue;
        4421                 :         }
        4422          581982 :         shape = obj->nativeLookup(cx, id);
        4423          581982 :         if (shape) {
        4424          115737 :             if (!obj->shadowingShapeChange(cx, *shape))
        4425               0 :                 return false;
        4426                 :
        4427          115737 :             obj->shadowingShapeChange(cx, *shape);
        4428          115737 :             return true;
        4429                 :         }
        4430          466245 :         obj = obj->getProto();
        4431                 :     }
        4432                 :
        4433         1017709 :     return true;
        4434                 : }
        4435                 :
        4436                 : bool
        4437         1133305 : js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id)
        4438                 : {
        4439         2266610 :     RootObject objRoot(cx, &obj);
        4440         2266610 :     RootId idRoot(cx, &id);
        4441                 :
        4442         1133305 :     JS_ASSERT(obj->isDelegate());
        4443         1133305 :     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         1133305 :     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         1133305 :     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           40589 : 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           40589 :     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           40589 :     return obj->changeProperty(cx, shape, attrs, mask, getter, setter);
        4500                 : }
        4501                 :
        4502                 : JSBool
        4503        19067725 : js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
        4504                 :                   PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
        4505                 : {
        4506        19067725 :     return !!DefineNativeProperty(cx, obj, id, *value, getter, setter, attrs, 0, 0);
        4507                 : }
        4508                 :
        4509                 : JSBool
        4510         1607243 : js_DefineElement(JSContext *cx, JSObject *obj, uint32_t index, const Value *value,
        4511                 :                  PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
        4512                 : {
        4513                 :     jsid id;
        4514         1607243 :     if (!IndexToId(cx, index, &id))
        4515               0 :         return false;
        4516         1607243 :     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        40285296 : CallAddPropertyHook(JSContext *cx, Class *clasp, JSObject *obj, const Shape *shape, Value *vp)
        4527                 : {
        4528        40285296 :     if (clasp->addProperty != JS_PropertyStub) {
        4529         4546814 :         Value nominal = *vp;
        4530                 :
        4531         4546814 :         if (!CallJSPropertyOp(cx, clasp->addProperty, obj, shape->propid(), vp))
        4532               1 :             return false;
        4533         4546813 :         if (*vp != nominal) {
        4534               0 :             if (shape->hasSlot())
        4535               0 :                 obj->nativeSetSlotWithType(cx, shape, *vp);
        4536                 :         }
        4537                 :     }
        4538        40285295 :     return true;
        4539                 : }
        4540                 :
        4541                 : namespace js {
        4542                 :
        4543                 : const Shape *
        4544        36685361 : 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        36685361 :                              DNP_SET_METHOD | DNP_SKIP_TYPE)) == 0);
        4550                 :
        4551        73370722 :     RootObject objRoot(cx, &obj);
        4552        73370722 :     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        73370722 :     RootedVarValue value(cx);
        4559        36685361 :     value = value_;
        4560                 :
        4561                 :     /* Convert string indices to integers if appropriate. */
        4562        36685361 :     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        36685361 :     Shape *shape = NULL;
        4570        36685361 :     if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
        4571                 :         JSObject *pobj;
        4572                 :         JSProperty *prop;
        4573                 :
        4574                 :         /* Type information for getter/setter properties is unknown. */
        4575         2420949 :         AddTypePropertyId(cx, obj, id, types::Type::UnknownType());
        4576         2420949 :         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         2420949 :         if (!js_LookupProperty(cx, obj, id, &pobj, &prop))
        4584               0 :             return NULL;
        4585         2420949 :         if (prop && pobj == obj) {
        4586           30004 :             shape = (Shape *) prop;
        4587           30004 :             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           29656 :                                             : shape->setter());
        4596           29656 :                 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        36685361 :     if (!(defineHow & DNP_DONT_PURGE)) {
        4610        36684488 :         if (!js_PurgeScopeChain(cx, obj, id))
        4611               0 :             return NULL;
        4612                 :     }
        4613                 :
        4614                 :     /* Use the object's class getter and setter by default. */
        4615        36685361 :     Class *clasp = obj->getClass();
        4616        36685361 :     if (!(defineHow & DNP_SET_METHOD)) {
        4617        36670948 :         if (!getter && !(attrs & JSPROP_GETTER))
        4618         6362992 :             getter = clasp->getProperty;
        4619        36670948 :         if (!setter && !(attrs & JSPROP_SETTER))
        4620        17666192 :             setter = clasp->setProperty;
        4621                 :     }
        4622                 :
        4623        59800458 :     if (((defineHow & DNP_SET_METHOD) || getter == JS_PropertyStub) &&
        4624        23115097 :         !(defineHow & DNP_SKIP_TYPE)) {
        4625                 :         /*
        4626                 :          * Type information for normal native properties should reflect the
        4627                 :          * initial value of the property.
        4628                 :          */
        4629        23045161 :         AddTypePropertyId(cx, obj, id, value);
        4630        23045161 :         if (attrs & JSPROP_READONLY)
        4631         9322237 :             MarkTypePropertyConfigured(cx, obj, id);
        4632                 :     }
        4633                 :
        4634        36685361 :     if (!shape) {
        4635                 :         /* Add a new property, or replace an existing one of the same id. */
        4636        36655705 :         if (defineHow & DNP_SET_METHOD) {
        4637           14413 :             JS_ASSERT(clasp == &ObjectClass);
        4638           14413 :             JS_ASSERT(IsFunctionObject(value));
        4639           14413 :             JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
        4640           14413 :             JS_ASSERT(!getter && !setter);
        4641                 :
        4642           14413 :             JSObject *funobj = &value.raw().toObject();
        4643           14413 :             if (!funobj->toFunction()->isClonedMethod())
        4644           14413 :                 flags |= Shape::METHOD;
        4645                 :         }
        4646                 :
        4647        36655705 :         if (const Shape *existingShape = obj->nativeLookup(cx, id)) {
        4648         2333487 :             if (existingShape->isMethod() &&
        4649             270 :                 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        36655705 :                                  attrs, flags, shortid);
        4663        36655705 :         if (!shape)
        4664               0 :             return NULL;
        4665                 :     }
        4666                 :
        4667                 :     /* Store valueCopy before calling addProperty, in case the latter GC's. */
        4668        36685361 :     if (shape->hasSlot())
        4669        23851928 :         obj->nativeSetSlot(shape->slot(), value);
        4670                 :
        4671        36685361 :     if (!CallAddPropertyHook(cx, clasp, obj, shape, value.address())) {
        4672               0 :         obj->removeProperty(cx, id);
        4673               0 :         return NULL;
        4674                 :     }
        4675                 :
        4676        36685361 :     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         9967760 : CallResolveOp(JSContext *cx, JSObject *start, HandleObject obj, HandleId id, unsigned flags,
        4703                 :               JSObject **objp, JSProperty **propp, bool *recursedp)
        4704                 : {
        4705         9967760 :     Class *clasp = obj->getClass();
        4706         9967760 :     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        19935520 :     AutoResolving resolving(cx, obj, id);
        4717         9967760 :     if (resolving.alreadyStarted()) {
        4718                 :         /* Already resolving id in obj -- suppress recursion. */
        4719         1025708 :         *recursedp = true;
        4720         1025708 :         return true;
        4721                 :     }
        4722         8942052 :     *recursedp = false;
        4723                 :
        4724         8942052 :     *propp = NULL;
        4725                 :
        4726         8942052 :     if (clasp->flags & JSCLASS_NEW_RESOLVE) {
        4727         6105644 :         JSNewResolveOp newresolve = reinterpret_cast<JSNewResolveOp>(resolve);
        4728         6105644 :         if (flags == RESOLVE_INFER)
        4729         3408032 :             flags = js_InferFlags(cx, 0);
        4730                 :
        4731        12211288 :         RootedVarObject obj2(cx);
        4732         6105644 :         obj2 = (clasp->flags & JSCLASS_NEW_RESOLVE_GETS_START) ? start : NULL;
        4733         6105644 :         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         6105644 :         if (!obj2)
        4743         4790276 :             return true;
        4744                 :
        4745         1315368 :         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         7421012 :         obj = obj2;
        4751                 :     } else {
        4752         2836408 :         if (!resolve(cx, obj, id))
        4753               0 :             return false;
        4754                 :     }
        4755                 :
        4756         4151776 :     if (!obj->nativeEmpty()) {
        4757         3104842 :         if (const Shape *shape = obj->nativeLookup(cx, id)) {
        4758         2987372 :             *objp = obj;
        4759         2987372 :             *propp = (JSProperty *) shape;
        4760                 :         }
        4761                 :     }
        4762                 :
        4763         4151776 :     return true;
        4764                 : }
        4765                 :
        4766                 : static JS_ALWAYS_INLINE bool
        4767        91927441 : 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        91927441 :     JS_ASSERT(id == js_CheckForStringIndex(id));
        4772                 :
        4773       183854882 :     RootObject objRoot(cx, &obj);
        4774       183854882 :     RootId idRoot(cx, &id);
        4775                 :
        4776                 :     /* Search scopes starting with obj and following the prototype link. */
        4777        91927441 :     JSObject *start = obj;
        4778        21553800 :     while (true) {
        4779       113481241 :         const Shape *shape = obj->nativeLookup(cx, id);
        4780       113481241 :         if (shape) {
        4781        73885774 :             *objp = obj;
        4782        73885774 :             *propp = (JSProperty *) shape;
        4783        73885774 :             return true;
        4784                 :         }
        4785                 :
        4786                 :         /* Try obj's class resolve hook if id was not found in obj's scope. */
        4787        39595467 :         if (obj->getClass()->resolve != JS_ResolveStub) {
        4788                 :             bool recursed;
        4789         9967760 :             if (!CallResolveOp(cx, start, objRoot, idRoot, flags, objp, propp, &recursed))
        4790               0 :                 return false;
        4791         9967760 :             if (recursed)
        4792         1025708 :                 break;
        4793         8942052 :             if (*propp) {
        4794                 :                 /*
        4795                 :                  * For stats we do not recalculate protoIndex even if it was
        4796                 :                  * resolved on some other object.
        4797                 :                  */
        4798         2987372 :                 return true;
        4799                 :             }
        4800                 :         }
        4801                 :
        4802        35582387 :         JSObject *proto = obj->getProto();
        4803        35582387 :         if (!proto)
        4804        14027853 :             break;
        4805        21554534 :         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        21553800 :         obj = proto;
        4827                 :     }
        4828                 :
        4829        15053561 :     *objp = NULL;
        4830        15053561 :     *propp = NULL;
        4831        15053561 :     return true;
        4832                 : }
        4833                 :
        4834                 : JS_FRIEND_API(JSBool)
        4835        11587319 : js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
        4836                 :                   JSProperty **propp)
        4837                 : {
        4838                 :     /* Convert string indices to integers if appropriate. */
        4839        11587319 :     id = js_CheckForStringIndex(id);
        4840                 :
        4841        11587319 :     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        31630008 : 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        31630008 :     id = js_CheckForStringIndex(id);
        4860                 :
        4861        31630008 :     return LookupPropertyWithFlagsInline(cx, obj, id, flags, objp, propp);
        4862                 : }
        4863                 :
        4864                 : bool
        4865        11249750 : js::FindPropertyHelper(JSContext *cx, PropertyName *name, bool cacheResult, JSObject *scopeChain,
        4866                 :                        JSObject **objp, JSObject **pobjp, JSProperty **propp)
        4867                 : {
        4868        11249750 :     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        11249750 :     obj = scopeChain;
        4875        11249750 :     parent = obj->enclosingScope();
        4876        24083998 :     for (scopeIndex = 0;
        4877                 :          parent
        4878                 :          ? IsCacheableNonGlobalScope(obj)
        4879        10814540 :          : !obj->getOps()->lookupProperty;
        4880                 :          ++scopeIndex) {
        4881        13217488 :         if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &prop))
        4882               0 :             return false;
        4883                 :
        4884        13217488 :         if (prop) {
        4885                 : #ifdef DEBUG
        4886        10999362 :             if (parent) {
        4887          383240 :                 JS_ASSERT(pobj->isNative());
        4888          383240 :                 JS_ASSERT(pobj->getClass() == obj->getClass());
        4889          383240 :                 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           28494 :                     JS_ASSERT(pobj->isClonedBlock());
        4896                 :                 } else {
        4897                 :                     /* Call and DeclEnvClass objects have no prototypes. */
        4898          354746 :                     JS_ASSERT(!obj->getProto());
        4899                 :                 }
        4900          383240 :                 JS_ASSERT(pobj == obj);
        4901                 :             } else {
        4902        10616122 :                 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        10999362 :             if (cacheResult && pobj->isNative()) {
        4911                 :                 JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, pobj,
        4912         7450476 :                                            (Shape *) prop);
        4913                 :             }
        4914                 :
        4915        10999362 :             goto out;
        4916                 :         }
        4917                 :
        4918         2218126 :         if (!parent) {
        4919          198418 :             pobj = NULL;
        4920          198418 :             goto out;
        4921                 :         }
        4922         2019708 :         obj = parent;
        4923         2019708 :         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        11249750 :     JS_ASSERT(!!pobj == !!prop);
        4946        11249750 :     *objp = obj;
        4947        11249750 :     *pobjp = pobj;
        4948        11249750 :     *propp = prop;
        4949        11249750 :     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          182206 : js::FindProperty(JSContext *cx, PropertyName *name, JSObject *scopeChain,
        4958                 :                  JSObject **objp, JSObject **pobjp, JSProperty **propp)
        4959                 : {
        4960          182206 :     return !!FindPropertyHelper(cx, name, false, scopeChain, objp, pobjp, propp);
        4961                 : }
        4962                 :
        4963                 : JSObject *
        4964           59635 : 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           59635 :     JS_ASSERT(scopeChain->enclosingScope() != NULL);
        4971                 :
        4972           59635 :     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          263457 :     for (int scopeIndex = 0;
        4984          170096 :          obj->isGlobal() || IsCacheableNonGlobalScope(obj);
        4985                 :          scopeIndex++) {
        4986                 :         JSObject *pobj;
        4987                 :         JSProperty *prop;
        4988           92217 :         if (!LookupPropertyWithFlags(cx, obj, name, cx->resolveFlags, &pobj, &prop))
        4989               0 :             return NULL;
        4990           92217 :         if (prop) {
        4991           58054 :             if (!pobj->isNative()) {
        4992               0 :                 JS_ASSERT(obj->isGlobal());
        4993               0 :                 return obj;
        4994                 :             }
        4995           58054 :             JS_ASSERT_IF(obj->isScope(), pobj->getClass() == obj->getClass());
        4996           58054 :             JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, pobj, (Shape *) prop);
        4997           58054 :             return obj;
        4998                 :         }
        4999                 :
        5000           34163 :         JSObject *parent = obj->enclosingScope();
        5001           34163 :         if (!parent)
        5002             437 :             return obj;
        5003           33726 :         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        50866532 : js_NativeGetInline(JSContext *cx, JSObject *receiver, JSObject *obj, JSObject *pobj,
        5030                 :                    const Shape *shape, unsigned getHow, Value *vp)
        5031                 : {
        5032        50866532 :     JS_ASSERT(pobj->isNative());
        5033                 :
        5034        50866532 :     if (shape->hasSlot()) {
        5035        47539085 :         *vp = pobj->nativeGetSlot(shape->slot());
        5036        47539085 :         JS_ASSERT(!vp->isMagic());
        5037       121714626 :         JS_ASSERT_IF(!pobj->hasSingletonType() && shape->hasDefaultGetterOrIsMethod(),
        5038       121714626 :                      js::types::TypeHasProperty(cx, pobj->type(), shape->propid(), *vp));
        5039                 :     } else {
        5040         3327447 :         vp->setUndefined();
        5041                 :     }
        5042        50866532 :     if (shape->hasDefaultGetter())
        5043        44576162 :         return true;
        5044                 :
        5045         6290370 :     if (JS_UNLIKELY(shape->isMethod()) && (getHow & JSGET_NO_METHOD_BARRIER))
        5046          898003 :         return true;
        5047                 :
        5048                 :     jsbytecode *pc;
        5049         5392367 :     JSScript *script = cx->stack.currentScript(&pc);
        5050         5392367 :     if (script && script->hasAnalysis()) {
        5051         5353271 :         analyze::Bytecode *code = script->analysis()->maybeCode(pc);
        5052         5353271 :         if (code)
        5053         5353271 :             code->accessGetter = true;
        5054                 :     }
        5055                 :
        5056         5392367 :     if (!shape->get(cx, receiver, obj, pobj, vp))
        5057            3921 :         return false;
        5058                 :
        5059                 :     /* Update slotful shapes according to the value produced by the getter. */
        5060         5388446 :     if (shape->hasSlot() && pobj->nativeContains(cx, *shape)) {
        5061                 :         /* Method shapes were removed by methodReadBarrier under shape->get(). */
        5062         2062812 :         JS_ASSERT(!shape->isMethod());
        5063         2062812 :         pobj->nativeSetSlot(shape->slot(), *vp);
        5064                 :     }
        5065                 :
        5066         5388446 :     return true;
        5067                 : }
        5068                 :
        5069                 : JSBool
        5070         3849615 : js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, const Shape *shape, unsigned getHow,
        5071                 :              Value *vp)
        5072                 : {
        5073         3849615 :     return js_NativeGetInline(cx, obj, obj, pobj, shape, getHow, vp);
        5074                 : }
        5075                 :
        5076                 : JSBool
        5077        17337196 : js_NativeSet(JSContext *cx, JSObject *obj, const Shape *shape, bool added, bool strict, Value *vp)
        5078                 : {
        5079        17337196 :     AddTypePropertyId(cx, obj, shape->propid(), *vp);
        5080                 :
        5081        17337196 :     JS_ASSERT(obj->isNative());
        5082                 :
        5083        17337196 :     if (shape->hasSlot()) {
        5084        17225652 :         uint32_t slot = shape->slot();
        5085                 :
        5086                 :         /* If shape has a stub setter, just store *vp. */
        5087        17225652 :         if (shape->hasDefaultSetter()) {
        5088        17044318 :             if (!added) {
        5089        13452015 :                 if (shape->isMethod() && !obj->methodShapeChange(cx, *shape))
        5090               0 :                     return false;
        5091                 :             }
        5092        17044318 :             obj->nativeSetSlot(slot, *vp);
        5093        17044318 :             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          111544 :         if (!shape->hasGetterValue() && shape->hasDefaultSetter())
        5103               2 :             return js_ReportGetterOnlyAssignment(cx);
        5104                 :     }
        5105                 :
        5106          292876 :     int32_t sample = cx->runtime->propertyRemovals;
        5107          292876 :     if (!shape->set(cx, obj, strict, vp))
        5108             293 :         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          473916 :     if (shape->hasSlot() &&
        5115          181333 :         (JS_LIKELY(cx->runtime->propertyRemovals == sample) ||
        5116               0 :          obj->nativeContains(cx, *shape))) {
        5117          181333 :         obj->setSlot(shape->slot(), *vp);
        5118                 :     }
        5119                 :
        5120          292583 :     return true;
        5121                 : }
        5122                 :
        5123                 : static JS_ALWAYS_INLINE JSBool
        5124        48710114 : 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        48710114 :     id = js_CheckForStringIndex(id);
        5133                 :
        5134        48710114 :     aobj = js_GetProtoIfDenseArray(obj);
        5135                 :     /* This call site is hot -- use the always-inlined variant of LookupPropertyWithFlags(). */
        5136        48710114 :     if (!LookupPropertyWithFlagsInline(cx, aobj, id, cx->resolveFlags, &obj2, &prop))
        5137               0 :         return false;
        5138                 :
        5139        48710114 :     if (!prop) {
        5140         1692752 :         vp->setUndefined();
        5141                 :
        5142         1692752 :         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         1692749 :         if (!vp->isUndefined())
        5147          224577 :             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         1692749 :         if (vp->isUndefined() && ((pc = js_GetCurrentBytecodePC(cx)) != NULL)) {
        5155         1463046 :             JSOp op = (JSOp) *pc;
        5156                 :
        5157         1463046 :             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         1823277 :             if (!cx->hasStrictOption() ||
        5166          360231 :                 cx->stack.currentScript()->warnedAboutUndefinedProp ||
        5167                 :                 (op != JSOP_GETPROP && op != JSOP_GETELEM)) {
        5168         1369129 :                 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           93917 :             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           93917 :             if (cx->resolveFlags == RESOLVE_INFER) {
        5180           93892 :                 pc += js_CodeSpec[op].length;
        5181           93892 :                 if (Detecting(cx, pc))
        5182           93458 :                     return JS_TRUE;
        5183              25 :             } else if (cx->resolveFlags & JSRESOLVE_DETECTING) {
        5184               0 :                 return JS_TRUE;
        5185                 :             }
        5186                 :
        5187             459 :             unsigned flags = JSREPORT_WARNING | JSREPORT_STRICT;
        5188             459 :             cx->stack.currentScript()->warnedAboutUndefinedProp = true;
        5189                 :
        5190                 :             /* Ok, bad undefined property reference: whine about it. */
        5191             459 :             if (!js_ReportValueErrorFlags(cx, flags, JSMSG_UNDEFINED_PROP,
        5192                 :                                           JSDVG_IGNORE_STACK, IdToValue(id),
        5193             459 :                                           NULL, NULL, NULL))
        5194                 :             {
        5195               0 :                 return false;
        5196                 :             }
        5197                 :         }
        5198          230162 :         return JS_TRUE;
        5199                 :     }
        5200                 :
        5201        47017362 :     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        47016917 :     shape = (Shape *) prop;
        5208                 :
        5209        47016917 :     if (getHow & JSGET_CACHE_RESULT)
        5210        10438395 :         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        47016917 :     if (!js_NativeGetInline(cx, receiver, obj, obj2, shape, getHow, vp))
        5214             524 :         return JS_FALSE;
        5215                 :
        5216        47016393 :     return JS_TRUE;
        5217                 : }
        5218                 :
        5219                 : bool
        5220        12620909 : js::GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uint32_t getHow, Value *vp)
        5221                 : {
        5222        12620909 :     return !!js_GetPropertyHelperInline(cx, obj, obj, id, getHow, vp);
        5223                 : }
        5224                 :
        5225                 : JSBool
        5226        36089205 : 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        36089205 :     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         2251493 : js_GetMethod(JSContext *cx, JSObject *obj, jsid id, unsigned getHow, Value *vp)
        5261                 : {
        5262         4502986 :     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
        5263                 :
        5264         2251493 :     GenericIdOp op = obj->getOps()->getGeneric;
        5265         2251493 :     if (!op) {
        5266                 : #if JS_HAS_XML_SUPPORT
        5267         1946964 :         JS_ASSERT(!obj->isXML());
        5268                 : #endif
        5269         1946964 :         return GetPropertyHelper(cx, obj, id, getHow, vp);
        5270                 :     }
        5271                 : #if JS_HAS_XML_SUPPORT
        5272          304529 :     if (obj->isXML())
        5273              99 :         return js_GetXMLMethod(cx, obj, id, vp);
        5274                 : #endif
        5275          304430 :     return op(cx, obj, obj, id, vp);
        5276                 : }
        5277                 :
        5278                 : JS_FRIEND_API(bool)
        5279            2912 : js::CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname)
        5280                 : {
        5281            2912 :     StackFrame *const fp = js_GetTopStackFrame(cx, FRAME_EXPAND_ALL);
        5282            2912 :     if (!fp)
        5283               0 :         return true;
        5284                 :
        5285                 :     /* If neither cx nor the code is strict, then no check is needed. */
        5286            5815 :     if (!(fp->isScriptFrame() && fp->script()->strictModeCode) &&
        5287            2903 :         !cx->hasStrictOption()) {
        5288            1455 :         return true;
        5289                 :     }
        5290                 :
        5291            2914 :     JSAutoByteString bytes(cx, propname);
        5292            1457 :     return !!bytes &&
        5293                 :            JS_ReportErrorFlagsAndNumber(cx,
        5294                 :                                         (JSREPORT_WARNING | JSREPORT_STRICT
        5295                 :                                          | JSREPORT_STRICT_MODE_ERROR),
        5296                 :                                         js_GetErrorMessage, NULL,
        5297            1457 :                                         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            4059 : CloneFunctionForSetMethod(JSContext *cx, Value *vp)
        5334                 : {
        5335            4059 :     JSFunction *fun = vp->toObject().toFunction();
        5336                 :
        5337                 :     /* Clone the fun unless it already has been. */
        5338            4059 :     if (!fun->isClonedMethod()) {
        5339            4059 :         fun = CloneFunctionObject(cx, fun);
        5340            4059 :         if (!fun)
        5341               0 :             return false;
        5342            4059 :         vp->setObject(*fun);
        5343                 :     }
        5344            4059 :     return true;
        5345                 : }
        5346                 :
        5347                 : JSBool
        5348        17313159 : 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        17313159 :     JS_ASSERT((defineHow & ~(DNP_CACHE_RESULT | DNP_SET_METHOD | DNP_UNQUALIFIED)) == 0);
        5362                 :
        5363                 :     /* Convert string indices to integers if appropriate. */
        5364        17313159 :     id = js_CheckForStringIndex(id);
        5365                 :
        5366        17313159 :     if (JS_UNLIKELY(obj->watched())) {
        5367                 :         /* Fire watchpoints, if any. */
        5368            4399 :         WatchpointMap *wpmap = cx->compartment->watchpointMap;
        5369            4399 :         if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, vp))
        5370            2822 :             return false;
        5371                 :
        5372                 :         /* A watchpoint handler may set *vp to a non-function value. */
        5373            1577 :         defineHow &= ~DNP_SET_METHOD;
        5374                 :     }
        5375                 :
        5376        17310337 :     if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &prop))
        5377               0 :         return false;
        5378        17310337 :     if (prop) {
        5379        14346192 :         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         2964145 :         JS_ASSERT(!obj->isBlock());
        5404                 :
        5405         2967057 :         if (obj->isGlobal() &&
        5406                 :             (defineHow & DNP_UNQUALIFIED) &&
        5407            2912 :             !js::CheckUndeclaredVarAssignment(cx, JSID_TO_STRING(id))) {
        5408               9 :             return JS_FALSE;
        5409                 :         }
        5410                 :     }
        5411        17310328 :     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        17310328 :     attrs = JSPROP_ENUMERATE;
        5418        17310328 :     flags = 0;
        5419        17310328 :     shortid = 0;
        5420        17310328 :     clasp = obj->getClass();
        5421        17310328 :     getter = clasp->getProperty;
        5422        17310328 :     setter = clasp->setProperty;
        5423                 :
        5424        17310328 :     if (shape) {
        5425                 :         /* ES5 8.12.4 [[Put]] step 2. */
        5426        14346174 :         if (shape->isAccessorDescriptor()) {
        5427          126465 :             if (shape->hasDefaultSetter())
        5428            1102 :                 return js_ReportGetterOnlyAssignment(cx);
        5429                 :         } else {
        5430        14219709 :             JS_ASSERT(shape->isDataDescriptor());
        5431                 :
        5432        14219709 :             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        14344184 :         attrs = shape->attributes();
        5443        14344184 :         if (pobj != obj) {
        5444                 :             /*
        5445                 :              * We found id in a prototype object: prepare to share or shadow.
        5446                 :              */
        5447          691830 :             if (!shape->shadowable()) {
        5448           56045 :                 if (defineHow & DNP_SET_METHOD) {
        5449            2421 :                     JS_ASSERT(!shape->isMethod());
        5450            2421 :                     if (!CloneFunctionForSetMethod(cx, vp))
        5451               0 :                         return false;
        5452                 :                 }
        5453                 :
        5454           56045 :                 if (defineHow & DNP_CACHE_RESULT)
        5455           41353 :                     JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, pobj, shape);
        5456                 :
        5457           56045 :                 if (shape->hasDefaultSetter() && !shape->hasGetterValue())
        5458               0 :                     return JS_TRUE;
        5459                 :
        5460           56045 :                 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          635785 :             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          635785 :                 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          635785 :             shape = NULL;
        5497                 :         }
        5498                 :
        5499        14288139 :         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            3115 :             if (shape->isMethod()) {
        5508            1675 :                 if (obj->nativeGetMethod(shape) == &vp->toObject())
        5509            1477 :                     return true;
        5510             198 :                 shape = obj->methodShapeChange(cx, *shape);
        5511             198 :                 if (!shape)
        5512               0 :                     return false;
        5513                 :             }
        5514            1638 :             if (!CloneFunctionForSetMethod(cx, vp))
        5515               0 :                 return false;
        5516            1638 :             return js_NativeSet(cx, obj, shape, false, strict, vp);
        5517                 :         }
        5518                 :     }
        5519                 :
        5520        17249178 :     added = false;
        5521        17249178 :     if (!shape) {
        5522         3599939 :         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         3599935 :         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         3599935 :         if ((defineHow & DNP_SET_METHOD) && obj->canHaveMethodBarrier()) {
        5543            2419 :             JS_ASSERT(IsFunctionObject(*vp));
        5544            2419 :             JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
        5545                 :
        5546            2419 :             JSObject *funobj = &vp->toObject();
        5547            2419 :             if (!funobj->toFunction()->isClonedMethod())
        5548            2419 :                 flags |= Shape::METHOD;
        5549                 :         }
        5550                 :
        5551                 :         shape = obj->putProperty(cx, id, getter, setter, SHAPE_INVALID_SLOT,
        5552         3599935 :                                  attrs, flags, shortid);
        5553         3599935 :         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         3599935 :         if (shape->hasSlot())
        5562         3599935 :             obj->nativeSetSlot(shape->slot(), UndefinedValue());
        5563                 :
        5564                 :         /* XXXbe called with obj locked */
        5565         3599935 :         if (!CallAddPropertyHook(cx, clasp, obj, shape, vp)) {
        5566               1 :             obj->removeProperty(cx, id);
        5567               1 :             return JS_FALSE;
        5568                 :         }
        5569         3599934 :         added = true;
        5570                 :     }
        5571                 :
        5572        17249173 :     if ((defineHow & DNP_CACHE_RESULT) && !added)
        5573          630401 :         JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, obj, shape);
        5574                 :
        5575        17249173 :     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           92075 : js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp)
        5590                 : {
        5591                 :     JSProperty *prop;
        5592           92075 :     if (!js_LookupProperty(cx, obj, id, &obj, &prop))
        5593               0 :         return false;
        5594           92075 :     if (!prop) {
        5595               0 :         *attrsp = 0;
        5596               0 :         return true;
        5597                 :     }
        5598           92075 :     if (!obj->isNative())
        5599               0 :         return obj->getGenericAttributes(cx, id, attrsp);
        5600                 :
        5601           92075 :     const Shape *shape = (Shape *)prop;
        5602           92075 :     *attrsp = shape->attributes();
        5603           92075 :     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           40589 : js_SetNativeAttributes(JSContext *cx, JSObject *obj, Shape *shape, unsigned attrs)
        5626                 : {
        5627           40589 :     JS_ASSERT(obj->isNative());
        5628                 :     return !!js_ChangeNativePropertyAttrs(cx, obj, shape, attrs, 0,
        5629           40589 :                                           shape->getter(), shape->setter());
        5630                 : }
        5631                 :
        5632                 : JSBool
        5633           40589 : js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp)
        5634                 : {
        5635                 :     JSProperty *prop;
        5636           40589 :     if (!js_LookupProperty(cx, obj, id, &obj, &prop))
        5637               0 :         return false;
        5638           40589 :     if (!prop)
        5639               0 :         return true;
        5640           40589 :     return obj->isNative()
        5641           40589 :            ? js_SetNativeAttributes(cx, obj, (Shape *) prop, *attrsp)
        5642           81178 :            : 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          245819 : 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          245819 :     rval->setBoolean(true);
        5666                 :
        5667                 :     /* Convert string indices to integers if appropriate. */
        5668          245819 :     id = js_CheckForStringIndex(id);
        5669                 :
        5670          245819 :     if (!js_LookupProperty(cx, obj, id, &proto, &prop))
        5671               0 :         return false;
        5672          245819 :     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          194154 :         return CallJSPropertyOp(cx, obj->getClass()->delProperty, obj, id, rval);
        5678                 :     }
        5679                 :
        5680           51665 :     shape = (Shape *)prop;
        5681           51665 :     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           51638 :     if (shape->hasSlot()) {
        5689           21115 :         const Value &v = obj->nativeGetSlot(shape->slot());
        5690           21115 :         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           21115 :         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           51638 :     if (!CallJSPropertyOp(cx, obj->getClass()->delProperty, obj, shape->getUserId(), rval))
        5723               0 :         return false;
        5724           51638 :     if (rval->isFalse())
        5725               0 :         return true;
        5726                 :
        5727           51638 :     return obj->removeProperty(cx, id) && js_SuppressDeletedProperty(cx, obj, id);
        5728                 : }
        5729                 :
        5730                 : JSBool
        5731           48120 : js_DeleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict)
        5732                 : {
        5733           48120 :     return js_DeleteGeneric(cx, obj, ATOM_TO_JSID(name), rval, strict);
        5734                 : }
        5735                 :
        5736                 : JSBool
        5737          197258 : js_DeleteElement(JSContext *cx, JSObject *obj, uint32_t index, Value *rval, JSBool strict)
        5738                 : {
        5739                 :     jsid id;
        5740          197258 :     if (!IndexToId(cx, index, &id))
        5741               0 :         return false;
        5742          197258 :     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         1130436 : MaybeCallMethod(JSContext *cx, JSObject *obj, jsid id, Value *vp)
        5776                 : {
        5777         1130436 :     if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, vp))
        5778             135 :         return false;
        5779         1130301 :     if (!js_IsCallable(*vp)) {
        5780           20259 :         *vp = ObjectValue(*obj);
        5781           20259 :         return true;
        5782                 :     }
        5783         1110042 :     return Invoke(cx, ObjectValue(*obj), *vp, 0, NULL, vp);
        5784                 : }
        5785                 :
        5786                 : JSBool
        5787          921833 : DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp)
        5788                 : {
        5789          921833 :     JS_ASSERT(hint == JSTYPE_NUMBER || hint == JSTYPE_STRING || hint == JSTYPE_VOID);
        5790          921833 :     JS_ASSERT(!obj->isXML());
        5791                 :
        5792          921833 :     Class *clasp = obj->getClass();
        5793          921833 :     if (hint == JSTYPE_STRING) {
        5794                 :         /* Optimize (new String(...)).toString(). */
        5795           52710 :         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           51396 :         if (!MaybeCallMethod(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.toStringAtom), vp))
        5805            5440 :             return false;
        5806           45956 :         if (vp->isPrimitive())
        5807           45407 :             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         1052377 :         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          687201 :         if (!MaybeCallMethod(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom), vp))
        5830              18 :             return false;
        5831          687183 :         if (vp->isPrimitive())
        5832          295893 :             return true;
        5833                 :
        5834          391290 :         if (!MaybeCallMethod(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.toStringAtom), vp))
        5835              27 :             return false;
        5836          391263 :         if (vp->isPrimitive())
        5837          391191 :             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             329 : 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             329 :     Class *clasp = obj->getClass();
        5862             329 :     JSEnumerateOp enumerate = clasp->enumerate;
        5863             329 :     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             329 :     if (!enumerate(cx, obj))
        5869               0 :         return false;
        5870                 :
        5871                 :     /* Tell InitNativeIterator to treat us like a native object. */
        5872             329 :     JS_ASSERT(enum_op == JSENUMERATE_INIT || enum_op == JSENUMERATE_INIT_ALL);
        5873             329 :     statep->setMagic(JS_NATIVE_ENUMERATE);
        5874             329 :     return true;
        5875                 : }
        5876                 :
        5877                 : namespace js {
        5878                 :
        5879                 : JSBool
        5880          687264 : 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         1374528 :     while (JS_UNLIKELY(obj->isWith()))
        5889               0 :         obj = obj->getProto();
        5890                 :
        5891          687264 :     writing = (mode & JSACC_WRITE) != 0;
        5892          687264 :     switch (mode & JSACC_TYPEMASK) {
        5893                 :       case JSACC_PROTO:
        5894           17069 :         pobj = obj;
        5895           17069 :         if (!writing)
        5896            2152 :             vp->setObjectOrNull(obj->getProto());
        5897           17069 :         *attrsp = JSPROP_PERMANENT;
        5898           17069 :         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          670195 :         if (!obj->lookupGeneric(cx, id, &pobj, &prop))
        5909               0 :             return JS_FALSE;
        5910          670195 :         if (!prop) {
        5911          638053 :             if (!writing)
        5912          638053 :                 vp->setUndefined();
        5913          638053 :             *attrsp = 0;
        5914          638053 :             pobj = obj;
        5915          638053 :             break;
        5916                 :         }
        5917                 :
        5918           32142 :         if (!pobj->isNative()) {
        5919               0 :             if (!writing) {
        5920               0 :                     vp->setUndefined();
        5921               0 :                 *attrsp = 0;
        5922                 :             }
        5923               0 :             break;
        5924                 :         }
        5925                 :
        5926           32142 :         shape = (Shape *)prop;
        5927           32142 :         *attrsp = shape->attributes();
        5928           32142 :         if (!writing) {
        5929           32142 :             if (shape->hasSlot())
        5930             915 :                 *vp = pobj->nativeGetSlot(shape->slot());
        5931                 :             else
        5932           31227 :                 vp->setUndefined();
        5933                 :         }
        5934                 :     }
        5935                 :
        5936          687264 :     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          687264 :     JSCheckAccessOp check = pobj->getClass()->checkAccess;
        5951          687264 :     if (!check)
        5952          687264 :         check = cx->runtime->securityCallbacks->checkObjectAccess;
        5953          687264 :     return !check || check(cx, pobj, id, mode, vp);
        5954                 : }
        5955                 :
        5956                 : }
        5957                 :
        5958                 : JSType
        5959         7638499 : js_TypeOf(JSContext *cx, JSObject *obj)
        5960                 : {
        5961         7638499 :     return obj->isCallable() ? JSTYPE_FUNCTION : JSTYPE_OBJECT;
        5962                 : }
        5963                 :
        5964                 : bool
        5965         1060688 : js_IsDelegate(JSContext *cx, JSObject *obj, const Value &v)
        5966                 : {
        5967         1060688 :     if (v.isPrimitive())
        5968          262122 :         return false;
        5969          798566 :     JSObject *obj2 = &v.toObject();
        5970         1600197 :     while ((obj2 = obj2->getProto()) != NULL) {
        5971          800216 :         if (obj2 == obj)
        5972          797151 :             return true;
        5973                 :     }
        5974            1415 :     return false;
        5975                 : }
        5976                 :
        5977                 : bool
        5978          344257 : js::FindClassPrototype(JSContext *cx, JSObject *scopeobj, JSProtoKey protoKey,
        5979                 :                        JSObject **protop, Class *clasp)
        5980                 : {
        5981                 :     Value v;
        5982          344257 :     if (!js_FindClassObject(cx, scopeobj, protoKey, &v, clasp))
        5983               0 :         return false;
        5984                 :
        5985          344257 :     if (IsFunctionObject(v)) {
        5986           70311 :         JSObject *ctor = &v.toObject();
        5987           70311 :         if (!ctor->getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &v))
        5988               0 :             return false;
        5989                 :     }
        5990                 :
        5991          344257 :     *protop = v.isObject() ? &v.toObject() : NULL;
        5992          344257 :     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         9865312 : js_GetClassPrototype(JSContext *cx, JSObject *scopeobj, JSProtoKey protoKey,
        6001                 :                      JSObject **protop, Class *clasp)
        6002                 : {
        6003         9865312 :     JS_ASSERT(JSProto_Null <= protoKey);
        6004         9865312 :     JS_ASSERT(protoKey < JSProto_LIMIT);
        6005                 :
        6006         9865312 :     if (protoKey != JSProto_Null) {
        6007                 :         GlobalObject *global;
        6008         9599892 :         if (scopeobj) {
        6009         7962660 :             global = &scopeobj->global();
        6010                 :         } else {
        6011         1637232 :             global = GetCurrentGlobal(cx);
        6012         1637232 :             if (!global) {
        6013               0 :                 *protop = NULL;
        6014               0 :                 return true;
        6015                 :             }
        6016                 :         }
        6017         9599892 :         const Value &v = global->getReservedSlot(JSProto_LIMIT + protoKey);
        6018         9599892 :         if (v.isObject()) {
        6019         9521055 :             *protop = &v.toObject();
        6020         9521055 :             return true;
        6021                 :         }
        6022                 :     }
        6023                 :
        6024          344257 :     return FindClassPrototype(cx, scopeobj, protoKey, protop, clasp);
        6025                 : }
        6026                 :
        6027                 : JSObject *
        6028         5059530 : PrimitiveToObject(JSContext *cx, const Value &v)
        6029                 : {
        6030         5059530 :     if (v.isString())
        6031         4796733 :         return StringObject::create(cx, v.toString());
        6032          262797 :     if (v.isNumber())
        6033          256440 :         return NumberObject::create(cx, v.toNumber());
        6034                 :
        6035            6357 :     JS_ASSERT(v.isBoolean());
        6036            6357 :     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         5148915 : js_ValueToObjectOrNull(JSContext *cx, const Value &v, JSObject **objp)
        6052                 : {
        6053                 :     JSObject *obj;
        6054                 :
        6055         5148915 :     if (v.isObjectOrNull()) {
        6056           89876 :         obj = v.toObjectOrNull();
        6057         5059039 :     } else if (v.isUndefined()) {
        6058            1281 :         obj = NULL;
        6059                 :     } else {
        6060         5057758 :         obj = PrimitiveToObject(cx, v);
        6061         5057758 :         if (!obj)
        6062               0 :             return false;
        6063                 :     }
        6064         5148915 :     *objp = obj;
        6065         5148915 :     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         5035934 : js_ValueToNonNullObject(JSContext *cx, const Value &v)
        6093                 : {
        6094                 :     JSObject *obj;
        6095                 :
        6096         5035934 :     if (!js_ValueToObjectOrNull(cx, v, &obj))
        6097               0 :         return NULL;
        6098         5035934 :     if (!obj)
        6099             757 :         js_ReportIsNullOrUndefined(cx, JSDVG_SEARCH_STACK, v, NULL);
        6100         5035934 :     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          446336 : LastConfigurableShape(JSObject *obj)
        6149                 : {
        6150         9489964 :     for (Shape::Range r(obj->lastProperty()->all()); !r.empty(); r.popFront()) {
        6151         9476790 :         const Shape *shape = &r.front();
        6152         9476790 :         if (shape->configurable())
        6153          433162 :             return shape;
        6154                 :     }
        6155           13174 :     return NULL;
        6156                 : }
        6157                 :
        6158                 : bool
        6159          446336 : js_ClearNative(JSContext *cx, JSObject *obj)
        6160                 : {
        6161                 :     /* Remove all configurable properties from obj. */
        6162          879498 :     while (const Shape *shape = LastConfigurableShape(obj)) {
        6163          433162 :         if (!obj->removeProperty(cx, shape->propid()))
        6164               0 :             return false;
        6165                 :     }
        6166                 :
        6167                 :     /* Set all remaining writable plain data properties to undefined. */
        6168          492999 :     for (Shape::Range r(obj->lastProperty()->all()); !r.empty(); r.popFront()) {
        6169          479825 :         const Shape *shape = &r.front();
        6170         1550756 :         if (shape->isDataDescriptor() &&
        6171          479825 :             shape->writable() &&
        6172          295553 :             shape->hasDefaultSetter() &&
        6173          295553 :             shape->hasSlot()) {
        6174          295553 :             obj->nativeSetSlot(shape->slot(), UndefinedValue());
        6175                 :         }
        6176                 :     }
        6177           13174 :     return true;
        6178                 : }
        6179                 :
        6180                 : JSBool
        6181            1116 : 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            1116 :                                         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