LCOV - code coverage report
Current view: top level - js/src/jit - VMFunctions.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 299 813 36.8 %
Date: 2017-07-14 16:53:18 Functions: 50 122 41.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             : #include "jit/VMFunctions.h"
       8             : 
       9             : #include "jsgc.h"
      10             : 
      11             : #include "builtin/TypedObject.h"
      12             : #include "frontend/BytecodeCompiler.h"
      13             : #include "jit/arm/Simulator-arm.h"
      14             : #include "jit/BaselineIC.h"
      15             : #include "jit/JitCompartment.h"
      16             : #include "jit/JitFrames.h"
      17             : #include "jit/mips32/Simulator-mips32.h"
      18             : #include "jit/mips64/Simulator-mips64.h"
      19             : #include "vm/ArrayObject.h"
      20             : #include "vm/Debugger.h"
      21             : #include "vm/Interpreter.h"
      22             : #include "vm/TraceLogging.h"
      23             : 
      24             : #include "jit/BaselineFrame-inl.h"
      25             : #include "jit/JitFrames-inl.h"
      26             : #include "vm/Debugger-inl.h"
      27             : #include "vm/Interpreter-inl.h"
      28             : #include "vm/NativeObject-inl.h"
      29             : #include "vm/StringObject-inl.h"
      30             : #include "vm/TypeInference-inl.h"
      31             : #include "vm/UnboxedObject-inl.h"
      32             : 
      33             : using namespace js;
      34             : using namespace js::jit;
      35             : 
      36             : namespace js {
      37             : namespace jit {
      38             : 
      39             : // Statics are initialized to null.
      40             : /* static */ VMFunction* VMFunction::functions;
      41             : 
      42           0 : AutoDetectInvalidation::AutoDetectInvalidation(JSContext* cx, MutableHandleValue rval)
      43             :   : cx_(cx),
      44           0 :     ionScript_(GetTopJitJSScript(cx)->ionScript()),
      45             :     rval_(rval),
      46           0 :     disabled_(false)
      47           0 : { }
      48             : 
      49             : void
      50         777 : VMFunction::addToFunctions()
      51             : {
      52         777 :     this->next = functions;
      53         777 :     functions = this;
      54         777 : }
      55             : 
      56             : bool
      57           2 : InvokeFunction(JSContext* cx, HandleObject obj, bool constructing, bool ignoresReturnValue,
      58             :                uint32_t argc, Value* argv, MutableHandleValue rval)
      59             : {
      60           2 :     TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
      61           2 :     TraceLogStartEvent(logger, TraceLogger_Call);
      62             : 
      63           4 :     AutoArrayRooter argvRoot(cx, argc + 1 + constructing, argv);
      64             : 
      65             :     // Data in the argument vector is arranged for a JIT -> JIT call.
      66           4 :     RootedValue thisv(cx, argv[0]);
      67           2 :     Value* argvWithoutThis = argv + 1;
      68             : 
      69           4 :     RootedValue fval(cx, ObjectValue(*obj));
      70           2 :     if (constructing) {
      71           0 :         if (!IsConstructor(fval)) {
      72           0 :             ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, fval, nullptr);
      73           0 :             return false;
      74             :         }
      75             : 
      76           0 :         ConstructArgs cargs(cx);
      77           0 :         if (!cargs.init(cx, argc))
      78           0 :             return false;
      79             : 
      80           0 :         for (uint32_t i = 0; i < argc; i++)
      81           0 :             cargs[i].set(argvWithoutThis[i]);
      82             : 
      83           0 :         RootedValue newTarget(cx, argvWithoutThis[argc]);
      84             : 
      85             :         // If |this| hasn't been created, or is JS_UNINITIALIZED_LEXICAL,
      86             :         // we can use normal construction code without creating an extraneous
      87             :         // object.
      88           0 :         if (thisv.isMagic()) {
      89           0 :             MOZ_ASSERT(thisv.whyMagic() == JS_IS_CONSTRUCTING ||
      90             :                        thisv.whyMagic() == JS_UNINITIALIZED_LEXICAL);
      91             : 
      92           0 :             RootedObject obj(cx);
      93           0 :             if (!Construct(cx, fval, cargs, newTarget, &obj))
      94           0 :                 return false;
      95             : 
      96           0 :             rval.setObject(*obj);
      97           0 :             return true;
      98             :         }
      99             : 
     100             :         // Otherwise the default |this| has already been created.  We could
     101             :         // almost perform a *call* at this point, but we'd break |new.target|
     102             :         // in the function.  So in this one weird case we call a one-off
     103             :         // construction path that *won't* set |this| to JS_IS_CONSTRUCTING.
     104           0 :         return InternalConstructWithProvidedThis(cx, fval, thisv, cargs, newTarget, rval);
     105             :     }
     106             : 
     107           4 :     InvokeArgsMaybeIgnoresReturnValue args(cx, ignoresReturnValue);
     108           2 :     if (!args.init(cx, argc))
     109           0 :         return false;
     110             : 
     111           5 :     for (size_t i = 0; i < argc; i++)
     112           3 :         args[i].set(argvWithoutThis[i]);
     113             : 
     114           2 :     return Call(cx, fval, thisv, args, rval);
     115             : }
     116             : 
     117             : bool
     118           0 : InvokeFunctionShuffleNewTarget(JSContext* cx, HandleObject obj, uint32_t numActualArgs,
     119             :                                uint32_t numFormalArgs, Value* argv, MutableHandleValue rval)
     120             : {
     121           0 :     MOZ_ASSERT(numFormalArgs > numActualArgs);
     122           0 :     argv[1 + numActualArgs] = argv[1 + numFormalArgs];
     123           0 :     return InvokeFunction(cx, obj, true, false, numActualArgs, argv, rval);
     124             : }
     125             : 
     126             : #ifdef JS_SIMULATOR
     127             : static bool
     128             : CheckSimulatorRecursionLimitWithExtra(JSContext* cx, uint32_t extra)
     129             : {
     130             :     if (cx->simulator()->overRecursedWithExtra(extra)) {
     131             :         ReportOverRecursed(cx);
     132             :         return false;
     133             :     }
     134             :     return true;
     135             : }
     136             : #endif
     137             : 
     138             : bool
     139           0 : CheckOverRecursed(JSContext* cx)
     140             : {
     141             :     // We just failed the jitStackLimit check. There are two possible reasons:
     142             :     //  - jitStackLimit was the real stack limit and we're over-recursed
     143             :     //  - jitStackLimit was set to UINTPTR_MAX by JSRuntime::requestInterrupt
     144             :     //    and we need to call JSRuntime::handleInterrupt.
     145             : #ifdef JS_SIMULATOR
     146             :     if (!CheckSimulatorRecursionLimitWithExtra(cx, 0))
     147             :         return false;
     148             : #else
     149           0 :     if (!CheckRecursionLimit(cx))
     150           0 :         return false;
     151             : #endif
     152           0 :     gc::MaybeVerifyBarriers(cx);
     153           0 :     return cx->handleInterrupt();
     154             : }
     155             : 
     156             : // This function can get called in two contexts.  In the usual context, it's
     157             : // called with earlyCheck=false, after the env chain has been initialized on
     158             : // a baseline frame.  In this case, it's ok to throw an exception, so a failed
     159             : // stack check returns false, and a successful stack check promps a check for
     160             : // an interrupt from the runtime, which may also cause a false return.
     161             : //
     162             : // In the second case, it's called with earlyCheck=true, prior to frame
     163             : // initialization.  An exception cannot be thrown in this instance, so instead
     164             : // an error flag is set on the frame and true returned.
     165             : bool
     166          12 : CheckOverRecursedWithExtra(JSContext* cx, BaselineFrame* frame,
     167             :                            uint32_t extra, uint32_t earlyCheck)
     168             : {
     169          12 :     MOZ_ASSERT_IF(earlyCheck, !frame->overRecursed());
     170             : 
     171             :     // See |CheckOverRecursed| above.  This is a variant of that function which
     172             :     // accepts an argument holding the extra stack space needed for the Baseline
     173             :     // frame that's about to be pushed.
     174             :     uint8_t spDummy;
     175          12 :     uint8_t* checkSp = (&spDummy) - extra;
     176          12 :     if (earlyCheck) {
     177             : #ifdef JS_SIMULATOR
     178             :         (void)checkSp;
     179             :         if (!CheckSimulatorRecursionLimitWithExtra(cx, extra))
     180             :             frame->setOverRecursed();
     181             : #else
     182           0 :         if (!CheckRecursionLimitWithStackPointer(cx, checkSp))
     183           0 :             frame->setOverRecursed();
     184             : #endif
     185           0 :         return true;
     186             :     }
     187             : 
     188             :     // The OVERRECURSED flag may have already been set on the frame by an
     189             :     // early over-recursed check.  If so, throw immediately.
     190          12 :     if (frame->overRecursed())
     191           0 :         return false;
     192             : 
     193             : #ifdef JS_SIMULATOR
     194             :     if (!CheckSimulatorRecursionLimitWithExtra(cx, extra))
     195             :         return false;
     196             : #else
     197          12 :     if (!CheckRecursionLimitWithStackPointer(cx, checkSp))
     198           0 :         return false;
     199             : #endif
     200             : 
     201          12 :     gc::MaybeVerifyBarriers(cx);
     202          12 :     return cx->handleInterrupt();
     203             : }
     204             : 
     205             : JSObject*
     206           0 : BindVar(JSContext* cx, HandleObject envChain)
     207             : {
     208           0 :     JSObject* obj = envChain;
     209           0 :     while (!obj->isQualifiedVarObj())
     210           0 :         obj = obj->enclosingEnvironment();
     211           0 :     MOZ_ASSERT(obj);
     212           0 :     return obj;
     213             : }
     214             : 
     215             : bool
     216           0 : DefVar(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject envChain)
     217             : {
     218             :     // Given the ScopeChain, extract the VarObj.
     219           0 :     RootedObject obj(cx, BindVar(cx, envChain));
     220           0 :     return DefVarOperation(cx, obj, dn, attrs);
     221             : }
     222             : 
     223             : bool
     224           0 : DefLexical(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject envChain)
     225             : {
     226             :     // Find the extensible lexical scope.
     227             :     Rooted<LexicalEnvironmentObject*> lexicalEnv(cx,
     228           0 :         &NearestEnclosingExtensibleLexicalEnvironment(envChain));
     229             : 
     230             :     // Find the variables object.
     231           0 :     RootedObject varObj(cx, BindVar(cx, envChain));
     232           0 :     return DefLexicalOperation(cx, lexicalEnv, varObj, dn, attrs);
     233             : }
     234             : 
     235             : bool
     236           0 : DefGlobalLexical(JSContext* cx, HandlePropertyName dn, unsigned attrs)
     237             : {
     238           0 :     Rooted<LexicalEnvironmentObject*> globalLexical(cx, &cx->global()->lexicalEnvironment());
     239           0 :     return DefLexicalOperation(cx, globalLexical, cx->global(), dn, attrs);
     240             : }
     241             : 
     242             : bool
     243          35 : MutatePrototype(JSContext* cx, HandlePlainObject obj, HandleValue value)
     244             : {
     245          35 :     if (!value.isObjectOrNull())
     246           0 :         return true;
     247             : 
     248          70 :     RootedObject newProto(cx, value.toObjectOrNull());
     249          35 :     return SetPrototype(cx, obj, newProto);
     250             : }
     251             : 
     252             : bool
     253           0 : InitProp(JSContext* cx, HandleObject obj, HandlePropertyName name, HandleValue value,
     254             :          jsbytecode* pc)
     255             : {
     256           0 :     RootedId id(cx, NameToId(name));
     257           0 :     return InitPropertyOperation(cx, JSOp(*pc), obj, id, value);
     258             : }
     259             : 
     260             : template<bool Equal>
     261             : bool
     262         381 : LooselyEqual(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res)
     263             : {
     264         381 :     if (!js::LooselyEqual(cx, lhs, rhs, res))
     265           0 :         return false;
     266             :     if (!Equal)
     267          77 :         *res = !*res;
     268         381 :     return true;
     269             : }
     270             : 
     271             : template bool LooselyEqual<true>(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res);
     272             : template bool LooselyEqual<false>(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res);
     273             : 
     274             : template<bool Equal>
     275             : bool
     276         370 : StrictlyEqual(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res)
     277             : {
     278         370 :     if (!js::StrictlyEqual(cx, lhs, rhs, res))
     279           0 :         return false;
     280             :     if (!Equal)
     281          29 :         *res = !*res;
     282         370 :     return true;
     283             : }
     284             : 
     285             : template bool StrictlyEqual<true>(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res);
     286             : template bool StrictlyEqual<false>(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res);
     287             : 
     288             : bool
     289         151 : LessThan(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res)
     290             : {
     291         151 :     return LessThanOperation(cx, lhs, rhs, res);
     292             : }
     293             : 
     294             : bool
     295           8 : LessThanOrEqual(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res)
     296             : {
     297           8 :     return LessThanOrEqualOperation(cx, lhs, rhs, res);
     298             : }
     299             : 
     300             : bool
     301          30 : GreaterThan(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res)
     302             : {
     303          30 :     return GreaterThanOperation(cx, lhs, rhs, res);
     304             : }
     305             : 
     306             : bool
     307          62 : GreaterThanOrEqual(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res)
     308             : {
     309          62 :     return GreaterThanOrEqualOperation(cx, lhs, rhs, res);
     310             : }
     311             : 
     312             : template<bool Equal>
     313             : bool
     314           0 : StringsEqual(JSContext* cx, HandleString lhs, HandleString rhs, bool* res)
     315             : {
     316           0 :     if (!js::EqualStrings(cx, lhs, rhs, res))
     317           0 :         return false;
     318             :     if (!Equal)
     319           0 :         *res = !*res;
     320           0 :     return true;
     321             : }
     322             : 
     323             : template bool StringsEqual<true>(JSContext* cx, HandleString lhs, HandleString rhs, bool* res);
     324             : template bool StringsEqual<false>(JSContext* cx, HandleString lhs, HandleString rhs, bool* res);
     325             : 
     326          29 : bool StringSplitHelper(JSContext* cx, HandleString str, HandleString sep,
     327             :                        HandleObjectGroup group, uint32_t limit,
     328             :                        MutableHandleValue result)
     329             : {
     330          29 :     JSObject* resultObj = str_split_string(cx, group, str, sep, limit);
     331          29 :     if (!resultObj)
     332           0 :         return false;
     333             : 
     334          29 :     result.setObject(*resultObj);
     335          29 :     return true;
     336             : }
     337             : 
     338             : 
     339             : bool
     340           0 : ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval)
     341             : {
     342           0 :     MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
     343             : 
     344           0 :     AutoDetectInvalidation adi(cx, rval);
     345             : 
     346           0 :     JS::AutoValueArray<2> argv(cx);
     347           0 :     argv[0].setUndefined();
     348           0 :     argv[1].setObject(*obj);
     349           0 :     if (!js::array_pop(cx, 0, argv.begin()))
     350           0 :         return false;
     351             : 
     352             :     // If the result is |undefined|, the array was probably empty and we
     353             :     // have to monitor the return value.
     354           0 :     rval.set(argv[0]);
     355           0 :     if (rval.isUndefined())
     356           0 :         TypeScript::Monitor(cx, rval);
     357           0 :     return true;
     358             : }
     359             : 
     360             : bool
     361           0 : ArrayPushDense(JSContext* cx, HandleObject obj, HandleValue v, uint32_t* length)
     362             : {
     363           0 :     *length = GetAnyBoxedOrUnboxedArrayLength(obj);
     364             :     DenseElementResult result =
     365           0 :         SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, *length, v.address(), 1,
     366           0 :                                                   ShouldUpdateTypes::DontUpdate);
     367           0 :     if (result != DenseElementResult::Incomplete) {
     368           0 :         (*length)++;
     369           0 :         return result == DenseElementResult::Success;
     370             :     }
     371             : 
     372             :     // AutoDetectInvalidation uses GetTopJitJSScript(cx)->ionScript(), but it's
     373             :     // possible the SetOrExtendAnyBoxedOrUnboxedDenseElements call already
     374             :     // invalidated the IonScript. JitFrameIterator::ionScript works when the
     375             :     // script is invalidated so we use that instead.
     376           0 :     JitFrameIterator it(cx);
     377           0 :     MOZ_ASSERT(it.type() == JitFrame_Exit);
     378           0 :     ++it;
     379           0 :     IonScript* ionScript = it.ionScript();
     380             : 
     381           0 :     JS::AutoValueArray<3> argv(cx);
     382           0 :     AutoDetectInvalidation adi(cx, argv[0], ionScript);
     383           0 :     argv[0].setUndefined();
     384           0 :     argv[1].setObject(*obj);
     385           0 :     argv[2].set(v);
     386           0 :     if (!js::array_push(cx, 1, argv.begin()))
     387           0 :         return false;
     388             : 
     389           0 :     if (argv[0].isInt32()) {
     390           0 :         *length = argv[0].toInt32();
     391           0 :         return true;
     392             :     }
     393             : 
     394             :     // array_push changed the length to be larger than INT32_MAX. In this case
     395             :     // OBJECT_FLAG_LENGTH_OVERFLOW was set, TI invalidated the script, and the
     396             :     // AutoDetectInvalidation instance on the stack will replace *length with
     397             :     // the actual return value during bailout.
     398           0 :     MOZ_ASSERT(adi.shouldSetReturnOverride());
     399           0 :     MOZ_ASSERT(argv[0].toDouble() == double(INT32_MAX) + 1);
     400           0 :     *length = 0;
     401           0 :     return true;
     402             : }
     403             : 
     404             : bool
     405           0 : ArrayShiftDense(JSContext* cx, HandleObject obj, MutableHandleValue rval)
     406             : {
     407           0 :     MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
     408             : 
     409           0 :     AutoDetectInvalidation adi(cx, rval);
     410             : 
     411           0 :     JS::AutoValueArray<2> argv(cx);
     412           0 :     argv[0].setUndefined();
     413           0 :     argv[1].setObject(*obj);
     414           0 :     if (!js::array_shift(cx, 0, argv.begin()))
     415           0 :         return false;
     416             : 
     417             :     // If the result is |undefined|, the array was probably empty and we
     418             :     // have to monitor the return value.
     419           0 :     rval.set(argv[0]);
     420           0 :     if (rval.isUndefined())
     421           0 :         TypeScript::Monitor(cx, rval);
     422           0 :     return true;
     423             : }
     424             : 
     425             : JSString*
     426          51 : ArrayJoin(JSContext* cx, HandleObject array, HandleString sep)
     427             : {
     428         102 :     JS::AutoValueArray<3> argv(cx);
     429          51 :     argv[0].setUndefined();
     430          51 :     argv[1].setObject(*array);
     431          51 :     argv[2].setString(sep);
     432          51 :     if (!js::array_join(cx, 1, argv.begin()))
     433           0 :         return nullptr;
     434          51 :     return argv[0].toString();
     435             : }
     436             : 
     437             : bool
     438          53 : SetArrayLength(JSContext* cx, HandleObject obj, HandleValue value, bool strict)
     439             : {
     440          53 :     Handle<ArrayObject*> array = obj.as<ArrayObject>();
     441             : 
     442         106 :     RootedId id(cx, NameToId(cx->names().length));
     443          53 :     ObjectOpResult result;
     444             : 
     445             :     // SetArrayLength is called by IC stubs for SetProp and SetElem on arrays'
     446             :     // "length" property.
     447             :     //
     448             :     // ArraySetLength below coerces |value| before checking for length being
     449             :     // writable, and in the case of illegal values, will throw RangeError even
     450             :     // when "length" is not writable. This is incorrect observable behavior,
     451             :     // as a regular [[Set]] operation will check for "length" being
     452             :     // writable before attempting any assignment.
     453             :     //
     454             :     // So, perform ArraySetLength if and only if "length" is writable.
     455          53 :     if (array->lengthIsWritable()) {
     456          53 :         if (!ArraySetLength(cx, array, id, JSPROP_PERMANENT, value, result))
     457           0 :             return false;
     458             :     } else {
     459           0 :         MOZ_ALWAYS_TRUE(result.fail(JSMSG_READ_ONLY));
     460             :     }
     461             : 
     462          53 :     return result.checkStrictErrorOrWarning(cx, obj, id, strict);
     463             : }
     464             : 
     465             : bool
     466           0 : CharCodeAt(JSContext* cx, HandleString str, int32_t index, uint32_t* code)
     467             : {
     468             :     char16_t c;
     469           0 :     if (!str->getChar(cx, index, &c))
     470           0 :         return false;
     471           0 :     *code = c;
     472           0 :     return true;
     473             : }
     474             : 
     475             : JSFlatString*
     476           0 : StringFromCharCode(JSContext* cx, int32_t code)
     477             : {
     478           0 :     char16_t c = char16_t(code);
     479             : 
     480           0 :     if (StaticStrings::hasUnit(c))
     481           0 :         return cx->staticStrings().getUnit(c);
     482             : 
     483           0 :     return NewStringCopyN<CanGC>(cx, &c, 1);
     484             : }
     485             : 
     486             : JSString*
     487           0 : StringFromCodePoint(JSContext* cx, int32_t codePoint)
     488             : {
     489           0 :     RootedValue rval(cx, Int32Value(codePoint));
     490           0 :     if (!str_fromCodePoint_one_arg(cx, rval, &rval))
     491           0 :         return nullptr;
     492             : 
     493           0 :     return rval.toString();
     494             : }
     495             : 
     496             : bool
     497           0 : SetProperty(JSContext* cx, HandleObject obj, HandlePropertyName name, HandleValue value,
     498             :             bool strict, jsbytecode* pc)
     499             : {
     500           0 :     RootedId id(cx, NameToId(name));
     501             : 
     502           0 :     JSOp op = JSOp(*pc);
     503             : 
     504           0 :     if (op == JSOP_SETALIASEDVAR || op == JSOP_INITALIASEDLEXICAL) {
     505             :         // Aliased var assigns ignore readonly attributes on the property, as
     506             :         // required for initializing 'const' closure variables.
     507           0 :         Shape* shape = obj->as<NativeObject>().lookup(cx, name);
     508           0 :         MOZ_ASSERT(shape && shape->hasSlot());
     509           0 :         obj->as<NativeObject>().setSlotWithType(cx, shape, value);
     510           0 :         return true;
     511             :     }
     512             : 
     513           0 :     RootedValue receiver(cx, ObjectValue(*obj));
     514           0 :     ObjectOpResult result;
     515           0 :     if (MOZ_LIKELY(!obj->getOpsSetProperty())) {
     516           0 :         if (!NativeSetProperty(
     517             :                 cx, obj.as<NativeObject>(), id, value, receiver,
     518           0 :                 (op == JSOP_SETNAME || op == JSOP_STRICTSETNAME ||
     519           0 :                  op == JSOP_SETGNAME || op == JSOP_STRICTSETGNAME)
     520             :                 ? Unqualified
     521             :                 : Qualified,
     522             :                 result))
     523             :         {
     524           0 :             return false;
     525             :         }
     526             :     } else {
     527           0 :         if (!SetProperty(cx, obj, id, value, receiver, result))
     528           0 :             return false;
     529             :     }
     530           0 :     return result.checkStrictErrorOrWarning(cx, obj, id, strict);
     531             : }
     532             : 
     533             : bool
     534           4 : InterruptCheck(JSContext* cx)
     535             : {
     536           4 :     gc::MaybeVerifyBarriers(cx);
     537             : 
     538             :     {
     539           4 :         JSRuntime* rt = cx->runtime();
     540           8 :         JitRuntime::AutoPreventBackedgePatching apbp(rt);
     541           4 :         cx->zone()->group()->jitZoneGroup->patchIonBackedges(cx, JitZoneGroup::BackedgeLoopHeader);
     542             :     }
     543             : 
     544           4 :     return CheckForInterrupt(cx);
     545             : }
     546             : 
     547             : void*
     548           0 : MallocWrapper(JSRuntime* rt, size_t nbytes)
     549             : {
     550           0 :     return rt->pod_malloc<uint8_t>(nbytes);
     551             : }
     552             : 
     553             : JSObject*
     554           0 : NewCallObject(JSContext* cx, HandleShape shape, HandleObjectGroup group)
     555             : {
     556           0 :     JSObject* obj = CallObject::create(cx, shape, group);
     557           0 :     if (!obj)
     558           0 :         return nullptr;
     559             : 
     560             :     // The JIT creates call objects in the nursery, so elides barriers for
     561             :     // the initializing writes. The interpreter, however, may have allocated
     562             :     // the call object tenured, so barrier as needed before re-entering.
     563           0 :     if (!IsInsideNursery(obj))
     564           0 :         cx->zone()->group()->storeBuffer().putWholeCell(obj);
     565             : 
     566           0 :     return obj;
     567             : }
     568             : 
     569             : JSObject*
     570           0 : NewSingletonCallObject(JSContext* cx, HandleShape shape)
     571             : {
     572           0 :     JSObject* obj = CallObject::createSingleton(cx, shape);
     573           0 :     if (!obj)
     574           0 :         return nullptr;
     575             : 
     576             :     // The JIT creates call objects in the nursery, so elides barriers for
     577             :     // the initializing writes. The interpreter, however, may have allocated
     578             :     // the call object tenured, so barrier as needed before re-entering.
     579           0 :     MOZ_ASSERT(!IsInsideNursery(obj),
     580             :                "singletons are created in the tenured heap");
     581           0 :     cx->zone()->group()->storeBuffer().putWholeCell(obj);
     582             : 
     583           0 :     return obj;
     584             : }
     585             : 
     586             : JSObject*
     587           0 : NewStringObject(JSContext* cx, HandleString str)
     588             : {
     589           0 :     return StringObject::create(cx, str);
     590             : }
     591             : 
     592             : bool
     593         616 : OperatorIn(JSContext* cx, HandleValue key, HandleObject obj, bool* out)
     594             : {
     595        1232 :     RootedId id(cx);
     596        3080 :     return ToPropertyKey(cx, key, &id) &&
     597        2464 :            HasProperty(cx, obj, id, out);
     598             : }
     599             : 
     600             : bool
     601           0 : OperatorInI(JSContext* cx, uint32_t index, HandleObject obj, bool* out)
     602             : {
     603           0 :     RootedValue key(cx, Int32Value(index));
     604           0 :     return OperatorIn(cx, key, obj, out);
     605             : }
     606             : 
     607             : bool
     608           0 : GetIntrinsicValue(JSContext* cx, HandlePropertyName name, MutableHandleValue rval)
     609             : {
     610           0 :     if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, rval))
     611           0 :         return false;
     612             : 
     613             :     // This function is called when we try to compile a cold getintrinsic
     614             :     // op. MCallGetIntrinsicValue has an AliasSet of None for optimization
     615             :     // purposes, as its side effect is not observable from JS. We are
     616             :     // guaranteed to bail out after this function, but because of its AliasSet,
     617             :     // type info will not be reflowed. Manually monitor here.
     618           0 :     TypeScript::Monitor(cx, rval);
     619             : 
     620           0 :     return true;
     621             : }
     622             : 
     623             : bool
     624          24 : CreateThis(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHandleValue rval)
     625             : {
     626          24 :     rval.set(MagicValue(JS_IS_CONSTRUCTING));
     627             : 
     628          24 :     if (callee->is<JSFunction>()) {
     629          48 :         RootedFunction fun(cx, &callee->as<JSFunction>());
     630          24 :         if (fun->isInterpreted() && fun->isConstructor()) {
     631          24 :             JSScript* script = JSFunction::getOrCreateScript(cx, fun);
     632          24 :             if (!script || !script->ensureHasTypes(cx))
     633           0 :                 return false;
     634          24 :             if (fun->isBoundFunction() || script->isDerivedClassConstructor()) {
     635           0 :                 rval.set(MagicValue(JS_UNINITIALIZED_LEXICAL));
     636             :             } else {
     637          24 :                 JSObject* thisObj = CreateThisForFunction(cx, callee, newTarget, GenericObject);
     638          24 :                 if (!thisObj)
     639           0 :                     return false;
     640          24 :                 rval.set(ObjectValue(*thisObj));
     641             :             }
     642             :         }
     643             :     }
     644             : 
     645          24 :     return true;
     646             : }
     647             : 
     648             : void
     649           0 : GetDynamicName(JSContext* cx, JSObject* envChain, JSString* str, Value* vp)
     650             : {
     651             :     // Lookup a string on the env chain, returning either the value found or
     652             :     // undefined through rval. This function is infallible, and cannot GC or
     653             :     // invalidate.
     654             : 
     655             :     JSAtom* atom;
     656           0 :     if (str->isAtom()) {
     657           0 :         atom = &str->asAtom();
     658             :     } else {
     659           0 :         atom = AtomizeString(cx, str);
     660           0 :         if (!atom) {
     661           0 :             vp->setUndefined();
     662           0 :             return;
     663             :         }
     664             :     }
     665             : 
     666           0 :     if (!frontend::IsIdentifier(atom) || frontend::IsKeyword(atom)) {
     667           0 :         vp->setUndefined();
     668           0 :         return;
     669             :     }
     670             : 
     671           0 :     PropertyResult prop;
     672           0 :     JSObject* scope = nullptr;
     673           0 :     JSObject* pobj = nullptr;
     674           0 :     if (LookupNameNoGC(cx, atom->asPropertyName(), envChain, &scope, &pobj, &prop)) {
     675           0 :         if (FetchNameNoGC(pobj, prop, MutableHandleValue::fromMarkedLocation(vp)))
     676           0 :             return;
     677             :     }
     678             : 
     679           0 :     vp->setUndefined();
     680             : }
     681             : 
     682             : void
     683         264 : PostWriteBarrier(JSRuntime* rt, JSObject* obj)
     684             : {
     685         528 :     JS::AutoCheckCannotGC nogc;
     686         264 :     MOZ_ASSERT(!IsInsideNursery(obj));
     687         264 :     rt->gc.storeBuffer().putWholeCell(obj);
     688         264 : }
     689             : 
     690             : static const size_t MAX_WHOLE_CELL_BUFFER_SIZE = 4096;
     691             : 
     692             : template <IndexInBounds InBounds>
     693             : void
     694           0 : PostWriteElementBarrier(JSRuntime* rt, JSObject* obj, int32_t index)
     695             : {
     696           0 :     JS::AutoCheckCannotGC nogc;
     697             : 
     698           0 :     MOZ_ASSERT(!IsInsideNursery(obj));
     699             : 
     700             :     if (InBounds == IndexInBounds::Yes) {
     701           0 :         MOZ_ASSERT(uint32_t(index) < obj->as<NativeObject>().getDenseInitializedLength());
     702             :     } else {
     703           0 :         if (MOZ_UNLIKELY(!obj->is<NativeObject>()) ||
     704           0 :             uint32_t(index) >= obj->as<NativeObject>().getDenseInitializedLength())
     705             :         {
     706           0 :             rt->gc.storeBuffer().putWholeCell(obj);
     707           0 :             return;
     708             :         }
     709             :     }
     710             : 
     711           0 :     NativeObject* nobj = &obj->as<NativeObject>();
     712           0 :     if (nobj->isInWholeCellBuffer())
     713           0 :         return;
     714             : 
     715           0 :     if (nobj->getDenseInitializedLength() > MAX_WHOLE_CELL_BUFFER_SIZE
     716             : #ifdef JS_GC_ZEAL
     717           0 :          || rt->hasZealMode(gc::ZealMode::ElementsBarrier)
     718             : #endif
     719             :         )
     720             :     {
     721           0 :         rt->gc.storeBuffer().putSlot(nobj, HeapSlot::Element,
     722           0 :                                      nobj->unshiftedIndex(index),
     723             :                                      1);
     724           0 :         return;
     725             :     }
     726             : 
     727           0 :     rt->gc.storeBuffer().putWholeCell(obj);
     728             : }
     729             : 
     730             : template void
     731             : PostWriteElementBarrier<IndexInBounds::Yes>(JSRuntime* rt, JSObject* obj, int32_t index);
     732             : 
     733             : template void
     734             : PostWriteElementBarrier<IndexInBounds::Maybe>(JSRuntime* rt, JSObject* obj, int32_t index);
     735             : 
     736             : void
     737           0 : PostGlobalWriteBarrier(JSRuntime* rt, JSObject* obj)
     738             : {
     739           0 :     MOZ_ASSERT(obj->is<GlobalObject>());
     740           0 :     if (!obj->compartment()->globalWriteBarriered) {
     741           0 :         PostWriteBarrier(rt, obj);
     742           0 :         obj->compartment()->globalWriteBarriered = 1;
     743             :     }
     744           0 : }
     745             : 
     746             : int32_t
     747           2 : GetIndexFromString(JSString* str)
     748             : {
     749             :     // We shouldn't GC here as this is called directly from IC code.
     750           4 :     JS::AutoCheckCannotGC nogc;
     751             : 
     752           2 :     if (!str->isFlat())
     753           0 :         return -1;
     754             : 
     755             :     uint32_t index;
     756           2 :     if (!str->asFlat().isIndex(&index) || index > INT32_MAX)
     757           0 :         return -1;
     758             : 
     759           2 :     return int32_t(index);
     760             : }
     761             : 
     762             : JSObject*
     763         543 : WrapObjectPure(JSContext* cx, JSObject* obj)
     764             : {
     765             :     // IC code calls this directly so we shouldn't GC.
     766        1086 :     JS::AutoCheckCannotGC nogc;
     767             : 
     768         543 :     MOZ_ASSERT(obj);
     769         543 :     MOZ_ASSERT(cx->compartment() != obj->compartment());
     770             : 
     771             :     // From: JSCompartment::getNonWrapperObjectForCurrentCompartment
     772             :     // Note that if the object is same-compartment, but has been wrapped into a
     773             :     // different compartment, we need to unwrap it and return the bare same-
     774             :     // compartment object. Note again that windows are always wrapped by a
     775             :     // WindowProxy even when same-compartment so take care not to strip this
     776             :     // particular wrapper.
     777         543 :     obj = UncheckedUnwrap(obj, /* stopAtWindowProxy = */ true);
     778         543 :     if (cx->compartment() == obj->compartment()) {
     779           0 :         MOZ_ASSERT(!IsWindow(obj));
     780           0 :         JS::ExposeObjectToActiveJS(obj);
     781           0 :         return obj;
     782             :     }
     783             : 
     784             :     // Try to Lookup an existing wrapper for this object. We assume that
     785             :     // if we can find such a wrapper, not calling preWrap is correct.
     786         543 :     if (WrapperMap::Ptr p = cx->compartment()->lookupWrapper(obj)) {
     787         399 :         JSObject* wrapped = &p->value().get().toObject();
     788             : 
     789             :         // Ensure the wrapper is still exposed.
     790         399 :         JS::ExposeObjectToActiveJS(wrapped);
     791         399 :         return wrapped;
     792             :     }
     793             : 
     794         144 :     return nullptr;
     795             : }
     796             : 
     797             : bool
     798           0 : DebugPrologue(JSContext* cx, BaselineFrame* frame, jsbytecode* pc, bool* mustReturn)
     799             : {
     800           0 :     *mustReturn = false;
     801             : 
     802           0 :     switch (Debugger::onEnterFrame(cx, frame)) {
     803             :       case JSTRAP_CONTINUE:
     804           0 :         return true;
     805             : 
     806             :       case JSTRAP_RETURN:
     807             :         // The script is going to return immediately, so we have to call the
     808             :         // debug epilogue handler as well.
     809           0 :         MOZ_ASSERT(frame->hasReturnValue());
     810           0 :         *mustReturn = true;
     811           0 :         return jit::DebugEpilogue(cx, frame, pc, true);
     812             : 
     813             :       case JSTRAP_THROW:
     814             :       case JSTRAP_ERROR:
     815           0 :         return false;
     816             : 
     817             :       default:
     818           0 :         MOZ_CRASH("bad Debugger::onEnterFrame status");
     819             :     }
     820             : }
     821             : 
     822             : bool
     823           0 : DebugEpilogueOnBaselineReturn(JSContext* cx, BaselineFrame* frame, jsbytecode* pc)
     824             : {
     825           0 :     if (!DebugEpilogue(cx, frame, pc, true)) {
     826             :         // DebugEpilogue popped the frame by updating exitFP, so run the stop
     827             :         // event here before we enter the exception handler.
     828           0 :         TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
     829           0 :         TraceLogStopEvent(logger, TraceLogger_Baseline);
     830           0 :         TraceLogStopEvent(logger, TraceLogger_Scripts);
     831           0 :         return false;
     832             :     }
     833             : 
     834           0 :     return true;
     835             : }
     836             : 
     837             : bool
     838          78 : DebugEpilogue(JSContext* cx, BaselineFrame* frame, jsbytecode* pc, bool ok)
     839             : {
     840             :     // If Debugger::onLeaveFrame returns |true| we have to return the frame's
     841             :     // return value. If it returns |false|, the debugger threw an exception.
     842             :     // In both cases we have to pop debug scopes.
     843          78 :     ok = Debugger::onLeaveFrame(cx, frame, pc, ok);
     844             : 
     845             :     // Unwind to the outermost environment and set pc to the end of the
     846             :     // script, regardless of error.
     847         156 :     EnvironmentIter ei(cx, frame, pc);
     848          78 :     UnwindAllEnvironmentsInFrame(cx, ei);
     849          78 :     JSScript* script = frame->script();
     850          78 :     frame->setOverridePc(script->lastPC());
     851             : 
     852          78 :     if (!ok) {
     853             :         // Pop this frame by updating exitFP, so that the exception handling
     854             :         // code will start at the previous frame.
     855          78 :         JitFrameLayout* prefix = frame->framePrefix();
     856          78 :         EnsureBareExitFrame(cx, prefix);
     857          78 :         return false;
     858             :     }
     859             : 
     860             :     // Clear the override pc. This is not necessary for correctness: the frame
     861             :     // will return immediately, but this simplifies the check we emit in debug
     862             :     // builds after each callVM, to ensure this flag is not set.
     863           0 :     frame->clearOverridePc();
     864           0 :     return true;
     865             : }
     866             : 
     867             : void
     868           0 : FrameIsDebuggeeCheck(BaselineFrame* frame)
     869             : {
     870           0 :     if (frame->script()->isDebuggee())
     871           0 :         frame->setIsDebuggee();
     872           0 : }
     873             : 
     874             : JSObject*
     875          64 : CreateGenerator(JSContext* cx, BaselineFrame* frame)
     876             : {
     877          64 :     return GeneratorObject::create(cx, frame);
     878             : }
     879             : 
     880             : bool
     881         438 : NormalSuspend(JSContext* cx, HandleObject obj, BaselineFrame* frame, jsbytecode* pc,
     882             :               uint32_t stackDepth)
     883             : {
     884         438 :     MOZ_ASSERT(*pc == JSOP_YIELD || *pc == JSOP_AWAIT);
     885             : 
     886             :     // Return value is still on the stack.
     887         438 :     MOZ_ASSERT(stackDepth >= 1);
     888             : 
     889             :     // The expression stack slots are stored on the stack in reverse order, so
     890             :     // we copy them to a Vector and pass a pointer to that instead. We use
     891             :     // stackDepth - 1 because we don't want to include the return value.
     892         876 :     AutoValueVector exprStack(cx);
     893         438 :     if (!exprStack.reserve(stackDepth - 1))
     894           0 :         return false;
     895             : 
     896         438 :     size_t firstSlot = frame->numValueSlots() - stackDepth;
     897        1802 :     for (size_t i = 0; i < stackDepth - 1; i++)
     898        1364 :         exprStack.infallibleAppend(*frame->valueSlot(firstSlot + i));
     899             : 
     900         438 :     MOZ_ASSERT(exprStack.length() == stackDepth - 1);
     901             : 
     902         438 :     return GeneratorObject::normalSuspend(cx, obj, frame, pc, exprStack.begin(), stackDepth - 1);
     903             : }
     904             : 
     905             : bool
     906          70 : FinalSuspend(JSContext* cx, HandleObject obj, BaselineFrame* frame, jsbytecode* pc)
     907             : {
     908          70 :     MOZ_ASSERT(*pc == JSOP_FINALYIELDRVAL);
     909             : 
     910          70 :     if (!GeneratorObject::finalSuspend(cx, obj)) {
     911             : 
     912           0 :         TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
     913           0 :         TraceLogStopEvent(logger, TraceLogger_Engine);
     914           0 :         TraceLogStopEvent(logger, TraceLogger_Scripts);
     915             : 
     916             :         // Leave this frame and propagate the exception to the caller.
     917           0 :         return DebugEpilogue(cx, frame, pc, /* ok = */ false);
     918             :     }
     919             : 
     920          70 :     return true;
     921             : }
     922             : 
     923             : bool
     924          76 : InterpretResume(JSContext* cx, HandleObject obj, HandleValue val, HandlePropertyName kind,
     925             :                 MutableHandleValue rval)
     926             : {
     927          76 :     MOZ_ASSERT(obj->is<GeneratorObject>());
     928             : 
     929         152 :     RootedValue selfHostedFun(cx);
     930          76 :     if (!GlobalObject::getIntrinsicValue(cx, cx->global(), cx->names().InterpretGeneratorResume,
     931             :                                          &selfHostedFun))
     932             :     {
     933           0 :         return false;
     934             :     }
     935             : 
     936          76 :     MOZ_ASSERT(selfHostedFun.toObject().is<JSFunction>());
     937             : 
     938         152 :     FixedInvokeArgs<3> args(cx);
     939             : 
     940          76 :     args[0].setObject(*obj);
     941          76 :     args[1].set(val);
     942          76 :     args[2].setString(kind);
     943             : 
     944          76 :     return Call(cx, selfHostedFun, UndefinedHandleValue, args, rval);
     945             : }
     946             : 
     947             : bool
     948           0 : DebugAfterYield(JSContext* cx, BaselineFrame* frame)
     949             : {
     950             :     // The BaselineFrame has just been constructed by JSOP_RESUME in the
     951             :     // caller. We need to set its debuggee flag as necessary.
     952           0 :     if (frame->script()->isDebuggee())
     953           0 :         frame->setIsDebuggee();
     954           0 :     return true;
     955             : }
     956             : 
     957             : bool
     958           0 : GeneratorThrowOrClose(JSContext* cx, BaselineFrame* frame, Handle<GeneratorObject*> genObj,
     959             :                       HandleValue arg, uint32_t resumeKind)
     960             : {
     961             :     // Set the frame's pc to the current resume pc, so that frame iterators
     962             :     // work. This function always returns false, so we're guaranteed to enter
     963             :     // the exception handler where we will clear the pc.
     964           0 :     JSScript* script = frame->script();
     965           0 :     uint32_t offset = script->yieldAndAwaitOffsets()[genObj->yieldAndAwaitIndex()];
     966           0 :     frame->setOverridePc(script->offsetToPC(offset));
     967             : 
     968           0 :     MOZ_ALWAYS_TRUE(DebugAfterYield(cx, frame));
     969           0 :     MOZ_ALWAYS_FALSE(js::GeneratorThrowOrClose(cx, frame, genObj, arg, resumeKind));
     970           0 :     return false;
     971             : }
     972             : 
     973             : bool
     974           0 : CheckGlobalOrEvalDeclarationConflicts(JSContext* cx, BaselineFrame* frame)
     975             : {
     976           0 :     RootedScript script(cx, frame->script());
     977           0 :     RootedObject envChain(cx, frame->environmentChain());
     978           0 :     RootedObject varObj(cx, BindVar(cx, envChain));
     979             : 
     980           0 :     if (script->isForEval()) {
     981             :         // Strict eval and eval in parameter default expressions have their
     982             :         // own call objects.
     983             :         //
     984             :         // Non-strict eval may introduce 'var' bindings that conflict with
     985             :         // lexical bindings in an enclosing lexical scope.
     986           0 :         if (!script->bodyScope()->hasEnvironment()) {
     987           0 :             MOZ_ASSERT(!script->strict() &&
     988             :                        (!script->enclosingScope()->is<FunctionScope>() ||
     989             :                         !script->enclosingScope()->as<FunctionScope>().hasParameterExprs()));
     990           0 :             if (!CheckEvalDeclarationConflicts(cx, script, envChain, varObj))
     991           0 :                 return false;
     992             :         }
     993             :     } else {
     994             :         Rooted<LexicalEnvironmentObject*> lexicalEnv(cx,
     995           0 :             &NearestEnclosingExtensibleLexicalEnvironment(envChain));
     996           0 :         if (!CheckGlobalDeclarationConflicts(cx, script, lexicalEnv, varObj))
     997           0 :             return false;
     998             :     }
     999             : 
    1000           0 :     return true;
    1001             : }
    1002             : 
    1003             : bool
    1004           0 : GlobalNameConflictsCheckFromIon(JSContext* cx, HandleScript script)
    1005             : {
    1006           0 :     Rooted<LexicalEnvironmentObject*> globalLexical(cx, &cx->global()->lexicalEnvironment());
    1007           0 :     return CheckGlobalDeclarationConflicts(cx, script, globalLexical, cx->global());
    1008             : }
    1009             : 
    1010             : bool
    1011        3124 : InitFunctionEnvironmentObjects(JSContext* cx, BaselineFrame* frame)
    1012             : {
    1013        3124 :     return frame->initFunctionEnvironmentObjects(cx);
    1014             : }
    1015             : 
    1016             : bool
    1017          50 : NewArgumentsObject(JSContext* cx, BaselineFrame* frame, MutableHandleValue res)
    1018             : {
    1019          50 :     ArgumentsObject* obj = ArgumentsObject::createExpected(cx, frame);
    1020          50 :     if (!obj)
    1021           0 :         return false;
    1022          50 :     res.setObject(*obj);
    1023          50 :     return true;
    1024             : }
    1025             : 
    1026             : JSObject*
    1027           0 : CopyLexicalEnvironmentObject(JSContext* cx, HandleObject env, bool copySlots)
    1028             : {
    1029           0 :     Handle<LexicalEnvironmentObject*> lexicalEnv = env.as<LexicalEnvironmentObject>();
    1030             : 
    1031           0 :     if (copySlots)
    1032           0 :         return LexicalEnvironmentObject::clone(cx, lexicalEnv);
    1033             : 
    1034           0 :     return LexicalEnvironmentObject::recreate(cx, lexicalEnv);
    1035             : }
    1036             : 
    1037             : JSObject*
    1038          51 : InitRestParameter(JSContext* cx, uint32_t length, Value* rest, HandleObject templateObj,
    1039             :                   HandleObject objRes)
    1040             : {
    1041          51 :     if (objRes) {
    1042         102 :         Rooted<ArrayObject*> arrRes(cx, &objRes->as<ArrayObject>());
    1043             : 
    1044          51 :         MOZ_ASSERT(!arrRes->getDenseInitializedLength());
    1045          51 :         MOZ_ASSERT(arrRes->group() == templateObj->group());
    1046             : 
    1047             :         // Fast path: we managed to allocate the array inline; initialize the
    1048             :         // slots.
    1049          51 :         if (length > 0) {
    1050          51 :             if (!arrRes->ensureElements(cx, length))
    1051           0 :                 return nullptr;
    1052          51 :             arrRes->setDenseInitializedLength(length);
    1053          51 :             arrRes->initDenseElements(0, rest, length);
    1054          51 :             arrRes->setLengthInt32(length);
    1055             :         }
    1056          51 :         return arrRes;
    1057             :     }
    1058             : 
    1059           0 :     NewObjectKind newKind = templateObj->group()->shouldPreTenure()
    1060           0 :                             ? TenuredObject
    1061           0 :                             : GenericObject;
    1062           0 :     ArrayObject* arrRes = NewDenseCopiedArray(cx, length, rest, nullptr, newKind);
    1063           0 :     if (arrRes)
    1064           0 :         arrRes->setGroup(templateObj->group());
    1065           0 :     return arrRes;
    1066             : }
    1067             : 
    1068             : bool
    1069           0 : HandleDebugTrap(JSContext* cx, BaselineFrame* frame, uint8_t* retAddr, bool* mustReturn)
    1070             : {
    1071           0 :     *mustReturn = false;
    1072             : 
    1073           0 :     RootedScript script(cx, frame->script());
    1074           0 :     jsbytecode* pc = script->baselineScript()->icEntryFromReturnAddress(retAddr).pc(script);
    1075             : 
    1076           0 :     if (*pc == JSOP_DEBUGAFTERYIELD) {
    1077             :         // JSOP_DEBUGAFTERYIELD will set the frame's debuggee flag, but if we
    1078             :         // set a breakpoint there we have to do it now.
    1079           0 :         MOZ_ASSERT(!frame->isDebuggee());
    1080           0 :         if (!DebugAfterYield(cx, frame))
    1081           0 :             return false;
    1082             :     }
    1083             : 
    1084           0 :     MOZ_ASSERT(frame->isDebuggee());
    1085           0 :     MOZ_ASSERT(script->stepModeEnabled() || script->hasBreakpointsAt(pc));
    1086             : 
    1087           0 :     RootedValue rval(cx);
    1088           0 :     JSTrapStatus status = JSTRAP_CONTINUE;
    1089             : 
    1090           0 :     if (script->stepModeEnabled())
    1091           0 :         status = Debugger::onSingleStep(cx, &rval);
    1092             : 
    1093           0 :     if (status == JSTRAP_CONTINUE && script->hasBreakpointsAt(pc))
    1094           0 :         status = Debugger::onTrap(cx, &rval);
    1095             : 
    1096           0 :     switch (status) {
    1097             :       case JSTRAP_CONTINUE:
    1098           0 :         break;
    1099             : 
    1100             :       case JSTRAP_ERROR:
    1101           0 :         return false;
    1102             : 
    1103             :       case JSTRAP_RETURN:
    1104           0 :         *mustReturn = true;
    1105           0 :         frame->setReturnValue(rval);
    1106           0 :         return jit::DebugEpilogue(cx, frame, pc, true);
    1107             : 
    1108             :       case JSTRAP_THROW:
    1109           0 :         cx->setPendingException(rval);
    1110           0 :         return false;
    1111             : 
    1112             :       default:
    1113           0 :         MOZ_CRASH("Invalid trap status");
    1114             :     }
    1115             : 
    1116           0 :     return true;
    1117             : }
    1118             : 
    1119             : bool
    1120           0 : OnDebuggerStatement(JSContext* cx, BaselineFrame* frame, jsbytecode* pc, bool* mustReturn)
    1121             : {
    1122           0 :     *mustReturn = false;
    1123             : 
    1124           0 :     switch (Debugger::onDebuggerStatement(cx, frame)) {
    1125             :       case JSTRAP_ERROR:
    1126           0 :         return false;
    1127             : 
    1128             :       case JSTRAP_CONTINUE:
    1129           0 :         return true;
    1130             : 
    1131             :       case JSTRAP_RETURN:
    1132           0 :         *mustReturn = true;
    1133           0 :         return jit::DebugEpilogue(cx, frame, pc, true);
    1134             : 
    1135             :       case JSTRAP_THROW:
    1136           0 :         return false;
    1137             : 
    1138             :       default:
    1139           0 :         MOZ_CRASH("Invalid trap status");
    1140             :     }
    1141             : }
    1142             : 
    1143             : bool
    1144           0 : GlobalHasLiveOnDebuggerStatement(JSContext* cx)
    1145             : {
    1146           0 :     return cx->compartment()->isDebuggee() &&
    1147           0 :            Debugger::hasLiveHook(cx->global(), Debugger::OnDebuggerStatement);
    1148             : }
    1149             : 
    1150             : bool
    1151         993 : PushLexicalEnv(JSContext* cx, BaselineFrame* frame, Handle<LexicalScope*> scope)
    1152             : {
    1153         993 :     return frame->pushLexicalEnvironment(cx, scope);
    1154             : }
    1155             : 
    1156             : bool
    1157        1015 : PopLexicalEnv(JSContext* cx, BaselineFrame* frame)
    1158             : {
    1159        1015 :     frame->popOffEnvironmentChain<LexicalEnvironmentObject>();
    1160        1015 :     return true;
    1161             : }
    1162             : 
    1163             : bool
    1164           0 : DebugLeaveThenPopLexicalEnv(JSContext* cx, BaselineFrame* frame, jsbytecode* pc)
    1165             : {
    1166           0 :     MOZ_ALWAYS_TRUE(DebugLeaveLexicalEnv(cx, frame, pc));
    1167           0 :     frame->popOffEnvironmentChain<LexicalEnvironmentObject>();
    1168           0 :     return true;
    1169             : }
    1170             : 
    1171             : bool
    1172           0 : FreshenLexicalEnv(JSContext* cx, BaselineFrame* frame)
    1173             : {
    1174           0 :     return frame->freshenLexicalEnvironment(cx);
    1175             : }
    1176             : 
    1177             : bool
    1178           0 : DebugLeaveThenFreshenLexicalEnv(JSContext* cx, BaselineFrame* frame, jsbytecode* pc)
    1179             : {
    1180           0 :     MOZ_ALWAYS_TRUE(DebugLeaveLexicalEnv(cx, frame, pc));
    1181           0 :     return frame->freshenLexicalEnvironment(cx);
    1182             : }
    1183             : 
    1184             : bool
    1185         546 : RecreateLexicalEnv(JSContext* cx, BaselineFrame* frame)
    1186             : {
    1187         546 :     return frame->recreateLexicalEnvironment(cx);
    1188             : }
    1189             : 
    1190             : bool
    1191           0 : DebugLeaveThenRecreateLexicalEnv(JSContext* cx, BaselineFrame* frame, jsbytecode* pc)
    1192             : {
    1193           0 :     MOZ_ALWAYS_TRUE(DebugLeaveLexicalEnv(cx, frame, pc));
    1194           0 :     return frame->recreateLexicalEnvironment(cx);
    1195             : }
    1196             : 
    1197             : bool
    1198           0 : DebugLeaveLexicalEnv(JSContext* cx, BaselineFrame* frame, jsbytecode* pc)
    1199             : {
    1200           0 :     MOZ_ASSERT(frame->script()->baselineScript()->hasDebugInstrumentation());
    1201           0 :     if (cx->compartment()->isDebuggee())
    1202           0 :         DebugEnvironments::onPopLexical(cx, frame, pc);
    1203           0 :     return true;
    1204             : }
    1205             : 
    1206             : bool
    1207           9 : PushVarEnv(JSContext* cx, BaselineFrame* frame, HandleScope scope)
    1208             : {
    1209           9 :     return frame->pushVarEnvironment(cx, scope);
    1210             : }
    1211             : 
    1212             : bool
    1213           0 : PopVarEnv(JSContext* cx, BaselineFrame* frame)
    1214             : {
    1215           0 :     frame->popOffEnvironmentChain<VarEnvironmentObject>();
    1216           0 :     return true;
    1217             : }
    1218             : 
    1219             : bool
    1220           0 : EnterWith(JSContext* cx, BaselineFrame* frame, HandleValue val, Handle<WithScope*> templ)
    1221             : {
    1222           0 :     return EnterWithOperation(cx, frame, val, templ);
    1223             : }
    1224             : 
    1225             : bool
    1226           0 : LeaveWith(JSContext* cx, BaselineFrame* frame)
    1227             : {
    1228           0 :     if (MOZ_UNLIKELY(frame->isDebuggee()))
    1229           0 :         DebugEnvironments::onPopWith(frame);
    1230           0 :     frame->popOffEnvironmentChain<WithEnvironmentObject>();
    1231           0 :     return true;
    1232             : }
    1233             : 
    1234             : bool
    1235         141 : InitBaselineFrameForOsr(BaselineFrame* frame, InterpreterFrame* interpFrame,
    1236             :                         uint32_t numStackValues)
    1237             : {
    1238         141 :     return frame->initForOsr(interpFrame, numStackValues);
    1239             : }
    1240             : 
    1241             : JSObject*
    1242           0 : CreateDerivedTypedObj(JSContext* cx, HandleObject descr,
    1243             :                       HandleObject owner, int32_t offset)
    1244             : {
    1245           0 :     MOZ_ASSERT(descr->is<TypeDescr>());
    1246           0 :     MOZ_ASSERT(owner->is<TypedObject>());
    1247           0 :     Rooted<TypeDescr*> descr1(cx, &descr->as<TypeDescr>());
    1248           0 :     Rooted<TypedObject*> owner1(cx, &owner->as<TypedObject>());
    1249           0 :     return OutlineTypedObject::createDerived(cx, descr1, owner1, offset);
    1250             : }
    1251             : 
    1252             : JSString*
    1253           0 : StringReplace(JSContext* cx, HandleString string, HandleString pattern, HandleString repl)
    1254             : {
    1255           0 :     MOZ_ASSERT(string);
    1256           0 :     MOZ_ASSERT(pattern);
    1257           0 :     MOZ_ASSERT(repl);
    1258             : 
    1259           0 :     return str_replace_string_raw(cx, string, pattern, repl);
    1260             : }
    1261             : 
    1262             : bool
    1263           0 : RecompileImpl(JSContext* cx, bool force)
    1264             : {
    1265           0 :     MOZ_ASSERT(cx->currentlyRunningInJit());
    1266           0 :     JitActivationIterator activations(cx);
    1267           0 :     JitFrameIterator iter(activations);
    1268             : 
    1269           0 :     MOZ_ASSERT(iter.type() == JitFrame_Exit);
    1270           0 :     ++iter;
    1271             : 
    1272           0 :     RootedScript script(cx, iter.script());
    1273           0 :     MOZ_ASSERT(script->hasIonScript());
    1274             : 
    1275           0 :     if (!IsIonEnabled(cx))
    1276           0 :         return true;
    1277             : 
    1278           0 :     MethodStatus status = Recompile(cx, script, nullptr, nullptr, force);
    1279           0 :     if (status == Method_Error)
    1280           0 :         return false;
    1281             : 
    1282           0 :     return true;
    1283             : }
    1284             : 
    1285             : bool
    1286           0 : ForcedRecompile(JSContext* cx)
    1287             : {
    1288           0 :     return RecompileImpl(cx, /* force = */ true);
    1289             : }
    1290             : 
    1291             : bool
    1292           0 : Recompile(JSContext* cx)
    1293             : {
    1294           0 :     return RecompileImpl(cx, /* force = */ false);
    1295             : }
    1296             : 
    1297             : bool
    1298           6 : SetDenseOrUnboxedArrayElement(JSContext* cx, HandleObject obj, int32_t index,
    1299             :                               HandleValue value, bool strict)
    1300             : {
    1301             :     // This function is called from Ion code for StoreElementHole's OOL path.
    1302             :     // In this case we know the object is native or an unboxed array and that
    1303             :     // no type changes are needed.
    1304             : 
    1305             :     DenseElementResult result =
    1306          12 :         SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, index, value.address(), 1,
    1307          12 :                                                   ShouldUpdateTypes::DontUpdate);
    1308           6 :     if (result != DenseElementResult::Incomplete)
    1309           6 :         return result == DenseElementResult::Success;
    1310             : 
    1311           0 :     RootedValue indexVal(cx, Int32Value(index));
    1312           0 :     return SetObjectElement(cx, obj, indexVal, value, strict);
    1313             : }
    1314             : 
    1315             : void
    1316           0 : AutoDetectInvalidation::setReturnOverride()
    1317             : {
    1318           0 :     cx_->setIonReturnOverride(rval_.get());
    1319           0 : }
    1320             : 
    1321             : void
    1322       12673 : AssertValidObjectPtr(JSContext* cx, JSObject* obj)
    1323             : {
    1324             : #ifdef DEBUG
    1325             :     // Check what we can, so that we'll hopefully assert/crash if we get a
    1326             :     // bogus object (pointer).
    1327       12673 :     MOZ_ASSERT(obj->compartment() == cx->compartment());
    1328       12673 :     MOZ_ASSERT(obj->runtimeFromActiveCooperatingThread() == cx->runtime());
    1329             : 
    1330       12673 :     MOZ_ASSERT_IF(!obj->hasLazyGroup() && obj->maybeShape(),
    1331             :                   obj->group()->clasp() == obj->maybeShape()->getObjectClass());
    1332             : 
    1333       12673 :     if (obj->isTenured()) {
    1334        3094 :         MOZ_ASSERT(obj->isAligned());
    1335        3094 :         gc::AllocKind kind = obj->asTenured().getAllocKind();
    1336        3094 :         MOZ_ASSERT(gc::IsObjectAllocKind(kind));
    1337        3094 :         MOZ_ASSERT(obj->asTenured().zone() == cx->zone());
    1338             :     }
    1339             : #endif
    1340       12673 : }
    1341             : 
    1342             : void
    1343           0 : AssertValidObjectOrNullPtr(JSContext* cx, JSObject* obj)
    1344             : {
    1345           0 :     if (obj)
    1346           0 :         AssertValidObjectPtr(cx, obj);
    1347           0 : }
    1348             : 
    1349             : void
    1350        5989 : AssertValidStringPtr(JSContext* cx, JSString* str)
    1351             : {
    1352             : #ifdef DEBUG
    1353             :     // We can't closely inspect strings from another runtime.
    1354        5989 :     if (str->runtimeFromAnyThread() != cx->runtime()) {
    1355           0 :         MOZ_ASSERT(str->isPermanentAtom());
    1356           0 :         return;
    1357             :     }
    1358             : 
    1359        5989 :     if (str->isAtom())
    1360        5587 :         MOZ_ASSERT(str->zone()->isAtomsZone());
    1361             :     else
    1362         402 :         MOZ_ASSERT(str->zone() == cx->zone());
    1363             : 
    1364        5989 :     MOZ_ASSERT(str->isAligned());
    1365        5989 :     MOZ_ASSERT(str->length() <= JSString::MAX_LENGTH);
    1366             : 
    1367        5989 :     gc::AllocKind kind = str->getAllocKind();
    1368        5989 :     if (str->isFatInline()) {
    1369         137 :         MOZ_ASSERT(kind == gc::AllocKind::FAT_INLINE_STRING ||
    1370             :                    kind == gc::AllocKind::FAT_INLINE_ATOM);
    1371        5852 :     } else if (str->isExternal()) {
    1372           0 :         MOZ_ASSERT(kind == gc::AllocKind::EXTERNAL_STRING);
    1373        5852 :     } else if (str->isAtom()) {
    1374        5474 :         MOZ_ASSERT(kind == gc::AllocKind::ATOM);
    1375         378 :     } else if (str->isFlat()) {
    1376         378 :         MOZ_ASSERT(kind == gc::AllocKind::STRING ||
    1377             :                    kind == gc::AllocKind::FAT_INLINE_STRING ||
    1378             :                    kind == gc::AllocKind::EXTERNAL_STRING);
    1379             :     } else {
    1380           0 :         MOZ_ASSERT(kind == gc::AllocKind::STRING);
    1381             :     }
    1382             : #endif
    1383             : }
    1384             : 
    1385             : void
    1386           0 : AssertValidSymbolPtr(JSContext* cx, JS::Symbol* sym)
    1387             : {
    1388             :     // We can't closely inspect symbols from another runtime.
    1389           0 :     if (sym->runtimeFromAnyThread() != cx->runtime()) {
    1390           0 :         MOZ_ASSERT(sym->isWellKnownSymbol());
    1391           0 :         return;
    1392             :     }
    1393             : 
    1394           0 :     MOZ_ASSERT(sym->zone()->isAtomsZone());
    1395           0 :     MOZ_ASSERT(sym->isAligned());
    1396           0 :     if (JSString* desc = sym->description()) {
    1397           0 :         MOZ_ASSERT(desc->isAtom());
    1398           0 :         AssertValidStringPtr(cx, desc);
    1399             :     }
    1400             : 
    1401           0 :     MOZ_ASSERT(sym->getAllocKind() == gc::AllocKind::SYMBOL);
    1402             : }
    1403             : 
    1404             : void
    1405       14440 : AssertValidValue(JSContext* cx, Value* v)
    1406             : {
    1407       14440 :     if (v->isObject())
    1408        3140 :         AssertValidObjectPtr(cx, &v->toObject());
    1409       11300 :     else if (v->isString())
    1410        2628 :         AssertValidStringPtr(cx, v->toString());
    1411        8672 :     else if (v->isSymbol())
    1412           0 :         AssertValidSymbolPtr(cx, v->toSymbol());
    1413       14440 : }
    1414             : 
    1415             : bool
    1416           0 : ObjectIsCallable(JSObject* obj)
    1417             : {
    1418           0 :     return obj->isCallable();
    1419             : }
    1420             : 
    1421             : bool
    1422           0 : ObjectIsConstructor(JSObject* obj)
    1423             : {
    1424           0 :     return obj->isConstructor();
    1425             : }
    1426             : 
    1427             : void
    1428           0 : MarkValueFromIon(JSRuntime* rt, Value* vp)
    1429             : {
    1430           0 :     TraceManuallyBarrieredEdge(&rt->gc.marker, vp, "write barrier");
    1431           0 : }
    1432             : 
    1433             : void
    1434           0 : MarkStringFromIon(JSRuntime* rt, JSString** stringp)
    1435             : {
    1436           0 :     MOZ_ASSERT(*stringp);
    1437           0 :     TraceManuallyBarrieredEdge(&rt->gc.marker, stringp, "write barrier");
    1438           0 : }
    1439             : 
    1440             : void
    1441           0 : MarkObjectFromIon(JSRuntime* rt, JSObject** objp)
    1442             : {
    1443           0 :     MOZ_ASSERT(*objp);
    1444           0 :     TraceManuallyBarrieredEdge(&rt->gc.marker, objp, "write barrier");
    1445           0 : }
    1446             : 
    1447             : void
    1448           0 : MarkShapeFromIon(JSRuntime* rt, Shape** shapep)
    1449             : {
    1450           0 :     TraceManuallyBarrieredEdge(&rt->gc.marker, shapep, "write barrier");
    1451           0 : }
    1452             : 
    1453             : void
    1454           0 : MarkObjectGroupFromIon(JSRuntime* rt, ObjectGroup** groupp)
    1455             : {
    1456           0 :     TraceManuallyBarrieredEdge(&rt->gc.marker, groupp, "write barrier");
    1457           0 : }
    1458             : 
    1459             : bool
    1460           0 : ThrowRuntimeLexicalError(JSContext* cx, unsigned errorNumber)
    1461             : {
    1462           0 :     ScriptFrameIter iter(cx);
    1463           0 :     RootedScript script(cx, iter.script());
    1464           0 :     ReportRuntimeLexicalError(cx, errorNumber, script, iter.pc());
    1465           0 :     return false;
    1466             : }
    1467             : 
    1468             : bool
    1469           0 : ThrowReadOnlyError(JSContext* cx, HandleObject obj, int32_t index)
    1470             : {
    1471             :     // We have to throw different errors depending on whether |index| is past
    1472             :     // the array length, etc. It's simpler to just call SetProperty to ensure
    1473             :     // we match the interpreter.
    1474             : 
    1475           0 :     RootedValue objVal(cx, ObjectValue(*obj));
    1476           0 :     RootedValue indexVal(cx, Int32Value(index));
    1477           0 :     RootedId id(cx);
    1478           0 :     if (!ValueToId<CanGC>(cx, indexVal, &id))
    1479           0 :         return false;
    1480             : 
    1481           0 :     ObjectOpResult result;
    1482           0 :     MOZ_ALWAYS_FALSE(SetProperty(cx, obj, id, UndefinedHandleValue, objVal, result) &&
    1483             :                      result.checkStrictErrorOrWarning(cx, obj, id, /* strict = */ true));
    1484           0 :     return false;
    1485             : }
    1486             : 
    1487             : bool
    1488           0 : ThrowBadDerivedReturn(JSContext* cx, HandleValue v)
    1489             : {
    1490           0 :     ReportValueError(cx, JSMSG_BAD_DERIVED_RETURN, JSDVG_IGNORE_STACK, v, nullptr);
    1491           0 :     return false;
    1492             : }
    1493             : 
    1494             : bool
    1495           0 : BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame)
    1496             : {
    1497           0 :     return ThrowUninitializedThis(cx, frame);
    1498             : }
    1499             : 
    1500             : bool
    1501           0 : BaselineThrowInitializedThis(JSContext* cx, BaselineFrame* frame)
    1502             : {
    1503           0 :     return ThrowInitializedThis(cx, frame);
    1504             : }
    1505             : 
    1506             : 
    1507             : bool
    1508           0 : ThrowObjectCoercible(JSContext* cx, HandleValue v)
    1509             : {
    1510           0 :     MOZ_ASSERT(v.isUndefined() || v.isNull());
    1511           0 :     MOZ_ALWAYS_FALSE(ToObjectSlow(cx, v, true));
    1512           0 :     return false;
    1513             : }
    1514             : 
    1515             : bool
    1516           0 : BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue res)
    1517             : {
    1518           0 :     return GetFunctionThis(cx, frame, res);
    1519             : }
    1520             : 
    1521             : bool
    1522         246 : CallNativeGetter(JSContext* cx, HandleFunction callee, HandleObject obj,
    1523             :                  MutableHandleValue result)
    1524             : {
    1525         246 :     MOZ_ASSERT(callee->isNative());
    1526         246 :     JSNative natfun = callee->native();
    1527             : 
    1528         492 :     JS::AutoValueArray<2> vp(cx);
    1529         246 :     vp[0].setObject(*callee.get());
    1530         246 :     vp[1].setObject(*obj.get());
    1531             : 
    1532         246 :     if (!natfun(cx, 0, vp.begin()))
    1533           0 :         return false;
    1534             : 
    1535         246 :     result.set(vp[0]);
    1536         246 :     return true;
    1537             : }
    1538             : 
    1539             : bool
    1540           6 : CallNativeSetter(JSContext* cx, HandleFunction callee, HandleObject obj, HandleValue rhs)
    1541             : {
    1542           6 :     MOZ_ASSERT(callee->isNative());
    1543           6 :     JSNative natfun = callee->native();
    1544             : 
    1545          12 :     JS::AutoValueArray<3> vp(cx);
    1546           6 :     vp[0].setObject(*callee.get());
    1547           6 :     vp[1].setObject(*obj.get());
    1548           6 :     vp[2].set(rhs);
    1549             : 
    1550          12 :     return natfun(cx, 1, vp.begin());
    1551             : }
    1552             : 
    1553             : bool
    1554         408 : EqualStringsHelper(JSString* str1, JSString* str2)
    1555             : {
    1556             :     // IC code calls this directly so we shouldn't GC.
    1557         816 :     JS::AutoCheckCannotGC nogc;
    1558             : 
    1559         408 :     MOZ_ASSERT(str1->isAtom());
    1560         408 :     MOZ_ASSERT(!str2->isAtom());
    1561         408 :     MOZ_ASSERT(str1->length() == str2->length());
    1562             : 
    1563         408 :     JSLinearString* str2Linear = str2->ensureLinear(nullptr);
    1564         408 :     if (!str2Linear)
    1565           0 :         return false;
    1566             : 
    1567         408 :     return EqualChars(&str1->asLinear(), str2Linear);
    1568             : }
    1569             : 
    1570             : bool
    1571           0 : CheckIsCallable(JSContext* cx, HandleValue v, CheckIsCallableKind kind)
    1572             : {
    1573           0 :     if (!IsCallable(v))
    1574           0 :         return ThrowCheckIsCallable(cx, kind);
    1575             : 
    1576           0 :     return true;
    1577             : }
    1578             : 
    1579             : template <bool HandleMissing>
    1580             : static MOZ_ALWAYS_INLINE bool
    1581        5458 : GetNativeDataProperty(JSContext* cx, NativeObject* obj, jsid id, Value* vp)
    1582             : {
    1583             :     // Fast path used by megamorphic IC stubs. Unlike our other property
    1584             :     // lookup paths, this is optimized to be as fast as possible for simple
    1585             :     // data property lookups.
    1586             : 
    1587       10916 :     JS::AutoCheckCannotGC nogc;
    1588             : 
    1589        5458 :     MOZ_ASSERT(JSID_IS_ATOM(id) || JSID_IS_SYMBOL(id));
    1590             : 
    1591        2948 :     while (true) {
    1592        8406 :         if (Shape* shape = obj->lastProperty()->search(cx, id)) {
    1593        2998 :             if (!shape->hasSlot() || !shape->hasDefaultGetter())
    1594          10 :                 return false;
    1595             : 
    1596        2988 :             *vp = obj->getSlot(shape->slot());
    1597        2988 :             return true;
    1598             :         }
    1599             : 
    1600             :         // Property not found. Watch out for Class hooks.
    1601        5408 :         if (MOZ_UNLIKELY(!obj->is<PlainObject>())) {
    1602         406 :             if (ClassMayResolveId(cx->names(), obj->getClass(), id, obj) ||
    1603         191 :                 obj->getClass()->getGetProperty())
    1604             :             {
    1605          24 :                 return false;
    1606             :             }
    1607             :         }
    1608             : 
    1609        5384 :         JSObject* proto = obj->staticPrototype();
    1610        5384 :         if (!proto) {
    1611             :             if (HandleMissing) {
    1612        2436 :                 vp->setUndefined();
    1613        2436 :                 return true;
    1614             :             }
    1615           0 :             return false;
    1616             :         }
    1617             : 
    1618        2948 :         if (!proto->isNative())
    1619           0 :             return false;
    1620        2948 :         obj = &proto->as<NativeObject>();
    1621             :     }
    1622             : }
    1623             : 
    1624             : template <bool HandleMissing>
    1625             : bool
    1626        1629 : GetNativeDataProperty(JSContext* cx, JSObject* obj, PropertyName* name, Value* vp)
    1627             : {
    1628        1629 :     if (MOZ_UNLIKELY(!obj->isNative()))
    1629           0 :         return false;
    1630        1629 :     return GetNativeDataProperty<HandleMissing>(cx, &obj->as<NativeObject>(), NameToId(name), vp);
    1631             : }
    1632             : 
    1633             : template bool
    1634             : GetNativeDataProperty<true>(JSContext* cx, JSObject* obj, PropertyName* name, Value* vp);
    1635             : 
    1636             : template bool
    1637             : GetNativeDataProperty<false>(JSContext* cx, JSObject* obj, PropertyName* name, Value* vp);
    1638             : 
    1639             : static MOZ_ALWAYS_INLINE bool
    1640        3842 : ValueToAtomOrSymbol(JSContext* cx, Value& idVal, jsid* id)
    1641             : {
    1642        7684 :     JS::AutoCheckCannotGC nogc;
    1643             : 
    1644        3842 :     if (MOZ_LIKELY(idVal.isString())) {
    1645        3842 :         JSString* s = idVal.toString();
    1646             :         JSAtom* atom;
    1647        3842 :         if (s->isAtom()) {
    1648        3322 :             atom = &s->asAtom();
    1649             :         } else {
    1650         520 :             atom = AtomizeString(cx, s);
    1651         520 :             if (!atom)
    1652           0 :                 return false;
    1653             :         }
    1654        3842 :         *id = AtomToId(atom);
    1655           0 :     } else if (idVal.isSymbol()) {
    1656           0 :         *id = SYMBOL_TO_JSID(idVal.toSymbol());
    1657             :     } else {
    1658           0 :         if (!ValueToIdPure(idVal, id))
    1659           0 :             return false;
    1660             :     }
    1661             : 
    1662             :     // Watch out for ids that may be stored in dense elements.
    1663             :     static_assert(NativeObject::MAX_DENSE_ELEMENTS_COUNT < JSID_INT_MAX,
    1664             :                   "All dense elements must have integer jsids");
    1665        3842 :     if (MOZ_UNLIKELY(JSID_IS_INT(*id)))
    1666          13 :         return false;
    1667             : 
    1668        3829 :     return true;
    1669             : }
    1670             : 
    1671             : template <bool HandleMissing>
    1672             : bool
    1673        3842 : GetNativeDataPropertyByValue(JSContext* cx, JSObject* obj, Value* vp)
    1674             : {
    1675        7684 :     JS::AutoCheckCannotGC nogc;
    1676             : 
    1677        3842 :     if (MOZ_UNLIKELY(!obj->isNative()))
    1678           0 :         return false;
    1679             : 
    1680             :     // vp[0] contains the id, result will be stored in vp[1].
    1681        3842 :     Value idVal = vp[0];
    1682             :     jsid id;
    1683        3842 :     if (!ValueToAtomOrSymbol(cx, idVal, &id))
    1684          13 :         return false;
    1685             : 
    1686        3829 :     Value* res = vp + 1;
    1687        3829 :     return GetNativeDataProperty<HandleMissing>(cx, &obj->as<NativeObject>(), id, res);
    1688             : }
    1689             : 
    1690             : template bool
    1691             : GetNativeDataPropertyByValue<true>(JSContext* cx, JSObject* obj, Value* vp);
    1692             : 
    1693             : template bool
    1694             : GetNativeDataPropertyByValue<false>(JSContext* cx, JSObject* obj, Value* vp);
    1695             : 
    1696             : template <bool NeedsTypeBarrier>
    1697             : bool
    1698           0 : SetNativeDataProperty(JSContext* cx, JSObject* obj, PropertyName* name, Value* val)
    1699             : {
    1700           0 :     JS::AutoCheckCannotGC nogc;
    1701             : 
    1702           0 :     if (MOZ_UNLIKELY(!obj->isNative()))
    1703           0 :         return false;
    1704             : 
    1705           0 :     NativeObject* nobj = &obj->as<NativeObject>();
    1706           0 :     Shape* shape = nobj->lastProperty()->search(cx, NameToId(name));
    1707           0 :     if (!shape ||
    1708           0 :         !shape->hasSlot() ||
    1709           0 :         !shape->hasDefaultSetter() ||
    1710           0 :         !shape->writable() ||
    1711           0 :         nobj->watched())
    1712             :     {
    1713           0 :         return false;
    1714             :     }
    1715             : 
    1716           0 :     if (NeedsTypeBarrier && !HasTypePropertyId(nobj, NameToId(name), *val))
    1717           0 :         return false;
    1718             : 
    1719           0 :     nobj->setSlot(shape->slot(), *val);
    1720           0 :     return true;
    1721             : }
    1722             : 
    1723             : template bool
    1724             : SetNativeDataProperty<true>(JSContext* cx, JSObject* obj, PropertyName* name, Value* val);
    1725             : 
    1726             : template bool
    1727             : SetNativeDataProperty<false>(JSContext* cx, JSObject* obj, PropertyName* name, Value* val);
    1728             : 
    1729             : bool
    1730          35 : ObjectHasGetterSetter(JSContext* cx, JSObject* objArg, Shape* propShape)
    1731             : {
    1732          70 :     JS::AutoCheckCannotGC nogc;
    1733             : 
    1734          35 :     MOZ_ASSERT(propShape->hasGetterObject() || propShape->hasSetterObject());
    1735             : 
    1736             :     // Window objects may require outerizing (passing the WindowProxy to the
    1737             :     // getter/setter), so we don't support them here.
    1738          35 :     if (MOZ_UNLIKELY(!objArg->isNative() || IsWindow(objArg)))
    1739           0 :         return false;
    1740             : 
    1741          35 :     NativeObject* nobj = &objArg->as<NativeObject>();
    1742          35 :     jsid id = propShape->propid();
    1743             : 
    1744             :     while (true) {
    1745          61 :         if (Shape* shape = nobj->lastProperty()->search(cx, id)) {
    1746          35 :             if (shape == propShape)
    1747           8 :                 return true;
    1748          54 :             if (shape->getterOrUndefined() == propShape->getterOrUndefined() &&
    1749          27 :                 shape->setterOrUndefined() == propShape->setterOrUndefined())
    1750             :             {
    1751           0 :                 return true;
    1752             :             }
    1753          27 :             return false;
    1754             :         }
    1755             : 
    1756             :         // Property not found. Watch out for Class hooks.
    1757          26 :         if (!nobj->is<PlainObject>()) {
    1758          48 :             if (ClassMayResolveId(cx->names(), nobj->getClass(), id, nobj) ||
    1759          24 :                 nobj->getClass()->getGetProperty())
    1760             :             {
    1761           0 :                 return false;
    1762             :             }
    1763             :         }
    1764             : 
    1765          26 :         JSObject* proto = nobj->staticPrototype();
    1766          26 :         if (!proto)
    1767           0 :             return false;
    1768             : 
    1769          26 :         if (!proto->isNative())
    1770           0 :             return false;
    1771          26 :         nobj = &proto->as<NativeObject>();
    1772          26 :     }
    1773             : }
    1774             : 
    1775             : bool
    1776           0 : HasOwnNativeDataProperty(JSContext* cx, JSObject* obj, Value* vp)
    1777             : {
    1778           0 :     JS::AutoCheckCannotGC nogc;
    1779             : 
    1780             :     // vp[0] contains the id, result will be stored in vp[1].
    1781           0 :     Value idVal = vp[0];
    1782             :     jsid id;
    1783           0 :     if (!ValueToAtomOrSymbol(cx, idVal, &id))
    1784           0 :         return false;
    1785             : 
    1786           0 :     if (!obj->isNative()) {
    1787           0 :         if (obj->is<UnboxedPlainObject>()) {
    1788           0 :             bool res = obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id);
    1789           0 :             vp[1].setBoolean(res);
    1790           0 :             return true;
    1791             :         }
    1792           0 :         return false;
    1793             :     }
    1794             : 
    1795           0 :     NativeObject* nobj = &obj->as<NativeObject>();
    1796           0 :     if (nobj->lastProperty()->search(cx, id)) {
    1797           0 :         vp[1].setBoolean(true);
    1798           0 :         return true;
    1799             :     }
    1800             : 
    1801             :     // Property not found. Watch out for Class hooks.
    1802           0 :     if (MOZ_UNLIKELY(!nobj->is<PlainObject>())) {
    1803           0 :         if (ClassMayResolveId(cx->names(), nobj->getClass(), id, nobj))
    1804           0 :             return false;
    1805             :     }
    1806             : 
    1807             :     // Missing property.
    1808           0 :     vp[1].setBoolean(false);
    1809           0 :     return true;
    1810             : }
    1811             : 
    1812             : JSString*
    1813          71 : TypeOfObject(JSObject* obj, JSRuntime* rt)
    1814             : {
    1815          71 :     JSType type = js::TypeOfObject(obj);
    1816          71 :     return TypeName(type, *rt->commonNames);
    1817             : }
    1818             : 
    1819             : } // namespace jit
    1820             : } // namespace js

Generated by: LCOV version 1.13