1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 /*
8  * JavaScript bytecode interpreter.
9  */
10 
11 #include "vm/Interpreter-inl.h"
12 
13 #include "mozilla/DebugOnly.h"
14 #include "mozilla/FloatingPoint.h"
15 #include "mozilla/Maybe.h"
16 #include "mozilla/ScopeExit.h"
17 #include "mozilla/Sprintf.h"
18 #include "mozilla/WrappingOperations.h"
19 
20 #include <string.h>
21 
22 #include "jslibmath.h"
23 #include "jsmath.h"
24 #include "jsnum.h"
25 
26 #include "builtin/Array.h"
27 #include "builtin/Eval.h"
28 #include "builtin/ModuleObject.h"
29 #include "builtin/Promise.h"
30 #include "jit/AtomicOperations.h"
31 #include "jit/BaselineJIT.h"
32 #include "jit/Ion.h"
33 #include "jit/IonAnalysis.h"
34 #include "jit/Jit.h"
35 #include "jit/JitRuntime.h"
36 #include "js/CharacterEncoding.h"
37 #include "js/experimental/JitInfo.h"  // JSJitInfo
38 #include "js/friend/ErrorMessages.h"  // js::GetErrorMessage, JSMSG_*
39 #include "js/friend/StackLimits.h"    // js::AutoCheckRecursionLimit
40 #include "js/friend/WindowProxy.h"    // js::IsWindowProxy
41 #include "util/CheckedArithmetic.h"
42 #include "util/StringBuffer.h"
43 #include "vm/AsyncFunction.h"
44 #include "vm/AsyncIteration.h"
45 #include "vm/BigIntType.h"
46 #include "vm/BytecodeUtil.h"        // JSDVG_SEARCH_STACK
47 #include "vm/EqualityOperations.h"  // js::StrictlyEqual
48 #include "vm/FunctionFlags.h"       // js::FunctionFlags
49 #include "vm/GeneratorObject.h"
50 #include "vm/Iteration.h"
51 #include "vm/JSAtom.h"
52 #include "vm/JSContext.h"
53 #include "vm/JSFunction.h"
54 #include "vm/JSObject.h"
55 #include "vm/JSScript.h"
56 #include "vm/Opcodes.h"
57 #include "vm/PIC.h"
58 #include "vm/PlainObject.h"  // js::PlainObject
59 #include "vm/Printer.h"
60 #include "vm/Scope.h"
61 #include "vm/Shape.h"
62 #include "vm/SharedStencil.h"  // GCThingIndex
63 #include "vm/StringType.h"
64 #include "vm/ThrowMsgKind.h"  // ThrowMsgKind
65 #include "vm/TraceLogging.h"
66 
67 #include "builtin/Boolean-inl.h"
68 #include "debugger/DebugAPI-inl.h"
69 #include "vm/EnvironmentObject-inl.h"
70 #include "vm/GeckoProfiler-inl.h"
71 #include "vm/JSAtom-inl.h"
72 #include "vm/JSFunction-inl.h"
73 #include "vm/JSScript-inl.h"
74 #include "vm/NativeObject-inl.h"
75 #include "vm/ObjectOperations-inl.h"
76 #include "vm/PlainObject-inl.h"  // js::CopyInitializerObject, js::CreateThis
77 #include "vm/Probes-inl.h"
78 #include "vm/Stack-inl.h"
79 
80 using namespace js;
81 
82 using mozilla::DebugOnly;
83 using mozilla::NumberEqualsInt32;
84 
85 using js::jit::JitScript;
86 
87 template <bool Eq>
LooseEqualityOp(JSContext * cx,InterpreterRegs & regs)88 static MOZ_ALWAYS_INLINE bool LooseEqualityOp(JSContext* cx,
89                                               InterpreterRegs& regs) {
90   HandleValue rval = regs.stackHandleAt(-1);
91   HandleValue lval = regs.stackHandleAt(-2);
92   bool cond;
93   if (!LooselyEqual(cx, lval, rval, &cond)) {
94     return false;
95   }
96   cond = (cond == Eq);
97   regs.sp--;
98   regs.sp[-1].setBoolean(cond);
99   return true;
100 }
101 
BoxNonStrictThis(JSContext * cx,HandleValue thisv)102 JSObject* js::BoxNonStrictThis(JSContext* cx, HandleValue thisv) {
103   MOZ_ASSERT(!thisv.isMagic());
104 
105   if (thisv.isNullOrUndefined()) {
106     return cx->global()->lexicalEnvironment().thisObject();
107   }
108 
109   if (thisv.isObject()) {
110     return &thisv.toObject();
111   }
112 
113   return PrimitiveToObject(cx, thisv);
114 }
115 
GetFunctionThis(JSContext * cx,AbstractFramePtr frame,MutableHandleValue res)116 bool js::GetFunctionThis(JSContext* cx, AbstractFramePtr frame,
117                          MutableHandleValue res) {
118   MOZ_ASSERT(frame.isFunctionFrame());
119   MOZ_ASSERT(!frame.callee()->isArrow());
120 
121   if (frame.thisArgument().isObject() || frame.callee()->strict()) {
122     res.set(frame.thisArgument());
123     return true;
124   }
125 
126   MOZ_ASSERT(!frame.callee()->isSelfHostedBuiltin(),
127              "Self-hosted builtins must be strict");
128 
129   RootedValue thisv(cx, frame.thisArgument());
130 
131   // If there is a NSVO on environment chain, use it as basis for fallback
132   // global |this|. This gives a consistent definition of global lexical
133   // |this| between function and global contexts.
134   //
135   // NOTE: If only non-syntactic WithEnvironments are on the chain, we use the
136   // global lexical |this| value. This is for compatibility with the Subscript
137   // Loader.
138   if (frame.script()->hasNonSyntacticScope() && thisv.isNullOrUndefined()) {
139     RootedObject env(cx, frame.environmentChain());
140     while (true) {
141       if (IsNSVOLexicalEnvironment(env) || IsGlobalLexicalEnvironment(env)) {
142         res.setObject(*GetThisObjectOfLexical(env));
143         return true;
144       }
145       if (!env->enclosingEnvironment()) {
146         // This can only happen in Debugger eval frames: in that case we
147         // don't always have a global lexical env, see EvaluateInEnv.
148         MOZ_ASSERT(env->is<GlobalObject>());
149         res.setObject(*GetThisObject(env));
150         return true;
151       }
152       env = env->enclosingEnvironment();
153     }
154   }
155 
156   JSObject* obj = BoxNonStrictThis(cx, thisv);
157   if (!obj) {
158     return false;
159   }
160 
161   res.setObject(*obj);
162   return true;
163 }
164 
GetNonSyntacticGlobalThis(JSContext * cx,HandleObject envChain,MutableHandleValue res)165 void js::GetNonSyntacticGlobalThis(JSContext* cx, HandleObject envChain,
166                                    MutableHandleValue res) {
167   RootedObject env(cx, envChain);
168   while (true) {
169     if (IsExtensibleLexicalEnvironment(env)) {
170       res.setObject(*GetThisObjectOfLexical(env));
171       return;
172     }
173     if (!env->enclosingEnvironment()) {
174       // This can only happen in Debugger eval frames: in that case we
175       // don't always have a global lexical env, see EvaluateInEnv.
176       MOZ_ASSERT(env->is<GlobalObject>());
177       res.setObject(*GetThisObject(env));
178       return;
179     }
180     env = env->enclosingEnvironment();
181   }
182 }
183 
Debug_CheckSelfHosted(JSContext * cx,HandleValue fun)184 bool js::Debug_CheckSelfHosted(JSContext* cx, HandleValue fun) {
185 #ifndef DEBUG
186   MOZ_CRASH("self-hosted checks should only be done in Debug builds");
187 #endif
188 
189   RootedObject funObj(cx, UncheckedUnwrap(&fun.toObject()));
190   MOZ_ASSERT(funObj->as<JSFunction>().isSelfHostedOrIntrinsic());
191 
192   // This is purely to police self-hosted code. There is no actual operation.
193   return true;
194 }
195 
GetPropertyOperation(JSContext * cx,InterpreterFrame * fp,HandleScript script,jsbytecode * pc,MutableHandleValue lval,MutableHandleValue vp)196 static inline bool GetPropertyOperation(JSContext* cx, InterpreterFrame* fp,
197                                         HandleScript script, jsbytecode* pc,
198                                         MutableHandleValue lval,
199                                         MutableHandleValue vp) {
200   RootedPropertyName name(cx, script->getName(pc));
201 
202   if (name == cx->names().length && GetLengthProperty(lval, vp)) {
203     return true;
204   }
205 
206   // Copy lval, because it might alias vp.
207   RootedValue v(cx, lval);
208   return GetProperty(cx, v, name, vp);
209 }
210 
GetNameOperation(JSContext * cx,InterpreterFrame * fp,jsbytecode * pc,MutableHandleValue vp)211 static inline bool GetNameOperation(JSContext* cx, InterpreterFrame* fp,
212                                     jsbytecode* pc, MutableHandleValue vp) {
213   RootedObject envChain(cx, fp->environmentChain());
214   RootedPropertyName name(cx, fp->script()->getName(pc));
215 
216   /*
217    * Skip along the env chain to the enclosing global object. This is
218    * used for GNAME opcodes where the bytecode emitter has determined a
219    * name access must be on the global. It also insulates us from bugs
220    * in the emitter: type inference will assume that GNAME opcodes are
221    * accessing the global object, and the inferred behavior should match
222    * the actual behavior even if the id could be found on the env chain
223    * before the global object.
224    */
225   if (IsGlobalOp(JSOp(*pc)) && !fp->script()->hasNonSyntacticScope()) {
226     envChain = &cx->global()->lexicalEnvironment();
227   }
228 
229   /* Kludge to allow (typeof foo == "undefined") tests. */
230   JSOp op2 = JSOp(pc[JSOpLength_GetName]);
231   if (op2 == JSOp::Typeof) {
232     return GetEnvironmentName<GetNameMode::TypeOf>(cx, envChain, name, vp);
233   }
234   return GetEnvironmentName<GetNameMode::Normal>(cx, envChain, name, vp);
235 }
236 
GetImportOperation(JSContext * cx,HandleObject envChain,HandleScript script,jsbytecode * pc,MutableHandleValue vp)237 bool js::GetImportOperation(JSContext* cx, HandleObject envChain,
238                             HandleScript script, jsbytecode* pc,
239                             MutableHandleValue vp) {
240   RootedObject env(cx), pobj(cx);
241   RootedPropertyName name(cx, script->getName(pc));
242   PropertyResult prop;
243 
244   MOZ_ALWAYS_TRUE(LookupName(cx, name, envChain, &env, &pobj, &prop));
245   MOZ_ASSERT(env && env->is<ModuleEnvironmentObject>());
246   MOZ_ASSERT(env->as<ModuleEnvironmentObject>().hasImportBinding(name));
247   return FetchName<GetNameMode::Normal>(cx, env, pobj, name, prop, vp);
248 }
249 
SetPropertyOperation(JSContext * cx,JSOp op,HandleValue lval,int lvalIndex,HandleId id,HandleValue rval)250 static bool SetPropertyOperation(JSContext* cx, JSOp op, HandleValue lval,
251                                  int lvalIndex, HandleId id, HandleValue rval) {
252   MOZ_ASSERT(op == JSOp::SetProp || op == JSOp::StrictSetProp);
253 
254   RootedObject obj(cx,
255                    ToObjectFromStackForPropertyAccess(cx, lval, lvalIndex, id));
256   if (!obj) {
257     return false;
258   }
259 
260   ObjectOpResult result;
261   return SetProperty(cx, obj, id, rval, lval, result) &&
262          result.checkStrictModeError(cx, obj, id, op == JSOp::StrictSetProp);
263 }
264 
SuperFunOperation(JSObject * callee)265 static JSObject* SuperFunOperation(JSObject* callee) {
266   MOZ_ASSERT(callee->as<JSFunction>().isClassConstructor());
267   MOZ_ASSERT(
268       callee->as<JSFunction>().baseScript()->isDerivedClassConstructor());
269 
270   return callee->as<JSFunction>().staticPrototype();
271 }
272 
HomeObjectSuperBase(JSContext * cx,JSObject * homeObj)273 static JSObject* HomeObjectSuperBase(JSContext* cx, JSObject* homeObj) {
274   MOZ_ASSERT(homeObj->is<PlainObject>() || homeObj->is<JSFunction>());
275 
276   if (JSObject* superBase = homeObj->staticPrototype()) {
277     return superBase;
278   }
279 
280   ThrowHomeObjectNotObject(cx);
281   return nullptr;
282 }
283 
ReportIsNotFunction(JSContext * cx,HandleValue v,int numToSkip,MaybeConstruct construct)284 bool js::ReportIsNotFunction(JSContext* cx, HandleValue v, int numToSkip,
285                              MaybeConstruct construct) {
286   unsigned error = construct ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
287   int spIndex = numToSkip >= 0 ? -(numToSkip + 1) : JSDVG_SEARCH_STACK;
288 
289   ReportValueError(cx, error, spIndex, v, nullptr);
290   return false;
291 }
292 
ValueToCallable(JSContext * cx,HandleValue v,int numToSkip,MaybeConstruct construct)293 JSObject* js::ValueToCallable(JSContext* cx, HandleValue v, int numToSkip,
294                               MaybeConstruct construct) {
295   if (v.isObject() && v.toObject().isCallable()) {
296     return &v.toObject();
297   }
298 
299   ReportIsNotFunction(cx, v, numToSkip, construct);
300   return nullptr;
301 }
302 
MaybeCreateThisForConstructor(JSContext * cx,const CallArgs & args)303 static bool MaybeCreateThisForConstructor(JSContext* cx, const CallArgs& args) {
304   if (args.thisv().isObject()) {
305     return true;
306   }
307 
308   RootedFunction callee(cx, &args.callee().as<JSFunction>());
309   RootedObject newTarget(cx, &args.newTarget().toObject());
310 
311   MOZ_ASSERT(callee->hasBytecode());
312 
313   if (!CreateThis(cx, callee, newTarget, GenericObject, args.mutableThisv())) {
314     return false;
315   }
316 
317   // Ensure the callee still has a non-lazy script. We normally don't relazify
318   // in active compartments, but the .prototype lookup might have called the
319   // relazifyFunctions testing function that doesn't have this restriction.
320   return JSFunction::getOrCreateScript(cx, callee);
321 }
322 
323 static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
324                                                               RunState& state);
325 
pushInterpreterFrame(JSContext * cx)326 InterpreterFrame* InvokeState::pushInterpreterFrame(JSContext* cx) {
327   return cx->interpreterStack().pushInvokeFrame(cx, args_, construct_);
328 }
329 
pushInterpreterFrame(JSContext * cx)330 InterpreterFrame* ExecuteState::pushInterpreterFrame(JSContext* cx) {
331   return cx->interpreterStack().pushExecuteFrame(cx, script_, newTargetValue_,
332                                                  envChain_, evalInFrame_);
333 }
334 
pushInterpreterFrame(JSContext * cx)335 InterpreterFrame* RunState::pushInterpreterFrame(JSContext* cx) {
336   if (isInvoke()) {
337     return asInvoke()->pushInterpreterFrame(cx);
338   }
339   return asExecute()->pushInterpreterFrame(cx);
340 }
341 
342 // MSVC with PGO inlines a lot of functions in RunScript, resulting in large
343 // stack frames and stack overflow issues, see bug 1167883. Turn off PGO to
344 // avoid this.
345 #ifdef _MSC_VER
346 #  pragma optimize("g", off)
347 #endif
RunScript(JSContext * cx,RunState & state)348 bool js::RunScript(JSContext* cx, RunState& state) {
349   AutoCheckRecursionLimit recursion(cx);
350   if (!recursion.check(cx)) {
351     return false;
352   }
353 
354   MOZ_ASSERT_IF(cx->runtime()->hasJitRuntime(),
355                 !cx->runtime()->jitRuntime()->disallowArbitraryCode());
356 
357   // Since any script can conceivably GC, make sure it's safe to do so.
358   cx->verifyIsSafeToGC();
359 
360   MOZ_ASSERT(cx->realm() == state.script()->realm());
361 
362   MOZ_DIAGNOSTIC_ASSERT(cx->realm()->isSystem() ||
363                         cx->runtime()->allowContentJS());
364 
365   if (!DebugAPI::checkNoExecute(cx, state.script())) {
366     return false;
367   }
368 
369   GeckoProfilerEntryMarker marker(cx, state.script());
370 
371   bool measuringTime = !cx->isMeasuringExecutionTime();
372   mozilla::TimeStamp startTime;
373   if (measuringTime) {
374     cx->setIsMeasuringExecutionTime(true);
375     startTime = ReallyNow();
376   }
377   auto timerEnd = mozilla::MakeScopeExit([&]() {
378     if (measuringTime) {
379       mozilla::TimeDuration delta = ReallyNow() - startTime;
380       cx->realm()->timers.executionTime += delta;
381       cx->setIsMeasuringExecutionTime(false);
382     }
383   });
384 
385   jit::EnterJitStatus status = jit::MaybeEnterJit(cx, state);
386   switch (status) {
387     case jit::EnterJitStatus::Error:
388       return false;
389     case jit::EnterJitStatus::Ok:
390       return true;
391     case jit::EnterJitStatus::NotEntered:
392       break;
393   }
394 
395   bool ok = Interpret(cx, state);
396 
397   return ok;
398 }
399 #ifdef _MSC_VER
400 #  pragma optimize("", on)
401 #endif
402 
403 STATIC_PRECONDITION_ASSUME(ubound(args.argv_) >= argc)
CallJSNative(JSContext * cx,Native native,CallReason reason,const CallArgs & args)404 MOZ_ALWAYS_INLINE bool CallJSNative(JSContext* cx, Native native,
405                                     CallReason reason, const CallArgs& args) {
406   TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
407   AutoTraceLog traceLog(logger, TraceLogger_Call);
408 
409   AutoCheckRecursionLimit recursion(cx);
410   if (!recursion.check(cx)) {
411     return false;
412   }
413 
414   NativeResumeMode resumeMode = DebugAPI::onNativeCall(cx, args, reason);
415   if (resumeMode != NativeResumeMode::Continue) {
416     return resumeMode == NativeResumeMode::Override;
417   }
418 
419 #ifdef DEBUG
420   bool alreadyThrowing = cx->isExceptionPending();
421 #endif
422   cx->check(args);
423   MOZ_ASSERT(!args.callee().is<ProxyObject>());
424 
425   AutoRealm ar(cx, &args.callee());
426   bool ok = native(cx, args.length(), args.base());
427   if (ok) {
428     cx->check(args.rval());
429     MOZ_ASSERT_IF(!alreadyThrowing, !cx->isExceptionPending());
430   }
431   return ok;
432 }
433 
434 STATIC_PRECONDITION(ubound(args.argv_) >= argc)
CallJSNativeConstructor(JSContext * cx,Native native,const CallArgs & args)435 MOZ_ALWAYS_INLINE bool CallJSNativeConstructor(JSContext* cx, Native native,
436                                                const CallArgs& args) {
437 #ifdef DEBUG
438   RootedObject callee(cx, &args.callee());
439 #endif
440 
441   MOZ_ASSERT(args.thisv().isMagic());
442   if (!CallJSNative(cx, native, CallReason::Call, args)) {
443     return false;
444   }
445 
446   /*
447    * Native constructors must return non-primitive values on success.
448    * Although it is legal, if a constructor returns the callee, there is a
449    * 99.9999% chance it is a bug. If any valid code actually wants the
450    * constructor to return the callee, the assertion can be removed or
451    * (another) conjunct can be added to the antecedent.
452    *
453    * Exception: (new Object(Object)) returns the callee.
454    */
455   MOZ_ASSERT_IF((!callee->is<JSFunction>() ||
456                  callee->as<JSFunction>().native() != obj_construct),
457                 args.rval().isObject() && callee != &args.rval().toObject());
458 
459   return true;
460 }
461 
462 /*
463  * Find a function reference and its 'this' value implicit first parameter
464  * under argc arguments on cx's stack, and call the function.  Push missing
465  * required arguments, allocate declared local variables, and pop everything
466  * when done.  Then push the return value.
467  *
468  * Note: This function DOES NOT call GetThisValue to munge |args.thisv()| if
469  *       necessary.  The caller (usually the interpreter) must have performed
470  *       this step already!
471  */
InternalCallOrConstruct(JSContext * cx,const CallArgs & args,MaybeConstruct construct,CallReason reason)472 bool js::InternalCallOrConstruct(JSContext* cx, const CallArgs& args,
473                                  MaybeConstruct construct, CallReason reason) {
474   MOZ_ASSERT(args.length() <= ARGS_LENGTH_MAX);
475 
476   unsigned skipForCallee = args.length() + 1 + (construct == CONSTRUCT);
477   if (args.calleev().isPrimitive()) {
478     return ReportIsNotFunction(cx, args.calleev(), skipForCallee, construct);
479   }
480 
481   /* Invoke non-functions. */
482   if (MOZ_UNLIKELY(!args.callee().is<JSFunction>())) {
483     MOZ_ASSERT_IF(construct, !args.callee().isConstructor());
484 
485     if (!args.callee().isCallable()) {
486       return ReportIsNotFunction(cx, args.calleev(), skipForCallee, construct);
487     }
488 
489     if (args.callee().is<ProxyObject>()) {
490       RootedObject proxy(cx, &args.callee());
491       return Proxy::call(cx, proxy, args);
492     }
493 
494     JSNative call = args.callee().callHook();
495     MOZ_ASSERT(call, "isCallable without a callHook?");
496 
497     return CallJSNative(cx, call, reason, args);
498   }
499 
500   /* Invoke native functions. */
501   RootedFunction fun(cx, &args.callee().as<JSFunction>());
502   if (fun->isNativeFun()) {
503     MOZ_ASSERT_IF(construct, !fun->isConstructor());
504     JSNative native = fun->native();
505     if (!construct && args.ignoresReturnValue() && fun->hasJitInfo()) {
506       const JSJitInfo* jitInfo = fun->jitInfo();
507       if (jitInfo->type() == JSJitInfo::IgnoresReturnValueNative) {
508         native = jitInfo->ignoresReturnValueMethod;
509       }
510     }
511     return CallJSNative(cx, native, reason, args);
512   }
513 
514   // Self-hosted builtins are considered native by the onNativeCall hook.
515   if (fun->isSelfHostedBuiltin()) {
516     NativeResumeMode resumeMode = DebugAPI::onNativeCall(cx, args, reason);
517     if (resumeMode != NativeResumeMode::Continue) {
518       return resumeMode == NativeResumeMode::Override;
519     }
520   }
521 
522   if (!JSFunction::getOrCreateScript(cx, fun)) {
523     return false;
524   }
525 
526   /* Run function until JSOp::RetRval, JSOp::Return or error. */
527   InvokeState state(cx, args, construct);
528 
529   // Create |this| if we're constructing. Switch to the callee's realm to
530   // ensure this object has the correct realm.
531   AutoRealm ar(cx, state.script());
532   if (construct && !MaybeCreateThisForConstructor(cx, args)) {
533     return false;
534   }
535 
536   // Calling class constructors throws an error from the callee's realm.
537   if (construct != CONSTRUCT && fun->isClassConstructor()) {
538     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
539                               JSMSG_CANT_CALL_CLASS_CONSTRUCTOR);
540     return false;
541   }
542 
543   bool ok = RunScript(cx, state);
544 
545   MOZ_ASSERT_IF(ok && construct, args.rval().isObject());
546   return ok;
547 }
548 
InternalCall(JSContext * cx,const AnyInvokeArgs & args,CallReason reason=CallReason::Call)549 static bool InternalCall(JSContext* cx, const AnyInvokeArgs& args,
550                          CallReason reason = CallReason::Call) {
551   MOZ_ASSERT(args.array() + args.length() == args.end(),
552              "must pass calling arguments to a calling attempt");
553 
554   if (args.thisv().isObject()) {
555     // We must call the thisValue hook in case we are not called from the
556     // interpreter, where a prior bytecode has computed an appropriate
557     // |this| already.  But don't do that if fval is a DOM function.
558     HandleValue fval = args.calleev();
559     if (!fval.isObject() || !fval.toObject().is<JSFunction>() ||
560         !fval.toObject().as<JSFunction>().isNativeFun() ||
561         !fval.toObject().as<JSFunction>().hasJitInfo() ||
562         fval.toObject()
563             .as<JSFunction>()
564             .jitInfo()
565             ->needsOuterizedThisObject()) {
566       JSObject* thisObj = GetThisObject(&args.thisv().toObject());
567       args.mutableThisv().setObject(*thisObj);
568     }
569   }
570 
571   return InternalCallOrConstruct(cx, args, NO_CONSTRUCT, reason);
572 }
573 
CallFromStack(JSContext * cx,const CallArgs & args)574 bool js::CallFromStack(JSContext* cx, const CallArgs& args) {
575   return InternalCall(cx, static_cast<const AnyInvokeArgs&>(args));
576 }
577 
578 // ES7 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93
579 // 7.3.12 Call.
Call(JSContext * cx,HandleValue fval,HandleValue thisv,const AnyInvokeArgs & args,MutableHandleValue rval,CallReason reason)580 bool js::Call(JSContext* cx, HandleValue fval, HandleValue thisv,
581               const AnyInvokeArgs& args, MutableHandleValue rval,
582               CallReason reason) {
583   // Explicitly qualify these methods to bypass AnyInvokeArgs's deliberate
584   // shadowing.
585   args.CallArgs::setCallee(fval);
586   args.CallArgs::setThis(thisv);
587 
588   if (!InternalCall(cx, args, reason)) {
589     return false;
590   }
591 
592   rval.set(args.rval());
593   return true;
594 }
595 
InternalConstruct(JSContext * cx,const AnyConstructArgs & args)596 static bool InternalConstruct(JSContext* cx, const AnyConstructArgs& args) {
597   MOZ_ASSERT(args.array() + args.length() + 1 == args.end(),
598              "must pass constructing arguments to a construction attempt");
599   MOZ_ASSERT(!JSFunction::class_.getConstruct());
600 
601   // Callers are responsible for enforcing these preconditions.
602   MOZ_ASSERT(IsConstructor(args.calleev()),
603              "trying to construct a value that isn't a constructor");
604   MOZ_ASSERT(IsConstructor(args.CallArgs::newTarget()),
605              "provided new.target value must be a constructor");
606 
607   MOZ_ASSERT(args.thisv().isMagic(JS_IS_CONSTRUCTING) ||
608              args.thisv().isObject());
609 
610   JSObject& callee = args.callee();
611   if (callee.is<JSFunction>()) {
612     RootedFunction fun(cx, &callee.as<JSFunction>());
613 
614     if (fun->isNativeFun()) {
615       return CallJSNativeConstructor(cx, fun->native(), args);
616     }
617 
618     if (!InternalCallOrConstruct(cx, args, CONSTRUCT)) {
619       return false;
620     }
621 
622     MOZ_ASSERT(args.CallArgs::rval().isObject());
623     return true;
624   }
625 
626   if (callee.is<ProxyObject>()) {
627     RootedObject proxy(cx, &callee);
628     return Proxy::construct(cx, proxy, args);
629   }
630 
631   JSNative construct = callee.constructHook();
632   MOZ_ASSERT(construct != nullptr, "IsConstructor without a construct hook?");
633 
634   return CallJSNativeConstructor(cx, construct, args);
635 }
636 
637 // Check that |callee|, the callee in a |new| expression, is a constructor.
StackCheckIsConstructorCalleeNewTarget(JSContext * cx,HandleValue callee,HandleValue newTarget)638 static bool StackCheckIsConstructorCalleeNewTarget(JSContext* cx,
639                                                    HandleValue callee,
640                                                    HandleValue newTarget) {
641   // Calls from the stack could have any old non-constructor callee.
642   if (!IsConstructor(callee)) {
643     ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_SEARCH_STACK, callee,
644                      nullptr);
645     return false;
646   }
647 
648   // The new.target has already been vetted by previous calls, or is the callee.
649   // We can just assert that it's a constructor.
650   MOZ_ASSERT(IsConstructor(newTarget));
651 
652   return true;
653 }
654 
ConstructFromStack(JSContext * cx,const CallArgs & args)655 bool js::ConstructFromStack(JSContext* cx, const CallArgs& args) {
656   if (!StackCheckIsConstructorCalleeNewTarget(cx, args.calleev(),
657                                               args.newTarget())) {
658     return false;
659   }
660 
661   return InternalConstruct(cx, static_cast<const AnyConstructArgs&>(args));
662 }
663 
Construct(JSContext * cx,HandleValue fval,const AnyConstructArgs & args,HandleValue newTarget,MutableHandleObject objp)664 bool js::Construct(JSContext* cx, HandleValue fval,
665                    const AnyConstructArgs& args, HandleValue newTarget,
666                    MutableHandleObject objp) {
667   MOZ_ASSERT(args.thisv().isMagic(JS_IS_CONSTRUCTING));
668 
669   // Explicitly qualify to bypass AnyConstructArgs's deliberate shadowing.
670   args.CallArgs::setCallee(fval);
671   args.CallArgs::newTarget().set(newTarget);
672 
673   if (!InternalConstruct(cx, args)) {
674     return false;
675   }
676 
677   MOZ_ASSERT(args.CallArgs::rval().isObject());
678   objp.set(&args.CallArgs::rval().toObject());
679   return true;
680 }
681 
InternalConstructWithProvidedThis(JSContext * cx,HandleValue fval,HandleValue thisv,const AnyConstructArgs & args,HandleValue newTarget,MutableHandleValue rval)682 bool js::InternalConstructWithProvidedThis(JSContext* cx, HandleValue fval,
683                                            HandleValue thisv,
684                                            const AnyConstructArgs& args,
685                                            HandleValue newTarget,
686                                            MutableHandleValue rval) {
687   args.CallArgs::setCallee(fval);
688 
689   MOZ_ASSERT(thisv.isObject());
690   args.CallArgs::setThis(thisv);
691 
692   args.CallArgs::newTarget().set(newTarget);
693 
694   if (!InternalConstruct(cx, args)) {
695     return false;
696   }
697 
698   rval.set(args.CallArgs::rval());
699   return true;
700 }
701 
CallGetter(JSContext * cx,HandleValue thisv,HandleValue getter,MutableHandleValue rval)702 bool js::CallGetter(JSContext* cx, HandleValue thisv, HandleValue getter,
703                     MutableHandleValue rval) {
704   // Invoke could result in another try to get or set the same id again, see
705   // bug 355497.
706   AutoCheckRecursionLimit recursion(cx);
707   if (!recursion.check(cx)) {
708     return false;
709   }
710 
711   FixedInvokeArgs<0> args(cx);
712 
713   return Call(cx, getter, thisv, args, rval, CallReason::Getter);
714 }
715 
CallSetter(JSContext * cx,HandleValue thisv,HandleValue setter,HandleValue v)716 bool js::CallSetter(JSContext* cx, HandleValue thisv, HandleValue setter,
717                     HandleValue v) {
718   AutoCheckRecursionLimit recursion(cx);
719   if (!recursion.check(cx)) {
720     return false;
721   }
722 
723   FixedInvokeArgs<1> args(cx);
724 
725   args[0].set(v);
726 
727   RootedValue ignored(cx);
728   return Call(cx, setter, thisv, args, &ignored, CallReason::Setter);
729 }
730 
ExecuteKernel(JSContext * cx,HandleScript script,HandleObject envChainArg,HandleValue newTargetValue,AbstractFramePtr evalInFrame,MutableHandleValue result)731 bool js::ExecuteKernel(JSContext* cx, HandleScript script,
732                        HandleObject envChainArg, HandleValue newTargetValue,
733                        AbstractFramePtr evalInFrame,
734                        MutableHandleValue result) {
735   MOZ_ASSERT_IF(script->isGlobalCode(),
736                 IsGlobalLexicalEnvironment(envChainArg) ||
737                     !IsSyntacticEnvironment(envChainArg));
738 #ifdef DEBUG
739   RootedObject terminatingEnv(cx, envChainArg);
740   while (IsSyntacticEnvironment(terminatingEnv)) {
741     terminatingEnv = terminatingEnv->enclosingEnvironment();
742   }
743   MOZ_ASSERT(terminatingEnv->is<GlobalObject>() ||
744              script->hasNonSyntacticScope());
745 #endif
746 
747   if (script->treatAsRunOnce()) {
748     if (script->hasRunOnce()) {
749       JS_ReportErrorASCII(cx,
750                           "Trying to execute a run-once script multiple times");
751       return false;
752     }
753 
754     script->setHasRunOnce();
755   }
756 
757   if (script->isEmpty()) {
758     result.setUndefined();
759     return true;
760   }
761 
762   probes::StartExecution(script);
763   ExecuteState state(cx, script, newTargetValue, envChainArg, evalInFrame,
764                      result);
765   bool ok = RunScript(cx, state);
766   probes::StopExecution(script);
767 
768   return ok;
769 }
770 
Execute(JSContext * cx,HandleScript script,HandleObject envChain,MutableHandleValue rval)771 bool js::Execute(JSContext* cx, HandleScript script, HandleObject envChain,
772                  MutableHandleValue rval) {
773   /* The env chain is something we control, so we know it can't
774      have any outer objects on it. */
775   MOZ_ASSERT(!IsWindowProxy(envChain));
776 
777   if (script->isModule()) {
778     MOZ_RELEASE_ASSERT(
779         envChain == script->module()->environment(),
780         "Module scripts can only be executed in the module's environment");
781   } else {
782     MOZ_RELEASE_ASSERT(
783         IsGlobalLexicalEnvironment(envChain) || script->hasNonSyntacticScope(),
784         "Only global scripts with non-syntactic envs can be executed with "
785         "interesting envchains");
786   }
787 
788   /* Ensure the env chain is all same-compartment and terminates in a global. */
789 #ifdef DEBUG
790   JSObject* s = envChain;
791   do {
792     cx->check(s);
793     MOZ_ASSERT_IF(!s->enclosingEnvironment(), s->is<GlobalObject>());
794   } while ((s = s->enclosingEnvironment()));
795 #endif
796 
797   return ExecuteKernel(cx, script, envChain, NullHandleValue,
798                        NullFramePtr() /* evalInFrame */, rval);
799 }
800 
801 /*
802  * ES6 (4-25-16) 12.10.4 InstanceofOperator
803  */
InstanceofOperator(JSContext * cx,HandleObject obj,HandleValue v,bool * bp)804 extern bool JS::InstanceofOperator(JSContext* cx, HandleObject obj,
805                                    HandleValue v, bool* bp) {
806   /* Step 1. is handled by caller. */
807 
808   /* Step 2. */
809   RootedValue hasInstance(cx);
810   RootedId id(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().hasInstance));
811   if (!GetProperty(cx, obj, obj, id, &hasInstance)) {
812     return false;
813   }
814 
815   if (!hasInstance.isNullOrUndefined()) {
816     if (!IsCallable(hasInstance)) {
817       return ReportIsNotFunction(cx, hasInstance);
818     }
819 
820     /* Step 3. */
821     RootedValue rval(cx);
822     if (!Call(cx, hasInstance, obj, v, &rval)) {
823       return false;
824     }
825     *bp = ToBoolean(rval);
826     return true;
827   }
828 
829   /* Step 4. */
830   if (!obj->isCallable()) {
831     RootedValue val(cx, ObjectValue(*obj));
832     return ReportIsNotFunction(cx, val);
833   }
834 
835   /* Step 5. */
836   return OrdinaryHasInstance(cx, obj, v, bp);
837 }
838 
HasInstance(JSContext * cx,HandleObject obj,HandleValue v,bool * bp)839 bool js::HasInstance(JSContext* cx, HandleObject obj, HandleValue v, bool* bp) {
840   const JSClass* clasp = obj->getClass();
841   RootedValue local(cx, v);
842   if (JSHasInstanceOp hasInstance = clasp->getHasInstance()) {
843     return hasInstance(cx, obj, &local, bp);
844   }
845   return JS::InstanceofOperator(cx, obj, local, bp);
846 }
847 
TypeOfObject(JSObject * obj)848 JSType js::TypeOfObject(JSObject* obj) {
849   if (EmulatesUndefined(obj)) {
850     return JSTYPE_UNDEFINED;
851   }
852   if (obj->isCallable()) {
853     return JSTYPE_FUNCTION;
854   }
855   return JSTYPE_OBJECT;
856 }
857 
TypeOfValue(const Value & v)858 JSType js::TypeOfValue(const Value& v) {
859   switch (v.type()) {
860     case ValueType::Double:
861     case ValueType::Int32:
862       return JSTYPE_NUMBER;
863     case ValueType::String:
864       return JSTYPE_STRING;
865     case ValueType::Null:
866       return JSTYPE_OBJECT;
867     case ValueType::Undefined:
868       return JSTYPE_UNDEFINED;
869     case ValueType::Object:
870       return TypeOfObject(&v.toObject());
871     case ValueType::Boolean:
872       return JSTYPE_BOOLEAN;
873     case ValueType::BigInt:
874       return JSTYPE_BIGINT;
875     case ValueType::Symbol:
876       return JSTYPE_SYMBOL;
877     case ValueType::Magic:
878     case ValueType::PrivateGCThing:
879       break;
880   }
881 
882   ReportBadValueTypeAndCrash(v);
883 }
884 
CheckClassHeritageOperation(JSContext * cx,HandleValue heritage)885 bool js::CheckClassHeritageOperation(JSContext* cx, HandleValue heritage) {
886   if (IsConstructor(heritage)) {
887     return true;
888   }
889 
890   if (heritage.isNull()) {
891     return true;
892   }
893 
894   if (heritage.isObject()) {
895     ReportIsNotFunction(cx, heritage, 0, CONSTRUCT);
896     return false;
897   }
898 
899   ReportValueError(cx, JSMSG_BAD_HERITAGE, -1, heritage, nullptr,
900                    "not an object or null");
901   return false;
902 }
903 
ObjectWithProtoOperation(JSContext * cx,HandleValue val)904 PlainObject* js::ObjectWithProtoOperation(JSContext* cx, HandleValue val) {
905   if (!val.isObjectOrNull()) {
906     ReportValueError(cx, JSMSG_NOT_OBJORNULL, -1, val, nullptr);
907     return nullptr;
908   }
909 
910   RootedObject proto(cx, val.toObjectOrNull());
911   return NewObjectWithGivenProto<PlainObject>(cx, proto);
912 }
913 
FunWithProtoOperation(JSContext * cx,HandleFunction fun,HandleObject parent,HandleObject proto)914 JSObject* js::FunWithProtoOperation(JSContext* cx, HandleFunction fun,
915                                     HandleObject parent, HandleObject proto) {
916   return CloneFunctionObject(cx, fun, parent, proto);
917 }
918 
919 /*
920  * Enter the new with environment using an object at sp[-1] and associate the
921  * depth of the with block with sp + stackIndex.
922  */
EnterWithOperation(JSContext * cx,AbstractFramePtr frame,HandleValue val,Handle<WithScope * > scope)923 bool js::EnterWithOperation(JSContext* cx, AbstractFramePtr frame,
924                             HandleValue val, Handle<WithScope*> scope) {
925   RootedObject obj(cx);
926   if (val.isObject()) {
927     obj = &val.toObject();
928   } else {
929     obj = ToObject(cx, val);
930     if (!obj) {
931       return false;
932     }
933   }
934 
935   RootedObject envChain(cx, frame.environmentChain());
936   WithEnvironmentObject* withobj =
937       WithEnvironmentObject::create(cx, obj, envChain, scope);
938   if (!withobj) {
939     return false;
940   }
941 
942   frame.pushOnEnvironmentChain(*withobj);
943   return true;
944 }
945 
PopEnvironment(JSContext * cx,EnvironmentIter & ei)946 static void PopEnvironment(JSContext* cx, EnvironmentIter& ei) {
947   switch (ei.scope().kind()) {
948     case ScopeKind::Lexical:
949     case ScopeKind::SimpleCatch:
950     case ScopeKind::Catch:
951     case ScopeKind::NamedLambda:
952     case ScopeKind::StrictNamedLambda:
953     case ScopeKind::FunctionLexical:
954     case ScopeKind::ClassBody:
955       if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
956         DebugEnvironments::onPopLexical(cx, ei);
957       }
958       if (ei.scope().hasEnvironment()) {
959         ei.initialFrame()
960             .popOffEnvironmentChain<ScopedLexicalEnvironmentObject>();
961       }
962       break;
963     case ScopeKind::With:
964       if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
965         DebugEnvironments::onPopWith(ei.initialFrame());
966       }
967       ei.initialFrame().popOffEnvironmentChain<WithEnvironmentObject>();
968       break;
969     case ScopeKind::Function:
970       if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
971         DebugEnvironments::onPopCall(cx, ei.initialFrame());
972       }
973       if (ei.scope().hasEnvironment()) {
974         ei.initialFrame().popOffEnvironmentChain<CallObject>();
975       }
976       break;
977     case ScopeKind::FunctionBodyVar:
978     case ScopeKind::StrictEval:
979       if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
980         DebugEnvironments::onPopVar(cx, ei);
981       }
982       if (ei.scope().hasEnvironment()) {
983         ei.initialFrame().popOffEnvironmentChain<VarEnvironmentObject>();
984       }
985       break;
986     case ScopeKind::Module:
987       if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
988         DebugEnvironments::onPopModule(cx, ei);
989       }
990       break;
991     case ScopeKind::Eval:
992     case ScopeKind::Global:
993     case ScopeKind::NonSyntactic:
994       break;
995     case ScopeKind::WasmInstance:
996     case ScopeKind::WasmFunction:
997       MOZ_CRASH("wasm is not interpreted");
998       break;
999   }
1000 }
1001 
1002 // Unwind environment chain and iterator to match the env corresponding to
1003 // the given bytecode position.
UnwindEnvironment(JSContext * cx,EnvironmentIter & ei,jsbytecode * pc)1004 void js::UnwindEnvironment(JSContext* cx, EnvironmentIter& ei, jsbytecode* pc) {
1005   if (!ei.withinInitialFrame()) {
1006     return;
1007   }
1008 
1009   RootedScope scope(cx, ei.initialFrame().script()->innermostScope(pc));
1010 
1011 #ifdef DEBUG
1012   // A frame's environment chain cannot be unwound to anything enclosing the
1013   // body scope of a script.  This includes the parameter defaults
1014   // environment and the decl env object. These environments, once pushed
1015   // onto the environment chain, are expected to be there for the duration
1016   // of the frame.
1017   //
1018   // Attempting to unwind to the parameter defaults code in a script is a
1019   // bug; that section of code has no try-catch blocks.
1020   JSScript* script = ei.initialFrame().script();
1021   for (uint32_t i = 0; i < script->bodyScopeIndex(); i++) {
1022     MOZ_ASSERT(scope != script->getScope(GCThingIndex(i)));
1023   }
1024 #endif
1025 
1026   for (; ei.maybeScope() != scope; ei++) {
1027     PopEnvironment(cx, ei);
1028   }
1029 }
1030 
1031 // Unwind all environments. This is needed because block scopes may cover the
1032 // first bytecode at a script's main(). e.g.,
1033 //
1034 //     function f() { { let i = 0; } }
1035 //
1036 // will have no pc location distinguishing the first block scope from the
1037 // outermost function scope.
UnwindAllEnvironmentsInFrame(JSContext * cx,EnvironmentIter & ei)1038 void js::UnwindAllEnvironmentsInFrame(JSContext* cx, EnvironmentIter& ei) {
1039   for (; ei.withinInitialFrame(); ei++) {
1040     PopEnvironment(cx, ei);
1041   }
1042 }
1043 
1044 // Compute the pc needed to unwind the environment to the beginning of a try
1045 // block. We cannot unwind to *after* the JSOp::Try, because that might be the
1046 // first opcode of an inner scope, with the same problem as above. e.g.,
1047 //
1048 // try { { let x; } }
1049 //
1050 // will have no pc location distinguishing the try block scope from the inner
1051 // let block scope.
UnwindEnvironmentToTryPc(JSScript * script,const TryNote * tn)1052 jsbytecode* js::UnwindEnvironmentToTryPc(JSScript* script, const TryNote* tn) {
1053   jsbytecode* pc = script->offsetToPC(tn->start);
1054   if (tn->kind() == TryNoteKind::Catch || tn->kind() == TryNoteKind::Finally) {
1055     pc -= JSOpLength_Try;
1056     MOZ_ASSERT(JSOp(*pc) == JSOp::Try);
1057   } else if (tn->kind() == TryNoteKind::Destructuring) {
1058     pc -= JSOpLength_TryDestructuring;
1059     MOZ_ASSERT(JSOp(*pc) == JSOp::TryDestructuring);
1060   }
1061   return pc;
1062 }
1063 
SettleOnTryNote(JSContext * cx,const TryNote * tn,EnvironmentIter & ei,InterpreterRegs & regs)1064 static void SettleOnTryNote(JSContext* cx, const TryNote* tn,
1065                             EnvironmentIter& ei, InterpreterRegs& regs) {
1066   // Unwind the environment to the beginning of the JSOp::Try.
1067   UnwindEnvironment(cx, ei, UnwindEnvironmentToTryPc(regs.fp()->script(), tn));
1068 
1069   // Set pc to the first bytecode after the the try note to point
1070   // to the beginning of catch or finally.
1071   regs.pc = regs.fp()->script()->offsetToPC(tn->start + tn->length);
1072   regs.sp = regs.spForStackDepth(tn->stackDepth);
1073 }
1074 
1075 class InterpreterTryNoteFilter {
1076   const InterpreterRegs& regs_;
1077 
1078  public:
InterpreterTryNoteFilter(const InterpreterRegs & regs)1079   explicit InterpreterTryNoteFilter(const InterpreterRegs& regs)
1080       : regs_(regs) {}
operator ()(const TryNote * note)1081   bool operator()(const TryNote* note) {
1082     return note->stackDepth <= regs_.stackDepth();
1083   }
1084 };
1085 
1086 class TryNoteIterInterpreter : public TryNoteIter<InterpreterTryNoteFilter> {
1087  public:
TryNoteIterInterpreter(JSContext * cx,const InterpreterRegs & regs)1088   TryNoteIterInterpreter(JSContext* cx, const InterpreterRegs& regs)
1089       : TryNoteIter(cx, regs.fp()->script(), regs.pc,
1090                     InterpreterTryNoteFilter(regs)) {}
1091 };
1092 
UnwindIteratorsForUncatchableException(JSContext * cx,const InterpreterRegs & regs)1093 static void UnwindIteratorsForUncatchableException(
1094     JSContext* cx, const InterpreterRegs& regs) {
1095   // c.f. the regular (catchable) TryNoteIterInterpreter loop in
1096   // ProcessTryNotes.
1097   for (TryNoteIterInterpreter tni(cx, regs); !tni.done(); ++tni) {
1098     const TryNote* tn = *tni;
1099     switch (tn->kind()) {
1100       case TryNoteKind::ForIn: {
1101         Value* sp = regs.spForStackDepth(tn->stackDepth);
1102         UnwindIteratorForUncatchableException(&sp[-1].toObject());
1103         break;
1104       }
1105       default:
1106         break;
1107     }
1108   }
1109 }
1110 
1111 enum HandleErrorContinuation {
1112   SuccessfulReturnContinuation,
1113   ErrorReturnContinuation,
1114   CatchContinuation,
1115   FinallyContinuation
1116 };
1117 
ProcessTryNotes(JSContext * cx,EnvironmentIter & ei,InterpreterRegs & regs)1118 static HandleErrorContinuation ProcessTryNotes(JSContext* cx,
1119                                                EnvironmentIter& ei,
1120                                                InterpreterRegs& regs) {
1121   for (TryNoteIterInterpreter tni(cx, regs); !tni.done(); ++tni) {
1122     const TryNote* tn = *tni;
1123 
1124     switch (tn->kind()) {
1125       case TryNoteKind::Catch:
1126         /* Catch cannot intercept the closing of a generator. */
1127         if (cx->isClosingGenerator()) {
1128           break;
1129         }
1130 
1131         SettleOnTryNote(cx, tn, ei, regs);
1132         return CatchContinuation;
1133 
1134       case TryNoteKind::Finally:
1135         SettleOnTryNote(cx, tn, ei, regs);
1136         return FinallyContinuation;
1137 
1138       case TryNoteKind::ForIn: {
1139         /* This is similar to JSOp::EndIter in the interpreter loop. */
1140         MOZ_ASSERT(tn->stackDepth <= regs.stackDepth());
1141         Value* sp = regs.spForStackDepth(tn->stackDepth);
1142         JSObject* obj = &sp[-1].toObject();
1143         CloseIterator(obj);
1144         break;
1145       }
1146 
1147       case TryNoteKind::Destructuring: {
1148         // Whether the destructuring iterator is done is at the top of the
1149         // stack. The iterator object is second from the top.
1150         MOZ_ASSERT(tn->stackDepth > 1);
1151         Value* sp = regs.spForStackDepth(tn->stackDepth);
1152         RootedValue doneValue(cx, sp[-1]);
1153         MOZ_RELEASE_ASSERT(!doneValue.isMagic());
1154         bool done = ToBoolean(doneValue);
1155         if (!done) {
1156           RootedObject iterObject(cx, &sp[-2].toObject());
1157           if (!IteratorCloseForException(cx, iterObject)) {
1158             SettleOnTryNote(cx, tn, ei, regs);
1159             return ErrorReturnContinuation;
1160           }
1161         }
1162         break;
1163       }
1164 
1165       case TryNoteKind::ForOf:
1166       case TryNoteKind::Loop:
1167         break;
1168 
1169       // TryNoteKind::ForOfIterClose is handled internally by the try note
1170       // iterator.
1171       default:
1172         MOZ_CRASH("Invalid try note");
1173     }
1174   }
1175 
1176   return SuccessfulReturnContinuation;
1177 }
1178 
HandleClosingGeneratorReturn(JSContext * cx,AbstractFramePtr frame,bool ok)1179 bool js::HandleClosingGeneratorReturn(JSContext* cx, AbstractFramePtr frame,
1180                                       bool ok) {
1181   /*
1182    * Propagate the exception or error to the caller unless the exception
1183    * is an asynchronous return from a generator.
1184    */
1185   if (cx->isClosingGenerator()) {
1186     cx->clearPendingException();
1187     ok = true;
1188     auto* genObj = GetGeneratorObjectForFrame(cx, frame);
1189     genObj->setClosed();
1190   }
1191   return ok;
1192 }
1193 
HandleError(JSContext * cx,InterpreterRegs & regs)1194 static HandleErrorContinuation HandleError(JSContext* cx,
1195                                            InterpreterRegs& regs) {
1196   MOZ_ASSERT(regs.fp()->script()->containsPC(regs.pc));
1197   MOZ_ASSERT(cx->realm() == regs.fp()->script()->realm());
1198 
1199   if (regs.fp()->script()->hasScriptCounts()) {
1200     PCCounts* counts = regs.fp()->script()->getThrowCounts(regs.pc);
1201     // If we failed to allocate, then skip the increment and continue to
1202     // handle the exception.
1203     if (counts) {
1204       counts->numExec()++;
1205     }
1206   }
1207 
1208   EnvironmentIter ei(cx, regs.fp(), regs.pc);
1209   bool ok = false;
1210 
1211 again:
1212   if (cx->isExceptionPending()) {
1213     /* Call debugger throw hooks. */
1214     if (!cx->isClosingGenerator()) {
1215       if (!DebugAPI::onExceptionUnwind(cx, regs.fp())) {
1216         if (!cx->isExceptionPending()) {
1217           goto again;
1218         }
1219       }
1220       // Ensure that the debugger hasn't returned 'true' while clearing the
1221       // exception state.
1222       MOZ_ASSERT(cx->isExceptionPending());
1223     }
1224 
1225     HandleErrorContinuation res = ProcessTryNotes(cx, ei, regs);
1226     switch (res) {
1227       case SuccessfulReturnContinuation:
1228         break;
1229       case ErrorReturnContinuation:
1230         goto again;
1231       case CatchContinuation:
1232       case FinallyContinuation:
1233         // No need to increment the PCCounts number of execution here, as
1234         // the interpreter increments any PCCounts if present.
1235         MOZ_ASSERT_IF(regs.fp()->script()->hasScriptCounts(),
1236                       regs.fp()->script()->maybeGetPCCounts(regs.pc));
1237         return res;
1238     }
1239 
1240     ok = HandleClosingGeneratorReturn(cx, regs.fp(), ok);
1241   } else {
1242     UnwindIteratorsForUncatchableException(cx, regs);
1243 
1244     // We may be propagating a forced return from a debugger hook function.
1245     if (MOZ_UNLIKELY(cx->isPropagatingForcedReturn())) {
1246       cx->clearPropagatingForcedReturn();
1247       ok = true;
1248     }
1249   }
1250 
1251   ok = DebugAPI::onLeaveFrame(cx, regs.fp(), regs.pc, ok);
1252 
1253   // After this point, we will pop the frame regardless. Settle the frame on
1254   // the end of the script.
1255   regs.setToEndOfScript();
1256 
1257   return ok ? SuccessfulReturnContinuation : ErrorReturnContinuation;
1258 }
1259 
1260 #define REGS (activation.regs())
1261 #define PUSH_COPY(v)                 \
1262   do {                               \
1263     *REGS.sp++ = (v);                \
1264     cx->debugOnlyCheck(REGS.sp[-1]); \
1265   } while (0)
1266 #define PUSH_COPY_SKIP_CHECK(v) *REGS.sp++ = (v)
1267 #define PUSH_NULL() REGS.sp++->setNull()
1268 #define PUSH_UNDEFINED() REGS.sp++->setUndefined()
1269 #define PUSH_BOOLEAN(b) REGS.sp++->setBoolean(b)
1270 #define PUSH_DOUBLE(d) REGS.sp++->setDouble(d)
1271 #define PUSH_INT32(i) REGS.sp++->setInt32(i)
1272 #define PUSH_SYMBOL(s) REGS.sp++->setSymbol(s)
1273 #define PUSH_BIGINT(b) REGS.sp++->setBigInt(b)
1274 #define PUSH_STRING(s)               \
1275   do {                               \
1276     REGS.sp++->setString(s);         \
1277     cx->debugOnlyCheck(REGS.sp[-1]); \
1278   } while (0)
1279 #define PUSH_OBJECT(obj)             \
1280   do {                               \
1281     REGS.sp++->setObject(obj);       \
1282     cx->debugOnlyCheck(REGS.sp[-1]); \
1283   } while (0)
1284 #define PUSH_OBJECT_OR_NULL(obj)     \
1285   do {                               \
1286     REGS.sp++->setObjectOrNull(obj); \
1287     cx->debugOnlyCheck(REGS.sp[-1]); \
1288   } while (0)
1289 #define PUSH_MAGIC(magic) REGS.sp++->setMagic(magic)
1290 #define POP_COPY_TO(v) (v) = *--REGS.sp
1291 #define POP_RETURN_VALUE() REGS.fp()->setReturnValue(*--REGS.sp)
1292 
1293 /*
1294  * Same for JSOp::SetName and JSOp::SetProp, which differ only slightly but
1295  * remain distinct for the decompiler.
1296  */
1297 static_assert(JSOpLength_SetName == JSOpLength_SetProp);
1298 
1299 /* See TRY_BRANCH_AFTER_COND. */
1300 static_assert(JSOpLength_JumpIfTrue == JSOpLength_JumpIfFalse);
1301 static_assert(uint8_t(JSOp::JumpIfTrue) == uint8_t(JSOp::JumpIfFalse) + 1);
1302 
1303 /*
1304  * Compute the implicit |this| value used by a call expression with an
1305  * unqualified name reference. The environment the binding was found on is
1306  * passed as argument, env.
1307  *
1308  * The implicit |this| is |undefined| for all environment types except
1309  * WithEnvironmentObject. This is the case for |with(...) {...}| expressions or
1310  * if the embedding uses a non-syntactic WithEnvironmentObject.
1311  *
1312  * NOTE: A non-syntactic WithEnvironmentObject may have a corresponding
1313  * extensible LexicalEnviornmentObject, but it will not be considered as an
1314  * implicit |this|. This is for compatibility with the Gecko subscript loader.
1315  */
ComputeImplicitThis(JSObject * env)1316 static inline Value ComputeImplicitThis(JSObject* env) {
1317   // Fast-path for GlobalObject
1318   if (env->is<GlobalObject>()) {
1319     return UndefinedValue();
1320   }
1321 
1322   // WithEnvironmentObjects have an actual implicit |this|
1323   if (env->is<WithEnvironmentObject>()) {
1324     return ObjectValue(*GetThisObjectOfWith(env));
1325   }
1326 
1327   // Debugger environments need special casing, as despite being
1328   // non-syntactic, they wrap syntactic environments and should not be
1329   // treated like other embedding-specific non-syntactic environments.
1330   if (env->is<DebugEnvironmentProxy>()) {
1331     return ComputeImplicitThis(&env->as<DebugEnvironmentProxy>().environment());
1332   }
1333 
1334   MOZ_ASSERT(env->is<EnvironmentObject>());
1335   return UndefinedValue();
1336 }
1337 
AddOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)1338 static MOZ_ALWAYS_INLINE bool AddOperation(JSContext* cx,
1339                                            MutableHandleValue lhs,
1340                                            MutableHandleValue rhs,
1341                                            MutableHandleValue res) {
1342   if (lhs.isInt32() && rhs.isInt32()) {
1343     int32_t l = lhs.toInt32(), r = rhs.toInt32();
1344     int32_t t;
1345     if (MOZ_LIKELY(SafeAdd(l, r, &t))) {
1346       res.setInt32(t);
1347       return true;
1348     }
1349   }
1350 
1351   if (!ToPrimitive(cx, lhs)) {
1352     return false;
1353   }
1354   if (!ToPrimitive(cx, rhs)) {
1355     return false;
1356   }
1357 
1358   bool lIsString = lhs.isString();
1359   bool rIsString = rhs.isString();
1360   if (lIsString || rIsString) {
1361     JSString* lstr;
1362     if (lIsString) {
1363       lstr = lhs.toString();
1364     } else {
1365       lstr = ToString<CanGC>(cx, lhs);
1366       if (!lstr) {
1367         return false;
1368       }
1369     }
1370 
1371     JSString* rstr;
1372     if (rIsString) {
1373       rstr = rhs.toString();
1374     } else {
1375       // Save/restore lstr in case of GC activity under ToString.
1376       lhs.setString(lstr);
1377       rstr = ToString<CanGC>(cx, rhs);
1378       if (!rstr) {
1379         return false;
1380       }
1381       lstr = lhs.toString();
1382     }
1383     JSString* str = ConcatStrings<NoGC>(cx, lstr, rstr);
1384     if (!str) {
1385       RootedString nlstr(cx, lstr), nrstr(cx, rstr);
1386       str = ConcatStrings<CanGC>(cx, nlstr, nrstr);
1387       if (!str) {
1388         return false;
1389       }
1390     }
1391     res.setString(str);
1392     return true;
1393   }
1394 
1395   if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1396     return false;
1397   }
1398 
1399   if (lhs.isBigInt() || rhs.isBigInt()) {
1400     return BigInt::addValue(cx, lhs, rhs, res);
1401   }
1402 
1403   res.setNumber(lhs.toNumber() + rhs.toNumber());
1404   return true;
1405 }
1406 
SubOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)1407 static MOZ_ALWAYS_INLINE bool SubOperation(JSContext* cx,
1408                                            MutableHandleValue lhs,
1409                                            MutableHandleValue rhs,
1410                                            MutableHandleValue res) {
1411   if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1412     return false;
1413   }
1414 
1415   if (lhs.isBigInt() || rhs.isBigInt()) {
1416     return BigInt::subValue(cx, lhs, rhs, res);
1417   }
1418 
1419   res.setNumber(lhs.toNumber() - rhs.toNumber());
1420   return true;
1421 }
1422 
MulOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)1423 static MOZ_ALWAYS_INLINE bool MulOperation(JSContext* cx,
1424                                            MutableHandleValue lhs,
1425                                            MutableHandleValue rhs,
1426                                            MutableHandleValue res) {
1427   if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1428     return false;
1429   }
1430 
1431   if (lhs.isBigInt() || rhs.isBigInt()) {
1432     return BigInt::mulValue(cx, lhs, rhs, res);
1433   }
1434 
1435   res.setNumber(lhs.toNumber() * rhs.toNumber());
1436   return true;
1437 }
1438 
DivOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)1439 static MOZ_ALWAYS_INLINE bool DivOperation(JSContext* cx,
1440                                            MutableHandleValue lhs,
1441                                            MutableHandleValue rhs,
1442                                            MutableHandleValue res) {
1443   if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1444     return false;
1445   }
1446 
1447   if (lhs.isBigInt() || rhs.isBigInt()) {
1448     return BigInt::divValue(cx, lhs, rhs, res);
1449   }
1450 
1451   res.setNumber(NumberDiv(lhs.toNumber(), rhs.toNumber()));
1452   return true;
1453 }
1454 
ModOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)1455 static MOZ_ALWAYS_INLINE bool ModOperation(JSContext* cx,
1456                                            MutableHandleValue lhs,
1457                                            MutableHandleValue rhs,
1458                                            MutableHandleValue res) {
1459   int32_t l, r;
1460   if (lhs.isInt32() && rhs.isInt32() && (l = lhs.toInt32()) >= 0 &&
1461       (r = rhs.toInt32()) > 0) {
1462     int32_t mod = l % r;
1463     res.setInt32(mod);
1464     return true;
1465   }
1466 
1467   if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1468     return false;
1469   }
1470 
1471   if (lhs.isBigInt() || rhs.isBigInt()) {
1472     return BigInt::modValue(cx, lhs, rhs, res);
1473   }
1474 
1475   res.setNumber(NumberMod(lhs.toNumber(), rhs.toNumber()));
1476   return true;
1477 }
1478 
PowOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)1479 static MOZ_ALWAYS_INLINE bool PowOperation(JSContext* cx,
1480                                            MutableHandleValue lhs,
1481                                            MutableHandleValue rhs,
1482                                            MutableHandleValue res) {
1483   if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1484     return false;
1485   }
1486 
1487   if (lhs.isBigInt() || rhs.isBigInt()) {
1488     return BigInt::powValue(cx, lhs, rhs, res);
1489   }
1490 
1491   res.setNumber(ecmaPow(lhs.toNumber(), rhs.toNumber()));
1492   return true;
1493 }
1494 
BitNotOperation(JSContext * cx,MutableHandleValue in,MutableHandleValue out)1495 static MOZ_ALWAYS_INLINE bool BitNotOperation(JSContext* cx,
1496                                               MutableHandleValue in,
1497                                               MutableHandleValue out) {
1498   if (!ToInt32OrBigInt(cx, in)) {
1499     return false;
1500   }
1501 
1502   if (in.isBigInt()) {
1503     return BigInt::bitNotValue(cx, in, out);
1504   }
1505 
1506   out.setInt32(~in.toInt32());
1507   return true;
1508 }
1509 
BitXorOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue out)1510 static MOZ_ALWAYS_INLINE bool BitXorOperation(JSContext* cx,
1511                                               MutableHandleValue lhs,
1512                                               MutableHandleValue rhs,
1513                                               MutableHandleValue out) {
1514   if (!ToInt32OrBigInt(cx, lhs) || !ToInt32OrBigInt(cx, rhs)) {
1515     return false;
1516   }
1517 
1518   if (lhs.isBigInt() || rhs.isBigInt()) {
1519     return BigInt::bitXorValue(cx, lhs, rhs, out);
1520   }
1521 
1522   out.setInt32(lhs.toInt32() ^ rhs.toInt32());
1523   return true;
1524 }
1525 
BitOrOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue out)1526 static MOZ_ALWAYS_INLINE bool BitOrOperation(JSContext* cx,
1527                                              MutableHandleValue lhs,
1528                                              MutableHandleValue rhs,
1529                                              MutableHandleValue out) {
1530   if (!ToInt32OrBigInt(cx, lhs) || !ToInt32OrBigInt(cx, rhs)) {
1531     return false;
1532   }
1533 
1534   if (lhs.isBigInt() || rhs.isBigInt()) {
1535     return BigInt::bitOrValue(cx, lhs, rhs, out);
1536   }
1537 
1538   out.setInt32(lhs.toInt32() | rhs.toInt32());
1539   return true;
1540 }
1541 
BitAndOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue out)1542 static MOZ_ALWAYS_INLINE bool BitAndOperation(JSContext* cx,
1543                                               MutableHandleValue lhs,
1544                                               MutableHandleValue rhs,
1545                                               MutableHandleValue out) {
1546   if (!ToInt32OrBigInt(cx, lhs) || !ToInt32OrBigInt(cx, rhs)) {
1547     return false;
1548   }
1549 
1550   if (lhs.isBigInt() || rhs.isBigInt()) {
1551     return BigInt::bitAndValue(cx, lhs, rhs, out);
1552   }
1553 
1554   out.setInt32(lhs.toInt32() & rhs.toInt32());
1555   return true;
1556 }
1557 
BitLshOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue out)1558 static MOZ_ALWAYS_INLINE bool BitLshOperation(JSContext* cx,
1559                                               MutableHandleValue lhs,
1560                                               MutableHandleValue rhs,
1561                                               MutableHandleValue out) {
1562   if (!ToInt32OrBigInt(cx, lhs) || !ToInt32OrBigInt(cx, rhs)) {
1563     return false;
1564   }
1565 
1566   if (lhs.isBigInt() || rhs.isBigInt()) {
1567     return BigInt::lshValue(cx, lhs, rhs, out);
1568   }
1569 
1570   // Signed left-shift is undefined on overflow, so |lhs << (rhs & 31)| won't
1571   // work.  Instead, convert to unsigned space (where overflow is treated
1572   // modularly), perform the operation there, then convert back.
1573   uint32_t left = static_cast<uint32_t>(lhs.toInt32());
1574   uint8_t right = rhs.toInt32() & 31;
1575   out.setInt32(mozilla::WrapToSigned(left << right));
1576   return true;
1577 }
1578 
BitRshOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue out)1579 static MOZ_ALWAYS_INLINE bool BitRshOperation(JSContext* cx,
1580                                               MutableHandleValue lhs,
1581                                               MutableHandleValue rhs,
1582                                               MutableHandleValue out) {
1583   if (!ToInt32OrBigInt(cx, lhs) || !ToInt32OrBigInt(cx, rhs)) {
1584     return false;
1585   }
1586 
1587   if (lhs.isBigInt() || rhs.isBigInt()) {
1588     return BigInt::rshValue(cx, lhs, rhs, out);
1589   }
1590 
1591   out.setInt32(lhs.toInt32() >> (rhs.toInt32() & 31));
1592   return true;
1593 }
1594 
UrshOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue out)1595 static MOZ_ALWAYS_INLINE bool UrshOperation(JSContext* cx,
1596                                             MutableHandleValue lhs,
1597                                             MutableHandleValue rhs,
1598                                             MutableHandleValue out) {
1599   if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1600     return false;
1601   }
1602 
1603   if (lhs.isBigInt() || rhs.isBigInt()) {
1604     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
1605                               JSMSG_BIGINT_TO_NUMBER);
1606     return false;
1607   }
1608 
1609   uint32_t left;
1610   int32_t right;
1611   if (!ToUint32(cx, lhs, &left) || !ToInt32(cx, rhs, &right)) {
1612     return false;
1613   }
1614   left >>= right & 31;
1615   out.setNumber(uint32_t(left));
1616   return true;
1617 }
1618 
1619 // BigInt proposal 3.2.4 Abstract Relational Comparison
1620 // Returns Nothing when at least one operand is a NaN, or when
1621 // ToNumeric or StringToBigInt can't interpret a string as a numeric
1622 // value. (These cases correspond to a NaN result in the spec.)
1623 // Otherwise, return a boolean to indicate whether lhs is less than
1624 // rhs. The operands must be primitives; the caller is responsible for
1625 // evaluating them in the correct order.
LessThanImpl(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,mozilla::Maybe<bool> & res)1626 static MOZ_ALWAYS_INLINE bool LessThanImpl(JSContext* cx,
1627                                            MutableHandleValue lhs,
1628                                            MutableHandleValue rhs,
1629                                            mozilla::Maybe<bool>& res) {
1630   // Steps 1 and 2 are performed by the caller.
1631 
1632   // Step 3.
1633   if (lhs.isString() && rhs.isString()) {
1634     JSString* l = lhs.toString();
1635     JSString* r = rhs.toString();
1636     int32_t result;
1637     if (!CompareStrings(cx, l, r, &result)) {
1638       return false;
1639     }
1640     res = mozilla::Some(result < 0);
1641     return true;
1642   }
1643 
1644   // Step 4a.
1645   if (lhs.isBigInt() && rhs.isString()) {
1646     return BigInt::lessThan(cx, lhs, rhs, res);
1647   }
1648 
1649   // Step 4b.
1650   if (lhs.isString() && rhs.isBigInt()) {
1651     return BigInt::lessThan(cx, lhs, rhs, res);
1652   }
1653 
1654   // Steps 4c and 4d.
1655   if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1656     return false;
1657   }
1658 
1659   // Steps 4e-j.
1660   if (lhs.isBigInt() || rhs.isBigInt()) {
1661     return BigInt::lessThan(cx, lhs, rhs, res);
1662   }
1663 
1664   // Step 4e for Number operands.
1665   MOZ_ASSERT(lhs.isNumber() && rhs.isNumber());
1666   double lhsNum = lhs.toNumber();
1667   double rhsNum = rhs.toNumber();
1668 
1669   if (mozilla::IsNaN(lhsNum) || mozilla::IsNaN(rhsNum)) {
1670     res = mozilla::Maybe<bool>(mozilla::Nothing());
1671     return true;
1672   }
1673 
1674   res = mozilla::Some(lhsNum < rhsNum);
1675   return true;
1676 }
1677 
LessThanOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,bool * res)1678 static MOZ_ALWAYS_INLINE bool LessThanOperation(JSContext* cx,
1679                                                 MutableHandleValue lhs,
1680                                                 MutableHandleValue rhs,
1681                                                 bool* res) {
1682   if (lhs.isInt32() && rhs.isInt32()) {
1683     *res = lhs.toInt32() < rhs.toInt32();
1684     return true;
1685   }
1686 
1687   if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
1688     return false;
1689   }
1690 
1691   if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
1692     return false;
1693   }
1694 
1695   mozilla::Maybe<bool> tmpResult;
1696   if (!LessThanImpl(cx, lhs, rhs, tmpResult)) {
1697     return false;
1698   }
1699   *res = tmpResult.valueOr(false);
1700   return true;
1701 }
1702 
LessThanOrEqualOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,bool * res)1703 static MOZ_ALWAYS_INLINE bool LessThanOrEqualOperation(JSContext* cx,
1704                                                        MutableHandleValue lhs,
1705                                                        MutableHandleValue rhs,
1706                                                        bool* res) {
1707   if (lhs.isInt32() && rhs.isInt32()) {
1708     *res = lhs.toInt32() <= rhs.toInt32();
1709     return true;
1710   }
1711 
1712   if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
1713     return false;
1714   }
1715 
1716   if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
1717     return false;
1718   }
1719 
1720   mozilla::Maybe<bool> tmpResult;
1721   if (!LessThanImpl(cx, rhs, lhs, tmpResult)) {
1722     return false;
1723   }
1724   *res = !tmpResult.valueOr(true);
1725   return true;
1726 }
1727 
GreaterThanOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,bool * res)1728 static MOZ_ALWAYS_INLINE bool GreaterThanOperation(JSContext* cx,
1729                                                    MutableHandleValue lhs,
1730                                                    MutableHandleValue rhs,
1731                                                    bool* res) {
1732   if (lhs.isInt32() && rhs.isInt32()) {
1733     *res = lhs.toInt32() > rhs.toInt32();
1734     return true;
1735   }
1736 
1737   if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
1738     return false;
1739   }
1740 
1741   if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
1742     return false;
1743   }
1744 
1745   mozilla::Maybe<bool> tmpResult;
1746   if (!LessThanImpl(cx, rhs, lhs, tmpResult)) {
1747     return false;
1748   }
1749   *res = tmpResult.valueOr(false);
1750   return true;
1751 }
1752 
GreaterThanOrEqualOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,bool * res)1753 static MOZ_ALWAYS_INLINE bool GreaterThanOrEqualOperation(
1754     JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res) {
1755   if (lhs.isInt32() && rhs.isInt32()) {
1756     *res = lhs.toInt32() >= rhs.toInt32();
1757     return true;
1758   }
1759 
1760   if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
1761     return false;
1762   }
1763 
1764   if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
1765     return false;
1766   }
1767 
1768   mozilla::Maybe<bool> tmpResult;
1769   if (!LessThanImpl(cx, lhs, rhs, tmpResult)) {
1770     return false;
1771   }
1772   *res = !tmpResult.valueOr(true);
1773   return true;
1774 }
1775 
SetObjectElementOperation(JSContext * cx,HandleObject obj,HandleId id,HandleValue value,HandleValue receiver,bool strict)1776 static MOZ_ALWAYS_INLINE bool SetObjectElementOperation(
1777     JSContext* cx, HandleObject obj, HandleId id, HandleValue value,
1778     HandleValue receiver, bool strict) {
1779   ObjectOpResult result;
1780   return SetProperty(cx, obj, id, value, receiver, result) &&
1781          result.checkStrictModeError(cx, obj, id, strict);
1782 }
1783 
InitElemArrayOperation(JSContext * cx,jsbytecode * pc,HandleArrayObject arr,HandleValue val)1784 static MOZ_ALWAYS_INLINE void InitElemArrayOperation(JSContext* cx,
1785                                                      jsbytecode* pc,
1786                                                      HandleArrayObject arr,
1787                                                      HandleValue val) {
1788   MOZ_ASSERT(JSOp(*pc) == JSOp::InitElemArray);
1789 
1790   // The dense elements must have been initialized up to this index. The JIT
1791   // implementation also depends on this.
1792   uint32_t index = GET_UINT32(pc);
1793   MOZ_ASSERT(index < arr->getDenseCapacity());
1794   MOZ_ASSERT(index == arr->getDenseInitializedLength());
1795 
1796   // Bump the initialized length even for hole values to ensure the
1797   // index == initLength invariant holds for later InitElemArray ops.
1798   arr->setDenseInitializedLength(index + 1);
1799 
1800   if (val.isMagic(JS_ELEMENTS_HOLE)) {
1801     arr->initDenseElementHole(index);
1802   } else {
1803     arr->initDenseElement(index, val);
1804   }
1805 }
1806 
1807 /*
1808  * As an optimization, the interpreter creates a handful of reserved Rooted<T>
1809  * variables at the beginning, thus inserting them into the Rooted list once
1810  * upon entry. ReservedRooted "borrows" a reserved Rooted variable and uses it
1811  * within a local scope, resetting the value to nullptr (or the appropriate
1812  * equivalent for T) at scope end. This avoids inserting/removing the Rooted
1813  * from the rooter list, while preventing stale values from being kept alive
1814  * unnecessarily.
1815  */
1816 
1817 template <typename T>
1818 class ReservedRooted : public RootedBase<T, ReservedRooted<T>> {
1819   Rooted<T>* savedRoot;
1820 
1821  public:
ReservedRooted(Rooted<T> * root,const T & ptr)1822   ReservedRooted(Rooted<T>* root, const T& ptr) : savedRoot(root) {
1823     *root = ptr;
1824   }
1825 
ReservedRooted(Rooted<T> * root)1826   explicit ReservedRooted(Rooted<T>* root) : savedRoot(root) {
1827     *root = JS::SafelyInitialized<T>();
1828   }
1829 
~ReservedRooted()1830   ~ReservedRooted() { *savedRoot = JS::SafelyInitialized<T>(); }
1831 
set(const T & p) const1832   void set(const T& p) const { *savedRoot = p; }
operator Handle<T>()1833   operator Handle<T>() { return *savedRoot; }
operator Rooted<T>&()1834   operator Rooted<T>&() { return *savedRoot; }
operator &()1835   MutableHandle<T> operator&() { return &*savedRoot; }
1836 
1837   DECLARE_NONPOINTER_ACCESSOR_METHODS(savedRoot->get())
1838   DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(savedRoot->get())
1839   DECLARE_POINTER_CONSTREF_OPS(T)
1840   DECLARE_POINTER_ASSIGN_OPS(ReservedRooted, T)
1841 };
1842 
ReportInNotObjectError(JSContext * cx,HandleValue lref,HandleValue rref)1843 void js::ReportInNotObjectError(JSContext* cx, HandleValue lref,
1844                                 HandleValue rref) {
1845   auto uniqueCharsFromString = [](JSContext* cx,
1846                                   HandleValue ref) -> UniqueChars {
1847     static const size_t MaxStringLength = 16;
1848     RootedString str(cx, ref.toString());
1849     if (str->length() > MaxStringLength) {
1850       JSStringBuilder buf(cx);
1851       if (!buf.appendSubstring(str, 0, MaxStringLength)) {
1852         return nullptr;
1853       }
1854       if (!buf.append("...")) {
1855         return nullptr;
1856       }
1857       str = buf.finishString();
1858       if (!str) {
1859         return nullptr;
1860       }
1861     }
1862     return QuoteString(cx, str, '"');
1863   };
1864 
1865   if (lref.isString() && rref.isString()) {
1866     UniqueChars lbytes = uniqueCharsFromString(cx, lref);
1867     if (!lbytes) {
1868       return;
1869     }
1870     UniqueChars rbytes = uniqueCharsFromString(cx, rref);
1871     if (!rbytes) {
1872       return;
1873     }
1874     JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_IN_STRING,
1875                              lbytes.get(), rbytes.get());
1876     return;
1877   }
1878 
1879   JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_IN_NOT_OBJECT,
1880                             InformalValueTypeName(rref));
1881 }
1882 
Interpret(JSContext * cx,RunState & state)1883 static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
1884                                                               RunState& state) {
1885 /*
1886  * Define macros for an interpreter loop. Opcode dispatch is done by
1887  * indirect goto (aka a threaded interpreter), which is technically
1888  * non-standard but is supported by all of our supported compilers.
1889  */
1890 #define INTERPRETER_LOOP()
1891 #define CASE(OP) label_##OP:
1892 #define DEFAULT() \
1893   label_default:
1894 #define DISPATCH_TO(OP) goto* addresses[(OP)]
1895 
1896 #define LABEL(X) (&&label_##X)
1897 
1898   // Use addresses instead of offsets to optimize for runtime speed over
1899   // load-time relocation overhead.
1900   static const void* const addresses[EnableInterruptsPseudoOpcode + 1] = {
1901 #define OPCODE_LABEL(op, ...) LABEL(op),
1902       FOR_EACH_OPCODE(OPCODE_LABEL)
1903 #undef OPCODE_LABEL
1904 #define TRAILING_LABEL(v)                                                    \
1905   ((v) == EnableInterruptsPseudoOpcode ? LABEL(EnableInterruptsPseudoOpcode) \
1906                                        : LABEL(default)),
1907           FOR_EACH_TRAILING_UNUSED_OPCODE(TRAILING_LABEL)
1908 #undef TRAILING_LABEL
1909   };
1910 
1911   /*
1912    * Increment REGS.pc by N, load the opcode at that position,
1913    * and jump to the code to execute it.
1914    *
1915    * When Debugger puts a script in single-step mode, all js::Interpret
1916    * invocations that might be presently running that script must have
1917    * interrupts enabled. It's not practical to simply check
1918    * script->stepModeEnabled() at each point some callee could have changed
1919    * it, because there are so many places js::Interpret could possibly cause
1920    * JavaScript to run: each place an object might be coerced to a primitive
1921    * or a number, for example. So instead, we expose a simple mechanism to
1922    * let Debugger tweak the affected js::Interpret frames when an onStep
1923    * handler is added: calling activation.enableInterruptsUnconditionally()
1924    * will enable interrupts, and activation.opMask() is or'd with the opcode
1925    * to implement a simple alternate dispatch.
1926    */
1927 #define ADVANCE_AND_DISPATCH(N)                  \
1928   JS_BEGIN_MACRO                                 \
1929     REGS.pc += (N);                              \
1930     SANITY_CHECKS();                             \
1931     DISPATCH_TO(*REGS.pc | activation.opMask()); \
1932   JS_END_MACRO
1933 
1934   /*
1935    * Shorthand for the common sequence at the end of a fixed-size opcode.
1936    */
1937 #define END_CASE(OP) ADVANCE_AND_DISPATCH(JSOpLength_##OP);
1938 
1939   /*
1940    * Prepare to call a user-supplied branch handler, and abort the script
1941    * if it returns false.
1942    */
1943 #define CHECK_BRANCH()                      \
1944   JS_BEGIN_MACRO                            \
1945     if (!CheckForInterrupt(cx)) goto error; \
1946   JS_END_MACRO
1947 
1948   /*
1949    * This is a simple wrapper around ADVANCE_AND_DISPATCH which also does
1950    * a CHECK_BRANCH() if n is not positive, which possibly indicates that it
1951    * is the backedge of a loop.
1952    */
1953 #define BRANCH(n)                  \
1954   JS_BEGIN_MACRO                   \
1955     int32_t nlen = (n);            \
1956     if (nlen <= 0) CHECK_BRANCH(); \
1957     ADVANCE_AND_DISPATCH(nlen);    \
1958   JS_END_MACRO
1959 
1960   /*
1961    * Initialize code coverage vectors.
1962    */
1963 #define INIT_COVERAGE()                                \
1964   JS_BEGIN_MACRO                                       \
1965     if (!script->hasScriptCounts()) {                  \
1966       if (cx->realm()->collectCoverageForDebug()) {    \
1967         if (!script->initScriptCounts(cx)) goto error; \
1968       }                                                \
1969     }                                                  \
1970   JS_END_MACRO
1971 
1972   /*
1973    * Increment the code coverage counter associated with the given pc.
1974    */
1975 #define COUNT_COVERAGE_PC(PC)                          \
1976   JS_BEGIN_MACRO                                       \
1977     if (script->hasScriptCounts()) {                   \
1978       PCCounts* counts = script->maybeGetPCCounts(PC); \
1979       MOZ_ASSERT(counts);                              \
1980       counts->numExec()++;                             \
1981     }                                                  \
1982   JS_END_MACRO
1983 
1984 #define COUNT_COVERAGE_MAIN()                                        \
1985   JS_BEGIN_MACRO                                                     \
1986     jsbytecode* main = script->main();                               \
1987     if (!BytecodeIsJumpTarget(JSOp(*main))) COUNT_COVERAGE_PC(main); \
1988   JS_END_MACRO
1989 
1990 #define COUNT_COVERAGE()                              \
1991   JS_BEGIN_MACRO                                      \
1992     MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*REGS.pc))); \
1993     COUNT_COVERAGE_PC(REGS.pc);                       \
1994   JS_END_MACRO
1995 
1996 #define SET_SCRIPT(s)                                    \
1997   JS_BEGIN_MACRO                                         \
1998     script = (s);                                        \
1999     MOZ_ASSERT(cx->realm() == script->realm());          \
2000     if (DebugAPI::hasAnyBreakpointsOrStepMode(script) || \
2001         script->hasScriptCounts())                       \
2002       activation.enableInterruptsUnconditionally();      \
2003   JS_END_MACRO
2004 
2005 #define SANITY_CHECKS()              \
2006   JS_BEGIN_MACRO                     \
2007     js::gc::MaybeVerifyBarriers(cx); \
2008   JS_END_MACRO
2009 
2010 // Verify that an uninitialized lexical is followed by a correct check op.
2011 #ifdef DEBUG
2012 #  define ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val)                        \
2013     JS_BEGIN_MACRO                                                         \
2014       if (IsUninitializedLexical(val)) {                                   \
2015         JSOp next = JSOp(*GetNextPc(REGS.pc));                             \
2016         MOZ_ASSERT(next == JSOp::CheckThis || next == JSOp::CheckReturn || \
2017                    next == JSOp::CheckThisReinit ||                        \
2018                    next == JSOp::CheckAliasedLexical);                     \
2019       }                                                                    \
2020     JS_END_MACRO
2021 #else
2022 #  define ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val) \
2023     JS_BEGIN_MACRO                                  \
2024     /* nothing */                                   \
2025     JS_END_MACRO
2026 #endif
2027 
2028   gc::MaybeVerifyBarriers(cx, true);
2029 
2030   InterpreterFrame* entryFrame = state.pushInterpreterFrame(cx);
2031   if (!entryFrame) {
2032     return false;
2033   }
2034 
2035   ActivationEntryMonitor entryMonitor(cx, entryFrame);
2036   InterpreterActivation activation(state, cx, entryFrame);
2037 
2038   /* The script is used frequently, so keep a local copy. */
2039   RootedScript script(cx);
2040   SET_SCRIPT(REGS.fp()->script());
2041 
2042   TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
2043   TraceLoggerEvent scriptEvent(TraceLogger_Scripts, script);
2044   TraceLogStartEvent(logger, scriptEvent);
2045   TraceLogStartEvent(logger, TraceLogger_Interpreter);
2046 
2047   /*
2048    * Pool of rooters for use in this interpreter frame. References to these
2049    * are used for local variables within interpreter cases. This avoids
2050    * creating new rooters each time an interpreter case is entered, and also
2051    * correctness pitfalls due to incorrect compilation of destructor calls
2052    * around computed gotos.
2053    */
2054   RootedValue rootValue0(cx), rootValue1(cx);
2055   RootedString rootString0(cx), rootString1(cx);
2056   RootedObject rootObject0(cx), rootObject1(cx), rootObject2(cx);
2057   RootedNativeObject rootNativeObject0(cx);
2058   RootedFunction rootFunction0(cx);
2059   RootedPropertyName rootName0(cx);
2060   RootedId rootId0(cx);
2061   RootedShape rootShape0(cx);
2062   RootedScript rootScript0(cx);
2063   Rooted<Scope*> rootScope0(cx);
2064   DebugOnly<uint32_t> blockDepth;
2065 
2066   /* State communicated between non-local jumps: */
2067   bool interpReturnOK;
2068   bool frameHalfInitialized;
2069 
2070   if (!activation.entryFrame()->prologue(cx)) {
2071     goto prologue_error;
2072   }
2073 
2074   if (!DebugAPI::onEnterFrame(cx, activation.entryFrame())) {
2075     goto error;
2076   }
2077 
2078   // Increment the coverage for the main entry point.
2079   INIT_COVERAGE();
2080   COUNT_COVERAGE_MAIN();
2081 
2082   // Enter the interpreter loop starting at the current pc.
2083   ADVANCE_AND_DISPATCH(0);
2084 
2085   INTERPRETER_LOOP() {
2086     CASE(EnableInterruptsPseudoOpcode) {
2087       bool moreInterrupts = false;
2088       jsbytecode op = *REGS.pc;
2089 
2090       if (!script->hasScriptCounts() &&
2091           cx->realm()->collectCoverageForDebug()) {
2092         if (!script->initScriptCounts(cx)) {
2093           goto error;
2094         }
2095       }
2096 
2097       if (script->isDebuggee()) {
2098         if (DebugAPI::stepModeEnabled(script)) {
2099           if (!DebugAPI::onSingleStep(cx)) {
2100             goto error;
2101           }
2102           moreInterrupts = true;
2103         }
2104 
2105         if (DebugAPI::hasAnyBreakpointsOrStepMode(script)) {
2106           moreInterrupts = true;
2107         }
2108 
2109         if (DebugAPI::hasBreakpointsAt(script, REGS.pc)) {
2110           if (!DebugAPI::onTrap(cx)) {
2111             goto error;
2112           }
2113         }
2114       }
2115 
2116       MOZ_ASSERT(activation.opMask() == EnableInterruptsPseudoOpcode);
2117       if (!moreInterrupts) {
2118         activation.clearInterruptsMask();
2119       }
2120 
2121       /* Commence executing the actual opcode. */
2122       SANITY_CHECKS();
2123       DISPATCH_TO(op);
2124     }
2125 
2126     /* Various 1-byte no-ops. */
2127     CASE(Nop)
2128     CASE(Try)
2129     CASE(NopDestructuring)
2130     CASE(TryDestructuring) {
2131       MOZ_ASSERT(GetBytecodeLength(REGS.pc) == 1);
2132       ADVANCE_AND_DISPATCH(1);
2133     }
2134 
2135     CASE(JumpTarget)
2136     COUNT_COVERAGE();
2137     END_CASE(JumpTarget)
2138 
2139     CASE(LoopHead) {
2140       COUNT_COVERAGE();
2141 
2142       // Attempt on-stack replacement into the Baseline Interpreter.
2143       if (jit::IsBaselineInterpreterEnabled()) {
2144         script->incWarmUpCounter();
2145 
2146         jit::MethodStatus status =
2147             jit::CanEnterBaselineInterpreterAtBranch(cx, REGS.fp());
2148         if (status == jit::Method_Error) {
2149           goto error;
2150         }
2151         if (status == jit::Method_Compiled) {
2152           bool wasProfiler = REGS.fp()->hasPushedGeckoProfilerFrame();
2153 
2154           jit::JitExecStatus maybeOsr;
2155           {
2156             GeckoProfilerBaselineOSRMarker osr(cx, wasProfiler);
2157             maybeOsr =
2158                 jit::EnterBaselineInterpreterAtBranch(cx, REGS.fp(), REGS.pc);
2159           }
2160 
2161           // We failed to call into baseline at all, so treat as an error.
2162           if (maybeOsr == jit::JitExec_Aborted) {
2163             goto error;
2164           }
2165 
2166           interpReturnOK = (maybeOsr == jit::JitExec_Ok);
2167 
2168           // Pop the profiler frame pushed by the interpreter.  (The compiled
2169           // version of the function popped a copy of the frame pushed by the
2170           // OSR trampoline.)
2171           if (wasProfiler) {
2172             cx->geckoProfiler().exit(cx, script);
2173           }
2174 
2175           if (activation.entryFrame() != REGS.fp()) {
2176             goto jit_return_pop_frame;
2177           }
2178           goto leave_on_safe_point;
2179         }
2180       }
2181     }
2182     END_CASE(LoopHead)
2183 
2184     CASE(Lineno)
2185     END_CASE(Lineno)
2186 
2187     CASE(ForceInterpreter) {
2188       // Ensure pattern matching still works.
2189       MOZ_ASSERT(script->hasForceInterpreterOp());
2190     }
2191     END_CASE(ForceInterpreter)
2192 
2193     CASE(Undefined) {
2194       // If this ever changes, change what JSOp::GImplicitThis does too.
2195       PUSH_UNDEFINED();
2196     }
2197     END_CASE(Undefined)
2198 
2199     CASE(Pop) { REGS.sp--; }
2200     END_CASE(Pop)
2201 
2202     CASE(PopN) {
2203       MOZ_ASSERT(GET_UINT16(REGS.pc) <= REGS.stackDepth());
2204       REGS.sp -= GET_UINT16(REGS.pc);
2205     }
2206     END_CASE(PopN)
2207 
2208     CASE(DupAt) {
2209       MOZ_ASSERT(GET_UINT24(REGS.pc) < REGS.stackDepth());
2210       unsigned i = GET_UINT24(REGS.pc);
2211       const Value& rref = REGS.sp[-int(i + 1)];
2212       PUSH_COPY(rref);
2213     }
2214     END_CASE(DupAt)
2215 
2216     CASE(SetRval) { POP_RETURN_VALUE(); }
2217     END_CASE(SetRval)
2218 
2219     CASE(GetRval) { PUSH_COPY(REGS.fp()->returnValue()); }
2220     END_CASE(GetRval)
2221 
2222     CASE(EnterWith) {
2223       ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
2224       REGS.sp--;
2225       ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
2226 
2227       if (!EnterWithOperation(cx, REGS.fp(), val, scope.as<WithScope>())) {
2228         goto error;
2229       }
2230     }
2231     END_CASE(EnterWith)
2232 
2233     CASE(LeaveWith) {
2234       REGS.fp()->popOffEnvironmentChain<WithEnvironmentObject>();
2235     }
2236     END_CASE(LeaveWith)
2237 
2238     CASE(Return) {
2239       POP_RETURN_VALUE();
2240       /* FALL THROUGH */
2241     }
2242     CASE(RetRval) {
2243       /*
2244        * When the inlined frame exits with an exception or an error, ok will be
2245        * false after the inline_return label.
2246        */
2247       CHECK_BRANCH();
2248 
2249     successful_return_continuation:
2250       interpReturnOK = true;
2251 
2252     return_continuation:
2253       frameHalfInitialized = false;
2254 
2255     prologue_return_continuation:
2256 
2257       if (activation.entryFrame() != REGS.fp()) {
2258         // Stop the engine. (No details about which engine exactly, could be
2259         // interpreter, Baseline or IonMonkey.)
2260         TraceLogStopEvent(logger, TraceLogger_Engine);
2261         TraceLogStopEvent(logger, TraceLogger_Scripts);
2262 
2263         if (MOZ_LIKELY(!frameHalfInitialized)) {
2264           interpReturnOK =
2265               DebugAPI::onLeaveFrame(cx, REGS.fp(), REGS.pc, interpReturnOK);
2266 
2267           REGS.fp()->epilogue(cx, REGS.pc);
2268         }
2269 
2270       jit_return_pop_frame:
2271 
2272         activation.popInlineFrame(REGS.fp());
2273         {
2274           JSScript* callerScript = REGS.fp()->script();
2275           if (cx->realm() != callerScript->realm()) {
2276             cx->leaveRealm(callerScript->realm());
2277           }
2278           SET_SCRIPT(callerScript);
2279         }
2280 
2281       jit_return:
2282 
2283         MOZ_ASSERT(IsInvokePC(REGS.pc));
2284         MOZ_ASSERT(cx->realm() == script->realm());
2285 
2286         /* Resume execution in the calling frame. */
2287         if (MOZ_LIKELY(interpReturnOK)) {
2288           if (JSOp(*REGS.pc) == JSOp::Resume) {
2289             ADVANCE_AND_DISPATCH(JSOpLength_Resume);
2290           }
2291 
2292           MOZ_ASSERT(GetBytecodeLength(REGS.pc) == JSOpLength_Call);
2293           ADVANCE_AND_DISPATCH(JSOpLength_Call);
2294         }
2295 
2296         goto error;
2297       } else {
2298         // Stack should be empty for the outer frame, unless we executed the
2299         // first |await| expression in an async function.
2300         MOZ_ASSERT(REGS.stackDepth() == 0 ||
2301                    (JSOp(*REGS.pc) == JSOp::Await &&
2302                     !REGS.fp()->isResumedGenerator()));
2303       }
2304       goto exit;
2305     }
2306 
2307     CASE(Default) {
2308       REGS.sp--;
2309       /* FALL THROUGH */
2310     }
2311     CASE(Goto) { BRANCH(GET_JUMP_OFFSET(REGS.pc)); }
2312 
2313     CASE(JumpIfFalse) {
2314       bool cond = ToBoolean(REGS.stackHandleAt(-1));
2315       REGS.sp--;
2316       if (!cond) {
2317         BRANCH(GET_JUMP_OFFSET(REGS.pc));
2318       }
2319     }
2320     END_CASE(JumpIfFalse)
2321 
2322     CASE(JumpIfTrue) {
2323       bool cond = ToBoolean(REGS.stackHandleAt(-1));
2324       REGS.sp--;
2325       if (cond) {
2326         BRANCH(GET_JUMP_OFFSET(REGS.pc));
2327       }
2328     }
2329     END_CASE(JumpIfTrue)
2330 
2331     CASE(Or) {
2332       bool cond = ToBoolean(REGS.stackHandleAt(-1));
2333       if (cond) {
2334         ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
2335       }
2336     }
2337     END_CASE(Or)
2338 
2339     CASE(Coalesce) {
2340       MutableHandleValue res = REGS.stackHandleAt(-1);
2341       bool cond = !res.isNullOrUndefined();
2342       if (cond) {
2343         ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
2344       }
2345     }
2346     END_CASE(Coalesce)
2347 
2348     CASE(And) {
2349       bool cond = ToBoolean(REGS.stackHandleAt(-1));
2350       if (!cond) {
2351         ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
2352       }
2353     }
2354     END_CASE(And)
2355 
2356 #define FETCH_ELEMENT_ID(n, id)                                       \
2357   JS_BEGIN_MACRO                                                      \
2358     if (!ToPropertyKey(cx, REGS.stackHandleAt(n), &(id))) goto error; \
2359   JS_END_MACRO
2360 
2361 #define TRY_BRANCH_AFTER_COND(cond, spdec)                          \
2362   JS_BEGIN_MACRO                                                    \
2363     MOZ_ASSERT(GetBytecodeLength(REGS.pc) == 1);                    \
2364     unsigned diff_ =                                                \
2365         (unsigned)GET_UINT8(REGS.pc) - (unsigned)JSOp::JumpIfFalse; \
2366     if (diff_ <= 1) {                                               \
2367       REGS.sp -= (spdec);                                           \
2368       if ((cond) == (diff_ != 0)) {                                 \
2369         ++REGS.pc;                                                  \
2370         BRANCH(GET_JUMP_OFFSET(REGS.pc));                           \
2371       }                                                             \
2372       ADVANCE_AND_DISPATCH(1 + JSOpLength_JumpIfFalse);             \
2373     }                                                               \
2374   JS_END_MACRO
2375 
2376     CASE(In) {
2377       HandleValue rref = REGS.stackHandleAt(-1);
2378       if (!rref.isObject()) {
2379         HandleValue lref = REGS.stackHandleAt(-2);
2380         ReportInNotObjectError(cx, lref, rref);
2381         goto error;
2382       }
2383       bool found;
2384       {
2385         ReservedRooted<JSObject*> obj(&rootObject0, &rref.toObject());
2386         ReservedRooted<jsid> id(&rootId0);
2387         FETCH_ELEMENT_ID(-2, id);
2388         if (!HasProperty(cx, obj, id, &found)) {
2389           goto error;
2390         }
2391       }
2392       TRY_BRANCH_AFTER_COND(found, 2);
2393       REGS.sp--;
2394       REGS.sp[-1].setBoolean(found);
2395     }
2396     END_CASE(In)
2397 
2398     CASE(HasOwn) {
2399       HandleValue val = REGS.stackHandleAt(-1);
2400       HandleValue idval = REGS.stackHandleAt(-2);
2401 
2402       bool found;
2403       if (!HasOwnProperty(cx, val, idval, &found)) {
2404         goto error;
2405       }
2406 
2407       REGS.sp--;
2408       REGS.sp[-1].setBoolean(found);
2409     }
2410     END_CASE(HasOwn)
2411 
2412     CASE(CheckPrivateField) {
2413       /* Load the object being initialized into lval/val. */
2414       HandleValue val = REGS.stackHandleAt(-2);
2415       HandleValue idval = REGS.stackHandleAt(-1);
2416 
2417       bool result = false;
2418       if (!CheckPrivateFieldOperation(cx, REGS.pc, val, idval, &result)) {
2419         goto error;
2420       }
2421 
2422       PUSH_BOOLEAN(result);
2423     }
2424     END_CASE(CheckPrivateField)
2425 
2426     CASE(Iter) {
2427       MOZ_ASSERT(REGS.stackDepth() >= 1);
2428       HandleValue val = REGS.stackHandleAt(-1);
2429       JSObject* iter = ValueToIterator(cx, val);
2430       if (!iter) {
2431         goto error;
2432       }
2433       REGS.sp[-1].setObject(*iter);
2434     }
2435     END_CASE(Iter)
2436 
2437     CASE(MoreIter) {
2438       MOZ_ASSERT(REGS.stackDepth() >= 1);
2439       MOZ_ASSERT(REGS.sp[-1].isObject());
2440       Value v = IteratorMore(&REGS.sp[-1].toObject());
2441       PUSH_COPY(v);
2442     }
2443     END_CASE(MoreIter)
2444 
2445     CASE(IsNoIter) {
2446       bool b = REGS.sp[-1].isMagic(JS_NO_ITER_VALUE);
2447       PUSH_BOOLEAN(b);
2448     }
2449     END_CASE(IsNoIter)
2450 
2451     CASE(EndIter) {
2452       MOZ_ASSERT(REGS.stackDepth() >= 2);
2453       CloseIterator(&REGS.sp[-2].toObject());
2454       REGS.sp -= 2;
2455     }
2456     END_CASE(EndIter)
2457 
2458     CASE(IsGenClosing) {
2459       bool b = REGS.sp[-1].isMagic(JS_GENERATOR_CLOSING);
2460       PUSH_BOOLEAN(b);
2461     }
2462     END_CASE(IsGenClosing)
2463 
2464     CASE(Dup) {
2465       MOZ_ASSERT(REGS.stackDepth() >= 1);
2466       const Value& rref = REGS.sp[-1];
2467       PUSH_COPY(rref);
2468     }
2469     END_CASE(Dup)
2470 
2471     CASE(Dup2) {
2472       MOZ_ASSERT(REGS.stackDepth() >= 2);
2473       const Value& lref = REGS.sp[-2];
2474       const Value& rref = REGS.sp[-1];
2475       PUSH_COPY(lref);
2476       PUSH_COPY(rref);
2477     }
2478     END_CASE(Dup2)
2479 
2480     CASE(Swap) {
2481       MOZ_ASSERT(REGS.stackDepth() >= 2);
2482       Value& lref = REGS.sp[-2];
2483       Value& rref = REGS.sp[-1];
2484       lref.swap(rref);
2485     }
2486     END_CASE(Swap)
2487 
2488     CASE(Pick) {
2489       unsigned i = GET_UINT8(REGS.pc);
2490       MOZ_ASSERT(REGS.stackDepth() >= i + 1);
2491       Value lval = REGS.sp[-int(i + 1)];
2492       memmove(REGS.sp - (i + 1), REGS.sp - i, sizeof(Value) * i);
2493       REGS.sp[-1] = lval;
2494     }
2495     END_CASE(Pick)
2496 
2497     CASE(Unpick) {
2498       int i = GET_UINT8(REGS.pc);
2499       MOZ_ASSERT(REGS.stackDepth() >= unsigned(i) + 1);
2500       Value lval = REGS.sp[-1];
2501       memmove(REGS.sp - i, REGS.sp - (i + 1), sizeof(Value) * i);
2502       REGS.sp[-(i + 1)] = lval;
2503     }
2504     END_CASE(Unpick)
2505 
2506     CASE(BindGName)
2507     CASE(BindName) {
2508       JSOp op = JSOp(*REGS.pc);
2509       ReservedRooted<JSObject*> envChain(&rootObject0);
2510       if (op == JSOp::BindName || script->hasNonSyntacticScope()) {
2511         envChain.set(REGS.fp()->environmentChain());
2512       } else {
2513         envChain.set(&REGS.fp()->global().lexicalEnvironment());
2514       }
2515       ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
2516 
2517       // Assigning to an undeclared name adds a property to the global object.
2518       ReservedRooted<JSObject*> env(&rootObject1);
2519       if (!LookupNameUnqualified(cx, name, envChain, &env)) {
2520         goto error;
2521       }
2522 
2523       PUSH_OBJECT(*env);
2524 
2525       static_assert(JSOpLength_BindName == JSOpLength_BindGName,
2526                     "We're sharing the END_CASE so the lengths better match");
2527     }
2528     END_CASE(BindName)
2529 
2530     CASE(BindVar) {
2531       JSObject* varObj = BindVarOperation(cx, REGS.fp()->environmentChain());
2532       PUSH_OBJECT(*varObj);
2533     }
2534     END_CASE(BindVar)
2535 
2536     CASE(BitOr) {
2537       MutableHandleValue lhs = REGS.stackHandleAt(-2);
2538       MutableHandleValue rhs = REGS.stackHandleAt(-1);
2539       MutableHandleValue res = REGS.stackHandleAt(-2);
2540       if (!BitOrOperation(cx, lhs, rhs, res)) {
2541         goto error;
2542       }
2543       REGS.sp--;
2544     }
2545     END_CASE(BitOr)
2546 
2547     CASE(BitXor) {
2548       MutableHandleValue lhs = REGS.stackHandleAt(-2);
2549       MutableHandleValue rhs = REGS.stackHandleAt(-1);
2550       MutableHandleValue res = REGS.stackHandleAt(-2);
2551       if (!BitXorOperation(cx, lhs, rhs, res)) {
2552         goto error;
2553       }
2554       REGS.sp--;
2555     }
2556     END_CASE(BitXor)
2557 
2558     CASE(BitAnd) {
2559       MutableHandleValue lhs = REGS.stackHandleAt(-2);
2560       MutableHandleValue rhs = REGS.stackHandleAt(-1);
2561       MutableHandleValue res = REGS.stackHandleAt(-2);
2562       if (!BitAndOperation(cx, lhs, rhs, res)) {
2563         goto error;
2564       }
2565       REGS.sp--;
2566     }
2567     END_CASE(BitAnd)
2568 
2569     CASE(Eq) {
2570       if (!LooseEqualityOp<true>(cx, REGS)) {
2571         goto error;
2572       }
2573     }
2574     END_CASE(Eq)
2575 
2576     CASE(Ne) {
2577       if (!LooseEqualityOp<false>(cx, REGS)) {
2578         goto error;
2579       }
2580     }
2581     END_CASE(Ne)
2582 
2583 #define STRICT_EQUALITY_OP(OP, COND)                  \
2584   JS_BEGIN_MACRO                                      \
2585     HandleValue lval = REGS.stackHandleAt(-2);        \
2586     HandleValue rval = REGS.stackHandleAt(-1);        \
2587     bool equal;                                       \
2588     if (!js::StrictlyEqual(cx, lval, rval, &equal)) { \
2589       goto error;                                     \
2590     }                                                 \
2591     (COND) = equal OP true;                           \
2592     REGS.sp--;                                        \
2593   JS_END_MACRO
2594 
2595     CASE(StrictEq) {
2596       bool cond;
2597       STRICT_EQUALITY_OP(==, cond);
2598       REGS.sp[-1].setBoolean(cond);
2599     }
2600     END_CASE(StrictEq)
2601 
2602     CASE(StrictNe) {
2603       bool cond;
2604       STRICT_EQUALITY_OP(!=, cond);
2605       REGS.sp[-1].setBoolean(cond);
2606     }
2607     END_CASE(StrictNe)
2608 
2609 #undef STRICT_EQUALITY_OP
2610 
2611     CASE(Case) {
2612       bool cond = REGS.sp[-1].toBoolean();
2613       REGS.sp--;
2614       if (cond) {
2615         REGS.sp--;
2616         BRANCH(GET_JUMP_OFFSET(REGS.pc));
2617       }
2618     }
2619     END_CASE(Case)
2620 
2621     CASE(Lt) {
2622       bool cond;
2623       MutableHandleValue lval = REGS.stackHandleAt(-2);
2624       MutableHandleValue rval = REGS.stackHandleAt(-1);
2625       if (!LessThanOperation(cx, lval, rval, &cond)) {
2626         goto error;
2627       }
2628       TRY_BRANCH_AFTER_COND(cond, 2);
2629       REGS.sp[-2].setBoolean(cond);
2630       REGS.sp--;
2631     }
2632     END_CASE(Lt)
2633 
2634     CASE(Le) {
2635       bool cond;
2636       MutableHandleValue lval = REGS.stackHandleAt(-2);
2637       MutableHandleValue rval = REGS.stackHandleAt(-1);
2638       if (!LessThanOrEqualOperation(cx, lval, rval, &cond)) {
2639         goto error;
2640       }
2641       TRY_BRANCH_AFTER_COND(cond, 2);
2642       REGS.sp[-2].setBoolean(cond);
2643       REGS.sp--;
2644     }
2645     END_CASE(Le)
2646 
2647     CASE(Gt) {
2648       bool cond;
2649       MutableHandleValue lval = REGS.stackHandleAt(-2);
2650       MutableHandleValue rval = REGS.stackHandleAt(-1);
2651       if (!GreaterThanOperation(cx, lval, rval, &cond)) {
2652         goto error;
2653       }
2654       TRY_BRANCH_AFTER_COND(cond, 2);
2655       REGS.sp[-2].setBoolean(cond);
2656       REGS.sp--;
2657     }
2658     END_CASE(Gt)
2659 
2660     CASE(Ge) {
2661       bool cond;
2662       MutableHandleValue lval = REGS.stackHandleAt(-2);
2663       MutableHandleValue rval = REGS.stackHandleAt(-1);
2664       if (!GreaterThanOrEqualOperation(cx, lval, rval, &cond)) {
2665         goto error;
2666       }
2667       TRY_BRANCH_AFTER_COND(cond, 2);
2668       REGS.sp[-2].setBoolean(cond);
2669       REGS.sp--;
2670     }
2671     END_CASE(Ge)
2672 
2673     CASE(Lsh) {
2674       MutableHandleValue lhs = REGS.stackHandleAt(-2);
2675       MutableHandleValue rhs = REGS.stackHandleAt(-1);
2676       MutableHandleValue res = REGS.stackHandleAt(-2);
2677       if (!BitLshOperation(cx, lhs, rhs, res)) {
2678         goto error;
2679       }
2680       REGS.sp--;
2681     }
2682     END_CASE(Lsh)
2683 
2684     CASE(Rsh) {
2685       MutableHandleValue lhs = REGS.stackHandleAt(-2);
2686       MutableHandleValue rhs = REGS.stackHandleAt(-1);
2687       MutableHandleValue res = REGS.stackHandleAt(-2);
2688       if (!BitRshOperation(cx, lhs, rhs, res)) {
2689         goto error;
2690       }
2691       REGS.sp--;
2692     }
2693     END_CASE(Rsh)
2694 
2695     CASE(Ursh) {
2696       MutableHandleValue lhs = REGS.stackHandleAt(-2);
2697       MutableHandleValue rhs = REGS.stackHandleAt(-1);
2698       MutableHandleValue res = REGS.stackHandleAt(-2);
2699       if (!UrshOperation(cx, lhs, rhs, res)) {
2700         goto error;
2701       }
2702       REGS.sp--;
2703     }
2704     END_CASE(Ursh)
2705 
2706     CASE(Add) {
2707       MutableHandleValue lval = REGS.stackHandleAt(-2);
2708       MutableHandleValue rval = REGS.stackHandleAt(-1);
2709       MutableHandleValue res = REGS.stackHandleAt(-2);
2710       if (!AddOperation(cx, lval, rval, res)) {
2711         goto error;
2712       }
2713       REGS.sp--;
2714     }
2715     END_CASE(Add)
2716 
2717     CASE(Sub) {
2718       ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
2719       ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
2720       MutableHandleValue res = REGS.stackHandleAt(-2);
2721       if (!SubOperation(cx, &lval, &rval, res)) {
2722         goto error;
2723       }
2724       REGS.sp--;
2725     }
2726     END_CASE(Sub)
2727 
2728     CASE(Mul) {
2729       ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
2730       ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
2731       MutableHandleValue res = REGS.stackHandleAt(-2);
2732       if (!MulOperation(cx, &lval, &rval, res)) {
2733         goto error;
2734       }
2735       REGS.sp--;
2736     }
2737     END_CASE(Mul)
2738 
2739     CASE(Div) {
2740       ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
2741       ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
2742       MutableHandleValue res = REGS.stackHandleAt(-2);
2743       if (!DivOperation(cx, &lval, &rval, res)) {
2744         goto error;
2745       }
2746       REGS.sp--;
2747     }
2748     END_CASE(Div)
2749 
2750     CASE(Mod) {
2751       ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
2752       ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
2753       MutableHandleValue res = REGS.stackHandleAt(-2);
2754       if (!ModOperation(cx, &lval, &rval, res)) {
2755         goto error;
2756       }
2757       REGS.sp--;
2758     }
2759     END_CASE(Mod)
2760 
2761     CASE(Pow) {
2762       ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
2763       ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
2764       MutableHandleValue res = REGS.stackHandleAt(-2);
2765       if (!PowOperation(cx, &lval, &rval, res)) {
2766         goto error;
2767       }
2768       REGS.sp--;
2769     }
2770     END_CASE(Pow)
2771 
2772     CASE(Not) {
2773       bool cond = ToBoolean(REGS.stackHandleAt(-1));
2774       REGS.sp--;
2775       PUSH_BOOLEAN(!cond);
2776     }
2777     END_CASE(Not)
2778 
2779     CASE(BitNot) {
2780       MutableHandleValue val = REGS.stackHandleAt(-1);
2781       if (!BitNotOperation(cx, val, val)) {
2782         goto error;
2783       }
2784     }
2785     END_CASE(BitNot)
2786 
2787     CASE(Neg) {
2788       MutableHandleValue val = REGS.stackHandleAt(-1);
2789       if (!NegOperation(cx, val, val)) {
2790         goto error;
2791       }
2792     }
2793     END_CASE(Neg)
2794 
2795     CASE(Pos) {
2796       if (!ToNumber(cx, REGS.stackHandleAt(-1))) {
2797         goto error;
2798       }
2799     }
2800     END_CASE(Pos)
2801 
2802     CASE(DelName) {
2803       ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
2804       ReservedRooted<JSObject*> envObj(&rootObject0,
2805                                        REGS.fp()->environmentChain());
2806 
2807       PUSH_BOOLEAN(true);
2808       MutableHandleValue res = REGS.stackHandleAt(-1);
2809       if (!DeleteNameOperation(cx, name, envObj, res)) {
2810         goto error;
2811       }
2812     }
2813     END_CASE(DelName)
2814 
2815     CASE(DelProp)
2816     CASE(StrictDelProp) {
2817       static_assert(JSOpLength_DelProp == JSOpLength_StrictDelProp,
2818                     "delprop and strictdelprop must be the same size");
2819       HandleValue val = REGS.stackHandleAt(-1);
2820       ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
2821       bool res = false;
2822       if (JSOp(*REGS.pc) == JSOp::StrictDelProp) {
2823         if (!DelPropOperation<true>(cx, val, name, &res)) {
2824           goto error;
2825         }
2826       } else {
2827         if (!DelPropOperation<false>(cx, val, name, &res)) {
2828           goto error;
2829         }
2830       }
2831       REGS.sp[-1].setBoolean(res);
2832     }
2833     END_CASE(DelProp)
2834 
2835     CASE(DelElem)
2836     CASE(StrictDelElem) {
2837       static_assert(JSOpLength_DelElem == JSOpLength_StrictDelElem,
2838                     "delelem and strictdelelem must be the same size");
2839       HandleValue val = REGS.stackHandleAt(-2);
2840       HandleValue propval = REGS.stackHandleAt(-1);
2841       bool res = false;
2842       if (JSOp(*REGS.pc) == JSOp::StrictDelElem) {
2843         if (!DelElemOperation<true>(cx, val, propval, &res)) {
2844           goto error;
2845         }
2846       } else {
2847         if (!DelElemOperation<false>(cx, val, propval, &res)) {
2848           goto error;
2849         }
2850       }
2851       REGS.sp[-2].setBoolean(res);
2852       REGS.sp--;
2853     }
2854     END_CASE(DelElem)
2855 
2856     CASE(ToPropertyKey) {
2857       ReservedRooted<Value> idval(&rootValue1, REGS.sp[-1]);
2858       MutableHandleValue res = REGS.stackHandleAt(-1);
2859       if (!ToPropertyKeyOperation(cx, idval, res)) {
2860         goto error;
2861       }
2862     }
2863     END_CASE(ToPropertyKey)
2864 
2865     CASE(TypeofExpr)
2866     CASE(Typeof) {
2867       REGS.sp[-1].setString(TypeOfOperation(REGS.sp[-1], cx->runtime()));
2868     }
2869     END_CASE(Typeof)
2870 
2871     CASE(Void) { REGS.sp[-1].setUndefined(); }
2872     END_CASE(Void)
2873 
2874     CASE(FunctionThis) {
2875       PUSH_NULL();
2876       if (!GetFunctionThis(cx, REGS.fp(), REGS.stackHandleAt(-1))) {
2877         goto error;
2878       }
2879     }
2880     END_CASE(FunctionThis)
2881 
2882     CASE(GlobalThis) {
2883       if (script->hasNonSyntacticScope()) {
2884         PUSH_NULL();
2885         GetNonSyntacticGlobalThis(cx, REGS.fp()->environmentChain(),
2886                                   REGS.stackHandleAt(-1));
2887       } else {
2888         PUSH_OBJECT(*cx->global()->lexicalEnvironment().thisObject());
2889       }
2890     }
2891     END_CASE(GlobalThis)
2892 
2893     CASE(CheckIsObj) {
2894       if (!REGS.sp[-1].isObject()) {
2895         MOZ_ALWAYS_FALSE(
2896             ThrowCheckIsObject(cx, CheckIsObjectKind(GET_UINT8(REGS.pc))));
2897         goto error;
2898       }
2899     }
2900     END_CASE(CheckIsObj)
2901 
2902     CASE(CheckThis) {
2903       if (REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
2904         MOZ_ALWAYS_FALSE(ThrowUninitializedThis(cx));
2905         goto error;
2906       }
2907     }
2908     END_CASE(CheckThis)
2909 
2910     CASE(CheckThisReinit) {
2911       if (!REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
2912         MOZ_ALWAYS_FALSE(ThrowInitializedThis(cx));
2913         goto error;
2914       }
2915     }
2916     END_CASE(CheckThisReinit)
2917 
2918     CASE(CheckReturn) {
2919       if (!REGS.fp()->checkReturn(cx, REGS.stackHandleAt(-1))) {
2920         goto error;
2921       }
2922       REGS.sp--;
2923     }
2924     END_CASE(CheckReturn)
2925 
2926     CASE(GetProp) {
2927       MutableHandleValue lval = REGS.stackHandleAt(-1);
2928       if (!GetPropertyOperation(cx, REGS.fp(), script, REGS.pc, lval, lval)) {
2929         goto error;
2930       }
2931       cx->debugOnlyCheck(lval);
2932     }
2933     END_CASE(GetProp)
2934 
2935     CASE(GetPropSuper) {
2936       ReservedRooted<Value> receiver(&rootValue0, REGS.sp[-2]);
2937       ReservedRooted<JSObject*> obj(&rootObject1, &REGS.sp[-1].toObject());
2938       MutableHandleValue rref = REGS.stackHandleAt(-2);
2939 
2940       if (!GetProperty(cx, obj, receiver, script->getName(REGS.pc), rref)) {
2941         goto error;
2942       }
2943 
2944       cx->debugOnlyCheck(rref);
2945 
2946       REGS.sp--;
2947     }
2948     END_CASE(GetPropSuper)
2949 
2950     CASE(GetBoundName) {
2951       ReservedRooted<JSObject*> env(&rootObject0, &REGS.sp[-1].toObject());
2952       ReservedRooted<jsid> id(&rootId0, NameToId(script->getName(REGS.pc)));
2953       MutableHandleValue rval = REGS.stackHandleAt(-1);
2954       if (!GetNameBoundInEnvironment(cx, env, id, rval)) {
2955         goto error;
2956       }
2957       cx->debugOnlyCheck(rval);
2958     }
2959     END_CASE(GetBoundName)
2960 
2961     CASE(SetIntrinsic) {
2962       HandleValue value = REGS.stackHandleAt(-1);
2963 
2964       if (!SetIntrinsicOperation(cx, script, REGS.pc, value)) {
2965         goto error;
2966       }
2967     }
2968     END_CASE(SetIntrinsic)
2969 
2970     CASE(SetGName)
2971     CASE(StrictSetGName)
2972     CASE(SetName)
2973     CASE(StrictSetName) {
2974       static_assert(JSOpLength_SetName == JSOpLength_StrictSetName,
2975                     "setname and strictsetname must be the same size");
2976       static_assert(JSOpLength_SetGName == JSOpLength_StrictSetGName,
2977                     "setganem adn strictsetgname must be the same size");
2978       static_assert(JSOpLength_SetName == JSOpLength_SetGName,
2979                     "We're sharing the END_CASE so the lengths better match");
2980 
2981       ReservedRooted<JSObject*> env(&rootObject0, &REGS.sp[-2].toObject());
2982       HandleValue value = REGS.stackHandleAt(-1);
2983 
2984       if (!SetNameOperation(cx, script, REGS.pc, env, value)) {
2985         goto error;
2986       }
2987 
2988       REGS.sp[-2] = REGS.sp[-1];
2989       REGS.sp--;
2990     }
2991     END_CASE(SetName)
2992 
2993     CASE(SetProp)
2994     CASE(StrictSetProp) {
2995       static_assert(JSOpLength_SetProp == JSOpLength_StrictSetProp,
2996                     "setprop and strictsetprop must be the same size");
2997       int lvalIndex = -2;
2998       HandleValue lval = REGS.stackHandleAt(lvalIndex);
2999       HandleValue rval = REGS.stackHandleAt(-1);
3000 
3001       ReservedRooted<jsid> id(&rootId0, NameToId(script->getName(REGS.pc)));
3002       if (!SetPropertyOperation(cx, JSOp(*REGS.pc), lval, lvalIndex, id,
3003                                 rval)) {
3004         goto error;
3005       }
3006 
3007       REGS.sp[-2] = REGS.sp[-1];
3008       REGS.sp--;
3009     }
3010     END_CASE(SetProp)
3011 
3012     CASE(SetPropSuper)
3013     CASE(StrictSetPropSuper) {
3014       static_assert(
3015           JSOpLength_SetPropSuper == JSOpLength_StrictSetPropSuper,
3016           "setprop-super and strictsetprop-super must be the same size");
3017 
3018       ReservedRooted<Value> receiver(&rootValue0, REGS.sp[-3]);
3019       ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
3020       ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
3021       ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
3022 
3023       bool strict = JSOp(*REGS.pc) == JSOp::StrictSetPropSuper;
3024 
3025       if (!SetPropertySuper(cx, obj, receiver, name, rval, strict)) {
3026         goto error;
3027       }
3028 
3029       REGS.sp[-3] = REGS.sp[-1];
3030       REGS.sp -= 2;
3031     }
3032     END_CASE(SetPropSuper)
3033 
3034     CASE(GetElem) {
3035       int lvalIndex = -2;
3036       MutableHandleValue lval = REGS.stackHandleAt(lvalIndex);
3037       HandleValue rval = REGS.stackHandleAt(-1);
3038       MutableHandleValue res = REGS.stackHandleAt(-2);
3039 
3040       if (!GetElementOperationWithStackIndex(cx, lval, lvalIndex, rval, res)) {
3041         goto error;
3042       }
3043 
3044       REGS.sp--;
3045     }
3046     END_CASE(GetElem)
3047 
3048     CASE(GetElemSuper) {
3049       ReservedRooted<Value> receiver(&rootValue1, REGS.sp[-3]);
3050       ReservedRooted<Value> rval(&rootValue0, REGS.sp[-2]);
3051       ReservedRooted<JSObject*> obj(&rootObject1, &REGS.sp[-1].toObject());
3052 
3053       MutableHandleValue res = REGS.stackHandleAt(-3);
3054 
3055       // Since we have asserted that obj has to be an object, it cannot be
3056       // either optimized arguments, or indeed any primitive. This simplifies
3057       // our task some.
3058       if (!GetObjectElementOperation(cx, JSOp(*REGS.pc), obj, receiver, rval,
3059                                      res)) {
3060         goto error;
3061       }
3062 
3063       REGS.sp -= 2;
3064     }
3065     END_CASE(GetElemSuper)
3066 
3067     CASE(SetElem)
3068     CASE(StrictSetElem) {
3069       static_assert(JSOpLength_SetElem == JSOpLength_StrictSetElem,
3070                     "setelem and strictsetelem must be the same size");
3071       int receiverIndex = -3;
3072       HandleValue receiver = REGS.stackHandleAt(receiverIndex);
3073       ReservedRooted<JSObject*> obj(&rootObject0);
3074       obj = ToObjectFromStackForPropertyAccess(cx, receiver, receiverIndex,
3075                                                REGS.stackHandleAt(-2));
3076       if (!obj) {
3077         goto error;
3078       }
3079       ReservedRooted<jsid> id(&rootId0);
3080       FETCH_ELEMENT_ID(-2, id);
3081       HandleValue value = REGS.stackHandleAt(-1);
3082       if (!SetObjectElementOperation(cx, obj, id, value, receiver,
3083                                      JSOp(*REGS.pc) == JSOp::StrictSetElem)) {
3084         goto error;
3085       }
3086       REGS.sp[-3] = value;
3087       REGS.sp -= 2;
3088     }
3089     END_CASE(SetElem)
3090 
3091     CASE(SetElemSuper)
3092     CASE(StrictSetElemSuper) {
3093       static_assert(
3094           JSOpLength_SetElemSuper == JSOpLength_StrictSetElemSuper,
3095           "setelem-super and strictsetelem-super must be the same size");
3096 
3097       ReservedRooted<Value> receiver(&rootValue0, REGS.sp[-4]);
3098       ReservedRooted<Value> index(&rootValue1, REGS.sp[-3]);
3099       ReservedRooted<JSObject*> obj(&rootObject1, &REGS.sp[-2].toObject());
3100       HandleValue value = REGS.stackHandleAt(-1);
3101 
3102       bool strict = JSOp(*REGS.pc) == JSOp::StrictSetElemSuper;
3103       if (!SetObjectElementWithReceiver(cx, obj, index, value, receiver,
3104                                         strict)) {
3105         goto error;
3106       }
3107       REGS.sp[-4] = value;
3108       REGS.sp -= 3;
3109     }
3110     END_CASE(SetElemSuper)
3111 
3112     CASE(Eval)
3113     CASE(StrictEval) {
3114       static_assert(JSOpLength_Eval == JSOpLength_StrictEval,
3115                     "eval and stricteval must be the same size");
3116 
3117       CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp);
3118       if (cx->global()->valueIsEval(args.calleev())) {
3119         if (!DirectEval(cx, args.get(0), args.rval())) {
3120           goto error;
3121         }
3122       } else {
3123         if (!CallFromStack(cx, args)) {
3124           goto error;
3125         }
3126       }
3127 
3128       REGS.sp = args.spAfterCall();
3129     }
3130     END_CASE(Eval)
3131 
3132     CASE(SpreadNew)
3133     CASE(SpreadCall)
3134     CASE(SpreadSuperCall) {
3135       if (REGS.fp()->hasPushedGeckoProfilerFrame()) {
3136         cx->geckoProfiler().updatePC(cx, script, REGS.pc);
3137       }
3138       /* FALL THROUGH */
3139     }
3140 
3141     CASE(SpreadEval)
3142     CASE(StrictSpreadEval) {
3143       static_assert(JSOpLength_SpreadEval == JSOpLength_StrictSpreadEval,
3144                     "spreadeval and strictspreadeval must be the same size");
3145       bool construct = JSOp(*REGS.pc) == JSOp::SpreadNew ||
3146                        JSOp(*REGS.pc) == JSOp::SpreadSuperCall;
3147       ;
3148 
3149       MOZ_ASSERT(REGS.stackDepth() >= 3u + construct);
3150 
3151       HandleValue callee = REGS.stackHandleAt(-3 - construct);
3152       HandleValue thisv = REGS.stackHandleAt(-2 - construct);
3153       HandleValue arr = REGS.stackHandleAt(-1 - construct);
3154       MutableHandleValue ret = REGS.stackHandleAt(-3 - construct);
3155 
3156       RootedValue& newTarget = rootValue0;
3157       if (construct) {
3158         newTarget = REGS.sp[-1];
3159       } else {
3160         newTarget = NullValue();
3161       }
3162 
3163       if (!SpreadCallOperation(cx, script, REGS.pc, thisv, callee, arr,
3164                                newTarget, ret)) {
3165         goto error;
3166       }
3167 
3168       REGS.sp -= 2 + construct;
3169     }
3170     END_CASE(SpreadCall)
3171 
3172     CASE(New)
3173     CASE(Call)
3174     CASE(CallIgnoresRv)
3175     CASE(CallIter)
3176     CASE(SuperCall)
3177     CASE(FunCall)
3178     CASE(FunApply) {
3179       static_assert(JSOpLength_Call == JSOpLength_New,
3180                     "call and new must be the same size");
3181       static_assert(JSOpLength_Call == JSOpLength_CallIgnoresRv,
3182                     "call and call-ignores-rv must be the same size");
3183       static_assert(JSOpLength_Call == JSOpLength_CallIter,
3184                     "call and calliter must be the same size");
3185       static_assert(JSOpLength_Call == JSOpLength_SuperCall,
3186                     "call and supercall must be the same size");
3187       static_assert(JSOpLength_Call == JSOpLength_FunCall,
3188                     "call and funcall must be the same size");
3189       static_assert(JSOpLength_Call == JSOpLength_FunApply,
3190                     "call and funapply must be the same size");
3191 
3192       if (REGS.fp()->hasPushedGeckoProfilerFrame()) {
3193         cx->geckoProfiler().updatePC(cx, script, REGS.pc);
3194       }
3195 
3196       MaybeConstruct construct = MaybeConstruct(
3197           JSOp(*REGS.pc) == JSOp::New || JSOp(*REGS.pc) == JSOp::SuperCall);
3198       bool ignoresReturnValue = JSOp(*REGS.pc) == JSOp::CallIgnoresRv;
3199       unsigned argStackSlots = GET_ARGC(REGS.pc) + construct;
3200 
3201       MOZ_ASSERT(REGS.stackDepth() >= 2u + GET_ARGC(REGS.pc));
3202       CallArgs args =
3203           CallArgsFromSp(argStackSlots, REGS.sp, construct, ignoresReturnValue);
3204 
3205       JSFunction* maybeFun;
3206       bool isFunction = IsFunctionObject(args.calleev(), &maybeFun);
3207 
3208       // Use the slow path if the callee is not an interpreted function, if we
3209       // have to throw an exception, or if we might have to invoke the
3210       // OnNativeCall hook for a self-hosted builtin.
3211       if (!isFunction || !maybeFun->isInterpreted() ||
3212           (construct && !maybeFun->isConstructor()) ||
3213           (!construct && maybeFun->isClassConstructor()) ||
3214           cx->insideDebuggerEvaluationWithOnNativeCallHook) {
3215         if (construct) {
3216           if (!ConstructFromStack(cx, args)) {
3217             goto error;
3218           }
3219         } else {
3220           if (JSOp(*REGS.pc) == JSOp::CallIter &&
3221               args.calleev().isPrimitive()) {
3222             MOZ_ASSERT(args.length() == 0, "thisv must be on top of the stack");
3223             ReportValueError(cx, JSMSG_NOT_ITERABLE, -1, args.thisv(), nullptr);
3224             goto error;
3225           }
3226           if (!CallFromStack(cx, args)) {
3227             goto error;
3228           }
3229         }
3230         Value* newsp = args.spAfterCall();
3231         REGS.sp = newsp;
3232         ADVANCE_AND_DISPATCH(JSOpLength_Call);
3233       }
3234 
3235       {
3236         MOZ_ASSERT(maybeFun);
3237         ReservedRooted<JSFunction*> fun(&rootFunction0, maybeFun);
3238         ReservedRooted<JSScript*> funScript(
3239             &rootScript0, JSFunction::getOrCreateScript(cx, fun));
3240         if (!funScript) {
3241           goto error;
3242         }
3243 
3244         // Enter the callee's realm if this is a cross-realm call. Use
3245         // MakeScopeExit to leave this realm on all error/JIT-return paths
3246         // below.
3247         const bool isCrossRealm = cx->realm() != funScript->realm();
3248         if (isCrossRealm) {
3249           cx->enterRealmOf(funScript);
3250         }
3251         auto leaveRealmGuard =
3252             mozilla::MakeScopeExit([isCrossRealm, cx, &script] {
3253               if (isCrossRealm) {
3254                 cx->leaveRealm(script->realm());
3255               }
3256             });
3257 
3258         if (construct && !MaybeCreateThisForConstructor(cx, args)) {
3259           goto error;
3260         }
3261 
3262         {
3263           InvokeState state(cx, args, construct);
3264 
3265           jit::EnterJitStatus status = jit::MaybeEnterJit(cx, state);
3266           switch (status) {
3267             case jit::EnterJitStatus::Error:
3268               goto error;
3269             case jit::EnterJitStatus::Ok:
3270               interpReturnOK = true;
3271               CHECK_BRANCH();
3272               REGS.sp = args.spAfterCall();
3273               goto jit_return;
3274             case jit::EnterJitStatus::NotEntered:
3275               break;
3276           }
3277         }
3278 
3279         funScript = fun->nonLazyScript();
3280 
3281         if (!activation.pushInlineFrame(args, funScript, construct)) {
3282           goto error;
3283         }
3284         leaveRealmGuard.release();  // We leave the callee's realm when we
3285                                     // call popInlineFrame.
3286       }
3287 
3288       SET_SCRIPT(REGS.fp()->script());
3289 
3290       {
3291         TraceLoggerEvent event(TraceLogger_Scripts, script);
3292         TraceLogStartEvent(logger, event);
3293         TraceLogStartEvent(logger, TraceLogger_Interpreter);
3294       }
3295 
3296       if (!REGS.fp()->prologue(cx)) {
3297         goto prologue_error;
3298       }
3299 
3300       if (!DebugAPI::onEnterFrame(cx, REGS.fp())) {
3301         goto error;
3302       }
3303 
3304       // Increment the coverage for the main entry point.
3305       INIT_COVERAGE();
3306       COUNT_COVERAGE_MAIN();
3307 
3308       /* Load first op and dispatch it (safe since JSOp::RetRval). */
3309       ADVANCE_AND_DISPATCH(0);
3310     }
3311 
3312     CASE(OptimizeSpreadCall) {
3313       ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
3314 
3315       bool optimized = false;
3316       if (!OptimizeSpreadCall(cx, val, &optimized)) {
3317         goto error;
3318       }
3319 
3320       PUSH_BOOLEAN(optimized);
3321     }
3322     END_CASE(OptimizeSpreadCall)
3323 
3324     CASE(ThrowMsg) {
3325       MOZ_ALWAYS_FALSE(ThrowMsgOperation(cx, GET_UINT8(REGS.pc)));
3326       goto error;
3327     }
3328     END_CASE(ThrowMsg)
3329 
3330     CASE(ImplicitThis)
3331     CASE(GImplicitThis) {
3332       JSOp op = JSOp(*REGS.pc);
3333       if (op == JSOp::ImplicitThis || script->hasNonSyntacticScope()) {
3334         ReservedRooted<PropertyName*> name(&rootName0,
3335                                            script->getName(REGS.pc));
3336         ReservedRooted<JSObject*> envObj(&rootObject0,
3337                                          REGS.fp()->environmentChain());
3338         ReservedRooted<JSObject*> env(&rootObject1);
3339         if (!LookupNameWithGlobalDefault(cx, name, envObj, &env)) {
3340           goto error;
3341         }
3342 
3343         Value v = ComputeImplicitThis(env);
3344         PUSH_COPY(v);
3345       } else {
3346         // Treat it like JSOp::Undefined.
3347         PUSH_UNDEFINED();
3348       }
3349       static_assert(JSOpLength_ImplicitThis == JSOpLength_GImplicitThis,
3350                     "We're sharing the END_CASE so the lengths better match");
3351     }
3352     END_CASE(ImplicitThis)
3353 
3354     CASE(GetGName)
3355     CASE(GetName) {
3356       ReservedRooted<Value> rval(&rootValue0);
3357       if (!GetNameOperation(cx, REGS.fp(), REGS.pc, &rval)) {
3358         goto error;
3359       }
3360 
3361       PUSH_COPY(rval);
3362       static_assert(JSOpLength_GetName == JSOpLength_GetGName,
3363                     "We're sharing the END_CASE so the lengths better match");
3364     }
3365     END_CASE(GetName)
3366 
3367     CASE(GetImport) {
3368       PUSH_NULL();
3369       MutableHandleValue rval = REGS.stackHandleAt(-1);
3370       HandleObject envChain = REGS.fp()->environmentChain();
3371       if (!GetImportOperation(cx, envChain, script, REGS.pc, rval)) {
3372         goto error;
3373       }
3374     }
3375     END_CASE(GetImport)
3376 
3377     CASE(GetIntrinsic) {
3378       ReservedRooted<Value> rval(&rootValue0);
3379       if (!GetIntrinsicOperation(cx, script, REGS.pc, &rval)) {
3380         goto error;
3381       }
3382 
3383       PUSH_COPY(rval);
3384     }
3385     END_CASE(GetIntrinsic)
3386 
3387     CASE(Uint16) { PUSH_INT32((int32_t)GET_UINT16(REGS.pc)); }
3388     END_CASE(Uint16)
3389 
3390     CASE(Uint24)
3391     CASE(ResumeIndex) { PUSH_INT32((int32_t)GET_UINT24(REGS.pc)); }
3392     END_CASE(Uint24)
3393 
3394     CASE(Int8) { PUSH_INT32(GET_INT8(REGS.pc)); }
3395     END_CASE(Int8)
3396 
3397     CASE(Int32) { PUSH_INT32(GET_INT32(REGS.pc)); }
3398     END_CASE(Int32)
3399 
3400     CASE(Double) { PUSH_COPY(GET_INLINE_VALUE(REGS.pc)); }
3401     END_CASE(Double)
3402 
3403     CASE(String) { PUSH_STRING(script->getAtom(REGS.pc)); }
3404     END_CASE(String)
3405 
3406     CASE(ToString) {
3407       MutableHandleValue oper = REGS.stackHandleAt(-1);
3408 
3409       if (!oper.isString()) {
3410         JSString* operString = ToString<CanGC>(cx, oper);
3411         if (!operString) {
3412           goto error;
3413         }
3414         oper.setString(operString);
3415       }
3416     }
3417     END_CASE(ToString)
3418 
3419     CASE(Symbol) {
3420       PUSH_SYMBOL(cx->wellKnownSymbols().get(GET_UINT8(REGS.pc)));
3421     }
3422     END_CASE(Symbol)
3423 
3424     CASE(Object) {
3425       MOZ_ASSERT(script->treatAsRunOnce());
3426       PUSH_OBJECT(*script->getObject(REGS.pc));
3427     }
3428     END_CASE(Object)
3429 
3430     CASE(CallSiteObj) {
3431       JSObject* cso = ProcessCallSiteObjOperation(cx, script, REGS.pc);
3432       if (!cso) {
3433         goto error;
3434       }
3435       PUSH_OBJECT(*cso);
3436     }
3437     END_CASE(CallSiteObj)
3438 
3439     CASE(RegExp) {
3440       /*
3441        * Push a regexp object cloned from the regexp literal object mapped by
3442        * the bytecode at pc.
3443        */
3444       ReservedRooted<JSObject*> re(&rootObject0, script->getRegExp(REGS.pc));
3445       JSObject* obj = CloneRegExpObject(cx, re.as<RegExpObject>());
3446       if (!obj) {
3447         goto error;
3448       }
3449       PUSH_OBJECT(*obj);
3450     }
3451     END_CASE(RegExp)
3452 
3453     CASE(Zero) { PUSH_INT32(0); }
3454     END_CASE(Zero)
3455 
3456     CASE(One) { PUSH_INT32(1); }
3457     END_CASE(One)
3458 
3459     CASE(Null) { PUSH_NULL(); }
3460     END_CASE(Null)
3461 
3462     CASE(False) { PUSH_BOOLEAN(false); }
3463     END_CASE(False)
3464 
3465     CASE(True) { PUSH_BOOLEAN(true); }
3466     END_CASE(True)
3467 
3468     CASE(TableSwitch) {
3469       jsbytecode* pc2 = REGS.pc;
3470       int32_t len = GET_JUMP_OFFSET(pc2);
3471 
3472       /*
3473        * ECMAv2+ forbids conversion of discriminant, so we will skip to the
3474        * default case if the discriminant isn't already an int jsval.  (This
3475        * opcode is emitted only for dense int-domain switches.)
3476        */
3477       const Value& rref = *--REGS.sp;
3478       int32_t i;
3479       if (rref.isInt32()) {
3480         i = rref.toInt32();
3481       } else {
3482         /* Use mozilla::NumberEqualsInt32 to treat -0 (double) as 0. */
3483         if (!rref.isDouble() || !NumberEqualsInt32(rref.toDouble(), &i)) {
3484           ADVANCE_AND_DISPATCH(len);
3485         }
3486       }
3487 
3488       pc2 += JUMP_OFFSET_LEN;
3489       int32_t low = GET_JUMP_OFFSET(pc2);
3490       pc2 += JUMP_OFFSET_LEN;
3491       int32_t high = GET_JUMP_OFFSET(pc2);
3492 
3493       i = uint32_t(i) - uint32_t(low);
3494       if (uint32_t(i) < uint32_t(high - low + 1)) {
3495         len = script->tableSwitchCaseOffset(REGS.pc, uint32_t(i)) -
3496               script->pcToOffset(REGS.pc);
3497       }
3498       ADVANCE_AND_DISPATCH(len);
3499     }
3500 
3501     CASE(Arguments) {
3502       MOZ_ASSERT(script->needsArgsObj());
3503       ArgumentsObject* obj = ArgumentsObject::createExpected(cx, REGS.fp());
3504       if (!obj) {
3505         goto error;
3506       }
3507       PUSH_COPY(ObjectValue(*obj));
3508     }
3509     END_CASE(Arguments)
3510 
3511     CASE(Rest) {
3512       ReservedRooted<JSObject*> rest(&rootObject0,
3513                                      REGS.fp()->createRestParameter(cx));
3514       if (!rest) {
3515         goto error;
3516       }
3517       PUSH_COPY(ObjectValue(*rest));
3518     }
3519     END_CASE(Rest)
3520 
3521     CASE(GetAliasedVar) {
3522       EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
3523       ReservedRooted<Value> val(
3524           &rootValue0, REGS.fp()->aliasedEnvironment(ec).aliasedBinding(ec));
3525 
3526       ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val);
3527 
3528       PUSH_COPY(val);
3529     }
3530     END_CASE(GetAliasedVar)
3531 
3532     CASE(GetAliasedDebugVar) {
3533       EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
3534       ReservedRooted<Value> val(
3535           &rootValue0,
3536           REGS.fp()->aliasedEnvironmentMaybeDebug(ec).aliasedBinding(ec));
3537 
3538       ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val);
3539 
3540       PUSH_COPY(val);
3541     }
3542     END_CASE(GetAliasedVar)
3543 
3544     CASE(SetAliasedVar) {
3545       EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
3546       EnvironmentObject& obj = REGS.fp()->aliasedEnvironment(ec);
3547       SetAliasedVarOperation(cx, script, REGS.pc, obj, ec, REGS.sp[-1],
3548                              CheckTDZ);
3549     }
3550     END_CASE(SetAliasedVar)
3551 
3552     CASE(ThrowSetConst) {
3553       ReportRuntimeLexicalError(cx, JSMSG_BAD_CONST_ASSIGN, script, REGS.pc);
3554       goto error;
3555     }
3556     END_CASE(ThrowSetConst)
3557 
3558     CASE(CheckLexical) {
3559       if (REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
3560         ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, script,
3561                                   REGS.pc);
3562         goto error;
3563       }
3564     }
3565     END_CASE(CheckLexical)
3566 
3567     CASE(CheckAliasedLexical) {
3568       if (REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
3569         ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, script,
3570                                   REGS.pc);
3571         goto error;
3572       }
3573     }
3574     END_CASE(CheckAliasedLexical)
3575 
3576     CASE(InitLexical) {
3577       uint32_t i = GET_LOCALNO(REGS.pc);
3578       REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
3579     }
3580     END_CASE(InitLexical)
3581 
3582     CASE(InitAliasedLexical) {
3583       EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
3584       EnvironmentObject& obj = REGS.fp()->aliasedEnvironment(ec);
3585       SetAliasedVarOperation(cx, script, REGS.pc, obj, ec, REGS.sp[-1],
3586                              DontCheckTDZ);
3587     }
3588     END_CASE(InitAliasedLexical)
3589 
3590     CASE(InitGLexical) {
3591       ExtensibleLexicalEnvironmentObject* lexicalEnv;
3592       if (script->hasNonSyntacticScope()) {
3593         lexicalEnv = &REGS.fp()->extensibleLexicalEnvironment();
3594       } else {
3595         lexicalEnv = &cx->global()->lexicalEnvironment();
3596       }
3597       HandleValue value = REGS.stackHandleAt(-1);
3598       InitGlobalLexicalOperation(cx, lexicalEnv, script, REGS.pc, value);
3599     }
3600     END_CASE(InitGLexical)
3601 
3602     CASE(Uninitialized) { PUSH_MAGIC(JS_UNINITIALIZED_LEXICAL); }
3603     END_CASE(Uninitialized)
3604 
3605     CASE(GetArg) {
3606       unsigned i = GET_ARGNO(REGS.pc);
3607       if (script->argsObjAliasesFormals()) {
3608         PUSH_COPY(REGS.fp()->argsObj().arg(i));
3609       } else {
3610         PUSH_COPY(REGS.fp()->unaliasedFormal(i));
3611       }
3612     }
3613     END_CASE(GetArg)
3614 
3615     CASE(SetArg) {
3616       unsigned i = GET_ARGNO(REGS.pc);
3617       if (script->argsObjAliasesFormals()) {
3618         REGS.fp()->argsObj().setArg(i, REGS.sp[-1]);
3619       } else {
3620         REGS.fp()->unaliasedFormal(i) = REGS.sp[-1];
3621       }
3622     }
3623     END_CASE(SetArg)
3624 
3625     CASE(GetLocal) {
3626       uint32_t i = GET_LOCALNO(REGS.pc);
3627       PUSH_COPY_SKIP_CHECK(REGS.fp()->unaliasedLocal(i));
3628 
3629 #ifdef DEBUG
3630       if (IsUninitializedLexical(REGS.sp[-1])) {
3631         JSOp next = JSOp(*GetNextPc(REGS.pc));
3632         MOZ_ASSERT(next == JSOp::CheckThis || next == JSOp::CheckReturn ||
3633                    next == JSOp::CheckThisReinit || next == JSOp::CheckLexical);
3634       }
3635 
3636       /*
3637        * Skip the same-compartment assertion if the local will be immediately
3638        * popped. We do not guarantee sync for dead locals when coming in from
3639        * the method JIT, and a GetLocal followed by Pop is not considered to
3640        * be a use of the variable.
3641        */
3642       if (JSOp(REGS.pc[JSOpLength_GetLocal]) != JSOp::Pop) {
3643         cx->debugOnlyCheck(REGS.sp[-1]);
3644       }
3645 #endif
3646     }
3647     END_CASE(GetLocal)
3648 
3649     CASE(SetLocal) {
3650       uint32_t i = GET_LOCALNO(REGS.pc);
3651 
3652       MOZ_ASSERT(!IsUninitializedLexical(REGS.fp()->unaliasedLocal(i)));
3653 
3654       REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
3655     }
3656     END_CASE(SetLocal)
3657 
3658     CASE(GlobalOrEvalDeclInstantiation) {
3659       GCThingIndex lastFun = GET_GCTHING_INDEX(REGS.pc);
3660       HandleObject env = REGS.fp()->environmentChain();
3661       if (!GlobalOrEvalDeclInstantiation(cx, env, script, lastFun)) {
3662         goto error;
3663       }
3664     }
3665     END_CASE(GlobalOrEvalDeclInstantiation)
3666 
3667     CASE(Lambda) {
3668       /* Load the specified function object literal. */
3669       ReservedRooted<JSFunction*> fun(&rootFunction0,
3670                                       script->getFunction(REGS.pc));
3671       JSObject* obj = Lambda(cx, fun, REGS.fp()->environmentChain());
3672       if (!obj) {
3673         goto error;
3674       }
3675 
3676       MOZ_ASSERT(obj->staticPrototype());
3677       PUSH_OBJECT(*obj);
3678     }
3679     END_CASE(Lambda)
3680 
3681     CASE(LambdaArrow) {
3682       /* Load the specified function object literal. */
3683       ReservedRooted<JSFunction*> fun(&rootFunction0,
3684                                       script->getFunction(REGS.pc));
3685       ReservedRooted<Value> newTarget(&rootValue1, REGS.sp[-1]);
3686       JSObject* obj =
3687           LambdaArrow(cx, fun, REGS.fp()->environmentChain(), newTarget);
3688       if (!obj) {
3689         goto error;
3690       }
3691 
3692       MOZ_ASSERT(obj->staticPrototype());
3693       REGS.sp[-1].setObject(*obj);
3694     }
3695     END_CASE(LambdaArrow)
3696 
3697     CASE(ToAsyncIter) {
3698       ReservedRooted<Value> nextMethod(&rootValue0, REGS.sp[-1]);
3699       ReservedRooted<JSObject*> iter(&rootObject1, &REGS.sp[-2].toObject());
3700       JSObject* asyncIter = CreateAsyncFromSyncIterator(cx, iter, nextMethod);
3701       if (!asyncIter) {
3702         goto error;
3703       }
3704 
3705       REGS.sp--;
3706       REGS.sp[-1].setObject(*asyncIter);
3707     }
3708     END_CASE(ToAsyncIter)
3709 
3710     CASE(CanSkipAwait) {
3711       ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
3712       bool canSkip;
3713       if (!CanSkipAwait(cx, val, &canSkip)) {
3714         goto error;
3715       }
3716 
3717       PUSH_BOOLEAN(canSkip);
3718     }
3719     END_CASE(CanSkipAwait)
3720 
3721     CASE(MaybeExtractAwaitValue) {
3722       MutableHandleValue val = REGS.stackHandleAt(-2);
3723       ReservedRooted<Value> canSkip(&rootValue0, REGS.sp[-1]);
3724 
3725       if (canSkip.toBoolean()) {
3726         if (!ExtractAwaitValue(cx, val, val)) {
3727           goto error;
3728         }
3729       }
3730     }
3731     END_CASE(MaybeExtractAwaitValue)
3732 
3733     CASE(AsyncAwait) {
3734       MOZ_ASSERT(REGS.stackDepth() >= 2);
3735       ReservedRooted<JSObject*> gen(&rootObject1, &REGS.sp[-1].toObject());
3736       ReservedRooted<Value> value(&rootValue0, REGS.sp[-2]);
3737       JSObject* promise =
3738           AsyncFunctionAwait(cx, gen.as<AsyncFunctionGeneratorObject>(), value);
3739       if (!promise) {
3740         goto error;
3741       }
3742 
3743       REGS.sp--;
3744       REGS.sp[-1].setObject(*promise);
3745     }
3746     END_CASE(AsyncAwait)
3747 
3748     CASE(AsyncResolve) {
3749       MOZ_ASSERT(REGS.stackDepth() >= 2);
3750       auto resolveKind = AsyncFunctionResolveKind(GET_UINT8(REGS.pc));
3751       ReservedRooted<JSObject*> gen(&rootObject1, &REGS.sp[-1].toObject());
3752       ReservedRooted<Value> valueOrReason(&rootValue0, REGS.sp[-2]);
3753       JSObject* promise =
3754           AsyncFunctionResolve(cx, gen.as<AsyncFunctionGeneratorObject>(),
3755                                valueOrReason, resolveKind);
3756       if (!promise) {
3757         goto error;
3758       }
3759 
3760       REGS.sp--;
3761       REGS.sp[-1].setObject(*promise);
3762     }
3763     END_CASE(AsyncResolve)
3764 
3765     CASE(SetFunName) {
3766       MOZ_ASSERT(REGS.stackDepth() >= 2);
3767       FunctionPrefixKind prefixKind = FunctionPrefixKind(GET_UINT8(REGS.pc));
3768       ReservedRooted<Value> name(&rootValue0, REGS.sp[-1]);
3769       ReservedRooted<JSFunction*> fun(&rootFunction0,
3770                                       &REGS.sp[-2].toObject().as<JSFunction>());
3771       if (!SetFunctionName(cx, fun, name, prefixKind)) {
3772         goto error;
3773       }
3774 
3775       REGS.sp--;
3776     }
3777     END_CASE(SetFunName)
3778 
3779     CASE(Callee) {
3780       MOZ_ASSERT(REGS.fp()->isFunctionFrame());
3781       PUSH_COPY(REGS.fp()->calleev());
3782     }
3783     END_CASE(Callee)
3784 
3785     CASE(InitPropGetter)
3786     CASE(InitHiddenPropGetter)
3787     CASE(InitPropSetter)
3788     CASE(InitHiddenPropSetter) {
3789       MOZ_ASSERT(REGS.stackDepth() >= 2);
3790 
3791       ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
3792       ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
3793       ReservedRooted<JSObject*> val(&rootObject1, &REGS.sp[-1].toObject());
3794 
3795       if (!InitPropGetterSetterOperation(cx, REGS.pc, obj, name, val)) {
3796         goto error;
3797       }
3798 
3799       REGS.sp--;
3800     }
3801     END_CASE(InitPropGetter)
3802 
3803     CASE(InitElemGetter)
3804     CASE(InitHiddenElemGetter)
3805     CASE(InitElemSetter)
3806     CASE(InitHiddenElemSetter) {
3807       MOZ_ASSERT(REGS.stackDepth() >= 3);
3808 
3809       ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-3].toObject());
3810       ReservedRooted<Value> idval(&rootValue0, REGS.sp[-2]);
3811       ReservedRooted<JSObject*> val(&rootObject1, &REGS.sp[-1].toObject());
3812 
3813       if (!InitElemGetterSetterOperation(cx, REGS.pc, obj, idval, val)) {
3814         goto error;
3815       }
3816 
3817       REGS.sp -= 2;
3818     }
3819     END_CASE(InitElemGetter)
3820 
3821     CASE(Hole) { PUSH_MAGIC(JS_ELEMENTS_HOLE); }
3822     END_CASE(Hole)
3823 
3824     CASE(NewInit) {
3825       JSObject* obj = NewObjectOperation(cx, script, REGS.pc);
3826 
3827       if (!obj) {
3828         goto error;
3829       }
3830       PUSH_OBJECT(*obj);
3831     }
3832     END_CASE(NewInit)
3833 
3834     CASE(NewArray) {
3835       uint32_t length = GET_UINT32(REGS.pc);
3836       ArrayObject* obj = NewArrayOperation(cx, length);
3837       if (!obj) {
3838         goto error;
3839       }
3840       PUSH_OBJECT(*obj);
3841     }
3842     END_CASE(NewArray)
3843 
3844     CASE(NewObject) {
3845       JSObject* obj = NewObjectOperation(cx, script, REGS.pc);
3846       if (!obj) {
3847         goto error;
3848       }
3849       PUSH_OBJECT(*obj);
3850     }
3851     END_CASE(NewObject)
3852 
3853     CASE(MutateProto) {
3854       MOZ_ASSERT(REGS.stackDepth() >= 2);
3855 
3856       if (REGS.sp[-1].isObjectOrNull()) {
3857         ReservedRooted<JSObject*> newProto(&rootObject1,
3858                                            REGS.sp[-1].toObjectOrNull());
3859         ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
3860         MOZ_ASSERT(obj->is<PlainObject>());
3861 
3862         if (!SetPrototype(cx, obj, newProto)) {
3863           goto error;
3864         }
3865       }
3866 
3867       REGS.sp--;
3868     }
3869     END_CASE(MutateProto)
3870 
3871     CASE(InitProp)
3872     CASE(InitLockedProp)
3873     CASE(InitHiddenProp) {
3874       static_assert(JSOpLength_InitProp == JSOpLength_InitLockedProp,
3875                     "initprop and initlockedprop must be the same size");
3876       static_assert(JSOpLength_InitProp == JSOpLength_InitHiddenProp,
3877                     "initprop and inithiddenprop must be the same size");
3878       /* Load the property's initial value into rval. */
3879       MOZ_ASSERT(REGS.stackDepth() >= 2);
3880       ReservedRooted<Value> rval(&rootValue0, REGS.sp[-1]);
3881 
3882       /* Load the object being initialized into lval/obj. */
3883       ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
3884 
3885       ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
3886 
3887       if (!InitPropertyOperation(cx, JSOp(*REGS.pc), obj, name, rval)) {
3888         goto error;
3889       }
3890 
3891       REGS.sp--;
3892     }
3893     END_CASE(InitProp)
3894 
3895     CASE(InitElem)
3896     CASE(InitHiddenElem)
3897     CASE(InitLockedElem) {
3898       MOZ_ASSERT(REGS.stackDepth() >= 3);
3899       HandleValue val = REGS.stackHandleAt(-1);
3900       HandleValue id = REGS.stackHandleAt(-2);
3901 
3902       ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-3].toObject());
3903 
3904       if (!InitElemOperation(cx, REGS.pc, obj, id, val)) {
3905         goto error;
3906       }
3907 
3908       REGS.sp -= 2;
3909     }
3910     END_CASE(InitElem)
3911 
3912     CASE(InitElemArray) {
3913       MOZ_ASSERT(REGS.stackDepth() >= 2);
3914       HandleValue val = REGS.stackHandleAt(-1);
3915       ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
3916 
3917       InitElemArrayOperation(cx, REGS.pc, obj.as<ArrayObject>(), val);
3918       REGS.sp--;
3919     }
3920     END_CASE(InitElemArray)
3921 
3922     CASE(InitElemInc) {
3923       MOZ_ASSERT(REGS.stackDepth() >= 3);
3924       HandleValue val = REGS.stackHandleAt(-1);
3925 
3926       ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-3].toObject());
3927 
3928       uint32_t index = REGS.sp[-2].toInt32();
3929       if (!InitElemIncOperation(cx, obj.as<ArrayObject>(), index, val)) {
3930         goto error;
3931       }
3932 
3933       REGS.sp[-2].setInt32(index + 1);
3934       REGS.sp--;
3935     }
3936     END_CASE(InitElemInc)
3937 
3938     CASE(Gosub) {
3939       int32_t len = GET_JUMP_OFFSET(REGS.pc);
3940       ADVANCE_AND_DISPATCH(len);
3941     }
3942 
3943     CASE(Retsub) {
3944       /* Pop [exception or hole, retsub pc-index]. */
3945       Value rval, lval;
3946       POP_COPY_TO(rval);
3947       POP_COPY_TO(lval);
3948       MOZ_ASSERT(lval.isBoolean());
3949       if (lval.toBoolean()) {
3950         /*
3951          * Exception was pending during finally, throw it *before* we adjust
3952          * pc, because pc indexes into script->trynotes.  This turns out not
3953          * to be necessary, but it seems clearer.  And it points out a FIXME:
3954          * 350509, due to Igor Bukanov.
3955          */
3956         ReservedRooted<Value> v(&rootValue0, rval);
3957         cx->setPendingExceptionAndCaptureStack(v);
3958         goto error;
3959       }
3960 
3961       MOZ_ASSERT(rval.toInt32() >= 0);
3962 
3963       uint32_t offset = script->resumeOffsets()[rval.toInt32()];
3964       REGS.pc = script->offsetToPC(offset);
3965       ADVANCE_AND_DISPATCH(0);
3966     }
3967 
3968     CASE(Exception) {
3969       PUSH_NULL();
3970       MutableHandleValue res = REGS.stackHandleAt(-1);
3971       if (!GetAndClearException(cx, res)) {
3972         goto error;
3973       }
3974     }
3975     END_CASE(Exception)
3976 
3977     CASE(Finally) { CHECK_BRANCH(); }
3978     END_CASE(Finally)
3979 
3980     CASE(Throw) {
3981       CHECK_BRANCH();
3982       ReservedRooted<Value> v(&rootValue0);
3983       POP_COPY_TO(v);
3984       MOZ_ALWAYS_FALSE(ThrowOperation(cx, v));
3985       /* let the code at error try to catch the exception. */
3986       goto error;
3987     }
3988 
3989     CASE(Instanceof) {
3990       ReservedRooted<Value> rref(&rootValue0, REGS.sp[-1]);
3991       if (HandleValue(rref).isPrimitive()) {
3992         ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rref, nullptr);
3993         goto error;
3994       }
3995       ReservedRooted<JSObject*> obj(&rootObject0, &rref.toObject());
3996       bool cond = false;
3997       if (!HasInstance(cx, obj, REGS.stackHandleAt(-2), &cond)) {
3998         goto error;
3999       }
4000       REGS.sp--;
4001       REGS.sp[-1].setBoolean(cond);
4002     }
4003     END_CASE(Instanceof)
4004 
4005     CASE(Debugger) {
4006       if (!DebugAPI::onDebuggerStatement(cx, REGS.fp())) {
4007         goto error;
4008       }
4009     }
4010     END_CASE(Debugger)
4011 
4012     CASE(PushLexicalEnv) {
4013       ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
4014 
4015       // Create block environment and push on scope chain.
4016       if (!REGS.fp()->pushLexicalEnvironment(cx, scope.as<LexicalScope>())) {
4017         goto error;
4018       }
4019     }
4020     END_CASE(PushLexicalEnv)
4021 
4022     CASE(PopLexicalEnv) {
4023 #ifdef DEBUG
4024       Scope* scope = script->lookupScope(REGS.pc);
4025       MOZ_ASSERT(scope);
4026       MOZ_ASSERT(scope->is<LexicalScope>() || scope->is<ClassBodyScope>());
4027       MOZ_ASSERT_IF(scope->is<LexicalScope>(),
4028                     scope->as<LexicalScope>().hasEnvironment());
4029       MOZ_ASSERT_IF(scope->is<ClassBodyScope>(),
4030                     scope->as<ClassBodyScope>().hasEnvironment());
4031 #endif
4032 
4033       if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
4034         DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
4035       }
4036 
4037       // Pop block from scope chain.
4038       REGS.fp()->popOffEnvironmentChain<LexicalEnvironmentObject>();
4039     }
4040     END_CASE(PopLexicalEnv)
4041 
4042     CASE(DebugLeaveLexicalEnv) {
4043 #ifdef DEBUG
4044       Scope* scope = script->lookupScope(REGS.pc);
4045       MOZ_ASSERT(scope);
4046       MOZ_ASSERT(scope->is<LexicalScope>() || scope->is<ClassBodyScope>());
4047       MOZ_ASSERT_IF(scope->is<LexicalScope>(),
4048                     !scope->as<LexicalScope>().hasEnvironment());
4049       MOZ_ASSERT_IF(scope->is<ClassBodyScope>(),
4050                     !scope->as<ClassBodyScope>().hasEnvironment());
4051 #endif
4052       // FIXME: This opcode should not be necessary.  The debugger shouldn't
4053       // need help from bytecode to do its job.  See bug 927782.
4054 
4055       if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
4056         DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
4057       }
4058     }
4059     END_CASE(DebugLeaveLexicalEnv)
4060 
4061     CASE(FreshenLexicalEnv) {
4062       if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
4063         DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
4064       }
4065 
4066       if (!REGS.fp()->freshenLexicalEnvironment(cx)) {
4067         goto error;
4068       }
4069     }
4070     END_CASE(FreshenLexicalEnv)
4071 
4072     CASE(RecreateLexicalEnv) {
4073       if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
4074         DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
4075       }
4076 
4077       if (!REGS.fp()->recreateLexicalEnvironment(cx)) {
4078         goto error;
4079       }
4080     }
4081     END_CASE(RecreateLexicalEnv)
4082 
4083     CASE(PushClassBodyEnv) {
4084       ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
4085 
4086       if (!REGS.fp()->pushClassBodyEnvironment(cx,
4087                                                scope.as<ClassBodyScope>())) {
4088         goto error;
4089       }
4090     }
4091     END_CASE(PushClassBodyEnv)
4092 
4093     CASE(PushVarEnv) {
4094       ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
4095 
4096       if (!REGS.fp()->pushVarEnvironment(cx, scope)) {
4097         goto error;
4098       }
4099     }
4100     END_CASE(PushVarEnv)
4101 
4102     CASE(Generator) {
4103       MOZ_ASSERT(!cx->isExceptionPending());
4104       MOZ_ASSERT(REGS.stackDepth() == 0);
4105       JSObject* obj = AbstractGeneratorObject::createFromFrame(cx, REGS.fp());
4106       if (!obj) {
4107         goto error;
4108       }
4109       PUSH_OBJECT(*obj);
4110     }
4111     END_CASE(Generator)
4112 
4113     CASE(InitialYield) {
4114       MOZ_ASSERT(!cx->isExceptionPending());
4115       MOZ_ASSERT_IF(script->isModule() && script->isAsync(),
4116                     REGS.fp()->isModuleFrame());
4117       MOZ_ASSERT_IF(!script->isModule() && script->isAsync(),
4118                     REGS.fp()->isFunctionFrame());
4119       ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-1].toObject());
4120       POP_RETURN_VALUE();
4121       MOZ_ASSERT(REGS.stackDepth() == 0);
4122       if (!AbstractGeneratorObject::suspend(cx, obj, REGS.fp(), REGS.pc,
4123                                             script->nfixed())) {
4124         goto error;
4125       }
4126       goto successful_return_continuation;
4127     }
4128 
4129     CASE(Yield)
4130     CASE(Await) {
4131       MOZ_ASSERT(!cx->isExceptionPending());
4132       MOZ_ASSERT_IF(script->isModule() && script->isAsync(),
4133                     REGS.fp()->isModuleFrame());
4134       MOZ_ASSERT_IF(!script->isModule() && script->isAsync(),
4135                     REGS.fp()->isFunctionFrame());
4136       ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-1].toObject());
4137       if (!AbstractGeneratorObject::suspend(
4138               cx, obj, REGS.fp(), REGS.pc,
4139               script->nfixed() + REGS.stackDepth() - 2)) {
4140         goto error;
4141       }
4142 
4143       REGS.sp--;
4144       POP_RETURN_VALUE();
4145 
4146       goto successful_return_continuation;
4147     }
4148 
4149     CASE(ResumeKind) {
4150       GeneratorResumeKind resumeKind = ResumeKindFromPC(REGS.pc);
4151       PUSH_INT32(int32_t(resumeKind));
4152     }
4153     END_CASE(ResumeKind)
4154 
4155     CASE(CheckResumeKind) {
4156       int32_t kindInt = REGS.sp[-1].toInt32();
4157       GeneratorResumeKind resumeKind = IntToResumeKind(kindInt);
4158       if (MOZ_UNLIKELY(resumeKind != GeneratorResumeKind::Next)) {
4159         ReservedRooted<Value> val(&rootValue0, REGS.sp[-3]);
4160         Rooted<AbstractGeneratorObject*> gen(
4161             cx, &REGS.sp[-2].toObject().as<AbstractGeneratorObject>());
4162         MOZ_ALWAYS_FALSE(GeneratorThrowOrReturn(cx, activation.regs().fp(), gen,
4163                                                 val, resumeKind));
4164         goto error;
4165       }
4166       REGS.sp -= 2;
4167     }
4168     END_CASE(CheckResumeKind)
4169 
4170     CASE(Resume) {
4171       {
4172         Rooted<AbstractGeneratorObject*> gen(
4173             cx, &REGS.sp[-3].toObject().as<AbstractGeneratorObject>());
4174         ReservedRooted<Value> val(&rootValue0, REGS.sp[-2]);
4175         ReservedRooted<Value> resumeKindVal(&rootValue1, REGS.sp[-1]);
4176 
4177         // popInlineFrame expects there to be an additional value on the stack
4178         // to pop off, so leave "gen" on the stack.
4179         REGS.sp -= 1;
4180 
4181         if (!AbstractGeneratorObject::resume(cx, activation, gen, val,
4182                                              resumeKindVal)) {
4183           goto error;
4184         }
4185 
4186         JSScript* generatorScript = REGS.fp()->script();
4187         if (cx->realm() != generatorScript->realm()) {
4188           cx->enterRealmOf(generatorScript);
4189         }
4190         SET_SCRIPT(generatorScript);
4191 
4192         TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
4193         TraceLoggerEvent scriptEvent(TraceLogger_Scripts, script);
4194         TraceLogStartEvent(logger, scriptEvent);
4195         TraceLogStartEvent(logger, TraceLogger_Interpreter);
4196 
4197         if (!DebugAPI::onResumeFrame(cx, REGS.fp())) {
4198           if (cx->isPropagatingForcedReturn()) {
4199             MOZ_ASSERT_IF(
4200                 REGS.fp()
4201                     ->callee()
4202                     .isGenerator(),  // as opposed to an async function
4203                 gen->isClosed());
4204           }
4205           goto error;
4206         }
4207       }
4208       ADVANCE_AND_DISPATCH(0);
4209     }
4210 
4211     CASE(AfterYield) {
4212       // AbstractGeneratorObject::resume takes care of setting the frame's
4213       // debuggee flag.
4214       MOZ_ASSERT_IF(REGS.fp()->script()->isDebuggee(), REGS.fp()->isDebuggee());
4215       COUNT_COVERAGE();
4216     }
4217     END_CASE(AfterYield)
4218 
4219     CASE(FinalYieldRval) {
4220       ReservedRooted<JSObject*> gen(&rootObject0, &REGS.sp[-1].toObject());
4221       REGS.sp--;
4222       AbstractGeneratorObject::finalSuspend(gen);
4223       goto successful_return_continuation;
4224     }
4225 
4226     CASE(CheckClassHeritage) {
4227       HandleValue heritage = REGS.stackHandleAt(-1);
4228 
4229       if (!CheckClassHeritageOperation(cx, heritage)) {
4230         goto error;
4231       }
4232     }
4233     END_CASE(CheckClassHeritage)
4234 
4235     CASE(BuiltinObject) {
4236       auto kind = BuiltinObjectKind(GET_UINT8(REGS.pc));
4237       JSObject* builtin = BuiltinObjectOperation(cx, kind);
4238       if (!builtin) {
4239         goto error;
4240       }
4241       PUSH_OBJECT(*builtin);
4242     }
4243     END_CASE(BuiltinObject)
4244 
4245     CASE(FunWithProto) {
4246       ReservedRooted<JSObject*> proto(&rootObject1, &REGS.sp[-1].toObject());
4247 
4248       /* Load the specified function object literal. */
4249       ReservedRooted<JSFunction*> fun(&rootFunction0,
4250                                       script->getFunction(REGS.pc));
4251 
4252       JSObject* obj =
4253           FunWithProtoOperation(cx, fun, REGS.fp()->environmentChain(), proto);
4254       if (!obj) {
4255         goto error;
4256       }
4257 
4258       REGS.sp[-1].setObject(*obj);
4259     }
4260     END_CASE(FunWithProto)
4261 
4262     CASE(ObjWithProto) {
4263       JSObject* obj = ObjectWithProtoOperation(cx, REGS.stackHandleAt(-1));
4264       if (!obj) {
4265         goto error;
4266       }
4267 
4268       REGS.sp[-1].setObject(*obj);
4269     }
4270     END_CASE(ObjWithProto)
4271 
4272     CASE(InitHomeObject) {
4273       MOZ_ASSERT(REGS.stackDepth() >= 2);
4274 
4275       /* Load the function to be initialized */
4276       JSFunction* func = &REGS.sp[-2].toObject().as<JSFunction>();
4277       MOZ_ASSERT(func->allowSuperProperty());
4278 
4279       /* Load the home object */
4280       JSObject* obj = &REGS.sp[-1].toObject();
4281       MOZ_ASSERT(obj->is<PlainObject>() || obj->is<JSFunction>());
4282 
4283       func->setExtendedSlot(FunctionExtended::METHOD_HOMEOBJECT_SLOT,
4284                             ObjectValue(*obj));
4285       REGS.sp--;
4286     }
4287     END_CASE(InitHomeObject)
4288 
4289     CASE(SuperBase) {
4290       JSFunction& superEnvFunc = REGS.sp[-1].toObject().as<JSFunction>();
4291       MOZ_ASSERT(superEnvFunc.allowSuperProperty());
4292       MOZ_ASSERT(superEnvFunc.baseScript()->needsHomeObject());
4293       const Value& homeObjVal = superEnvFunc.getExtendedSlot(
4294           FunctionExtended::METHOD_HOMEOBJECT_SLOT);
4295 
4296       ReservedRooted<JSObject*> homeObj(&rootObject0, &homeObjVal.toObject());
4297       JSObject* superBase = HomeObjectSuperBase(cx, homeObj);
4298       if (!superBase) {
4299         goto error;
4300       }
4301 
4302       REGS.sp[-1].setObject(*superBase);
4303     }
4304     END_CASE(SuperBase)
4305 
4306     CASE(NewTarget) {
4307       PUSH_COPY(REGS.fp()->newTarget());
4308       MOZ_ASSERT(REGS.sp[-1].isObject() || REGS.sp[-1].isUndefined());
4309     }
4310     END_CASE(NewTarget)
4311 
4312     CASE(ImportMeta) {
4313       JSObject* metaObject = ImportMetaOperation(cx, script);
4314       if (!metaObject) {
4315         goto error;
4316       }
4317 
4318       PUSH_OBJECT(*metaObject);
4319     }
4320     END_CASE(ImportMeta)
4321 
4322     CASE(DynamicImport) {
4323       ReservedRooted<Value> specifier(&rootValue1);
4324       POP_COPY_TO(specifier);
4325 
4326       JSObject* promise = StartDynamicModuleImport(cx, script, specifier);
4327       if (!promise) goto error;
4328 
4329       PUSH_OBJECT(*promise);
4330     }
4331     END_CASE(DynamicImport)
4332 
4333     CASE(EnvCallee) {
4334       uint8_t numHops = GET_UINT8(REGS.pc);
4335       JSObject* env = &REGS.fp()->environmentChain()->as<EnvironmentObject>();
4336       for (unsigned i = 0; i < numHops; i++) {
4337         env = &env->as<EnvironmentObject>().enclosingEnvironment();
4338       }
4339       PUSH_OBJECT(env->as<CallObject>().callee());
4340     }
4341     END_CASE(EnvCallee)
4342 
4343     CASE(SuperFun) {
4344       JSObject* superEnvFunc = &REGS.sp[-1].toObject();
4345       JSObject* superFun = SuperFunOperation(superEnvFunc);
4346       REGS.sp[-1].setObjectOrNull(superFun);
4347     }
4348     END_CASE(SuperFun)
4349 
4350     CASE(CheckObjCoercible) {
4351       ReservedRooted<Value> checkVal(&rootValue0, REGS.sp[-1]);
4352       if (checkVal.isNullOrUndefined()) {
4353         MOZ_ALWAYS_FALSE(ThrowObjectCoercible(cx, checkVal));
4354         goto error;
4355       }
4356     }
4357     END_CASE(CheckObjCoercible)
4358 
4359     CASE(DebugCheckSelfHosted) {
4360 #ifdef DEBUG
4361       ReservedRooted<Value> checkVal(&rootValue0, REGS.sp[-1]);
4362       if (!Debug_CheckSelfHosted(cx, checkVal)) {
4363         goto error;
4364       }
4365 #endif
4366     }
4367     END_CASE(DebugCheckSelfHosted)
4368 
4369     CASE(IsConstructing) { PUSH_MAGIC(JS_IS_CONSTRUCTING); }
4370     END_CASE(IsConstructing)
4371 
4372     CASE(Inc) {
4373       MutableHandleValue val = REGS.stackHandleAt(-1);
4374       if (!IncOperation(cx, val, val)) {
4375         goto error;
4376       }
4377     }
4378     END_CASE(Inc)
4379 
4380     CASE(Dec) {
4381       MutableHandleValue val = REGS.stackHandleAt(-1);
4382       if (!DecOperation(cx, val, val)) {
4383         goto error;
4384       }
4385     }
4386     END_CASE(Dec)
4387 
4388     CASE(ToNumeric) {
4389       if (!ToNumeric(cx, REGS.stackHandleAt(-1))) {
4390         goto error;
4391       }
4392     }
4393     END_CASE(ToNumeric)
4394 
4395     CASE(BigInt) { PUSH_BIGINT(script->getBigInt(REGS.pc)); }
4396     END_CASE(BigInt)
4397 
4398     DEFAULT() {
4399       char numBuf[12];
4400       SprintfLiteral(numBuf, "%d", *REGS.pc);
4401       JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
4402                                 JSMSG_BAD_BYTECODE, numBuf);
4403       goto error;
4404     }
4405 
4406   } /* interpreter loop */
4407 
4408   MOZ_CRASH("Interpreter loop exited via fallthrough");
4409 
4410 error:
4411   switch (HandleError(cx, REGS)) {
4412     case SuccessfulReturnContinuation:
4413       goto successful_return_continuation;
4414 
4415     case ErrorReturnContinuation:
4416       interpReturnOK = false;
4417       goto return_continuation;
4418 
4419     case CatchContinuation:
4420       ADVANCE_AND_DISPATCH(0);
4421 
4422     case FinallyContinuation: {
4423       /*
4424        * Push (true, exception) pair for finally to indicate that [retsub]
4425        * should rethrow the exception.
4426        */
4427       ReservedRooted<Value> exception(&rootValue0);
4428       if (!cx->getPendingException(&exception)) {
4429         interpReturnOK = false;
4430         goto return_continuation;
4431       }
4432       PUSH_BOOLEAN(true);
4433       PUSH_COPY(exception);
4434       cx->clearPendingException();
4435     }
4436       ADVANCE_AND_DISPATCH(0);
4437   }
4438 
4439   MOZ_CRASH("Invalid HandleError continuation");
4440 
4441 exit:
4442   if (MOZ_LIKELY(!frameHalfInitialized)) {
4443     interpReturnOK =
4444         DebugAPI::onLeaveFrame(cx, REGS.fp(), REGS.pc, interpReturnOK);
4445 
4446     REGS.fp()->epilogue(cx, REGS.pc);
4447   }
4448 
4449   gc::MaybeVerifyBarriers(cx, true);
4450 
4451   TraceLogStopEvent(logger, TraceLogger_Engine);
4452   TraceLogStopEvent(logger, scriptEvent);
4453 
4454   /*
4455    * This path is used when it's guaranteed the method can be finished
4456    * inside the JIT.
4457    */
4458 leave_on_safe_point:
4459 
4460   if (interpReturnOK) {
4461     state.setReturnValue(activation.entryFrame()->returnValue());
4462   }
4463 
4464   return interpReturnOK;
4465 
4466 prologue_error:
4467   interpReturnOK = false;
4468   frameHalfInitialized = true;
4469   goto prologue_return_continuation;
4470 }
4471 
ThrowOperation(JSContext * cx,HandleValue v)4472 bool js::ThrowOperation(JSContext* cx, HandleValue v) {
4473   MOZ_ASSERT(!cx->isExceptionPending());
4474   cx->setPendingExceptionAndCaptureStack(v);
4475   return false;
4476 }
4477 
GetProperty(JSContext * cx,HandleValue v,HandlePropertyName name,MutableHandleValue vp)4478 bool js::GetProperty(JSContext* cx, HandleValue v, HandlePropertyName name,
4479                      MutableHandleValue vp) {
4480   if (name == cx->names().length) {
4481     // Fast path for strings, arrays and arguments.
4482     if (GetLengthProperty(v, vp)) {
4483       return true;
4484     }
4485   }
4486 
4487   // Optimize common cases like (2).toString() or "foo".valueOf() to not
4488   // create a wrapper object.
4489   if (v.isPrimitive() && !v.isNullOrUndefined()) {
4490     JSObject* proto;
4491 
4492     switch (v.type()) {
4493       case ValueType::Double:
4494       case ValueType::Int32:
4495         proto = GlobalObject::getOrCreateNumberPrototype(cx, cx->global());
4496         break;
4497       case ValueType::Boolean:
4498         proto = GlobalObject::getOrCreateBooleanPrototype(cx, cx->global());
4499         break;
4500       case ValueType::String:
4501         proto = GlobalObject::getOrCreateStringPrototype(cx, cx->global());
4502         break;
4503       case ValueType::Symbol:
4504         proto = GlobalObject::getOrCreateSymbolPrototype(cx, cx->global());
4505         break;
4506       case ValueType::BigInt:
4507         proto = GlobalObject::getOrCreateBigIntPrototype(cx, cx->global());
4508         break;
4509       case ValueType::Undefined:
4510       case ValueType::Null:
4511       case ValueType::Magic:
4512       case ValueType::PrivateGCThing:
4513       case ValueType::Object:
4514         MOZ_CRASH("unexpected type");
4515     }
4516 
4517     if (!proto) {
4518       return false;
4519     }
4520 
4521     if (GetPropertyPure(cx, proto, NameToId(name), vp.address())) {
4522       return true;
4523     }
4524   }
4525 
4526   RootedValue receiver(cx, v);
4527   RootedObject obj(
4528       cx, ToObjectFromStackForPropertyAccess(cx, v, JSDVG_SEARCH_STACK, name));
4529   if (!obj) {
4530     return false;
4531   }
4532 
4533   return GetProperty(cx, obj, receiver, name, vp);
4534 }
4535 
Lambda(JSContext * cx,HandleFunction fun,HandleObject parent)4536 JSObject* js::Lambda(JSContext* cx, HandleFunction fun, HandleObject parent) {
4537   MOZ_ASSERT(!fun->isArrow());
4538 
4539   JSFunction* clone;
4540   if (fun->isNativeFun()) {
4541     MOZ_ASSERT(IsAsmJSModule(fun));
4542     clone = CloneAsmJSModuleFunction(cx, fun);
4543   } else {
4544     clone = CloneFunctionObject(cx, fun, parent);
4545   }
4546   if (!clone) {
4547     return nullptr;
4548   }
4549 
4550   MOZ_ASSERT(fun->global() == clone->global());
4551   return clone;
4552 }
4553 
LambdaArrow(JSContext * cx,HandleFunction fun,HandleObject parent,HandleValue newTargetv)4554 JSObject* js::LambdaArrow(JSContext* cx, HandleFunction fun,
4555                           HandleObject parent, HandleValue newTargetv) {
4556   MOZ_ASSERT(fun->isArrow());
4557 
4558   JSFunction* clone = CloneFunctionObject(cx, fun, parent);
4559   if (!clone) {
4560     return nullptr;
4561   }
4562 
4563   MOZ_ASSERT(clone->isArrow());
4564   clone->setExtendedSlot(0, newTargetv);
4565 
4566   MOZ_ASSERT(fun->global() == clone->global());
4567   return clone;
4568 }
4569 
BindVarOperation(JSContext * cx,JSObject * envChain)4570 JSObject* js::BindVarOperation(JSContext* cx, JSObject* envChain) {
4571   // Note: BindVarOperation has an unused cx argument because the JIT callVM
4572   // machinery requires this.
4573   return &GetVariablesObject(envChain);
4574 }
4575 
ImportMetaOperation(JSContext * cx,HandleScript script)4576 JSObject* js::ImportMetaOperation(JSContext* cx, HandleScript script) {
4577   RootedObject module(cx, GetModuleObjectForScript(script));
4578   MOZ_ASSERT(module);
4579   return GetOrCreateModuleMetaObject(cx, module);
4580 }
4581 
BuiltinObjectOperation(JSContext * cx,BuiltinObjectKind kind)4582 JSObject* js::BuiltinObjectOperation(JSContext* cx, BuiltinObjectKind kind) {
4583   return GetOrCreateBuiltinObject(cx, kind);
4584 }
4585 
ThrowMsgOperation(JSContext * cx,const unsigned throwMsgKind)4586 bool js::ThrowMsgOperation(JSContext* cx, const unsigned throwMsgKind) {
4587   auto errorNum = ThrowMsgKindToErrNum(ThrowMsgKind(throwMsgKind));
4588   JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, errorNum);
4589   return false;
4590 }
4591 
GetAndClearExceptionAndStack(JSContext * cx,MutableHandleValue res,MutableHandleSavedFrame stack)4592 bool js::GetAndClearExceptionAndStack(JSContext* cx, MutableHandleValue res,
4593                                       MutableHandleSavedFrame stack) {
4594   if (!cx->getPendingException(res)) {
4595     return false;
4596   }
4597   stack.set(cx->getPendingExceptionStack());
4598   cx->clearPendingException();
4599 
4600   // Allow interrupting deeply nested exception handling.
4601   return CheckForInterrupt(cx);
4602 }
4603 
GetAndClearException(JSContext * cx,MutableHandleValue res)4604 bool js::GetAndClearException(JSContext* cx, MutableHandleValue res) {
4605   RootedSavedFrame stack(cx);
4606   return GetAndClearExceptionAndStack(cx, res, &stack);
4607 }
4608 
4609 template <bool strict>
DelPropOperation(JSContext * cx,HandleValue val,HandlePropertyName name,bool * res)4610 bool js::DelPropOperation(JSContext* cx, HandleValue val,
4611                           HandlePropertyName name, bool* res) {
4612   const int valIndex = -1;
4613   RootedObject obj(cx,
4614                    ToObjectFromStackForPropertyAccess(cx, val, valIndex, name));
4615   if (!obj) {
4616     return false;
4617   }
4618 
4619   RootedId id(cx, NameToId(name));
4620   ObjectOpResult result;
4621   if (!DeleteProperty(cx, obj, id, result)) {
4622     return false;
4623   }
4624 
4625   if (strict) {
4626     if (!result) {
4627       return result.reportError(cx, obj, id);
4628     }
4629     *res = true;
4630   } else {
4631     *res = result.ok();
4632   }
4633   return true;
4634 }
4635 
4636 template bool js::DelPropOperation<true>(JSContext* cx, HandleValue val,
4637                                          HandlePropertyName name, bool* res);
4638 template bool js::DelPropOperation<false>(JSContext* cx, HandleValue val,
4639                                           HandlePropertyName name, bool* res);
4640 
4641 template <bool strict>
DelElemOperation(JSContext * cx,HandleValue val,HandleValue index,bool * res)4642 bool js::DelElemOperation(JSContext* cx, HandleValue val, HandleValue index,
4643                           bool* res) {
4644   const int valIndex = -2;
4645   RootedObject obj(
4646       cx, ToObjectFromStackForPropertyAccess(cx, val, valIndex, index));
4647   if (!obj) {
4648     return false;
4649   }
4650 
4651   RootedId id(cx);
4652   if (!ToPropertyKey(cx, index, &id)) {
4653     return false;
4654   }
4655   ObjectOpResult result;
4656   if (!DeleteProperty(cx, obj, id, result)) {
4657     return false;
4658   }
4659 
4660   if (strict) {
4661     if (!result) {
4662       return result.reportError(cx, obj, id);
4663     }
4664     *res = true;
4665   } else {
4666     *res = result.ok();
4667   }
4668   return true;
4669 }
4670 
4671 template bool js::DelElemOperation<true>(JSContext*, HandleValue, HandleValue,
4672                                          bool*);
4673 template bool js::DelElemOperation<false>(JSContext*, HandleValue, HandleValue,
4674                                           bool*);
4675 
SetObjectElement(JSContext * cx,HandleObject obj,HandleValue index,HandleValue value,bool strict)4676 bool js::SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index,
4677                           HandleValue value, bool strict) {
4678   RootedId id(cx);
4679   if (!ToPropertyKey(cx, index, &id)) {
4680     return false;
4681   }
4682   RootedValue receiver(cx, ObjectValue(*obj));
4683   return SetObjectElementOperation(cx, obj, id, value, receiver, strict);
4684 }
4685 
SetObjectElementWithReceiver(JSContext * cx,HandleObject obj,HandleValue index,HandleValue value,HandleValue receiver,bool strict)4686 bool js::SetObjectElementWithReceiver(JSContext* cx, HandleObject obj,
4687                                       HandleValue index, HandleValue value,
4688                                       HandleValue receiver, bool strict) {
4689   RootedId id(cx);
4690   if (!ToPropertyKey(cx, index, &id)) {
4691     return false;
4692   }
4693   return SetObjectElementOperation(cx, obj, id, value, receiver, strict);
4694 }
4695 
AddValues(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4696 bool js::AddValues(JSContext* cx, MutableHandleValue lhs,
4697                    MutableHandleValue rhs, MutableHandleValue res) {
4698   return AddOperation(cx, lhs, rhs, res);
4699 }
4700 
SubValues(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4701 bool js::SubValues(JSContext* cx, MutableHandleValue lhs,
4702                    MutableHandleValue rhs, MutableHandleValue res) {
4703   return SubOperation(cx, lhs, rhs, res);
4704 }
4705 
MulValues(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4706 bool js::MulValues(JSContext* cx, MutableHandleValue lhs,
4707                    MutableHandleValue rhs, MutableHandleValue res) {
4708   return MulOperation(cx, lhs, rhs, res);
4709 }
4710 
DivValues(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4711 bool js::DivValues(JSContext* cx, MutableHandleValue lhs,
4712                    MutableHandleValue rhs, MutableHandleValue res) {
4713   return DivOperation(cx, lhs, rhs, res);
4714 }
4715 
ModValues(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4716 bool js::ModValues(JSContext* cx, MutableHandleValue lhs,
4717                    MutableHandleValue rhs, MutableHandleValue res) {
4718   return ModOperation(cx, lhs, rhs, res);
4719 }
4720 
PowValues(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4721 bool js::PowValues(JSContext* cx, MutableHandleValue lhs,
4722                    MutableHandleValue rhs, MutableHandleValue res) {
4723   return PowOperation(cx, lhs, rhs, res);
4724 }
4725 
BitNot(JSContext * cx,MutableHandleValue in,MutableHandleValue res)4726 bool js::BitNot(JSContext* cx, MutableHandleValue in, MutableHandleValue res) {
4727   return BitNotOperation(cx, in, res);
4728 }
4729 
BitXor(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4730 bool js::BitXor(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
4731                 MutableHandleValue res) {
4732   return BitXorOperation(cx, lhs, rhs, res);
4733 }
4734 
BitOr(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4735 bool js::BitOr(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
4736                MutableHandleValue res) {
4737   return BitOrOperation(cx, lhs, rhs, res);
4738 }
4739 
BitAnd(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4740 bool js::BitAnd(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
4741                 MutableHandleValue res) {
4742   return BitAndOperation(cx, lhs, rhs, res);
4743 }
4744 
BitLsh(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4745 bool js::BitLsh(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
4746                 MutableHandleValue res) {
4747   return BitLshOperation(cx, lhs, rhs, res);
4748 }
4749 
BitRsh(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4750 bool js::BitRsh(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
4751                 MutableHandleValue res) {
4752   return BitRshOperation(cx, lhs, rhs, res);
4753 }
4754 
UrshValues(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4755 bool js::UrshValues(JSContext* cx, MutableHandleValue lhs,
4756                     MutableHandleValue rhs, MutableHandleValue res) {
4757   return UrshOperation(cx, lhs, rhs, res);
4758 }
4759 
LessThan(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,bool * res)4760 bool js::LessThan(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
4761                   bool* res) {
4762   return LessThanOperation(cx, lhs, rhs, res);
4763 }
4764 
LessThanOrEqual(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,bool * res)4765 bool js::LessThanOrEqual(JSContext* cx, MutableHandleValue lhs,
4766                          MutableHandleValue rhs, bool* res) {
4767   return LessThanOrEqualOperation(cx, lhs, rhs, res);
4768 }
4769 
GreaterThan(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,bool * res)4770 bool js::GreaterThan(JSContext* cx, MutableHandleValue lhs,
4771                      MutableHandleValue rhs, bool* res) {
4772   return GreaterThanOperation(cx, lhs, rhs, res);
4773 }
4774 
GreaterThanOrEqual(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,bool * res)4775 bool js::GreaterThanOrEqual(JSContext* cx, MutableHandleValue lhs,
4776                             MutableHandleValue rhs, bool* res) {
4777   return GreaterThanOrEqualOperation(cx, lhs, rhs, res);
4778 }
4779 
AtomicIsLockFree(JSContext * cx,HandleValue in,int * out)4780 bool js::AtomicIsLockFree(JSContext* cx, HandleValue in, int* out) {
4781   int i;
4782   if (!ToInt32(cx, in, &i)) {
4783     return false;
4784   }
4785   *out = js::jit::AtomicOperations::isLockfreeJS(i);
4786   return true;
4787 }
4788 
DeleteNameOperation(JSContext * cx,HandlePropertyName name,HandleObject scopeObj,MutableHandleValue res)4789 bool js::DeleteNameOperation(JSContext* cx, HandlePropertyName name,
4790                              HandleObject scopeObj, MutableHandleValue res) {
4791   RootedObject scope(cx), pobj(cx);
4792   PropertyResult prop;
4793   if (!LookupName(cx, name, scopeObj, &scope, &pobj, &prop)) {
4794     return false;
4795   }
4796 
4797   if (!scope) {
4798     // Return true for non-existent names.
4799     res.setBoolean(true);
4800     return true;
4801   }
4802 
4803   ObjectOpResult result;
4804   RootedId id(cx, NameToId(name));
4805   if (!DeleteProperty(cx, scope, id, result)) {
4806     return false;
4807   }
4808 
4809   bool status = result.ok();
4810   res.setBoolean(status);
4811 
4812   if (status) {
4813     // Deleting a name from the global object removes it from [[VarNames]].
4814     if (pobj == scope && scope->is<GlobalObject>()) {
4815       scope->as<GlobalObject>().realm()->removeFromVarNames(name);
4816     }
4817   }
4818 
4819   return true;
4820 }
4821 
ImplicitThisOperation(JSContext * cx,HandleObject scopeObj,HandlePropertyName name,MutableHandleValue res)4822 bool js::ImplicitThisOperation(JSContext* cx, HandleObject scopeObj,
4823                                HandlePropertyName name,
4824                                MutableHandleValue res) {
4825   RootedObject obj(cx);
4826   if (!LookupNameWithGlobalDefault(cx, name, scopeObj, &obj)) {
4827     return false;
4828   }
4829 
4830   res.set(ComputeImplicitThis(obj));
4831   return true;
4832 }
4833 
GetInitDataPropAttrs(JSOp op)4834 unsigned js::GetInitDataPropAttrs(JSOp op) {
4835   switch (op) {
4836     case JSOp::InitProp:
4837     case JSOp::InitElem:
4838       return JSPROP_ENUMERATE;
4839     case JSOp::InitLockedProp:
4840     case JSOp::InitLockedElem:
4841       return JSPROP_PERMANENT | JSPROP_READONLY;
4842     case JSOp::InitHiddenProp:
4843     case JSOp::InitHiddenElem:
4844       // Non-enumerable, but writable and configurable
4845       return 0;
4846     default:;
4847   }
4848   MOZ_CRASH("Unknown data initprop");
4849 }
4850 
InitGetterSetterOperation(JSContext * cx,jsbytecode * pc,HandleObject obj,HandleId id,HandleObject val)4851 static bool InitGetterSetterOperation(JSContext* cx, jsbytecode* pc,
4852                                       HandleObject obj, HandleId id,
4853                                       HandleObject val) {
4854   MOZ_ASSERT(val->isCallable());
4855 
4856   JSOp op = JSOp(*pc);
4857 
4858   unsigned attrs = 0;
4859   if (!IsHiddenInitOp(op)) {
4860     attrs |= JSPROP_ENUMERATE;
4861   }
4862 
4863   if (op == JSOp::InitPropGetter || op == JSOp::InitElemGetter ||
4864       op == JSOp::InitHiddenPropGetter || op == JSOp::InitHiddenElemGetter) {
4865     return DefineAccessorProperty(cx, obj, id, val, nullptr, attrs);
4866   }
4867 
4868   MOZ_ASSERT(op == JSOp::InitPropSetter || op == JSOp::InitElemSetter ||
4869              op == JSOp::InitHiddenPropSetter ||
4870              op == JSOp::InitHiddenElemSetter);
4871   return DefineAccessorProperty(cx, obj, id, nullptr, val, attrs);
4872 }
4873 
InitPropGetterSetterOperation(JSContext * cx,jsbytecode * pc,HandleObject obj,HandlePropertyName name,HandleObject val)4874 bool js::InitPropGetterSetterOperation(JSContext* cx, jsbytecode* pc,
4875                                        HandleObject obj,
4876                                        HandlePropertyName name,
4877                                        HandleObject val) {
4878   RootedId id(cx, NameToId(name));
4879   return InitGetterSetterOperation(cx, pc, obj, id, val);
4880 }
4881 
InitElemGetterSetterOperation(JSContext * cx,jsbytecode * pc,HandleObject obj,HandleValue idval,HandleObject val)4882 bool js::InitElemGetterSetterOperation(JSContext* cx, jsbytecode* pc,
4883                                        HandleObject obj, HandleValue idval,
4884                                        HandleObject val) {
4885   RootedId id(cx);
4886   if (!ToPropertyKey(cx, idval, &id)) {
4887     return false;
4888   }
4889 
4890   return InitGetterSetterOperation(cx, pc, obj, id, val);
4891 }
4892 
SpreadCallOperation(JSContext * cx,HandleScript script,jsbytecode * pc,HandleValue thisv,HandleValue callee,HandleValue arr,HandleValue newTarget,MutableHandleValue res)4893 bool js::SpreadCallOperation(JSContext* cx, HandleScript script, jsbytecode* pc,
4894                              HandleValue thisv, HandleValue callee,
4895                              HandleValue arr, HandleValue newTarget,
4896                              MutableHandleValue res) {
4897   RootedArrayObject aobj(cx, &arr.toObject().as<ArrayObject>());
4898   uint32_t length = aobj->length();
4899   JSOp op = JSOp(*pc);
4900   bool constructing = op == JSOp::SpreadNew || op == JSOp::SpreadSuperCall;
4901 
4902   // {Construct,Invoke}Args::init does this too, but this gives us a better
4903   // error message.
4904   if (length > ARGS_LENGTH_MAX) {
4905     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
4906                               constructing ? JSMSG_TOO_MANY_CON_SPREADARGS
4907                                            : JSMSG_TOO_MANY_FUN_SPREADARGS);
4908     return false;
4909   }
4910 
4911   // Do our own checks for the callee being a function, as Invoke uses the
4912   // expression decompiler to decompile the callee stack operand based on
4913   // the number of arguments. Spread operations have the callee at sp - 3
4914   // when not constructing, and sp - 4 when constructing.
4915   if (callee.isPrimitive()) {
4916     return ReportIsNotFunction(cx, callee, 2 + constructing,
4917                                constructing ? CONSTRUCT : NO_CONSTRUCT);
4918   }
4919 
4920   if (!callee.toObject().isCallable()) {
4921     return ReportIsNotFunction(cx, callee, 2 + constructing,
4922                                constructing ? CONSTRUCT : NO_CONSTRUCT);
4923   }
4924 
4925   // The object must be an array with dense elements and no holes. Baseline's
4926   // optimized spread call stubs rely on this.
4927   MOZ_ASSERT(IsPackedArray(aobj));
4928 
4929   if (constructing) {
4930     if (!StackCheckIsConstructorCalleeNewTarget(cx, callee, newTarget)) {
4931       return false;
4932     }
4933 
4934     ConstructArgs cargs(cx);
4935     if (!cargs.init(cx, length)) {
4936       return false;
4937     }
4938 
4939     if (!GetElements(cx, aobj, length, cargs.array())) {
4940       return false;
4941     }
4942 
4943     RootedObject obj(cx);
4944     if (!Construct(cx, callee, cargs, newTarget, &obj)) {
4945       return false;
4946     }
4947     res.setObject(*obj);
4948   } else {
4949     InvokeArgs args(cx);
4950     if (!args.init(cx, length)) {
4951       return false;
4952     }
4953 
4954     if (!GetElements(cx, aobj, length, args.array())) {
4955       return false;
4956     }
4957 
4958     if ((op == JSOp::SpreadEval || op == JSOp::StrictSpreadEval) &&
4959         cx->global()->valueIsEval(callee)) {
4960       if (!DirectEval(cx, args.get(0), res)) {
4961         return false;
4962       }
4963     } else {
4964       MOZ_ASSERT(op == JSOp::SpreadCall || op == JSOp::SpreadEval ||
4965                      op == JSOp::StrictSpreadEval,
4966                  "bad spread opcode");
4967 
4968       if (!Call(cx, callee, thisv, args, res)) {
4969         return false;
4970       }
4971     }
4972   }
4973 
4974   return true;
4975 }
4976 
OptimizeSpreadCall(JSContext * cx,HandleValue arg,bool * optimized)4977 bool js::OptimizeSpreadCall(JSContext* cx, HandleValue arg, bool* optimized) {
4978   // Optimize spread call by skipping spread operation when following
4979   // conditions are met:
4980   //   * the argument is an array
4981   //   * the array has no hole
4982   //   * array[@@iterator] is not modified
4983   //   * the array's prototype is Array.prototype
4984   //   * Array.prototype[@@iterator] is not modified
4985   //   * %ArrayIteratorPrototype%.next is not modified
4986   if (!arg.isObject()) {
4987     *optimized = false;
4988     return true;
4989   }
4990 
4991   RootedObject obj(cx, &arg.toObject());
4992   if (!IsPackedArray(obj)) {
4993     *optimized = false;
4994     return true;
4995   }
4996 
4997   ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx);
4998   if (!stubChain) {
4999     return false;
5000   }
5001 
5002   return stubChain->tryOptimizeArray(cx, obj.as<ArrayObject>(), optimized);
5003 }
5004 
NewObjectOperation(JSContext * cx,HandleScript script,jsbytecode * pc,NewObjectKind newKind)5005 JSObject* js::NewObjectOperation(JSContext* cx, HandleScript script,
5006                                  jsbytecode* pc,
5007                                  NewObjectKind newKind /* = GenericObject */) {
5008   // Extract the template object, if one exists, and copy it.
5009   if (JSOp(*pc) == JSOp::NewObject) {
5010     RootedPlainObject baseObject(cx, &script->getObject(pc)->as<PlainObject>());
5011     return CopyTemplateObject(cx, baseObject, newKind);
5012   }
5013 
5014   MOZ_ASSERT(JSOp(*pc) == JSOp::NewInit);
5015   return NewBuiltinClassInstanceWithKind<PlainObject>(cx, newKind);
5016 }
5017 
NewObjectOperationWithTemplate(JSContext * cx,HandleObject templateObject)5018 JSObject* js::NewObjectOperationWithTemplate(JSContext* cx,
5019                                              HandleObject templateObject) {
5020   MOZ_ASSERT(cx->realm() == templateObject->nonCCWRealm());
5021 
5022   NewObjectKind newKind = GenericObject;
5023   return CopyTemplateObject(cx, templateObject.as<PlainObject>(), newKind);
5024 }
5025 
NewPlainObjectBaselineFallback(JSContext * cx,HandleShape shape,gc::AllocKind allocKind,gc::AllocSite * site)5026 JSObject* js::NewPlainObjectBaselineFallback(JSContext* cx, HandleShape shape,
5027                                              gc::AllocKind allocKind,
5028                                              gc::AllocSite* site) {
5029   MOZ_ASSERT(shape->getObjectClass() == &PlainObject::class_);
5030   gc::InitialHeap initialHeap = site->initialHeap();
5031   auto r = NativeObject::create(cx, allocKind, initialHeap, shape, site);
5032   return cx->resultToPtr(r);
5033 }
5034 
NewPlainObjectOptimizedFallback(JSContext * cx,HandleShape shape,gc::AllocKind allocKind,gc::InitialHeap initialHeap)5035 JSObject* js::NewPlainObjectOptimizedFallback(JSContext* cx, HandleShape shape,
5036                                               gc::AllocKind allocKind,
5037                                               gc::InitialHeap initialHeap) {
5038   MOZ_ASSERT(shape->getObjectClass() == &PlainObject::class_);
5039   gc::AllocSite* site = cx->zone()->optimizedAllocSite();
5040   auto r = NativeObject::create(cx, allocKind, initialHeap, shape, site);
5041   return cx->resultToPtr(r);
5042 }
5043 
CreateThisWithTemplate(JSContext * cx,HandleObject templateObject)5044 JSObject* js::CreateThisWithTemplate(JSContext* cx,
5045                                      HandleObject templateObject) {
5046   mozilla::Maybe<AutoRealm> ar;
5047   if (cx->realm() != templateObject->nonCCWRealm()) {
5048     MOZ_ASSERT(cx->compartment() == templateObject->compartment());
5049     ar.emplace(cx, templateObject);
5050   }
5051 
5052   NewObjectKind newKind = GenericObject;
5053   return CopyTemplateObject(cx, templateObject.as<PlainObject>(), newKind);
5054 }
5055 
NewArrayOperation(JSContext * cx,uint32_t length,NewObjectKind newKind)5056 ArrayObject* js::NewArrayOperation(
5057     JSContext* cx, uint32_t length,
5058     NewObjectKind newKind /* = GenericObject */) {
5059   return NewDenseFullyAllocatedArray(cx, length, nullptr, newKind);
5060 }
5061 
NewArrayObjectBaselineFallback(JSContext * cx,uint32_t length,gc::AllocKind allocKind,gc::AllocSite * site)5062 ArrayObject* js::NewArrayObjectBaselineFallback(JSContext* cx, uint32_t length,
5063                                                 gc::AllocKind allocKind,
5064                                                 gc::AllocSite* site) {
5065   NewObjectKind newKind =
5066       site->initialHeap() == gc::TenuredHeap ? TenuredObject : GenericObject;
5067   ArrayObject* array =
5068       NewDenseFullyAllocatedArray(cx, length, nullptr, newKind, site);
5069   // It's important that we allocate an object with the alloc kind we were
5070   // expecting so that a new arena gets allocated if the current arena for that
5071   // kind is full.
5072   MOZ_ASSERT_IF(array && array->isTenured(),
5073                 array->asTenured().getAllocKind() == allocKind);
5074   return array;
5075 }
5076 
NewArrayObjectOptimizedFallback(JSContext * cx,uint32_t length,gc::AllocKind allocKind,NewObjectKind newKind)5077 ArrayObject* js::NewArrayObjectOptimizedFallback(JSContext* cx, uint32_t length,
5078                                                  gc::AllocKind allocKind,
5079                                                  NewObjectKind newKind) {
5080   gc::AllocSite* site = cx->zone()->optimizedAllocSite();
5081   ArrayObject* array =
5082       NewDenseFullyAllocatedArray(cx, length, nullptr, newKind, site);
5083   // It's important that we allocate an object with the alloc kind we were
5084   // expecting so that a new arena gets allocated if the current arena for that
5085   // kind is full.
5086   MOZ_ASSERT_IF(array && array->isTenured(),
5087                 array->asTenured().getAllocKind() == allocKind);
5088   return array;
5089 }
5090 
ReportRuntimeLexicalError(JSContext * cx,unsigned errorNumber,HandleId id)5091 void js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
5092                                    HandleId id) {
5093   MOZ_ASSERT(errorNumber == JSMSG_UNINITIALIZED_LEXICAL ||
5094              errorNumber == JSMSG_BAD_CONST_ASSIGN);
5095   if (UniqueChars printable =
5096           IdToPrintableUTF8(cx, id, IdToPrintableBehavior::IdIsIdentifier)) {
5097     JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, errorNumber,
5098                              printable.get());
5099   }
5100 }
5101 
ReportRuntimeLexicalError(JSContext * cx,unsigned errorNumber,HandlePropertyName name)5102 void js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
5103                                    HandlePropertyName name) {
5104   RootedId id(cx, NameToId(name));
5105   ReportRuntimeLexicalError(cx, errorNumber, id);
5106 }
5107 
ReportRuntimeLexicalError(JSContext * cx,unsigned errorNumber,HandleScript script,jsbytecode * pc)5108 void js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
5109                                    HandleScript script, jsbytecode* pc) {
5110   JSOp op = JSOp(*pc);
5111   MOZ_ASSERT(op == JSOp::CheckLexical || op == JSOp::CheckAliasedLexical ||
5112              op == JSOp::ThrowSetConst || op == JSOp::GetImport);
5113 
5114   RootedPropertyName name(cx);
5115   if (IsLocalOp(op)) {
5116     name = FrameSlotName(script, pc)->asPropertyName();
5117   } else if (IsAliasedVarOp(op)) {
5118     name = EnvironmentCoordinateNameSlow(script, pc);
5119   } else {
5120     MOZ_ASSERT(IsAtomOp(op));
5121     name = script->getName(pc);
5122   }
5123 
5124   ReportRuntimeLexicalError(cx, errorNumber, name);
5125 }
5126 
ReportRuntimeRedeclaration(JSContext * cx,HandlePropertyName name,const char * redeclKind)5127 void js::ReportRuntimeRedeclaration(JSContext* cx, HandlePropertyName name,
5128                                     const char* redeclKind) {
5129   if (UniqueChars printable = AtomToPrintableString(cx, name)) {
5130     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5131                               JSMSG_REDECLARED_VAR, redeclKind,
5132                               printable.get());
5133   }
5134 }
5135 
ThrowCheckIsObject(JSContext * cx,CheckIsObjectKind kind)5136 bool js::ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind) {
5137   switch (kind) {
5138     case CheckIsObjectKind::IteratorNext:
5139       JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5140                                 JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "next");
5141       break;
5142     case CheckIsObjectKind::IteratorReturn:
5143       JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5144                                 JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "return");
5145       break;
5146     case CheckIsObjectKind::IteratorThrow:
5147       JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5148                                 JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "throw");
5149       break;
5150     case CheckIsObjectKind::GetIterator:
5151       JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5152                                 JSMSG_GET_ITER_RETURNED_PRIMITIVE);
5153       break;
5154     case CheckIsObjectKind::GetAsyncIterator:
5155       JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5156                                 JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE);
5157       break;
5158     default:
5159       MOZ_CRASH("Unknown kind");
5160   }
5161   return false;
5162 }
5163 
ThrowUninitializedThis(JSContext * cx)5164 bool js::ThrowUninitializedThis(JSContext* cx) {
5165   JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5166                             JSMSG_UNINITIALIZED_THIS);
5167   return false;
5168 }
5169 
ThrowInitializedThis(JSContext * cx)5170 bool js::ThrowInitializedThis(JSContext* cx) {
5171   JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_REINIT_THIS);
5172   return false;
5173 }
5174 
ThrowHomeObjectNotObject(JSContext * cx)5175 bool js::ThrowHomeObjectNotObject(JSContext* cx) {
5176   JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO,
5177                             "null", "object");
5178   return false;
5179 }
5180 
ThrowObjectCoercible(JSContext * cx,HandleValue value)5181 bool js::ThrowObjectCoercible(JSContext* cx, HandleValue value) {
5182   MOZ_ASSERT(value.isNullOrUndefined());
5183   ReportIsNullOrUndefinedForPropertyAccess(cx, value, JSDVG_SEARCH_STACK);
5184   return false;
5185 }
5186 
SetPropertySuper(JSContext * cx,HandleObject obj,HandleValue receiver,HandlePropertyName name,HandleValue rval,bool strict)5187 bool js::SetPropertySuper(JSContext* cx, HandleObject obj, HandleValue receiver,
5188                           HandlePropertyName name, HandleValue rval,
5189                           bool strict) {
5190   RootedId id(cx, NameToId(name));
5191   ObjectOpResult result;
5192   if (!SetProperty(cx, obj, id, rval, receiver, result)) {
5193     return false;
5194   }
5195 
5196   return result.checkStrictModeError(cx, obj, id, strict);
5197 }
5198 
LoadAliasedDebugVar(JSContext * cx,JSObject * env,jsbytecode * pc,MutableHandleValue result)5199 bool js::LoadAliasedDebugVar(JSContext* cx, JSObject* env, jsbytecode* pc,
5200                              MutableHandleValue result) {
5201   EnvironmentCoordinate ec(pc);
5202 
5203   for (unsigned i = ec.hops(); i; i--) {
5204     if (env->is<EnvironmentObject>()) {
5205       env = &env->as<EnvironmentObject>().enclosingEnvironment();
5206     } else {
5207       MOZ_ASSERT(env->is<DebugEnvironmentProxy>());
5208       env = &env->as<DebugEnvironmentProxy>().enclosingEnvironment();
5209     }
5210   }
5211 
5212   EnvironmentObject& finalEnv =
5213       env->is<EnvironmentObject>()
5214           ? env->as<EnvironmentObject>()
5215           : env->as<DebugEnvironmentProxy>().environment();
5216 
5217   result.set(finalEnv.aliasedBinding(ec));
5218   return true;
5219 }
5220