LCOV - code coverage report
Current view: directory - js/src - jsobj.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 2986 1989 66.6 %
Date: 2012-04-07 Functions: 193 163 84.5 %

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

Generated by: LCOV version 1.7