LCOV - code coverage report
Current view: top level - js/src/builtin - Object.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 302 810 37.3 %
Date: 2017-07-14 16:53:18 Functions: 27 48 56.2 %
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             : #include "builtin/Object.h"
       8             : 
       9             : #include "mozilla/ArrayUtils.h"
      10             : 
      11             : #include "jscntxt.h"
      12             : #include "jsstr.h"
      13             : 
      14             : #include "builtin/Eval.h"
      15             : #include "frontend/BytecodeCompiler.h"
      16             : #include "jit/InlinableNatives.h"
      17             : #include "js/UniquePtr.h"
      18             : #include "vm/AsyncFunction.h"
      19             : #include "vm/RegExpObject.h"
      20             : #include "vm/StringBuffer.h"
      21             : 
      22             : #include "jsobjinlines.h"
      23             : 
      24             : #include "vm/NativeObject-inl.h"
      25             : #include "vm/Shape-inl.h"
      26             : 
      27             : #ifdef FUZZING
      28             : #include "builtin/TestingFunctions.h"
      29             : #endif
      30             : 
      31             : using namespace js;
      32             : 
      33             : using js::frontend::IsIdentifier;
      34             : using mozilla::ArrayLength;
      35             : 
      36             : bool
      37          18 : js::obj_construct(JSContext* cx, unsigned argc, Value* vp)
      38             : {
      39          18 :     CallArgs args = CallArgsFromVp(argc, vp);
      40             : 
      41          36 :     RootedObject obj(cx, nullptr);
      42          18 :     if (args.isConstructing() && (&args.newTarget().toObject() != &args.callee())) {
      43           0 :         RootedObject newTarget(cx, &args.newTarget().toObject());
      44           0 :         obj = CreateThis(cx, &PlainObject::class_, newTarget);
      45           0 :         if (!obj)
      46           0 :             return false;
      47          18 :     } else if (args.length() > 0 && !args[0].isNullOrUndefined()) {
      48           1 :         obj = ToObject(cx, args[0]);
      49           1 :         if (!obj)
      50           0 :             return false;
      51             :     } else {
      52             :         /* Make an object whether this was called with 'new' or not. */
      53          17 :         if (!NewObjectScriptedCall(cx, &obj))
      54           0 :             return false;
      55             :     }
      56             : 
      57          18 :     args.rval().setObject(*obj);
      58          18 :     return true;
      59             : }
      60             : 
      61             : /* ES5 15.2.4.7. */
      62             : bool
      63           0 : js::obj_propertyIsEnumerable(JSContext* cx, unsigned argc, Value* vp)
      64             : {
      65           0 :     CallArgs args = CallArgsFromVp(argc, vp);
      66             : 
      67           0 :     HandleValue idValue = args.get(0);
      68             : 
      69             :     // As an optimization, provide a fast path when rooting is not necessary and
      70             :     // we can safely retrieve the attributes from the object's shape.
      71             : 
      72             :     /* Steps 1-2. */
      73             :     jsid id;
      74           0 :     if (args.thisv().isObject() && ValueToId<NoGC>(cx, idValue, &id)) {
      75           0 :         JSObject* obj = &args.thisv().toObject();
      76             : 
      77             :         /* Step 3. */
      78           0 :         PropertyResult prop;
      79           0 :         if (obj->isNative() &&
      80           0 :             NativeLookupOwnProperty<NoGC>(cx, &obj->as<NativeObject>(), id, &prop))
      81             :         {
      82             :             /* Step 4. */
      83           0 :             if (!prop) {
      84           0 :                 args.rval().setBoolean(false);
      85           0 :                 return true;
      86             :             }
      87             : 
      88             :             /* Step 5. */
      89           0 :             unsigned attrs = GetPropertyAttributes(obj, prop);
      90           0 :             args.rval().setBoolean((attrs & JSPROP_ENUMERATE) != 0);
      91           0 :             return true;
      92             :         }
      93             :     }
      94             : 
      95             :     /* Step 1. */
      96           0 :     RootedId idRoot(cx);
      97           0 :     if (!ToPropertyKey(cx, idValue, &idRoot))
      98           0 :         return false;
      99             : 
     100             :     /* Step 2. */
     101           0 :     RootedObject obj(cx, ToObject(cx, args.thisv()));
     102           0 :     if (!obj)
     103           0 :         return false;
     104             : 
     105             :     /* Step 3. */
     106           0 :     Rooted<PropertyDescriptor> desc(cx);
     107           0 :     if (!GetOwnPropertyDescriptor(cx, obj, idRoot, &desc))
     108           0 :         return false;
     109             : 
     110             :     /* Steps 4-5. */
     111           0 :     args.rval().setBoolean(desc.object() && desc.enumerable());
     112           0 :     return true;
     113             : }
     114             : 
     115             : #if JS_HAS_TOSOURCE
     116             : static bool
     117           0 : obj_toSource(JSContext* cx, unsigned argc, Value* vp)
     118             : {
     119           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     120             : 
     121           0 :     if (!CheckRecursionLimit(cx))
     122           0 :         return false;
     123             : 
     124           0 :     RootedObject obj(cx, ToObject(cx, args.thisv()));
     125           0 :     if (!obj)
     126           0 :         return false;
     127             : 
     128           0 :     JSString* str = ObjectToSource(cx, obj);
     129           0 :     if (!str)
     130           0 :         return false;
     131             : 
     132           0 :     args.rval().setString(str);
     133           0 :     return true;
     134             : }
     135             : 
     136             : template <typename CharT>
     137             : static bool
     138           0 : Consume(const CharT*& s, const CharT* e, const char *chars)
     139             : {
     140           0 :     size_t len = strlen(chars);
     141           0 :     if (s + len >= e)
     142           0 :         return false;
     143           0 :     if (!EqualChars(s, chars, len))
     144           0 :         return false;
     145           0 :     s += len;
     146           0 :     return true;
     147             : }
     148             : 
     149             : template <typename CharT>
     150             : static void
     151           0 : ConsumeSpaces(const CharT*& s, const CharT* e)
     152             : {
     153           0 :     while (*s == ' ' && s < e)
     154           0 :         s++;
     155           0 : }
     156             : 
     157             : /*
     158             :  * Given a function source string, return the offset and length of the part
     159             :  * between '(function $name' and ')'.
     160             :  */
     161             : template <typename CharT>
     162             : static bool
     163           0 : ArgsAndBodySubstring(mozilla::Range<const CharT> chars, size_t* outOffset, size_t* outLen)
     164             : {
     165           0 :     const CharT* const start = chars.begin().get();
     166           0 :     const CharT* s = start;
     167           0 :     const CharT* e = chars.end().get();
     168             : 
     169           0 :     if (s == e)
     170           0 :         return false;
     171             : 
     172             :     // Remove enclosing parentheses.
     173           0 :     if (*s == '(' && *(e - 1) == ')') {
     174           0 :         s++;
     175           0 :         e--;
     176             :     }
     177             : 
     178             :     // Support the following cases, with spaces between tokens:
     179             :     //
     180             :     //   -+---------+-+------------+-+-----+-+- [ - <any> - ] - ( -+-
     181             :     //    |         | |            | |     | |                     |
     182             :     //    +- async -+ +- function -+ +- * -+ +- <any> - ( ---------+
     183             :     //                |            |
     184             :     //                +- get ------+
     185             :     //                |            |
     186             :     //                +- set ------+
     187             :     //
     188             :     // This accepts some invalid syntax, but we don't care, since it's only
     189             :     // used by the non-standard toSource, and we're doing a best-effort attempt
     190             :     // here.
     191             : 
     192           0 :     (void) Consume(s, e, "async");
     193           0 :     ConsumeSpaces(s, e);
     194           0 :     (void) (Consume(s, e, "function") || Consume(s, e, "get") || Consume(s, e, "set"));
     195           0 :     ConsumeSpaces(s, e);
     196           0 :     (void) Consume(s, e, "*");
     197           0 :     ConsumeSpaces(s, e);
     198             : 
     199             :     // Jump over the function's name.
     200           0 :     if (Consume(s, e, "[")) {
     201           0 :         s = js_strchr_limit(s, ']', e);
     202           0 :         if (!s)
     203           0 :             return false;
     204           0 :         s++;
     205           0 :         ConsumeSpaces(s, e);
     206           0 :         if (*s != '(')
     207           0 :             return false;
     208             :     } else {
     209           0 :         s = js_strchr_limit(s, '(', e);
     210           0 :         if (!s)
     211           0 :             return false;
     212             :     }
     213             : 
     214           0 :     *outOffset = s - start;
     215           0 :     *outLen = e - s;
     216           0 :     MOZ_ASSERT(*outOffset + *outLen <= chars.length());
     217           0 :     return true;
     218             : }
     219             : 
     220             : enum class PropertyKind {
     221             :     Getter,
     222             :     Setter,
     223             :     Method,
     224             :     Normal
     225             : };
     226             : 
     227             : JSString*
     228           0 : js::ObjectToSource(JSContext* cx, HandleObject obj)
     229             : {
     230             :     /* If outermost, we need parentheses to be an expression, not a block. */
     231           0 :     bool outermost = cx->cycleDetectorVector().empty();
     232             : 
     233           0 :     AutoCycleDetector detector(cx, obj);
     234           0 :     if (!detector.init())
     235           0 :         return nullptr;
     236           0 :     if (detector.foundCycle())
     237           0 :         return NewStringCopyZ<CanGC>(cx, "{}");
     238             : 
     239           0 :     StringBuffer buf(cx);
     240           0 :     if (outermost && !buf.append('('))
     241           0 :         return nullptr;
     242           0 :     if (!buf.append('{'))
     243           0 :         return nullptr;
     244             : 
     245           0 :     AutoIdVector idv(cx);
     246           0 :     if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_SYMBOLS, &idv))
     247           0 :         return nullptr;
     248             : 
     249           0 :     bool comma = false;
     250             : 
     251           0 :     auto AddProperty = [cx, &comma, &buf](HandleId id, HandleValue val, PropertyKind kind) -> bool {
     252             :         /* Convert id to a string. */
     253           0 :         RootedString idstr(cx);
     254           0 :         if (JSID_IS_SYMBOL(id)) {
     255           0 :             RootedValue v(cx, SymbolValue(JSID_TO_SYMBOL(id)));
     256           0 :             idstr = ValueToSource(cx, v);
     257           0 :             if (!idstr)
     258           0 :                 return false;
     259             :         } else {
     260           0 :             RootedValue idv(cx, IdToValue(id));
     261           0 :             idstr = ToString<CanGC>(cx, idv);
     262           0 :             if (!idstr)
     263           0 :                 return false;
     264             : 
     265             :             /*
     266             :              * If id is a string that's not an identifier, or if it's a
     267             :              * negative integer, then it must be quoted.
     268             :              */
     269           0 :             if (JSID_IS_ATOM(id)
     270           0 :                 ? !IsIdentifier(JSID_TO_ATOM(id))
     271           0 :                 : JSID_TO_INT(id) < 0)
     272             :             {
     273           0 :                 idstr = QuoteString(cx, idstr, char16_t('\''));
     274           0 :                 if (!idstr)
     275           0 :                     return false;
     276             :             }
     277             :         }
     278             : 
     279           0 :         RootedString valsource(cx, ValueToSource(cx, val));
     280           0 :         if (!valsource)
     281           0 :             return false;
     282             : 
     283           0 :         RootedLinearString valstr(cx, valsource->ensureLinear(cx));
     284           0 :         if (!valstr)
     285           0 :             return false;
     286             : 
     287           0 :         if (comma && !buf.append(", "))
     288           0 :             return false;
     289           0 :         comma = true;
     290             : 
     291             :         size_t voffset, vlength;
     292             : 
     293             :         // Methods and accessors can return exact syntax of source, that fits
     294             :         // into property without adding property name or "get"/"set" prefix.
     295             :         // Use the exact syntax when the following conditions are met:
     296             :         //
     297             :         //   * It's a function object
     298             :         //     (exclude proxies)
     299             :         //   * Function's kind and property's kind are same
     300             :         //     (this can be false for dynamically defined properties)
     301             :         //   * Function has explicit name
     302             :         //     (this can be false for computed property and dynamically defined
     303             :         //      properties)
     304             :         //   * Function's name and property's name are same
     305             :         //     (this can be false for dynamically defined properties)
     306           0 :         if (kind == PropertyKind::Getter || kind == PropertyKind::Setter ||
     307             :             kind == PropertyKind::Method)
     308             :         {
     309           0 :             RootedFunction fun(cx);
     310           0 :             if (val.toObject().is<JSFunction>()) {
     311           0 :                 fun = &val.toObject().as<JSFunction>();
     312             :                 // Method's case should be checked on caller.
     313           0 :                 if (((fun->isGetter() && kind == PropertyKind::Getter) ||
     314           0 :                      (fun->isSetter() && kind == PropertyKind::Setter) ||
     315           0 :                      kind == PropertyKind::Method) &&
     316           0 :                     fun->explicitName())
     317             :                 {
     318             :                     bool result;
     319           0 :                     if (!EqualStrings(cx, fun->explicitName(), idstr, &result))
     320           0 :                         return false;
     321             : 
     322           0 :                     if (result)  {
     323           0 :                         if (!buf.append(valstr))
     324           0 :                             return false;
     325           0 :                         return true;
     326             :                     }
     327             :                 }
     328             :             }
     329             : 
     330             :             {
     331             :                 // When falling back try to generate a better string
     332             :                 // representation by skipping the prelude, and also removing
     333             :                 // the enclosing parentheses.
     334             :                 bool success;
     335           0 :                 JS::AutoCheckCannotGC nogc;
     336           0 :                 if (valstr->hasLatin1Chars())
     337           0 :                     success = ArgsAndBodySubstring(valstr->latin1Range(nogc), &voffset, &vlength);
     338             :                 else
     339           0 :                     success = ArgsAndBodySubstring(valstr->twoByteRange(nogc), &voffset, &vlength);
     340           0 :                 if (!success)
     341           0 :                     kind = PropertyKind::Normal;
     342             :             }
     343             : 
     344           0 :             if (kind == PropertyKind::Getter) {
     345           0 :                 if (!buf.append("get "))
     346           0 :                     return false;
     347           0 :             } else if (kind == PropertyKind::Setter) {
     348           0 :                 if (!buf.append("set "))
     349           0 :                     return false;
     350           0 :             } else if (kind == PropertyKind::Method && fun) {
     351           0 :                 if (IsWrappedAsyncFunction(fun)) {
     352           0 :                     if (!buf.append("async "))
     353           0 :                         return false;
     354             :                 }
     355             : 
     356           0 :                 if (fun->isStarGenerator()) {
     357           0 :                     if (!buf.append('*'))
     358           0 :                         return false;
     359             :                 }
     360             :             }
     361             :         }
     362             : 
     363           0 :         bool needsBracket = JSID_IS_SYMBOL(id);
     364           0 :         if (needsBracket && !buf.append('['))
     365           0 :             return false;
     366           0 :         if (!buf.append(idstr))
     367           0 :             return false;
     368           0 :         if (needsBracket && !buf.append(']'))
     369           0 :             return false;
     370             : 
     371           0 :         if (kind == PropertyKind::Getter || kind == PropertyKind::Setter ||
     372             :             kind == PropertyKind::Method)
     373             :         {
     374           0 :             if (!buf.appendSubstring(valstr, voffset, vlength))
     375           0 :                 return false;
     376             :         } else {
     377           0 :             if (!buf.append(':'))
     378           0 :                 return false;
     379           0 :             if (!buf.append(valstr))
     380           0 :                 return false;
     381             :         }
     382           0 :         return true;
     383           0 :     };
     384             : 
     385           0 :     RootedId id(cx);
     386           0 :     Rooted<PropertyDescriptor> desc(cx);
     387           0 :     RootedValue val(cx);
     388           0 :     RootedFunction fun(cx);
     389           0 :     for (size_t i = 0; i < idv.length(); ++i) {
     390           0 :         id = idv[i];
     391           0 :         if (!GetOwnPropertyDescriptor(cx, obj, id, &desc))
     392           0 :             return nullptr;
     393             : 
     394           0 :         if (!desc.object())
     395           0 :             continue;
     396             : 
     397           0 :         if (desc.isAccessorDescriptor()) {
     398           0 :             if (desc.hasGetterObject() && desc.getterObject()) {
     399           0 :                 val.setObject(*desc.getterObject());
     400           0 :                 if (!AddProperty(id, val, PropertyKind::Getter))
     401           0 :                     return nullptr;
     402             :             }
     403           0 :             if (desc.hasSetterObject() && desc.setterObject()) {
     404           0 :                 val.setObject(*desc.setterObject());
     405           0 :                 if (!AddProperty(id, val, PropertyKind::Setter))
     406           0 :                     return nullptr;
     407             :             }
     408           0 :             continue;
     409             :         }
     410             : 
     411           0 :         val.set(desc.value());
     412           0 :         if (IsFunctionObject(val, fun.address())) {
     413           0 :             if (IsWrappedAsyncFunction(fun))
     414           0 :                 fun = GetUnwrappedAsyncFunction(fun);
     415             : 
     416           0 :             if (fun->isMethod()) {
     417           0 :                 if (!AddProperty(id, val, PropertyKind::Method))
     418           0 :                     return nullptr;
     419           0 :                 continue;
     420             :             }
     421             :         }
     422             : 
     423           0 :         if (!AddProperty(id, val, PropertyKind::Normal))
     424           0 :             return nullptr;
     425             :     }
     426             : 
     427           0 :     if (!buf.append('}'))
     428           0 :         return nullptr;
     429           0 :     if (outermost && !buf.append(')'))
     430           0 :         return nullptr;
     431             : 
     432           0 :     return buf.finishString();
     433             : }
     434             : #endif /* JS_HAS_TOSOURCE */
     435             : 
     436             : static bool
     437          37 : GetBuiltinTagSlow(JSContext* cx, HandleObject obj, MutableHandleString builtinTag)
     438             : {
     439             :     // Step 4.
     440             :     bool isArray;
     441          37 :     if (!IsArray(cx, obj, &isArray))
     442           0 :         return false;
     443             : 
     444             :     // Step 5.
     445          37 :     if (isArray) {
     446           2 :         builtinTag.set(cx->names().objectArray);
     447           2 :         return true;
     448             :     }
     449             : 
     450             :     // Steps 6-13.
     451             :     ESClass cls;
     452          35 :     if (!GetBuiltinClass(cx, obj, &cls))
     453           0 :         return false;
     454             : 
     455          35 :     switch (cls) {
     456             :       case ESClass::String:
     457           0 :         builtinTag.set(cx->names().objectString);
     458           0 :         return true;
     459             :       case ESClass::Arguments:
     460           0 :         builtinTag.set(cx->names().objectArguments);
     461           0 :         return true;
     462             :       case ESClass::Error:
     463           0 :         builtinTag.set(cx->names().objectError);
     464           0 :         return true;
     465             :       case ESClass::Boolean:
     466           0 :         builtinTag.set(cx->names().objectBoolean);
     467           0 :         return true;
     468             :       case ESClass::Number:
     469           0 :         builtinTag.set(cx->names().objectNumber);
     470           0 :         return true;
     471             :       case ESClass::Date:
     472           0 :         builtinTag.set(cx->names().objectDate);
     473           0 :         return true;
     474             :       case ESClass::RegExp:
     475           0 :         builtinTag.set(cx->names().objectRegExp);
     476           0 :         return true;
     477             :       default:
     478          35 :         if (obj->isCallable()) {
     479             :             // Non-standard: Prevent <object> from showing up as Function.
     480           0 :             RootedObject unwrapped(cx, CheckedUnwrap(obj));
     481           0 :             if (!unwrapped || !unwrapped->getClass()->isDOMClass()) {
     482           0 :                 builtinTag.set(cx->names().objectFunction);
     483           0 :                 return true;
     484             :             }
     485             :         }
     486          35 :         builtinTag.set(nullptr);
     487          35 :         return true;
     488             :     }
     489             : }
     490             : 
     491             : // ES6 19.1.3.6
     492             : bool
     493          38 : js::obj_toString(JSContext* cx, unsigned argc, Value* vp)
     494             : {
     495          38 :     CallArgs args = CallArgsFromVp(argc, vp);
     496             : 
     497             :     // Step 1.
     498          38 :     if (args.thisv().isUndefined()) {
     499           1 :         args.rval().setString(cx->names().objectUndefined);
     500           1 :         return true;
     501             :     }
     502             : 
     503             :     // Step 2.
     504          37 :     if (args.thisv().isNull()) {
     505           0 :         args.rval().setString(cx->names().objectNull);
     506           0 :         return true;
     507             :     }
     508             : 
     509             :     // Step 3.
     510          74 :     RootedObject obj(cx, ToObject(cx, args.thisv()));
     511          37 :     if (!obj)
     512           0 :         return false;
     513             : 
     514          74 :     RootedString builtinTag(cx);
     515          37 :     const Class* clasp = obj->getClass();
     516          37 :     if (MOZ_UNLIKELY(clasp->isProxy())) {
     517           0 :         if (!GetBuiltinTagSlow(cx, obj, &builtinTag))
     518           0 :             return false;
     519             :     } else {
     520             :         // Optimize the non-proxy case to bypass GetBuiltinClass.
     521          37 :         if (clasp == &PlainObject::class_ || clasp == &UnboxedPlainObject::class_) {
     522             :             // This is not handled by GetBuiltinTagSlow, but this case is by far
     523             :             // the most common so we optimize it here.
     524          34 :             builtinTag = cx->names().objectObject;
     525             : 
     526           3 :         } else if (clasp == &ArrayObject::class_ || clasp == &UnboxedArrayObject::class_) {
     527           2 :             builtinTag = cx->names().objectArray;
     528             : 
     529           1 :         } else if (clasp == &JSFunction::class_) {
     530           0 :             builtinTag = cx->names().objectFunction;
     531             : 
     532           1 :         } else if (clasp == &StringObject::class_) {
     533           0 :             builtinTag = cx->names().objectString;
     534             : 
     535           1 :         } else if (clasp == &NumberObject::class_) {
     536           0 :             builtinTag = cx->names().objectNumber;
     537             : 
     538           1 :         } else if (clasp == &BooleanObject::class_) {
     539           0 :             builtinTag = cx->names().objectBoolean;
     540             : 
     541           1 :         } else if (clasp == &DateObject::class_) {
     542           0 :             builtinTag = cx->names().objectDate;
     543             : 
     544           1 :         } else if (clasp == &RegExpObject::class_) {
     545           0 :             builtinTag = cx->names().objectRegExp;
     546             : 
     547           1 :         } else if (obj->is<ArgumentsObject>()) {
     548           0 :             builtinTag = cx->names().objectArguments;
     549             : 
     550           1 :         } else if (obj->is<ErrorObject>()) {
     551           0 :             builtinTag = cx->names().objectError;
     552             : 
     553           1 :         } else if (obj->isCallable() && !obj->getClass()->isDOMClass()) {
     554             :             // Non-standard: Prevent <object> from showing up as Function.
     555           0 :             builtinTag = cx->names().objectFunction;
     556             :         }
     557             : #ifdef DEBUG
     558             :         // Assert this fast path is correct and matches BuiltinTagSlow. The
     559             :         // only exception is the PlainObject case: we special-case it here
     560             :         // because it's so common, but BuiltinTagSlow doesn't handle this.
     561          74 :         RootedString builtinTagSlow(cx);
     562          37 :         if (!GetBuiltinTagSlow(cx, obj, &builtinTagSlow))
     563           0 :             return false;
     564          37 :         if (clasp == &PlainObject::class_ || clasp == &UnboxedPlainObject::class_)
     565          34 :             MOZ_ASSERT(!builtinTagSlow);
     566             :         else
     567           3 :             MOZ_ASSERT(builtinTagSlow == builtinTag);
     568             : #endif
     569             :     }
     570             : 
     571             :     // Step 14.
     572             :     // Currently omitted for non-standard fallback.
     573             : 
     574             :     // Step 15.
     575          74 :     RootedValue tag(cx);
     576          37 :     if (!GetInterestingSymbolProperty(cx, obj, cx->wellKnownSymbols().toStringTag, &tag))
     577           0 :         return false;
     578             : 
     579             :     // Step 16.
     580          37 :     if (!tag.isString()) {
     581             :         // Non-standard (bug 1277801): Use ClassName as a fallback in the interim
     582          37 :         if (!builtinTag) {
     583           1 :             const char* className = GetObjectClassName(cx, obj);
     584           2 :             StringBuffer sb(cx);
     585           2 :             if (!sb.append("[object ") || !sb.append(className, strlen(className)) ||
     586           1 :                 !sb.append("]"))
     587             :             {
     588           0 :                 return false;
     589             :             }
     590             : 
     591           1 :             builtinTag = sb.finishAtom();
     592           1 :             if (!builtinTag)
     593           0 :                 return false;
     594             :         }
     595             : 
     596          37 :         args.rval().setString(builtinTag);
     597          37 :         return true;
     598             :     }
     599             : 
     600             :     // Step 17.
     601           0 :     StringBuffer sb(cx);
     602           0 :     if (!sb.append("[object ") || !sb.append(tag.toString()) || !sb.append("]"))
     603           0 :         return false;
     604             : 
     605           0 :     JSString* str = sb.finishAtom();
     606           0 :     if (!str)
     607           0 :         return false;
     608             : 
     609           0 :     args.rval().setString(str);
     610           0 :     return true;
     611             : }
     612             : 
     613             : static bool
     614           0 : obj_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
     615             : {
     616           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     617             : 
     618           0 :     if (args.length() < 2) {
     619             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
     620           0 :                                   "Object.setPrototypeOf", "1", "");
     621           0 :         return false;
     622             :     }
     623             : 
     624             :     /* Step 1-2. */
     625           0 :     if (args[0].isNullOrUndefined()) {
     626           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO,
     627           0 :                                   args[0].isNull() ? "null" : "undefined", "object");
     628           0 :         return false;
     629             :     }
     630             : 
     631             :     /* Step 3. */
     632           0 :     if (!args[1].isObjectOrNull()) {
     633           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
     634             :                                   "Object.setPrototypeOf", "an object or null",
     635           0 :                                   InformalValueTypeName(args[1]));
     636           0 :         return false;
     637             :     }
     638             : 
     639             :     /* Step 4. */
     640           0 :     if (!args[0].isObject()) {
     641           0 :         args.rval().set(args[0]);
     642           0 :         return true;
     643             :     }
     644             : 
     645             :     /* Step 5-7. */
     646           0 :     RootedObject obj(cx, &args[0].toObject());
     647           0 :     RootedObject newProto(cx, args[1].toObjectOrNull());
     648           0 :     if (!SetPrototype(cx, obj, newProto))
     649           0 :         return false;
     650             : 
     651             :     /* Step 8. */
     652           0 :     args.rval().set(args[0]);
     653           0 :     return true;
     654             : }
     655             : 
     656             : static bool
     657          50 : PropertyIsEnumerable(JSContext* cx, HandleObject obj, HandleId id, bool* enumerable)
     658             : {
     659          50 :     PropertyResult prop;
     660         248 :     if (obj->isNative() &&
     661         246 :         NativeLookupOwnProperty<NoGC>(cx, &obj->as<NativeObject>(), id, &prop))
     662             :     {
     663          49 :         if (!prop) {
     664           0 :             *enumerable = false;
     665           0 :             return true;
     666             :         }
     667             : 
     668          49 :         unsigned attrs = GetPropertyAttributes(obj, prop);
     669          49 :         *enumerable = (attrs & JSPROP_ENUMERATE) != 0;
     670          49 :         return true;
     671             :     }
     672             : 
     673           2 :     Rooted<PropertyDescriptor> desc(cx);
     674           1 :     if (!GetOwnPropertyDescriptor(cx, obj, id, &desc))
     675           0 :         return false;
     676             : 
     677           1 :     *enumerable = desc.object() && desc.enumerable();
     678           1 :     return true;
     679             : }
     680             : 
     681             : static bool
     682          16 : TryAssignNative(JSContext* cx, HandleObject to, HandleObject from, bool* optimized)
     683             : {
     684          16 :     *optimized = false;
     685             : 
     686          16 :     if (!from->isNative() || !to->isNative())
     687          15 :         return true;
     688             : 
     689             :     // Don't use the fast path if |from| may have extra indexed or lazy
     690             :     // properties.
     691           1 :     NativeObject* fromNative = &from->as<NativeObject>();
     692           3 :     if (fromNative->getDenseInitializedLength() > 0 ||
     693           2 :         fromNative->isIndexed() ||
     694           2 :         fromNative->is<TypedArrayObject>() ||
     695           3 :         fromNative->getClass()->getNewEnumerate() ||
     696           1 :         fromNative->getClass()->getEnumerate())
     697             :     {
     698           1 :         return true;
     699             :     }
     700             : 
     701             :     // Get a list of |from| shapes. As long as from->lastProperty() == fromShape
     702             :     // we can use this to speed up both the enumerability check and the GetProp.
     703             : 
     704             :     using ShapeVector = GCVector<Shape*, 8>;
     705           0 :     Rooted<ShapeVector> shapes(cx, ShapeVector(cx));
     706             : 
     707           0 :     RootedShape fromShape(cx, fromNative->lastProperty());
     708           0 :     for (Shape::Range<NoGC> r(fromShape); !r.empty(); r.popFront()) {
     709             :         // Symbol properties need to be assigned last. For now fall back to the
     710             :         // slow path if we see a symbol property.
     711           0 :         if (MOZ_UNLIKELY(JSID_IS_SYMBOL(r.front().propidRaw())))
     712           0 :             return true;
     713           0 :         if (MOZ_UNLIKELY(!shapes.append(&r.front())))
     714           0 :             return false;
     715             :     }
     716             : 
     717           0 :     *optimized = true;
     718             : 
     719           0 :     RootedShape shape(cx);
     720           0 :     RootedValue propValue(cx);
     721           0 :     RootedId nextKey(cx);
     722           0 :     RootedValue toReceiver(cx, ObjectValue(*to));
     723             : 
     724           0 :     for (size_t i = shapes.length(); i > 0; i--) {
     725           0 :         shape = shapes[i - 1];
     726           0 :         nextKey = shape->propid();
     727             : 
     728             :         // Ensure |from| is still native: a getter/setter might have turned
     729             :         // |from| or |to| into an unboxed object or it could have been swapped
     730             :         // with a non-native object.
     731           0 :         if (MOZ_LIKELY(from->isNative() &&
     732             :                        from->as<NativeObject>().lastProperty() == fromShape &&
     733             :                        shape->hasDefaultGetter() &&
     734             :                        shape->hasSlot()))
     735             :         {
     736           0 :             if (!shape->enumerable())
     737           0 :                 continue;
     738           0 :             propValue = from->as<NativeObject>().getSlot(shape->slot());
     739             :         } else {
     740             :             // |from| changed shape or the property is not a data property, so
     741             :             // we have to do the slower enumerability check and GetProp.
     742             :             bool enumerable;
     743           0 :             if (!PropertyIsEnumerable(cx, from, nextKey, &enumerable))
     744           0 :                 return false;
     745           0 :             if (!enumerable)
     746           0 :                 continue;
     747           0 :             if (!GetProperty(cx, from, from, nextKey, &propValue))
     748           0 :                 return false;
     749             :         }
     750             : 
     751           0 :         ObjectOpResult result;
     752           0 :         if (MOZ_UNLIKELY(!SetProperty(cx, to, nextKey, propValue, toReceiver, result)))
     753           0 :             return false;
     754           0 :         if (MOZ_UNLIKELY(!result.checkStrict(cx, to, nextKey)))
     755           0 :             return false;
     756             :     }
     757             : 
     758           0 :     return true;
     759             : }
     760             : 
     761             : static bool
     762          16 : AssignSlow(JSContext* cx, HandleObject to, HandleObject from)
     763             : {
     764             :     // Step 4.b.ii.
     765          32 :     AutoIdVector keys(cx);
     766          16 :     if (!GetPropertyKeys(cx, from, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &keys))
     767           0 :         return false;
     768             : 
     769             :     // Step 4.c.
     770          32 :     RootedId nextKey(cx);
     771          32 :     RootedValue propValue(cx);
     772          66 :     for (size_t i = 0, len = keys.length(); i < len; i++) {
     773          50 :         nextKey = keys[i];
     774             : 
     775             :         // Step 4.c.i.
     776             :         bool enumerable;
     777          50 :         if (MOZ_UNLIKELY(!PropertyIsEnumerable(cx, from, nextKey, &enumerable)))
     778           0 :             return false;
     779          50 :         if (!enumerable)
     780           3 :             continue;
     781             : 
     782             :         // Step 4.c.ii.1.
     783          47 :         if (MOZ_UNLIKELY(!GetProperty(cx, from, from, nextKey, &propValue)))
     784           0 :             return false;
     785             : 
     786             :         // Step 4.c.ii.2.
     787          47 :         if (MOZ_UNLIKELY(!SetProperty(cx, to, nextKey, propValue)))
     788           0 :             return false;
     789             :     }
     790             : 
     791          16 :     return true;
     792             : }
     793             : 
     794             : // ES2018 draft rev 48ad2688d8f964da3ea8c11163ef20eb126fb8a4
     795             : // 19.1.2.1 Object.assign(target, ...sources)
     796             : static bool
     797          16 : obj_assign(JSContext* cx, unsigned argc, Value* vp)
     798             : {
     799          16 :     CallArgs args = CallArgsFromVp(argc, vp);
     800             : 
     801             :     // Step 1.
     802          32 :     RootedObject to(cx, ToObject(cx, args.get(0)));
     803          16 :     if (!to)
     804           0 :         return false;
     805             : 
     806             :     // Note: step 2 is implicit. If there are 0 arguments, ToObject throws. If
     807             :     // there's 1 argument, the loop below is a no-op.
     808             : 
     809             :     // Step 4.
     810          32 :     RootedObject from(cx);
     811          32 :     for (size_t i = 1; i < args.length(); i++) {
     812             :         // Step 4.a.
     813          16 :         if (args[i].isNullOrUndefined())
     814           0 :             continue;
     815             : 
     816             :         // Step 4.b.i.
     817          16 :         from = ToObject(cx, args[i]);
     818          16 :         if (!from)
     819           0 :             return false;
     820             : 
     821             :         // Steps 4.b.ii, 4.c.
     822             :         bool optimized;
     823          16 :         if (!TryAssignNative(cx, to, from, &optimized))
     824           0 :             return false;
     825          16 :         if (optimized)
     826           0 :             continue;
     827             : 
     828          16 :         if (!AssignSlow(cx, to, from))
     829           0 :             return false;
     830             :     }
     831             : 
     832             :     // Step 5.
     833          16 :     args.rval().setObject(*to);
     834          16 :     return true;
     835             : }
     836             : 
     837             : #if JS_HAS_OBJ_WATCHPOINT
     838             : 
     839             : bool
     840           0 : js::WatchHandler(JSContext* cx, JSObject* obj_, jsid id_, const JS::Value& old,
     841             :                  JS::Value* nvp, void* closure)
     842             : {
     843           0 :     RootedObject obj(cx, obj_);
     844           0 :     RootedId id(cx, id_);
     845             : 
     846             :     /* Avoid recursion on (obj, id) already being watched on cx. */
     847           0 :     AutoResolving resolving(cx, obj, id, AutoResolving::WATCH);
     848           0 :     if (resolving.alreadyStarted())
     849           0 :         return true;
     850             : 
     851           0 :     FixedInvokeArgs<3> args(cx);
     852             : 
     853           0 :     args[0].set(IdToValue(id));
     854           0 :     args[1].set(old);
     855           0 :     args[2].set(*nvp);
     856             : 
     857           0 :     RootedValue callable(cx, ObjectValue(*static_cast<JSObject*>(closure)));
     858           0 :     RootedValue thisv(cx, ObjectValue(*obj));
     859           0 :     RootedValue rv(cx);
     860           0 :     if (!Call(cx, callable, thisv, args, &rv))
     861           0 :         return false;
     862             : 
     863           0 :     *nvp = rv;
     864           0 :     return true;
     865             : }
     866             : 
     867             : static bool
     868           0 : obj_watch(JSContext* cx, unsigned argc, Value* vp)
     869             : {
     870           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     871             : 
     872           0 :     RootedObject obj(cx, ToObject(cx, args.thisv()));
     873           0 :     if (!obj)
     874           0 :         return false;
     875             : 
     876           0 :     if (!GlobalObject::warnOnceAboutWatch(cx, obj))
     877           0 :         return false;
     878             : 
     879           0 :     if (args.length() <= 1) {
     880           0 :         ReportMissingArg(cx, args.calleev(), 1);
     881           0 :         return false;
     882             :     }
     883             : 
     884           0 :     RootedObject callable(cx, ValueToCallable(cx, args[1], args.length() - 2));
     885           0 :     if (!callable)
     886           0 :         return false;
     887             : 
     888           0 :     RootedId propid(cx);
     889           0 :     if (!ValueToId<CanGC>(cx, args[0], &propid))
     890           0 :         return false;
     891             : 
     892           0 :     if (!WatchProperty(cx, obj, propid, callable))
     893           0 :         return false;
     894             : 
     895           0 :     args.rval().setUndefined();
     896           0 :     return true;
     897             : }
     898             : 
     899             : static bool
     900           0 : obj_unwatch(JSContext* cx, unsigned argc, Value* vp)
     901             : {
     902           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     903             : 
     904           0 :     RootedObject obj(cx, ToObject(cx, args.thisv()));
     905           0 :     if (!obj)
     906           0 :         return false;
     907             : 
     908           0 :     if (!GlobalObject::warnOnceAboutWatch(cx, obj))
     909           0 :         return false;
     910             : 
     911           0 :     RootedId id(cx);
     912           0 :     if (args.length() != 0) {
     913           0 :         if (!ValueToId<CanGC>(cx, args[0], &id))
     914           0 :             return false;
     915             :     } else {
     916           0 :         id = JSID_VOID;
     917             :     }
     918             : 
     919           0 :     if (!UnwatchProperty(cx, obj, id))
     920           0 :         return false;
     921             : 
     922           0 :     args.rval().setUndefined();
     923           0 :     return true;
     924             : }
     925             : 
     926             : #endif /* JS_HAS_OBJ_WATCHPOINT */
     927             : 
     928             : /* ES5 15.2.4.6. */
     929             : static bool
     930           0 : obj_isPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
     931             : {
     932           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     933             : 
     934             :     /* Step 1. */
     935           0 :     if (args.length() < 1 || !args[0].isObject()) {
     936           0 :         args.rval().setBoolean(false);
     937           0 :         return true;
     938             :     }
     939             : 
     940             :     /* Step 2. */
     941           0 :     RootedObject obj(cx, ToObject(cx, args.thisv()));
     942           0 :     if (!obj)
     943           0 :         return false;
     944             : 
     945             :     /* Step 3. */
     946             :     bool isDelegate;
     947           0 :     if (!IsDelegate(cx, obj, args[0], &isDelegate))
     948           0 :         return false;
     949           0 :     args.rval().setBoolean(isDelegate);
     950           0 :     return true;
     951             : }
     952             : 
     953             : PlainObject*
     954         131 : js::ObjectCreateImpl(JSContext* cx, HandleObject proto, NewObjectKind newKind,
     955             :                      HandleObjectGroup group)
     956             : {
     957             :     // Give the new object a small number of fixed slots, like we do for empty
     958             :     // object literals ({}).
     959         131 :     gc::AllocKind allocKind = GuessObjectGCKind(0);
     960             : 
     961         131 :     if (!proto) {
     962             :         // Object.create(null) is common, optimize it by using an allocation
     963             :         // site specific ObjectGroup. Because GetCallerInitGroup is pretty
     964             :         // slow, the caller can pass in the group if it's known and we use that
     965             :         // instead.
     966         130 :         RootedObjectGroup ngroup(cx, group);
     967          65 :         if (!ngroup) {
     968          65 :             ngroup = ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Null);
     969          65 :             if (!ngroup)
     970           0 :                 return nullptr;
     971             :         }
     972             : 
     973          65 :         MOZ_ASSERT(!ngroup->proto().toObjectOrNull());
     974             : 
     975          65 :         return NewObjectWithGroup<PlainObject>(cx, ngroup, allocKind, newKind);
     976             :     }
     977             : 
     978          66 :     return NewObjectWithGivenProto<PlainObject>(cx, proto, allocKind, newKind);
     979             : }
     980             : 
     981             : PlainObject*
     982           0 : js::ObjectCreateWithTemplate(JSContext* cx, HandlePlainObject templateObj)
     983             : {
     984           0 :     RootedObject proto(cx, templateObj->staticPrototype());
     985           0 :     RootedObjectGroup group(cx, templateObj->group());
     986           0 :     return ObjectCreateImpl(cx, proto, GenericObject, group);
     987             : }
     988             : 
     989             : // ES 2017 draft 19.1.2.3.1
     990             : static bool
     991          85 : ObjectDefineProperties(JSContext* cx, HandleObject obj, HandleValue properties)
     992             : {
     993             :     // Step 1. implicit
     994             :     // Step 2.
     995         170 :     RootedObject props(cx, ToObject(cx, properties));
     996          85 :     if (!props)
     997           0 :         return false;
     998             : 
     999             :     // Step 3.
    1000         170 :     AutoIdVector keys(cx);
    1001          85 :     if (!GetPropertyKeys(cx, props, JSITER_OWNONLY | JSITER_SYMBOLS | JSITER_HIDDEN, &keys))
    1002           0 :         return false;
    1003             : 
    1004         170 :     RootedId nextKey(cx);
    1005         170 :     Rooted<PropertyDescriptor> desc(cx);
    1006         170 :     RootedValue descObj(cx);
    1007             : 
    1008             :     // Step 4.
    1009         170 :     Rooted<PropertyDescriptorVector> descriptors(cx, PropertyDescriptorVector(cx));
    1010         170 :     AutoIdVector descriptorKeys(cx);
    1011             : 
    1012             :     // Step 5.
    1013         451 :     for (size_t i = 0, len = keys.length(); i < len; i++) {
    1014         366 :         nextKey = keys[i];
    1015             : 
    1016             :         // Step 5.a.
    1017         366 :         if (!GetOwnPropertyDescriptor(cx, props, nextKey, &desc))
    1018           0 :             return false;
    1019             : 
    1020             :         // Step 5.b.
    1021         366 :         if (desc.object() && desc.enumerable()) {
    1022        3660 :             if (!GetProperty(cx, props, props, nextKey, &descObj) ||
    1023        1830 :                 !ToPropertyDescriptor(cx, descObj, true, &desc) ||
    1024        2928 :                 !descriptors.append(desc) ||
    1025         366 :                 !descriptorKeys.append(nextKey))
    1026             :             {
    1027           0 :                 return false;
    1028             :             }
    1029             :         }
    1030             :     }
    1031             : 
    1032             :     // Step 6.
    1033         451 :     for (size_t i = 0, len = descriptors.length(); i < len; i++) {
    1034         366 :         if (!DefineProperty(cx, obj, descriptorKeys[i], descriptors[i]))
    1035           0 :             return false;
    1036             :     }
    1037             : 
    1038          85 :     return true;
    1039             : }
    1040             : 
    1041             : // ES6 draft rev34 (2015/02/20) 19.1.2.2 Object.create(O [, Properties])
    1042             : bool
    1043         129 : js::obj_create(JSContext* cx, unsigned argc, Value* vp)
    1044             : {
    1045         129 :     CallArgs args = CallArgsFromVp(argc, vp);
    1046             : 
    1047             :     // Step 1.
    1048         129 :     if (args.length() == 0) {
    1049             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
    1050           0 :                                   "Object.create", "0", "s");
    1051           0 :         return false;
    1052             :     }
    1053             : 
    1054         129 :     if (!args[0].isObjectOrNull()) {
    1055           0 :         RootedValue v(cx, args[0]);
    1056           0 :         UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, nullptr);
    1057           0 :         if (!bytes)
    1058           0 :             return false;
    1059             : 
    1060           0 :         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
    1061           0 :                                    bytes.get(), "not an object or null");
    1062           0 :         return false;
    1063             :     }
    1064             : 
    1065             :     // Step 2.
    1066         258 :     RootedObject proto(cx, args[0].toObjectOrNull());
    1067         258 :     RootedPlainObject obj(cx, ObjectCreateImpl(cx, proto));
    1068         129 :     if (!obj)
    1069           0 :         return false;
    1070             : 
    1071             :     // Step 3.
    1072         129 :     if (args.hasDefined(1)) {
    1073          48 :         if (!ObjectDefineProperties(cx, obj, args[1]))
    1074           0 :             return false;
    1075             :     }
    1076             : 
    1077             :     // Step 4.
    1078         129 :     args.rval().setObject(*obj);
    1079         129 :     return true;
    1080             : }
    1081             : 
    1082             : // ES6 draft rev27 (2014/08/24) 19.1.2.6 Object.getOwnPropertyDescriptor(O, P)
    1083             : bool
    1084         212 : js::obj_getOwnPropertyDescriptor(JSContext* cx, unsigned argc, Value* vp)
    1085             : {
    1086         212 :     CallArgs args = CallArgsFromVp(argc, vp);
    1087             : 
    1088             :     // Steps 1-2.
    1089         424 :     RootedObject obj(cx, ToObject(cx, args.get(0)));
    1090         212 :     if (!obj)
    1091           0 :         return false;
    1092             : 
    1093             :     // Steps 3-4.
    1094         424 :     RootedId id(cx);
    1095         212 :     if (!ToPropertyKey(cx, args.get(1), &id))
    1096           0 :         return false;
    1097             : 
    1098             :     // Steps 5-7.
    1099         424 :     Rooted<PropertyDescriptor> desc(cx);
    1100        1060 :     return GetOwnPropertyDescriptor(cx, obj, id, &desc) &&
    1101         636 :            JS::FromPropertyDescriptor(cx, desc, args.rval());
    1102             : }
    1103             : 
    1104             : enum EnumerableOwnPropertiesKind {
    1105             :     Keys,
    1106             :     Values,
    1107             :     KeysAndValues
    1108             : };
    1109             : 
    1110             : // ES7 proposal 2015-12-14
    1111             : // http://tc39.github.io/proposal-object-values-entries/#EnumerableOwnProperties
    1112             : static bool
    1113          19 : EnumerableOwnProperties(JSContext* cx, const JS::CallArgs& args, EnumerableOwnPropertiesKind kind)
    1114             : {
    1115             :     // Step 1. (Step 1 of Object.{keys,values,entries}, really.)
    1116          38 :     RootedObject obj(cx, ToObject(cx, args.get(0)));
    1117          19 :     if (!obj)
    1118           0 :         return false;
    1119             : 
    1120             :     // Step 2.
    1121          38 :     AutoIdVector ids(cx);
    1122          19 :     if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &ids))
    1123           0 :         return false;
    1124             : 
    1125             :     // Step 3.
    1126          38 :     AutoValueVector properties(cx);
    1127          19 :     size_t len = ids.length();
    1128          19 :     if (!properties.resize(len))
    1129           0 :         return false;
    1130             : 
    1131          38 :     RootedId id(cx);
    1132          38 :     RootedValue key(cx);
    1133          38 :     RootedValue value(cx);
    1134          38 :     RootedNativeObject nobj(cx);
    1135          19 :     if (obj->is<NativeObject>())
    1136          18 :         nobj = &obj->as<NativeObject>();
    1137          38 :     RootedShape shape(cx);
    1138          38 :     Rooted<PropertyDescriptor> desc(cx);
    1139             :     // Step 4.
    1140          19 :     size_t out = 0;
    1141         102 :     for (size_t i = 0; i < len; i++) {
    1142          83 :         id = ids[i];
    1143             : 
    1144             :         // Step 4.a. (Symbols were filtered out in step 2.)
    1145          83 :         MOZ_ASSERT(!JSID_IS_SYMBOL(id));
    1146             : 
    1147          83 :         if (kind != Values) {
    1148          41 :             if (!IdToStringOrSymbol(cx, id, &key))
    1149           0 :                 return false;
    1150             :         }
    1151             : 
    1152             :         // Step 4.a.i.
    1153          83 :         if (nobj) {
    1154          83 :             if (JSID_IS_INT(id) && nobj->containsDenseElement(JSID_TO_INT(id))) {
    1155           0 :                 value = nobj->getDenseOrTypedArrayElement(JSID_TO_INT(id));
    1156             :             } else {
    1157          83 :                 shape = nobj->lookup(cx, id);
    1158          83 :                 if (!shape || !(shape->attributes() & JSPROP_ENUMERATE))
    1159           0 :                     continue;
    1160          83 :                 if (!shape->isAccessorShape()) {
    1161          83 :                     if (!NativeGetExistingProperty(cx, nobj, nobj, shape, &value))
    1162           0 :                         return false;
    1163           0 :                 } else if (!GetProperty(cx, obj, obj, id, &value)) {
    1164           0 :                     return false;
    1165             :                 }
    1166             :             }
    1167             :         } else {
    1168           0 :             if (!GetOwnPropertyDescriptor(cx, obj, id, &desc))
    1169           0 :                 return false;
    1170             : 
    1171             :             // Step 4.a.ii. (inverted.)
    1172           0 :             if (!desc.object() || !desc.enumerable())
    1173           0 :                 continue;
    1174             : 
    1175             :             // Step 4.a.ii.1.
    1176             :             // (Omitted because Object.keys doesn't use this implementation.)
    1177             : 
    1178             :             // Step 4.a.ii.2.a.
    1179           0 :             if (!GetProperty(cx, obj, obj, id, &value))
    1180           0 :                 return false;
    1181             :         }
    1182             : 
    1183             :         // Steps 4.a.ii.2.b-c.
    1184          83 :         if (kind == Values)
    1185          42 :             properties[out++].set(value);
    1186          41 :         else if (!NewValuePair(cx, key, value, properties[out++]))
    1187           0 :             return false;
    1188             :     }
    1189             : 
    1190             :     // Step 5.
    1191             :     // (Implemented in step 2.)
    1192             : 
    1193             :     // Step 3 of Object.{keys,values,entries}
    1194          19 :     JSObject* aobj = NewDenseCopiedArray(cx, out, properties.begin());
    1195          19 :     if (!aobj)
    1196           0 :         return false;
    1197             : 
    1198          19 :     args.rval().setObject(*aobj);
    1199          19 :     return true;
    1200             : }
    1201             : 
    1202             : // ES7 proposal 2015-12-14
    1203             : // http://tc39.github.io/proposal-object-values-entries/#Object.keys
    1204             : static bool
    1205          45 : obj_keys(JSContext* cx, unsigned argc, Value* vp)
    1206             : {
    1207          45 :     CallArgs args = CallArgsFromVp(argc, vp);
    1208          45 :     return GetOwnPropertyKeys(cx, args, JSITER_OWNONLY);
    1209             : }
    1210             : 
    1211             : // ES7 proposal 2015-12-14
    1212             : // http://tc39.github.io/proposal-object-values-entries/#Object.values
    1213             : static bool
    1214          10 : obj_values(JSContext* cx, unsigned argc, Value* vp)
    1215             : {
    1216          10 :     CallArgs args = CallArgsFromVp(argc, vp);
    1217          10 :     return EnumerableOwnProperties(cx, args, Values);
    1218             : }
    1219             : 
    1220             : // ES7 proposal 2015-12-14
    1221             : // http://tc39.github.io/proposal-object-values-entries/#Object.entries
    1222             : static bool
    1223           9 : obj_entries(JSContext* cx, unsigned argc, Value* vp)
    1224             : {
    1225           9 :     CallArgs args = CallArgsFromVp(argc, vp);
    1226           9 :     return EnumerableOwnProperties(cx, args, KeysAndValues);
    1227             : }
    1228             : 
    1229             : /* ES6 draft 15.2.3.16 */
    1230             : static bool
    1231           0 : obj_is(JSContext* cx, unsigned argc, Value* vp)
    1232             : {
    1233           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1234             : 
    1235             :     bool same;
    1236           0 :     if (!SameValue(cx, args.get(0), args.get(1), &same))
    1237           0 :         return false;
    1238             : 
    1239           0 :     args.rval().setBoolean(same);
    1240           0 :     return true;
    1241             : }
    1242             : 
    1243             : bool
    1244        2886 : js::IdToStringOrSymbol(JSContext* cx, HandleId id, MutableHandleValue result)
    1245             : {
    1246        2886 :     if (JSID_IS_INT(id)) {
    1247           1 :         JSString* str = Int32ToString<CanGC>(cx, JSID_TO_INT(id));
    1248           1 :         if (!str)
    1249           0 :             return false;
    1250           1 :         result.setString(str);
    1251        2885 :     } else if (JSID_IS_ATOM(id)) {
    1252        2884 :         result.setString(JSID_TO_STRING(id));
    1253             :     } else {
    1254           1 :         result.setSymbol(JSID_TO_SYMBOL(id));
    1255             :     }
    1256        2886 :     return true;
    1257             : }
    1258             : 
    1259             : /* ES6 draft rev 25 (2014 May 22) 19.1.2.8.1 */
    1260             : bool
    1261         161 : js::GetOwnPropertyKeys(JSContext* cx, const JS::CallArgs& args, unsigned flags)
    1262             : {
    1263             :     // Steps 1-2.
    1264         322 :     RootedObject obj(cx, ToObject(cx, args.get(0)));
    1265         161 :     if (!obj)
    1266           0 :         return false;
    1267             : 
    1268             :     // Steps 3-10.
    1269         322 :     AutoIdVector keys(cx);
    1270         161 :     if (!GetPropertyKeys(cx, obj, flags, &keys))
    1271           0 :         return false;
    1272             : 
    1273             :     // Step 11.
    1274         322 :     AutoValueVector vals(cx);
    1275         161 :     if (!vals.resize(keys.length()))
    1276           0 :         return false;
    1277             : 
    1278        2991 :     for (size_t i = 0, len = keys.length(); i < len; i++) {
    1279        2830 :         MOZ_ASSERT_IF(JSID_IS_SYMBOL(keys[i]), flags & JSITER_SYMBOLS);
    1280        2830 :         MOZ_ASSERT_IF(!JSID_IS_SYMBOL(keys[i]), !(flags & JSITER_SYMBOLSONLY));
    1281        2830 :         if (!IdToStringOrSymbol(cx, keys[i], vals[i]))
    1282           0 :             return false;
    1283             :     }
    1284             : 
    1285         161 :     JSObject* aobj = NewDenseCopiedArray(cx, vals.length(), vals.begin());
    1286         161 :     if (!aobj)
    1287           0 :         return false;
    1288             : 
    1289         161 :     args.rval().setObject(*aobj);
    1290         161 :     return true;
    1291             : }
    1292             : 
    1293             : bool
    1294          60 : js::obj_getOwnPropertyNames(JSContext* cx, unsigned argc, Value* vp)
    1295             : {
    1296          60 :     CallArgs args = CallArgsFromVp(argc, vp);
    1297          60 :     return GetOwnPropertyKeys(cx, args, JSITER_OWNONLY | JSITER_HIDDEN);
    1298             : }
    1299             : 
    1300             : /* ES6 draft rev 25 (2014 May 22) 19.1.2.8 */
    1301             : static bool
    1302          56 : obj_getOwnPropertySymbols(JSContext* cx, unsigned argc, Value* vp)
    1303             : {
    1304          56 :     CallArgs args = CallArgsFromVp(argc, vp);
    1305             :     return GetOwnPropertyKeys(cx, args,
    1306          56 :                               JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS | JSITER_SYMBOLSONLY);
    1307             : }
    1308             : 
    1309             : /* ES6 draft rev 32 (2015 Feb 2) 19.1.2.4: Object.defineProperty(O, P, Attributes) */
    1310             : bool
    1311        1951 : js::obj_defineProperty(JSContext* cx, unsigned argc, Value* vp)
    1312             : {
    1313        1951 :     CallArgs args = CallArgsFromVp(argc, vp);
    1314             : 
    1315             :     // Steps 1-3.
    1316        3902 :     RootedObject obj(cx);
    1317        1951 :     if (!GetFirstArgumentAsObject(cx, args, "Object.defineProperty", &obj))
    1318           0 :         return false;
    1319        3902 :     RootedId id(cx);
    1320        1951 :     if (!ToPropertyKey(cx, args.get(1), &id))
    1321           0 :         return false;
    1322             : 
    1323             :     // Steps 4-5.
    1324        3902 :     Rooted<PropertyDescriptor> desc(cx);
    1325        1951 :     if (!ToPropertyDescriptor(cx, args.get(2), true, &desc))
    1326           0 :         return false;
    1327             : 
    1328             :     // Steps 6-8.
    1329        1951 :     if (!DefineProperty(cx, obj, id, desc))
    1330           0 :         return false;
    1331        1951 :     args.rval().setObject(*obj);
    1332        1951 :     return true;
    1333             : }
    1334             : 
    1335             : /* ES5 15.2.3.7: Object.defineProperties(O, Properties) */
    1336             : static bool
    1337          37 : obj_defineProperties(JSContext* cx, unsigned argc, Value* vp)
    1338             : {
    1339          37 :     CallArgs args = CallArgsFromVp(argc, vp);
    1340             : 
    1341             :     /* Steps 1 and 7. */
    1342          74 :     RootedObject obj(cx);
    1343          37 :     if (!GetFirstArgumentAsObject(cx, args, "Object.defineProperties", &obj))
    1344           0 :         return false;
    1345          37 :     args.rval().setObject(*obj);
    1346             : 
    1347             :     /* Step 2. */
    1348          37 :     if (args.length() < 2) {
    1349             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
    1350           0 :                                   "Object.defineProperties", "0", "s");
    1351           0 :         return false;
    1352             :     }
    1353             : 
    1354             :     /* Steps 3-6. */
    1355          37 :     return ObjectDefineProperties(cx, obj, args[1]);
    1356             : }
    1357             : 
    1358             : // ES6 20141014 draft 19.1.2.15 Object.preventExtensions(O)
    1359             : static bool
    1360           0 : obj_preventExtensions(JSContext* cx, unsigned argc, Value* vp)
    1361             : {
    1362           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1363           0 :     args.rval().set(args.get(0));
    1364             : 
    1365             :     // Step 1.
    1366           0 :     if (!args.get(0).isObject())
    1367           0 :         return true;
    1368             : 
    1369             :     // Steps 2-5.
    1370           0 :     RootedObject obj(cx, &args.get(0).toObject());
    1371           0 :     return PreventExtensions(cx, obj);
    1372             : }
    1373             : 
    1374             : // ES6 draft rev27 (2014/08/24) 19.1.2.5 Object.freeze(O)
    1375             : static bool
    1376         176 : obj_freeze(JSContext* cx, unsigned argc, Value* vp)
    1377             : {
    1378         176 :     CallArgs args = CallArgsFromVp(argc, vp);
    1379         176 :     args.rval().set(args.get(0));
    1380             : 
    1381             :     // Step 1.
    1382         176 :     if (!args.get(0).isObject())
    1383           0 :         return true;
    1384             : 
    1385             :     // Steps 2-5.
    1386         352 :     RootedObject obj(cx, &args.get(0).toObject());
    1387         176 :     return SetIntegrityLevel(cx, obj, IntegrityLevel::Frozen);
    1388             : }
    1389             : 
    1390             : // ES6 draft rev27 (2014/08/24) 19.1.2.12 Object.isFrozen(O)
    1391             : static bool
    1392          32 : obj_isFrozen(JSContext* cx, unsigned argc, Value* vp)
    1393             : {
    1394          32 :     CallArgs args = CallArgsFromVp(argc, vp);
    1395             : 
    1396             :     // Step 1.
    1397          32 :     bool frozen = true;
    1398             : 
    1399             :     // Step 2.
    1400          32 :     if (args.get(0).isObject()) {
    1401          64 :         RootedObject obj(cx, &args.get(0).toObject());
    1402          32 :         if (!TestIntegrityLevel(cx, obj, IntegrityLevel::Frozen, &frozen))
    1403           0 :             return false;
    1404             :     }
    1405          32 :     args.rval().setBoolean(frozen);
    1406          32 :     return true;
    1407             : }
    1408             : 
    1409             : // ES6 draft rev27 (2014/08/24) 19.1.2.17 Object.seal(O)
    1410             : static bool
    1411           4 : obj_seal(JSContext* cx, unsigned argc, Value* vp)
    1412             : {
    1413           4 :     CallArgs args = CallArgsFromVp(argc, vp);
    1414           4 :     args.rval().set(args.get(0));
    1415             : 
    1416             :     // Step 1.
    1417           4 :     if (!args.get(0).isObject())
    1418           0 :         return true;
    1419             : 
    1420             :     // Steps 2-5.
    1421           8 :     RootedObject obj(cx, &args.get(0).toObject());
    1422           4 :     return SetIntegrityLevel(cx, obj, IntegrityLevel::Sealed);
    1423             : }
    1424             : 
    1425             : // ES6 draft rev27 (2014/08/24) 19.1.2.13 Object.isSealed(O)
    1426             : static bool
    1427           0 : obj_isSealed(JSContext* cx, unsigned argc, Value* vp)
    1428             : {
    1429           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1430             : 
    1431             :     // Step 1.
    1432           0 :     bool sealed = true;
    1433             : 
    1434             :     // Step 2.
    1435           0 :     if (args.get(0).isObject()) {
    1436           0 :         RootedObject obj(cx, &args.get(0).toObject());
    1437           0 :         if (!TestIntegrityLevel(cx, obj, IntegrityLevel::Sealed, &sealed))
    1438           0 :             return false;
    1439             :     }
    1440           0 :     args.rval().setBoolean(sealed);
    1441           0 :     return true;
    1442             : }
    1443             : 
    1444             : static bool
    1445           0 : ProtoGetter(JSContext* cx, unsigned argc, Value* vp)
    1446             : {
    1447           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1448             : 
    1449           0 :     RootedValue thisv(cx, args.thisv());
    1450           0 :     if (thisv.isPrimitive()) {
    1451           0 :         if (thisv.isNullOrUndefined()) {
    1452           0 :             ReportIncompatible(cx, args);
    1453           0 :             return false;
    1454             :         }
    1455             : 
    1456           0 :         if (!BoxNonStrictThis(cx, thisv, &thisv))
    1457           0 :             return false;
    1458             :     }
    1459             : 
    1460           0 :     RootedObject obj(cx, &thisv.toObject());
    1461           0 :     RootedObject proto(cx);
    1462           0 :     if (!GetPrototype(cx, obj, &proto))
    1463           0 :         return false;
    1464             : 
    1465           0 :     args.rval().setObjectOrNull(proto);
    1466           0 :     return true;
    1467             : }
    1468             : 
    1469             : namespace js {
    1470             : size_t sSetProtoCalled = 0;
    1471             : } // namespace js
    1472             : 
    1473             : static bool
    1474           0 : ProtoSetter(JSContext* cx, unsigned argc, Value* vp)
    1475             : {
    1476           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1477             : 
    1478           0 :     HandleValue thisv = args.thisv();
    1479           0 :     if (thisv.isNullOrUndefined()) {
    1480           0 :         ReportIncompatible(cx, args);
    1481           0 :         return false;
    1482             :     }
    1483           0 :     if (thisv.isPrimitive()) {
    1484             :         // Mutating a boxed primitive's [[Prototype]] has no side effects.
    1485           0 :         args.rval().setUndefined();
    1486           0 :         return true;
    1487             :     }
    1488             : 
    1489           0 :     if (!cx->runningWithTrustedPrincipals())
    1490           0 :         ++sSetProtoCalled;
    1491             : 
    1492           0 :     Rooted<JSObject*> obj(cx, &args.thisv().toObject());
    1493             : 
    1494             :     /* Do nothing if __proto__ isn't being set to an object or null. */
    1495           0 :     if (args.length() == 0 || !args[0].isObjectOrNull()) {
    1496           0 :         args.rval().setUndefined();
    1497           0 :         return true;
    1498             :     }
    1499             : 
    1500           0 :     Rooted<JSObject*> newProto(cx, args[0].toObjectOrNull());
    1501           0 :     if (!SetPrototype(cx, obj, newProto))
    1502           0 :         return false;
    1503             : 
    1504           0 :     args.rval().setUndefined();
    1505           0 :     return true;
    1506             : }
    1507             : 
    1508             : static const JSFunctionSpec object_methods[] = {
    1509             : #if JS_HAS_TOSOURCE
    1510             :     JS_FN(js_toSource_str,             obj_toSource,                0,0),
    1511             : #endif
    1512             :     JS_FN(js_toString_str,             obj_toString,                0,0),
    1513             :     JS_SELF_HOSTED_FN(js_toLocaleString_str, "Object_toLocaleString", 0, 0),
    1514             :     JS_SELF_HOSTED_FN(js_valueOf_str,  "Object_valueOf",            0,0),
    1515             : #if JS_HAS_OBJ_WATCHPOINT
    1516             :     JS_FN(js_watch_str,                obj_watch,                   2,0),
    1517             :     JS_FN(js_unwatch_str,              obj_unwatch,                 1,0),
    1518             : #endif
    1519             :     JS_SELF_HOSTED_FN(js_hasOwnProperty_str, "Object_hasOwnProperty", 1,0),
    1520             :     JS_FN(js_isPrototypeOf_str,        obj_isPrototypeOf,           1,0),
    1521             :     JS_FN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable,    1,0),
    1522             : #if JS_OLD_GETTER_SETTER_METHODS
    1523             :     JS_SELF_HOSTED_FN(js_defineGetter_str, "ObjectDefineGetter",    2,0),
    1524             :     JS_SELF_HOSTED_FN(js_defineSetter_str, "ObjectDefineSetter",    2,0),
    1525             :     JS_SELF_HOSTED_FN(js_lookupGetter_str, "ObjectLookupGetter",    1,0),
    1526             :     JS_SELF_HOSTED_FN(js_lookupSetter_str, "ObjectLookupSetter",    1,0),
    1527             : #endif
    1528             :     JS_FS_END
    1529             : };
    1530             : 
    1531             : static const JSPropertySpec object_properties[] = {
    1532             : #if JS_HAS_OBJ_PROTO_PROP
    1533             :     JS_PSGS("__proto__", ProtoGetter, ProtoSetter, 0),
    1534             : #endif
    1535             :     JS_PS_END
    1536             : };
    1537             : 
    1538             : static const JSFunctionSpec object_static_methods[] = {
    1539             :     JS_FN("assign",                    obj_assign,                  2, 0),
    1540             :     JS_SELF_HOSTED_FN("getPrototypeOf", "ObjectGetPrototypeOf",     1, 0),
    1541             :     JS_FN("setPrototypeOf",            obj_setPrototypeOf,          2, 0),
    1542             :     JS_FN("getOwnPropertyDescriptor",  obj_getOwnPropertyDescriptor,2, 0),
    1543             :     JS_SELF_HOSTED_FN("getOwnPropertyDescriptors", "ObjectGetOwnPropertyDescriptors", 1, 0),
    1544             :     JS_FN("keys",                      obj_keys,                    1, 0),
    1545             :     JS_FN("values",                    obj_values,                  1, 0),
    1546             :     JS_FN("entries",                   obj_entries,                 1, 0),
    1547             :     JS_FN("is",                        obj_is,                      2, 0),
    1548             :     JS_FN("defineProperty",            obj_defineProperty,          3, 0),
    1549             :     JS_FN("defineProperties",          obj_defineProperties,        2, 0),
    1550             :     JS_INLINABLE_FN("create",          obj_create,                  2, 0, ObjectCreate),
    1551             :     JS_FN("getOwnPropertyNames",       obj_getOwnPropertyNames,     1, 0),
    1552             :     JS_FN("getOwnPropertySymbols",     obj_getOwnPropertySymbols,   1, 0),
    1553             :     JS_SELF_HOSTED_FN("isExtensible",  "ObjectIsExtensible",        1, 0),
    1554             :     JS_FN("preventExtensions",         obj_preventExtensions,       1, 0),
    1555             :     JS_FN("freeze",                    obj_freeze,                  1, 0),
    1556             :     JS_FN("isFrozen",                  obj_isFrozen,                1, 0),
    1557             :     JS_FN("seal",                      obj_seal,                    1, 0),
    1558             :     JS_FN("isSealed",                  obj_isSealed,                1, 0),
    1559             :     JS_FS_END
    1560             : };
    1561             : 
    1562             : static JSObject*
    1563         312 : CreateObjectConstructor(JSContext* cx, JSProtoKey key)
    1564             : {
    1565         624 :     Rooted<GlobalObject*> self(cx, cx->global());
    1566         312 :     if (!GlobalObject::ensureConstructor(cx, self, JSProto_Function))
    1567           0 :         return nullptr;
    1568             : 
    1569             :     /* Create the Object function now that we have a [[Prototype]] for it. */
    1570         624 :     return NewNativeConstructor(cx, obj_construct, 1, HandlePropertyName(cx->names().Object),
    1571         312 :                                 gc::AllocKind::FUNCTION, SingletonObject);
    1572             : }
    1573             : 
    1574             : static JSObject*
    1575         312 : CreateObjectPrototype(JSContext* cx, JSProtoKey key)
    1576             : {
    1577         312 :     MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
    1578         312 :     MOZ_ASSERT(cx->global()->isNative());
    1579             : 
    1580             :     /*
    1581             :      * Create |Object.prototype| first, mirroring CreateBlankProto but for the
    1582             :      * prototype of the created object.
    1583             :      */
    1584         624 :     RootedPlainObject objectProto(cx, NewObjectWithGivenProto<PlainObject>(cx, nullptr,
    1585         624 :                                                                            SingletonObject));
    1586         312 :     if (!objectProto)
    1587           0 :         return nullptr;
    1588             : 
    1589             :     bool succeeded;
    1590         312 :     if (!SetImmutablePrototype(cx, objectProto, &succeeded))
    1591           0 :         return nullptr;
    1592         312 :     MOZ_ASSERT(succeeded,
    1593             :                "should have been able to make a fresh Object.prototype's "
    1594             :                "[[Prototype]] immutable");
    1595             : 
    1596             :     /*
    1597             :      * The default 'new' type of Object.prototype is required by type inference
    1598             :      * to have unknown properties, to simplify handling of e.g. heterogenous
    1599             :      * objects in JSON and script literals.
    1600             :      */
    1601         312 :     if (!JSObject::setNewGroupUnknown(cx, &PlainObject::class_, objectProto))
    1602           0 :         return nullptr;
    1603             : 
    1604         312 :     return objectProto;
    1605             : }
    1606             : 
    1607             : static bool
    1608         311 : FinishObjectClassInit(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto)
    1609             : {
    1610         622 :     Rooted<GlobalObject*> global(cx, cx->global());
    1611             : 
    1612             :     /* ES5 15.1.2.1. */
    1613         622 :     RootedId evalId(cx, NameToId(cx->names().eval));
    1614         622 :     JSObject* evalobj = DefineFunction(cx, global, evalId, IndirectEval, 1,
    1615         311 :                                        JSFUN_STUB_GSOPS | JSPROP_RESOLVING);
    1616         311 :     if (!evalobj)
    1617           0 :         return false;
    1618         311 :     global->setOriginalEval(evalobj);
    1619             : 
    1620             : #ifdef FUZZING
    1621             :     if (cx->options().fuzzing()) {
    1622             :         if (!DefineTestingFunctions(cx, global, /* fuzzingSafe = */ true,
    1623             :                                     /* disableOOMFunctions = */ false))
    1624             :         {
    1625             :             return false;
    1626             :         }
    1627             :     }
    1628             : #endif
    1629             : 
    1630         622 :     Rooted<NativeObject*> holder(cx, GlobalObject::getIntrinsicsHolder(cx, global));
    1631         311 :     if (!holder)
    1632           0 :         return false;
    1633             : 
    1634             :     /*
    1635             :      * The global object should have |Object.prototype| as its [[Prototype]].
    1636             :      * Eventually we'd like to have standard classes be there from the start,
    1637             :      * and thus we would know we were always setting what had previously been a
    1638             :      * null [[Prototype]], but right now some code assumes it can set the
    1639             :      * [[Prototype]] before standard classes have been initialized.  For now,
    1640             :      * only set the [[Prototype]] if it hasn't already been set.
    1641             :      */
    1642         622 :     Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
    1643         311 :     if (global->shouldSplicePrototype()) {
    1644         311 :         if (!JSObject::splicePrototype(cx, global, global->getClass(), tagged))
    1645           0 :             return false;
    1646             :     }
    1647         311 :     return true;
    1648             : }
    1649             : 
    1650             : static const ClassSpec PlainObjectClassSpec = {
    1651             :     CreateObjectConstructor,
    1652             :     CreateObjectPrototype,
    1653             :     object_static_methods,
    1654             :     nullptr,
    1655             :     object_methods,
    1656             :     object_properties,
    1657             :     FinishObjectClassInit
    1658             : };
    1659             : 
    1660             : const Class PlainObject::class_ = {
    1661             :     js_Object_str,
    1662             :     JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
    1663             :     JS_NULL_CLASS_OPS,
    1664             :     &PlainObjectClassSpec
    1665             : };
    1666             : 
    1667             : const Class* const js::ObjectClassPtr = &PlainObject::class_;

Generated by: LCOV version 1.13