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

LCOV - code coverage report
| Current view: | directory - js/src - jsobj.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 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