LCOV - code coverage report
Current view: top level - js/src - jsobj.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1069 2147 49.8 %
Date: 2017-07-14 16:53:18 Functions: 97 148 65.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /*
       8             :  * JS object implementation.
       9             :  */
      10             : 
      11             : #include "jsobjinlines.h"
      12             : 
      13             : #include "mozilla/ArrayUtils.h"
      14             : #include "mozilla/MathAlgorithms.h"
      15             : #include "mozilla/MemoryReporting.h"
      16             : #include "mozilla/SizePrintfMacros.h"
      17             : #include "mozilla/TemplateLib.h"
      18             : 
      19             : #include <string.h>
      20             : 
      21             : #include "jsapi.h"
      22             : #include "jsarray.h"
      23             : #include "jsatom.h"
      24             : #include "jscntxt.h"
      25             : #include "jsexn.h"
      26             : #include "jsfriendapi.h"
      27             : #include "jsfun.h"
      28             : #include "jsgc.h"
      29             : #include "jsiter.h"
      30             : #include "jsnum.h"
      31             : #include "jsopcode.h"
      32             : #include "jsprf.h"
      33             : #include "jsscript.h"
      34             : #include "jsstr.h"
      35             : #include "jstypes.h"
      36             : #include "jsutil.h"
      37             : #include "jswatchpoint.h"
      38             : #include "jswin.h"
      39             : #include "jswrapper.h"
      40             : 
      41             : #include "builtin/Eval.h"
      42             : #include "builtin/Object.h"
      43             : #include "builtin/SymbolObject.h"
      44             : #include "frontend/BytecodeCompiler.h"
      45             : #include "gc/Marking.h"
      46             : #include "gc/Policy.h"
      47             : #include "jit/BaselineJIT.h"
      48             : #include "js/MemoryMetrics.h"
      49             : #include "js/Proxy.h"
      50             : #include "js/UbiNode.h"
      51             : #include "js/UniquePtr.h"
      52             : #include "vm/ArgumentsObject.h"
      53             : #include "vm/Interpreter.h"
      54             : #include "vm/ProxyObject.h"
      55             : #include "vm/RegExpStaticsObject.h"
      56             : #include "vm/Shape.h"
      57             : #include "vm/TypedArrayObject.h"
      58             : 
      59             : #include "jsatominlines.h"
      60             : #include "jsboolinlines.h"
      61             : #include "jscntxtinlines.h"
      62             : #include "jscompartmentinlines.h"
      63             : 
      64             : #include "vm/ArrayObject-inl.h"
      65             : #include "vm/BooleanObject-inl.h"
      66             : #include "vm/Caches-inl.h"
      67             : #include "vm/Interpreter-inl.h"
      68             : #include "vm/NativeObject-inl.h"
      69             : #include "vm/NumberObject-inl.h"
      70             : #include "vm/Shape-inl.h"
      71             : #include "vm/StringObject-inl.h"
      72             : 
      73             : using namespace js;
      74             : using namespace js::gc;
      75             : 
      76             : using mozilla::DebugOnly;
      77             : using mozilla::Maybe;
      78             : 
      79             : void
      80           0 : js::ReportNotObject(JSContext* cx, const Value& v)
      81             : {
      82           0 :     MOZ_ASSERT(!v.isObject());
      83             : 
      84           0 :     RootedValue value(cx, v);
      85           0 :     UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, value, nullptr);
      86           0 :     if (bytes)
      87           0 :         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
      88           0 :                                    bytes.get());
      89           0 : }
      90             : 
      91             : void
      92           0 : js::ReportNotObjectArg(JSContext* cx, const char* nth, const char* fun, HandleValue v)
      93             : {
      94           0 :     MOZ_ASSERT(!v.isObject());
      95             : 
      96           0 :     JSAutoByteString bytes;
      97           0 :     if (const char* chars = ValueToSourceForError(cx, v, bytes)) {
      98             :         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT_ARG,
      99           0 :                                    nth, fun, chars);
     100             :     }
     101           0 : }
     102             : 
     103             : void
     104           0 : js::ReportNotObjectWithName(JSContext* cx, const char* name, HandleValue v)
     105             : {
     106           0 :     MOZ_ASSERT(!v.isObject());
     107             : 
     108           0 :     JSAutoByteString bytes;
     109           0 :     if (const char* chars = ValueToSourceForError(cx, v, bytes)) {
     110             :         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT_NAME,
     111           0 :                                    name, chars);
     112             :     }
     113           0 : }
     114             : 
     115             : JS_PUBLIC_API(const char*)
     116           0 : JS::InformalValueTypeName(const Value& v)
     117             : {
     118           0 :     if (v.isObject())
     119           0 :         return v.toObject().getClass()->name;
     120           0 :     if (v.isString())
     121           0 :         return "string";
     122           0 :     if (v.isSymbol())
     123           0 :         return "symbol";
     124           0 :     if (v.isNumber())
     125           0 :         return "number";
     126           0 :     if (v.isBoolean())
     127           0 :         return "boolean";
     128           0 :     if (v.isNull())
     129           0 :         return "null";
     130           0 :     if (v.isUndefined())
     131           0 :         return "undefined";
     132           0 :     return "value";
     133             : }
     134             : 
     135             : // ES6 draft rev37 6.2.4.4 FromPropertyDescriptor
     136             : JS_PUBLIC_API(bool)
     137         212 : JS::FromPropertyDescriptor(JSContext* cx, Handle<PropertyDescriptor> desc, MutableHandleValue vp)
     138             : {
     139         212 :     AssertHeapIsIdle();
     140         424 :     CHECK_REQUEST(cx);
     141         212 :     assertSameCompartment(cx, desc);
     142             : 
     143             :     // Step 1.
     144         212 :     if (!desc.object()) {
     145           1 :         vp.setUndefined();
     146           1 :         return true;
     147             :     }
     148             : 
     149         211 :     return FromPropertyDescriptorToObject(cx, desc, vp);
     150             : }
     151             : 
     152             : bool
     153         211 : js::FromPropertyDescriptorToObject(JSContext* cx, Handle<PropertyDescriptor> desc,
     154             :                                    MutableHandleValue vp)
     155             : {
     156             :     // Step 2-3.
     157         422 :     RootedObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
     158         211 :     if (!obj)
     159           0 :         return false;
     160             : 
     161         211 :     const JSAtomState& names = cx->names();
     162             : 
     163             :     // Step 4.
     164         211 :     if (desc.hasValue()) {
     165         166 :         if (!DefineProperty(cx, obj, names.value, desc.value()))
     166           0 :             return false;
     167             :     }
     168             : 
     169             :     // Step 5.
     170         422 :     RootedValue v(cx);
     171         211 :     if (desc.hasWritable()) {
     172         166 :         v.setBoolean(desc.writable());
     173         166 :         if (!DefineProperty(cx, obj, names.writable, v))
     174           0 :             return false;
     175             :     }
     176             : 
     177             :     // Step 6.
     178         211 :     if (desc.hasGetterObject()) {
     179          45 :         if (JSObject* get = desc.getterObject())
     180          45 :             v.setObject(*get);
     181             :         else
     182           0 :             v.setUndefined();
     183          45 :         if (!DefineProperty(cx, obj, names.get, v))
     184           0 :             return false;
     185             :     }
     186             : 
     187             :     // Step 7.
     188         211 :     if (desc.hasSetterObject()) {
     189          45 :         if (JSObject* set = desc.setterObject())
     190           0 :             v.setObject(*set);
     191             :         else
     192          45 :             v.setUndefined();
     193          45 :         if (!DefineProperty(cx, obj, names.set, v))
     194           0 :             return false;
     195             :     }
     196             : 
     197             :     // Step 8.
     198         211 :     if (desc.hasEnumerable()) {
     199         211 :         v.setBoolean(desc.enumerable());
     200         211 :         if (!DefineProperty(cx, obj, names.enumerable, v))
     201           0 :             return false;
     202             :     }
     203             : 
     204             :     // Step 9.
     205         211 :     if (desc.hasConfigurable()) {
     206         211 :         v.setBoolean(desc.configurable());
     207         211 :         if (!DefineProperty(cx, obj, names.configurable, v))
     208           0 :             return false;
     209             :     }
     210             : 
     211         211 :     vp.setObject(*obj);
     212         211 :     return true;
     213             : }
     214             : 
     215             : bool
     216        1988 : js::GetFirstArgumentAsObject(JSContext* cx, const CallArgs& args, const char* method,
     217             :                              MutableHandleObject objp)
     218             : {
     219        1988 :     if (args.length() == 0) {
     220             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
     221           0 :                                   method, "0", "s");
     222           0 :         return false;
     223             :     }
     224             : 
     225        1988 :     HandleValue v = args[0];
     226        1988 :     if (!v.isObject()) {
     227           0 :         UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, nullptr);
     228           0 :         if (!bytes)
     229           0 :             return false;
     230           0 :         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
     231           0 :                                    bytes.get(), "not an object");
     232           0 :         return false;
     233             :     }
     234             : 
     235        1988 :     objp.set(&v.toObject());
     236        1988 :     return true;
     237             : }
     238             : 
     239             : static bool
     240       13902 : GetPropertyIfPresent(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp,
     241             :                      bool* foundp)
     242             : {
     243       13902 :     if (!HasProperty(cx, obj, id, foundp))
     244           0 :         return false;
     245       13902 :     if (!*foundp) {
     246        6905 :         vp.setUndefined();
     247        6905 :         return true;
     248             :     }
     249             : 
     250        6997 :     return GetProperty(cx, obj, obj, id, vp);
     251             : }
     252             : 
     253             : bool
     254           0 : js::Throw(JSContext* cx, jsid id, unsigned errorNumber)
     255             : {
     256           0 :     MOZ_ASSERT(js_ErrorFormatString[errorNumber].argCount == 1);
     257             : 
     258           0 :     RootedValue idVal(cx, IdToValue(id));
     259           0 :     JSString* idstr = ValueToSource(cx, idVal);
     260           0 :     if (!idstr)
     261           0 :        return false;
     262           0 :     JSAutoByteString bytes(cx, idstr);
     263           0 :     if (!bytes)
     264           0 :         return false;
     265           0 :     JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber, bytes.ptr());
     266           0 :     return false;
     267             : }
     268             : 
     269             : bool
     270           0 : js::Throw(JSContext* cx, JSObject* obj, unsigned errorNumber)
     271             : {
     272           0 :     if (js_ErrorFormatString[errorNumber].argCount == 1) {
     273           0 :         RootedValue val(cx, ObjectValue(*obj));
     274           0 :         ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber,
     275             :                               JSDVG_IGNORE_STACK, val, nullptr,
     276           0 :                               nullptr, nullptr);
     277             :     } else {
     278           0 :         MOZ_ASSERT(js_ErrorFormatString[errorNumber].argCount == 0);
     279           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, errorNumber);
     280             :     }
     281           0 :     return false;
     282             : }
     283             : 
     284             : 
     285             : /*** PropertyDescriptor operations and DefineProperties ******************************************/
     286             : 
     287             : static Result<>
     288        1564 : CheckCallable(JSContext* cx, JSObject* obj, const char* fieldName)
     289             : {
     290        1564 :     if (obj && !obj->isCallable()) {
     291             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_GET_SET_FIELD,
     292           0 :                                   fieldName);
     293           0 :         return cx->alreadyReportedError();
     294             :     }
     295        1564 :     return Ok();
     296             : }
     297             : 
     298             : bool
     299        2317 : js::ToPropertyDescriptor(JSContext* cx, HandleValue descval, bool checkAccessors,
     300             :                          MutableHandle<PropertyDescriptor> desc)
     301             : {
     302             :     // step 2
     303        4634 :     RootedObject obj(cx, NonNullObjectWithName(cx, "property descriptor", descval));
     304        2317 :     if (!obj)
     305           0 :         return false;
     306             : 
     307             :     // step 3
     308        2317 :     desc.clear();
     309             : 
     310        2317 :     bool found = false;
     311        4634 :     RootedId id(cx);
     312        4634 :     RootedValue v(cx);
     313        2317 :     unsigned attrs = 0;
     314             : 
     315             :     // step 4
     316        2317 :     id = NameToId(cx->names().enumerable);
     317        2317 :     if (!GetPropertyIfPresent(cx, obj, id, &v, &found))
     318           0 :         return false;
     319        2317 :     if (found) {
     320        2066 :         if (ToBoolean(v))
     321        2047 :             attrs |= JSPROP_ENUMERATE;
     322             :     } else {
     323         251 :         attrs |= JSPROP_IGNORE_ENUMERATE;
     324             :     }
     325             : 
     326             :     // step 5
     327        2317 :     id = NameToId(cx->names().configurable);
     328        2317 :     if (!GetPropertyIfPresent(cx, obj, id, &v, &found))
     329           0 :         return false;
     330        2317 :     if (found) {
     331        2022 :         if (!ToBoolean(v))
     332           1 :             attrs |= JSPROP_PERMANENT;
     333             :     } else {
     334         295 :         attrs |= JSPROP_IGNORE_PERMANENT;
     335             :     }
     336             : 
     337             :     // step 6
     338        2317 :     id = NameToId(cx->names().value);
     339        2317 :     if (!GetPropertyIfPresent(cx, obj, id, &v, &found))
     340           0 :         return false;
     341        2317 :     if (found)
     342         764 :         desc.value().set(v);
     343             :     else
     344        1553 :         attrs |= JSPROP_IGNORE_VALUE;
     345             : 
     346             :     // step 7
     347        2317 :     id = NameToId(cx->names().writable);
     348        2317 :     if (!GetPropertyIfPresent(cx, obj, id, &v, &found))
     349           0 :         return false;
     350        2317 :     if (found) {
     351         538 :         if (!ToBoolean(v))
     352          19 :             attrs |= JSPROP_READONLY;
     353             :     } else {
     354        1779 :         attrs |= JSPROP_IGNORE_READONLY;
     355             :     }
     356             : 
     357             :     // step 8
     358             :     bool hasGetOrSet;
     359        2317 :     id = NameToId(cx->names().get);
     360        2317 :     if (!GetPropertyIfPresent(cx, obj, id, &v, &found))
     361           0 :         return false;
     362        2317 :     hasGetOrSet = found;
     363        2317 :     if (found) {
     364        1550 :         if (v.isObject()) {
     365        1550 :             if (checkAccessors)
     366        1550 :                 JS_TRY_OR_RETURN_FALSE(cx, CheckCallable(cx, &v.toObject(), js_getter_str));
     367        1550 :             desc.setGetterObject(&v.toObject());
     368           0 :         } else if (!v.isUndefined()) {
     369             :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_GET_SET_FIELD,
     370           0 :                                       js_getter_str);
     371           0 :             return false;
     372             :         }
     373        1550 :         attrs |= JSPROP_GETTER | JSPROP_SHARED;
     374             :     }
     375             : 
     376             :     // step 9
     377        2317 :     id = NameToId(cx->names().set);
     378        2317 :     if (!GetPropertyIfPresent(cx, obj, id, &v, &found))
     379           0 :         return false;
     380        2317 :     hasGetOrSet |= found;
     381        2317 :     if (found) {
     382          57 :         if (v.isObject()) {
     383          14 :             if (checkAccessors)
     384          14 :                 JS_TRY_OR_RETURN_FALSE(cx, CheckCallable(cx, &v.toObject(), js_setter_str));
     385          14 :             desc.setSetterObject(&v.toObject());
     386          43 :         } else if (!v.isUndefined()) {
     387             :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_GET_SET_FIELD,
     388           0 :                                       js_setter_str);
     389           0 :             return false;
     390             :         }
     391          57 :         attrs |= JSPROP_SETTER | JSPROP_SHARED;
     392             :     }
     393             : 
     394             :     // step 10
     395        2317 :     if (hasGetOrSet) {
     396        1553 :         if (!(attrs & JSPROP_IGNORE_READONLY) || !(attrs & JSPROP_IGNORE_VALUE)) {
     397           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INVALID_DESCRIPTOR);
     398           0 :             return false;
     399             :         }
     400             : 
     401             :         // By convention, these bits are not used on accessor descriptors.
     402        1553 :         attrs &= ~(JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE);
     403             :     }
     404             : 
     405        2317 :     desc.setAttributes(attrs);
     406        2317 :     MOZ_ASSERT_IF(attrs & JSPROP_READONLY, !(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
     407        2317 :     MOZ_ASSERT_IF(attrs & (JSPROP_GETTER | JSPROP_SETTER), attrs & JSPROP_SHARED);
     408        2317 :     return true;
     409             : }
     410             : 
     411             : Result<>
     412           0 : js::CheckPropertyDescriptorAccessors(JSContext* cx, Handle<PropertyDescriptor> desc)
     413             : {
     414           0 :     if (desc.hasGetterObject())
     415           0 :         MOZ_TRY(CheckCallable(cx, desc.getterObject(), js_getter_str));
     416             : 
     417           0 :     if (desc.hasSetterObject())
     418           0 :         MOZ_TRY(CheckCallable(cx, desc.setterObject(), js_setter_str));
     419             : 
     420           0 :     return Ok();
     421             : }
     422             : 
     423             : void
     424      116379 : js::CompletePropertyDescriptor(MutableHandle<PropertyDescriptor> desc)
     425             : {
     426      116379 :     desc.assertValid();
     427             : 
     428      116378 :     if (desc.isGenericDescriptor() || desc.isDataDescriptor()) {
     429      101707 :         if (!desc.hasWritable())
     430         226 :             desc.attributesRef() |= JSPROP_READONLY;
     431      101707 :         desc.attributesRef() &= ~(JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE);
     432             :     } else {
     433       14671 :         if (!desc.hasGetterObject())
     434          34 :             desc.setGetterObject(nullptr);
     435       14671 :         if (!desc.hasSetterObject())
     436        9144 :             desc.setSetterObject(nullptr);
     437       14671 :         desc.attributesRef() |= JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
     438             :     }
     439      116378 :     if (!desc.hasConfigurable())
     440         290 :         desc.attributesRef() |= JSPROP_PERMANENT;
     441      116378 :     desc.attributesRef() &= ~(JSPROP_IGNORE_PERMANENT | JSPROP_IGNORE_ENUMERATE);
     442             : 
     443      116378 :     desc.assertComplete();
     444      116378 : }
     445             : 
     446             : bool
     447           0 : js::ReadPropertyDescriptors(JSContext* cx, HandleObject props, bool checkAccessors,
     448             :                             AutoIdVector* ids, MutableHandle<PropertyDescriptorVector> descs)
     449             : {
     450           0 :     if (!GetPropertyKeys(cx, props, JSITER_OWNONLY | JSITER_SYMBOLS, ids))
     451           0 :         return false;
     452             : 
     453           0 :     RootedId id(cx);
     454           0 :     for (size_t i = 0, len = ids->length(); i < len; i++) {
     455           0 :         id = (*ids)[i];
     456           0 :         Rooted<PropertyDescriptor> desc(cx);
     457           0 :         RootedValue v(cx);
     458           0 :         if (!GetProperty(cx, props, props, id, &v) ||
     459           0 :             !ToPropertyDescriptor(cx, v, checkAccessors, &desc) ||
     460           0 :             !descs.append(desc))
     461             :         {
     462           0 :             return false;
     463             :         }
     464             :     }
     465           0 :     return true;
     466             : }
     467             : 
     468             : /*** Seal and freeze *****************************************************************************/
     469             : 
     470             : static unsigned
     471        2415 : GetSealedOrFrozenAttributes(unsigned attrs, IntegrityLevel level)
     472             : {
     473             :     /* Make all attributes permanent; if freezing, make data attributes read-only. */
     474        2415 :     if (level == IntegrityLevel::Frozen && !(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
     475        1815 :         return JSPROP_PERMANENT | JSPROP_READONLY;
     476         600 :     return JSPROP_PERMANENT;
     477             : }
     478             : 
     479             : /* ES6 draft rev 29 (6 Dec 2014) 7.3.13. */
     480             : bool
     481        2396 : js::SetIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level)
     482             : {
     483        2396 :     assertSameCompartment(cx, obj);
     484             : 
     485             :     // Steps 3-5. (Steps 1-2 are redundant assertions.)
     486        2396 :     if (!PreventExtensions(cx, obj, level))
     487           0 :         return false;
     488             : 
     489             :     // Steps 6-9, loosely interpreted.
     490        9565 :     if (obj->isNative() && !obj->as<NativeObject>().inDictionaryMode() &&
     491        7154 :         !obj->is<TypedArrayObject>() && !obj->is<MappedArgumentsObject>())
     492             :     {
     493        2379 :         HandleNativeObject nobj = obj.as<NativeObject>();
     494             : 
     495             :         // Seal/freeze non-dictionary objects by constructing a new shape
     496             :         // hierarchy mirroring the original one, which can be shared if many
     497             :         // objects with the same structure are sealed/frozen. If we use the
     498             :         // generic path below then any non-empty object will be converted to
     499             :         // dictionary mode.
     500        9516 :         RootedShape last(cx, EmptyShape::getInitialShape(cx, nobj->getClass(),
     501        4758 :                                                          nobj->taggedProto(),
     502        2379 :                                                          nobj->numFixedSlots(),
     503        7137 :                                                          nobj->lastProperty()->getObjectFlags()));
     504        2379 :         if (!last)
     505           0 :             return false;
     506             : 
     507             :         // Get an in-order list of the shapes in this object.
     508             :         using ShapeVec = GCVector<Shape*, 8>;
     509        4758 :         Rooted<ShapeVec> shapes(cx, ShapeVec(cx));
     510        4794 :         for (Shape::Range<NoGC> r(nobj->lastProperty()); !r.empty(); r.popFront()) {
     511        2415 :             if (!shapes.append(&r.front()))
     512           0 :                 return false;
     513             :         }
     514        2379 :         Reverse(shapes.begin(), shapes.end());
     515             : 
     516        4794 :         for (Shape* shape : shapes) {
     517        4830 :             Rooted<StackShape> child(cx, StackShape(shape));
     518        2415 :             child.setAttrs(child.attrs() | GetSealedOrFrozenAttributes(child.attrs(), level));
     519             : 
     520        2415 :             if (!JSID_IS_EMPTY(child.get().propid) && level == IntegrityLevel::Frozen)
     521        2382 :                 MarkTypePropertyNonWritable(cx, nobj, child.get().propid);
     522             : 
     523        2415 :             last = cx->zone()->propertyTree().getChild(cx, last, child);
     524        2415 :             if (!last)
     525           0 :                 return false;
     526             :         }
     527             : 
     528        2379 :         MOZ_ASSERT(nobj->lastProperty()->slotSpan() == last->slotSpan());
     529        2379 :         JS_ALWAYS_TRUE(nobj->setLastProperty(cx, last));
     530             : 
     531             :         // Ordinarily ArraySetLength handles this, but we're going behind its back
     532             :         // right now, so we must do this manually.
     533        2379 :         if (level == IntegrityLevel::Frozen && obj->is<ArrayObject>()) {
     534           8 :             if (!obj->as<ArrayObject>().maybeCopyElementsForWrite(cx))
     535           0 :                 return false;
     536           8 :             obj->as<ArrayObject>().setNonWritableLength(cx);
     537             :         }
     538             :     } else {
     539             :         // Steps 6-7.
     540          34 :         AutoIdVector keys(cx);
     541          17 :         if (!GetPropertyKeys(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY | JSITER_SYMBOLS, &keys))
     542           0 :             return false;
     543             : 
     544          34 :         RootedId id(cx);
     545          34 :         Rooted<PropertyDescriptor> desc(cx);
     546             : 
     547             :         const unsigned AllowConfigure = JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_READONLY |
     548          17 :                                         JSPROP_IGNORE_VALUE;
     549          17 :         const unsigned AllowConfigureAndWritable = AllowConfigure & ~JSPROP_IGNORE_READONLY;
     550             : 
     551             :         // 8.a/9.a. The two different loops are merged here.
     552         278 :         for (size_t i = 0; i < keys.length(); i++) {
     553         261 :             id = keys[i];
     554             : 
     555         261 :             if (level == IntegrityLevel::Sealed) {
     556             :                 // 8.a.i.
     557           0 :                 desc.setAttributes(AllowConfigure | JSPROP_PERMANENT);
     558             :             } else {
     559             :                 // 9.a.i-ii.
     560         522 :                 Rooted<PropertyDescriptor> currentDesc(cx);
     561         261 :                 if (!GetOwnPropertyDescriptor(cx, obj, id, &currentDesc))
     562           0 :                     return false;
     563             : 
     564             :                 // 9.a.iii.
     565         261 :                 if (!currentDesc.object())
     566           0 :                     continue;
     567             : 
     568             :                 // 9.a.iii.1-2
     569         261 :                 if (currentDesc.isAccessorDescriptor())
     570          55 :                     desc.setAttributes(AllowConfigure | JSPROP_PERMANENT);
     571             :                 else
     572         206 :                     desc.setAttributes(AllowConfigureAndWritable | JSPROP_PERMANENT | JSPROP_READONLY);
     573             :             }
     574             : 
     575             :             // 8.a.i-ii. / 9.a.iii.3-4
     576         261 :             if (!DefineProperty(cx, obj, id, desc))
     577           0 :                 return false;
     578             :         }
     579             :     }
     580             : 
     581             :     // Finally, freeze the dense elements.
     582        2396 :     if (level == IntegrityLevel::Frozen && obj->isNative()) {
     583        2390 :         if (!ObjectElements::FreezeElements(cx, obj.as<NativeObject>()))
     584           0 :             return false;
     585             :     }
     586             : 
     587        2396 :     return true;
     588             : }
     589             : 
     590             : // ES6 draft rev33 (12 Feb 2015) 7.3.15
     591             : bool
     592          32 : js::TestIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level, bool* result)
     593             : {
     594             :     // Steps 3-6. (Steps 1-2 are redundant assertions.)
     595             :     bool status;
     596          32 :     if (!IsExtensible(cx, obj, &status))
     597           0 :         return false;
     598          32 :     if (status) {
     599          32 :         *result = false;
     600          32 :         return true;
     601             :     }
     602             : 
     603             :     // Steps 7-8.
     604           0 :     AutoIdVector props(cx);
     605           0 :     if (!GetPropertyKeys(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY | JSITER_SYMBOLS, &props))
     606           0 :         return false;
     607             : 
     608             :     // Step 9.
     609           0 :     RootedId id(cx);
     610           0 :     Rooted<PropertyDescriptor> desc(cx);
     611           0 :     for (size_t i = 0, len = props.length(); i < len; i++) {
     612           0 :         id = props[i];
     613             : 
     614             :         // Steps 9.a-b.
     615           0 :         if (!GetOwnPropertyDescriptor(cx, obj, id, &desc))
     616           0 :             return false;
     617             : 
     618             :         // Step 9.c.
     619           0 :         if (!desc.object())
     620           0 :             continue;
     621             : 
     622             :         // Steps 9.c.i-ii.
     623           0 :         if (desc.configurable() ||
     624           0 :             (level == IntegrityLevel::Frozen && desc.isDataDescriptor() && desc.writable()))
     625             :         {
     626           0 :             *result = false;
     627           0 :             return true;
     628             :         }
     629             :     }
     630             : 
     631             :     // Step 10.
     632           0 :     *result = true;
     633           0 :     return true;
     634             : }
     635             : 
     636             : 
     637             : /* * */
     638             : 
     639             : /*
     640             :  * Get the GC kind to use for scripted 'new' on the given class.
     641             :  * FIXME bug 547327: estimate the size from the allocation site.
     642             :  */
     643             : static inline gc::AllocKind
     644          44 : NewObjectGCKind(const js::Class* clasp)
     645             : {
     646          44 :     if (clasp == &ArrayObject::class_)
     647           0 :         return gc::AllocKind::OBJECT8;
     648          44 :     if (clasp == &JSFunction::class_)
     649           0 :         return gc::AllocKind::OBJECT2;
     650          44 :     return gc::AllocKind::OBJECT4;
     651             : }
     652             : 
     653             : static inline JSObject*
     654      124286 : NewObject(JSContext* cx, HandleObjectGroup group, gc::AllocKind kind,
     655             :           NewObjectKind newKind, uint32_t initialShapeFlags = 0)
     656             : {
     657      124286 :     const Class* clasp = group->clasp();
     658             : 
     659      124287 :     MOZ_ASSERT(clasp != &ArrayObject::class_);
     660      124287 :     MOZ_ASSERT_IF(clasp == &JSFunction::class_,
     661             :                   kind == AllocKind::FUNCTION || kind == AllocKind::FUNCTION_EXTENDED);
     662             : 
     663             :     // For objects which can have fixed data following the object, only use
     664             :     // enough fixed slots to cover the number of reserved slots in the object,
     665             :     // regardless of the allocation kind specified.
     666      124287 :     size_t nfixed = ClassCanHaveFixedData(clasp)
     667      124287 :                     ? GetGCKindSlots(gc::GetGCObjectKind(clasp), clasp)
     668      124287 :                     : GetGCKindSlots(kind, clasp);
     669             : 
     670      248575 :     RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, group->proto(), nfixed,
     671      248576 :                                                       initialShapeFlags));
     672      124288 :     if (!shape)
     673           0 :         return nullptr;
     674             : 
     675      124288 :     gc::InitialHeap heap = GetInitialHeap(newKind, clasp);
     676             : 
     677             :     JSObject* obj;
     678      124288 :     if (MOZ_LIKELY(clasp->isNative())) {
     679      124288 :         JS_TRY_VAR_OR_RETURN_NULL(cx, obj, NativeObject::create(cx, kind, heap, shape, group));
     680             :     } else {
     681           0 :         MOZ_ASSERT(IsTypedObjectClass(clasp));
     682           0 :         JS_TRY_VAR_OR_RETURN_NULL(cx, obj, TypedObject::create(cx, kind, heap, shape, group));
     683             :     }
     684             : 
     685      124289 :     if (newKind == SingletonObject) {
     686      150360 :         RootedObject nobj(cx, obj);
     687       75180 :         if (!JSObject::setSingleton(cx, nobj))
     688           0 :             return nullptr;
     689       75180 :         obj = nobj;
     690             :     }
     691             : 
     692      124289 :     probes::CreateObject(cx, obj);
     693      124289 :     return obj;
     694             : }
     695             : 
     696             : void
     697        5132 : NewObjectCache::fillProto(EntryIndex entry, const Class* clasp, js::TaggedProto proto,
     698             :                           gc::AllocKind kind, NativeObject* obj)
     699             : {
     700        5132 :     MOZ_ASSERT_IF(proto.isObject(), !proto.toObject()->is<GlobalObject>());
     701        5132 :     MOZ_ASSERT(obj->taggedProto() == proto);
     702        5132 :     return fill(entry, clasp, proto.raw(), kind, obj);
     703             : }
     704             : 
     705             : bool
     706       30926 : js::NewObjectWithTaggedProtoIsCachable(JSContext* cx, Handle<TaggedProto> proto,
     707             :                                        NewObjectKind newKind, const Class* clasp)
     708             : {
     709       61169 :     return !cx->helperThread() &&
     710       53138 :            proto.isObject() &&
     711       15822 :            newKind == GenericObject &&
     712       62570 :            clasp->isNative() &&
     713       46748 :            !proto.toObject()->is<GlobalObject>();
     714             : }
     715             : 
     716             : JSObject*
     717       25170 : js::NewObjectWithGivenTaggedProto(JSContext* cx, const Class* clasp,
     718             :                                   Handle<TaggedProto> proto,
     719             :                                   gc::AllocKind allocKind, NewObjectKind newKind,
     720             :                                   uint32_t initialShapeFlags)
     721             : {
     722       25170 :     if (CanBeFinalizedInBackground(allocKind, clasp))
     723        7965 :         allocKind = GetBackgroundAllocKind(allocKind);
     724             : 
     725       25170 :     bool isCachable = NewObjectWithTaggedProtoIsCachable(cx, proto, newKind, clasp);
     726       25170 :     if (isCachable) {
     727       11656 :         NewObjectCache& cache = cx->caches().newObjectCache;
     728       11656 :         NewObjectCache::EntryIndex entry = -1;
     729       11656 :         if (cache.lookupProto(clasp, proto.toObject(), allocKind, &entry)) {
     730        7413 :             JSObject* obj = cache.newObjectFromHit(cx, entry, GetInitialHeap(newKind, clasp));
     731        7413 :             if (obj)
     732        7413 :                 return obj;
     733             :         }
     734             :     }
     735             : 
     736       35514 :     RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, clasp, proto, nullptr));
     737       17757 :     if (!group)
     738           0 :         return nullptr;
     739             : 
     740       35514 :     RootedObject obj(cx, NewObject(cx, group, allocKind, newKind, initialShapeFlags));
     741       17757 :     if (!obj)
     742           0 :         return nullptr;
     743             : 
     744       17757 :     if (isCachable && !obj->as<NativeObject>().hasDynamicSlots()) {
     745        4243 :         NewObjectCache& cache = cx->caches().newObjectCache;
     746        4243 :         NewObjectCache::EntryIndex entry = -1;
     747        4243 :         cache.lookupProto(clasp, proto.toObject(), allocKind, &entry);
     748        4243 :         cache.fillProto(entry, clasp, proto, allocKind, &obj->as<NativeObject>());
     749             :     }
     750             : 
     751       17757 :     return obj;
     752             : }
     753             : 
     754             : static bool
     755      114474 : NewObjectIsCachable(JSContext* cx, NewObjectKind newKind, const Class* clasp)
     756             : {
     757      222974 :     return !cx->helperThread() &&
     758      129815 :            newKind == GenericObject &&
     759      129815 :            clasp->isNative();
     760             : }
     761             : 
     762             : JSObject*
     763      116982 : js::NewObjectWithClassProtoCommon(JSContext* cx, const Class* clasp, HandleObject protoArg,
     764             :                                   gc::AllocKind allocKind, NewObjectKind newKind)
     765             : {
     766      116982 :     if (protoArg)
     767        2508 :         return NewObjectWithGivenTaggedProto(cx, clasp, AsTaggedProto(protoArg), allocKind, newKind);
     768             : 
     769      114474 :     if (CanBeFinalizedInBackground(allocKind, clasp))
     770        5512 :         allocKind = GetBackgroundAllocKind(allocKind);
     771             : 
     772      114474 :     Handle<GlobalObject*> global = cx->global();
     773             : 
     774      114474 :     bool isCachable = NewObjectIsCachable(cx, newKind, clasp);
     775      114476 :     if (isCachable) {
     776       15339 :         NewObjectCache& cache = cx->caches().newObjectCache;
     777       15339 :         NewObjectCache::EntryIndex entry = -1;
     778       15339 :         if (cache.lookupGlobal(clasp, global, allocKind, &entry)) {
     779       13439 :             gc::InitialHeap heap = GetInitialHeap(newKind, clasp);
     780       13439 :             JSObject* obj = cache.newObjectFromHit(cx, entry, heap);
     781       13439 :             if (obj)
     782       13439 :                 return obj;
     783             :         }
     784             :     }
     785             : 
     786             :     // Find the appropriate proto for clasp. Built-in classes have a cached
     787             :     // proto on cx->global(); all others get %ObjectPrototype%.
     788      101037 :     JSProtoKey protoKey = JSCLASS_CACHED_PROTO_KEY(clasp);
     789      101037 :     if (protoKey == JSProto_Null)
     790         144 :         protoKey = JSProto_Object;
     791             : 
     792      202074 :     RootedObject proto(cx);
     793      101037 :     if (!GetBuiltinPrototype(cx, protoKey, &proto))
     794           0 :         return nullptr;
     795             : 
     796      202073 :     RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, clasp, AsTaggedProto(proto)));
     797      101036 :     if (!group)
     798           0 :         return nullptr;
     799             : 
     800      101036 :     JSObject* obj = NewObject(cx, group, allocKind, newKind);
     801      101037 :     if (!obj)
     802           0 :         return nullptr;
     803             : 
     804      101037 :     if (isCachable && !obj->as<NativeObject>().hasDynamicSlots()) {
     805        1900 :         NewObjectCache& cache = cx->caches().newObjectCache;
     806        1900 :         NewObjectCache::EntryIndex entry = -1;
     807        1900 :         cache.lookupGlobal(clasp, global, allocKind, &entry);
     808        1900 :         cache.fillGlobal(entry, clasp, global, allocKind,
     809        3800 :                          &obj->as<NativeObject>());
     810             :     }
     811             : 
     812      101037 :     return obj;
     813             : }
     814             : 
     815             : static bool
     816        5687 : NewObjectWithGroupIsCachable(JSContext* cx, HandleObjectGroup group,
     817             :                              NewObjectKind newKind)
     818             : {
     819       11309 :     return group->proto().isObject() &&
     820         249 :            newKind == GenericObject &&
     821         498 :            group->clasp()->isNative() &&
     822        6185 :            (!group->newScript() || group->newScript()->analyzed()) &&
     823        5936 :            !cx->helperThread();
     824             : }
     825             : 
     826             : /*
     827             :  * Create a plain object with the specified group. This bypasses getNewGroup to
     828             :  * avoid losing creation site information for objects made by scripted 'new'.
     829             :  */
     830             : JSObject*
     831        5687 : js::NewObjectWithGroupCommon(JSContext* cx, HandleObjectGroup group,
     832             :                              gc::AllocKind allocKind, NewObjectKind newKind)
     833             : {
     834        5687 :     MOZ_ASSERT(gc::IsObjectAllocKind(allocKind));
     835        5687 :     if (CanBeFinalizedInBackground(allocKind, group->clasp()))
     836        5687 :         allocKind = GetBackgroundAllocKind(allocKind);
     837             : 
     838        5687 :     bool isCachable = NewObjectWithGroupIsCachable(cx, group, newKind);
     839        5687 :     if (isCachable) {
     840         249 :         NewObjectCache& cache = cx->caches().newObjectCache;
     841         249 :         NewObjectCache::EntryIndex entry = -1;
     842         249 :         if (cache.lookupGroup(group, allocKind, &entry)) {
     843         192 :             JSObject* obj = cache.newObjectFromHit(cx, entry,
     844         384 :                                                    GetInitialHeap(newKind, group->clasp()));
     845         192 :             if (obj)
     846         192 :                 return obj;
     847             :         }
     848             :     }
     849             : 
     850        5495 :     JSObject* obj = NewObject(cx, group, allocKind, newKind);
     851        5495 :     if (!obj)
     852           0 :         return nullptr;
     853             : 
     854        5495 :     if (isCachable && !obj->as<NativeObject>().hasDynamicSlots()) {
     855          57 :         NewObjectCache& cache = cx->caches().newObjectCache;
     856          57 :         NewObjectCache::EntryIndex entry = -1;
     857          57 :         cache.lookupGroup(group, allocKind, &entry);
     858          57 :         cache.fillGroup(entry, group, allocKind, &obj->as<NativeObject>());
     859             :     }
     860             : 
     861        5495 :     return obj;
     862             : }
     863             : 
     864             : bool
     865          17 : js::NewObjectScriptedCall(JSContext* cx, MutableHandleObject pobj)
     866             : {
     867             :     jsbytecode* pc;
     868          34 :     RootedScript script(cx, cx->currentScript(&pc));
     869          17 :     gc::AllocKind allocKind = NewObjectGCKind(&PlainObject::class_);
     870          17 :     NewObjectKind newKind = GenericObject;
     871          17 :     if (script && ObjectGroup::useSingletonForAllocationSite(script, pc, &PlainObject::class_))
     872           0 :         newKind = SingletonObject;
     873          34 :     RootedObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx, allocKind, newKind));
     874          17 :     if (!obj)
     875           0 :         return false;
     876             : 
     877          17 :     if (script) {
     878             :         /* Try to specialize the group of the object to the scripted call site. */
     879           0 :         if (!ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, obj, newKind == SingletonObject))
     880           0 :             return false;
     881             :     }
     882             : 
     883          17 :     pobj.set(obj);
     884          17 :     return true;
     885             : }
     886             : 
     887             : JSObject*
     888           0 : js::CreateThis(JSContext* cx, const Class* newclasp, HandleObject callee)
     889             : {
     890           0 :     RootedObject proto(cx);
     891           0 :     if (!GetPrototypeFromConstructor(cx, callee, &proto))
     892           0 :         return nullptr;
     893           0 :     gc::AllocKind kind = NewObjectGCKind(newclasp);
     894           0 :     return NewObjectWithClassProto(cx, newclasp, proto, kind);
     895             : }
     896             : 
     897             : static inline JSObject*
     898         491 : CreateThisForFunctionWithGroup(JSContext* cx, HandleObjectGroup group,
     899             :                                NewObjectKind newKind)
     900             : {
     901         491 :     if (group->maybeUnboxedLayout() && newKind != SingletonObject)
     902           0 :         return UnboxedPlainObject::create(cx, group, newKind);
     903             : 
     904         491 :     if (TypeNewScript* newScript = group->newScript()) {
     905         464 :         if (newScript->analyzed()) {
     906             :             // The definite properties analysis has been performed for this
     907             :             // group, so get the shape and alloc kind to use from the
     908             :             // TypeNewScript's template.
     909          36 :             RootedPlainObject templateObject(cx, newScript->templateObject());
     910          18 :             MOZ_ASSERT(templateObject->group() == group);
     911             : 
     912          36 :             RootedPlainObject res(cx, CopyInitializerObject(cx, templateObject, newKind));
     913          18 :             if (!res)
     914           0 :                 return nullptr;
     915             : 
     916          18 :             if (newKind == SingletonObject) {
     917           0 :                 Rooted<TaggedProto> proto(cx, TaggedProto(templateObject->staticPrototype()));
     918           0 :                 if (!JSObject::splicePrototype(cx, res, &PlainObject::class_, proto))
     919           0 :                     return nullptr;
     920             :             } else {
     921          18 :                 res->setGroup(group);
     922             :             }
     923          18 :             return res;
     924             :         }
     925             : 
     926             :         // The initial objects registered with a TypeNewScript can't be in the
     927             :         // nursery.
     928         446 :         if (newKind == GenericObject)
     929         446 :             newKind = TenuredObject;
     930             : 
     931             :         // Not enough objects with this group have been created yet, so make a
     932             :         // plain object and register it with the group. Use the maximum number
     933             :         // of fixed slots, as is also required by the TypeNewScript.
     934         446 :         gc::AllocKind allocKind = GuessObjectGCKind(NativeObject::MAX_FIXED_SLOTS);
     935         446 :         PlainObject* res = NewObjectWithGroup<PlainObject>(cx, group, allocKind, newKind);
     936         446 :         if (!res)
     937           0 :             return nullptr;
     938             : 
     939             :         // Make sure group->newScript is still there.
     940         446 :         if (newKind != SingletonObject && group->newScript())
     941         446 :             group->newScript()->registerNewObject(res);
     942             : 
     943         446 :         return res;
     944             :     }
     945             : 
     946          27 :     gc::AllocKind allocKind = NewObjectGCKind(&PlainObject::class_);
     947             : 
     948          27 :     if (newKind == SingletonObject) {
     949           0 :         Rooted<TaggedProto> protoRoot(cx, group->proto());
     950           0 :         return NewObjectWithGivenTaggedProto(cx, &PlainObject::class_, protoRoot, allocKind, newKind);
     951             :     }
     952          27 :     return NewObjectWithGroup<PlainObject>(cx, group, allocKind, newKind);
     953             : }
     954             : 
     955             : JSObject*
     956         492 : js::CreateThisForFunctionWithProto(JSContext* cx, HandleObject callee, HandleObject newTarget,
     957             :                                    HandleObject proto, NewObjectKind newKind /* = GenericObject */)
     958             : {
     959         984 :     RootedObject res(cx);
     960             : 
     961         492 :     if (proto) {
     962         982 :         RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, nullptr, TaggedProto(proto),
     963        1473 :                                                                  newTarget));
     964         491 :         if (!group)
     965           0 :             return nullptr;
     966             : 
     967         491 :         if (group->newScript() && !group->newScript()->analyzed()) {
     968             :             bool regenerate;
     969         447 :             if (!group->newScript()->maybeAnalyze(cx, group, &regenerate))
     970           0 :                 return nullptr;
     971         447 :             if (regenerate) {
     972             :                 // The script was analyzed successfully and may have changed
     973             :                 // the new type table, so refetch the group.
     974           2 :                 group = ObjectGroup::defaultNewGroup(cx, nullptr, TaggedProto(proto),
     975           2 :                                                      newTarget);
     976           1 :                 MOZ_ASSERT(group && group->newScript());
     977             :             }
     978             :         }
     979             : 
     980         491 :         res = CreateThisForFunctionWithGroup(cx, group, newKind);
     981             :     } else {
     982           1 :         res = NewBuiltinClassInstance<PlainObject>(cx, newKind);
     983             :     }
     984             : 
     985         492 :     if (res) {
     986         492 :         JSScript* script = JSFunction::getOrCreateScript(cx, callee.as<JSFunction>());
     987         492 :         if (!script)
     988           0 :             return nullptr;
     989         492 :         TypeScript::SetThis(cx, script, TypeSet::ObjectType(res));
     990             :     }
     991             : 
     992         492 :     return res;
     993             : }
     994             : 
     995             : bool
     996         519 : js::GetPrototypeFromConstructor(JSContext* cx, HandleObject newTarget, MutableHandleObject proto)
     997             : {
     998        1038 :     RootedValue protov(cx);
     999         519 :     if (!GetProperty(cx, newTarget, newTarget, cx->names().prototype, &protov))
    1000           0 :         return false;
    1001         519 :     proto.set(protov.isObject() ? &protov.toObject() : nullptr);
    1002         519 :     return true;
    1003             : }
    1004             : 
    1005             : JSObject*
    1006         492 : js::CreateThisForFunction(JSContext* cx, HandleObject callee, HandleObject newTarget,
    1007             :                           NewObjectKind newKind)
    1008             : {
    1009         984 :     RootedObject proto(cx);
    1010         492 :     if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
    1011           0 :         return nullptr;
    1012             : 
    1013         492 :     JSObject* obj = CreateThisForFunctionWithProto(cx, callee, newTarget, proto, newKind);
    1014             : 
    1015         492 :     if (obj && newKind == SingletonObject) {
    1016           0 :         RootedPlainObject nobj(cx, &obj->as<PlainObject>());
    1017             : 
    1018             :         /* Reshape the singleton before passing it as the 'this' value. */
    1019           0 :         NativeObject::clear(cx, nobj);
    1020             : 
    1021           0 :         JSScript* calleeScript = callee->as<JSFunction>().nonLazyScript();
    1022           0 :         TypeScript::SetThis(cx, calleeScript, TypeSet::ObjectType(nobj));
    1023             : 
    1024           0 :         return nobj;
    1025             :     }
    1026             : 
    1027         492 :     return obj;
    1028             : }
    1029             : 
    1030             : /* static */ bool
    1031         386 : JSObject::nonNativeSetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
    1032             :                                HandleValue receiver, ObjectOpResult& result)
    1033             : {
    1034         772 :     RootedValue value(cx, v);
    1035         386 :     if (MOZ_UNLIKELY(obj->watched())) {
    1036           0 :         WatchpointMap* wpmap = cx->compartment()->watchpointMap;
    1037           0 :         if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, &value))
    1038           0 :             return false;
    1039             :     }
    1040         386 :     return obj->getOpsSetProperty()(cx, obj, id, value, receiver, result);
    1041             : }
    1042             : 
    1043             : /* static */ bool
    1044           0 : JSObject::nonNativeSetElement(JSContext* cx, HandleObject obj, uint32_t index, HandleValue v,
    1045             :                               HandleValue receiver, ObjectOpResult& result)
    1046             : {
    1047           0 :     RootedId id(cx);
    1048           0 :     if (!IndexToId(cx, index, &id))
    1049           0 :         return false;
    1050           0 :     return nonNativeSetProperty(cx, obj, id, v, receiver, result);
    1051             : }
    1052             : 
    1053             : JS_FRIEND_API(bool)
    1054           0 : JS_CopyPropertyFrom(JSContext* cx, HandleId id, HandleObject target,
    1055             :                     HandleObject obj, PropertyCopyBehavior copyBehavior)
    1056             : {
    1057             :     // |obj| and |cx| are generally not same-compartment with |target| here.
    1058           0 :     assertSameCompartment(cx, obj, id);
    1059           0 :     Rooted<PropertyDescriptor> desc(cx);
    1060             : 
    1061           0 :     if (!GetOwnPropertyDescriptor(cx, obj, id, &desc))
    1062           0 :         return false;
    1063           0 :     MOZ_ASSERT(desc.object());
    1064             : 
    1065             :     // Silently skip JSGetterOp/JSSetterOp-implemented accessors.
    1066           0 :     if (desc.getter() && !desc.hasGetterObject())
    1067           0 :         return true;
    1068           0 :     if (desc.setter() && !desc.hasSetterObject())
    1069           0 :         return true;
    1070             : 
    1071           0 :     if (copyBehavior == MakeNonConfigurableIntoConfigurable) {
    1072             :         // Mask off the JSPROP_PERMANENT bit.
    1073           0 :         desc.attributesRef() &= ~JSPROP_PERMANENT;
    1074             :     }
    1075             : 
    1076           0 :     JSAutoCompartment ac(cx, target);
    1077           0 :     cx->markId(id);
    1078           0 :     RootedId wrappedId(cx, id);
    1079           0 :     if (!cx->compartment()->wrap(cx, &desc))
    1080           0 :         return false;
    1081             : 
    1082           0 :     return DefineProperty(cx, target, wrappedId, desc);
    1083             : }
    1084             : 
    1085             : JS_FRIEND_API(bool)
    1086           0 : JS_CopyPropertiesFrom(JSContext* cx, HandleObject target, HandleObject obj)
    1087             : {
    1088           0 :     JSAutoCompartment ac(cx, obj);
    1089             : 
    1090           0 :     AutoIdVector props(cx);
    1091           0 :     if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &props))
    1092           0 :         return false;
    1093             : 
    1094           0 :     for (size_t i = 0; i < props.length(); ++i) {
    1095           0 :         if (!JS_CopyPropertyFrom(cx, props[i], target, obj))
    1096           0 :             return false;
    1097             :     }
    1098             : 
    1099           0 :     return true;
    1100             : }
    1101             : 
    1102             : static bool
    1103           0 : CopyProxyObject(JSContext* cx, Handle<ProxyObject*> from, Handle<ProxyObject*> to)
    1104             : {
    1105           0 :     MOZ_ASSERT(from->getClass() == to->getClass());
    1106             : 
    1107           0 :     if (from->is<WrapperObject>() &&
    1108           0 :         (Wrapper::wrapperHandler(from)->flags() &
    1109             :          Wrapper::CROSS_COMPARTMENT))
    1110             :     {
    1111           0 :         to->setCrossCompartmentPrivate(GetProxyPrivate(from));
    1112             :     } else {
    1113           0 :         RootedValue v(cx, GetProxyPrivate(from));
    1114           0 :         if (!cx->compartment()->wrap(cx, &v))
    1115           0 :             return false;
    1116           0 :         to->setSameCompartmentPrivate(v);
    1117             :     }
    1118             : 
    1119           0 :     MOZ_ASSERT(from->numReservedSlots() == to->numReservedSlots());
    1120             : 
    1121           0 :     RootedValue v(cx);
    1122           0 :     for (size_t n = 0; n < from->numReservedSlots(); n++) {
    1123           0 :         v = GetProxyReservedSlot(from, n);
    1124           0 :         if (!cx->compartment()->wrap(cx, &v))
    1125           0 :             return false;
    1126           0 :         SetProxyReservedSlot(to, n, v);
    1127             :     }
    1128             : 
    1129           0 :     return true;
    1130             : }
    1131             : 
    1132             : JSObject*
    1133           0 : js::CloneObject(JSContext* cx, HandleObject obj, Handle<js::TaggedProto> proto)
    1134             : {
    1135           0 :     if (!obj->isNative() && !obj->is<ProxyObject>()) {
    1136           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CLONE_OBJECT);
    1137           0 :         return nullptr;
    1138             :     }
    1139             : 
    1140           0 :     RootedObject clone(cx);
    1141           0 :     if (obj->isNative()) {
    1142           0 :         clone = NewObjectWithGivenTaggedProto(cx, obj->getClass(), proto);
    1143           0 :         if (!clone)
    1144           0 :             return nullptr;
    1145             : 
    1146           0 :         if (clone->is<JSFunction>() && (obj->compartment() != clone->compartment())) {
    1147           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CLONE_OBJECT);
    1148           0 :             return nullptr;
    1149             :         }
    1150             : 
    1151           0 :         if (obj->as<NativeObject>().hasPrivate())
    1152           0 :             clone->as<NativeObject>().setPrivate(obj->as<NativeObject>().getPrivate());
    1153             :     } else {
    1154           0 :         ProxyOptions options;
    1155           0 :         options.setClass(obj->getClass());
    1156             : 
    1157           0 :         clone = ProxyObject::New(cx, GetProxyHandler(obj), JS::NullHandleValue, proto, options);
    1158           0 :         if (!clone)
    1159           0 :             return nullptr;
    1160             : 
    1161           0 :         if (!CopyProxyObject(cx, obj.as<ProxyObject>(), clone.as<ProxyObject>()))
    1162           0 :             return nullptr;
    1163             :     }
    1164             : 
    1165           0 :     return clone;
    1166             : }
    1167             : 
    1168             : static bool
    1169         737 : GetScriptArrayObjectElements(JSContext* cx, HandleObject obj, MutableHandle<GCVector<Value>> values)
    1170             : {
    1171         737 :     MOZ_ASSERT(!obj->isSingleton());
    1172         737 :     MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
    1173         737 :     MOZ_ASSERT(!obj->isIndexed());
    1174             : 
    1175         737 :     size_t length = GetAnyBoxedOrUnboxedArrayLength(obj);
    1176         737 :     if (!values.appendN(MagicValue(JS_ELEMENTS_HOLE), length))
    1177           0 :         return false;
    1178             : 
    1179         737 :     size_t initlen = GetAnyBoxedOrUnboxedInitializedLength(obj);
    1180        3258 :     for (size_t i = 0; i < initlen; i++)
    1181        2521 :         values[i].set(GetAnyBoxedOrUnboxedDenseElement(obj, i));
    1182             : 
    1183         737 :     return true;
    1184             : }
    1185             : 
    1186             : static bool
    1187        3473 : GetScriptPlainObjectProperties(JSContext* cx, HandleObject obj,
    1188             :                                MutableHandle<IdValueVector> properties)
    1189             : {
    1190        3473 :     if (obj->is<PlainObject>()) {
    1191        3473 :         PlainObject* nobj = &obj->as<PlainObject>();
    1192             : 
    1193        3473 :         if (!properties.appendN(IdValuePair(), nobj->slotSpan()))
    1194           0 :             return false;
    1195             : 
    1196       12845 :         for (Shape::Range<NoGC> r(nobj->lastProperty()); !r.empty(); r.popFront()) {
    1197        9372 :             Shape& shape = r.front();
    1198        9372 :             MOZ_ASSERT(shape.isDataDescriptor());
    1199        9372 :             uint32_t slot = shape.slot();
    1200        9372 :             properties[slot].get().id = shape.propid();
    1201        9372 :             properties[slot].get().value = nobj->getSlot(slot);
    1202             :         }
    1203             : 
    1204        3473 :         for (size_t i = 0; i < nobj->getDenseInitializedLength(); i++) {
    1205           0 :             Value v = nobj->getDenseElement(i);
    1206           0 :             if (!v.isMagic(JS_ELEMENTS_HOLE) && !properties.append(IdValuePair(INT_TO_JSID(i), v)))
    1207           0 :                 return false;
    1208             :         }
    1209             : 
    1210        3473 :         return true;
    1211             :     }
    1212             : 
    1213           0 :     if (obj->is<UnboxedPlainObject>()) {
    1214           0 :         UnboxedPlainObject* nobj = &obj->as<UnboxedPlainObject>();
    1215             : 
    1216           0 :         const UnboxedLayout& layout = nobj->layout();
    1217           0 :         if (!properties.appendN(IdValuePair(), layout.properties().length()))
    1218           0 :             return false;
    1219             : 
    1220           0 :         for (size_t i = 0; i < layout.properties().length(); i++) {
    1221           0 :             const UnboxedLayout::Property& property = layout.properties()[i];
    1222           0 :             properties[i].get().id = NameToId(property.name);
    1223           0 :             properties[i].get().value = nobj->getValue(property);
    1224             :         }
    1225             : 
    1226           0 :         return true;
    1227             :     }
    1228             : 
    1229           0 :     MOZ_CRASH("Bad object kind");
    1230             : }
    1231             : 
    1232             : static bool
    1233        8581 : DeepCloneValue(JSContext* cx, Value* vp, NewObjectKind newKind)
    1234             : {
    1235        8581 :     if (vp->isObject()) {
    1236           0 :         RootedObject obj(cx, &vp->toObject());
    1237           0 :         obj = DeepCloneObjectLiteral(cx, obj, newKind);
    1238           0 :         if (!obj)
    1239           0 :             return false;
    1240           0 :         vp->setObject(*obj);
    1241             :     } else {
    1242        8581 :         cx->markAtomValue(*vp);
    1243             :     }
    1244        8581 :     return true;
    1245             : }
    1246             : 
    1247             : JSObject*
    1248        2939 : js::DeepCloneObjectLiteral(JSContext* cx, HandleObject obj, NewObjectKind newKind)
    1249             : {
    1250             :     /* NB: Keep this in sync with XDRObjectLiteral. */
    1251        2939 :     MOZ_ASSERT_IF(obj->isSingleton(),
    1252             :                   cx->compartment()->behaviors().getSingletonsAsTemplates());
    1253        2939 :     MOZ_ASSERT(obj->is<PlainObject>() || obj->is<UnboxedPlainObject>() ||
    1254             :                obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
    1255        2939 :     MOZ_ASSERT(newKind != SingletonObject);
    1256             : 
    1257        2939 :     if (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) {
    1258         898 :         Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
    1259         449 :         if (!GetScriptArrayObjectElements(cx, obj, &values))
    1260           0 :             return nullptr;
    1261             : 
    1262             :         // Deep clone any elements.
    1263        2233 :         for (uint32_t i = 0; i < values.length(); ++i) {
    1264        1784 :             if (!DeepCloneValue(cx, values[i].address(), newKind))
    1265           0 :                 return nullptr;
    1266             :         }
    1267             : 
    1268         449 :         ObjectGroup::NewArrayKind arrayKind = ObjectGroup::NewArrayKind::Normal;
    1269         449 :         if (obj->is<ArrayObject>() && obj->as<ArrayObject>().denseElementsAreCopyOnWrite())
    1270         449 :             arrayKind = ObjectGroup::NewArrayKind::CopyOnWrite;
    1271             : 
    1272         449 :         return ObjectGroup::newArrayObject(cx, values.begin(), values.length(), newKind,
    1273         449 :                                            arrayKind);
    1274             :     }
    1275             : 
    1276        4980 :     Rooted<IdValueVector> properties(cx, IdValueVector(cx));
    1277        2490 :     if (!GetScriptPlainObjectProperties(cx, obj, &properties))
    1278           0 :         return nullptr;
    1279             : 
    1280        9287 :     for (size_t i = 0; i < properties.length(); i++) {
    1281        6797 :         cx->markId(properties[i].get().id);
    1282        6797 :         if (!DeepCloneValue(cx, &properties[i].get().value, newKind))
    1283           0 :             return nullptr;
    1284             :     }
    1285             : 
    1286        2490 :     if (obj->isSingleton())
    1287           0 :         newKind = SingletonObject;
    1288             : 
    1289        2490 :     return ObjectGroup::newPlainObject(cx, properties.begin(), properties.length(), newKind);
    1290             : }
    1291             : 
    1292             : static bool
    1293          67 : InitializePropertiesFromCompatibleNativeObject(JSContext* cx,
    1294             :                                                HandleNativeObject dst,
    1295             :                                                HandleNativeObject src)
    1296             : {
    1297          67 :     assertSameCompartment(cx, src, dst);
    1298          67 :     MOZ_ASSERT(src->getClass() == dst->getClass());
    1299          67 :     MOZ_ASSERT(dst->lastProperty()->getObjectFlags() == 0);
    1300          67 :     MOZ_ASSERT(!src->isSingleton());
    1301          67 :     MOZ_ASSERT(src->numFixedSlots() == dst->numFixedSlots());
    1302             : 
    1303          67 :     if (!dst->ensureElements(cx, src->getDenseInitializedLength()))
    1304           0 :         return false;
    1305             : 
    1306          67 :     uint32_t initialized = src->getDenseInitializedLength();
    1307          67 :     for (uint32_t i = 0; i < initialized; ++i) {
    1308           0 :         dst->setDenseInitializedLength(i + 1);
    1309           0 :         dst->initDenseElement(i, src->getDenseElement(i));
    1310             :     }
    1311             : 
    1312          67 :     MOZ_ASSERT(!src->hasPrivate());
    1313         134 :     RootedShape shape(cx);
    1314          67 :     if (src->staticPrototype() == dst->staticPrototype()) {
    1315          67 :         shape = src->lastProperty();
    1316             :     } else {
    1317             :         // We need to generate a new shape for dst that has dst's proto but all
    1318             :         // the property information from src.  Note that we asserted above that
    1319             :         // dst's object flags are 0.
    1320           0 :         shape = EmptyShape::getInitialShape(cx, dst->getClass(), dst->taggedProto(),
    1321           0 :                                             dst->numFixedSlots(), 0);
    1322           0 :         if (!shape)
    1323           0 :             return false;
    1324             : 
    1325             :         // Get an in-order list of the shapes in the src object.
    1326           0 :         Rooted<ShapeVector> shapes(cx, ShapeVector(cx));
    1327           0 :         for (Shape::Range<NoGC> r(src->lastProperty()); !r.empty(); r.popFront()) {
    1328           0 :             if (!shapes.append(&r.front()))
    1329           0 :                 return false;
    1330             :         }
    1331           0 :         Reverse(shapes.begin(), shapes.end());
    1332             : 
    1333           0 :         for (Shape* shape : shapes) {
    1334           0 :             Rooted<StackShape> child(cx, StackShape(shape));
    1335           0 :             shape = cx->zone()->propertyTree().getChild(cx, shape, child);
    1336           0 :             if (!shape)
    1337           0 :                 return false;
    1338             :         }
    1339             :     }
    1340          67 :     size_t span = shape->slotSpan();
    1341          67 :     if (!dst->setLastProperty(cx, shape))
    1342           0 :         return false;
    1343          85 :     for (size_t i = JSCLASS_RESERVED_SLOTS(src->getClass()); i < span; i++)
    1344          18 :         dst->setSlot(i, src->getSlot(i));
    1345             : 
    1346          67 :     return true;
    1347             : }
    1348             : 
    1349             : JS_FRIEND_API(bool)
    1350          67 : JS_InitializePropertiesFromCompatibleNativeObject(JSContext* cx,
    1351             :                                                   HandleObject dst,
    1352             :                                                   HandleObject src)
    1353             : {
    1354          67 :     return InitializePropertiesFromCompatibleNativeObject(cx,
    1355             :                                                           dst.as<NativeObject>(),
    1356          67 :                                                           src.as<NativeObject>());
    1357             : }
    1358             : 
    1359             : template<XDRMode mode>
    1360             : bool
    1361        4535 : js::XDRObjectLiteral(XDRState<mode>* xdr, MutableHandleObject obj)
    1362             : {
    1363             :     /* NB: Keep this in sync with DeepCloneObjectLiteral. */
    1364             : 
    1365        4535 :     JSContext* cx = xdr->cx();
    1366        4535 :     assertSameCompartment(cx, obj);
    1367             : 
    1368             :     // Distinguish between objects and array classes.
    1369        4535 :     uint32_t isArray = 0;
    1370             :     {
    1371             :         if (mode == XDR_ENCODE) {
    1372        1271 :             MOZ_ASSERT(obj->is<PlainObject>() ||
    1373             :                        obj->is<UnboxedPlainObject>() ||
    1374             :                        obj->is<ArrayObject>() ||
    1375             :                        obj->is<UnboxedArrayObject>());
    1376        1271 :             isArray = (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) ? 1 : 0;
    1377             :         }
    1378             : 
    1379        4535 :         if (!xdr->codeUint32(&isArray))
    1380           0 :             return false;
    1381             :     }
    1382             : 
    1383        9069 :     RootedValue tmpValue(cx), tmpIdValue(cx);
    1384        9069 :     RootedId tmpId(cx);
    1385             : 
    1386        4535 :     if (isArray) {
    1387        1668 :         Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
    1388         834 :         if (mode == XDR_ENCODE && !GetScriptArrayObjectElements(cx, obj, &values))
    1389           0 :             return false;
    1390             : 
    1391             :         uint32_t initialized;
    1392             :         if (mode == XDR_ENCODE)
    1393         288 :             initialized = values.length();
    1394         834 :         if (!xdr->codeUint32(&initialized))
    1395           0 :             return false;
    1396         834 :         if (mode == XDR_DECODE && !values.appendN(MagicValue(JS_ELEMENTS_HOLE), initialized))
    1397           0 :             return false;
    1398             : 
    1399             :         // Recursively copy dense elements.
    1400        3197 :         for (unsigned i = 0; i < initialized; i++) {
    1401        2363 :             if (!xdr->codeConstValue(values[i]))
    1402           0 :                 return false;
    1403             :         }
    1404             : 
    1405             :         uint32_t copyOnWrite;
    1406             :         if (mode == XDR_ENCODE)
    1407         576 :             copyOnWrite = obj->is<ArrayObject>() &&
    1408         288 :                           obj->as<ArrayObject>().denseElementsAreCopyOnWrite();
    1409         834 :         if (!xdr->codeUint32(&copyOnWrite))
    1410           0 :             return false;
    1411             : 
    1412             :         if (mode == XDR_DECODE) {
    1413             :             ObjectGroup::NewArrayKind arrayKind = copyOnWrite
    1414             :                                                   ? ObjectGroup::NewArrayKind::CopyOnWrite
    1415         546 :                                                   : ObjectGroup::NewArrayKind::Normal;
    1416         546 :             obj.set(ObjectGroup::newArrayObject(cx, values.begin(), values.length(),
    1417             :                                                 TenuredObject, arrayKind));
    1418         546 :             if (!obj)
    1419           0 :                 return false;
    1420             :         }
    1421             : 
    1422         834 :         return true;
    1423             :     }
    1424             : 
    1425             :     // Code the properties in the object.
    1426        7401 :     Rooted<IdValueVector> properties(cx, IdValueVector(cx));
    1427        3701 :     if (mode == XDR_ENCODE && !GetScriptPlainObjectProperties(cx, obj, &properties))
    1428           0 :         return false;
    1429             : 
    1430        3701 :     uint32_t nproperties = properties.length();
    1431        3701 :     if (!xdr->codeUint32(&nproperties))
    1432           0 :         return false;
    1433             : 
    1434        3701 :     if (mode == XDR_DECODE && !properties.appendN(IdValuePair(), nproperties))
    1435           0 :         return false;
    1436             : 
    1437       13812 :     for (size_t i = 0; i < nproperties; i++) {
    1438             :         if (mode == XDR_ENCODE) {
    1439        2575 :             tmpIdValue = IdToValue(properties[i].get().id);
    1440        2575 :             tmpValue = properties[i].get().value;
    1441             :         }
    1442             : 
    1443       10111 :         if (!xdr->codeConstValue(&tmpIdValue) || !xdr->codeConstValue(&tmpValue))
    1444           0 :             return false;
    1445             : 
    1446             :         if (mode == XDR_DECODE) {
    1447        7536 :             if (!ValueToId<CanGC>(cx, tmpIdValue, &tmpId))
    1448           0 :                 return false;
    1449        7536 :             properties[i].get().id = tmpId;
    1450        7536 :             properties[i].get().value = tmpValue;
    1451             :         }
    1452             :     }
    1453             : 
    1454             :     // Code whether the object is a singleton.
    1455             :     uint32_t isSingleton;
    1456             :     if (mode == XDR_ENCODE)
    1457         983 :         isSingleton = obj->isSingleton() ? 1 : 0;
    1458        3701 :     if (!xdr->codeUint32(&isSingleton))
    1459           0 :         return false;
    1460             : 
    1461             :     if (mode == XDR_DECODE) {
    1462        2718 :         NewObjectKind newKind = isSingleton ? SingletonObject : TenuredObject;
    1463        2718 :         obj.set(ObjectGroup::newPlainObject(cx, properties.begin(), properties.length(), newKind));
    1464        2717 :         if (!obj)
    1465           0 :             return false;
    1466             :     }
    1467             : 
    1468        3700 :     return true;
    1469             : }
    1470             : 
    1471             : template bool
    1472             : js::XDRObjectLiteral(XDRState<XDR_ENCODE>* xdr, MutableHandleObject obj);
    1473             : 
    1474             : template bool
    1475             : js::XDRObjectLiteral(XDRState<XDR_DECODE>* xdr, MutableHandleObject obj);
    1476             : 
    1477             : /* static */ bool
    1478           0 : NativeObject::fillInAfterSwap(JSContext* cx, HandleNativeObject obj,
    1479             :                               const Vector<Value>& values, void* priv)
    1480             : {
    1481             :     // This object has just been swapped with some other object, and its shape
    1482             :     // no longer reflects its allocated size. Correct this information and
    1483             :     // fill the slots in with the specified values.
    1484           0 :     MOZ_ASSERT(obj->slotSpan() == values.length());
    1485             : 
    1486             :     // Make sure the shape's numFixedSlots() is correct.
    1487           0 :     size_t nfixed = gc::GetGCKindSlots(obj->asTenured().getAllocKind(), obj->getClass());
    1488           0 :     if (nfixed != obj->shape_->numFixedSlots()) {
    1489           0 :         if (!NativeObject::generateOwnShape(cx, obj))
    1490           0 :             return false;
    1491           0 :         obj->shape_->setNumFixedSlots(nfixed);
    1492             :     }
    1493             : 
    1494           0 :     if (obj->hasPrivate())
    1495           0 :         obj->setPrivate(priv);
    1496             :     else
    1497           0 :         MOZ_ASSERT(!priv);
    1498             : 
    1499           0 :     if (obj->slots_) {
    1500           0 :         js_free(obj->slots_);
    1501           0 :         obj->slots_ = nullptr;
    1502             :     }
    1503             : 
    1504           0 :     if (size_t ndynamic = dynamicSlotsCount(nfixed, values.length(), obj->getClass())) {
    1505           0 :         obj->slots_ = cx->zone()->pod_malloc<HeapSlot>(ndynamic);
    1506           0 :         if (!obj->slots_)
    1507           0 :             return false;
    1508           0 :         Debug_SetSlotRangeToCrashOnTouch(obj->slots_, ndynamic);
    1509             :     }
    1510             : 
    1511           0 :     obj->initSlotRange(0, values.begin(), values.length());
    1512           0 :     return true;
    1513             : }
    1514             : 
    1515             : void
    1516           4 : JSObject::fixDictionaryShapeAfterSwap()
    1517             : {
    1518             :     // Dictionary shapes can point back to their containing objects, so after
    1519             :     // swapping the guts of those objects fix the pointers up.
    1520           4 :     if (isNative() && as<NativeObject>().inDictionaryMode())
    1521           0 :         as<NativeObject>().shape_->listp = &as<NativeObject>().shape_;
    1522           4 : }
    1523             : 
    1524             : static MOZ_MUST_USE bool
    1525           0 : CopyProxyValuesBeforeSwap(ProxyObject* proxy, Vector<Value>& values)
    1526             : {
    1527           0 :     MOZ_ASSERT(values.empty());
    1528             : 
    1529             :     // Remove the GCPtrValues we're about to swap from the store buffer, to
    1530             :     // ensure we don't trace bogus values.
    1531           0 :     StoreBuffer& sb = proxy->zone()->group()->storeBuffer();
    1532             : 
    1533             :     // Reserve space for the private slot and the reserved slots.
    1534           0 :     if (!values.reserve(1 + proxy->numReservedSlots()))
    1535           0 :         return false;
    1536             : 
    1537           0 :     js::detail::ProxyValueArray* valArray = js::detail::GetProxyDataLayout(proxy)->values();
    1538           0 :     sb.unputValue(&valArray->privateSlot);
    1539           0 :     values.infallibleAppend(valArray->privateSlot);
    1540             : 
    1541           0 :     for (size_t i = 0; i < proxy->numReservedSlots(); i++) {
    1542           0 :         sb.unputValue(&valArray->reservedSlots.slots[i]);
    1543           0 :         values.infallibleAppend(valArray->reservedSlots.slots[i]);
    1544             :     }
    1545             : 
    1546           0 :     return true;
    1547             : }
    1548             : 
    1549             : bool
    1550           0 : ProxyObject::initExternalValueArrayAfterSwap(JSContext* cx, const Vector<Value>& values)
    1551             : {
    1552           0 :     MOZ_ASSERT(getClass()->isProxy());
    1553             : 
    1554           0 :     size_t nreserved = numReservedSlots();
    1555             : 
    1556             :     // |values| contains the private slot and the reserved slots.
    1557           0 :     MOZ_ASSERT(values.length() == 1 + nreserved);
    1558             : 
    1559           0 :     size_t nbytes = js::detail::ProxyValueArray::sizeOf(nreserved);
    1560             : 
    1561             :     auto* valArray =
    1562           0 :         reinterpret_cast<js::detail::ProxyValueArray*>(cx->zone()->pod_malloc<uint8_t>(nbytes));
    1563           0 :     if (!valArray)
    1564           0 :         return false;
    1565             : 
    1566           0 :     valArray->privateSlot = values[0];
    1567             : 
    1568           0 :     for (size_t i = 0; i < nreserved; i++)
    1569           0 :         valArray->reservedSlots.slots[i] = values[i + 1];
    1570             : 
    1571             :     // Note: we allocate external slots iff the proxy had an inline
    1572             :     // ProxyValueArray, so at this point reservedSlots points into the
    1573             :     // old object and we don't have to free anything.
    1574           0 :     data.reservedSlots = &valArray->reservedSlots;
    1575           0 :     return true;
    1576             : }
    1577             : 
    1578             : /* Use this method with extreme caution. It trades the guts of two objects. */
    1579             : bool
    1580           2 : JSObject::swap(JSContext* cx, HandleObject a, HandleObject b)
    1581             : {
    1582             :     // Ensure swap doesn't cause a finalizer to not be run.
    1583           2 :     MOZ_ASSERT(IsBackgroundFinalized(a->asTenured().getAllocKind()) ==
    1584             :                IsBackgroundFinalized(b->asTenured().getAllocKind()));
    1585           2 :     MOZ_ASSERT(a->compartment() == b->compartment());
    1586             : 
    1587             :     // You must have entered the objects' compartment before calling this.
    1588           2 :     MOZ_ASSERT(cx->compartment() == a->compartment());
    1589             : 
    1590           4 :     AutoEnterOOMUnsafeRegion oomUnsafe;
    1591             : 
    1592           2 :     if (!JSObject::getGroup(cx, a))
    1593           0 :         oomUnsafe.crash("JSObject::swap");
    1594           2 :     if (!JSObject::getGroup(cx, b))
    1595           0 :         oomUnsafe.crash("JSObject::swap");
    1596             : 
    1597             :     /*
    1598             :      * Neither object may be in the nursery, but ensure we update any embedded
    1599             :      * nursery pointers in either object.
    1600             :      */
    1601           2 :     MOZ_ASSERT(!IsInsideNursery(a) && !IsInsideNursery(b));
    1602           2 :     cx->zone()->group()->storeBuffer().putWholeCell(a);
    1603           2 :     cx->zone()->group()->storeBuffer().putWholeCell(b);
    1604             : 
    1605           2 :     unsigned r = NotifyGCPreSwap(a, b);
    1606             : 
    1607             :     // Do the fundamental swapping of the contents of two objects.
    1608           2 :     MOZ_ASSERT(a->compartment() == b->compartment());
    1609           2 :     MOZ_ASSERT(a->is<JSFunction>() == b->is<JSFunction>());
    1610             : 
    1611             :     // Don't try to swap functions with different sizes.
    1612           2 :     MOZ_ASSERT_IF(a->is<JSFunction>(), a->tenuredSizeOfThis() == b->tenuredSizeOfThis());
    1613             : 
    1614             :     // Watch for oddball objects that have special organizational issues and
    1615             :     // can't be swapped.
    1616           2 :     MOZ_ASSERT(!a->is<RegExpObject>() && !b->is<RegExpObject>());
    1617           2 :     MOZ_ASSERT(!a->is<ArrayObject>() && !b->is<ArrayObject>());
    1618           2 :     MOZ_ASSERT(!a->is<ArrayBufferObject>() && !b->is<ArrayBufferObject>());
    1619           2 :     MOZ_ASSERT(!a->is<TypedArrayObject>() && !b->is<TypedArrayObject>());
    1620           2 :     MOZ_ASSERT(!a->is<TypedObject>() && !b->is<TypedObject>());
    1621             : 
    1622             :     bool aIsProxyWithInlineValues =
    1623           2 :         a->is<ProxyObject>() && a->as<ProxyObject>().usingInlineValueArray();
    1624             :     bool bIsProxyWithInlineValues =
    1625           2 :         b->is<ProxyObject>() && b->as<ProxyObject>().usingInlineValueArray();
    1626             : 
    1627           2 :     if (a->tenuredSizeOfThis() == b->tenuredSizeOfThis()) {
    1628             :         // When both objects are the same size, just do a plain swap of their
    1629             :         // contents.
    1630           2 :         size_t size = a->tenuredSizeOfThis();
    1631             : 
    1632             :         char tmp[mozilla::tl::Max<sizeof(JSFunction), sizeof(JSObject_Slots16)>::value];
    1633           2 :         MOZ_ASSERT(size <= sizeof(tmp));
    1634             : 
    1635           2 :         js_memcpy(tmp, a, size);
    1636           2 :         js_memcpy(a, b, size);
    1637           2 :         js_memcpy(b, tmp, size);
    1638             : 
    1639           2 :         a->fixDictionaryShapeAfterSwap();
    1640           2 :         b->fixDictionaryShapeAfterSwap();
    1641             : 
    1642           2 :         if (aIsProxyWithInlineValues)
    1643           2 :             b->as<ProxyObject>().setInlineValueArray();
    1644           2 :         if (bIsProxyWithInlineValues)
    1645           2 :             a->as<ProxyObject>().setInlineValueArray();
    1646             :     } else {
    1647             :         // Avoid GC in here to avoid confusing the tracing code with our
    1648             :         // intermediate state.
    1649           0 :         AutoSuppressGC suppress(cx);
    1650             : 
    1651             :         // When the objects have different sizes, they will have different
    1652             :         // numbers of fixed slots before and after the swap, so the slots for
    1653             :         // native objects will need to be rearranged.
    1654           0 :         NativeObject* na = a->isNative() ? &a->as<NativeObject>() : nullptr;
    1655           0 :         NativeObject* nb = b->isNative() ? &b->as<NativeObject>() : nullptr;
    1656             : 
    1657             :         // Remember the original values from the objects.
    1658           0 :         Vector<Value> avals(cx);
    1659           0 :         void* apriv = nullptr;
    1660           0 :         if (na) {
    1661           0 :             apriv = na->hasPrivate() ? na->getPrivate() : nullptr;
    1662           0 :             for (size_t i = 0; i < na->slotSpan(); i++) {
    1663           0 :                 if (!avals.append(na->getSlot(i)))
    1664           0 :                     oomUnsafe.crash("JSObject::swap");
    1665             :             }
    1666             :         }
    1667           0 :         Vector<Value> bvals(cx);
    1668           0 :         void* bpriv = nullptr;
    1669           0 :         if (nb) {
    1670           0 :             bpriv = nb->hasPrivate() ? nb->getPrivate() : nullptr;
    1671           0 :             for (size_t i = 0; i < nb->slotSpan(); i++) {
    1672           0 :                 if (!bvals.append(nb->getSlot(i)))
    1673           0 :                     oomUnsafe.crash("JSObject::swap");
    1674             :             }
    1675             :         }
    1676             : 
    1677             :         // Do the same for proxies storing ProxyValueArray inline.
    1678           0 :         ProxyObject* proxyA = a->is<ProxyObject>() ? &a->as<ProxyObject>() : nullptr;
    1679           0 :         ProxyObject* proxyB = b->is<ProxyObject>() ? &b->as<ProxyObject>() : nullptr;
    1680             : 
    1681           0 :         if (aIsProxyWithInlineValues) {
    1682           0 :             if (!CopyProxyValuesBeforeSwap(proxyA, avals))
    1683           0 :                 oomUnsafe.crash("CopyProxyValuesBeforeSwap");
    1684             :         }
    1685           0 :         if (bIsProxyWithInlineValues) {
    1686           0 :             if (!CopyProxyValuesBeforeSwap(proxyB, bvals))
    1687           0 :                 oomUnsafe.crash("CopyProxyValuesBeforeSwap");
    1688             :         }
    1689             : 
    1690             :         // Swap the main fields of the objects, whether they are native objects or proxies.
    1691             :         char tmp[sizeof(JSObject_Slots0)];
    1692           0 :         js_memcpy(&tmp, a, sizeof tmp);
    1693           0 :         js_memcpy(a, b, sizeof tmp);
    1694           0 :         js_memcpy(b, &tmp, sizeof tmp);
    1695             : 
    1696           0 :         a->fixDictionaryShapeAfterSwap();
    1697           0 :         b->fixDictionaryShapeAfterSwap();
    1698             : 
    1699           0 :         if (na) {
    1700           0 :             if (!NativeObject::fillInAfterSwap(cx, b.as<NativeObject>(), avals, apriv))
    1701           0 :                 oomUnsafe.crash("fillInAfterSwap");
    1702             :         }
    1703           0 :         if (nb) {
    1704           0 :             if (!NativeObject::fillInAfterSwap(cx, a.as<NativeObject>(), bvals, bpriv))
    1705           0 :                 oomUnsafe.crash("fillInAfterSwap");
    1706             :         }
    1707           0 :         if (aIsProxyWithInlineValues) {
    1708           0 :             if (!b->as<ProxyObject>().initExternalValueArrayAfterSwap(cx, avals))
    1709           0 :                 oomUnsafe.crash("initExternalValueArray");
    1710             :         }
    1711           0 :         if (bIsProxyWithInlineValues) {
    1712           0 :             if (!a->as<ProxyObject>().initExternalValueArrayAfterSwap(cx, bvals))
    1713           0 :                 oomUnsafe.crash("initExternalValueArray");
    1714             :         }
    1715             :     }
    1716             : 
    1717             :     // Swapping the contents of two objects invalidates type sets which contain
    1718             :     // either of the objects, so mark all such sets as unknown.
    1719           2 :     MarkObjectGroupUnknownProperties(cx, a->group());
    1720           2 :     MarkObjectGroupUnknownProperties(cx, b->group());
    1721             : 
    1722             :     /*
    1723             :      * We need a write barrier here. If |a| was marked and |b| was not, then
    1724             :      * after the swap, |b|'s guts would never be marked. The write barrier
    1725             :      * solves this.
    1726             :      *
    1727             :      * Normally write barriers happen before the write. However, that's not
    1728             :      * necessary here because nothing is being destroyed. We're just swapping.
    1729             :      */
    1730           2 :     JS::Zone* zone = a->zone();
    1731           2 :     if (zone->needsIncrementalBarrier()) {
    1732           0 :         a->traceChildren(zone->barrierTracer());
    1733           0 :         b->traceChildren(zone->barrierTracer());
    1734             :     }
    1735             : 
    1736           2 :     NotifyGCPostSwap(a, b, r);
    1737           4 :     return true;
    1738             : }
    1739             : 
    1740             : static bool
    1741           4 : DefineStandardSlot(JSContext* cx, HandleObject obj, JSProtoKey key, JSAtom* atom,
    1742             :                    HandleValue v, uint32_t attrs, bool& named)
    1743             : {
    1744           8 :     RootedId id(cx, AtomToId(atom));
    1745           4 :     named = DefineProperty(cx, obj, id, v, nullptr, nullptr, attrs);
    1746           8 :     return named;
    1747             : }
    1748             : 
    1749             : static void
    1750           0 : SetClassObject(JSObject* obj, JSProtoKey key, JSObject* cobj, JSObject* proto)
    1751             : {
    1752           0 :     if (!obj->is<GlobalObject>())
    1753           0 :         return;
    1754             : 
    1755           0 :     obj->as<GlobalObject>().setConstructor(key, ObjectOrNullValue(cobj));
    1756           0 :     obj->as<GlobalObject>().setPrototype(key, ObjectOrNullValue(proto));
    1757             : }
    1758             : 
    1759             : static void
    1760           0 : ClearClassObject(JSObject* obj, JSProtoKey key)
    1761             : {
    1762           0 :     if (!obj->is<GlobalObject>())
    1763           0 :         return;
    1764             : 
    1765           0 :     obj->as<GlobalObject>().setConstructor(key, UndefinedValue());
    1766           0 :     obj->as<GlobalObject>().setPrototype(key, UndefinedValue());
    1767             : }
    1768             : 
    1769             : static NativeObject*
    1770           4 : DefineConstructorAndPrototype(JSContext* cx, HandleObject obj, JSProtoKey key, HandleAtom atom,
    1771             :                               HandleObject protoProto, const Class* clasp,
    1772             :                               Native constructor, unsigned nargs,
    1773             :                               const JSPropertySpec* ps, const JSFunctionSpec* fs,
    1774             :                               const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs,
    1775             :                               NativeObject** ctorp, AllocKind ctorKind)
    1776             : {
    1777             :     /*
    1778             :      * Create a prototype object for this class.
    1779             :      *
    1780             :      * FIXME: lazy standard (built-in) class initialization and even older
    1781             :      * eager boostrapping code rely on all of these properties:
    1782             :      *
    1783             :      * 1. NewObject attempting to compute a default prototype object when
    1784             :      *    passed null for proto; and
    1785             :      *
    1786             :      * 2. NewObject tolerating no default prototype (null proto slot value)
    1787             :      *    due to this js::InitClass call coming from js::InitFunctionClass on an
    1788             :      *    otherwise-uninitialized global.
    1789             :      *
    1790             :      * 3. NewObject allocating a JSFunction-sized GC-thing when clasp is
    1791             :      *    &JSFunction::class_, not a JSObject-sized (smaller) GC-thing.
    1792             :      *
    1793             :      * The JS_NewObjectForGivenProto and JS_NewObject APIs also allow clasp to
    1794             :      * be &JSFunction::class_ (we could break compatibility easily). But
    1795             :      * fixing (3) is not enough without addressing the bootstrapping dependency
    1796             :      * on (1) and (2).
    1797             :      */
    1798             : 
    1799             :     /*
    1800             :      * Create the prototype object.  (GlobalObject::createBlankPrototype isn't
    1801             :      * used because it won't let us use protoProto as the proto.
    1802             :      */
    1803           8 :     RootedNativeObject proto(cx, NewNativeObjectWithClassProto(cx, clasp, protoProto, SingletonObject));
    1804           4 :     if (!proto)
    1805           0 :         return nullptr;
    1806             : 
    1807             :     /* After this point, control must exit via label bad or out. */
    1808           8 :     RootedNativeObject ctor(cx);
    1809           4 :     bool named = false;
    1810           4 :     bool cached = false;
    1811           4 :     if (!constructor) {
    1812             :         /*
    1813             :          * Lacking a constructor, name the prototype (e.g., Math) unless this
    1814             :          * class (a) is anonymous, i.e. for internal use only; (b) the class
    1815             :          * of obj (the global object) is has a reserved slot indexed by key;
    1816             :          * and (c) key is not the null key.
    1817             :          */
    1818           0 :         if (!(clasp->flags & JSCLASS_IS_ANONYMOUS) || !obj->is<GlobalObject>() ||
    1819             :             key == JSProto_Null)
    1820             :         {
    1821           0 :             uint32_t attrs = (clasp->flags & JSCLASS_IS_ANONYMOUS)
    1822           0 :                            ? JSPROP_READONLY | JSPROP_PERMANENT
    1823           0 :                            : 0;
    1824           0 :             RootedValue value(cx, ObjectValue(*proto));
    1825           0 :             if (!DefineStandardSlot(cx, obj, key, atom, value, attrs, named))
    1826           0 :                 goto bad;
    1827             :         }
    1828             : 
    1829           0 :         ctor = proto;
    1830             :     } else {
    1831           8 :         RootedFunction fun(cx, NewNativeConstructor(cx, constructor, nargs, atom, ctorKind));
    1832           4 :         if (!fun)
    1833           0 :             goto bad;
    1834             : 
    1835             :         /*
    1836             :          * Set the class object early for standard class constructors. Type
    1837             :          * inference may need to access these, and js::GetBuiltinPrototype will
    1838             :          * fail if it tries to do a reentrant reconstruction of the class.
    1839             :          */
    1840           4 :         if (key != JSProto_Null) {
    1841           0 :             SetClassObject(obj, key, fun, proto);
    1842           0 :             cached = true;
    1843             :         }
    1844             : 
    1845           8 :         RootedValue value(cx, ObjectValue(*fun));
    1846           4 :         if (!DefineStandardSlot(cx, obj, key, atom, value, 0, named))
    1847           0 :             goto bad;
    1848             : 
    1849             :         /*
    1850             :          * Optionally construct the prototype object, before the class has
    1851             :          * been fully initialized.  Allow the ctor to replace proto with a
    1852             :          * different object, as is done for operator new.
    1853             :          */
    1854           4 :         ctor = fun;
    1855           4 :         if (!LinkConstructorAndPrototype(cx, ctor, proto))
    1856           0 :             goto bad;
    1857             : 
    1858             :         /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */
    1859           8 :         Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
    1860           4 :         if (ctor->getClass() == clasp && !JSObject::splicePrototype(cx, ctor, clasp, tagged))
    1861           0 :             goto bad;
    1862             :     }
    1863             : 
    1864          12 :     if (!DefinePropertiesAndFunctions(cx, proto, ps, fs) ||
    1865          12 :         (ctor != proto && !DefinePropertiesAndFunctions(cx, ctor, static_ps, static_fs)))
    1866             :     {
    1867           0 :         goto bad;
    1868             :     }
    1869             : 
    1870             :     /* If this is a standard class, cache its prototype. */
    1871           4 :     if (!cached && key != JSProto_Null)
    1872           0 :         SetClassObject(obj, key, ctor, proto);
    1873             : 
    1874           4 :     if (ctorp)
    1875           0 :         *ctorp = ctor;
    1876           4 :     return proto;
    1877             : 
    1878             : bad:
    1879           0 :     if (named) {
    1880           0 :         ObjectOpResult ignored;
    1881           0 :         RootedId id(cx, AtomToId(atom));
    1882             : 
    1883             :         // XXX FIXME - absurd to call this here; instead define the property last.
    1884           0 :         DeleteProperty(cx, obj, id, ignored);
    1885             :     }
    1886           0 :     if (cached)
    1887           0 :         ClearClassObject(obj, key);
    1888           0 :     return nullptr;
    1889             : }
    1890             : 
    1891             : NativeObject*
    1892           4 : js::InitClass(JSContext* cx, HandleObject obj, HandleObject protoProto_,
    1893             :               const Class* clasp, Native constructor, unsigned nargs,
    1894             :               const JSPropertySpec* ps, const JSFunctionSpec* fs,
    1895             :               const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs,
    1896             :               NativeObject** ctorp, AllocKind ctorKind)
    1897             : {
    1898           8 :     RootedObject protoProto(cx, protoProto_);
    1899             : 
    1900             :     /* Check function pointer members. */
    1901           4 :     MOZ_ASSERT(clasp->getGetProperty() != JS_PropertyStub);
    1902           4 :     MOZ_ASSERT(clasp->getSetProperty() != JS_StrictPropertyStub);
    1903             : 
    1904           8 :     RootedAtom atom(cx, Atomize(cx, clasp->name, strlen(clasp->name)));
    1905           4 :     if (!atom)
    1906           0 :         return nullptr;
    1907             : 
    1908             :     /*
    1909             :      * All instances of the class will inherit properties from the prototype
    1910             :      * object we are about to create (in DefineConstructorAndPrototype), which
    1911             :      * in turn will inherit from protoProto.
    1912             :      *
    1913             :      * When initializing a standard class (other than Object), if protoProto is
    1914             :      * null, default to Object.prototype. The engine's internal uses of
    1915             :      * js::InitClass depend on this nicety.
    1916             :      */
    1917           4 :     JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp);
    1918          12 :     if (key != JSProto_Null &&
    1919           4 :         !protoProto &&
    1920           4 :         !GetBuiltinPrototype(cx, JSProto_Object, &protoProto))
    1921             :     {
    1922           0 :         return nullptr;
    1923             :     }
    1924             : 
    1925           8 :     return DefineConstructorAndPrototype(cx, obj, key, atom, protoProto, clasp, constructor, nargs,
    1926           4 :                                          ps, fs, static_ps, static_fs, ctorp, ctorKind);
    1927             : }
    1928             : 
    1929             : void
    1930           0 : JSObject::fixupAfterMovingGC()
    1931             : {
    1932             :     // For copy-on-write objects that don't own their elements, fix up the
    1933             :     // elements pointer if it points to inline elements in the owning object.
    1934           0 :     if (is<NativeObject>()) {
    1935           0 :         NativeObject& obj = as<NativeObject>();
    1936           0 :         if (obj.denseElementsAreCopyOnWrite()) {
    1937           0 :             NativeObject* owner = obj.getElementsHeader()->ownerObject();
    1938             :             // Get the new owner pointer but don't call MaybeForwarded as we
    1939             :             // don't need to access the object's shape.
    1940           0 :             if (IsForwarded(owner))
    1941           0 :                 owner = Forwarded(owner);
    1942           0 :             if (owner != &obj && owner->hasFixedElements())
    1943           0 :                 obj.elements_ = owner->getElementsHeader()->elements();
    1944           0 :             MOZ_ASSERT(!IsForwarded(obj.getElementsHeader()->ownerObject().get()));
    1945             :         }
    1946             :     }
    1947           0 : }
    1948             : 
    1949             : bool
    1950         692 : js::SetClassAndProto(JSContext* cx, HandleObject obj,
    1951             :                      const Class* clasp, Handle<js::TaggedProto> proto)
    1952             : {
    1953             :     // Regenerate the object's shape. If the object is a proto (isDelegate()),
    1954             :     // we also need to regenerate shapes for all of the objects along the old
    1955             :     // prototype chain, in case any entries were filled by looking up through
    1956             :     // obj. Stop when a non-native object is found, prototype lookups will not
    1957             :     // be cached across these.
    1958             :     //
    1959             :     // How this shape change is done is very delicate; the change can be made
    1960             :     // either by marking the object's prototype as uncacheable (such that the
    1961             :     // JIT'ed ICs cannot assume the shape determines the prototype) or by just
    1962             :     // generating a new shape for the object. Choosing the former is bad if the
    1963             :     // object is on the prototype chain of other objects, as the uncacheable
    1964             :     // prototype can inhibit iterator caches on those objects and slow down
    1965             :     // prototype accesses. Choosing the latter is bad if there are many similar
    1966             :     // objects to this one which will have their prototype mutated, as the
    1967             :     // generateOwnShape forces the object into dictionary mode and similar
    1968             :     // property lineages will be repeatedly cloned.
    1969             :     //
    1970             :     // :XXX: bug 707717 make this code less brittle.
    1971        1384 :     RootedObject oldproto(cx, obj);
    1972         692 :     while (oldproto && oldproto->isNative()) {
    1973         692 :         if (oldproto->isSingleton()) {
    1974             :             // We always generate a new shape if the object is a singleton,
    1975             :             // regardless of the uncacheable-proto flag. ICs may rely on
    1976             :             // this.
    1977          62 :             if (!NativeObject::generateOwnShape(cx, oldproto.as<NativeObject>()))
    1978           0 :                 return false;
    1979             :         } else {
    1980         630 :             if (!JSObject::setUncacheableProto(cx, oldproto))
    1981           0 :                 return false;
    1982             :         }
    1983         692 :         if (!obj->isDelegate()) {
    1984             :             // If |obj| is not a proto of another object, we don't need to
    1985             :             // reshape the whole proto chain.
    1986         692 :             MOZ_ASSERT(obj == oldproto);
    1987         692 :             break;
    1988             :         }
    1989           0 :         oldproto = oldproto->staticPrototype();
    1990             :     }
    1991             : 
    1992         692 :     if (proto.isObject()) {
    1993        1220 :         RootedObject protoObj(cx, proto.toObject());
    1994         610 :         if (!JSObject::setDelegate(cx, protoObj))
    1995           0 :             return false;
    1996             :     }
    1997             : 
    1998         692 :     if (obj->isSingleton()) {
    1999             :         /*
    2000             :          * Just splice the prototype, but mark the properties as unknown for
    2001             :          * consistent behavior.
    2002             :          */
    2003          62 :         if (!JSObject::splicePrototype(cx, obj, clasp, proto))
    2004           0 :             return false;
    2005          62 :         MarkObjectGroupUnknownProperties(cx, obj->group());
    2006          62 :         return true;
    2007             :     }
    2008             : 
    2009        1260 :     RootedObjectGroup oldGroup(cx, obj->group());
    2010             : 
    2011             :     ObjectGroup* newGroup;
    2012         630 :     if (oldGroup->maybeInterpretedFunction()) {
    2013             :         // We're changing the group/proto of a scripted function. Create a new
    2014             :         // group so we can keep track of the interpreted function for Ion
    2015             :         // inlining.
    2016           6 :         MOZ_ASSERT(obj->is<JSFunction>());
    2017           6 :         newGroup = ObjectGroupCompartment::makeGroup(cx, &JSFunction::class_, proto);
    2018           6 :         if (!newGroup)
    2019           0 :             return false;
    2020           6 :         newGroup->setInterpretedFunction(oldGroup->maybeInterpretedFunction());
    2021             :     } else {
    2022         624 :         newGroup = ObjectGroup::defaultNewGroup(cx, clasp, proto);
    2023         624 :         if (!newGroup)
    2024           0 :             return false;
    2025             :     }
    2026             : 
    2027         630 :     obj->setGroup(newGroup);
    2028             : 
    2029             :     // Add the object's property types to the new group.
    2030         630 :     if (!newGroup->unknownProperties()) {
    2031          76 :         if (obj->isNative())
    2032          76 :             AddPropertyTypesAfterProtoChange(cx, &obj->as<NativeObject>(), oldGroup);
    2033             :         else
    2034           0 :             MarkObjectGroupUnknownProperties(cx, newGroup);
    2035             :     }
    2036             : 
    2037             :     // Type sets containing this object will contain the old group but not the
    2038             :     // new group of the object, so we need to treat all such type sets as
    2039             :     // unknown.
    2040         630 :     MarkObjectGroupUnknownProperties(cx, oldGroup);
    2041             : 
    2042         630 :     return true;
    2043             : }
    2044             : 
    2045             : /* static */ bool
    2046         109 : JSObject::changeToSingleton(JSContext* cx, HandleObject obj)
    2047             : {
    2048         109 :     MOZ_ASSERT(!obj->isSingleton());
    2049             : 
    2050         109 :     MarkObjectGroupUnknownProperties(cx, obj->group());
    2051             : 
    2052         109 :     ObjectGroup* group = ObjectGroup::lazySingletonGroup(cx, obj->getClass(),
    2053         218 :                                                          obj->taggedProto());
    2054         109 :     if (!group)
    2055           0 :         return false;
    2056             : 
    2057         109 :     obj->group_ = group;
    2058         109 :     return true;
    2059             : }
    2060             : 
    2061             : static bool
    2062      113471 : MaybeResolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey key)
    2063             : {
    2064      113471 :     if (global->isStandardClassResolved(key))
    2065      113108 :         return true;
    2066         360 :     MOZ_ASSERT(!cx->helperThread());
    2067             : 
    2068         360 :     return GlobalObject::resolveConstructor(cx, global, key);
    2069             : }
    2070             : 
    2071             : bool
    2072          77 : js::GetBuiltinConstructor(JSContext* cx, JSProtoKey key, MutableHandleObject objp)
    2073             : {
    2074          77 :     MOZ_ASSERT(key != JSProto_Null);
    2075         154 :     Rooted<GlobalObject*> global(cx, cx->global());
    2076          77 :     if (!MaybeResolveConstructor(cx, global, key))
    2077           0 :         return false;
    2078             : 
    2079          77 :     objp.set(&global->getConstructor(key).toObject());
    2080          77 :     return true;
    2081             : }
    2082             : 
    2083             : bool
    2084      113394 : js::GetBuiltinPrototype(JSContext* cx, JSProtoKey key, MutableHandleObject protop)
    2085             : {
    2086      113394 :     MOZ_ASSERT(key != JSProto_Null);
    2087      226789 :     Rooted<GlobalObject*> global(cx, cx->global());
    2088      113394 :     if (!MaybeResolveConstructor(cx, global, key))
    2089           0 :         return false;
    2090             : 
    2091      113392 :     protop.set(&global->getPrototype(key).toObject());
    2092      113395 :     return true;
    2093             : }
    2094             : 
    2095             : bool
    2096        6929 : js::IsStandardPrototype(JSObject* obj, JSProtoKey key)
    2097             : {
    2098        6929 :     GlobalObject& global = obj->global();
    2099        6929 :     Value v = global.getPrototype(key);
    2100        6929 :     return v.isObject() && obj == &v.toObject();
    2101             : }
    2102             : 
    2103             : 
    2104             : /**
    2105             :  * Returns the original Object.prototype from the embedding-provided incumbent
    2106             :  * global.
    2107             :  *
    2108             :  * Really, we want the incumbent global itself so we can pass it to other
    2109             :  * embedding hooks which need it. Specifically, the enqueue promise hook
    2110             :  * takes an incumbent global so it can set that on the PromiseCallbackJob
    2111             :  * it creates.
    2112             :  *
    2113             :  * The reason for not just returning the global itself is that we'd need to
    2114             :  * wrap it into the current compartment, and later unwrap it. Unwrapping
    2115             :  * globals is tricky, though: we might accidentally unwrap through an inner
    2116             :  * to its outer window and end up with the wrong global. Plain objects don't
    2117             :  * have this problem, so we use the global's Object.prototype. The code using
    2118             :  * it - e.g. EnqueuePromiseReactionJob - can then unwrap the object and get
    2119             :  * its global without fear of unwrapping too far.
    2120             :  */
    2121             : bool
    2122         346 : js::GetObjectFromIncumbentGlobal(JSContext* cx, MutableHandleObject obj)
    2123             : {
    2124         692 :     RootedObject globalObj(cx, cx->runtime()->getIncumbentGlobal(cx));
    2125         346 :     if (!globalObj) {
    2126           0 :         obj.set(nullptr);
    2127           0 :         return true;
    2128             :     }
    2129             : 
    2130             :     {
    2131         692 :         AutoCompartment ac(cx, globalObj);
    2132         346 :         Handle<GlobalObject*> global = globalObj.as<GlobalObject>();
    2133         346 :         obj.set(GlobalObject::getOrCreateObjectPrototype(cx, global));
    2134         346 :         if (!obj)
    2135           0 :             return false;
    2136             :     }
    2137             : 
    2138             :     // The object might be from a different compartment, so wrap it.
    2139         346 :     if (obj && !cx->compartment()->wrap(cx, obj))
    2140           0 :         return false;
    2141             : 
    2142         346 :     return true;
    2143             : }
    2144             : 
    2145             : JSProtoKey
    2146           6 : JS::IdentifyStandardInstance(JSObject* obj)
    2147             : {
    2148             :     // Note: The prototype shares its JSClass with instances.
    2149           6 :     MOZ_ASSERT(!obj->is<CrossCompartmentWrapperObject>());
    2150           6 :     JSProtoKey key = StandardProtoKeyOrNull(obj);
    2151           6 :     if (key != JSProto_Null && !IsStandardPrototype(obj, key))
    2152           4 :         return key;
    2153           2 :     return JSProto_Null;
    2154             : }
    2155             : 
    2156             : JSProtoKey
    2157        6923 : JS::IdentifyStandardPrototype(JSObject* obj)
    2158             : {
    2159             :     // Note: The prototype shares its JSClass with instances.
    2160        6923 :     MOZ_ASSERT(!obj->is<CrossCompartmentWrapperObject>());
    2161        6923 :     JSProtoKey key = StandardProtoKeyOrNull(obj);
    2162        6923 :     if (key != JSProto_Null && IsStandardPrototype(obj, key))
    2163        6649 :         return key;
    2164         274 :     return JSProto_Null;
    2165             : }
    2166             : 
    2167             : JSProtoKey
    2168        1137 : JS::IdentifyStandardInstanceOrPrototype(JSObject* obj)
    2169             : {
    2170        1137 :     return StandardProtoKeyOrNull(obj);
    2171             : }
    2172             : 
    2173             : JSProtoKey
    2174           0 : JS::IdentifyStandardConstructor(JSObject* obj)
    2175             : {
    2176             :     // Note that NATIVE_CTOR does not imply that we are a standard constructor,
    2177             :     // but the converse is true (at least until we start having self-hosted
    2178             :     // constructors for standard classes). This lets us avoid a costly loop for
    2179             :     // many functions (which, depending on the call site, may be the common case).
    2180           0 :     if (!obj->is<JSFunction>() || !(obj->as<JSFunction>().flags() & JSFunction::NATIVE_CTOR))
    2181           0 :         return JSProto_Null;
    2182             : 
    2183           0 :     GlobalObject& global = obj->global();
    2184           0 :     for (size_t k = 0; k < JSProto_LIMIT; ++k) {
    2185           0 :         JSProtoKey key = static_cast<JSProtoKey>(k);
    2186           0 :         if (global.getConstructor(key) == ObjectValue(*obj))
    2187           0 :             return key;
    2188             :     }
    2189             : 
    2190           0 :     return JSProto_Null;
    2191             : }
    2192             : 
    2193             : bool
    2194       17258 : js::LookupProperty(JSContext* cx, HandleObject obj, js::HandleId id,
    2195             :                    MutableHandleObject objp, MutableHandle<PropertyResult> propp)
    2196             : {
    2197       17258 :     if (LookupPropertyOp op = obj->getOpsLookupProperty())
    2198        3130 :         return op(cx, obj, id, objp, propp);
    2199       14128 :     return LookupPropertyInline<CanGC>(cx, obj.as<NativeObject>(), id, objp, propp);
    2200             : }
    2201             : 
    2202             : bool
    2203        2308 : js::LookupName(JSContext* cx, HandlePropertyName name, HandleObject envChain,
    2204             :                MutableHandleObject objp, MutableHandleObject pobjp, MutableHandle<PropertyResult> propp)
    2205             : {
    2206        4616 :     RootedId id(cx, NameToId(name));
    2207             : 
    2208        7623 :     for (RootedObject env(cx, envChain); env; env = env->enclosingEnvironment()) {
    2209        7609 :         if (!LookupProperty(cx, env, id, pobjp, propp))
    2210           0 :             return false;
    2211        7609 :         if (propp) {
    2212        2294 :             objp.set(env);
    2213        2294 :             return true;
    2214             :         }
    2215             :     }
    2216             : 
    2217          14 :     objp.set(nullptr);
    2218          14 :     pobjp.set(nullptr);
    2219          14 :     propp.setNotFound();
    2220          14 :     return true;
    2221             : }
    2222             : 
    2223             : bool
    2224       17072 : js::LookupNameNoGC(JSContext* cx, PropertyName* name, JSObject* envChain,
    2225             :                    JSObject** objp, JSObject** pobjp, PropertyResult* propp)
    2226             : {
    2227       34144 :     AutoAssertNoException nogc(cx);
    2228             : 
    2229       17072 :     MOZ_ASSERT(!*objp && !*pobjp && !*propp);
    2230             : 
    2231       31910 :     for (JSObject* env = envChain; env; env = env->enclosingEnvironment()) {
    2232       31910 :         if (env->getOpsLookupProperty())
    2233        1073 :             return false;
    2234       30837 :         if (!LookupPropertyInline<NoGC>(cx, &env->as<NativeObject>(), NameToId(name), pobjp, propp))
    2235         653 :             return false;
    2236       30184 :         if (*propp) {
    2237       15346 :             *objp = env;
    2238       15346 :             return true;
    2239             :         }
    2240             :     }
    2241             : 
    2242           0 :     return true;
    2243             : }
    2244             : 
    2245             : bool
    2246         919 : js::LookupNameWithGlobalDefault(JSContext* cx, HandlePropertyName name, HandleObject envChain,
    2247             :                                 MutableHandleObject objp)
    2248             : {
    2249        1838 :     RootedId id(cx, NameToId(name));
    2250             : 
    2251        1838 :     RootedObject pobj(cx);
    2252        1838 :     Rooted<PropertyResult> prop(cx);
    2253             : 
    2254        1838 :     RootedObject env(cx, envChain);
    2255        5075 :     for (; !env->is<GlobalObject>(); env = env->enclosingEnvironment()) {
    2256        2515 :         if (!LookupProperty(cx, env, id, &pobj, &prop))
    2257           0 :             return false;
    2258        2515 :         if (prop)
    2259         437 :             break;
    2260             :     }
    2261             : 
    2262         919 :     objp.set(env);
    2263         919 :     return true;
    2264             : }
    2265             : 
    2266             : bool
    2267         844 : js::LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject envChain,
    2268             :                           MutableHandleObject objp)
    2269             : {
    2270        1688 :     RootedId id(cx, NameToId(name));
    2271             : 
    2272        1688 :     RootedObject pobj(cx);
    2273        1688 :     Rooted<PropertyResult> prop(cx);
    2274             : 
    2275        1688 :     RootedObject env(cx, envChain);
    2276        2448 :     for (; !env->isUnqualifiedVarObj(); env = env->enclosingEnvironment()) {
    2277         866 :         if (!LookupProperty(cx, env, id, &pobj, &prop))
    2278           0 :             return false;
    2279         866 :         if (prop)
    2280          64 :             break;
    2281             :     }
    2282             : 
    2283             :     // See note above RuntimeLexicalErrorObject.
    2284         844 :     if (pobj == env) {
    2285          44 :         bool isTDZ = false;
    2286          44 :         if (prop && name != cx->names().dotThis) {
    2287             :             // Treat Debugger environments specially for TDZ checks, as they
    2288             :             // look like non-native environments but in fact wrap native
    2289             :             // environments.
    2290          44 :             if (env->is<DebugEnvironmentProxy>()) {
    2291           0 :                 RootedValue v(cx);
    2292           0 :                 Rooted<DebugEnvironmentProxy*> envProxy(cx, &env->as<DebugEnvironmentProxy>());
    2293           0 :                 if (!DebugEnvironmentProxy::getMaybeSentinelValue(cx, envProxy, id, &v))
    2294           0 :                     return false;
    2295           0 :                 isTDZ = IsUninitializedLexical(v);
    2296             :             } else {
    2297          44 :                 isTDZ = IsUninitializedLexicalSlot(env, prop);
    2298             :             }
    2299             :         }
    2300             : 
    2301          44 :         if (isTDZ) {
    2302           0 :             env = RuntimeLexicalErrorObject::create(cx, env, JSMSG_UNINITIALIZED_LEXICAL);
    2303           0 :             if (!env)
    2304           0 :                 return false;
    2305          44 :         } else if (env->is<LexicalEnvironmentObject>() && !prop.shape()->writable()) {
    2306             :             // Assigning to a named lambda callee name is a no-op in sloppy mode.
    2307           0 :             Rooted<LexicalEnvironmentObject*> lexicalEnv(cx, &env->as<LexicalEnvironmentObject>());
    2308           0 :             if (lexicalEnv->isExtensible() ||
    2309           0 :                 lexicalEnv->scope().kind() != ScopeKind::NamedLambda)
    2310             :             {
    2311           0 :                 MOZ_ASSERT(name != cx->names().dotThis);
    2312           0 :                 env = RuntimeLexicalErrorObject::create(cx, env, JSMSG_BAD_CONST_ASSIGN);
    2313           0 :                 if (!env)
    2314           0 :                     return false;
    2315             :             }
    2316             :         }
    2317             :     }
    2318             : 
    2319         844 :     objp.set(env);
    2320         844 :     return true;
    2321             : }
    2322             : 
    2323             : bool
    2324        4349 : js::HasOwnProperty(JSContext* cx, HandleObject obj, HandleId id, bool* result)
    2325             : {
    2326        4349 :     if (obj->is<ProxyObject>())
    2327          52 :         return Proxy::hasOwn(cx, obj, id, result);
    2328             : 
    2329        4297 :     if (GetOwnPropertyOp op = obj->getOpsGetOwnPropertyDescriptor()) {
    2330           0 :         Rooted<PropertyDescriptor> desc(cx);
    2331           0 :         if (!op(cx, obj, id, &desc))
    2332           0 :             return false;
    2333           0 :         *result = !!desc.object();
    2334           0 :         return true;
    2335             :     }
    2336             : 
    2337        8594 :     Rooted<PropertyResult> prop(cx);
    2338        4297 :     if (!NativeLookupOwnProperty<CanGC>(cx, obj.as<NativeObject>(), id, &prop))
    2339           0 :         return false;
    2340        4297 :     *result = prop.isFound();
    2341        4297 :     return true;
    2342             : }
    2343             : 
    2344             : bool
    2345        6137 : js::LookupPropertyPure(JSContext* cx, JSObject* obj, jsid id, JSObject** objp,
    2346             :                        PropertyResult* propp)
    2347             : {
    2348        6137 :     bool isTypedArrayOutOfRange = false;
    2349        2048 :     do {
    2350        8185 :         if (!LookupOwnPropertyPure(cx, obj, id, propp, &isTypedArrayOutOfRange))
    2351        1003 :             return false;
    2352             : 
    2353        7182 :         if (*propp) {
    2354        4493 :             *objp = obj;
    2355        4493 :             return true;
    2356             :         }
    2357             : 
    2358        2689 :         if (isTypedArrayOutOfRange) {
    2359           0 :             *objp = nullptr;
    2360           0 :             return true;
    2361             :         }
    2362             : 
    2363        2689 :         obj = obj->staticPrototype();
    2364        2689 :     } while (obj);
    2365             : 
    2366         641 :     *objp = nullptr;
    2367         641 :     propp->setNotFound();
    2368         641 :     return true;
    2369             : }
    2370             : 
    2371             : bool
    2372        8257 : js::LookupOwnPropertyPure(JSContext* cx, JSObject* obj, jsid id, PropertyResult* propp,
    2373             :                           bool* isTypedArrayOutOfRange /* = nullptr */)
    2374             : {
    2375       16514 :     JS::AutoCheckCannotGC nogc;
    2376        8257 :     if (isTypedArrayOutOfRange)
    2377        8185 :         *isTypedArrayOutOfRange = false;
    2378             : 
    2379        8257 :     if (obj->isNative()) {
    2380             :         // Search for a native dense element, typed array element, or property.
    2381             : 
    2382        7538 :         if (JSID_IS_INT(id) && obj->as<NativeObject>().containsDenseElement(JSID_TO_INT(id))) {
    2383           0 :             propp->setDenseOrTypedArrayElement();
    2384           0 :             return true;
    2385             :         }
    2386             : 
    2387        7538 :         if (obj->is<TypedArrayObject>()) {
    2388             :             uint64_t index;
    2389           0 :             if (IsTypedArrayIndex(id, &index)) {
    2390           0 :                 if (index < obj->as<TypedArrayObject>().length()) {
    2391           0 :                     propp->setDenseOrTypedArrayElement();
    2392             :                 } else {
    2393           0 :                     propp->setNotFound();
    2394           0 :                     if (isTypedArrayOutOfRange)
    2395           0 :                         *isTypedArrayOutOfRange = true;
    2396             :                 }
    2397           0 :                 return true;
    2398             :             }
    2399             :         }
    2400             : 
    2401        7538 :         if (Shape* shape = obj->as<NativeObject>().lookupPure(id)) {
    2402        4557 :             propp->setNativeProperty(shape);
    2403        4557 :             return true;
    2404             :         }
    2405             : 
    2406             :         // Fail if there's a resolve hook, unless the mayResolve hook tells
    2407             :         // us the resolve hook won't define a property with this id.
    2408        2981 :         if (ClassMayResolveId(cx->names(), obj->getClass(), id, obj))
    2409         292 :             return false;
    2410         719 :     } else if (obj->is<UnboxedPlainObject>()) {
    2411           8 :         if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) {
    2412           8 :             propp->setNonNativeProperty();
    2413           8 :             return true;
    2414             :         }
    2415         711 :     } else if (obj->is<UnboxedArrayObject>()) {
    2416           0 :         if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
    2417           0 :             propp->setNonNativeProperty();
    2418           0 :             return true;
    2419             :         }
    2420         711 :     } else if (obj->is<TypedObject>()) {
    2421           0 :         if (obj->as<TypedObject>().typeDescr().hasProperty(cx->names(), id)) {
    2422           0 :             propp->setNonNativeProperty();
    2423           0 :             return true;
    2424             :         }
    2425             :     } else {
    2426         711 :         return false;
    2427             :     }
    2428             : 
    2429        2689 :     propp->setNotFound();
    2430        2689 :     return true;
    2431             : }
    2432             : 
    2433             : static inline bool
    2434         536 : NativeGetPureInline(NativeObject* pobj, jsid id, PropertyResult prop, Value* vp)
    2435             : {
    2436         536 :     if (prop.isDenseOrTypedArrayElement()) {
    2437             :         // For simplicity we ignore the TypedArray with string index case.
    2438           0 :         if (!JSID_IS_INT(id))
    2439           0 :             return false;
    2440             : 
    2441           0 :         *vp = pobj->getDenseOrTypedArrayElement(JSID_TO_INT(id));
    2442           0 :         return true;
    2443             :     }
    2444             : 
    2445             :     // Fail if we have a custom getter.
    2446         536 :     Shape* shape = prop.shape();
    2447         536 :     if (!shape->hasDefaultGetter())
    2448           0 :         return false;
    2449             : 
    2450         536 :     if (shape->hasSlot()) {
    2451         536 :         *vp = pobj->getSlot(shape->slot());
    2452         536 :         MOZ_ASSERT(!vp->isMagic());
    2453             :     } else {
    2454           0 :         vp->setUndefined();
    2455             :     }
    2456             : 
    2457         536 :     return true;
    2458             : }
    2459             : 
    2460             : bool
    2461         542 : js::GetPropertyPure(JSContext* cx, JSObject* obj, jsid id, Value* vp)
    2462             : {
    2463             :     JSObject* pobj;
    2464         542 :     PropertyResult prop;
    2465         542 :     if (!LookupPropertyPure(cx, obj, id, &pobj, &prop))
    2466           2 :         return false;
    2467             : 
    2468         540 :     if (!prop) {
    2469           4 :         vp->setUndefined();
    2470           4 :         return true;
    2471             :     }
    2472             : 
    2473         536 :     return pobj->isNative() && NativeGetPureInline(&pobj->as<NativeObject>(), id, prop, vp);
    2474             : }
    2475             : 
    2476             : static inline bool
    2477          31 : NativeGetGetterPureInline(PropertyResult prop, JSFunction** fp)
    2478             : {
    2479          31 :     if (!prop.isDenseOrTypedArrayElement() && prop.shape()->hasGetterObject()) {
    2480          31 :         Shape* shape = prop.shape();
    2481          31 :         if (shape->getterObject()->is<JSFunction>()) {
    2482          31 :             *fp = &shape->getterObject()->as<JSFunction>();
    2483          31 :             return true;
    2484             :         }
    2485             :     }
    2486             : 
    2487           0 :     *fp = nullptr;
    2488           0 :     return true;
    2489             : }
    2490             : 
    2491             : bool
    2492          23 : js::GetGetterPure(JSContext* cx, JSObject* obj, jsid id, JSFunction** fp)
    2493             : {
    2494             :     /* Just like GetPropertyPure, but get getter function, without invoking
    2495             :      * it. */
    2496             :     JSObject* pobj;
    2497          23 :     PropertyResult prop;
    2498          23 :     if (!LookupPropertyPure(cx, obj, id, &pobj, &prop))
    2499           0 :         return false;
    2500             : 
    2501          23 :     if (!prop) {
    2502           0 :         *fp = nullptr;
    2503           0 :         return true;
    2504             :     }
    2505             : 
    2506          23 :     return prop.isNativeProperty() && NativeGetGetterPureInline(prop, fp);
    2507             : }
    2508             : 
    2509             : bool
    2510           8 : js::GetOwnGetterPure(JSContext* cx, JSObject* obj, jsid id, JSFunction** fp)
    2511             : {
    2512          16 :     JS::AutoCheckCannotGC nogc;
    2513           8 :     PropertyResult prop;
    2514           8 :     if (!LookupOwnPropertyPure(cx, obj, id, &prop))
    2515           0 :         return false;
    2516             : 
    2517           8 :     if (!prop) {
    2518           0 :         *fp = nullptr;
    2519           0 :         return true;
    2520             :     }
    2521             : 
    2522           8 :     return prop.isNativeProperty() && NativeGetGetterPureInline(prop, fp);
    2523             : }
    2524             : 
    2525             : bool
    2526          40 : js::GetOwnNativeGetterPure(JSContext* cx, JSObject* obj, jsid id, JSNative* native)
    2527             : {
    2528          80 :     JS::AutoCheckCannotGC nogc;
    2529          40 :     *native = nullptr;
    2530          40 :     PropertyResult prop;
    2531          40 :     if (!LookupOwnPropertyPure(cx, obj, id, &prop))
    2532           0 :         return false;
    2533             : 
    2534          40 :     if (!prop || prop.isDenseOrTypedArrayElement() || !prop.shape()->hasGetterObject())
    2535           0 :         return true;
    2536             : 
    2537          40 :     JSObject* getterObj = prop.shape()->getterObject();
    2538          40 :     if (!getterObj->is<JSFunction>())
    2539           0 :         return true;
    2540             : 
    2541          40 :     JSFunction* getter = &getterObj->as<JSFunction>();
    2542          40 :     if (!getter->isNative())
    2543           0 :         return true;
    2544             : 
    2545          40 :     *native = getter->native();
    2546          40 :     return true;
    2547             : }
    2548             : 
    2549             : bool
    2550          24 : js::HasOwnDataPropertyPure(JSContext* cx, JSObject* obj, jsid id, bool* result)
    2551             : {
    2552          24 :     PropertyResult prop;
    2553          24 :     if (!LookupOwnPropertyPure(cx, obj, id, &prop))
    2554           0 :         return false;
    2555             : 
    2556          48 :     *result = prop && !prop.isDenseOrTypedArrayElement() && prop.shape()->hasDefaultGetter() &&
    2557          24 :               prop.shape()->hasSlot();
    2558          24 :     return true;
    2559             : }
    2560             : 
    2561             : /* static */ bool
    2562           0 : JSObject::reportReadOnly(JSContext* cx, jsid id, unsigned report)
    2563             : {
    2564           0 :     RootedValue val(cx, IdToValue(id));
    2565           0 :     return ReportValueErrorFlags(cx, report, JSMSG_READ_ONLY,
    2566             :                                  JSDVG_IGNORE_STACK, val, nullptr,
    2567           0 :                                  nullptr, nullptr);
    2568             : }
    2569             : 
    2570             : /* static */ bool
    2571           0 : JSObject::reportNotConfigurable(JSContext* cx, jsid id, unsigned report)
    2572             : {
    2573           0 :     RootedValue val(cx, IdToValue(id));
    2574           0 :     return ReportValueErrorFlags(cx, report, JSMSG_CANT_DELETE,
    2575             :                                  JSDVG_IGNORE_STACK, val, nullptr,
    2576           0 :                                  nullptr, nullptr);
    2577             : }
    2578             : 
    2579             : /* static */ bool
    2580           0 : JSObject::reportNotExtensible(JSContext* cx, HandleObject obj, unsigned report)
    2581             : {
    2582           0 :     RootedValue val(cx, ObjectValue(*obj));
    2583           0 :     return ReportValueErrorFlags(cx, report, JSMSG_OBJECT_NOT_EXTENSIBLE,
    2584             :                                  JSDVG_IGNORE_STACK, val, nullptr,
    2585           0 :                                  nullptr, nullptr);
    2586             : }
    2587             : 
    2588             : bool
    2589        3886 : js::GetPrototypeIfOrdinary(JSContext* cx, HandleObject obj, bool* isOrdinary,
    2590             :                            MutableHandleObject protop)
    2591             : {
    2592        3886 :     if (obj->is<js::ProxyObject>())
    2593           5 :         return js::Proxy::getPrototypeIfOrdinary(cx, obj, isOrdinary, protop);
    2594             : 
    2595        3881 :     *isOrdinary = true;
    2596        3881 :     protop.set(obj->staticPrototype());
    2597        3881 :     return true;
    2598             : }
    2599             : 
    2600             : /*** ES6 standard internal methods ***************************************************************/
    2601             : 
    2602             : bool
    2603         695 : js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto, JS::ObjectOpResult& result)
    2604             : {
    2605             :     // The proxy trap subsystem fully handles prototype-setting for proxies
    2606             :     // with dynamic [[Prototype]]s.
    2607         695 :     if (obj->hasDynamicPrototype()) {
    2608           0 :         MOZ_ASSERT(obj->is<ProxyObject>());
    2609           0 :         return Proxy::setPrototype(cx, obj, proto, result);
    2610             :     }
    2611             : 
    2612             :     /*
    2613             :      * ES6 9.1.2 step 3-4 if |obj.[[Prototype]]| has SameValue as |proto| return true.
    2614             :      * Since the values in question are objects, we can just compare pointers.
    2615             :      */
    2616         695 :     if (proto == obj->staticPrototype())
    2617           3 :         return result.succeed();
    2618             : 
    2619             :     /* Disallow mutation of immutable [[Prototype]]s. */
    2620         692 :     if (obj->staticPrototypeIsImmutable())
    2621           0 :         return result.fail(JSMSG_CANT_SET_PROTO);
    2622             : 
    2623             :     /*
    2624             :      * Disallow mutating the [[Prototype]] on ArrayBuffer objects, which
    2625             :      * due to their complicated delegate-object shenanigans can't easily
    2626             :      * have a mutable [[Prototype]].
    2627             :      */
    2628         692 :     if (obj->is<ArrayBufferObject>()) {
    2629             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_SET_PROTO_OF,
    2630           0 :                                   "incompatible ArrayBuffer");
    2631           0 :         return false;
    2632             :     }
    2633             : 
    2634             :     /*
    2635             :      * Disallow mutating the [[Prototype]] on Typed Objects, per the spec.
    2636             :      */
    2637         692 :     if (obj->is<TypedObject>()) {
    2638             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_SET_PROTO_OF,
    2639           0 :                                   "incompatible TypedObject");
    2640           0 :         return false;
    2641             :     }
    2642             : 
    2643             :     /* ES6 9.1.2 step 5 forbids changing [[Prototype]] if not [[Extensible]]. */
    2644             :     bool extensible;
    2645         692 :     if (!IsExtensible(cx, obj, &extensible))
    2646           0 :         return false;
    2647         692 :     if (!extensible)
    2648           0 :         return result.fail(JSMSG_CANT_SET_PROTO);
    2649             : 
    2650             :     // If this is a global object, resolve the Object class so that its
    2651             :     // [[Prototype]] chain is always properly immutable, even in the presence
    2652             :     // of lazy standard classes.
    2653         692 :     if (obj->is<GlobalObject>()) {
    2654           0 :         Handle<GlobalObject*> global = obj.as<GlobalObject>();
    2655           0 :         if (!GlobalObject::ensureConstructor(cx, global, JSProto_Object))
    2656           0 :             return false;
    2657             :     }
    2658             : 
    2659             :     /*
    2660             :      * ES6 9.1.2 step 6 forbids generating cyclical prototype chains. But we
    2661             :      * have to do this comparison on the observable WindowProxy, not on the
    2662             :      * possibly-Window object we're setting the proto on.
    2663             :      */
    2664        1384 :     RootedObject objMaybeWindowProxy(cx, ToWindowProxyIfWindow(obj));
    2665        1384 :     RootedObject obj2(cx, proto);
    2666        8454 :     while (obj2) {
    2667        3881 :         MOZ_ASSERT(!IsWindow(obj2));
    2668        3881 :         if (obj2 == objMaybeWindowProxy)
    2669           0 :             return result.fail(JSMSG_CANT_SET_PROTO_CYCLE);
    2670             : 
    2671             :         bool isOrdinary;
    2672        3881 :         if (!GetPrototypeIfOrdinary(cx, obj2, &isOrdinary, &obj2))
    2673           0 :             return false;
    2674        3881 :         if (!isOrdinary)
    2675           0 :             break;
    2676             :     }
    2677             : 
    2678             :     // Convert unboxed objects to their native representations before changing
    2679             :     // their prototype/group, as they depend on the group for their layout.
    2680         692 :     if (!MaybeConvertUnboxedObjectToNative(cx, obj))
    2681           0 :         return false;
    2682             : 
    2683        1384 :     Rooted<TaggedProto> taggedProto(cx, TaggedProto(proto));
    2684         692 :     if (!SetClassAndProto(cx, obj, obj->getClass(), taggedProto))
    2685           0 :         return false;
    2686             : 
    2687         692 :     return result.succeed();
    2688             : }
    2689             : 
    2690             : bool
    2691         692 : js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto)
    2692             : {
    2693         692 :     ObjectOpResult result;
    2694         692 :     return SetPrototype(cx, obj, proto, result) && result.checkStrict(cx, obj);
    2695             : }
    2696             : 
    2697             : bool
    2698        2710 : js::PreventExtensions(JSContext* cx, HandleObject obj, ObjectOpResult& result, IntegrityLevel level)
    2699             : {
    2700        2710 :     if (obj->is<ProxyObject>())
    2701           3 :         return js::Proxy::preventExtensions(cx, obj, result);
    2702             : 
    2703        2707 :     if (!obj->nonProxyIsExtensible())
    2704           1 :         return result.succeed();
    2705             : 
    2706        2706 :     if (!MaybeConvertUnboxedObjectToNative(cx, obj))
    2707           0 :         return false;
    2708             : 
    2709             :     // Force lazy properties to be resolved.
    2710        2706 :     if (obj->isNative()) {
    2711        2706 :         const Class* clasp = obj->getClass();
    2712        2706 :         if (JSEnumerateOp enumerate = clasp->getEnumerate()) {
    2713         373 :             if (!enumerate(cx, obj.as<NativeObject>()))
    2714           0 :                 return false;
    2715             :         }
    2716        2706 :         if (clasp->getNewEnumerate() && clasp->getResolve()) {
    2717           0 :             AutoIdVector properties(cx);
    2718           0 :             if (!clasp->getNewEnumerate()(cx, obj, properties, /* enumerableOnly = */ false))
    2719           0 :                 return false;
    2720             : 
    2721           0 :             RootedId id(cx);
    2722           0 :             for (size_t i = 0; i < properties.length(); i++) {
    2723           0 :                 id = properties[i];
    2724             :                 bool found;
    2725           0 :                 if (!HasOwnProperty(cx, obj, id, &found))
    2726           0 :                     return false;
    2727             :             }
    2728             :         }
    2729             :     }
    2730             : 
    2731             :     // Sparsify dense elements, to make sure no element can be added without a
    2732             :     // call to isExtensible, at the cost of performance. If the object is being
    2733             :     // frozen, the caller is responsible for freezing the elements (and all
    2734             :     // other properties).
    2735        2706 :     if (obj->isNative() && level != IntegrityLevel::Frozen) {
    2736         316 :         if (!NativeObject::sparsifyDenseElements(cx, obj.as<NativeObject>()))
    2737           0 :             return false;
    2738             :     }
    2739             : 
    2740        2706 :     if (!JSObject::setFlags(cx, obj, BaseShape::NOT_EXTENSIBLE, JSObject::GENERATE_SHAPE))
    2741           0 :         return false;
    2742             : 
    2743        2706 :     return result.succeed();
    2744             : }
    2745             : 
    2746             : bool
    2747        2707 : js::PreventExtensions(JSContext* cx, HandleObject obj, IntegrityLevel level)
    2748             : {
    2749        2707 :     ObjectOpResult result;
    2750        2707 :     return PreventExtensions(cx, obj, result, level) && result.checkStrict(cx, obj);
    2751             : }
    2752             : 
    2753             : bool
    2754       10198 : js::GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
    2755             :                              MutableHandle<PropertyDescriptor> desc)
    2756             : {
    2757       10198 :     if (GetOwnPropertyOp op = obj->getOpsGetOwnPropertyDescriptor()) {
    2758         335 :         bool ok = op(cx, obj, id, desc);
    2759         335 :         if (ok)
    2760         335 :             desc.assertCompleteIfFound();
    2761         335 :         return ok;
    2762             :     }
    2763             : 
    2764        9863 :     return NativeGetOwnPropertyDescriptor(cx, obj.as<NativeObject>(), id, desc);
    2765             : }
    2766             : 
    2767             : bool
    2768        2578 : js::DefineProperty(JSContext* cx, HandleObject obj, HandleId id, Handle<PropertyDescriptor> desc)
    2769             : {
    2770        2578 :     ObjectOpResult result;
    2771        5156 :     return DefineProperty(cx, obj, id, desc, result) &&
    2772        5156 :            result.checkStrict(cx, obj, id);
    2773             : }
    2774             : 
    2775             : bool
    2776        4659 : js::DefineProperty(JSContext* cx, HandleObject obj, HandleId id, Handle<PropertyDescriptor> desc,
    2777             :                    ObjectOpResult& result)
    2778             : {
    2779        4659 :     desc.assertValid();
    2780        4659 :     if (DefinePropertyOp op = obj->getOpsDefineProperty())
    2781        1985 :         return op(cx, obj, id, desc, result);
    2782        2674 :     return NativeDefineProperty(cx, obj.as<NativeObject>(), id, desc, result);
    2783             : }
    2784             : 
    2785             : bool
    2786       88068 : js::DefineProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue value,
    2787             :                    JSGetterOp getter, JSSetterOp setter, unsigned attrs,
    2788             :                    ObjectOpResult& result)
    2789             : {
    2790       88068 :     MOZ_ASSERT(!(attrs & JSPROP_PROPOP_ACCESSORS));
    2791             : 
    2792      176137 :     Rooted<PropertyDescriptor> desc(cx);
    2793       88068 :     desc.initFields(nullptr, value, attrs, getter, setter);
    2794       88068 :     if (DefinePropertyOp op = obj->getOpsDefineProperty()) {
    2795          96 :         MOZ_ASSERT(!cx->helperThread());
    2796          96 :         return op(cx, obj, id, desc, result);
    2797             :     }
    2798       87972 :     return NativeDefineProperty(cx, obj.as<NativeObject>(), id, desc, result);
    2799             : }
    2800             : 
    2801             : bool
    2802           0 : js::DefineProperty(JSContext* cx, HandleObject obj, PropertyName* name, HandleValue value,
    2803             :                    JSGetterOp getter, JSSetterOp setter, unsigned attrs,
    2804             :                    ObjectOpResult& result)
    2805             : {
    2806           0 :     RootedId id(cx, NameToId(name));
    2807           0 :     return DefineProperty(cx, obj, id, value, getter, setter, attrs, result);
    2808             : }
    2809             : 
    2810             : bool
    2811           0 : js::DefineElement(JSContext* cx, HandleObject obj, uint32_t index, HandleValue value,
    2812             :                   JSGetterOp getter, JSSetterOp setter, unsigned attrs,
    2813             :                   ObjectOpResult& result)
    2814             : {
    2815           0 :     MOZ_ASSERT(getter != JS_PropertyStub);
    2816           0 :     MOZ_ASSERT(setter != JS_StrictPropertyStub);
    2817             : 
    2818           0 :     RootedId id(cx);
    2819           0 :     if (!IndexToId(cx, index, &id))
    2820           0 :         return false;
    2821           0 :     return DefineProperty(cx, obj, id, value, getter, setter, attrs, result);
    2822             : }
    2823             : 
    2824             : bool
    2825       87533 : js::DefineProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue value,
    2826             :                    JSGetterOp getter, JSSetterOp setter, unsigned attrs)
    2827             : {
    2828       87533 :     ObjectOpResult result;
    2829       87533 :     if (!DefineProperty(cx, obj, id, value, getter, setter, attrs, result))
    2830           0 :         return false;
    2831       87534 :     if (!result) {
    2832           0 :         MOZ_ASSERT(!cx->helperThread());
    2833           0 :         result.reportError(cx, obj, id);
    2834           0 :         return false;
    2835             :     }
    2836       87534 :     return true;
    2837             : }
    2838             : 
    2839             : bool
    2840       11994 : js::DefineProperty(JSContext* cx, HandleObject obj, PropertyName* name, HandleValue value,
    2841             :                    JSGetterOp getter, JSSetterOp setter, unsigned attrs)
    2842             : {
    2843       23988 :     RootedId id(cx, NameToId(name));
    2844       23988 :     return DefineProperty(cx, obj, id, value, getter, setter, attrs);
    2845             : }
    2846             : 
    2847             : bool
    2848        1589 : js::DefineElement(JSContext* cx, HandleObject obj, uint32_t index, HandleValue value,
    2849             :                   JSGetterOp getter, JSSetterOp setter, unsigned attrs)
    2850             : {
    2851        1589 :     MOZ_ASSERT(getter != JS_PropertyStub);
    2852        1589 :     MOZ_ASSERT(setter != JS_StrictPropertyStub);
    2853             : 
    2854        3178 :     RootedId id(cx);
    2855        1589 :     if (!IndexToId(cx, index, &id))
    2856           0 :         return false;
    2857        1589 :     return DefineProperty(cx, obj, id, value, getter, setter, attrs);
    2858             : }
    2859             : 
    2860             : 
    2861             : /*** SpiderMonkey nonstandard internal methods ***************************************************/
    2862             : 
    2863             : bool
    2864         371 : js::SetImmutablePrototype(JSContext* cx, HandleObject obj, bool* succeeded)
    2865             : {
    2866         371 :     if (obj->hasDynamicPrototype()) {
    2867           0 :         MOZ_ASSERT(!cx->helperThread());
    2868           0 :         return Proxy::setImmutablePrototype(cx, obj, succeeded);
    2869             :     }
    2870             : 
    2871         371 :     if (!JSObject::setFlags(cx, obj, BaseShape::IMMUTABLE_PROTOTYPE))
    2872           0 :         return false;
    2873         371 :     *succeeded = true;
    2874         371 :     return true;
    2875             : }
    2876             : 
    2877             : bool
    2878           0 : js::GetPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
    2879             :                           MutableHandle<PropertyDescriptor> desc)
    2880             : {
    2881           0 :     RootedObject pobj(cx);
    2882             : 
    2883           0 :     for (pobj = obj; pobj;) {
    2884           0 :         if (pobj->is<ProxyObject>()) {
    2885           0 :             bool ok = Proxy::getPropertyDescriptor(cx, pobj, id, desc);
    2886           0 :             if (ok)
    2887           0 :                 desc.assertCompleteIfFound();
    2888           0 :             return ok;
    2889             :         }
    2890             : 
    2891           0 :         if (!GetOwnPropertyDescriptor(cx, pobj, id, desc))
    2892           0 :             return false;
    2893             : 
    2894           0 :         if (desc.object())
    2895           0 :             return true;
    2896             : 
    2897           0 :         if (!GetPrototype(cx, pobj, &pobj))
    2898           0 :             return false;
    2899             :     }
    2900             : 
    2901           0 :     MOZ_ASSERT(!desc.object());
    2902           0 :     return true;
    2903             : }
    2904             : 
    2905             : bool
    2906           0 : js::WatchGuts(JSContext* cx, JS::HandleObject origObj, JS::HandleId id, JS::HandleObject callable)
    2907             : {
    2908           0 :     RootedObject obj(cx, ToWindowIfWindowProxy(origObj));
    2909           0 :     if (obj->isNative()) {
    2910             :         // Use sparse indexes for watched objects, as dense elements can be
    2911             :         // written to without checking the watchpoint map.
    2912           0 :         if (!NativeObject::sparsifyDenseElements(cx, obj.as<NativeObject>()))
    2913           0 :             return false;
    2914             : 
    2915           0 :         MarkTypePropertyNonData(cx, obj, id);
    2916             :     }
    2917             : 
    2918           0 :     WatchpointMap* wpmap = cx->compartment()->watchpointMap;
    2919           0 :     if (!wpmap) {
    2920           0 :         wpmap = cx->runtime()->new_<WatchpointMap>();
    2921           0 :         if (!wpmap || !wpmap->init()) {
    2922           0 :             ReportOutOfMemory(cx);
    2923           0 :             js_delete(wpmap);
    2924           0 :             return false;
    2925             :         }
    2926           0 :         cx->compartment()->watchpointMap = wpmap;
    2927             :     }
    2928             : 
    2929           0 :     return wpmap->watch(cx, obj, id, js::WatchHandler, callable);
    2930             : }
    2931             : 
    2932             : bool
    2933           0 : js::UnwatchGuts(JSContext* cx, JS::HandleObject origObj, JS::HandleId id)
    2934             : {
    2935             :     // Looking in the map for an unsupported object will never hit, so we don't
    2936             :     // need to check for nativeness or watchable-ness here.
    2937           0 :     RootedObject obj(cx, ToWindowIfWindowProxy(origObj));
    2938           0 :     if (WatchpointMap* wpmap = cx->compartment()->watchpointMap)
    2939           0 :         wpmap->unwatch(obj, id);
    2940           0 :     return true;
    2941             : }
    2942             : 
    2943             : bool
    2944           0 : js::WatchProperty(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable)
    2945             : {
    2946           0 :     if (WatchOp op = obj->getOpsWatch())
    2947           0 :         return op(cx, obj, id, callable);
    2948             : 
    2949           0 :     if (!obj->isNative() || obj->is<TypedArrayObject>()) {
    2950             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_WATCH,
    2951           0 :                                   obj->getClass()->name);
    2952           0 :         return false;
    2953             :     }
    2954             : 
    2955           0 :     return WatchGuts(cx, obj, id, callable);
    2956             : }
    2957             : 
    2958             : bool
    2959           0 : js::UnwatchProperty(JSContext* cx, HandleObject obj, HandleId id)
    2960             : {
    2961           0 :     if (UnwatchOp op = obj->getOpsUnwatch())
    2962           0 :         return op(cx, obj, id);
    2963             : 
    2964           0 :     return UnwatchGuts(cx, obj, id);
    2965             : }
    2966             : 
    2967             : /* * */
    2968             : 
    2969             : extern bool
    2970             : PropertySpecNameToId(JSContext* cx, const char* name, MutableHandleId id,
    2971             :                      js::PinningBehavior pin = js::DoNotPinAtom);
    2972             : 
    2973             : static bool
    2974       44631 : DefineFunctionFromSpec(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs, unsigned flags,
    2975             :                        DefineAsIntrinsic intrinsic)
    2976             : {
    2977             :     GetterOp gop;
    2978             :     SetterOp sop;
    2979       44631 :     if (flags & JSFUN_STUB_GSOPS) {
    2980             :         // JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
    2981             :         // the defined property's attributes.
    2982       20458 :         flags &= ~JSFUN_STUB_GSOPS;
    2983       20458 :         gop = nullptr;
    2984       20458 :         sop = nullptr;
    2985             :     } else {
    2986       24173 :         gop = obj->getClass()->getGetProperty();
    2987       24173 :         sop = obj->getClass()->getSetProperty();
    2988       24173 :         MOZ_ASSERT(gop != JS_PropertyStub);
    2989       24173 :         MOZ_ASSERT(sop != JS_StrictPropertyStub);
    2990             :     }
    2991             : 
    2992       89263 :     RootedId id(cx);
    2993       44631 :     if (!PropertySpecNameToId(cx, fs->name, &id))
    2994           0 :         return false;
    2995             : 
    2996       44631 :     JSFunction* fun = NewFunctionFromSpec(cx, fs, id);
    2997       44631 :     if (!fun)
    2998           0 :         return false;
    2999             : 
    3000       44631 :     if (intrinsic == AsIntrinsic)
    3001         831 :         fun->setIsIntrinsic();
    3002             : 
    3003       89263 :     RootedValue funVal(cx, ObjectValue(*fun));
    3004       44631 :     return DefineProperty(cx, obj, id, funVal, gop, sop, flags & ~JSFUN_FLAGS_MASK);
    3005             : }
    3006             : 
    3007             : bool
    3008       48867 : js::DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs,
    3009             :                     DefineAsIntrinsic intrinsic)
    3010             : {
    3011       93499 :     for (; fs->name; fs++) {
    3012       44631 :         if (!DefineFunctionFromSpec(cx, obj, fs, fs->flags, intrinsic))
    3013           0 :             return false;
    3014             :     }
    3015        4236 :     return true;
    3016             : }
    3017             : 
    3018             : 
    3019             : /*** ToPrimitive *************************************************************/
    3020             : 
    3021             : /*
    3022             :  * Gets |obj[id]|.  If that value's not callable, returns true and stores an
    3023             :  * object value in *vp.  If it's callable, calls it with no arguments and |obj|
    3024             :  * as |this|, returning the result in *vp.
    3025             :  *
    3026             :  * This is a mini-abstraction for ES6 draft rev 36 (2015 Mar 17),
    3027             :  * 7.1.1, second algorithm (OrdinaryToPrimitive), steps 5.a-c.
    3028             :  */
    3029             : static bool
    3030         106 : MaybeCallMethod(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp)
    3031             : {
    3032         106 :     if (!GetProperty(cx, obj, obj, id, vp))
    3033           0 :         return false;
    3034         106 :     if (!IsCallable(vp)) {
    3035           0 :         vp.setObject(*obj);
    3036           0 :         return true;
    3037             :     }
    3038             : 
    3039         106 :     return js::Call(cx, vp, obj, vp);
    3040             : }
    3041             : 
    3042             : static bool
    3043           0 : ReportCantConvert(JSContext* cx, unsigned errorNumber, HandleObject obj, JSType hint)
    3044             : {
    3045           0 :     const Class* clasp = obj->getClass();
    3046             : 
    3047             :     // Avoid recursive death when decompiling in ReportValueError.
    3048           0 :     RootedString str(cx);
    3049           0 :     if (hint == JSTYPE_STRING) {
    3050           0 :         str = JS_AtomizeAndPinString(cx, clasp->name);
    3051           0 :         if (!str)
    3052           0 :             return false;
    3053             :     } else {
    3054           0 :         str = nullptr;
    3055             :     }
    3056             : 
    3057           0 :     RootedValue val(cx, ObjectValue(*obj));
    3058           0 :     ReportValueError2(cx, errorNumber, JSDVG_SEARCH_STACK, val, str,
    3059             :                       hint == JSTYPE_UNDEFINED
    3060             :                       ? "primitive type"
    3061           0 :                       : hint == JSTYPE_STRING ? "string" : "number");
    3062           0 :     return false;
    3063             : }
    3064             : 
    3065             : bool
    3066          70 : JS::OrdinaryToPrimitive(JSContext* cx, HandleObject obj, JSType hint, MutableHandleValue vp)
    3067             : {
    3068          70 :     MOZ_ASSERT(hint == JSTYPE_NUMBER || hint == JSTYPE_STRING || hint == JSTYPE_UNDEFINED);
    3069             : 
    3070         140 :     Rooted<jsid> id(cx);
    3071             : 
    3072          70 :     const Class* clasp = obj->getClass();
    3073          70 :     if (hint == JSTYPE_STRING) {
    3074           3 :         id = NameToId(cx->names().toString);
    3075             : 
    3076             :         /* Optimize (new String(...)).toString(). */
    3077           3 :         if (clasp == &StringObject::class_) {
    3078           0 :             StringObject* nobj = &obj->as<StringObject>();
    3079           0 :             if (HasNativeMethodPure(nobj, cx->names().toString, str_toString, cx)) {
    3080           0 :                 vp.setString(nobj->unbox());
    3081           0 :                 return true;
    3082             :             }
    3083             :         }
    3084             : 
    3085           3 :         if (!MaybeCallMethod(cx, obj, id, vp))
    3086           0 :             return false;
    3087           3 :         if (vp.isPrimitive())
    3088           3 :             return true;
    3089             : 
    3090           0 :         id = NameToId(cx->names().valueOf);
    3091           0 :         if (!MaybeCallMethod(cx, obj, id, vp))
    3092           0 :             return false;
    3093           0 :         if (vp.isPrimitive())
    3094           0 :             return true;
    3095             :     } else {
    3096          67 :         id = NameToId(cx->names().valueOf);
    3097             : 
    3098             :         /* Optimize new String(...).valueOf(). */
    3099          67 :         if (clasp == &StringObject::class_) {
    3100           0 :             StringObject* nobj = &obj->as<StringObject>();
    3101           0 :             if (HasNativeMethodPure(nobj, cx->names().valueOf, str_toString, cx)) {
    3102           0 :                 vp.setString(nobj->unbox());
    3103           0 :                 return true;
    3104             :             }
    3105             :         }
    3106             : 
    3107             :         /* Optimize new Number(...).valueOf(). */
    3108          67 :         if (clasp == &NumberObject::class_) {
    3109           0 :             NumberObject* nobj = &obj->as<NumberObject>();
    3110           0 :             if (HasNativeMethodPure(nobj, cx->names().valueOf, num_valueOf, cx)) {
    3111           0 :                 vp.setNumber(nobj->unbox());
    3112           0 :                 return true;
    3113             :             }
    3114             :         }
    3115             : 
    3116          67 :         if (!MaybeCallMethod(cx, obj, id, vp))
    3117           0 :             return false;
    3118          67 :         if (vp.isPrimitive())
    3119          31 :             return true;
    3120             : 
    3121          36 :         id = NameToId(cx->names().toString);
    3122          36 :         if (!MaybeCallMethod(cx, obj, id, vp))
    3123           0 :             return false;
    3124          36 :         if (vp.isPrimitive())
    3125          36 :             return true;
    3126             :     }
    3127             : 
    3128           0 :     return ReportCantConvert(cx, JSMSG_CANT_CONVERT_TO, obj, hint);
    3129             : }
    3130             : 
    3131             : bool
    3132         905 : js::ToPrimitiveSlow(JSContext* cx, JSType preferredType, MutableHandleValue vp)
    3133             : {
    3134             :     // Step numbers refer to the first algorithm listed in ES6 draft rev 36
    3135             :     // (2015 Mar 17) 7.1.1 ToPrimitive.
    3136         905 :     MOZ_ASSERT(preferredType == JSTYPE_UNDEFINED ||
    3137             :                preferredType == JSTYPE_STRING ||
    3138             :                preferredType == JSTYPE_NUMBER);
    3139        1810 :     RootedObject obj(cx, &vp.toObject());
    3140             : 
    3141             :     // Steps 4-5.
    3142        1810 :     RootedValue method(cx);
    3143         905 :     if (!GetInterestingSymbolProperty(cx, obj, cx->wellKnownSymbols().toPrimitive, &method))
    3144           0 :         return false;
    3145             : 
    3146             :     // Step 6.
    3147         905 :     if (!method.isUndefined()) {
    3148             :         // Step 6 of GetMethod. js::Call() below would do this check and throw a
    3149             :         // TypeError anyway, but this produces a better error message.
    3150         866 :         if (!IsCallable(method))
    3151           0 :             return ReportCantConvert(cx, JSMSG_TOPRIMITIVE_NOT_CALLABLE, obj, preferredType);
    3152             : 
    3153             :         // Steps 1-3, 6.a-b.
    3154        1732 :         RootedValue arg0(cx, StringValue(preferredType == JSTYPE_STRING
    3155         828 :                                          ? cx->names().string
    3156             :                                          : preferredType == JSTYPE_NUMBER
    3157          45 :                                          ? cx->names().number
    3158        3471 :                                          : cx->names().default_));
    3159             : 
    3160         866 :         if (!js::Call(cx, method, vp, arg0, vp))
    3161           0 :             return false;
    3162             : 
    3163             :         // Steps 6.c-d.
    3164         866 :         if (vp.isObject())
    3165           0 :             return ReportCantConvert(cx, JSMSG_TOPRIMITIVE_RETURNED_OBJECT, obj, preferredType);
    3166         866 :         return true;
    3167             :     }
    3168             : 
    3169          39 :     return OrdinaryToPrimitive(cx, obj, preferredType, vp);
    3170             : }
    3171             : 
    3172             : 
    3173             : /* * */
    3174             : 
    3175             : bool
    3176          62 : js::IsDelegate(JSContext* cx, HandleObject obj, const js::Value& v, bool* result)
    3177             : {
    3178          62 :     if (v.isPrimitive()) {
    3179           0 :         *result = false;
    3180           0 :         return true;
    3181             :     }
    3182          62 :     return IsDelegateOfObject(cx, obj, &v.toObject(), result);
    3183             : }
    3184             : 
    3185             : bool
    3186          62 : js::IsDelegateOfObject(JSContext* cx, HandleObject protoObj, JSObject* obj, bool* result)
    3187             : {
    3188         124 :     RootedObject obj2(cx, obj);
    3189             :     for (;;) {
    3190         232 :         if (!GetPrototype(cx, obj2, &obj2))
    3191           0 :             return false;
    3192         147 :         if (!obj2) {
    3193          28 :             *result = false;
    3194          28 :             return true;
    3195             :         }
    3196         119 :         if (obj2 == protoObj) {
    3197          34 :             *result = true;
    3198          34 :             return true;
    3199             :         }
    3200             :     }
    3201             : }
    3202             : 
    3203             : JSObject*
    3204        6688 : js::GetBuiltinPrototypePure(GlobalObject* global, JSProtoKey protoKey)
    3205             : {
    3206        6688 :     MOZ_ASSERT(JSProto_Null <= protoKey);
    3207        6688 :     MOZ_ASSERT(protoKey < JSProto_LIMIT);
    3208             : 
    3209        6688 :     if (protoKey != JSProto_Null) {
    3210        6688 :         const Value& v = global->getPrototype(protoKey);
    3211        6688 :         if (v.isObject())
    3212        6687 :             return &v.toObject();
    3213             :     }
    3214             : 
    3215           1 :     return nullptr;
    3216             : }
    3217             : 
    3218             : JSObject*
    3219           0 : js::PrimitiveToObject(JSContext* cx, const Value& v)
    3220             : {
    3221           0 :     if (v.isString()) {
    3222           0 :         Rooted<JSString*> str(cx, v.toString());
    3223           0 :         return StringObject::create(cx, str);
    3224             :     }
    3225           0 :     if (v.isNumber())
    3226           0 :         return NumberObject::create(cx, v.toNumber());
    3227           0 :     if (v.isBoolean())
    3228           0 :         return BooleanObject::create(cx, v.toBoolean());
    3229           0 :     MOZ_ASSERT(v.isSymbol());
    3230           0 :     RootedSymbol symbol(cx, v.toSymbol());
    3231           0 :     return SymbolObject::create(cx, symbol);
    3232             : }
    3233             : 
    3234             : /*
    3235             :  * Invokes the ES5 ToObject algorithm on vp, returning the result. If vp might
    3236             :  * already be an object, use ToObject. reportCantConvert controls how null and
    3237             :  * undefined errors are reported.
    3238             :  *
    3239             :  * Callers must handle the already-object case.
    3240             :  */
    3241             : JSObject*
    3242           2 : js::ToObjectSlow(JSContext* cx, JS::HandleValue val, bool reportScanStack)
    3243             : {
    3244           2 :     MOZ_ASSERT(!val.isMagic());
    3245           2 :     MOZ_ASSERT(!val.isObject());
    3246             : 
    3247           2 :     if (val.isNullOrUndefined()) {
    3248           2 :         if (reportScanStack) {
    3249           2 :             ReportIsNullOrUndefined(cx, JSDVG_SEARCH_STACK, val, nullptr);
    3250             :         } else {
    3251           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO,
    3252           0 :                                       val.isNull() ? "null" : "undefined", "object");
    3253             :         }
    3254           2 :         return nullptr;
    3255             :     }
    3256             : 
    3257           0 :     return PrimitiveToObject(cx, val);
    3258             : }
    3259             : 
    3260             : Value
    3261       31548 : js::GetThisValue(JSObject* obj)
    3262             : {
    3263       31548 :     if (obj->is<GlobalObject>())
    3264        1154 :         return ObjectValue(*ToWindowProxyIfWindow(obj));
    3265             : 
    3266       30394 :     if (obj->is<LexicalEnvironmentObject>()) {
    3267          48 :         if (!obj->as<LexicalEnvironmentObject>().isExtensible())
    3268           0 :             return UndefinedValue();
    3269          48 :         return obj->as<LexicalEnvironmentObject>().thisValue();
    3270             :     }
    3271             : 
    3272       30346 :     if (obj->is<ModuleEnvironmentObject>())
    3273           0 :         return UndefinedValue();
    3274             : 
    3275       30346 :     if (obj->is<WithEnvironmentObject>())
    3276         490 :         return ObjectValue(*obj->as<WithEnvironmentObject>().withThis());
    3277             : 
    3278       29856 :     if (obj->is<NonSyntacticVariablesObject>())
    3279          48 :         return GetThisValue(obj->enclosingEnvironment());
    3280             : 
    3281       29808 :     return ObjectValue(*obj);
    3282             : }
    3283             : 
    3284             : class GetObjectSlotNameFunctor : public JS::CallbackTracer::ContextFunctor
    3285             : {
    3286             :     JSObject* obj;
    3287             : 
    3288             :   public:
    3289          25 :     explicit GetObjectSlotNameFunctor(JSObject* ctx) : obj(ctx) {}
    3290             :     virtual void operator()(JS::CallbackTracer* trc, char* buf, size_t bufsize) override;
    3291             : };
    3292             : 
    3293             : void
    3294           0 : GetObjectSlotNameFunctor::operator()(JS::CallbackTracer* trc, char* buf, size_t bufsize)
    3295             : {
    3296           0 :     MOZ_ASSERT(trc->contextIndex() != JS::CallbackTracer::InvalidIndex);
    3297             : 
    3298           0 :     uint32_t slot = uint32_t(trc->contextIndex());
    3299             : 
    3300             :     Shape* shape;
    3301           0 :     if (obj->isNative()) {
    3302           0 :         shape = obj->as<NativeObject>().lastProperty();
    3303           0 :         while (shape && (!shape->hasSlot() || shape->slot() != slot))
    3304           0 :             shape = shape->previous();
    3305             :     } else {
    3306           0 :         shape = nullptr;
    3307             :     }
    3308             : 
    3309           0 :     if (!shape) {
    3310             :         do {
    3311           0 :             const char* slotname = nullptr;
    3312           0 :             const char* pattern = nullptr;
    3313           0 :             if (obj->is<GlobalObject>()) {
    3314           0 :                 pattern = "CLASS_OBJECT(%s)";
    3315             :                 if (false)
    3316             :                     ;
    3317             : #define TEST_SLOT_MATCHES_PROTOTYPE(name,code,init,clasp) \
    3318             :                 else if ((code) == slot) { slotname = js_##name##_str; }
    3319           0 :                 JS_FOR_EACH_PROTOTYPE(TEST_SLOT_MATCHES_PROTOTYPE)
    3320             : #undef TEST_SLOT_MATCHES_PROTOTYPE
    3321             :             } else {
    3322           0 :                 pattern = "%s";
    3323           0 :                 if (obj->is<EnvironmentObject>()) {
    3324           0 :                     if (slot == EnvironmentObject::enclosingEnvironmentSlot()) {
    3325           0 :                         slotname = "enclosing_environment";
    3326           0 :                     } else if (obj->is<CallObject>()) {
    3327           0 :                         if (slot == CallObject::calleeSlot())
    3328           0 :                             slotname = "callee_slot";
    3329           0 :                     } else if (obj->is<WithEnvironmentObject>()) {
    3330           0 :                         if (slot == WithEnvironmentObject::objectSlot())
    3331           0 :                             slotname = "with_object";
    3332           0 :                         else if (slot == WithEnvironmentObject::thisSlot())
    3333           0 :                             slotname = "with_this";
    3334             :                     }
    3335             :                 }
    3336             :             }
    3337             : 
    3338           0 :             if (slotname)
    3339           0 :                 snprintf(buf, bufsize, pattern, slotname);
    3340             :             else
    3341           0 :                 snprintf(buf, bufsize, "**UNKNOWN SLOT %" PRIu32 "**", slot);
    3342             :         } while (false);
    3343             :     } else {
    3344           0 :         jsid propid = shape->propid();
    3345           0 :         if (JSID_IS_INT(propid)) {
    3346           0 :             snprintf(buf, bufsize, "%" PRId32, JSID_TO_INT(propid));
    3347           0 :         } else if (JSID_IS_ATOM(propid)) {
    3348           0 :             PutEscapedString(buf, bufsize, JSID_TO_ATOM(propid), 0);
    3349           0 :         } else if (JSID_IS_SYMBOL(propid)) {
    3350           0 :             snprintf(buf, bufsize, "**SYMBOL KEY**");
    3351             :         } else {
    3352           0 :             snprintf(buf, bufsize, "**FINALIZED ATOM KEY**");
    3353             :         }
    3354             :     }
    3355           0 : }
    3356             : 
    3357             : /*** Debugging routines **************************************************************************/
    3358             : 
    3359             : #ifdef DEBUG
    3360             : 
    3361             : /*
    3362             :  * Routines to print out values during debugging.  These are FRIEND_API to help
    3363             :  * the debugger find them and to support temporarily hacking js::Dump* calls
    3364             :  * into other code.
    3365             :  */
    3366             : 
    3367             : static void
    3368           0 : dumpValue(const Value& v, FILE* fp)
    3369             : {
    3370           0 :     if (v.isNull())
    3371           0 :         fprintf(fp, "null");
    3372           0 :     else if (v.isUndefined())
    3373           0 :         fprintf(fp, "undefined");
    3374           0 :     else if (v.isInt32())
    3375           0 :         fprintf(fp, "%d", v.toInt32());
    3376           0 :     else if (v.isDouble())
    3377           0 :         fprintf(fp, "%g", v.toDouble());
    3378           0 :     else if (v.isString())
    3379           0 :         v.toString()->dump(fp);
    3380           0 :     else if (v.isSymbol())
    3381           0 :         v.toSymbol()->dump(fp);
    3382           0 :     else if (v.isObject() && v.toObject().is<JSFunction>()) {
    3383           0 :         JSFunction* fun = &v.toObject().as<JSFunction>();
    3384           0 :         if (fun->displayAtom()) {
    3385           0 :             fputs("<function ", fp);
    3386           0 :             FileEscapedString(fp, fun->displayAtom(), 0);
    3387             :         } else {
    3388           0 :             fputs("<unnamed function", fp);
    3389             :         }
    3390           0 :         if (fun->hasScript()) {
    3391           0 :             JSScript* script = fun->nonLazyScript();
    3392           0 :             fprintf(fp, " (%s:%" PRIuSIZE ")",
    3393           0 :                     script->filename() ? script->filename() : "", script->lineno());
    3394             :         }
    3395           0 :         fprintf(fp, " at %p>", (void*) fun);
    3396           0 :     } else if (v.isObject()) {
    3397           0 :         JSObject* obj = &v.toObject();
    3398           0 :         const Class* clasp = obj->getClass();
    3399           0 :         fprintf(fp, "<%s%s at %p>",
    3400           0 :                 clasp->name,
    3401             :                 (clasp == &PlainObject::class_) ? "" : " object",
    3402           0 :                 (void*) obj);
    3403           0 :     } else if (v.isBoolean()) {
    3404           0 :         if (v.toBoolean())
    3405           0 :             fprintf(fp, "true");
    3406             :         else
    3407           0 :             fprintf(fp, "false");
    3408           0 :     } else if (v.isMagic()) {
    3409           0 :         fprintf(fp, "<invalid");
    3410             : #ifdef DEBUG
    3411           0 :         switch (v.whyMagic()) {
    3412           0 :           case JS_ELEMENTS_HOLE:     fprintf(fp, " elements hole");      break;
    3413           0 :           case JS_NO_ITER_VALUE:     fprintf(fp, " no iter value");      break;
    3414           0 :           case JS_GENERATOR_CLOSING: fprintf(fp, " generator closing");  break;
    3415           0 :           case JS_OPTIMIZED_OUT:     fprintf(fp, " optimized out");      break;
    3416           0 :           default:                   fprintf(fp, " ?!");                 break;
    3417             :         }
    3418             : #endif
    3419           0 :         fprintf(fp, ">");
    3420             :     } else {
    3421           0 :         fprintf(fp, "unexpected value");
    3422             :     }
    3423           0 : }
    3424             : 
    3425             : JS_FRIEND_API(void)
    3426           0 : js::DumpValue(const Value& val, FILE* fp)
    3427             : {
    3428           0 :     dumpValue(val, fp);
    3429           0 :     fputc('\n', fp);
    3430           0 : }
    3431             : 
    3432             : JS_FRIEND_API(void)
    3433           0 : js::DumpId(jsid id, FILE* fp)
    3434             : {
    3435           0 :     fprintf(fp, "jsid %p = ", (void*) JSID_BITS(id));
    3436           0 :     dumpValue(IdToValue(id), fp);
    3437           0 :     fputc('\n', fp);
    3438           0 : }
    3439             : 
    3440             : static void
    3441           0 : DumpProperty(const NativeObject* obj, Shape& shape, FILE* fp)
    3442             : {
    3443           0 :     jsid id = shape.propid();
    3444           0 :     uint8_t attrs = shape.attributes();
    3445             : 
    3446           0 :     fprintf(fp, "    ((js::Shape*) %p) ", (void*) &shape);
    3447           0 :     if (attrs & JSPROP_ENUMERATE) fprintf(fp, "enumerate ");
    3448           0 :     if (attrs & JSPROP_READONLY) fprintf(fp, "readonly ");
    3449           0 :     if (attrs & JSPROP_PERMANENT) fprintf(fp, "permanent ");
    3450           0 :     if (attrs & JSPROP_SHARED) fprintf(fp, "shared ");
    3451             : 
    3452           0 :     if (shape.hasGetterValue())
    3453           0 :         fprintf(fp, "getterValue=%p ", (void*) shape.getterObject());
    3454           0 :     else if (!shape.hasDefaultGetter())
    3455           0 :         fprintf(fp, "getterOp=%p ", JS_FUNC_TO_DATA_PTR(void*, shape.getterOp()));
    3456             : 
    3457           0 :     if (shape.hasSetterValue())
    3458           0 :         fprintf(fp, "setterValue=%p ", (void*) shape.setterObject());
    3459           0 :     else if (!shape.hasDefaultSetter())
    3460           0 :         fprintf(fp, "setterOp=%p ", JS_FUNC_TO_DATA_PTR(void*, shape.setterOp()));
    3461             : 
    3462           0 :     if (JSID_IS_ATOM(id) || JSID_IS_INT(id) || JSID_IS_SYMBOL(id))
    3463           0 :         dumpValue(js::IdToValue(id), fp);
    3464             :     else
    3465           0 :         fprintf(fp, "unknown jsid %p", (void*) JSID_BITS(id));
    3466             : 
    3467           0 :     uint32_t slot = shape.hasSlot() ? shape.maybeSlot() : SHAPE_INVALID_SLOT;
    3468           0 :     fprintf(fp, ": slot %d", slot);
    3469           0 :     if (shape.hasSlot()) {
    3470           0 :         fprintf(fp, " = ");
    3471           0 :         dumpValue(obj->getSlot(slot), fp);
    3472           0 :     } else if (slot != SHAPE_INVALID_SLOT) {
    3473           0 :         fprintf(fp, " (INVALID!)");
    3474             :     }
    3475           0 :     fprintf(fp, "\n");
    3476           0 : }
    3477             : 
    3478             : bool
    3479      280704 : JSObject::uninlinedIsProxy() const
    3480             : {
    3481      280704 :     return is<ProxyObject>();
    3482             : }
    3483             : 
    3484             : bool
    3485      117334 : JSObject::uninlinedNonProxyIsExtensible() const
    3486             : {
    3487      117334 :     return nonProxyIsExtensible();
    3488             : }
    3489             : 
    3490             : void
    3491           0 : JSObject::dump(FILE* fp) const
    3492             : {
    3493           0 :     const JSObject* obj = this;
    3494           0 :     JSObject* globalObj = &global();
    3495             :     fprintf(fp, "object %p from global %p [%s]\n", (void*) obj,
    3496           0 :             (void*) globalObj, globalObj->getClass()->name);
    3497           0 :     const Class* clasp = obj->getClass();
    3498           0 :     fprintf(fp, "class %p %s\n", (const void*)clasp, clasp->name);
    3499             : 
    3500           0 :     if (obj->hasLazyGroup()) {
    3501           0 :         fprintf(fp, "lazy group\n");
    3502             :     } else {
    3503           0 :         const ObjectGroup* group = obj->group();
    3504           0 :         fprintf(fp, "group %p\n", (const void*)group);
    3505             :     }
    3506             : 
    3507           0 :     fprintf(fp, "flags:");
    3508           0 :     if (obj->isDelegate()) fprintf(fp, " delegate");
    3509           0 :     if (!obj->is<ProxyObject>() && !obj->nonProxyIsExtensible()) fprintf(fp, " not_extensible");
    3510           0 :     if (obj->isIndexed()) fprintf(fp, " indexed");
    3511           0 :     if (obj->maybeHasInterestingSymbolProperty()) fprintf(fp, " maybe_has_interesting_symbol");
    3512           0 :     if (obj->isBoundFunction()) fprintf(fp, " bound_function");
    3513           0 :     if (obj->isQualifiedVarObj()) fprintf(fp, " varobj");
    3514           0 :     if (obj->isUnqualifiedVarObj()) fprintf(fp, " unqualified_varobj");
    3515           0 :     if (obj->watched()) fprintf(fp, " watched");
    3516           0 :     if (obj->isIteratedSingleton()) fprintf(fp, " iterated_singleton");
    3517           0 :     if (obj->isNewGroupUnknown()) fprintf(fp, " new_type_unknown");
    3518           0 :     if (obj->hasUncacheableProto()) fprintf(fp, " has_uncacheable_proto");
    3519           0 :     if (obj->hadElementsAccess()) fprintf(fp, " had_elements_access");
    3520           0 :     if (obj->wasNewScriptCleared()) fprintf(fp, " new_script_cleared");
    3521           0 :     if (obj->hasStaticPrototype() && obj->staticPrototypeIsImmutable())
    3522           0 :         fprintf(fp, " immutable_prototype");
    3523             : 
    3524           0 :     if (obj->isNative()) {
    3525           0 :         const NativeObject* nobj = &obj->as<NativeObject>();
    3526           0 :         if (nobj->inDictionaryMode())
    3527           0 :             fprintf(fp, " inDictionaryMode");
    3528           0 :         if (nobj->hasShapeTable())
    3529           0 :             fprintf(fp, " hasShapeTable");
    3530             :     }
    3531           0 :     fprintf(fp, "\n");
    3532             : 
    3533           0 :     if (obj->isNative()) {
    3534           0 :         const NativeObject* nobj = &obj->as<NativeObject>();
    3535           0 :         uint32_t slots = nobj->getDenseInitializedLength();
    3536           0 :         if (slots) {
    3537           0 :             fprintf(fp, "elements\n");
    3538           0 :             for (uint32_t i = 0; i < slots; i++) {
    3539           0 :                 fprintf(fp, " %3d: ", i);
    3540           0 :                 dumpValue(nobj->getDenseElement(i), fp);
    3541           0 :                 fprintf(fp, "\n");
    3542           0 :                 fflush(fp);
    3543             :             }
    3544             :         }
    3545             :     }
    3546             : 
    3547           0 :     fprintf(fp, "proto ");
    3548           0 :     TaggedProto proto = obj->taggedProto();
    3549           0 :     if (proto.isDynamic())
    3550           0 :         fprintf(fp, "<dynamic>");
    3551             :     else
    3552           0 :         dumpValue(ObjectOrNullValue(proto.toObjectOrNull()), fp);
    3553           0 :     fputc('\n', fp);
    3554             : 
    3555           0 :     if (clasp->flags & JSCLASS_HAS_PRIVATE)
    3556           0 :         fprintf(fp, "private %p\n", obj->as<NativeObject>().getPrivate());
    3557             : 
    3558           0 :     if (!obj->isNative())
    3559           0 :         fprintf(fp, "not native\n");
    3560             : 
    3561           0 :     uint32_t reservedEnd = JSCLASS_RESERVED_SLOTS(clasp);
    3562           0 :     uint32_t slots = obj->isNative() ? obj->as<NativeObject>().slotSpan() : 0;
    3563           0 :     uint32_t stop = obj->isNative() ? reservedEnd : slots;
    3564           0 :     if (stop > 0)
    3565           0 :         fprintf(fp, obj->isNative() ? "reserved slots:\n" : "slots:\n");
    3566           0 :     for (uint32_t i = 0; i < stop; i++) {
    3567           0 :         fprintf(fp, " %3d ", i);
    3568           0 :         if (i < reservedEnd)
    3569           0 :             fprintf(fp, "(reserved) ");
    3570           0 :         fprintf(fp, "= ");
    3571           0 :         dumpValue(obj->as<NativeObject>().getSlot(i), fp);
    3572           0 :         fputc('\n', fp);
    3573             :     }
    3574             : 
    3575           0 :     if (obj->isNative()) {
    3576           0 :         fprintf(fp, "properties:\n");
    3577           0 :         Vector<Shape*, 8, SystemAllocPolicy> props;
    3578           0 :         for (Shape::Range<NoGC> r(obj->as<NativeObject>().lastProperty()); !r.empty(); r.popFront()) {
    3579           0 :             if (!props.append(&r.front())) {
    3580           0 :                 fprintf(fp, "(OOM while appending properties)\n");
    3581           0 :                 break;
    3582             :             }
    3583             :         }
    3584           0 :         for (size_t i = props.length(); i-- != 0;)
    3585           0 :             DumpProperty(&obj->as<NativeObject>(), *props[i], fp);
    3586             :     }
    3587           0 :     fputc('\n', fp);
    3588           0 : }
    3589             : 
    3590             : // For debuggers.
    3591             : void
    3592           0 : JSObject::dump() const
    3593             : {
    3594           0 :     dump(stderr);
    3595           0 : }
    3596             : 
    3597             : static void
    3598           0 : MaybeDumpScope(Scope* scope, FILE* fp)
    3599             : {
    3600           0 :     if (scope) {
    3601           0 :         fprintf(fp, "  scope: %s\n", ScopeKindString(scope->kind()));
    3602           0 :         for (BindingIter bi(scope); bi; bi++) {
    3603           0 :             fprintf(fp, "    ");
    3604           0 :             dumpValue(StringValue(bi.name()), fp);
    3605           0 :             fputc('\n', fp);
    3606             :         }
    3607             :     }
    3608           0 : }
    3609             : 
    3610             : static void
    3611           0 : MaybeDumpValue(const char* name, const Value& v, FILE* fp)
    3612             : {
    3613           0 :     if (!v.isNull()) {
    3614           0 :         fprintf(fp, "  %s: ", name);
    3615           0 :         dumpValue(v, fp);
    3616           0 :         fputc('\n', fp);
    3617             :     }
    3618           0 : }
    3619             : 
    3620             : JS_FRIEND_API(void)
    3621           0 : js::DumpInterpreterFrame(JSContext* cx, FILE* fp, InterpreterFrame* start)
    3622             : {
    3623             :     /* This should only called during live debugging. */
    3624           0 :     ScriptFrameIter i(cx);
    3625           0 :     if (!start) {
    3626           0 :         if (i.done()) {
    3627           0 :             fprintf(fp, "no stack for cx = %p\n", (void*) cx);
    3628           0 :             return;
    3629             :         }
    3630             :     } else {
    3631           0 :         while (!i.done() && !i.isJit() && i.interpFrame() != start)
    3632           0 :             ++i;
    3633             : 
    3634           0 :         if (i.done()) {
    3635           0 :             fprintf(fp, "fp = %p not found in cx = %p\n",
    3636           0 :                     (void*)start, (void*)cx);
    3637           0 :             return;
    3638             :         }
    3639             :     }
    3640             : 
    3641           0 :     for (; !i.done(); ++i) {
    3642           0 :         if (i.isJit())
    3643           0 :             fprintf(fp, "JIT frame\n");
    3644             :         else
    3645           0 :             fprintf(fp, "InterpreterFrame at %p\n", (void*) i.interpFrame());
    3646             : 
    3647           0 :         if (i.isFunctionFrame()) {
    3648           0 :             fprintf(fp, "callee fun: ");
    3649           0 :             RootedValue v(cx);
    3650           0 :             JSObject* fun = i.callee(cx);
    3651           0 :             v.setObject(*fun);
    3652           0 :             dumpValue(v, fp);
    3653             :         } else {
    3654           0 :             fprintf(fp, "global or eval frame, no callee");
    3655             :         }
    3656           0 :         fputc('\n', fp);
    3657             : 
    3658           0 :         fprintf(fp, "file %s line %" PRIuSIZE "\n",
    3659           0 :                 i.script()->filename(), i.script()->lineno());
    3660             : 
    3661           0 :         if (jsbytecode* pc = i.pc()) {
    3662           0 :             fprintf(fp, "  pc = %p\n", pc);
    3663           0 :             fprintf(fp, "  current op: %s\n", CodeName[*pc]);
    3664           0 :             MaybeDumpScope(i.script()->lookupScope(pc), fp);
    3665             :         }
    3666           0 :         if (i.isFunctionFrame())
    3667           0 :             MaybeDumpValue("this", i.thisArgument(cx), fp);
    3668           0 :         if (!i.isJit()) {
    3669           0 :             fprintf(fp, "  rval: ");
    3670           0 :             dumpValue(i.interpFrame()->returnValue(), fp);
    3671           0 :             fputc('\n', fp);
    3672             :         }
    3673             : 
    3674           0 :         fprintf(fp, "  flags:");
    3675           0 :         if (i.isConstructing())
    3676           0 :             fprintf(fp, " constructing");
    3677           0 :         if (!i.isJit() && i.interpFrame()->isDebuggerEvalFrame())
    3678           0 :             fprintf(fp, " debugger eval");
    3679           0 :         if (i.isEvalFrame())
    3680           0 :             fprintf(fp, " eval");
    3681           0 :         fputc('\n', fp);
    3682             : 
    3683           0 :         fprintf(fp, "  envChain: (JSObject*) %p\n", (void*) i.environmentChain(cx));
    3684             : 
    3685           0 :         fputc('\n', fp);
    3686             :     }
    3687             : }
    3688             : 
    3689             : #endif /* DEBUG */
    3690             : 
    3691             : JS_FRIEND_API(void)
    3692           0 : js::DumpBacktrace(JSContext* cx, FILE* fp)
    3693             : {
    3694           0 :     Sprinter sprinter(cx, false);
    3695           0 :     if (!sprinter.init()) {
    3696           0 :         fprintf(fp, "js::DumpBacktrace: OOM\n");
    3697           0 :         return;
    3698             :     }
    3699           0 :     size_t depth = 0;
    3700           0 :     for (AllFramesIter i(cx); !i.done(); ++i, ++depth) {
    3701             :         const char* filename;
    3702             :         unsigned line;
    3703           0 :         if (i.hasScript()) {
    3704           0 :             filename = JS_GetScriptFilename(i.script());
    3705           0 :             line = PCToLineNumber(i.script(), i.pc());
    3706             :         } else {
    3707           0 :             filename = i.filename();
    3708           0 :             line = i.computeLine();
    3709             :         }
    3710             :         char frameType =
    3711           0 :             i.isInterp() ? 'i' :
    3712           0 :             i.isBaseline() ? 'b' :
    3713           0 :             i.isIon() ? 'I' :
    3714           0 :             i.isWasm() ? 'W' :
    3715           0 :             '?';
    3716             : 
    3717           0 :         sprinter.printf("#%" PRIuSIZE " %14p %c   %s:%d",
    3718           0 :                         depth, i.rawFramePtr(), frameType, filename, line);
    3719             : 
    3720           0 :         if (i.hasScript()) {
    3721           0 :             sprinter.printf(" (%p @ %" PRIuSIZE ")\n",
    3722           0 :                             i.script(), i.script()->pcToOffset(i.pc()));
    3723             :         } else {
    3724           0 :             sprinter.printf(" (%p)\n", i.pc());
    3725             :         }
    3726             :     }
    3727           0 :     fprintf(fp, "%s", sprinter.string());
    3728             : #ifdef XP_WIN32
    3729             :     if (IsDebuggerPresent())
    3730             :         OutputDebugStringA(sprinter.string());
    3731             : #endif
    3732             : }
    3733             : 
    3734             : JS_FRIEND_API(void)
    3735           0 : js::DumpBacktrace(JSContext* cx)
    3736             : {
    3737           0 :     DumpBacktrace(cx, stdout);
    3738           0 : }
    3739             : 
    3740             : /* * */
    3741             : 
    3742             : js::gc::AllocKind
    3743       27650 : JSObject::allocKindForTenure(const js::Nursery& nursery) const
    3744             : {
    3745       27650 :     if (is<ArrayObject>()) {
    3746        1964 :         const ArrayObject& aobj = as<ArrayObject>();
    3747        1964 :         MOZ_ASSERT(aobj.numFixedSlots() == 0);
    3748             : 
    3749             :         /* Use minimal size object if we are just going to copy the pointer. */
    3750        1964 :         if (!nursery.isInside(aobj.getElementsHeader()))
    3751         512 :             return AllocKind::OBJECT0_BACKGROUND;
    3752             : 
    3753        1452 :         size_t nelements = aobj.getDenseCapacity();
    3754        1452 :         return GetBackgroundAllocKind(GetGCArrayKind(nelements));
    3755             :     }
    3756             : 
    3757       25686 :     if (is<JSFunction>())
    3758       15531 :         return as<JSFunction>().getAllocKind();
    3759             : 
    3760             :     /*
    3761             :      * Typed arrays in the nursery may have a lazily allocated buffer, make
    3762             :      * sure there is room for the array's fixed data when moving the array.
    3763             :      */
    3764       10155 :     if (is<TypedArrayObject>() && !as<TypedArrayObject>().hasBuffer()) {
    3765           0 :         size_t nbytes = as<TypedArrayObject>().byteLength();
    3766           0 :         if (as<TypedArrayObject>().hasInlineElements())
    3767           0 :             return GetBackgroundAllocKind(TypedArrayObject::AllocKindForLazyBuffer(nbytes));
    3768           0 :         return GetGCObjectKind(getClass());
    3769             :     }
    3770             : 
    3771             :     // Proxies that are CrossCompartmentWrappers may be nursery allocated.
    3772       10155 :     if (IsProxy(this))
    3773        2105 :         return as<ProxyObject>().allocKindForTenure();
    3774             : 
    3775             :     // Unboxed plain objects are sized according to the data they store.
    3776        8050 :     if (is<UnboxedPlainObject>()) {
    3777          51 :         size_t nbytes = as<UnboxedPlainObject>().layoutDontCheckGeneration().size();
    3778          51 :         return GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + nbytes);
    3779             :     }
    3780             : 
    3781             :     // Unboxed arrays use inline data if their size is small enough.
    3782        7999 :     if (is<UnboxedArrayObject>()) {
    3783           0 :         const UnboxedArrayObject* nobj = &as<UnboxedArrayObject>();
    3784           0 :         size_t nbytes = UnboxedArrayObject::offsetOfInlineElements() +
    3785           0 :                         nobj->capacity() * nobj->elementSize();
    3786           0 :         if (nbytes <= JSObject::MAX_BYTE_SIZE)
    3787           0 :             return GetGCObjectKindForBytes(nbytes);
    3788           0 :         return AllocKind::OBJECT0;
    3789             :     }
    3790             : 
    3791             :     // Inlined typed objects are followed by their data, so make sure we copy
    3792             :     // it all over to the new object.
    3793        7999 :     if (is<InlineTypedObject>()) {
    3794             :         // Figure out the size of this object, from the prototype's TypeDescr.
    3795             :         // The objects we are traversing here are all tenured, so we don't need
    3796             :         // to check forwarding pointers.
    3797           0 :         TypeDescr& descr = as<InlineTypedObject>().typeDescr();
    3798           0 :         MOZ_ASSERT(!IsInsideNursery(&descr));
    3799           0 :         return InlineTypedObject::allocKindForTypeDescriptor(&descr);
    3800             :     }
    3801             : 
    3802             :     // Outline typed objects use the minimum allocation kind.
    3803        7999 :     if (is<OutlineTypedObject>())
    3804           0 :         return AllocKind::OBJECT0;
    3805             : 
    3806             :     // All nursery allocatable non-native objects are handled above.
    3807        7999 :     MOZ_ASSERT(isNative());
    3808             : 
    3809        7999 :     AllocKind kind = GetGCObjectFixedSlotsKind(as<NativeObject>().numFixedSlots());
    3810        7999 :     MOZ_ASSERT(!IsBackgroundFinalized(kind));
    3811        7999 :     if (!CanBeFinalizedInBackground(kind, getClass()))
    3812          66 :         return kind;
    3813        7933 :     return GetBackgroundAllocKind(kind);
    3814             : }
    3815             : 
    3816             : void
    3817           0 : JSObject::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::ClassInfo* info)
    3818             : {
    3819           0 :     if (is<NativeObject>() && as<NativeObject>().hasDynamicSlots())
    3820           0 :         info->objectsMallocHeapSlots += mallocSizeOf(as<NativeObject>().slots_);
    3821             : 
    3822           0 :     if (is<NativeObject>() && as<NativeObject>().hasDynamicElements()) {
    3823           0 :         js::ObjectElements* elements = as<NativeObject>().getElementsHeader();
    3824           0 :         if (!elements->isCopyOnWrite() || elements->ownerObject() == this) {
    3825           0 :             void* allocatedElements = as<NativeObject>().getUnshiftedElementsHeader();
    3826           0 :             info->objectsMallocHeapElementsNormal += mallocSizeOf(allocatedElements);
    3827             :         }
    3828             :     }
    3829             : 
    3830             :     // Other things may be measured in the future if DMD indicates it is worthwhile.
    3831           0 :     if (is<JSFunction>() ||
    3832           0 :         is<PlainObject>() ||
    3833           0 :         is<ArrayObject>() ||
    3834           0 :         is<CallObject>() ||
    3835           0 :         is<RegExpObject>() ||
    3836           0 :         is<ProxyObject>())
    3837             :     {
    3838             :         // Do nothing.  But this function is hot, and we win by getting the
    3839             :         // common cases out of the way early.  Some stats on the most common
    3840             :         // classes, as measured during a vanilla browser session:
    3841             :         // - (53.7%, 53.7%): Function
    3842             :         // - (18.0%, 71.7%): Object
    3843             :         // - (16.9%, 88.6%): Array
    3844             :         // - ( 3.9%, 92.5%): Call
    3845             :         // - ( 2.8%, 95.3%): RegExp
    3846             :         // - ( 1.0%, 96.4%): Proxy
    3847             : 
    3848             :         // Note that any JSClass that is special cased below likely needs to
    3849             :         // specify the JSCLASS_DELAY_METADATA_CALLBACK flag, or else we will
    3850             :         // probably crash if the object metadata callback attempts to get the
    3851             :         // size of the new object (which Debugger code does) before private
    3852             :         // slots are initialized.
    3853           0 :     } else if (is<ArgumentsObject>()) {
    3854           0 :         info->objectsMallocHeapMisc += as<ArgumentsObject>().sizeOfMisc(mallocSizeOf);
    3855           0 :     } else if (is<RegExpStaticsObject>()) {
    3856           0 :         info->objectsMallocHeapMisc += as<RegExpStaticsObject>().sizeOfData(mallocSizeOf);
    3857           0 :     } else if (is<PropertyIteratorObject>()) {
    3858           0 :         info->objectsMallocHeapMisc += as<PropertyIteratorObject>().sizeOfMisc(mallocSizeOf);
    3859           0 :     } else if (is<ArrayBufferObject>()) {
    3860           0 :         ArrayBufferObject::addSizeOfExcludingThis(this, mallocSizeOf, info);
    3861           0 :     } else if (is<SharedArrayBufferObject>()) {
    3862           0 :         SharedArrayBufferObject::addSizeOfExcludingThis(this, mallocSizeOf, info);
    3863             : #ifdef JS_HAS_CTYPES
    3864             :     } else {
    3865             :         // This must be the last case.
    3866           0 :         info->objectsMallocHeapMisc +=
    3867           0 :             js::SizeOfDataIfCDataObject(mallocSizeOf, const_cast<JSObject*>(this));
    3868             : #endif
    3869             :     }
    3870           0 : }
    3871             : 
    3872             : size_t
    3873           0 : JSObject::sizeOfIncludingThisInNursery() const
    3874             : {
    3875             :     // This function doesn't concern itself yet with typed objects (bug 1133593)
    3876             :     // nor unboxed objects (bug 1133592).
    3877             : 
    3878           0 :     MOZ_ASSERT(!isTenured());
    3879             : 
    3880           0 :     const Nursery& nursery = zone()->group()->nursery();
    3881           0 :     size_t size = Arena::thingSize(allocKindForTenure(nursery));
    3882             : 
    3883           0 :     if (is<NativeObject>()) {
    3884           0 :         const NativeObject& native = as<NativeObject>();
    3885             : 
    3886           0 :         size += native.numFixedSlots() * sizeof(Value);
    3887           0 :         size += native.numDynamicSlots() * sizeof(Value);
    3888             : 
    3889           0 :         if (native.hasDynamicElements()) {
    3890           0 :             js::ObjectElements& elements = *native.getElementsHeader();
    3891           0 :             if (!elements.isCopyOnWrite() || elements.ownerObject() == this)
    3892           0 :                 size += (elements.capacity + elements.numShiftedElements()) * sizeof(HeapSlot);
    3893             :         }
    3894             : 
    3895           0 :         if (is<ArgumentsObject>())
    3896           0 :             size += as<ArgumentsObject>().sizeOfData();
    3897             :     }
    3898             : 
    3899           0 :     return size;
    3900             : }
    3901             : 
    3902             : JS::ubi::Node::Size
    3903           0 : JS::ubi::Concrete<JSObject>::size(mozilla::MallocSizeOf mallocSizeOf) const
    3904             : {
    3905           0 :     JSObject& obj = get();
    3906             : 
    3907           0 :     if (!obj.isTenured())
    3908           0 :         return obj.sizeOfIncludingThisInNursery();
    3909             : 
    3910           0 :     JS::ClassInfo info;
    3911           0 :     obj.addSizeOfExcludingThis(mallocSizeOf, &info);
    3912           0 :     return obj.tenuredSizeOfThis() + info.sizeOfAllThings();
    3913             : }
    3914             : 
    3915             : const char16_t JS::ubi::Concrete<JSObject>::concreteTypeName[] = u"JSObject";
    3916             : 
    3917             : void
    3918          25 : JSObject::traceChildren(JSTracer* trc)
    3919             : {
    3920          25 :     TraceEdge(trc, &group_, "group");
    3921             : 
    3922          25 :     if (is<ShapedObject>())
    3923          25 :         as<ShapedObject>().traceShape(trc);
    3924             : 
    3925          25 :     const Class* clasp = group_->clasp();
    3926          25 :     if (clasp->isNative()) {
    3927          25 :         NativeObject* nobj = &as<NativeObject>();
    3928             : 
    3929             :         {
    3930          25 :             GetObjectSlotNameFunctor func(nobj);
    3931          50 :             JS::AutoTracingDetails ctx(trc, func);
    3932          50 :             JS::AutoTracingIndex index(trc);
    3933             :             // Tracing can mutate the target but cannot change the slot count,
    3934             :             // but the compiler has no way of knowing this.
    3935          25 :             const uint32_t nslots = nobj->slotSpan();
    3936        3925 :             for (uint32_t i = 0; i < nslots; ++i) {
    3937        3900 :                 TraceManuallyBarrieredEdge(trc, nobj->getSlotRef(i).unsafeUnbarrieredForTracing(),
    3938        3900 :                                            "object slot");
    3939        3900 :                 ++index;
    3940             :             }
    3941          25 :             MOZ_ASSERT(nslots == nobj->slotSpan());
    3942             :         }
    3943             : 
    3944             :         do {
    3945          25 :             if (nobj->denseElementsAreCopyOnWrite()) {
    3946           0 :                 GCPtrNativeObject& owner = nobj->getElementsHeader()->ownerObject();
    3947           0 :                 if (owner != nobj) {
    3948           0 :                     TraceEdge(trc, &owner, "objectElementsOwner");
    3949           0 :                     break;
    3950             :                 }
    3951             :             }
    3952             : 
    3953          25 :             TraceRange(trc,
    3954          25 :                        nobj->getDenseInitializedLength(),
    3955          50 :                        static_cast<HeapSlot*>(nobj->getDenseElementsAllowCopyOnWrite()),
    3956          25 :                        "objectElements");
    3957             :         } while (false);
    3958             :     }
    3959             : 
    3960             :     // Call the trace hook at the end so that during a moving GC the trace hook
    3961             :     // will see updated fields and slots.
    3962          25 :     if (clasp->hasTrace())
    3963          25 :         clasp->doTrace(trc, this);
    3964          25 : }
    3965             : 
    3966             : static JSAtom*
    3967           0 : displayAtomFromObjectGroup(ObjectGroup& group)
    3968             : {
    3969           0 :     TypeNewScript* script = group.newScript();
    3970           0 :     if (!script)
    3971           0 :         return nullptr;
    3972             : 
    3973           0 :     return script->function()->displayAtom();
    3974             : }
    3975             : 
    3976             : /* static */ bool
    3977           0 : JSObject::constructorDisplayAtom(JSContext* cx, js::HandleObject obj, js::MutableHandleAtom name)
    3978             : {
    3979           0 :     ObjectGroup *g = JSObject::getGroup(cx, obj);
    3980           0 :     if (!g)
    3981           0 :         return false;
    3982             : 
    3983           0 :     name.set(displayAtomFromObjectGroup(*g));
    3984           0 :     return true;
    3985             : }
    3986             : 
    3987             : JSAtom*
    3988           0 : JSObject::maybeConstructorDisplayAtom() const
    3989             : {
    3990           0 :     if (hasLazyGroup())
    3991           0 :         return nullptr;
    3992           0 :     return displayAtomFromObjectGroup(*group());
    3993             : }
    3994             : 
    3995             : bool
    3996         275 : js::SpeciesConstructor(JSContext* cx, HandleObject obj, HandleValue defaultCtor, MutableHandleValue pctor)
    3997             : {
    3998         275 :     HandlePropertyName shName = cx->names().SpeciesConstructor;
    3999         550 :     RootedValue func(cx);
    4000         275 :     if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, shName, 2, &func))
    4001           0 :         return false;
    4002             : 
    4003         550 :     FixedInvokeArgs<2> args(cx);
    4004             : 
    4005         275 :     args[0].setObject(*obj);
    4006         275 :     args[1].set(defaultCtor);
    4007             : 
    4008         275 :     if (!Call(cx, func, UndefinedHandleValue, args, pctor))
    4009           0 :         return false;
    4010             : 
    4011         275 :     pctor.set(args.rval());
    4012         275 :     return true;
    4013             : }
    4014             : 
    4015             : bool
    4016         267 : js::SpeciesConstructor(JSContext* cx, HandleObject obj, JSProtoKey ctorKey,
    4017             :                        MutableHandleValue pctor)
    4018             : {
    4019         267 :     if (!GlobalObject::ensureConstructor(cx, cx->global(), ctorKey))
    4020           0 :         return false;
    4021         534 :     RootedValue defaultCtor(cx, cx->global()->getConstructor(ctorKey));
    4022         267 :     return SpeciesConstructor(cx, obj, defaultCtor, pctor);
    4023             : }
    4024             : 
    4025             : bool
    4026          16 : js::Unbox(JSContext* cx, HandleObject obj, MutableHandleValue vp)
    4027             : {
    4028          16 :     if (MOZ_UNLIKELY(obj->is<ProxyObject>()))
    4029           0 :         return Proxy::boxedValue_unbox(cx, obj, vp);
    4030             : 
    4031          16 :     if (obj->is<BooleanObject>())
    4032           0 :         vp.setBoolean(obj->as<BooleanObject>().unbox());
    4033          16 :     else if (obj->is<NumberObject>())
    4034           0 :         vp.setNumber(obj->as<NumberObject>().unbox());
    4035          16 :     else if (obj->is<StringObject>())
    4036           0 :         vp.setString(obj->as<StringObject>().unbox());
    4037          16 :     else if (obj->is<DateObject>())
    4038          16 :         vp.set(obj->as<DateObject>().UTCTime());
    4039             :     else
    4040           0 :         vp.setUndefined();
    4041             : 
    4042          16 :     return true;
    4043             : }
    4044             : 
    4045             : #ifdef DEBUG
    4046             : /* static */ void
    4047      140736 : JSObject::debugCheckNewObject(ObjectGroup* group, Shape* shape, js::gc::AllocKind allocKind,
    4048             :                               js::gc::InitialHeap heap)
    4049             : {
    4050      140736 :     const js::Class* clasp = group->clasp();
    4051      140736 :     MOZ_ASSERT(clasp != &ArrayObject::class_);
    4052             : 
    4053      140736 :     if (shape)
    4054      140684 :         MOZ_ASSERT(clasp == shape->getObjectClass());
    4055             :     else
    4056          52 :         MOZ_ASSERT(clasp == &UnboxedPlainObject::class_ || clasp == &UnboxedArrayObject::class_);
    4057             : 
    4058      140736 :     if (!ClassCanHaveFixedData(clasp)) {
    4059      131349 :         MOZ_ASSERT(shape);
    4060      131349 :         MOZ_ASSERT(gc::GetGCKindSlots(allocKind, clasp) == shape->numFixedSlots());
    4061             :     }
    4062             : 
    4063             :     // Classes with a finalizer must specify whether instances will be finalized
    4064             :     // on the active thread or in the background, except proxies whose behaviour
    4065             :     // depends on the target object.
    4066             :     static const uint32_t FinalizeMask = JSCLASS_FOREGROUND_FINALIZE | JSCLASS_BACKGROUND_FINALIZE;
    4067      140735 :     uint32_t flags = clasp->flags;
    4068      140735 :     uint32_t finalizeFlags = flags & FinalizeMask;
    4069      140735 :     if (clasp->hasFinalize() && !clasp->isProxy()) {
    4070        9983 :         MOZ_ASSERT(finalizeFlags == JSCLASS_FOREGROUND_FINALIZE ||
    4071             :                    finalizeFlags == JSCLASS_BACKGROUND_FINALIZE);
    4072        9983 :         MOZ_ASSERT((finalizeFlags == JSCLASS_BACKGROUND_FINALIZE) == IsBackgroundFinalized(allocKind));
    4073             :     } else {
    4074      130753 :         MOZ_ASSERT(finalizeFlags == 0);
    4075             :     }
    4076             : 
    4077      140736 :     MOZ_ASSERT_IF(clasp->hasFinalize(), heap == gc::TenuredHeap ||
    4078             :                                         CanNurseryAllocateFinalizedClass(clasp) ||
    4079             :                                         clasp->isProxy());
    4080      140736 :     MOZ_ASSERT_IF(group->hasUnanalyzedPreliminaryObjects(), heap == gc::TenuredHeap);
    4081             : 
    4082      140736 :     MOZ_ASSERT(!group->compartment()->hasObjectPendingMetadata());
    4083             : 
    4084             :     // Non-native classes manage their own data and slots, so numFixedSlots and
    4085             :     // slotSpan are always 0. Note that proxy classes can have reserved slots
    4086             :     // but they're also not included in numFixedSlots/slotSpan.
    4087      140738 :     if (!clasp->isNative()) {
    4088        9386 :         MOZ_ASSERT_IF(!clasp->isProxy(), JSCLASS_RESERVED_SLOTS(clasp) == 0);
    4089        9386 :         MOZ_ASSERT(!clasp->hasPrivate());
    4090        9386 :         MOZ_ASSERT_IF(shape, shape->numFixedSlots() == 0);
    4091        9386 :         MOZ_ASSERT_IF(shape, shape->slotSpan() == 0);
    4092             :     }
    4093      140747 : }
    4094             : #endif

Generated by: LCOV version 1.13