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 #ifndef vm_Interpreter_h
8 #define vm_Interpreter_h
9 
10 /*
11  * JS interpreter interface.
12  */
13 
14 #include "jspubtd.h"
15 
16 #include "vm/BuiltinObjectKind.h"
17 #include "vm/CheckIsObjectKind.h"  // CheckIsObjectKind
18 #include "vm/Iteration.h"
19 #include "vm/Stack.h"
20 
21 namespace js {
22 
23 class WithScope;
24 class EnvironmentIter;
25 class PlainObject;
26 
27 /*
28  * Convert null/undefined |thisv| into the global lexical's |this| object, and
29  * replace other primitives with boxed versions.
30  */
31 extern JSObject* BoxNonStrictThis(JSContext* cx, HandleValue thisv);
32 
33 extern bool GetFunctionThis(JSContext* cx, AbstractFramePtr frame,
34                             MutableHandleValue res);
35 
36 extern void GetNonSyntacticGlobalThis(JSContext* cx, HandleObject envChain,
37                                       MutableHandleValue res);
38 
39 /*
40  * numToSkip is the number of stack values the expression decompiler should skip
41  * before it reaches |v|. If it's -1, the decompiler will search the stack.
42  */
43 extern bool ReportIsNotFunction(JSContext* cx, HandleValue v, int numToSkip,
44                                 MaybeConstruct construct = NO_CONSTRUCT);
45 
46 /* See ReportIsNotFunction comment for the meaning of numToSkip. */
47 extern JSObject* ValueToCallable(JSContext* cx, HandleValue v,
48                                  int numToSkip = -1,
49                                  MaybeConstruct construct = NO_CONSTRUCT);
50 
51 // Reasons why a call could be performed, for passing onto the debugger.
52 enum class CallReason { Call, Getter, Setter };
53 
54 /*
55  * Call or construct arguments that are stored in rooted memory.
56  *
57  * NOTE: Any necessary |GetThisValue| computation must have been performed on
58  *       |args.thisv()|, likely by the interpreter when pushing |this| onto the
59  *       stack.  If you're not sure whether |GetThisValue| processing has been
60  *       performed, use |Invoke|.
61  */
62 extern bool InternalCallOrConstruct(JSContext* cx, const CallArgs& args,
63                                     MaybeConstruct construct,
64                                     CallReason reason = CallReason::Call);
65 
66 /*
67  * These helpers take care of the infinite-recursion check necessary for
68  * getter/setter calls.
69  */
70 extern bool CallGetter(JSContext* cx, HandleValue thisv, HandleValue getter,
71                        MutableHandleValue rval);
72 
73 extern bool CallSetter(JSContext* cx, HandleValue thisv, HandleValue setter,
74                        HandleValue rval);
75 
76 // ES7 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93
77 // 7.3.12 Call(F, V, argumentsList).
78 // All parameters are required, hopefully forcing callers to be careful not to
79 // (say) blindly pass callee as |newTarget| when a different value should have
80 // been passed.  Behavior is unspecified if any element of |args| isn't
81 // initialized.
82 //
83 // |rval| is written to *only* after |fval| and |thisv| have been consumed, so
84 // |rval| *may* alias either argument.
85 extern bool Call(JSContext* cx, HandleValue fval, HandleValue thisv,
86                  const AnyInvokeArgs& args, MutableHandleValue rval,
87                  CallReason reason = CallReason::Call);
88 
Call(JSContext * cx,HandleValue fval,HandleValue thisv,MutableHandleValue rval)89 inline bool Call(JSContext* cx, HandleValue fval, HandleValue thisv,
90                  MutableHandleValue rval) {
91   FixedInvokeArgs<0> args(cx);
92   return Call(cx, fval, thisv, args, rval);
93 }
94 
Call(JSContext * cx,HandleValue fval,JSObject * thisObj,MutableHandleValue rval)95 inline bool Call(JSContext* cx, HandleValue fval, JSObject* thisObj,
96                  MutableHandleValue rval) {
97   RootedValue thisv(cx, ObjectOrNullValue(thisObj));
98   FixedInvokeArgs<0> args(cx);
99   return Call(cx, fval, thisv, args, rval);
100 }
101 
Call(JSContext * cx,HandleValue fval,HandleValue thisv,HandleValue arg0,MutableHandleValue rval)102 inline bool Call(JSContext* cx, HandleValue fval, HandleValue thisv,
103                  HandleValue arg0, MutableHandleValue rval) {
104   FixedInvokeArgs<1> args(cx);
105   args[0].set(arg0);
106   return Call(cx, fval, thisv, args, rval);
107 }
108 
Call(JSContext * cx,HandleValue fval,JSObject * thisObj,HandleValue arg0,MutableHandleValue rval)109 inline bool Call(JSContext* cx, HandleValue fval, JSObject* thisObj,
110                  HandleValue arg0, MutableHandleValue rval) {
111   RootedValue thisv(cx, ObjectOrNullValue(thisObj));
112   FixedInvokeArgs<1> args(cx);
113   args[0].set(arg0);
114   return Call(cx, fval, thisv, args, rval);
115 }
116 
Call(JSContext * cx,HandleValue fval,HandleValue thisv,HandleValue arg0,HandleValue arg1,MutableHandleValue rval)117 inline bool Call(JSContext* cx, HandleValue fval, HandleValue thisv,
118                  HandleValue arg0, HandleValue arg1, MutableHandleValue rval) {
119   FixedInvokeArgs<2> args(cx);
120   args[0].set(arg0);
121   args[1].set(arg1);
122   return Call(cx, fval, thisv, args, rval);
123 }
124 
Call(JSContext * cx,HandleValue fval,JSObject * thisObj,HandleValue arg0,HandleValue arg1,MutableHandleValue rval)125 inline bool Call(JSContext* cx, HandleValue fval, JSObject* thisObj,
126                  HandleValue arg0, HandleValue arg1, MutableHandleValue rval) {
127   RootedValue thisv(cx, ObjectOrNullValue(thisObj));
128   FixedInvokeArgs<2> args(cx);
129   args[0].set(arg0);
130   args[1].set(arg1);
131   return Call(cx, fval, thisv, args, rval);
132 }
133 
134 // Perform the above Call() operation using the given arguments.  Similar to
135 // ConstructFromStack() below, this handles |!IsCallable(args.calleev())|.
136 //
137 // This internal operation is intended only for use with arguments known to be
138 // on the JS stack, or at least in carefully-rooted memory. The vast majority of
139 // potential users should instead use InvokeArgs in concert with Call().
140 extern bool CallFromStack(JSContext* cx, const CallArgs& args);
141 
142 // ES6 7.3.13 Construct(F, argumentsList, newTarget).  All parameters are
143 // required, hopefully forcing callers to be careful not to (say) blindly pass
144 // callee as |newTarget| when a different value should have been passed.
145 // Behavior is unspecified if any element of |args| isn't initialized.
146 //
147 // |rval| is written to *only* after |fval| and |newTarget| have been consumed,
148 // so |rval| *may* alias either argument.
149 //
150 // NOTE: As with the ES6 spec operation, it's the caller's responsibility to
151 //       ensure |fval| and |newTarget| are both |IsConstructor|.
152 extern bool Construct(JSContext* cx, HandleValue fval,
153                       const AnyConstructArgs& args, HandleValue newTarget,
154                       MutableHandleObject objp);
155 
156 // Check that in the given |args|, which must be |args.isConstructing()|, that
157 // |IsConstructor(args.callee())|. If this is not the case, throw a TypeError.
158 // Otherwise, the user must ensure that, additionally,
159 // |IsConstructor(args.newTarget())|. (If |args| comes directly from the
160 // interpreter stack, as set up by JSOp::New, this comes for free.) Then perform
161 // a Construct() operation using |args|.
162 //
163 // This internal operation is intended only for use with arguments known to be
164 // on the JS stack, or at least in carefully-rooted memory. The vast majority of
165 // potential users should instead use ConstructArgs in concert with Construct().
166 extern bool ConstructFromStack(JSContext* cx, const CallArgs& args);
167 
168 // Call Construct(fval, args, newTarget), but use the given |thisv| as |this|
169 // during construction of |fval|.
170 //
171 // |rval| is written to *only* after |fval|, |thisv|, and |newTarget| have been
172 // consumed, so |rval| *may* alias any of these arguments.
173 //
174 // This method exists only for very rare cases where a |this| was created
175 // caller-side for construction of |fval|: basically only for JITs using
176 // |CreateThis|.  If that's not you, use Construct()!
177 extern bool InternalConstructWithProvidedThis(JSContext* cx, HandleValue fval,
178                                               HandleValue thisv,
179                                               const AnyConstructArgs& args,
180                                               HandleValue newTarget,
181                                               MutableHandleValue rval);
182 
183 /*
184  * Executes a script with the given envChain. To support debugging, the
185  * evalInFrame parameter can point to an arbitrary frame in the context's call
186  * stack to simulate executing an eval in that frame.
187  */
188 extern bool ExecuteKernel(JSContext* cx, HandleScript script,
189                           HandleObject envChainArg, HandleValue newTargetValue,
190                           AbstractFramePtr evalInFrame,
191                           MutableHandleValue result);
192 
193 /* Execute a script with the given envChain as global code. */
194 extern bool Execute(JSContext* cx, HandleScript script, HandleObject envChain,
195                     MutableHandleValue rval);
196 
197 class ExecuteState;
198 class InvokeState;
199 
200 // RunState is passed to RunScript and RunScript then either passes it to the
201 // interpreter or to the JITs. RunState contains all information we need to
202 // construct an interpreter or JIT frame.
203 class MOZ_RAII RunState {
204  protected:
205   enum Kind { Execute, Invoke };
206   Kind kind_;
207 
208   RootedScript script_;
209 
RunState(JSContext * cx,Kind kind,JSScript * script)210   explicit RunState(JSContext* cx, Kind kind, JSScript* script)
211       : kind_(kind), script_(cx, script) {}
212 
213  public:
isExecute()214   bool isExecute() const { return kind_ == Execute; }
isInvoke()215   bool isInvoke() const { return kind_ == Invoke; }
216 
asExecute()217   ExecuteState* asExecute() const {
218     MOZ_ASSERT(isExecute());
219     return (ExecuteState*)this;
220   }
asInvoke()221   InvokeState* asInvoke() const {
222     MOZ_ASSERT(isInvoke());
223     return (InvokeState*)this;
224   }
225 
script()226   JS::HandleScript script() const { return script_; }
227 
228   InterpreterFrame* pushInterpreterFrame(JSContext* cx);
229   inline void setReturnValue(const Value& v);
230 
231  private:
232   RunState(const RunState& other) = delete;
233   RunState(const ExecuteState& other) = delete;
234   RunState(const InvokeState& other) = delete;
235   void operator=(const RunState& other) = delete;
236 };
237 
238 // Eval or global script.
239 class MOZ_RAII ExecuteState : public RunState {
240   RootedValue newTargetValue_;
241   HandleObject envChain_;
242 
243   AbstractFramePtr evalInFrame_;
244   MutableHandleValue result_;
245 
246  public:
ExecuteState(JSContext * cx,JSScript * script,HandleValue newTargetValue,HandleObject envChain,AbstractFramePtr evalInFrame,MutableHandleValue result)247   ExecuteState(JSContext* cx, JSScript* script, HandleValue newTargetValue,
248                HandleObject envChain, AbstractFramePtr evalInFrame,
249                MutableHandleValue result)
250       : RunState(cx, Execute, script),
251         newTargetValue_(cx, newTargetValue),
252         envChain_(envChain),
253         evalInFrame_(evalInFrame),
254         result_(result) {}
255 
newTarget()256   Value newTarget() const { return newTargetValue_; }
addressOfNewTarget()257   Value* addressOfNewTarget() { return newTargetValue_.address(); }
258 
environmentChain()259   JSObject* environmentChain() const { return envChain_; }
isDebuggerEval()260   bool isDebuggerEval() const { return !!evalInFrame_; }
261 
262   InterpreterFrame* pushInterpreterFrame(JSContext* cx);
263 
setReturnValue(const Value & v)264   void setReturnValue(const Value& v) { result_.set(v); }
265 };
266 
267 // Data to invoke a function.
268 class MOZ_RAII InvokeState final : public RunState {
269   const CallArgs& args_;
270   MaybeConstruct construct_;
271 
272  public:
InvokeState(JSContext * cx,const CallArgs & args,MaybeConstruct construct)273   InvokeState(JSContext* cx, const CallArgs& args, MaybeConstruct construct)
274       : RunState(cx, Invoke, args.callee().as<JSFunction>().nonLazyScript()),
275         args_(args),
276         construct_(construct) {}
277 
constructing()278   bool constructing() const { return construct_; }
args()279   const CallArgs& args() const { return args_; }
280 
281   InterpreterFrame* pushInterpreterFrame(JSContext* cx);
282 
setReturnValue(const Value & v)283   void setReturnValue(const Value& v) { args_.rval().set(v); }
284 };
285 
setReturnValue(const Value & v)286 inline void RunState::setReturnValue(const Value& v) {
287   if (isInvoke()) {
288     asInvoke()->setReturnValue(v);
289   } else {
290     asExecute()->setReturnValue(v);
291   }
292 }
293 
294 extern bool RunScript(JSContext* cx, RunState& state);
295 
296 extern JSType TypeOfObject(JSObject* obj);
297 
298 extern JSType TypeOfValue(const Value& v);
299 
300 extern bool HasInstance(JSContext* cx, HandleObject obj, HandleValue v,
301                         bool* bp);
302 
303 // Unwind environment chain and iterator to match the scope corresponding to
304 // the given bytecode position.
305 extern void UnwindEnvironment(JSContext* cx, EnvironmentIter& ei,
306                               jsbytecode* pc);
307 
308 // Unwind all environments.
309 extern void UnwindAllEnvironmentsInFrame(JSContext* cx, EnvironmentIter& ei);
310 
311 // Compute the pc needed to unwind the scope to the beginning of the block
312 // pointed to by the try note.
313 extern jsbytecode* UnwindEnvironmentToTryPc(JSScript* script,
314                                             const TryNote* tn);
315 
316 namespace detail {
317 
318 template <class TryNoteFilter>
319 class MOZ_STACK_CLASS BaseTryNoteIter {
320   uint32_t pcOffset_;
321   TryNoteFilter isTryNoteValid_;
322 
323   const TryNote* tn_;
324   const TryNote* tnEnd_;
325 
settle()326   void settle() {
327     for (; tn_ != tnEnd_; ++tn_) {
328       if (!pcInRange()) {
329         continue;
330       }
331 
332       /*  Try notes cannot be disjoint. That is, we can't have
333        *  multiple notes with disjoint pc ranges jumping to the same
334        *  catch block. This interacts awkwardly with for-of loops, in
335        *  which calls to IteratorClose emitted due to abnormal
336        *  completion (break, throw, return) are emitted inline, at the
337        *  source location of the break, throw, or return
338        *  statement. For example:
339        *
340        *      for (x of iter) {
341        *        try { return; } catch (e) { }
342        *      }
343        *
344        *  From the try-note nesting's perspective, the IteratorClose
345        *  resulting from |return| is covered by the inner try, when it
346        *  should not be. If IteratorClose throws, we don't want to
347        *  catch it here.
348        *
349        *  To make this work, we use TryNoteKind::ForOfIterClose try-notes,
350        *  which cover the range of the abnormal completion. When
351        *  looking up trynotes, a for-of iterclose note indicates that
352        *  the enclosing for-of has just been terminated. As a result,
353        *  trynotes within that for-of are no longer active. When we
354        *  see a for-of-iterclose, we skip ahead in the trynotes list
355        *  until we see the matching for-of.
356        *
357        *  Breaking out of multiple levels of for-of at once is handled
358        *  using nested FOR_OF_ITERCLOSE try-notes. Consider this code:
359        *
360        *  try {
361        *    loop: for (i of first) {
362        *      <A>
363        *      for (j of second) {
364        *        <B>
365        *        break loop; // <C1/2>
366        *      }
367        *    }
368        *  } catch {...}
369        *
370        *  Here is the mapping from various PCs to try-notes that we
371        *  want to return:
372        *
373        *        A     B     C1     C2
374        *        |     |     |      |
375        *        |     |     |  [---|---]     ForOfIterClose (outer)
376        *        |     | [---|------|---]     ForOfIterClose (inner)
377        *        |  [--X-----|------|----]    ForOf (inner)
378        *    [---X-----------X------|-----]   ForOf (outer)
379        *  [------------------------X------]  TryCatch
380        *
381        *  - At A, we find the outer for-of.
382        *  - At B, we find the inner for-of.
383        *  - At C1, we find one FOR_OF_ITERCLOSE, skip past one FOR_OF, and find
384        *    the outer for-of. (This occurs if an exception is thrown while
385        *    closing the inner iterator.)
386        *  - At C2, we find two FOR_OF_ITERCLOSE, skip past two FOR_OF, and reach
387        *    the outer try-catch. (This occurs if an exception is thrown while
388        *    closing the outer iterator.)
389        */
390       if (tn_->kind() == TryNoteKind::ForOfIterClose) {
391         uint32_t iterCloseDepth = 1;
392         do {
393           ++tn_;
394           MOZ_ASSERT(tn_ != tnEnd_);
395           if (pcInRange()) {
396             if (tn_->kind() == TryNoteKind::ForOfIterClose) {
397               iterCloseDepth++;
398             } else if (tn_->kind() == TryNoteKind::ForOf) {
399               iterCloseDepth--;
400             }
401           }
402         } while (iterCloseDepth > 0);
403 
404         // Advance to trynote following the enclosing for-of.
405         continue;
406       }
407 
408       /*
409        * We have a note that covers the exception pc but we must check
410        * whether the interpreter has already executed the corresponding
411        * handler. This is possible when the executed bytecode implements
412        * break or return from inside a for-in loop.
413        *
414        * In this case the emitter generates additional [enditer] and [gosub]
415        * opcodes to close all outstanding iterators and execute the finally
416        * blocks. If such an [enditer] throws an exception, its pc can still
417        * be inside several nested for-in loops and try-finally statements
418        * even if we have already closed the corresponding iterators and
419        * invoked the finally blocks.
420        *
421        * To address this, we make [enditer] always decrease the stack even
422        * when its implementation throws an exception. Thus already executed
423        * [enditer] and [gosub] opcodes will have try notes with the stack
424        * depth exceeding the current one and this condition is what we use to
425        * filter them out.
426        */
427       if (tn_ == tnEnd_ || isTryNoteValid_(tn_)) {
428         return;
429       }
430     }
431   }
432 
433  public:
BaseTryNoteIter(JSScript * script,jsbytecode * pc,TryNoteFilter isTryNoteValid)434   BaseTryNoteIter(JSScript* script, jsbytecode* pc,
435                   TryNoteFilter isTryNoteValid)
436       : pcOffset_(script->pcToOffset(pc)), isTryNoteValid_(isTryNoteValid) {
437     // NOTE: The Span is a temporary so we can't use begin()/end()
438     // here or the iterator will outlive the span.
439     auto trynotes = script->trynotes();
440     tn_ = trynotes.data();
441     tnEnd_ = tn_ + trynotes.size();
442 
443     settle();
444   }
445 
446   void operator++() {
447     ++tn_;
448     settle();
449   }
450 
pcInRange()451   bool pcInRange() const {
452     // This checks both ends of the range at once
453     // because unsigned integers wrap on underflow.
454     uint32_t offset = pcOffset_;
455     uint32_t start = tn_->start;
456     uint32_t length = tn_->length;
457     return offset - start < length;
458   }
done()459   bool done() const { return tn_ == tnEnd_; }
460   const TryNote* operator*() const { return tn_; }
461 };
462 
463 }  // namespace detail
464 
465 template <class TryNoteFilter>
466 class MOZ_STACK_CLASS TryNoteIter
467     : public detail::BaseTryNoteIter<TryNoteFilter> {
468   using Base = detail::BaseTryNoteIter<TryNoteFilter>;
469 
470   // Keep the script alive as long as the iterator is live.
471   RootedScript script_;
472 
473  public:
TryNoteIter(JSContext * cx,JSScript * script,jsbytecode * pc,TryNoteFilter isTryNoteValid)474   TryNoteIter(JSContext* cx, JSScript* script, jsbytecode* pc,
475               TryNoteFilter isTryNoteValid)
476       : Base(script, pc, isTryNoteValid), script_(cx, script) {}
477 };
478 
479 class NoOpTryNoteFilter {
480  public:
481   explicit NoOpTryNoteFilter() = default;
operator()482   bool operator()(const TryNote*) { return true; }
483 };
484 
485 // Iterator over all try notes. Code using this iterator is not allowed to
486 // trigger GC to make sure the script stays alive. See TryNoteIter above for the
487 // can-GC version.
488 class MOZ_STACK_CLASS TryNoteIterAllNoGC
489     : public detail::BaseTryNoteIter<NoOpTryNoteFilter> {
490   using Base = detail::BaseTryNoteIter<NoOpTryNoteFilter>;
491   JS::AutoCheckCannotGC nogc;
492 
493  public:
TryNoteIterAllNoGC(JSScript * script,jsbytecode * pc)494   TryNoteIterAllNoGC(JSScript* script, jsbytecode* pc)
495       : Base(script, pc, NoOpTryNoteFilter()) {}
496 };
497 
498 bool HandleClosingGeneratorReturn(JSContext* cx, AbstractFramePtr frame,
499                                   bool ok);
500 
501 /************************************************************************/
502 
503 bool ThrowOperation(JSContext* cx, HandleValue v);
504 
505 bool GetProperty(JSContext* cx, HandleValue value, HandlePropertyName name,
506                  MutableHandleValue vp);
507 
508 JSObject* Lambda(JSContext* cx, HandleFunction fun, HandleObject parent);
509 
510 JSObject* LambdaArrow(JSContext* cx, HandleFunction fun, HandleObject parent,
511                       HandleValue newTargetv);
512 
513 bool SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index,
514                       HandleValue value, bool strict);
515 
516 bool SetObjectElementWithReceiver(JSContext* cx, HandleObject obj,
517                                   HandleValue index, HandleValue value,
518                                   HandleValue receiver, bool strict);
519 
520 bool AddValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
521                MutableHandleValue res);
522 
523 bool SubValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
524                MutableHandleValue res);
525 
526 bool MulValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
527                MutableHandleValue res);
528 
529 bool DivValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
530                MutableHandleValue res);
531 
532 bool ModValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
533                MutableHandleValue res);
534 
535 bool PowValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
536                MutableHandleValue res);
537 
538 bool BitNot(JSContext* cx, MutableHandleValue in, MutableHandleValue res);
539 
540 bool BitXor(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
541             MutableHandleValue res);
542 
543 bool BitOr(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
544            MutableHandleValue res);
545 
546 bool BitAnd(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
547             MutableHandleValue res);
548 
549 bool BitLsh(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
550             MutableHandleValue res);
551 
552 bool BitRsh(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
553             MutableHandleValue res);
554 
555 bool UrshValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
556                 MutableHandleValue res);
557 
558 bool LessThan(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
559               bool* res);
560 
561 bool LessThanOrEqual(JSContext* cx, MutableHandleValue lhs,
562                      MutableHandleValue rhs, bool* res);
563 
564 bool GreaterThan(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
565                  bool* res);
566 
567 bool GreaterThanOrEqual(JSContext* cx, MutableHandleValue lhs,
568                         MutableHandleValue rhs, bool* res);
569 
570 bool AtomicIsLockFree(JSContext* cx, HandleValue in, int* out);
571 
572 template <bool strict>
573 bool DelPropOperation(JSContext* cx, HandleValue val, HandlePropertyName name,
574                       bool* res);
575 
576 template <bool strict>
577 bool DelElemOperation(JSContext* cx, HandleValue val, HandleValue index,
578                       bool* res);
579 
580 JSObject* BindVarOperation(JSContext* cx, JSObject* envChain);
581 
582 JSObject* ImportMetaOperation(JSContext* cx, HandleScript script);
583 
584 JSObject* BuiltinObjectOperation(JSContext* cx, BuiltinObjectKind kind);
585 
586 bool ThrowMsgOperation(JSContext* cx, const unsigned throwMsgKind);
587 
588 bool GetAndClearException(JSContext* cx, MutableHandleValue res);
589 
590 bool GetAndClearExceptionAndStack(JSContext* cx, MutableHandleValue res,
591                                   MutableHandleSavedFrame stack);
592 
593 bool DeleteNameOperation(JSContext* cx, HandlePropertyName name,
594                          HandleObject scopeObj, MutableHandleValue res);
595 
596 bool ImplicitThisOperation(JSContext* cx, HandleObject scopeObj,
597                            HandlePropertyName name, MutableHandleValue res);
598 
599 bool InitPropGetterSetterOperation(JSContext* cx, jsbytecode* pc,
600                                    HandleObject obj, HandlePropertyName name,
601                                    HandleObject val);
602 
603 unsigned GetInitDataPropAttrs(JSOp op);
604 
605 bool EnterWithOperation(JSContext* cx, AbstractFramePtr frame, HandleValue val,
606                         Handle<WithScope*> scope);
607 
608 bool InitElemGetterSetterOperation(JSContext* cx, jsbytecode* pc,
609                                    HandleObject obj, HandleValue idval,
610                                    HandleObject val);
611 
612 bool SpreadCallOperation(JSContext* cx, HandleScript script, jsbytecode* pc,
613                          HandleValue thisv, HandleValue callee, HandleValue arr,
614                          HandleValue newTarget, MutableHandleValue res);
615 
616 bool OptimizeSpreadCall(JSContext* cx, HandleValue arg, bool* optimized);
617 
618 JSObject* NewObjectOperation(JSContext* cx, HandleScript script, jsbytecode* pc,
619                              NewObjectKind newKind = GenericObject);
620 
621 JSObject* NewObjectOperationWithTemplate(JSContext* cx,
622                                          HandleObject templateObject);
623 
624 JSObject* NewPlainObjectBaselineFallback(JSContext* cx, HandleShape shape,
625                                          gc::AllocKind allocKind,
626                                          gc::AllocSite* site);
627 
628 JSObject* NewPlainObjectOptimizedFallback(JSContext* cx, HandleShape shape,
629                                           gc::AllocKind allocKind,
630                                           gc::InitialHeap initialHeap);
631 
632 JSObject* CreateThisWithTemplate(JSContext* cx, HandleObject templateObject);
633 
634 ArrayObject* NewArrayOperation(JSContext* cx, uint32_t length,
635                                NewObjectKind newKind = GenericObject);
636 
637 // Called from JIT code when inline array allocation fails.
638 ArrayObject* NewArrayObjectBaselineFallback(JSContext* cx, uint32_t length,
639                                             gc::AllocKind allocKind,
640                                             gc::AllocSite* site);
641 ArrayObject* NewArrayObjectOptimizedFallback(JSContext* cx, uint32_t length,
642                                              gc::AllocKind allocKind,
643                                              NewObjectKind newKind);
644 
645 [[nodiscard]] bool GetImportOperation(JSContext* cx, HandleObject envChain,
646                                       HandleScript script, jsbytecode* pc,
647                                       MutableHandleValue vp);
648 
649 void ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
650                                HandleId id);
651 
652 void ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
653                                HandlePropertyName name);
654 
655 void ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
656                                HandleScript script, jsbytecode* pc);
657 
658 void ReportInNotObjectError(JSContext* cx, HandleValue lref, HandleValue rref);
659 
660 // The parser only reports redeclarations that occurs within a single
661 // script. Due to the extensibility of the global lexical scope, we also check
662 // for redeclarations during runtime in JSOp::GlobalOrEvalDeclInstantation.
663 void ReportRuntimeRedeclaration(JSContext* cx, HandlePropertyName name,
664                                 const char* redeclKind);
665 
666 bool ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind);
667 
668 bool ThrowUninitializedThis(JSContext* cx);
669 
670 bool ThrowInitializedThis(JSContext* cx);
671 
672 bool ThrowHomeObjectNotObject(JSContext* cx);
673 
674 bool ThrowObjectCoercible(JSContext* cx, HandleValue value);
675 
676 bool DefaultClassConstructor(JSContext* cx, unsigned argc, Value* vp);
677 
678 bool Debug_CheckSelfHosted(JSContext* cx, HandleValue v);
679 
680 bool CheckClassHeritageOperation(JSContext* cx, HandleValue heritage);
681 
682 PlainObject* ObjectWithProtoOperation(JSContext* cx, HandleValue proto);
683 
684 JSObject* FunWithProtoOperation(JSContext* cx, HandleFunction fun,
685                                 HandleObject parent, HandleObject proto);
686 
687 bool SetPropertySuper(JSContext* cx, HandleObject obj, HandleValue receiver,
688                       HandlePropertyName id, HandleValue rval, bool strict);
689 
690 bool LoadAliasedDebugVar(JSContext* cx, JSObject* env, jsbytecode* pc,
691                          MutableHandleValue result);
692 } /* namespace js */
693 
694 #endif /* vm_Interpreter_h */
695