diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /js/src/vm/Interpreter.h | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | js/src/vm/Interpreter.h | 723 |
1 files changed, 723 insertions, 0 deletions
diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h new file mode 100644 index 0000000000..d962e7f344 --- /dev/null +++ b/js/src/vm/Interpreter.h @@ -0,0 +1,723 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef vm_Interpreter_h +#define vm_Interpreter_h + +/* + * JS interpreter interface. + */ + +#include "jspubtd.h" + +#include "vm/BuiltinObjectKind.h" +#include "vm/CheckIsObjectKind.h" // CheckIsObjectKind +#include "vm/Stack.h" + +namespace js { + +class WithScope; +class EnvironmentIter; +class PlainObject; + +/* + * Convert null/undefined |thisv| into the global lexical's |this| object, and + * replace other primitives with boxed versions. + */ +extern JSObject* BoxNonStrictThis(JSContext* cx, HandleValue thisv); + +extern bool GetFunctionThis(JSContext* cx, AbstractFramePtr frame, + MutableHandleValue res); + +extern void GetNonSyntacticGlobalThis(JSContext* cx, HandleObject envChain, + MutableHandleValue res); + +/* + * numToSkip is the number of stack values the expression decompiler should skip + * before it reaches |v|. If it's -1, the decompiler will search the stack. + */ +extern bool ReportIsNotFunction(JSContext* cx, HandleValue v, int numToSkip, + MaybeConstruct construct = NO_CONSTRUCT); + +/* See ReportIsNotFunction comment for the meaning of numToSkip. */ +extern JSObject* ValueToCallable(JSContext* cx, HandleValue v, + int numToSkip = -1, + MaybeConstruct construct = NO_CONSTRUCT); + +// Reasons why a call could be performed, for passing onto the debugger's +// `onNativeCall` hook. +// `onNativeCall` hook disabled all JITs, and this needs to be handled only in +// the interpreter. +enum class CallReason { + Call, + // callContentFunction or constructContentFunction in self-hosted JS. + CallContent, + // Function.prototype.call or Function.prototype.apply. + FunCall, + Getter, + Setter, +}; + +/* + * Call or construct arguments that are stored in rooted memory. + * + * NOTE: Any necessary |GetThisValue| computation must have been performed on + * |args.thisv()|, likely by the interpreter when pushing |this| onto the + * stack. If you're not sure whether |GetThisValue| processing has been + * performed, use |Invoke|. + */ +extern bool InternalCallOrConstruct(JSContext* cx, const CallArgs& args, + MaybeConstruct construct, + CallReason reason = CallReason::Call); + +/* + * These helpers take care of the infinite-recursion check necessary for + * getter/setter calls. + */ +extern bool CallGetter(JSContext* cx, HandleValue thisv, HandleValue getter, + MutableHandleValue rval); + +extern bool CallSetter(JSContext* cx, HandleValue thisv, HandleValue setter, + HandleValue rval); + +// ES7 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 +// 7.3.12 Call(F, V, argumentsList). +// All parameters are required, hopefully forcing callers to be careful not to +// (say) blindly pass callee as |newTarget| when a different value should have +// been passed. Behavior is unspecified if any element of |args| isn't +// initialized. +// +// |rval| is written to *only* after |fval| and |thisv| have been consumed, so +// |rval| *may* alias either argument. +extern bool Call(JSContext* cx, HandleValue fval, HandleValue thisv, + const AnyInvokeArgs& args, MutableHandleValue rval, + CallReason reason = CallReason::Call); + +inline bool Call(JSContext* cx, HandleValue fval, HandleValue thisv, + MutableHandleValue rval) { + FixedInvokeArgs<0> args(cx); + return Call(cx, fval, thisv, args, rval); +} + +inline bool Call(JSContext* cx, HandleValue fval, JSObject* thisObj, + MutableHandleValue rval) { + RootedValue thisv(cx, ObjectOrNullValue(thisObj)); + FixedInvokeArgs<0> args(cx); + return Call(cx, fval, thisv, args, rval); +} + +inline bool Call(JSContext* cx, HandleValue fval, HandleValue thisv, + HandleValue arg0, MutableHandleValue rval) { + FixedInvokeArgs<1> args(cx); + args[0].set(arg0); + return Call(cx, fval, thisv, args, rval); +} + +inline bool Call(JSContext* cx, HandleValue fval, JSObject* thisObj, + HandleValue arg0, MutableHandleValue rval) { + RootedValue thisv(cx, ObjectOrNullValue(thisObj)); + FixedInvokeArgs<1> args(cx); + args[0].set(arg0); + return Call(cx, fval, thisv, args, rval); +} + +inline bool Call(JSContext* cx, HandleValue fval, HandleValue thisv, + HandleValue arg0, HandleValue arg1, MutableHandleValue rval) { + FixedInvokeArgs<2> args(cx); + args[0].set(arg0); + args[1].set(arg1); + return Call(cx, fval, thisv, args, rval); +} + +inline bool Call(JSContext* cx, HandleValue fval, JSObject* thisObj, + HandleValue arg0, HandleValue arg1, MutableHandleValue rval) { + RootedValue thisv(cx, ObjectOrNullValue(thisObj)); + FixedInvokeArgs<2> args(cx); + args[0].set(arg0); + args[1].set(arg1); + return Call(cx, fval, thisv, args, rval); +} + +inline bool Call(JSContext* cx, HandleValue fval, JSObject* thisObj, + HandleValue arg0, HandleValue arg1, HandleValue arg2, + MutableHandleValue rval) { + RootedValue thisv(cx, ObjectOrNullValue(thisObj)); + FixedInvokeArgs<3> args(cx); + args[0].set(arg0); + args[1].set(arg1); + args[2].set(arg2); + return Call(cx, fval, thisv, args, rval); +} + +// Perform the above Call() operation using the given arguments. Similar to +// ConstructFromStack() below, this handles |!IsCallable(args.calleev())|. +// +// This internal operation is intended only for use with arguments known to be +// on the JS stack, or at least in carefully-rooted memory. The vast majority of +// potential users should instead use InvokeArgs in concert with Call(). +extern bool CallFromStack(JSContext* cx, const CallArgs& args, + CallReason reason = CallReason::Call); + +// ES6 7.3.13 Construct(F, argumentsList, newTarget). All parameters are +// required, hopefully forcing callers to be careful not to (say) blindly pass +// callee as |newTarget| when a different value should have been passed. +// Behavior is unspecified if any element of |args| isn't initialized. +// +// |rval| is written to *only* after |fval| and |newTarget| have been consumed, +// so |rval| *may* alias either argument. +// +// NOTE: As with the ES6 spec operation, it's the caller's responsibility to +// ensure |fval| and |newTarget| are both |IsConstructor|. +extern bool Construct(JSContext* cx, HandleValue fval, + const AnyConstructArgs& args, HandleValue newTarget, + MutableHandleObject objp); + +// Check that in the given |args|, which must be |args.isConstructing()|, that +// |IsConstructor(args.callee())|. If this is not the case, throw a TypeError. +// Otherwise, the user must ensure that, additionally, +// |IsConstructor(args.newTarget())|. (If |args| comes directly from the +// interpreter stack, as set up by JSOp::New, this comes for free.) Then perform +// a Construct() operation using |args|. +// +// This internal operation is intended only for use with arguments known to be +// on the JS stack, or at least in carefully-rooted memory. The vast majority of +// potential users should instead use ConstructArgs in concert with Construct(). +extern bool ConstructFromStack(JSContext* cx, const CallArgs& args, + CallReason reason = CallReason::Call); + +// Call Construct(fval, args, newTarget), but use the given |thisv| as |this| +// during construction of |fval|. +// +// |rval| is written to *only* after |fval|, |thisv|, and |newTarget| have been +// consumed, so |rval| *may* alias any of these arguments. +// +// This method exists only for very rare cases where a |this| was created +// caller-side for construction of |fval|: basically only for JITs using +// |CreateThis|. If that's not you, use Construct()! +extern bool InternalConstructWithProvidedThis(JSContext* cx, HandleValue fval, + HandleValue thisv, + const AnyConstructArgs& args, + HandleValue newTarget, + MutableHandleValue rval); + +/* + * Executes a script with the given envChain. To support debugging, the + * evalInFrame parameter can point to an arbitrary frame in the context's call + * stack to simulate executing an eval in that frame. + */ +extern bool ExecuteKernel(JSContext* cx, HandleScript script, + HandleObject envChainArg, + AbstractFramePtr evalInFrame, + MutableHandleValue result); + +/* Execute a script with the given envChain as global code. */ +extern bool Execute(JSContext* cx, HandleScript script, HandleObject envChain, + MutableHandleValue rval); + +class ExecuteState; +class InvokeState; + +// RunState is passed to RunScript and RunScript then either passes it to the +// interpreter or to the JITs. RunState contains all information we need to +// construct an interpreter or JIT frame. +class MOZ_RAII RunState { + protected: + enum Kind { Execute, Invoke }; + Kind kind_; + + RootedScript script_; + + explicit RunState(JSContext* cx, Kind kind, JSScript* script) + : kind_(kind), script_(cx, script) {} + + public: + bool isExecute() const { return kind_ == Execute; } + bool isInvoke() const { return kind_ == Invoke; } + + ExecuteState* asExecute() const { + MOZ_ASSERT(isExecute()); + return (ExecuteState*)this; + } + InvokeState* asInvoke() const { + MOZ_ASSERT(isInvoke()); + return (InvokeState*)this; + } + + JS::HandleScript script() const { return script_; } + + InterpreterFrame* pushInterpreterFrame(JSContext* cx); + inline void setReturnValue(const Value& v); + + private: + RunState(const RunState& other) = delete; + RunState(const ExecuteState& other) = delete; + RunState(const InvokeState& other) = delete; + void operator=(const RunState& other) = delete; +}; + +// Eval or global script. +class MOZ_RAII ExecuteState : public RunState { + HandleObject envChain_; + + AbstractFramePtr evalInFrame_; + MutableHandleValue result_; + + public: + ExecuteState(JSContext* cx, JSScript* script, HandleObject envChain, + AbstractFramePtr evalInFrame, MutableHandleValue result) + : RunState(cx, Execute, script), + envChain_(envChain), + evalInFrame_(evalInFrame), + result_(result) {} + + JSObject* environmentChain() const { return envChain_; } + bool isDebuggerEval() const { return !!evalInFrame_; } + + InterpreterFrame* pushInterpreterFrame(JSContext* cx); + + void setReturnValue(const Value& v) { result_.set(v); } +}; + +// Data to invoke a function. +class MOZ_RAII InvokeState final : public RunState { + const CallArgs& args_; + MaybeConstruct construct_; + + public: + InvokeState(JSContext* cx, const CallArgs& args, MaybeConstruct construct) + : RunState(cx, Invoke, args.callee().as<JSFunction>().nonLazyScript()), + args_(args), + construct_(construct) {} + + bool constructing() const { return construct_; } + const CallArgs& args() const { return args_; } + + InterpreterFrame* pushInterpreterFrame(JSContext* cx); + + void setReturnValue(const Value& v) { args_.rval().set(v); } +}; + +inline void RunState::setReturnValue(const Value& v) { + if (isInvoke()) { + asInvoke()->setReturnValue(v); + } else { + asExecute()->setReturnValue(v); + } +} + +extern bool RunScript(JSContext* cx, RunState& state); +extern bool Interpret(JSContext* cx, RunState& state); + +extern JSType TypeOfObject(JSObject* obj); + +extern JSType TypeOfValue(const Value& v); + +// Implementation of +// https://www.ecma-international.org/ecma-262/6.0/#sec-instanceofoperator +extern bool InstanceofOperator(JSContext* cx, HandleObject obj, HandleValue v, + bool* bp); + +// Unwind environment chain and iterator to match the scope corresponding to +// the given bytecode position. +extern void UnwindEnvironment(JSContext* cx, EnvironmentIter& ei, + jsbytecode* pc); + +// Unwind all environments. +extern void UnwindAllEnvironmentsInFrame(JSContext* cx, EnvironmentIter& ei); + +// Compute the pc needed to unwind the scope to the beginning of the block +// pointed to by the try note. +extern jsbytecode* UnwindEnvironmentToTryPc(JSScript* script, + const TryNote* tn); + +namespace detail { + +template <class TryNoteFilter> +class MOZ_STACK_CLASS BaseTryNoteIter { + uint32_t pcOffset_; + TryNoteFilter isTryNoteValid_; + + const TryNote* tn_; + const TryNote* tnEnd_; + + void settle() { + for (; tn_ != tnEnd_; ++tn_) { + if (!pcInRange()) { + continue; + } + + /* Try notes cannot be disjoint. That is, we can't have + * multiple notes with disjoint pc ranges jumping to the same + * catch block. This interacts awkwardly with for-of loops, in + * which calls to IteratorClose emitted due to abnormal + * completion (break, throw, return) are emitted inline, at the + * source location of the break, throw, or return + * statement. For example: + * + * for (x of iter) { + * try { return; } catch (e) { } + * } + * + * From the try-note nesting's perspective, the IteratorClose + * resulting from |return| is covered by the inner try, when it + * should not be. If IteratorClose throws, we don't want to + * catch it here. + * + * To make this work, we use TryNoteKind::ForOfIterClose try-notes, + * which cover the range of the abnormal completion. When + * looking up trynotes, a for-of iterclose note indicates that + * the enclosing for-of has just been terminated. As a result, + * trynotes within that for-of are no longer active. When we + * see a for-of-iterclose, we skip ahead in the trynotes list + * until we see the matching for-of. + * + * Breaking out of multiple levels of for-of at once is handled + * using nested TryNoteKind::ForOfIterClose try-notes. Consider this + * code: + * + * try { + * loop: for (i of first) { + * <A> + * for (j of second) { + * <B> + * break loop; // <C1/2> + * } + * } + * } catch {...} + * + * Here is the mapping from various PCs to try-notes that we + * want to return: + * + * A B C1 C2 + * | | | | + * | | | [---|---] ForOfIterClose (outer) + * | | [---|------|---] ForOfIterClose (inner) + * | [--X-----|------|----] ForOf (inner) + * [---X-----------X------|-----] ForOf (outer) + * [------------------------X------] TryCatch + * + * - At A, we find the outer for-of. + * - At B, we find the inner for-of. + * - At C1, we find one TryNoteKind::ForOfIterClose, skip past one + * TryNoteKind::ForOf, and find the outer for-of. (This occurs if an + * exception is thrown while closing the inner iterator.) + * - At C2, we find two TryNoteKind::ForOfIterClose, skip past two + * TryNoteKind::ForOf, and reach the outer try-catch. (This occurs if + * an exception is thrown while closing the outer iterator.) + */ + if (tn_->kind() == TryNoteKind::ForOfIterClose) { + uint32_t iterCloseDepth = 1; + do { + ++tn_; + MOZ_ASSERT(tn_ != tnEnd_); + if (pcInRange()) { + if (tn_->kind() == TryNoteKind::ForOfIterClose) { + iterCloseDepth++; + } else if (tn_->kind() == TryNoteKind::ForOf) { + iterCloseDepth--; + } + } + } while (iterCloseDepth > 0); + + // Advance to trynote following the enclosing for-of. + continue; + } + + /* + * We have a note that covers the exception pc but we must check + * whether the interpreter has already executed the corresponding + * handler. This is possible when the executed bytecode implements + * break or return from inside a for-in loop. + * + * In this case the emitter generates additional [enditer] and [goto] + * opcodes to close all outstanding iterators and execute the finally + * blocks. If such an [enditer] throws an exception, its pc can still + * be inside several nested for-in loops and try-finally statements + * even if we have already closed the corresponding iterators and + * invoked the finally blocks. + * + * To address this, we make [enditer] always decrease the stack even + * when its implementation throws an exception. Thus already executed + * [enditer] and [goto] opcodes will have try notes with the stack + * depth exceeding the current one and this condition is what we use to + * filter them out. + */ + if (tn_ == tnEnd_ || isTryNoteValid_(tn_)) { + return; + } + } + } + + public: + BaseTryNoteIter(JSScript* script, jsbytecode* pc, + TryNoteFilter isTryNoteValid) + : pcOffset_(script->pcToOffset(pc)), isTryNoteValid_(isTryNoteValid) { + // NOTE: The Span is a temporary so we can't use begin()/end() + // here or the iterator will outlive the span. + auto trynotes = script->trynotes(); + tn_ = trynotes.data(); + tnEnd_ = tn_ + trynotes.size(); + + settle(); + } + + void operator++() { + ++tn_; + settle(); + } + + bool pcInRange() const { + // This checks both ends of the range at once + // because unsigned integers wrap on underflow. + uint32_t offset = pcOffset_; + uint32_t start = tn_->start; + uint32_t length = tn_->length; + return offset - start < length; + } + bool done() const { return tn_ == tnEnd_; } + const TryNote* operator*() const { return tn_; } +}; + +} // namespace detail + +template <class TryNoteFilter> +class MOZ_STACK_CLASS TryNoteIter + : public detail::BaseTryNoteIter<TryNoteFilter> { + using Base = detail::BaseTryNoteIter<TryNoteFilter>; + + // Keep the script alive as long as the iterator is live. + RootedScript script_; + + public: + TryNoteIter(JSContext* cx, JSScript* script, jsbytecode* pc, + TryNoteFilter isTryNoteValid) + : Base(script, pc, isTryNoteValid), script_(cx, script) {} +}; + +class NoOpTryNoteFilter { + public: + explicit NoOpTryNoteFilter() = default; + bool operator()(const TryNote*) { return true; } +}; + +// Iterator over all try notes. Code using this iterator is not allowed to +// trigger GC to make sure the script stays alive. See TryNoteIter above for the +// can-GC version. +class MOZ_STACK_CLASS TryNoteIterAllNoGC + : public detail::BaseTryNoteIter<NoOpTryNoteFilter> { + using Base = detail::BaseTryNoteIter<NoOpTryNoteFilter>; + JS::AutoCheckCannotGC nogc; + + public: + TryNoteIterAllNoGC(JSScript* script, jsbytecode* pc) + : Base(script, pc, NoOpTryNoteFilter()) {} +}; + +bool HandleClosingGeneratorReturn(JSContext* cx, AbstractFramePtr frame, + bool ok); + +/************************************************************************/ + +bool ThrowOperation(JSContext* cx, HandleValue v); + +bool ThrowWithStackOperation(JSContext* cx, HandleValue v, HandleValue stack); + +bool GetPendingExceptionStack(JSContext* cx, MutableHandleValue vp); + +bool GetProperty(JSContext* cx, HandleValue value, Handle<PropertyName*> name, + MutableHandleValue vp); + +JSObject* Lambda(JSContext* cx, HandleFunction fun, HandleObject parent); + +bool SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index, + HandleValue value, bool strict); + +bool SetObjectElementWithReceiver(JSContext* cx, HandleObject obj, + HandleValue index, HandleValue value, + HandleValue receiver, bool strict); + +bool AddValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, + MutableHandleValue res); + +bool SubValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, + MutableHandleValue res); + +bool MulValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, + MutableHandleValue res); + +bool DivValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, + MutableHandleValue res); + +bool ModValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, + MutableHandleValue res); + +bool PowValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, + MutableHandleValue res); + +bool BitNot(JSContext* cx, MutableHandleValue in, MutableHandleValue res); + +bool BitXor(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, + MutableHandleValue res); + +bool BitOr(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, + MutableHandleValue res); + +bool BitAnd(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, + MutableHandleValue res); + +bool BitLsh(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, + MutableHandleValue res); + +bool BitRsh(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, + MutableHandleValue res); + +bool UrshValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, + MutableHandleValue res); + +bool LessThan(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, + bool* res); + +bool LessThanOrEqual(JSContext* cx, MutableHandleValue lhs, + MutableHandleValue rhs, bool* res); + +bool GreaterThan(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, + bool* res); + +bool GreaterThanOrEqual(JSContext* cx, MutableHandleValue lhs, + MutableHandleValue rhs, bool* res); + +bool AtomicIsLockFree(JSContext* cx, HandleValue in, int* out); + +template <bool strict> +bool DelPropOperation(JSContext* cx, HandleValue val, + Handle<PropertyName*> name, bool* res); + +template <bool strict> +bool DelElemOperation(JSContext* cx, HandleValue val, HandleValue index, + bool* res); + +JSObject* BindVarOperation(JSContext* cx, JSObject* envChain); + +JSObject* ImportMetaOperation(JSContext* cx, HandleScript script); + +JSObject* BuiltinObjectOperation(JSContext* cx, BuiltinObjectKind kind); + +bool ThrowMsgOperation(JSContext* cx, const unsigned throwMsgKind); + +bool GetAndClearException(JSContext* cx, MutableHandleValue res); + +bool GetAndClearExceptionAndStack(JSContext* cx, MutableHandleValue res, + MutableHandle<SavedFrame*> stack); + +bool DeleteNameOperation(JSContext* cx, Handle<PropertyName*> name, + HandleObject scopeObj, MutableHandleValue res); + +bool ImplicitThisOperation(JSContext* cx, HandleObject scopeObj, + Handle<PropertyName*> name, MutableHandleValue res); + +bool InitPropGetterSetterOperation(JSContext* cx, jsbytecode* pc, + HandleObject obj, Handle<PropertyName*> name, + HandleObject val); + +unsigned GetInitDataPropAttrs(JSOp op); + +bool EnterWithOperation(JSContext* cx, AbstractFramePtr frame, HandleValue val, + Handle<WithScope*> scope); + +bool InitElemGetterSetterOperation(JSContext* cx, jsbytecode* pc, + HandleObject obj, HandleValue idval, + HandleObject val); + +bool SpreadCallOperation(JSContext* cx, HandleScript script, jsbytecode* pc, + HandleValue thisv, HandleValue callee, HandleValue arr, + HandleValue newTarget, MutableHandleValue res); + +bool OptimizeSpreadCall(JSContext* cx, HandleValue arg, + MutableHandleValue result); + +bool OptimizeGetIterator(JSContext* cx, HandleValue arg, bool* result); + +ArrayObject* ArrayFromArgumentsObject(JSContext* cx, + Handle<ArgumentsObject*> args); + +JSObject* NewObjectOperation(JSContext* cx, HandleScript script, + const jsbytecode* pc); + +JSObject* NewPlainObjectBaselineFallback(JSContext* cx, + Handle<SharedShape*> shape, + gc::AllocKind allocKind, + gc::AllocSite* site); + +JSObject* NewPlainObjectOptimizedFallback(JSContext* cx, + Handle<SharedShape*> shape, + gc::AllocKind allocKind, + gc::Heap initialHeap); + +ArrayObject* NewArrayOperation(JSContext* cx, uint32_t length, + NewObjectKind newKind = GenericObject); + +// Called from JIT code when inline array allocation fails. +ArrayObject* NewArrayObjectBaselineFallback(JSContext* cx, uint32_t length, + gc::AllocKind allocKind, + gc::AllocSite* site); +ArrayObject* NewArrayObjectOptimizedFallback(JSContext* cx, uint32_t length, + gc::AllocKind allocKind, + NewObjectKind newKind); + +[[nodiscard]] bool GetImportOperation(JSContext* cx, HandleObject envChain, + HandleScript script, jsbytecode* pc, + MutableHandleValue vp); + +void ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber, + HandleId id); + +void ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber, + Handle<PropertyName*> name); + +void ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber, + HandleScript script, jsbytecode* pc); + +void ReportInNotObjectError(JSContext* cx, HandleValue lref, HandleValue rref); + +// The parser only reports redeclarations that occurs within a single +// script. Due to the extensibility of the global lexical scope, we also check +// for redeclarations during runtime in JSOp::GlobalOrEvalDeclInstantation. +void ReportRuntimeRedeclaration(JSContext* cx, Handle<PropertyName*> name, + const char* redeclKind); + +bool ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind); + +bool ThrowUninitializedThis(JSContext* cx); + +bool ThrowInitializedThis(JSContext* cx); + +bool ThrowObjectCoercible(JSContext* cx, HandleValue value); + +bool DefaultClassConstructor(JSContext* cx, unsigned argc, Value* vp); + +bool Debug_CheckSelfHosted(JSContext* cx, HandleValue funVal); + +bool CheckClassHeritageOperation(JSContext* cx, HandleValue heritage); + +PlainObject* ObjectWithProtoOperation(JSContext* cx, HandleValue proto); + +JSObject* FunWithProtoOperation(JSContext* cx, HandleFunction fun, + HandleObject parent, HandleObject proto); + +bool SetPropertySuper(JSContext* cx, HandleValue lval, HandleValue receiver, + Handle<PropertyName*> name, HandleValue rval, + bool strict); + +bool SetElementSuper(JSContext* cx, HandleValue lval, HandleValue receiver, + HandleValue index, HandleValue rval, bool strict); + +bool LoadAliasedDebugVar(JSContext* cx, JSObject* env, jsbytecode* pc, + MutableHandleValue result); + +bool CloseIterOperation(JSContext* cx, HandleObject iter, CompletionKind kind); +} /* namespace js */ + +#endif /* vm_Interpreter_h */ |