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

Generated by: LCOV version 1.13-14-ga5dd952