summaryrefslogtreecommitdiffstats
path: root/js/src/vm/Opcodes.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /js/src/vm/Opcodes.h
parentInitial commit. (diff)
downloadthunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz
thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/vm/Opcodes.h')
-rw-r--r--js/src/vm/Opcodes.h3632
1 files changed, 3632 insertions, 0 deletions
diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h
new file mode 100644
index 0000000000..d26ea4de39
--- /dev/null
+++ b/js/src/vm/Opcodes.h
@@ -0,0 +1,3632 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sw=2 et tw=0 ft=c:
+ *
+ * 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_Opcodes_h
+#define vm_Opcodes_h
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "js/TypeDecls.h"
+
+// clang-format off
+/*
+ * [SMDOC] Bytecode Definitions
+ *
+ * SpiderMonkey bytecode instructions.
+ *
+ * To use this header, define a macro of the form:
+ *
+ * #define MACRO(op, op_snake, token, length, nuses, ndefs, format) ...
+ *
+ * Then `FOR_EACH_OPCODE(MACRO)` invokes `MACRO` for every opcode.
+ *
+ * Field Description
+ * ----- -----------
+ * op UpperCamelCase form of opcode id
+ * op_snake snake_case form of opcode id
+ * token Pretty-printer string, or null if ugly
+ * length Number of bytes including any immediate operands
+ * nuses Number of stack slots consumed by bytecode, -1 if variadic
+ * ndefs Number of stack slots produced by bytecode
+ * format JOF_ flags describing instruction operand layout, etc.
+ *
+ * For more about `format`, see the comments on the `JOF_` constants defined in
+ * BytecodeUtil.h.
+ *
+ *
+ * [SMDOC] Bytecode Invariants
+ *
+ * Creating scripts that do not follow the rules can lead to undefined
+ * behavior. Bytecode has many consumers, not just the interpreter: JITs,
+ * analyses, the debugger. That's why the rules below apply even to code that
+ * can't be reached in ordinary execution (such as code after an infinite loop
+ * or inside an `if (false)` block).
+ *
+ * The `code()` of a script must be a packed (not aligned) sequence of valid
+ * instructions from start to end. Each instruction has a single byte opcode
+ * followed by a number of operand bytes based on the opcode.
+ *
+ * ## Jump instructions
+ *
+ * Operands named `offset`, `forwardOffset`, or `defaultOffset` are jump
+ * offsets, the distance in bytes from the start of the current instruction to
+ * the start of another instruction in the same script. Operands named
+ * `forwardOffset` or `defaultOffset` must be positive.
+ *
+ * Forward jumps must jump to a `JSOp::JumpTarget` instruction. Backward jumps,
+ * indicated by negative offsets, must jump to a `JSOp::LoopHead` instruction.
+ * Jump offsets can't be zero.
+ *
+ * Needless to say, scripts must not contain overlapping instruction sequences
+ * (in the sense of <https://en.wikipedia.org/wiki/Overlapping_gene>).
+ *
+ * A script's `trynotes` and `scopeNotes` impose further constraints. Each try
+ * note and each scope note marks a region of the bytecode where some invariant
+ * holds, or some cleanup behavior is needed--that there's a for-in iterator in
+ * a particular stack slot, for instance, which must be closed on error. All
+ * paths into the span must establish that invariant. In practice, this means
+ * other code never jumps into the span: the only way in is to execute the
+ * bytecode instruction that sets up the invariant (in our example,
+ * `JSOp::Iter`).
+ *
+ * If a script's `trynotes` (see "Try Notes" in JSScript.h) contain a
+ * `JSTRY_CATCH` or `JSTRY_FINALLY` span, there must be a `JSOp::Try`
+ * instruction immediately before the span and a `JSOp::JumpTarget immediately
+ * after it. Instructions must not jump to this `JSOp::JumpTarget`. (The VM puts
+ * us there on exception.) Furthermore, the instruction sequence immediately
+ * following a `JSTRY_CATCH` span must read `JumpTarget; Exception` or, in
+ * non-function scripts, `JumpTarget; Undefined; SetRval; Exception`. (These
+ * instructions run with an exception pending; other instructions aren't
+ * designed to handle that.)
+ *
+ * Unreachable instructions are allowed, but they have to follow all the rules.
+ *
+ * Control must not reach the end of a script. (Currently, the last instruction
+ * is always JSOp::RetRval.)
+ *
+ * ## Other operands
+ *
+ * Operands named `nameIndex` or `atomIndex` (which appear on instructions that
+ * have `JOF_ATOM` in the `format` field) must be valid indexes into
+ * `script->atoms()`.
+ *
+ * Operands named `argc` (`JOF_ARGC`) are argument counts for call
+ * instructions. `argc` must be small enough that the instruction's nuses is <=
+ * the current stack depth (see "Stack depth" below).
+ *
+ * Operands named `argno` (`JOF_QARG`) refer to an argument of the current
+ * function. `argno` must be in the range `0..script->function()->nargs()`.
+ * Instructions with these operands must appear only in function scripts.
+ *
+ * Operands named `localno` (`JOF_LOCAL`) refer to a local variable stored in
+ * the stack frame. `localno` must be in the range `0..script->nfixed()`.
+ *
+ * Operands named `resumeIndex` (`JOF_RESUMEINDEX`) refer to a resume point in
+ * the current script. `resumeIndex` must be a valid index into
+ * `script->resumeOffsets()`.
+ *
+ * Operands named `hops` and `slot` (`JOF_ENVCOORD`) refer a slot in an
+ * `EnvironmentObject`. At run time, they must point to a fixed slot in an
+ * object on the current environment chain. See `EnvironmentCoordinates`.
+ *
+ * Operands with the following names must be valid indexes into
+ * `script->gcthings()`, and the pointer in the vector must point to the right
+ * type of thing:
+ *
+ * - `objectIndex` (`JOF_OBJECT`): `PlainObject*` or `ArrayObject*`
+ * - `baseobjIndex` (`JOF_OBJECT`): `PlainObject*`
+ * - `funcIndex` (`JOF_OBJECT`): `JSFunction*`
+ * - `regexpIndex` (`JOF_REGEXP`): `RegExpObject*`
+ * - `shapeIndex` (`JOF_SHAPE`): `Shape*`
+ * - `scopeIndex` (`JOF_SCOPE`): `Scope*`
+ * - `lexicalScopeIndex` (`JOF_SCOPE`): `LexicalScope*`
+ * - `classBodyScopeIndex` (`JOF_SCOPE`): `ClassBodyScope*`
+ * - `withScopeIndex` (`JOF_SCOPE`): `WithScope*`
+ * - `bigIntIndex` (`JOF_BIGINT`): `BigInt*`
+ *
+ * Operands named `icIndex` (`JOF_ICINDEX`) must be exactly the number of
+ * preceding instructions in the script that have the JOF_IC flag.
+ * (Rationale: Each JOF_IC instruction has a unique entry in
+ * `script->jitScript()->icEntries()`. At run time, in the bytecode
+ * interpreter, we have to find that entry. We could store the IC index as an
+ * operand to each JOF_IC instruction, but it's more memory-efficient to use a
+ * counter and reset the counter to `icIndex` after each jump.)
+ *
+ * ## Stack depth
+ *
+ * Each instruction has a compile-time stack depth, the number of values on the
+ * interpreter stack just before executing the instruction. It isn't explicitly
+ * present in the bytecode itself, but (for reachable instructions, anyway)
+ * it's a function of the bytecode.
+ *
+ * - The first instruction has stack depth 0.
+ *
+ * - Each successor of an instruction X has a stack depth equal to
+ *
+ * X's stack depth - `js::StackUses(X)` + `js::StackDefs(X)`
+ *
+ * except for `JSOp::Case` (below).
+ *
+ * X's "successors" are: the next instruction in the script, if
+ * `js::FlowsIntoNext(op)` is true for X's opcode; one or more
+ * `JSOp::JumpTarget`s elsewhere, if X is a forward jump or
+ * `JSOp::TableSwitch`; and/or a `JSOp::LoopHead` if it's a backward jump.
+ *
+ * - `JSOp::Case` is a special case because its stack behavior is eccentric.
+ * The formula above is correct for the next instruction. The jump target
+ * has a stack depth that is 1 less.
+ *
+ * - The `JSOp::JumpTarget` instruction immediately following a `JSTRY_CATCH`
+ * or `JSTRY_FINALLY` span has the same stack depth as the `JSOp::Try`
+ * instruction that precedes the span.
+ *
+ * Every instruction covered by the `JSTRY_CATCH` or `JSTRY_FINALLY` span
+ * must have a stack depth >= that value, so that error recovery is
+ * guaranteed to find enough values on the stack to resume there.
+ *
+ * - `script->nslots() - script->nfixed()` must be >= the maximum stack
+ * depth of any instruction in `script`. (The stack frame must be big
+ * enough to run the code.)
+ *
+ * `BytecodeParser::parse()` computes stack depths for every reachable
+ * instruction in a script.
+ *
+ * ## Scopes and environments
+ *
+ * As with stack depth, each instruction has a static scope, which is a
+ * compile-time characterization of the eventual run-time environment chain
+ * when that instruction executes. Just as every instruction has a stack budget
+ * (nuses/ndefs), every instruction either pushes a scope, pops a scope, or
+ * neither. The same successor relation applies as above.
+ *
+ * Every scope used in a script is stored in the `JSScript::gcthings()` vector.
+ * They can be accessed using `getScope(index)` if you know what `index` to
+ * pass.
+ *
+ * The scope of every instruction (that's reachable via the successor relation)
+ * is given in two independent ways: by the bytecode itself and by the scope
+ * notes. The two sources must agree.
+ *
+ * ## Further rules
+ *
+ * All reachable instructions must be reachable without taking any backward
+ * edges.
+ *
+ * Instructions with the `JOF_CHECKSLOPPY` flag must not be used in strict mode
+ * code. `JOF_CHECKSTRICT` instructions must not be used in nonstrict code.
+ *
+ * Many instructions have their own additional rules. These are documented on
+ * the various opcodes below (look for the word "must").
+ */
+// clang-format on
+
+// clang-format off
+/*
+ * SpiderMonkey bytecode categorization (as used in generated documentation):
+ *
+ * [Index]
+ * [Constants]
+ * [Compound primitives]
+ * Record literals
+ * Tuple literals
+ * [Expressions]
+ * Unary operators
+ * Binary operators
+ * Conversions
+ * Other expressions
+ * [Objects]
+ * Creating objects
+ * Defining properties
+ * Accessing properties
+ * Super
+ * Enumeration
+ * Iteration
+ * SetPrototype
+ * Array literals
+ * RegExp literals
+ * Built-in objects
+ * [Functions]
+ * Creating functions
+ * Creating constructors
+ * Calls
+ * Generators and async functions
+ * [Control flow]
+ * Jump targets
+ * Jumps
+ * Return
+ * Exceptions
+ * [Variables and scopes]
+ * Initialization
+ * Looking up bindings
+ * Getting binding values
+ * Setting binding values
+ * Entering and leaving environments
+ * Creating and deleting bindings
+ * Function environment setup
+ * [Stack operations]
+ * [Other]
+ */
+// clang-format on
+
+// clang-format off
+#define FOR_EACH_OPCODE(MACRO) \
+ /*
+ * Push `undefined`.
+ *
+ * Category: Constants
+ * Operands:
+ * Stack: => undefined
+ */ \
+ MACRO(Undefined, undefined, "", 1, 0, 1, JOF_BYTE) \
+ /*
+ * Push `null`.
+ *
+ * Category: Constants
+ * Operands:
+ * Stack: => null
+ */ \
+ MACRO(Null, null, "null", 1, 0, 1, JOF_BYTE) \
+ /*
+ * Push a boolean constant.
+ *
+ * Category: Constants
+ * Operands:
+ * Stack: => true/false
+ */ \
+ MACRO(False, false_, "false", 1, 0, 1, JOF_BYTE) \
+ MACRO(True, true_, "true", 1, 0, 1, JOF_BYTE) \
+ /*
+ * Push the `int32_t` immediate operand as an `Int32Value`.
+ *
+ * `JSOp::Zero`, `JSOp::One`, `JSOp::Int8`, `JSOp::Uint16`, and `JSOp::Uint24`
+ * are all compact encodings for `JSOp::Int32`.
+ *
+ * Category: Constants
+ * Operands: int32_t val
+ * Stack: => val
+ */ \
+ MACRO(Int32, int32, NULL, 5, 0, 1, JOF_INT32) \
+ /*
+ * Push the number `0`.
+ *
+ * Category: Constants
+ * Operands:
+ * Stack: => 0
+ */ \
+ MACRO(Zero, zero, "0", 1, 0, 1, JOF_BYTE) \
+ /*
+ * Push the number `1`.
+ *
+ * Category: Constants
+ * Operands:
+ * Stack: => 1
+ */ \
+ MACRO(One, one, "1", 1, 0, 1, JOF_BYTE) \
+ /*
+ * Push the `int8_t` immediate operand as an `Int32Value`.
+ *
+ * Category: Constants
+ * Operands: int8_t val
+ * Stack: => val
+ */ \
+ MACRO(Int8, int8, NULL, 2, 0, 1, JOF_INT8) \
+ /*
+ * Push the `uint16_t` immediate operand as an `Int32Value`.
+ *
+ * Category: Constants
+ * Operands: uint16_t val
+ * Stack: => val
+ */ \
+ MACRO(Uint16, uint16, NULL, 3, 0, 1, JOF_UINT16) \
+ /*
+ * Push the `uint24_t` immediate operand as an `Int32Value`.
+ *
+ * Category: Constants
+ * Operands: uint24_t val
+ * Stack: => val
+ */ \
+ MACRO(Uint24, uint24, NULL, 4, 0, 1, JOF_UINT24) \
+ /*
+ * Push the 64-bit floating-point immediate operand as a `DoubleValue`.
+ *
+ * If the operand is a NaN, it must be the canonical NaN (see
+ * `JS::detail::CanonicalizeNaN`).
+ *
+ * Category: Constants
+ * Operands: double val
+ * Stack: => val
+ */ \
+ MACRO(Double, double_, NULL, 9, 0, 1, JOF_DOUBLE) \
+ /*
+ * Push the BigInt constant `script->getBigInt(bigIntIndex)`.
+ *
+ * Category: Constants
+ * Operands: uint32_t bigIntIndex
+ * Stack: => bigint
+ */ \
+ MACRO(BigInt, big_int, NULL, 5, 0, 1, JOF_BIGINT) \
+ /*
+ * Push the string constant `script->getAtom(atomIndex)`.
+ *
+ * Category: Constants
+ * Operands: uint32_t atomIndex
+ * Stack: => string
+ */ \
+ MACRO(String, string, NULL, 5, 0, 1, JOF_STRING) \
+ /*
+ * Push a well-known symbol.
+ *
+ * `symbol` must be in range for `JS::SymbolCode`.
+ *
+ * Category: Constants
+ * Operands: uint8_t symbol (the JS::SymbolCode of the symbol to use)
+ * Stack: => symbol
+ */ \
+ MACRO(Symbol, symbol, NULL, 2, 0, 1, JOF_UINT8) \
+ /*
+ * Pop the top value on the stack, discard it, and push `undefined`.
+ *
+ * Implements: [The `void` operator][1], step 3.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-void-operator
+ *
+ * Category: Expressions
+ * Type: Unary operators
+ * Operands:
+ * Stack: val => undefined
+ */ \
+ MACRO(Void, void_, NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * [The `typeof` operator][1].
+ *
+ * Infallible. The result is always a string that depends on the [type][2]
+ * of `val`.
+ *
+ * `JSOp::Typeof` and `JSOp::TypeofExpr` are the same except
+ * that--amazingly--`JSOp::Typeof` affects the behavior of an immediately
+ * *preceding* `JSOp::GetName` or `JSOp::GetGName` instruction! This is how
+ * we implement [`typeof`][1] step 2, making `typeof nonExistingVariable`
+ * return `"undefined"` instead of throwing a ReferenceError.
+ *
+ * In a global scope:
+ *
+ * - `typeof x` compiles to `GetGName "x"; Typeof`.
+ * - `typeof (0, x)` compiles to `GetGName "x"; TypeofExpr`.
+ *
+ * Emitting the same bytecode for these two expressions would be a bug.
+ * Per spec, the latter throws a ReferenceError if `x` doesn't exist.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-typeof-operator
+ * [2]: https://tc39.es/ecma262/#sec-ecmascript-language-types
+ *
+ * Category: Expressions
+ * Type: Unary operators
+ * Operands:
+ * Stack: val => (typeof val)
+ */ \
+ MACRO(Typeof, typeof_, NULL, 1, 1, 1, JOF_BYTE|JOF_IC) \
+ MACRO(TypeofExpr, typeof_expr, NULL, 1, 1, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * [The unary `+` operator][1].
+ *
+ * `+val` doesn't do any actual math. It just calls [ToNumber][2](val).
+ *
+ * The conversion can call `.toString()`/`.valueOf()` methods and can
+ * throw. The result on success is always a Number. (Per spec, unary `-`
+ * supports BigInts, but unary `+` does not.)
+ *
+ * [1]: https://tc39.es/ecma262/#sec-unary-plus-operator
+ * [2]: https://tc39.es/ecma262/#sec-tonumber
+ *
+ * Category: Expressions
+ * Type: Unary operators
+ * Operands:
+ * Stack: val => (+val)
+ */ \
+ MACRO(Pos, pos, "+ ", 1, 1, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * [The unary `-` operator][1].
+ *
+ * Convert `val` to a numeric value, then push `-val`. The conversion can
+ * call `.toString()`/`.valueOf()` methods and can throw. The result on
+ * success is always numeric.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-unary-minus-operator
+ *
+ * Category: Expressions
+ * Type: Unary operators
+ * Operands:
+ * Stack: val => (-val)
+ */ \
+ MACRO(Neg, neg, "- ", 1, 1, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * [The bitwise NOT operator][1] (`~`).
+ *
+ * `val` is converted to an integer, then bitwise negated. The conversion
+ * can call `.toString()`/`.valueOf()` methods and can throw. The result on
+ * success is always an Int32 or BigInt value.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-bitwise-not-operator
+ *
+ * Category: Expressions
+ * Type: Unary operators
+ * Operands:
+ * Stack: val => (~val)
+ */ \
+ MACRO(BitNot, bit_not, "~", 1, 1, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * [The logical NOT operator][1] (`!`).
+ *
+ * `val` is first converted with [ToBoolean][2], then logically
+ * negated. The result is always a boolean value. This does not call
+ * user-defined methods and can't throw.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-logical-not-operator
+ * [2]: https://tc39.es/ecma262/#sec-toboolean
+ *
+ * Category: Expressions
+ * Type: Unary operators
+ * Operands:
+ * Stack: val => (!val)
+ */ \
+ MACRO(Not, not_, "!", 1, 1, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * [Binary bitwise operations][1] (`|`, `^`, `&`).
+ *
+ * The arguments are converted to integers first. The conversion can call
+ * `.toString()`/`.valueOf()` methods and can throw. The result on success
+ * is always an Int32 or BigInt Value.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-binary-bitwise-operators
+ *
+ * Category: Expressions
+ * Type: Binary operators
+ * Operands:
+ * Stack: lval, rval => (lval OP rval)
+ */ \
+ MACRO(BitOr, bit_or, "|", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(BitXor, bit_xor, "^", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(BitAnd, bit_and, "&", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * Loose equality operators (`==` and `!=`).
+ *
+ * Pop two values, compare them, and push the boolean result. The
+ * comparison may perform conversions that call `.toString()`/`.valueOf()`
+ * methods and can throw.
+ *
+ * Implements: [Abstract Equality Comparison][1].
+ *
+ * [1]: https://tc39.es/ecma262/#sec-abstract-equality-comparison
+ *
+ * Category: Expressions
+ * Type: Binary operators
+ * Operands:
+ * Stack: lval, rval => (lval OP rval)
+ */ \
+ MACRO(Eq, eq, "==", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(Ne, ne, "!=", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * Strict equality operators (`===` and `!==`).
+ *
+ * Pop two values, check whether they're equal, and push the boolean
+ * result. This does not call user-defined methods and can't throw
+ * (except possibly due to OOM while flattening a string).
+ *
+ * Implements: [Strict Equality Comparison][1].
+ *
+ * [1]: https://tc39.es/ecma262/#sec-strict-equality-comparison
+ *
+ * Category: Expressions
+ * Type: Binary operators
+ * Operands:
+ * Stack: lval, rval => (lval OP rval)
+ */ \
+ MACRO(StrictEq, strict_eq, "===", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(StrictNe, strict_ne, "!==", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * Relative operators (`<`, `>`, `<=`, `>=`).
+ *
+ * Pop two values, compare them, and push the boolean result. The
+ * comparison may perform conversions that call `.toString()`/`.valueOf()`
+ * methods and can throw.
+ *
+ * Implements: [Relational Operators: Evaluation][1].
+ *
+ * [1]: https://tc39.es/ecma262/#sec-relational-operators-runtime-semantics-evaluation
+ *
+ * Category: Expressions
+ * Type: Binary operators
+ * Operands:
+ * Stack: lval, rval => (lval OP rval)
+ */ \
+ MACRO(Lt, lt, "<", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(Gt, gt, ">", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(Le, le, "<=", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(Ge, ge, ">=", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * [The `instanceof` operator][1].
+ *
+ * This throws a `TypeError` if `target` is not an object. It calls
+ * `target[Symbol.hasInstance](value)` if the method exists. On success,
+ * the result is always a boolean value.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-instanceofoperator
+ *
+ * Category: Expressions
+ * Type: Binary operators
+ * Operands:
+ * Stack: value, target => (value instanceof target)
+ */ \
+ MACRO(Instanceof, instanceof, "instanceof", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * [The `in` operator][1].
+ *
+ * Push `true` if `obj` has a property with the key `id`. Otherwise push `false`.
+ *
+ * This throws a `TypeError` if `obj` is not an object. This can fire
+ * proxy hooks and can throw. On success, the result is always a boolean
+ * value.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-relational-operators-runtime-semantics-evaluation
+ *
+ * Category: Expressions
+ * Type: Binary operators
+ * Operands:
+ * Stack: id, obj => (id in obj)
+ */ \
+ MACRO(In, in_, "in", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * [Bitwise shift operators][1] (`<<`, `>>`, `>>>`).
+ *
+ * Pop two values, convert them to integers, perform a bitwise shift, and
+ * push the result.
+ *
+ * Conversion can call `.toString()`/`.valueOf()` methods and can throw.
+ * The result on success is always an Int32 or BigInt Value.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-bitwise-shift-operators
+ *
+ * Category: Expressions
+ * Type: Binary operators
+ * Operands:
+ * Stack: lval, rval => (lval OP rval)
+ */ \
+ MACRO(Lsh, lsh, "<<", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(Rsh, rsh, ">>", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(Ursh, ursh, ">>>", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * [The binary `+` operator][1].
+ *
+ * Pop two values, convert them to primitive values, add them, and push the
+ * result. If both values are numeric, add them; if either is a
+ * string, do string concatenation instead.
+ *
+ * The conversion can call `.toString()`/`.valueOf()` methods and can throw.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-addition-operator-plus-runtime-semantics-evaluation
+ *
+ * Category: Expressions
+ * Type: Binary operators
+ * Operands:
+ * Stack: lval, rval => (lval + rval)
+ */ \
+ MACRO(Add, add, "+", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * [The binary `-` operator][1].
+ *
+ * Pop two values, convert them to numeric values, subtract the top value
+ * from the other one, and push the result.
+ *
+ * The conversion can call `.toString()`/`.valueOf()` methods and can
+ * throw. On success, the result is always numeric.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-subtraction-operator-minus-runtime-semantics-evaluation
+ *
+ * Category: Expressions
+ * Type: Binary operators
+ * Operands:
+ * Stack: lval, rval => (lval - rval)
+ */ \
+ MACRO(Sub, sub, "-", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * Add or subtract 1.
+ *
+ * `val` must already be a numeric value, such as the result of
+ * `JSOp::ToNumeric`.
+ *
+ * Implements: [The `++` and `--` operators][1], step 3 of each algorithm.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-postfix-increment-operator
+ *
+ * Category: Expressions
+ * Type: Binary operators
+ * Operands:
+ * Stack: val => (val +/- 1)
+ */ \
+ MACRO(Inc, inc, NULL, 1, 1, 1, JOF_BYTE|JOF_IC) \
+ MACRO(Dec, dec, NULL, 1, 1, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * [The multiplicative operators][1] (`*`, `/`, `%`).
+ *
+ * Pop two values, convert them to numeric values, do math, and push the
+ * result.
+ *
+ * The conversion can call `.toString()`/`.valueOf()` methods and can
+ * throw. On success, the result is always numeric.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-multiplicative-operators-runtime-semantics-evaluation
+ *
+ * Category: Expressions
+ * Type: Binary operators
+ * Operands:
+ * Stack: lval, rval => (lval OP rval)
+ */ \
+ MACRO(Mul, mul, "*", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(Div, div, "/", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(Mod, mod, "%", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * [The exponentiation operator][1] (`**`).
+ *
+ * Pop two values, convert them to numeric values, do exponentiation, and
+ * push the result. The top value is the exponent.
+ *
+ * The conversion can call `.toString()`/`.valueOf()` methods and can
+ * throw. This throws a RangeError if both values are BigInts and the
+ * exponent is negative.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-exp-operator
+ *
+ * Category: Expressions
+ * Type: Binary operators
+ * Operands:
+ * Stack: lval, rval => (lval ** rval)
+ */ \
+ MACRO(Pow, pow, "**", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * Convert a value to a property key.
+ *
+ * Implements: [ToPropertyKey][1], except that if the result would be the
+ * string representation of some integer in the range 0..2^31, we push the
+ * corresponding Int32 value instead. This is because the spec insists that
+ * array indices are strings, whereas for us they are integers.
+ *
+ * This is used for code like `++obj[index]`, which must do both a
+ * `JSOp::GetElem` and a `JSOp::SetElem` with the same property key. Both
+ * instructions would convert `index` to a property key for us, but the
+ * spec says to convert it only once.
+ *
+ * The conversion can call `.toString()`/`.valueOf()` methods and can
+ * throw.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-topropertykey
+ *
+ * Category: Expressions
+ * Type: Conversions
+ * Operands:
+ * Stack: propertyNameValue => propertyKey
+ */ \
+ MACRO(ToPropertyKey, to_property_key, NULL, 1, 1, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * Convert a value to a numeric value (a Number or BigInt).
+ *
+ * Implements: [ToNumeric][1](val).
+ *
+ * Note: This is used to implement [`++` and `--`][2]. Surprisingly, it's
+ * not possible to get the right behavior using `JSOp::Add` and `JSOp::Sub`
+ * alone. For one thing, `JSOp::Add` sometimes does string concatenation,
+ * while `++` always does numeric addition. More fundamentally, the result
+ * of evaluating `x--` is ToNumeric(old value of `x`), a value that the
+ * sequence `GetLocal "x"; One; Sub; SetLocal "x"` does not give us.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-tonumeric
+ * [2]: https://tc39.es/ecma262/#sec-postfix-increment-operator
+ *
+ * Category: Expressions
+ * Type: Conversions
+ * Operands:
+ * Stack: val => ToNumeric(val)
+ */ \
+ MACRO(ToNumeric, to_numeric, NULL, 1, 1, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * Convert a value to a string.
+ *
+ * Implements: [ToString][1](val).
+ *
+ * Note: This is used in code for template literals, like `${x}${y}`. Each
+ * substituted value must be converted using ToString. `JSOp::Add` by itself
+ * would do a slightly wrong kind of conversion (hint="number" rather than
+ * hint="string").
+ *
+ * [1]: https://tc39.es/ecma262/#sec-tostring
+ *
+ * Category: Expressions
+ * Type: Conversions
+ * Stack: val => ToString(val)
+ */ \
+ MACRO(ToString, to_string, NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Test whether the value on top of the stack is `NullValue` or
+ * `UndefinedValue` and push the boolean result.
+ *
+ * Category: Expressions
+ * Type: Other expressions
+ * Operands:
+ * Stack: val => val, IsNullOrUndefined(val)
+ */ \
+ MACRO(IsNullOrUndefined, is_null_or_undefined, NULL, 1, 1, 2, JOF_BYTE) \
+ /*
+ * Push the global `this` value. Not to be confused with the `globalThis`
+ * property on the global.
+ *
+ * This must be used only in scopes where `this` refers to the global
+ * `this`.
+ *
+ * Category: Expressions
+ * Type: Other expressions
+ * Operands:
+ * Stack: => this
+ */ \
+ MACRO(GlobalThis, global_this, NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Push the global `this` value for non-syntactic scope. Not to be confused
+ * with the `globalThis` property on the global.
+ *
+ * This must be used only in scopes where `this` refers to the global
+ * `this`.
+ *
+ * Category: Expressions
+ * Type: Other expressions
+ * Operands:
+ * Stack: => this
+ */ \
+ MACRO(NonSyntacticGlobalThis, non_syntactic_global_this, NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Push the value of `new.target`.
+ *
+ * The result is a constructor or `undefined`.
+ *
+ * This must be used only in non-arrow function scripts.
+ *
+ * Implements: [GetNewTarget][1].
+ *
+ * [1]: https://tc39.es/ecma262/#sec-getnewtarget
+ *
+ * Category: Expressions
+ * Type: Other expressions
+ * Operands:
+ * Stack: => new.target
+ */ \
+ MACRO(NewTarget, new_target, NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Dynamic import of the module specified by the string value on the top of
+ * the stack.
+ *
+ * Implements: [Import Calls][1].
+ *
+ * [1]: https://tc39.es/ecma262/#sec-import-calls
+ *
+ * Category: Expressions
+ * Type: Other expressions
+ * Operands:
+ * Stack: moduleId, options => promise
+ */ \
+ MACRO(DynamicImport, dynamic_import, NULL, 1, 2, 1, JOF_BYTE) \
+ /*
+ * Push the `import.meta` object.
+ *
+ * This must be used only in module code.
+ *
+ * Category: Expressions
+ * Type: Other expressions
+ * Operands:
+ * Stack: => import.meta
+ */ \
+ MACRO(ImportMeta, import_meta, NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Create and push a new object with no properties.
+ *
+ * Category: Objects
+ * Type: Creating objects
+ * Operands:
+ * Stack: => obj
+ */ \
+ MACRO(NewInit, new_init, NULL, 1, 0, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * Create and push a new object of a predetermined shape.
+ *
+ * The new object has the shape `script->getShape(shapeIndex)`.
+ * Subsequent `InitProp` instructions must fill in all slots of the new
+ * object before it is used in any other way.
+ *
+ * Category: Objects
+ * Type: Creating objects
+ * Operands: uint32_t shapeIndex
+ * Stack: => obj
+ */ \
+ MACRO(NewObject, new_object, NULL, 5, 0, 1, JOF_SHAPE|JOF_IC) \
+ /*
+ * Push a preconstructed object.
+ *
+ * Going one step further than `JSOp::NewObject`, this instruction doesn't
+ * just reuse the shape--it actually pushes the preconstructed object
+ * `script->getObject(objectIndex)` right onto the stack. The object must
+ * be a singleton `PlainObject` or `ArrayObject`.
+ *
+ * The spec requires that an *ObjectLiteral* or *ArrayLiteral* creates a
+ * new object every time it's evaluated, so this instruction must not be
+ * used anywhere it might be executed more than once.
+ *
+ * This may only be used in non-function run-once scripts. Care also must
+ * be taken to not emit in loops or other constructs where it could run
+ * more than once.
+ *
+ * Category: Objects
+ * Type: Creating objects
+ * Operands: uint32_t objectIndex
+ * Stack: => obj
+ */ \
+ MACRO(Object, object, NULL, 5, 0, 1, JOF_OBJECT) \
+ /*
+ * Create and push a new ordinary object with the provided [[Prototype]].
+ *
+ * This is used to create the `.prototype` object for derived classes.
+ *
+ * Category: Objects
+ * Type: Creating objects
+ * Operands:
+ * Stack: proto => obj
+ */ \
+ MACRO(ObjWithProto, obj_with_proto, NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Define a data property on an object.
+ *
+ * `obj` must be an object.
+ *
+ * Implements: [CreateDataPropertyOrThrow][1] as used in
+ * [PropertyDefinitionEvaluation][2] of regular and shorthand
+ * *PropertyDefinition*s.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-createdatapropertyorthrow
+ * [2]: https://tc39.es/ecma262/#sec-object-initializer-runtime-semantics-propertydefinitionevaluation
+ *
+ * Category: Objects
+ * Type: Defining properties
+ * Operands: uint32_t nameIndex
+ * Stack: obj, val => obj
+ */ \
+ MACRO(InitProp, init_prop, NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT|JOF_IC) \
+ /*
+ * Like `JSOp::InitProp`, but define a non-enumerable property.
+ *
+ * This is used to define class methods.
+ *
+ * Implements: [PropertyDefinitionEvaluation][1] for methods, steps 3 and
+ * 4, when *enumerable* is false.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-method-definitions-runtime-semantics-propertydefinitionevaluation
+ *
+ * Category: Objects
+ * Type: Defining properties
+ * Operands: uint32_t nameIndex
+ * Stack: obj, val => obj
+ */ \
+ MACRO(InitHiddenProp, init_hidden_prop, NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT|JOF_IC) \
+ /*
+ * Like `JSOp::InitProp`, but define a non-enumerable, non-writable,
+ * non-configurable property.
+ *
+ * This is used to define the `.prototype` property on classes.
+ *
+ * Implements: [MakeConstructor][1], step 8, when *writablePrototype* is
+ * false.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-makeconstructor
+ *
+ * Category: Objects
+ * Type: Defining properties
+ * Operands: uint32_t nameIndex
+ * Stack: obj, val => obj
+ */ \
+ MACRO(InitLockedProp, init_locked_prop, NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT|JOF_IC) \
+ /*
+ * Define a data property on `obj` with property key `id` and value `val`.
+ *
+ * `obj` must be an object.
+ *
+ * Implements: [CreateDataPropertyOrThrow][1]. This instruction is used for
+ * object literals like `{0: val}` and `{[id]: val}`, and methods like
+ * `*[Symbol.iterator]() {}`.
+ *
+ * `JSOp::InitHiddenElem` is the same but defines a non-enumerable property,
+ * for class methods.
+ * `JSOp::InitLockedElem` is the same but defines a non-enumerable, non-writable, non-configurable property,
+ * for private class methods.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-createdatapropertyorthrow
+ *
+ * Category: Objects
+ * Type: Defining properties
+ * Operands:
+ * Stack: obj, id, val => obj
+ */ \
+ MACRO(InitElem, init_elem, NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_IC) \
+ MACRO(InitHiddenElem, init_hidden_elem, NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_IC) \
+ MACRO(InitLockedElem, init_locked_elem, NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_IC) \
+ /*
+ * Define an accessor property on `obj` with the given `getter`.
+ * `nameIndex` gives the property name.
+ *
+ * `obj` must be an object and `getter` must be a function.
+ *
+ * `JSOp::InitHiddenPropGetter` is the same but defines a non-enumerable
+ * property, for getters in classes.
+ *
+ * Category: Objects
+ * Type: Defining properties
+ * Operands: uint32_t nameIndex
+ * Stack: obj, getter => obj
+ */ \
+ MACRO(InitPropGetter, init_prop_getter, NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT) \
+ MACRO(InitHiddenPropGetter, init_hidden_prop_getter, NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT) \
+ /*
+ * Define an accessor property on `obj` with property key `id` and the given `getter`.
+ *
+ * This is used to implement getters like `get [id]() {}` or `get 0() {}`.
+ *
+ * `obj` must be an object and `getter` must be a function.
+ *
+ * `JSOp::InitHiddenElemGetter` is the same but defines a non-enumerable
+ * property, for getters in classes.
+ *
+ * Category: Objects
+ * Type: Defining properties
+ * Operands:
+ * Stack: obj, id, getter => obj
+ */ \
+ MACRO(InitElemGetter, init_elem_getter, NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT) \
+ MACRO(InitHiddenElemGetter, init_hidden_elem_getter, NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT) \
+ /*
+ * Define an accessor property on `obj` with the given `setter`.
+ *
+ * This is used to implement ordinary setters like `set foo(v) {}`.
+ *
+ * `obj` must be an object and `setter` must be a function.
+ *
+ * `JSOp::InitHiddenPropSetter` is the same but defines a non-enumerable
+ * property, for setters in classes.
+ *
+ * Category: Objects
+ * Type: Defining properties
+ * Operands: uint32_t nameIndex
+ * Stack: obj, setter => obj
+ */ \
+ MACRO(InitPropSetter, init_prop_setter, NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT) \
+ MACRO(InitHiddenPropSetter, init_hidden_prop_setter, NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT) \
+ /*
+ * Define an accesssor property on `obj` with property key `id` and the
+ * given `setter`.
+ *
+ * This is used to implement setters with computed property keys or numeric
+ * keys.
+ *
+ * `JSOp::InitHiddenElemSetter` is the same but defines a non-enumerable
+ * property, for setters in classes.
+ *
+ * Category: Objects
+ * Type: Defining properties
+ * Operands:
+ * Stack: obj, id, setter => obj
+ */ \
+ MACRO(InitElemSetter, init_elem_setter, NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT) \
+ MACRO(InitHiddenElemSetter, init_hidden_elem_setter, NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT) \
+ /*
+ * Get the value of the property `obj.name`. This can call getters and
+ * proxy traps.
+ *
+ * Implements: [GetV][1], [GetValue][2] step 5.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-getv
+ * [2]: https://tc39.es/ecma262/#sec-getvalue
+ *
+ * Category: Objects
+ * Type: Accessing properties
+ * Operands: uint32_t nameIndex
+ * Stack: obj => obj[name]
+ */ \
+ MACRO(GetProp, get_prop, NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_IC) \
+ /*
+ * Get the value of the property `obj[key]`.
+ *
+ * Implements: [GetV][1], [GetValue][2] step 5.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-getv
+ * [2]: https://tc39.es/ecma262/#sec-getvalue
+ *
+ * Category: Objects
+ * Type: Accessing properties
+ * Operands:
+ * Stack: obj, key => obj[key]
+ */ \
+ MACRO(GetElem, get_elem, NULL, 1, 2, 1, JOF_BYTE|JOF_ELEM|JOF_IC) \
+ /*
+ * Non-strict assignment to a property, `obj.name = val`.
+ *
+ * This throws a TypeError if `obj` is null or undefined. If it's a
+ * primitive value, the property is set on ToObject(`obj`), typically with
+ * no effect.
+ *
+ * Implements: [PutValue][1] step 6 for non-strict code.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-putvalue
+ *
+ * Category: Objects
+ * Type: Accessing properties
+ * Operands: uint32_t nameIndex
+ * Stack: obj, val => val
+ */ \
+ MACRO(SetProp, set_prop, NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPSET|JOF_CHECKSLOPPY|JOF_IC) \
+ /*
+ * Like `JSOp::SetProp`, but for strict mode code. Throw a TypeError if
+ * `obj[key]` exists but is non-writable, if it's an accessor property with
+ * no setter, or if `obj` is a primitive value.
+ *
+ * Category: Objects
+ * Type: Accessing properties
+ * Operands: uint32_t nameIndex
+ * Stack: obj, val => val
+ */ \
+ MACRO(StrictSetProp, strict_set_prop, NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPSET|JOF_CHECKSTRICT|JOF_IC) \
+ /*
+ * Non-strict assignment to a property, `obj[key] = val`.
+ *
+ * Implements: [PutValue][1] step 6 for non-strict code.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-putvalue
+ *
+ * Category: Objects
+ * Type: Accessing properties
+ * Operands:
+ * Stack: obj, key, val => val
+ */ \
+ MACRO(SetElem, set_elem, NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPSET|JOF_CHECKSLOPPY|JOF_IC) \
+ /*
+ * Like `JSOp::SetElem`, but for strict mode code. Throw a TypeError if
+ * `obj[key]` exists but is non-writable, if it's an accessor property with
+ * no setter, or if `obj` is a primitive value.
+ *
+ * Category: Objects
+ * Type: Accessing properties
+ * Operands:
+ * Stack: obj, key, val => val
+ */ \
+ MACRO(StrictSetElem, strict_set_elem, NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPSET|JOF_CHECKSTRICT|JOF_IC) \
+ /*
+ * Delete a property from `obj`. Push true on success, false if the
+ * property existed but could not be deleted. This implements `delete
+ * obj.name` in non-strict code.
+ *
+ * Throws if `obj` is null or undefined. Can call proxy traps.
+ *
+ * Implements: [`delete obj.propname`][1] step 5 in non-strict code.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-delete-operator-runtime-semantics-evaluation
+ *
+ * Category: Objects
+ * Type: Accessing properties
+ * Operands: uint32_t nameIndex
+ * Stack: obj => succeeded
+ */ \
+ MACRO(DelProp, del_prop, NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_CHECKSLOPPY) \
+ /*
+ * Like `JSOp::DelProp`, but for strict mode code. Push `true` on success,
+ * else throw a TypeError.
+ *
+ * Category: Objects
+ * Type: Accessing properties
+ * Operands: uint32_t nameIndex
+ * Stack: obj => succeeded
+ */ \
+ MACRO(StrictDelProp, strict_del_prop, NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_CHECKSTRICT) \
+ /*
+ * Delete the property `obj[key]` and push `true` on success, `false`
+ * if the property existed but could not be deleted.
+ *
+ * This throws if `obj` is null or undefined. Can call proxy traps.
+ *
+ * Implements: [`delete obj[key]`][1] step 5 in non-strict code.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-delete-operator-runtime-semantics-evaluation
+ *
+ * Category: Objects
+ * Type: Accessing properties
+ * Operands:
+ * Stack: obj, key => succeeded
+ */ \
+ MACRO(DelElem, del_elem, NULL, 1, 2, 1, JOF_BYTE|JOF_ELEM|JOF_CHECKSLOPPY) \
+ /*
+ * Like `JSOp::DelElem, but for strict mode code. Push `true` on success,
+ * else throw a TypeError.
+ *
+ * Category: Objects
+ * Type: Accessing properties
+ * Operands:
+ * Stack: obj, key => succeeded
+ */ \
+ MACRO(StrictDelElem, strict_del_elem, NULL, 1, 2, 1, JOF_BYTE|JOF_ELEM|JOF_CHECKSTRICT) \
+ /*
+ * Push true if `obj` has an own property `id`.
+ *
+ * Note that `obj` is the top value, like `JSOp::In`.
+ *
+ * This opcode is not used for normal JS. Self-hosted code uses it by
+ * calling the intrinsic `hasOwn(id, obj)`. For example,
+ * `Object.prototype.hasOwnProperty` is implemented this way (see
+ * js/src/builtin/Object.js).
+ *
+ * Category: Objects
+ * Type: Accessing properties
+ * Operands:
+ * Stack: id, obj => (obj.hasOwnProperty(id))
+ */ \
+ MACRO(HasOwn, has_own, NULL, 1, 2, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * Push a bool representing the presence of private field id on obj.
+ * May throw, depending on the ThrowCondition.
+ *
+ * Two arguments:
+ * - throwCondition: One of the ThrowConditions defined in
+ * ThrowMsgKind.h. Determines why (or if) this op will throw.
+ * - msgKind: One of the ThrowMsgKinds defined in ThrowMsgKind.h, which
+ * maps to one of the messages in js.msg. Note: It's not possible to
+ * pass arguments to the message at the moment.
+ *
+ * Category: Objects
+ * Type: Accessing properties
+ * Operands: ThrowCondition throwCondition, ThrowMsgKind msgKind
+ * Stack: obj, key => obj, key, (obj.hasOwnProperty(id))
+ */ \
+ MACRO(CheckPrivateField, check_private_field, NULL, 3, 2, 3, JOF_TWO_UINT8|JOF_CHECKSTRICT|JOF_IC) \
+ /*
+ * Push a new private name.
+ *
+ * Category: Objects
+ * Type: Accessing properties
+ * Operands: uint32_t nameIndex
+ * Stack: => private_name
+ */ \
+ MACRO(NewPrivateName, new_private_name, NULL, 5, 0, 1, JOF_ATOM) \
+ /*
+ * Push the SuperBase of the method `callee`. The SuperBase is
+ * `callee.[[HomeObject]].[[GetPrototypeOf]]()`, the object where `super`
+ * property lookups should begin.
+ *
+ * `callee` must be a function that has a HomeObject that's an object,
+ * typically produced by `JSOp::Callee` or `JSOp::EnvCallee`.
+ *
+ * Implements: [GetSuperBase][1], except that instead of the environment,
+ * the argument supplies the callee.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-getsuperbase
+ *
+ * Category: Objects
+ * Type: Super
+ * Operands:
+ * Stack: callee => superBase
+ */ \
+ MACRO(SuperBase, super_base, NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Get the value of `receiver.name`, starting the property search at `obj`.
+ * In spec terms, `obj.[[Get]](name, receiver)`.
+ *
+ * Implements: [GetValue][1] for references created by [`super.name`][2].
+ * The `receiver` is `this` and `obj` is the SuperBase of the enclosing
+ * method.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-getvalue
+ * [2]: https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
+ *
+ * Category: Objects
+ * Type: Super
+ * Operands: uint32_t nameIndex
+ * Stack: receiver, obj => super.name
+ */ \
+ MACRO(GetPropSuper, get_prop_super, NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_IC) \
+ /*
+ * Get the value of `receiver[key]`, starting the property search at `obj`.
+ * In spec terms, `obj.[[Get]](key, receiver)`.
+ *
+ * Implements: [GetValue][1] for references created by [`super[key]`][2]
+ * (where the `receiver` is `this` and `obj` is the SuperBase of the enclosing
+ * method); [`Reflect.get(obj, key, receiver)`][3].
+ *
+ * [1]: https://tc39.es/ecma262/#sec-getvalue
+ * [2]: https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
+ * [3]: https://tc39.es/ecma262/#sec-reflect.get
+ *
+ * Category: Objects
+ * Type: Super
+ * Operands:
+ * Stack: receiver, key, obj => super[key]
+ */ \
+ MACRO(GetElemSuper, get_elem_super, NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_IC) \
+ /*
+ * Assign `val` to `receiver.name`, starting the search for an existing
+ * property at `obj`. In spec terms, `obj.[[Set]](name, val, receiver)`.
+ *
+ * Implements: [PutValue][1] for references created by [`super.name`][2] in
+ * non-strict code. The `receiver` is `this` and `obj` is the SuperBase of
+ * the enclosing method.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-putvalue
+ * [2]: https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
+ *
+ * Category: Objects
+ * Type: Super
+ * Operands: uint32_t nameIndex
+ * Stack: receiver, obj, val => val
+ */ \
+ MACRO(SetPropSuper, set_prop_super, NULL, 5, 3, 1, JOF_ATOM|JOF_PROP|JOF_PROPSET|JOF_CHECKSLOPPY) \
+ /*
+ * Like `JSOp::SetPropSuper`, but for strict mode code.
+ *
+ * Category: Objects
+ * Type: Super
+ * Operands: uint32_t nameIndex
+ * Stack: receiver, obj, val => val
+ */ \
+ MACRO(StrictSetPropSuper, strict_set_prop_super, NULL, 5, 3, 1, JOF_ATOM|JOF_PROP|JOF_PROPSET|JOF_CHECKSTRICT) \
+ /*
+ * Assign `val` to `receiver[key]`, strating the search for an existing
+ * property at `obj`. In spec terms, `obj.[[Set]](key, val, receiver)`.
+ *
+ * Implements: [PutValue][1] for references created by [`super[key]`][2] in
+ * non-strict code. The `receiver` is `this` and `obj` is the SuperBase of
+ * the enclosing method.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-putvalue
+ * [2]: https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
+ *
+ * Category: Objects
+ * Type: Super
+ * Operands:
+ * Stack: receiver, key, obj, val => val
+ */ \
+ MACRO(SetElemSuper, set_elem_super, NULL, 1, 4, 1, JOF_BYTE|JOF_ELEM|JOF_PROPSET|JOF_CHECKSLOPPY) \
+ /*
+ * Like `JSOp::SetElemSuper`, but for strict mode code.
+ *
+ * Category: Objects
+ * Type: Super
+ * Operands:
+ * Stack: receiver, key, obj, val => val
+ */ \
+ MACRO(StrictSetElemSuper, strict_set_elem_super, NULL, 1, 4, 1, JOF_BYTE|JOF_ELEM|JOF_PROPSET|JOF_CHECKSTRICT) \
+ /*
+ * Set up a for-in loop by pushing a `PropertyIteratorObject` over the
+ * enumerable properties of `val`.
+ *
+ * Implements: [ForIn/OfHeadEvaluation][1] step 6,
+ * [EnumerateObjectProperties][1]. (The spec refers to an "Iterator object"
+ * with a `next` method, but notes that it "is never directly accessible"
+ * to scripts. The object we use for this has no public methods.)
+ *
+ * If `val` is null or undefined, this pushes an empty iterator.
+ *
+ * The `iter` object pushed by this instruction must not be used or removed
+ * from the stack except by `JSOp::MoreIter` and `JSOp::EndIter`, or by error
+ * handling.
+ *
+ * The script's `JSScript::trynotes()` must mark the body of the `for-in`
+ * loop, i.e. exactly those instructions that begin executing with `iter`
+ * on the stack, starting with the next instruction (always
+ * `JSOp::LoopHead`). Code must not jump into or out of this region: control
+ * can enter only by executing `JSOp::Iter` and can exit only by executing a
+ * `JSOp::EndIter` or by exception unwinding. (A `JSOp::EndIter` is always
+ * emitted at the end of the loop, and extra copies are emitted on "exit
+ * slides", where a `break`, `continue`, or `return` statement exits the
+ * loop.)
+ *
+ * Typically a single try note entry marks the contiguous chunk of bytecode
+ * from the instruction after `JSOp::Iter` to `JSOp::EndIter` (inclusive);
+ * but if that range contains any instructions on exit slides, after a
+ * `JSOp::EndIter`, then those must be correctly noted as *outside* the
+ * loop.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-runtime-semantics-forin-div-ofheadevaluation-tdznames-expr-iterationkind
+ * [2]: https://tc39.es/ecma262/#sec-enumerate-object-properties
+ *
+ * Category: Objects
+ * Type: Enumeration
+ * Operands:
+ * Stack: val => iter
+ */ \
+ MACRO(Iter, iter, NULL, 1, 1, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * Get the next property name for a for-in loop.
+ *
+ * `iter` must be a `PropertyIteratorObject` produced by `JSOp::Iter`. This
+ * pushes the property name for the next loop iteration, or
+ * `MagicValue(JS_NO_ITER_VALUE)` if there are no more enumerable
+ * properties to iterate over. The magic value must be used only by
+ * `JSOp::IsNoIter` and `JSOp::EndIter`.
+ *
+ * Category: Objects
+ * Type: Enumeration
+ * Operands:
+ * Stack: iter => iter, name
+ */ \
+ MACRO(MoreIter, more_iter, NULL, 1, 1, 2, JOF_BYTE) \
+ /*
+ * Test whether the value on top of the stack is
+ * `MagicValue(JS_NO_ITER_VALUE)` and push the boolean result.
+ *
+ * Category: Objects
+ * Type: Enumeration
+ * Operands:
+ * Stack: val => val, done
+ */ \
+ MACRO(IsNoIter, is_no_iter, NULL, 1, 1, 2, JOF_BYTE) \
+ /*
+ * Exit a for-in loop, closing the iterator.
+ *
+ * `iter` must be a `PropertyIteratorObject` pushed by `JSOp::Iter`.
+ *
+ * Category: Objects
+ * Type: Enumeration
+ * Operands:
+ * Stack: iter, iterval =>
+ */ \
+ MACRO(EndIter, end_iter, NULL, 1, 2, 0, JOF_BYTE) \
+ /*
+ * If the iterator object on top of the stack has a `return` method,
+ * call that method. If the method exists but does not return an object,
+ * and `kind` is not `CompletionKind::Throw`, throw a TypeError. (If
+ * `kind` is `Throw`, the error we are already throwing takes precedence.)
+ *
+ * `iter` must be an object conforming to the [Iterator][1] interface.
+ *
+ * Implements: [IteratorClose][2]
+ *
+ * [1]: https://tc39.es/ecma262/#sec-iterator-interface
+ * [2]: https://tc39.es/ecma262/#sec-iteratorclose
+ * Category: Objects
+ * Type: Iteration
+ * Operands: CompletionKind kind
+ * Stack: iter =>
+ */ \
+ MACRO(CloseIter, close_iter, NULL, 2, 1, 0, JOF_UINT8|JOF_IC) \
+ /*
+ * Check that the top value on the stack is an object, and throw a
+ * TypeError if not. `kind` is used only to generate an appropriate error
+ * message.
+ *
+ * Implements: [GetIterator][1] step 5, [IteratorNext][2] step 3. Both
+ * operations call a JS method which scripts can define however they want,
+ * so they check afterwards that the method returned an object.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-getiterator
+ * [2]: https://tc39.es/ecma262/#sec-iteratornext
+ *
+ * Category: Objects
+ * Type: Iteration
+ * Operands: CheckIsObjectKind kind
+ * Stack: result => result
+ */ \
+ MACRO(CheckIsObj, check_is_obj, NULL, 2, 1, 1, JOF_UINT8) \
+ /*
+ * Throw a TypeError if `val` is `null` or `undefined`.
+ *
+ * Implements: [RequireObjectCoercible][1]. But most instructions that
+ * require an object will perform this check for us, so of the dozens of
+ * calls to RequireObjectCoercible in the spec, we need this instruction
+ * only for [destructuring assignment][2] and [initialization][3].
+ *
+ * [1]: https://tc39.es/ecma262/#sec-requireobjectcoercible
+ * [2]: https://tc39.es/ecma262/#sec-runtime-semantics-destructuringassignmentevaluation
+ * [3]: https://tc39.es/ecma262/#sec-destructuring-binding-patterns-runtime-semantics-bindinginitialization
+ *
+ * Category: Objects
+ * Type: Iteration
+ * Operands:
+ * Stack: val => val
+ */ \
+ MACRO(CheckObjCoercible, check_obj_coercible, NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Create and push an async iterator wrapping the sync iterator `iter`.
+ * `next` should be `iter`'s `.next` method.
+ *
+ * Implements: [CreateAsyncToSyncIterator][1]. The spec says this operation
+ * takes one argument, but that argument is a Record with two relevant
+ * fields, `[[Iterator]]` and `[[NextMethod]]`.
+ *
+ * Used for `for await` loops.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-createasyncfromsynciterator
+ *
+ * Category: Objects
+ * Type: Iteration
+ * Operands:
+ * Stack: iter, next => asynciter
+ */ \
+ MACRO(ToAsyncIter, to_async_iter, NULL, 1, 2, 1, JOF_BYTE) \
+ /*
+ * Set the prototype of `obj`.
+ *
+ * `obj` must be an object.
+ *
+ * Implements: [B.3.1 __proto__ Property Names in Object Initializers][1], step 7.a.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-__proto__-property-names-in-object-initializers
+ *
+ * Category: Objects
+ * Type: SetPrototype
+ * Operands:
+ * Stack: obj, protoVal => obj
+ */ \
+ MACRO(MutateProto, mutate_proto, NULL, 1, 2, 1, JOF_BYTE) \
+ /*
+ * Create and push a new Array object with the given `length`,
+ * preallocating enough memory to hold that many elements.
+ *
+ * Category: Objects
+ * Type: Array literals
+ * Operands: uint32_t length
+ * Stack: => array
+ */ \
+ MACRO(NewArray, new_array, NULL, 5, 0, 1, JOF_UINT32|JOF_IC) \
+ /*
+ * Initialize an array element `array[index]` with value `val`.
+ *
+ * `val` may be `MagicValue(JS_ELEMENTS_HOLE)` pushed by `JSOp::Hole`.
+ *
+ * This never calls setters or proxy traps.
+ *
+ * `array` must be an Array object created by `JSOp::NewArray` with length >
+ * `index`, and never used except by `JSOp::InitElemArray`.
+ *
+ * Implements: [ArrayAccumulation][1], the third algorithm, step 4, in the
+ * common case where *nextIndex* is known.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-runtime-semantics-arrayaccumulation
+ *
+ * Category: Objects
+ * Type: Array literals
+ * Operands: uint32_t index
+ * Stack: array, val => array
+ */ \
+ MACRO(InitElemArray, init_elem_array, NULL, 5, 2, 1, JOF_UINT32|JOF_ELEM|JOF_PROPINIT) \
+ /*
+ * Initialize an array element `array[index++]` with value `val`.
+ *
+ * `val` may be `MagicValue(JS_ELEMENTS_HOLE)` pushed by `JSOp::Hole`. If it
+ * is, no element is defined, but the array length and the stack value
+ * `index` are still incremented.
+ *
+ * This never calls setters or proxy traps.
+ *
+ * `array` must be an Array object created by `JSOp::NewArray` and never used
+ * except by `JSOp::InitElemArray` and `JSOp::InitElemInc`.
+ *
+ * `index` must be an integer, `0 <= index <= INT32_MAX`. If `index` is
+ * `INT32_MAX`, this throws a RangeError. Unlike `InitElemArray`, it is not
+ * necessary that the `array` length > `index`.
+ *
+ * This instruction is used when an array literal contains a
+ * *SpreadElement*. In `[a, ...b, c]`, `InitElemArray 0` is used to put
+ * `a` into the array, but `InitElemInc` is used for the elements of `b`
+ * and for `c`.
+ *
+ * Implements: Several steps in [ArrayAccumulation][1] that call
+ * CreateDataProperty, set the array length, and/or increment *nextIndex*.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-runtime-semantics-arrayaccumulation
+ *
+ * Category: Objects
+ * Type: Array literals
+ * Operands:
+ * Stack: array, index, val => array, (index + 1)
+ */ \
+ MACRO(InitElemInc, init_elem_inc, NULL, 1, 3, 2, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_IC) \
+ /*
+ * Push `MagicValue(JS_ELEMENTS_HOLE)`, representing an *Elision* in an
+ * array literal (like the missing property 0 in the array `[, 1]`).
+ *
+ * This magic value must be used only by `JSOp::InitElemArray` or
+ * `JSOp::InitElemInc`.
+ *
+ * Category: Objects
+ * Type: Array literals
+ * Operands:
+ * Stack: => hole
+ */ \
+ MACRO(Hole, hole, NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Clone and push a new RegExp object.
+ *
+ * Implements: [Evaluation for *RegularExpressionLiteral*][1].
+ *
+ * [1]: https://tc39.es/ecma262/#sec-regular-expression-literals-runtime-semantics-evaluation
+ *
+ * Category: Objects
+ * Type: RegExp literals
+ * Operands: uint32_t regexpIndex
+ * Stack: => regexp
+ */ \
+ MACRO(RegExp, reg_exp, NULL, 5, 0, 1, JOF_REGEXP) \
+ /*
+ * Initialize a new record, preallocating `length` memory slots. `length` can still grow
+ * if needed, for example when using the spread operator.
+ *
+ * Implements: [RecordLiteral Evaluation][1] step 1.
+ *
+ * [1]: https://tc39.es/proposal-record-tuple/#sec-record-initializer-runtime-semantics-evaluation
+ *
+ * Category: Compound primitives
+ * Type: Record literals
+ * Operands: uint32_t length
+ * Stack: => rval
+ */ \
+ IF_RECORD_TUPLE(MACRO(InitRecord, init_record, NULL, 5, 0, 1, JOF_UINT32)) \
+ /*
+ * Add the last element in the stack to the preceding tuple.
+ *
+ * Implements: [AddPropertyIntoRecordEntriesList][1].
+ *
+ * [1]: https://tc39.es/proposal-record-tuple/#sec-addpropertyintorecordentrieslist
+ *
+ * Category: Compound primitives
+ * Type: Record literals
+ * Operands:
+ * Stack: record, key, value => record
+ */ \
+ IF_RECORD_TUPLE(MACRO(AddRecordProperty, add_record_property, NULL, 1, 3, 1, JOF_BYTE)) \
+ /*
+ * Add the last element in the stack to the preceding tuple.
+ *
+ * Implements: [RecordPropertyDefinitionEvaluation][1] for
+ * RecordPropertyDefinition : ... AssignmentExpression
+ *
+ * [1]: https://tc39.es/proposal-record-tuple/#sec-addpropertyintorecordentrieslist
+ *
+ * Category: Compound primitives
+ * Type: Record literals
+ * Operands:
+ * Stack: record, value => record
+ */ \
+ IF_RECORD_TUPLE(MACRO(AddRecordSpread, add_record_spread, NULL, 1, 2, 1, JOF_BYTE)) \
+ /*
+ * Mark a record as "initialized", going from "write-only" mode to
+ * "read-only" mode.
+ *
+ * Category: Compound primitives
+ * Type: Record literals
+ * Operands:
+ * Stack: record => record
+ */ \
+ IF_RECORD_TUPLE(MACRO(FinishRecord, finish_record, NULL, 1, 1, 1, JOF_BYTE)) \
+ /*
+ * Initialize a new tuple, preallocating `length` memory slots. `length` can still grow
+ * if needed, for example when using the spread operator.
+ *
+ * Implements: [TupleLiteral Evaluation][1] step 1.
+ *
+ * [1]: https://tc39.es/proposal-record-tuple/#sec-tuple-initializer-runtime-semantics-evaluation
+ *
+ * Category: Compound primitives
+ * Type: Tuple literals
+ * Operands: uint32_t length
+ * Stack: => rval
+ */ \
+ IF_RECORD_TUPLE(MACRO(InitTuple, init_tuple, NULL, 5, 0, 1, JOF_UINT32)) \
+ /*
+ * Add the last element in the stack to the preceding tuple.
+ *
+ * Implements: [AddValueToTupleSequenceList][1].
+ *
+ * [1]: https://tc39.es/proposal-record-tuple/#sec-addvaluetotuplesequencelist
+ *
+ * Category: Compound primitives
+ * Type: Tuple literals
+ * Operands:
+ * Stack: tuple, element => tuple
+ */ \
+ IF_RECORD_TUPLE(MACRO(AddTupleElement, add_tuple_element, NULL, 1, 2, 1, JOF_BYTE)) \
+ /*
+ * Mark a tuple as "initialized", going from "write-only" mode to
+ * "read-only" mode.
+ *
+ * Category: Compound primitives
+ * Type: Tuple literals
+ * Operands:
+ * Stack: tuple => tuple
+ */ \
+ IF_RECORD_TUPLE(MACRO(FinishTuple, finish_tuple, NULL, 1, 1, 1, JOF_BYTE)) \
+ /*
+ * Push a new function object.
+ *
+ * The new function inherits the current environment chain.
+ *
+ * Used to create most JS functions. Notable exceptions are derived or
+ * default class constructors.
+ *
+ * Implements: [InstantiateFunctionObject][1], [Evaluation for
+ * *FunctionExpression*][2], and so on.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-function-definitions-runtime-semantics-instantiatefunctionobject
+ * [2]: https://tc39.es/ecma262/#sec-function-definitions-runtime-semantics-evaluation
+ *
+ * Category: Functions
+ * Type: Creating functions
+ * Operands: uint32_t funcIndex
+ * Stack: => fn
+ */ \
+ MACRO(Lambda, lambda, NULL, 5, 0, 1, JOF_OBJECT|JOF_USES_ENV) \
+ /*
+ * Set the name of a function.
+ *
+ * `fun` must be a function object. `name` must be a string, Int32 value,
+ * or symbol (like the result of `JSOp::ToId`).
+ *
+ * Implements: [SetFunctionName][1], used e.g. to name methods with
+ * computed property names.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-setfunctionname
+ *
+ * Category: Functions
+ * Type: Creating functions
+ * Operands: FunctionPrefixKind prefixKind
+ * Stack: fun, name => fun
+ */ \
+ MACRO(SetFunName, set_fun_name, NULL, 2, 2, 1, JOF_UINT8) \
+ /*
+ * Initialize the home object for functions with super bindings.
+ *
+ * `fun` must be a method, getter, or setter, so that it has a
+ * [[HomeObject]] slot. `homeObject` must be a plain object or (for static
+ * methods) a constructor.
+ *
+ * Category: Functions
+ * Type: Creating functions
+ * Operands:
+ * Stack: fun, homeObject => fun
+ */ \
+ MACRO(InitHomeObject, init_home_object, NULL, 1, 2, 1, JOF_BYTE) \
+ /*
+ * Throw a TypeError if `baseClass` isn't either `null` or a constructor.
+ *
+ * Implements: [ClassDefinitionEvaluation][1] step 6.f.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-runtime-semantics-classdefinitionevaluation
+ *
+ * Category: Functions
+ * Type: Creating constructors
+ * Operands:
+ * Stack: baseClass => baseClass
+ */ \
+ MACRO(CheckClassHeritage, check_class_heritage, NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Like `JSOp::Lambda`, but using `proto` as the new function's
+ * `[[Prototype]]` (or `%FunctionPrototype%` if `proto` is `null`).
+ *
+ * `proto` must be either a constructor or `null`. We use
+ * `JSOp::CheckClassHeritage` to check.
+ *
+ * This is used to create the constructor for a derived class.
+ *
+ * Implements: [ClassDefinitionEvaluation][1] steps 6.e.ii, 6.g.iii, and
+ * 12 for derived classes.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-runtime-semantics-classdefinitionevaluation
+ *
+ * Category: Functions
+ * Type: Creating constructors
+ * Operands: uint32_t funcIndex
+ * Stack: proto => obj
+ */ \
+ MACRO(FunWithProto, fun_with_proto, NULL, 5, 1, 1, JOF_OBJECT|JOF_USES_ENV) \
+ /*
+ * Pushes the current global's %BuiltinObject%.
+ *
+ * `kind` must be a valid `BuiltinObjectKind` (and must not be
+ * `BuiltinObjectKind::None`).
+ *
+ * Category: Objects
+ * Type: Built-in objects
+ * Operands: uint8_t kind
+ * Stack: => %BuiltinObject%
+ */ \
+ MACRO(BuiltinObject, builtin_object, NULL, 2, 0, 1, JOF_UINT8) \
+ /*
+ * Invoke `callee` with `this` and `args`, and push the return value. Throw
+ * a TypeError if `callee` isn't a function.
+ *
+ * `JSOp::CallContent` is for `callContentFunction` in self-hosted JS, and
+ * this is for handling it differently in debugger's `onNativeCall` hook.
+ * `onNativeCall` hook disables all JITs, and `JSOp::CallContent` is
+ * treated exactly the same as `JSOP::Call` in JIT.
+ *
+ * `JSOp::CallIter` is used for implicit calls to @@iterator methods, to
+ * ensure error messages are formatted with `JSMSG_NOT_ITERABLE` ("x is not
+ * iterable") rather than `JSMSG_NOT_FUNCTION` ("x[Symbol.iterator] is not
+ * a function"). The `argc` operand must be 0 for this variation.
+ *
+ * `JSOp::CallContentIter` is `JSOp::CallContent` variant of
+ * `JSOp::CallIter`.
+ *
+ * `JSOp::CallIgnoresRv` hints to the VM that the return value is ignored.
+ * This allows alternate faster implementations to be used that avoid
+ * unnecesary allocations.
+ *
+ * Implements: [EvaluateCall][1] steps 4, 5, and 7.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-evaluatecall
+ *
+ * Category: Functions
+ * Type: Calls
+ * Operands: uint16_t argc
+ * Stack: callee, this, args[0], ..., args[argc-1] => rval
+ */ \
+ MACRO(Call, call, NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) \
+ MACRO(CallContent, call_content, NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) \
+ MACRO(CallIter, call_iter, NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) \
+ MACRO(CallContentIter, call_content_iter, NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) \
+ MACRO(CallIgnoresRv, call_ignores_rv, NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) \
+ /*
+ * Like `JSOp::Call`, but the arguments are provided in an array rather than
+ * a span of stack slots. Used to implement spread-call syntax:
+ * `f(...args)`.
+ *
+ * `args` must be an Array object containing the actual arguments. The
+ * array must be packed (dense and free of holes; see IsPackedArray).
+ * This can be ensured by creating the array with `JSOp::NewArray` and
+ * populating it using `JSOp::InitElemArray`.
+ *
+ * Category: Functions
+ * Type: Calls
+ * Operands:
+ * Stack: callee, this, args => rval
+ */ \
+ MACRO(SpreadCall, spread_call, NULL, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_SPREAD|JOF_IC) \
+ /*
+ * Push an array object that can be passed directly as the `args` argument
+ * to `JSOp::SpreadCall`. If the operation can't be optimized, push
+ * `undefined` instead.
+ *
+ * This instruction and the branch around the iterator loop are emitted
+ * only when `iterable` is the sole argument in a call, as in `f(...arr)`.
+ *
+ * See `js::OptimizeSpreadCall`.
+ *
+ * Category: Functions
+ * Type: Calls
+ * Operands:
+ * Stack: iterable => array_or_undefined
+ */ \
+ MACRO(OptimizeSpreadCall, optimize_spread_call, NULL, 1, 1, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * Perform a direct eval in the current environment if `callee` is the
+ * builtin `eval` function, otherwise follow same behaviour as `JSOp::Call`.
+ *
+ * All direct evals use one of the JSOp::*Eval instructions here and these
+ * opcodes are only used when the syntactic conditions for a direct eval
+ * are met. If the builtin `eval` function is called though other means, it
+ * becomes an indirect eval.
+ *
+ * Direct eval causes all bindings in *enclosing* non-global scopes to be
+ * marked "aliased". The optimization that puts bindings in stack slots has
+ * to prove that the bindings won't need to be captured by closures or
+ * accessed using `JSOp::{Get,Bind,Set,Del}Name` instructions. Direct eval
+ * makes that analysis impossible.
+ *
+ * The instruction immediately following any `JSOp::*Eval` instruction must
+ * be `JSOp::Lineno`.
+ *
+ * Implements: [Function Call Evaluation][1], steps 5-7 and 9, when the
+ * syntactic critera for direct eval in step 6 are all met.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-function-calls-runtime-semantics-evaluation
+ *
+ * Category: Functions
+ * Type: Calls
+ * Operands: uint16_t argc
+ * Stack: callee, this, args[0], ..., args[argc-1] => rval
+ */ \
+ MACRO(Eval, eval, NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_CHECKSLOPPY|JOF_IC) \
+ /*
+ * Spread-call variant of `JSOp::Eval`.
+ *
+ * See `JSOp::SpreadCall` for restrictions on `args`.
+ *
+ * Category: Functions
+ * Type: Calls
+ * Operands:
+ * Stack: callee, this, args => rval
+ */ \
+ MACRO(SpreadEval, spread_eval, NULL, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_SPREAD|JOF_CHECKSLOPPY|JOF_IC) \
+ /*
+ * Like `JSOp::Eval`, but for strict mode code.
+ *
+ * Category: Functions
+ * Type: Calls
+ * Operands: uint16_t argc
+ * Stack: evalFn, this, args[0], ..., args[argc-1] => rval
+ */ \
+ MACRO(StrictEval, strict_eval, NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_CHECKSTRICT|JOF_IC) \
+ /*
+ * Spread-call variant of `JSOp::StrictEval`.
+ *
+ * See `JSOp::SpreadCall` for restrictions on `args`.
+ *
+ * Category: Functions
+ * Type: Calls
+ * Operands:
+ * Stack: callee, this, args => rval
+ */ \
+ MACRO(StrictSpreadEval, strict_spread_eval, NULL, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_SPREAD|JOF_CHECKSTRICT|JOF_IC) \
+ /*
+ * Push the implicit `this` value for an unqualified function call, like
+ * `foo()`. `nameIndex` gives the name of the function we're calling.
+ *
+ * The result is always `undefined` except when the name refers to a `with`
+ * binding. For example, in `with (date) { getFullYear(); }`, the
+ * implicit `this` passed to `getFullYear` is `date`, not `undefined`.
+ *
+ * This walks the run-time environment chain looking for the environment
+ * record that contains the function. If the function call definitely
+ * refers to a local binding, use `JSOp::Undefined`.
+ *
+ * Implements: [EvaluateCall][1] step 1.b. But not entirely correctly.
+ * See [bug 1166408][2].
+ *
+ * [1]: https://tc39.es/ecma262/#sec-evaluatecall
+ * [2]: https://bugzilla.mozilla.org/show_bug.cgi?id=1166408
+ *
+ * Category: Functions
+ * Type: Calls
+ * Operands: uint32_t nameIndex
+ * Stack: => this
+ */ \
+ MACRO(ImplicitThis, implicit_this, "", 5, 0, 1, JOF_ATOM|JOF_USES_ENV) \
+ /*
+ * Push the call site object for a tagged template call.
+ *
+ * `script->getObject(objectIndex)` is the call site object.
+ *
+ * The call site object will already have the `.raw` property defined on it
+ * and will be frozen.
+ *
+ * Category: Functions
+ * Type: Calls
+ * Operands: uint32_t objectIndex
+ * Stack: => callSiteObj
+ */ \
+ MACRO(CallSiteObj, call_site_obj, NULL, 5, 0, 1, JOF_OBJECT) \
+ /*
+ * Push `MagicValue(JS_IS_CONSTRUCTING)`.
+ *
+ * This magic value is a required argument to the `JSOp::New` and
+ * `JSOp::SuperCall` instructions and must not be used any other way.
+ *
+ * Category: Functions
+ * Type: Calls
+ * Operands:
+ * Stack: => JS_IS_CONSTRUCTING
+ */ \
+ MACRO(IsConstructing, is_constructing, NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Invoke `callee` as a constructor with `args` and `newTarget`, and push
+ * the return value. Throw a TypeError if `callee` isn't a constructor.
+ *
+ * `isConstructing` must be the value pushed by `JSOp::IsConstructing`.
+ *
+ * `JSOp::SuperCall` behaves exactly like `JSOp::New`, but is used for
+ * *SuperCall* expressions, to allow JITs to distinguish them from `new`
+ * expressions.
+ *
+ * `JSOp::NewContent` is for `constructContentFunction` in self-hosted JS.
+ * See the comment for `JSOp::CallContent` for more details.
+ *
+ * Implements: [EvaluateConstruct][1] steps 7 and 8.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-evaluatenew
+ *
+ * Category: Functions
+ * Type: Calls
+ * Operands: uint16_t argc
+ * Stack: callee, isConstructing, args[0], ..., args[argc-1], newTarget => rval
+ */ \
+ MACRO(New, new_, NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_CONSTRUCT|JOF_IC) \
+ MACRO(NewContent, new_content, NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_CONSTRUCT|JOF_IC) \
+ MACRO(SuperCall, super_call, NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_CONSTRUCT|JOF_IC) \
+ /*
+ * Spread-call variant of `JSOp::New`.
+ *
+ * Invokes `callee` as a constructor with `args` and `newTarget`, and
+ * pushes the return value onto the stack.
+ *
+ * `isConstructing` must be the value pushed by `JSOp::IsConstructing`.
+ * See `JSOp::SpreadCall` for restrictions on `args`.
+ *
+ * `JSOp::SpreadSuperCall` behaves exactly like `JSOp::SpreadNew`, but is
+ * used for *SuperCall* expressions.
+ *
+ * Category: Functions
+ * Type: Calls
+ * Operands:
+ * Stack: callee, isConstructing, args, newTarget => rval
+ */ \
+ MACRO(SpreadNew, spread_new, NULL, 1, 4, 1, JOF_BYTE|JOF_INVOKE|JOF_CONSTRUCT|JOF_SPREAD|JOF_IC) \
+ MACRO(SpreadSuperCall, spread_super_call, NULL, 1, 4, 1, JOF_BYTE|JOF_INVOKE|JOF_CONSTRUCT|JOF_SPREAD|JOF_IC) \
+ /*
+ * Push the prototype of `callee` in preparation for calling `super()`.
+ *
+ * `callee` must be a derived class constructor.
+ *
+ * Implements: [GetSuperConstructor][1], steps 4-7.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-getsuperconstructor
+ *
+ * Category: Functions
+ * Type: Calls
+ * Operands:
+ * Stack: callee => superFun
+ */ \
+ MACRO(SuperFun, super_fun, NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Throw a ReferenceError if `thisval` is not
+ * `MagicValue(JS_UNINITIALIZED_LEXICAL)`. Used in derived class
+ * constructors to prohibit calling `super` more than once.
+ *
+ * Implements: [BindThisValue][1], step 3.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-bindthisvalue
+ *
+ * Category: Functions
+ * Type: Calls
+ * Operands:
+ * Stack: thisval => thisval
+ */ \
+ MACRO(CheckThisReinit, check_this_reinit, NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Create and push a generator object for the current frame.
+ *
+ * This instruction must appear only in scripts for generators, async
+ * functions, and async generators. There must not already be a generator
+ * object for the current frame (that is, this instruction must execute at
+ * most once per generator or async call).
+ *
+ * Category: Functions
+ * Type: Generators and async functions
+ * Operands:
+ * Stack: => gen
+ */ \
+ MACRO(Generator, generator, NULL, 1, 0, 1, JOF_BYTE|JOF_USES_ENV) \
+ /*
+ * Suspend the current generator and return to the caller.
+ *
+ * When a generator is called, its script starts running, like any other JS
+ * function, because [FunctionDeclarationInstantation][1] and other
+ * [generator object setup][2] are implemented mostly in bytecode. However,
+ * the *FunctionBody* of the generator is not supposed to start running
+ * until the first `.next()` call, so after setup the script suspends
+ * itself: the "initial yield".
+ *
+ * Later, when resuming execution, `rval`, `gen` and `resumeKind` will
+ * receive the values passed in by `JSOp::Resume`. `resumeKind` is the
+ * `GeneratorResumeKind` stored as an Int32 value.
+ *
+ * This instruction must appear only in scripts for generators and async
+ * generators. `gen` must be the generator object for the current frame. It
+ * must not have been previously suspended. The resume point indicated by
+ * `resumeIndex` must be the next instruction in the script, which must be
+ * `AfterYield`.
+ *
+ * Implements: [GeneratorStart][3], steps 4-7.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-functiondeclarationinstantiation
+ * [2]: https://tc39.es/ecma262/#sec-generator-function-definitions-runtime-semantics-evaluatebody
+ * [3]: https://tc39.es/ecma262/#sec-generatorstart
+ *
+ * Category: Functions
+ * Type: Generators and async functions
+ * Operands: uint24_t resumeIndex
+ * Stack: gen => rval, gen, resumeKind
+ */ \
+ MACRO(InitialYield, initial_yield, NULL, 4, 1, 3, JOF_RESUMEINDEX) \
+ /*
+ * Bytecode emitted after `yield` expressions. This is useful for the
+ * Debugger and `AbstractGeneratorObject::isAfterYieldOrAwait`. It's
+ * treated as jump target op so that the Baseline Interpreter can
+ * efficiently restore the frame's interpreterICEntry when resuming a
+ * generator.
+ *
+ * The preceding instruction in the script must be `Yield`, `InitialYield`,
+ * or `Await`.
+ *
+ * Category: Functions
+ * Type: Generators and async functions
+ * Operands: uint32_t icIndex
+ * Stack: =>
+ */ \
+ MACRO(AfterYield, after_yield, NULL, 5, 0, 0, JOF_ICINDEX) \
+ /*
+ * Suspend and close the current generator, async function, or async
+ * generator.
+ *
+ * `gen` must be the generator object for the current frame.
+ *
+ * If the current function is a non-async generator, then the value in the
+ * frame's return value slot is returned to the caller. It should be an
+ * object of the form `{value: returnValue, done: true}`.
+ *
+ * If the current function is an async function or async generator, the
+ * frame's return value slot must contain the current frame's result
+ * promise, which must already be resolved or rejected.
+ *
+ * Category: Functions
+ * Type: Generators and async functions
+ * Operands:
+ * Stack: gen =>
+ */ \
+ MACRO(FinalYieldRval, final_yield_rval, NULL, 1, 1, 0, JOF_BYTE) \
+ /*
+ * Suspend execution of the current generator or async generator, returning
+ * `rval1`.
+ *
+ * For non-async generators, `rval1` should be an object of the form
+ * `{value: valueToYield, done: true}`. For async generators, `rval1`
+ * should be the value to yield, and the caller is responsible for creating
+ * the iterator result object (under `js::AsyncGeneratorYield`).
+ *
+ * This instruction must appear only in scripts for generators and async
+ * generators. `gen` must be the generator object for the current stack
+ * frame. The resume point indicated by `resumeIndex` must be the next
+ * instruction in the script, which must be `AfterYield`.
+ *
+ * When resuming execution, `rval2`, `gen` and `resumeKind` receive the
+ * values passed in by `JSOp::Resume`.
+ *
+ * Implements: [GeneratorYield][1] and [AsyncGeneratorYield][2].
+ *
+ * [1]: https://tc39.es/ecma262/#sec-generatoryield
+ * [2]: https://tc39.es/ecma262/#sec-asyncgeneratoryield
+ *
+ * Category: Functions
+ * Type: Generators and async functions
+ * Operands: uint24_t resumeIndex
+ * Stack: rval1, gen => rval2, gen, resumeKind
+ */ \
+ MACRO(Yield, yield, NULL, 4, 2, 3, JOF_RESUMEINDEX) \
+ /*
+ * Pushes a boolean indicating whether the top of the stack is
+ * `MagicValue(JS_GENERATOR_CLOSING)`.
+ *
+ * Category: Functions
+ * Type: Generators and async functions
+ * Operands:
+ * Stack: val => val, res
+ */ \
+ MACRO(IsGenClosing, is_gen_closing, NULL, 1, 1, 2, JOF_BYTE) \
+ /*
+ * Arrange for this async function to resume asynchronously when `value`
+ * becomes resolved.
+ *
+ * This is the last thing an async function does before suspending for an
+ * `await` expression. It coerces the awaited `value` to a promise and
+ * effectively calls `.then()` on it, passing handler functions that will
+ * resume this async function call later. See `js::AsyncFunctionAwait`.
+ *
+ * This instruction must appear only in non-generator async function
+ * scripts. `gen` must be the internal generator object for the current
+ * frame. After this instruction, the script should suspend itself with
+ * `Await` (rather than exiting any other way).
+ *
+ * The result `promise` is the async function's result promise,
+ * `gen->as<AsyncFunctionGeneratorObject>().promise()`.
+ *
+ * Implements: [Await][1], steps 2-9.
+ *
+ * [1]: https://tc39.github.io/ecma262/#await
+ *
+ * Category: Functions
+ * Type: Generators and async functions
+ * Operands:
+ * Stack: value, gen => promise
+ */ \
+ MACRO(AsyncAwait, async_await, NULL, 1, 2, 1, JOF_BYTE) \
+ /*
+ * Resolve or reject the current async function's result promise with
+ * 'valueOrReason'.
+ *
+ * This instruction must appear only in non-generator async function
+ * scripts. `gen` must be the internal generator object for the current
+ * frame. This instruction must run at most once per async function call,
+ * as resolving/rejecting an already resolved/rejected promise is not
+ * permitted.
+ *
+ * The result `promise` is the async function's result promise,
+ * `gen->as<AsyncFunctionGeneratorObject>().promise()`.
+ *
+ * Implements: [AsyncFunctionStart][1], step 4.d.i. and 4.e.i.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-async-functions-abstract-operations-async-function-start
+ *
+ * Category: Functions
+ * Type: Generators and async functions
+ * Operands: AsyncFunctionResolveKind fulfillOrReject
+ * Stack: valueOrReason, gen => promise
+ */ \
+ MACRO(AsyncResolve, async_resolve, NULL, 2, 2, 1, JOF_UINT8) \
+ /*
+ * Suspend the current frame for an `await` expression.
+ *
+ * This instruction must appear only in scripts for async functions and
+ * async generators. `gen` must be the internal generator object for the
+ * current frame.
+ *
+ * This returns `promise` to the caller. Later, when this async call is
+ * resumed, `resolved`, `gen` and `resumeKind` receive the values passed in
+ * by `JSOp::Resume`, and execution continues at the next instruction,
+ * which must be `AfterYield`.
+ *
+ * This instruction is used in two subtly different ways.
+ *
+ * 1. In async functions:
+ *
+ * ... # valueToAwait
+ * GetAliasedVar ".generator" # valueToAwait gen
+ * AsyncAwait # resultPromise
+ * GetAliasedVar ".generator" # resultPromise gen
+ * Await # resolved gen resumeKind
+ * AfterYield
+ *
+ * `AsyncAwait` arranges for this frame to be resumed later and pushes
+ * its result promise. `Await` then suspends the frame and removes it
+ * from the stack, returning the result promise to the caller. (If this
+ * async call hasn't awaited before, the caller may be user code.
+ * Otherwise, the caller is self-hosted code using `resumeGenerator`.)
+ *
+ * 2. In async generators:
+ *
+ * ... # valueToAwait
+ * GetAliasedVar ".generator" # valueToAwait gen
+ * Await # resolved gen resumeKind
+ * AfterYield
+ *
+ * `AsyncAwait` is not used, so (1) the value returned to the caller by
+ * `Await` is `valueToAwait`, not `resultPromise`; and (2) the caller
+ * is responsible for doing the async-generator equivalent of
+ * `AsyncAwait` (namely, `js::AsyncGeneratorAwait`, called from
+ * `js::AsyncGeneratorResume` after `js::CallSelfHostedFunction`
+ * returns).
+ *
+ * Implements: [Await][1], steps 10-12.
+ *
+ * [1]: https://tc39.es/ecma262/#await
+ *
+ * Category: Functions
+ * Type: Generators and async functions
+ * Operands: uint24_t resumeIndex
+ * Stack: promise, gen => resolved, gen, resumeKind
+ */ \
+ MACRO(Await, await, NULL, 4, 2, 3, JOF_RESUMEINDEX) \
+ /*
+ * Test if the re-entry to the microtask loop may be skipped.
+ *
+ * This is part of an optimization for `await` expressions. Programs very
+ * often await values that aren't promises, or promises that are already
+ * resolved. We can then sometimes skip suspending the current frame and
+ * returning to the microtask loop. If the circumstances permit the
+ * optimization, `CanSkipAwait` pushes true if the optimization is allowed,
+ * and false otherwise.
+ *
+ * Category: Functions
+ * Type: Generators and async functions
+ * Operands:
+ * Stack: value => value, can_skip
+ */ \
+ MACRO(CanSkipAwait, can_skip_await, NULL, 1, 1, 2, JOF_BYTE) \
+ /*
+ * Potentially extract an awaited value, if the await is skippable
+ *
+ * If re-entering the microtask loop is skippable (as checked by CanSkipAwait)
+ * if can_skip is true, `MaybeExtractAwaitValue` replaces `value` with the result of the
+ * `await` expression (unwrapping the resolved promise, if any). Otherwise, value remains
+ * as is.
+ *
+ * In both cases, can_skip remains the same.
+ *
+ * Category: Functions
+ * Type: Generators and async functions
+ * Operands:
+ * Stack: value, can_skip => value_or_resolved, can_skip
+ */ \
+ MACRO(MaybeExtractAwaitValue, maybe_extract_await_value, NULL, 1, 2, 2, JOF_BYTE) \
+ /*
+ * Pushes one of the GeneratorResumeKind values as Int32Value.
+ *
+ * Category: Functions
+ * Type: Generators and async functions
+ * Operands: GeneratorResumeKind resumeKind (encoded as uint8_t)
+ * Stack: => resumeKind
+ */ \
+ MACRO(ResumeKind, resume_kind, NULL, 2, 0, 1, JOF_UINT8) \
+ /*
+ * Handle Throw and Return resumption.
+ *
+ * `gen` must be the generator object for the current frame. `resumeKind`
+ * must be a `GeneratorResumeKind` stored as an `Int32` value. If it is
+ * `Next`, continue to the next instruction. If `resumeKind` is `Throw` or
+ * `Return`, these completions are handled by throwing an exception. See
+ * `GeneratorThrowOrReturn`.
+ *
+ * Category: Functions
+ * Type: Generators and async functions
+ * Operands:
+ * Stack: rval, gen, resumeKind => rval
+ */ \
+ MACRO(CheckResumeKind, check_resume_kind, NULL, 1, 3, 1, JOF_BYTE) \
+ /*
+ * Resume execution of a generator, async function, or async generator.
+ *
+ * This behaves something like a call instruction. It pushes a stack frame
+ * (the one saved when `gen` was suspended, rather than a fresh one) and
+ * runs instructions in it. Once `gen` returns or yields, its return value
+ * is pushed to this frame's stack and execution continues in this script.
+ *
+ * This instruction is emitted only for the `resumeGenerator` self-hosting
+ * intrinsic. It is used in the implementation of
+ * `%GeneratorPrototype%.next`, `.throw`, and `.return`.
+ *
+ * `gen` must be a suspended generator object. `resumeKind` must be in
+ * range for `GeneratorResumeKind`.
+ *
+ * Category: Functions
+ * Type: Generators and async functions
+ * Operands:
+ * Stack: gen, val, resumeKind => rval
+ */ \
+ MACRO(Resume, resume, NULL, 1, 3, 1, JOF_BYTE|JOF_INVOKE) \
+ /*
+ * No-op instruction marking the target of a jump instruction.
+ *
+ * This instruction and a few others (see `js::BytecodeIsJumpTarget`) are
+ * jump target instructions. The Baseline Interpreter uses these
+ * instructions to sync the frame's `interpreterICEntry` after a jump. Ion
+ * uses them to find block boundaries when translating bytecode to MIR.
+ *
+ * Category: Control flow
+ * Type: Jump targets
+ * Operands: uint32_t icIndex
+ * Stack: =>
+ */ \
+ MACRO(JumpTarget, jump_target, NULL, 5, 0, 0, JOF_ICINDEX) \
+ /*
+ * Marks the target of the backwards jump for some loop.
+ *
+ * This is a jump target instruction (see `JSOp::JumpTarget`). Additionally,
+ * it checks for interrupts and handles JIT tiering.
+ *
+ * The `depthHint` operand is a loop depth hint for Ion. It starts at 1 and
+ * deeply nested loops all have the same value.
+ *
+ * For the convenience of the JITs, scripts must not start with this
+ * instruction. See bug 1602390.
+ *
+ * Category: Control flow
+ * Type: Jump targets
+ * Operands: uint32_t icIndex, uint8_t depthHint
+ * Stack: =>
+ */ \
+ MACRO(LoopHead, loop_head, NULL, 6, 0, 0, JOF_LOOPHEAD) \
+ /*
+ * Jump to a 32-bit offset from the current bytecode.
+ *
+ * See "Jump instructions" above for details.
+ *
+ * Category: Control flow
+ * Type: Jumps
+ * Operands: int32_t offset
+ * Stack: =>
+ */ \
+ MACRO(Goto, goto_, NULL, 5, 0, 0, JOF_JUMP) \
+ /*
+ * If ToBoolean(`cond`) is false, jumps to a 32-bit offset from the current
+ * instruction.
+ *
+ * Category: Control flow
+ * Type: Jumps
+ * Operands: int32_t forwardOffset
+ * Stack: cond =>
+ */ \
+ MACRO(JumpIfFalse, jump_if_false, NULL, 5, 1, 0, JOF_JUMP|JOF_IC) \
+ /*
+ * If ToBoolean(`cond`) is true, jump to a 32-bit offset from the current
+ * instruction.
+ *
+ * `offset` may be positive or negative. This is the instruction used at the
+ * end of a do-while loop to jump back to the top.
+ *
+ * Category: Control flow
+ * Type: Jumps
+ * Operands: int32_t offset
+ * Stack: cond =>
+ */ \
+ MACRO(JumpIfTrue, jump_if_true, NULL, 5, 1, 0, JOF_JUMP|JOF_IC) \
+ /*
+ * Short-circuit for logical AND.
+ *
+ * If ToBoolean(`cond`) is false, jump to a 32-bit offset from the current
+ * instruction. The value remains on the stack.
+ *
+ * Category: Control flow
+ * Type: Jumps
+ * Operands: int32_t forwardOffset
+ * Stack: cond => cond
+ */ \
+ MACRO(And, and_, NULL, 5, 1, 1, JOF_JUMP|JOF_IC) \
+ /*
+ * Short-circuit for logical OR.
+ *
+ * If ToBoolean(`cond`) is true, jump to a 32-bit offset from the current
+ * instruction. The value remains on the stack.
+ *
+ * Category: Control flow
+ * Type: Jumps
+ * Operands: int32_t forwardOffset
+ * Stack: cond => cond
+ */ \
+ MACRO(Or, or_, NULL, 5, 1, 1, JOF_JUMP|JOF_IC) \
+ /*
+ * Short-circuiting for nullish coalescing.
+ *
+ * If `val` is not null or undefined, jump to a 32-bit offset from the
+ * current instruction.
+ *
+ * Category: Control flow
+ * Type: Jumps
+ * Operands: int32_t forwardOffset
+ * Stack: val => val
+ */ \
+ MACRO(Coalesce, coalesce, NULL, 5, 1, 1, JOF_JUMP) \
+ /*
+ * Like `JSOp::JumpIfTrue`, but if the branch is taken, pop and discard an
+ * additional stack value.
+ *
+ * This is used to implement `switch` statements when the
+ * `JSOp::TableSwitch` optimization is not possible. The switch statement
+ *
+ * switch (expr) {
+ * case A: stmt1;
+ * case B: stmt2;
+ * }
+ *
+ * compiles to this bytecode:
+ *
+ * # dispatch code - evaluate expr, check it against each `case`,
+ * # jump to the right place in the body or to the end.
+ * <expr>
+ * Dup; <A>; StrictEq; Case L1; JumpTarget
+ * Dup; <B>; StrictEq; Case L2; JumpTarget
+ * Default LE
+ *
+ * # body code
+ * L1: JumpTarget; <stmt1>
+ * L2: JumpTarget; <stmt2>
+ * LE: JumpTarget
+ *
+ * This opcode is weird: it's the only one whose ndefs varies depending on
+ * which way a conditional branch goes. We could implement switch
+ * statements using `JSOp::JumpIfTrue` and `JSOp::Pop`, but that would also
+ * be awkward--putting the `JSOp::Pop` inside the `switch` body would
+ * complicate fallthrough.
+ *
+ * Category: Control flow
+ * Type: Jumps
+ * Operands: int32_t forwardOffset
+ * Stack: val, cond => val (if !cond)
+ */ \
+ MACRO(Case, case_, NULL, 5, 2, 1, JOF_JUMP) \
+ /*
+ * Like `JSOp::Goto`, but pop and discard an additional stack value.
+ *
+ * This appears after all cases for a non-optimized `switch` statement. If
+ * there's a `default:` label, it jumps to that point in the body;
+ * otherwise it jumps to the next statement.
+ *
+ * Category: Control flow
+ * Type: Jumps
+ * Operands: int32_t forwardOffset
+ * Stack: lval =>
+ */ \
+ MACRO(Default, default_, NULL, 5, 1, 0, JOF_JUMP) \
+ /*
+ * Optimized switch-statement dispatch, used when all `case` labels are
+ * small integer constants.
+ *
+ * If `low <= i <= high`, jump to the instruction at the offset given by
+ * `script->resumeOffsets()[firstResumeIndex + i - low]`, in bytes from the
+ * start of the current script's bytecode. Otherwise, jump to the
+ * instruction at `defaultOffset` from the current instruction. All of
+ * these offsets must be in range for the current script and must point to
+ * `JSOp::JumpTarget` instructions.
+ *
+ * The following inequalities must hold: `low <= high` and
+ * `firstResumeIndex + high - low < resumeOffsets().size()`.
+ *
+ * Category: Control flow
+ * Type: Jumps
+ * Operands: int32_t defaultOffset, int32_t low, int32_t high,
+ * uint24_t firstResumeIndex
+ * Stack: i =>
+ */ \
+ MACRO(TableSwitch, table_switch, NULL, 16, 1, 0, JOF_TABLESWITCH) \
+ /*
+ * Return `rval`.
+ *
+ * This must not be used in derived class constructors. Instead use
+ * `JSOp::SetRval`, `JSOp::CheckReturn`, and `JSOp::RetRval`.
+ *
+ * Category: Control flow
+ * Type: Return
+ * Operands:
+ * Stack: rval =>
+ */ \
+ MACRO(Return, return_, NULL, 1, 1, 0, JOF_BYTE) \
+ /*
+ * Push the current stack frame's `returnValue`. If no `JSOp::SetRval`
+ * instruction has been executed in this stack frame, this is `undefined`.
+ *
+ * Every stack frame has a `returnValue` slot, used by top-level scripts,
+ * generators, async functions, and derived class constructors. Plain
+ * functions usually use `JSOp::Return` instead.
+ *
+ * Category: Control flow
+ * Type: Return
+ * Operands:
+ * Stack: => rval
+ */ \
+ MACRO(GetRval, get_rval, NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Store `rval` in the current stack frame's `returnValue` slot.
+ *
+ * This instruction must not be used in a toplevel script compiled with the
+ * `noScriptRval` option.
+ *
+ * Category: Control flow
+ * Type: Return
+ * Operands:
+ * Stack: rval =>
+ */ \
+ MACRO(SetRval, set_rval, NULL, 1, 1, 0, JOF_BYTE) \
+ /*
+ * Stop execution and return the current stack frame's `returnValue`. If no
+ * `JSOp::SetRval` instruction has been executed in this stack frame, this
+ * is `undefined`.
+ *
+ * Also emitted at end of every script so consumers don't need to worry
+ * about running off the end.
+ *
+ * If the current script is a derived class constructor, `returnValue` must
+ * be an object. The script can use `JSOp::CheckReturn` to ensure this.
+ *
+ * Category: Control flow
+ * Type: Return
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(RetRval, ret_rval, NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Check the return value in a derived class constructor.
+ *
+ * - If the current stack frame's `returnValue` is an object, push
+ * `returnValue` onto the stack.
+ *
+ * - Otherwise, if the `returnValue` is undefined and `thisval` is an
+ * object, push `thisval` onto the stack.
+ *
+ * - Otherwise, throw a TypeError.
+ *
+ * This is exactly what has to happen when a derived class constructor
+ * returns. `thisval` should be the current value of `this`, or
+ * `MagicValue(JS_UNINITIALIZED_LEXICAL)` if `this` is uninitialized.
+ *
+ * Implements: [The [[Construct]] internal method of JS functions][1],
+ * steps 13 and 15.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget
+ *
+ * Category: Control flow
+ * Type: Return
+ * Operands:
+ * Stack: thisval => rval
+ */ \
+ MACRO(CheckReturn, check_return, NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Throw `exc`. (ノಠ益ಠ)ノ彡┴──┴
+ *
+ * This sets the pending exception to `exc` and jumps to error-handling
+ * code. If we're in a `try` block, error handling adjusts the stack and
+ * environment chain and resumes execution at the top of the `catch` or
+ * `finally` block. Otherwise it starts unwinding the stack.
+ *
+ * Implements: [*ThrowStatement* Evaluation][1], step 3.
+ *
+ * This is also used in for-of loops. If the body of the loop throws an
+ * exception, we catch it, close the iterator, then use `JSOp::Throw` to
+ * rethrow.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-throw-statement-runtime-semantics-evaluation
+ *
+ * Category: Control flow
+ * Type: Exceptions
+ * Operands:
+ * Stack: exc =>
+ */ \
+ MACRO(Throw, throw_, NULL, 1, 1, 0, JOF_BYTE) \
+ /*
+ * Create and throw an Error object.
+ *
+ * Sometimes we know at emit time that an operation always throws. For
+ * example, `delete super.prop;` is allowed in methods, but always throws a
+ * ReferenceError.
+ *
+ * `msgNumber` determines the `.message` and [[Prototype]] of the new Error
+ * object. It must be an error number in js/public/friend/ErrorNumbers.msg.
+ * The number of arguments in the error message must be 0.
+ *
+ * Category: Control flow
+ * Type: Exceptions
+ * Operands: ThrowMsgKind msgNumber
+ * Stack: =>
+ */ \
+ MACRO(ThrowMsg, throw_msg, NULL, 2, 0, 0, JOF_UINT8) \
+ /*
+ * Throws a runtime TypeError for invalid assignment to a `const` binding.
+ *
+ * Category: Control flow
+ * Type: Exceptions
+ * Operands: uint32_t nameIndex
+ * Stack:
+ */ \
+ MACRO(ThrowSetConst, throw_set_const, NULL, 5, 0, 0, JOF_ATOM|JOF_NAME) \
+ /*
+ * No-op instruction that marks the top of the bytecode for a
+ * *TryStatement*.
+ *
+ * Location information for catch/finally blocks is stored in a side table,
+ * `script->trynotes()`.
+ *
+ * Category: Control flow
+ * Type: Exceptions
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(Try, try_, NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * No-op instruction used by the exception unwinder to determine the
+ * correct environment to unwind to when performing IteratorClose due to
+ * destructuring.
+ *
+ * This instruction must appear immediately before each
+ * `JSTRY_DESTRUCTURING` span in a script's try notes.
+ *
+ * Category: Control flow
+ * Type: Exceptions
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(TryDestructuring, try_destructuring, NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Push and clear the pending exception. ┬──┬◡ノ(° -°ノ)
+ *
+ * This must be used only in the fixed sequence of instructions following a
+ * `JSTRY_CATCH` span (see "Bytecode Invariants" above), as that's the only
+ * way instructions would run with an exception pending.
+ *
+ * Used to implement catch-blocks, including the implicit ones generated as
+ * part of for-of iteration.
+ *
+ * Category: Control flow
+ * Type: Exceptions
+ * Operands:
+ * Stack: => exception
+ */ \
+ MACRO(Exception, exception, NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * No-op instruction that marks the start of a `finally` block.
+ *
+ * Category: Control flow
+ * Type: Exceptions
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(Finally, finally, NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Push `MagicValue(JS_UNINITIALIZED_LEXICAL)`, a magic value used to mark
+ * a binding as uninitialized.
+ *
+ * This magic value must be used only by `JSOp::InitLexical`.
+ *
+ * Category: Variables and scopes
+ * Type: Initialization
+ * Operands:
+ * Stack: => uninitialized
+ */ \
+ MACRO(Uninitialized, uninitialized, NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Initialize an optimized local lexical binding; or mark it as
+ * uninitialized.
+ *
+ * This stores the value `v` in the fixed slot `localno` in the current
+ * stack frame. If `v` is the magic value produced by `JSOp::Uninitialized`,
+ * this marks the binding as uninitialized. Otherwise this initializes the
+ * binding with value `v`.
+ *
+ * Implements: [CreateMutableBinding][1] step 3, substep "record that it is
+ * uninitialized", and [InitializeBinding][2], for optimized locals. (Note:
+ * this is how `const` bindings are initialized.)
+ *
+ * [1]: https://tc39.es/ecma262/#sec-declarative-environment-records-createmutablebinding-n-d
+ * [2]: https://tc39.es/ecma262/#sec-declarative-environment-records-initializebinding-n-v
+ *
+ * Category: Variables and scopes
+ * Type: Initialization
+ * Operands: uint24_t localno
+ * Stack: v => v
+ */ \
+ MACRO(InitLexical, init_lexical, NULL, 4, 1, 1, JOF_LOCAL|JOF_NAME) \
+ /*
+ * Initialize a global lexical binding.
+ *
+ * The binding must already have been created by
+ * `GlobalOrEvalDeclInstantiation` and must be uninitialized.
+ *
+ * Like `JSOp::InitLexical` but for global lexicals. Unlike `InitLexical`
+ * this can't be used to mark a binding as uninitialized.
+ *
+ * Category: Variables and scopes
+ * Type: Initialization
+ * Operands: uint32_t nameIndex
+ * Stack: val => val
+ */ \
+ MACRO(InitGLexical, init_g_lexical, NULL, 5, 1, 1, JOF_ATOM|JOF_NAME|JOF_PROPINIT|JOF_GNAME|JOF_IC) \
+ /*
+ * Initialize an aliased lexical binding; or mark it as uninitialized.
+ *
+ * Like `JSOp::InitLexical` but for aliased bindings.
+ *
+ * Note: There is no even-less-optimized `InitName` instruction because JS
+ * doesn't need it. We always know statically which binding we're
+ * initializing.
+ *
+ * `hops` is usually 0, but in `function f(a=eval("var b;")) { }`, the
+ * argument `a` is initialized from inside a nested scope, so `hops == 1`.
+ *
+ * Category: Variables and scopes
+ * Type: Initialization
+ * Operands: uint8_t hops, uint24_t slot
+ * Stack: v => v
+ */ \
+ MACRO(InitAliasedLexical, init_aliased_lexical, NULL, 5, 1, 1, JOF_ENVCOORD|JOF_NAME|JOF_PROPINIT) \
+ /*
+ * Throw a ReferenceError if the value on top of the stack is uninitialized.
+ *
+ * Typically used after `JSOp::GetLocal` with the same `localno`.
+ *
+ * Implements: [GetBindingValue][1] step 3 and [SetMutableBinding][2] step
+ * 4 for declarative Environment Records.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-declarative-environment-records-getbindingvalue-n-s
+ * [2]: https://tc39.es/ecma262/#sec-declarative-environment-records-setmutablebinding-n-v-s
+ *
+ * Category: Variables and scopes
+ * Type: Initialization
+ * Operands: uint24_t localno
+ * Stack: v => v
+ */ \
+ MACRO(CheckLexical, check_lexical, NULL, 4, 1, 1, JOF_LOCAL|JOF_NAME) \
+ /*
+ * Like `JSOp::CheckLexical` but for aliased bindings.
+ *
+ * Typically used after `JSOp::GetAliasedVar` with the same hops/slot.
+ *
+ * Note: There are no `CheckName` or `CheckGName` instructions because
+ * they're unnecessary. `JSOp::{Get,Set}{Name,GName}` all check for
+ * uninitialized lexicals and throw if needed.
+ *
+ * Category: Variables and scopes
+ * Type: Initialization
+ * Operands: uint8_t hops, uint24_t slot
+ * Stack: v => v
+ */ \
+ MACRO(CheckAliasedLexical, check_aliased_lexical, NULL, 5, 1, 1, JOF_ENVCOORD|JOF_NAME) \
+ /*
+ * Throw a ReferenceError if the value on top of the stack is
+ * `MagicValue(JS_UNINITIALIZED_LEXICAL)`. Used in derived class
+ * constructors to check `this` (which needs to be initialized before use,
+ * by calling `super()`).
+ *
+ * Implements: [GetThisBinding][1] step 3.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-function-environment-records-getthisbinding
+ *
+ * Category: Variables and scopes
+ * Type: Initialization
+ * Operands:
+ * Stack: this => this
+ */ \
+ MACRO(CheckThis, check_this, NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Look up a name on the global lexical environment's chain and push the
+ * environment which contains a binding for that name. If no such binding
+ * exists, push the global lexical environment.
+ *
+ * Category: Variables and scopes
+ * Type: Looking up bindings
+ * Operands: uint32_t nameIndex
+ * Stack: => global
+ */ \
+ MACRO(BindGName, bind_g_name, NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_GNAME|JOF_IC) \
+ /*
+ * Look up a name on the environment chain and push the environment which
+ * contains a binding for that name. If no such binding exists, push the
+ * global lexical environment.
+ *
+ * Category: Variables and scopes
+ * Type: Looking up bindings
+ * Operands: uint32_t nameIndex
+ * Stack: => env
+ */ \
+ MACRO(BindName, bind_name, NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_IC|JOF_USES_ENV) \
+ /*
+ * Find a binding on the environment chain and push its value.
+ *
+ * If the binding is an uninitialized lexical, throw a ReferenceError. If
+ * no such binding exists, throw a ReferenceError unless the next
+ * instruction is `JSOp::Typeof`, in which case push `undefined`.
+ *
+ * Implements: [ResolveBinding][1] followed by [GetValue][2]
+ * (adjusted hackily for `typeof`).
+ *
+ * This is the fallback `Get` instruction that handles all unoptimized
+ * cases. Optimized instructions follow.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-resolvebinding
+ * [2]: https://tc39.es/ecma262/#sec-getvalue
+ *
+ * Category: Variables and scopes
+ * Type: Getting binding values
+ * Operands: uint32_t nameIndex
+ * Stack: => val
+ */ \
+ MACRO(GetName, get_name, NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_IC|JOF_USES_ENV) \
+ /*
+ * Find a global binding and push its value.
+ *
+ * This searches the global lexical environment and, failing that, the
+ * global object. (Unlike most declarative environments, the global lexical
+ * environment can gain more bindings after compilation, possibly shadowing
+ * global object properties.)
+ *
+ * This is an optimized version of `JSOp::GetName` that skips all local
+ * scopes, for use when the name doesn't refer to any local binding.
+ * `NonSyntacticVariablesObject`s break this optimization, so if the
+ * current script has a non-syntactic global scope, use `JSOp::GetName`
+ * instead.
+ *
+ * Like `JSOp::GetName`, this throws a ReferenceError if no such binding is
+ * found (unless the next instruction is `JSOp::Typeof`) or if the binding
+ * is an uninitialized lexical.
+ *
+ * Category: Variables and scopes
+ * Type: Getting binding values
+ * Operands: uint32_t nameIndex
+ * Stack: => val
+ */ \
+ MACRO(GetGName, get_g_name, NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_GNAME|JOF_IC) \
+ /*
+ * Push the value of an argument that is stored in the stack frame
+ * or in an `ArgumentsObject`.
+ *
+ * Category: Variables and scopes
+ * Type: Getting binding values
+ * Operands: uint16_t argno
+ * Stack: => arguments[argno]
+ */ \
+ MACRO(GetArg, get_arg, NULL, 3, 0, 1, JOF_QARG|JOF_NAME) \
+ /*
+ * Push the value of an argument that is stored in the stack frame. Like
+ * `JSOp::GetArg`, but ignores the frame's `ArgumentsObject` and doesn't
+ * assert the argument is unaliased.
+ *
+ * Category: Variables and scopes
+ * Type: Getting binding values
+ * Operands: uint16_t argno
+ * Stack: => arguments[argno]
+ */ \
+ MACRO(GetFrameArg, get_frame_arg, NULL, 3, 0, 1, JOF_QARG|JOF_NAME) \
+ /*
+ * Push the value of an optimized local variable.
+ *
+ * If the variable is an uninitialized lexical, push
+ * `MagicValue(JS_UNINIITALIZED_LEXICAL)`.
+ *
+ * Category: Variables and scopes
+ * Type: Getting binding values
+ * Operands: uint24_t localno
+ * Stack: => val
+ */ \
+ MACRO(GetLocal, get_local, NULL, 4, 0, 1, JOF_LOCAL|JOF_NAME) \
+ /*
+ * Push the number of actual arguments as Int32Value.
+ *
+ * This is emitted for the ArgumentsLength() intrinsic in self-hosted code.
+ *
+ * Category: Variables and scopes
+ * Type: Getting binding values
+ * Operands:
+ * Stack: => arguments.length
+ */ \
+ MACRO(ArgumentsLength, arguments_length, NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Push the value of an argument that is stored in the stack frame. The
+ * value on top of the stack must be an Int32Value storing the index. The
+ * index must be less than the number of actual arguments.
+ *
+ * This is emitted for the GetArgument(i) intrinsic in self-hosted code.
+ *
+ * Category: Variables and scopes
+ * Type: Getting binding values
+ * Operands:
+ * Stack: index => arguments[index]
+ */ \
+ MACRO(GetActualArg, get_actual_arg, NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Push the value of an aliased binding.
+ *
+ * Local bindings that aren't closed over or dynamically accessed are
+ * stored in stack slots. Global and `with` bindings are object properties.
+ * All other bindings are called "aliased" and stored in
+ * `EnvironmentObject`s.
+ *
+ * Where possible, `Aliased` instructions are used to access aliased
+ * bindings. (There's no difference in meaning between `AliasedVar` and
+ * `AliasedLexical`.) Each of these instructions has operands `hops` and
+ * `slot` that encode an [`EnvironmentCoordinate`][1], directions to the
+ * binding from the current environment object.
+ *
+ * `Aliased` instructions can't be used when there's a dynamic scope (due
+ * to non-strict `eval` or `with`) that might shadow the aliased binding.
+ *
+ * [1]: https://searchfox.org/mozilla-central/search?q=symbol:T_js%3A%3AEnvironmentCoordinate
+ *
+ * Category: Variables and scopes
+ * Type: Getting binding values
+ * Operands: uint8_t hops, uint24_t slot
+ * Stack: => aliasedVar
+ */ \
+ MACRO(GetAliasedVar, get_aliased_var, NULL, 5, 0, 1, JOF_ENVCOORD|JOF_NAME|JOF_USES_ENV) \
+ /*
+ * Push the value of an aliased binding, which may have to bypass a DebugEnvironmentProxy
+ * on the environment chain.
+ *
+ * Category: Variables and scopes
+ * Type: Getting binding values
+ * Operands: uint8_t hops, uint24_t slot
+ * Stack: => aliasedVar
+ */ \
+ MACRO(GetAliasedDebugVar, get_aliased_debug_var, NULL, 5, 0, 1, JOF_DEBUGCOORD|JOF_NAME) \
+ /*
+ * Get the value of a module import by name and pushes it onto the stack.
+ *
+ * Category: Variables and scopes
+ * Type: Getting binding values
+ * Operands: uint32_t nameIndex
+ * Stack: => val
+ */ \
+ MACRO(GetImport, get_import, NULL, 5, 0, 1, JOF_ATOM|JOF_NAME) \
+ /*
+ * Get the value of a binding from the environment `env`. If the name is
+ * not bound in `env`, throw a ReferenceError.
+ *
+ * `env` must be an environment currently on the environment chain, pushed
+ * by `JSOp::BindName` or `JSOp::BindVar`.
+ *
+ * Note: `JSOp::BindName` and `JSOp::GetBoundName` are the two halves of the
+ * `JSOp::GetName` operation: finding and reading a variable. This
+ * decomposed version is needed to implement the compound assignment and
+ * increment/decrement operators, which get and then set a variable. The
+ * spec says the variable lookup is done only once. If we did the lookup
+ * twice, there would be observable bugs, thanks to dynamic scoping. We
+ * could set the wrong variable or call proxy traps incorrectly.
+ *
+ * Implements: [GetValue][1] steps 4 and 6.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-getvalue
+ *
+ * Category: Variables and scopes
+ * Type: Getting binding values
+ * Operands: uint32_t nameIndex
+ * Stack: env => v
+ */ \
+ MACRO(GetBoundName, get_bound_name, NULL, 5, 1, 1, JOF_ATOM|JOF_NAME|JOF_IC) \
+ /*
+ * Push the value of an intrinsic onto the stack.
+ *
+ * Non-standard. Intrinsics are slots in the intrinsics holder object (see
+ * `GlobalObject::getIntrinsicsHolder`), which is used in lieu of global
+ * bindings in self-hosting code.
+ *
+ * Category: Variables and scopes
+ * Type: Getting binding values
+ * Operands: uint32_t nameIndex
+ * Stack: => intrinsic[name]
+ */ \
+ MACRO(GetIntrinsic, get_intrinsic, NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_IC) \
+ /*
+ * Pushes the currently executing function onto the stack.
+ *
+ * The current script must be a function script.
+ *
+ * Used to implement `super`. This is also used sometimes as a minor
+ * optimization when a named function expression refers to itself by name:
+ *
+ * f = function fac(n) { ... fac(n - 1) ... };
+ *
+ * This lets us optimize away a lexical environment that contains only the
+ * binding for `fac`, unless it's otherwise observable (via `with`, `eval`,
+ * or a nested closure).
+ *
+ * Category: Variables and scopes
+ * Type: Getting binding values
+ * Operands:
+ * Stack: => callee
+ */ \
+ MACRO(Callee, callee, NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Load the callee stored in a CallObject on the environment chain. The
+ * `numHops` operand is the number of environment objects to skip on the
+ * environment chain. The environment chain element indicated by `numHops`
+ * must be a CallObject.
+ *
+ * Category: Variables and scopes
+ * Type: Getting binding values
+ * Operands: uint8_t numHops
+ * Stack: => callee
+ */ \
+ MACRO(EnvCallee, env_callee, NULL, 2, 0, 1, JOF_UINT8) \
+ /*
+ * Assign `val` to the binding in `env` with the name given by `nameIndex`.
+ * Throw a ReferenceError if the binding is an uninitialized lexical.
+ * This can call setters and/or proxy traps.
+ *
+ * `env` must be an environment currently on the environment chain,
+ * pushed by `JSOp::BindName` or `JSOp::BindVar`.
+ *
+ * This is the fallback `Set` instruction that handles all unoptimized
+ * cases. Optimized instructions follow.
+ *
+ * Implements: [PutValue][1] steps 5 and 7 for unoptimized bindings.
+ *
+ * Note: `JSOp::BindName` and `JSOp::SetName` are the two halves of simple
+ * assignment: finding and setting a variable. They are two separate
+ * instructions because, per spec, the "finding" part happens before
+ * evaluating the right-hand side of the assignment, and the "setting" part
+ * after. Optimized cases don't need a `Bind` instruction because the
+ * "finding" is done statically.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-putvalue
+ *
+ * Category: Variables and scopes
+ * Type: Setting binding values
+ * Operands: uint32_t nameIndex
+ * Stack: env, val => val
+ */ \
+ MACRO(SetName, set_name, NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_PROPSET|JOF_CHECKSLOPPY|JOF_IC|JOF_USES_ENV) \
+ /*
+ * Like `JSOp::SetName`, but throw a TypeError if there is no binding for
+ * the specified name in `env`, or if the binding is immutable (a `const`
+ * or read-only property).
+ *
+ * Implements: [PutValue][1] steps 5 and 7 for strict mode code.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-putvalue
+ *
+ * Category: Variables and scopes
+ * Type: Setting binding values
+ * Operands: uint32_t nameIndex
+ * Stack: env, val => val
+ */ \
+ MACRO(StrictSetName, strict_set_name, NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_PROPSET|JOF_CHECKSTRICT|JOF_IC|JOF_USES_ENV) \
+ /*
+ * Like `JSOp::SetName`, but for assigning to globals. `env` must be an
+ * environment pushed by `JSOp::BindGName`.
+ *
+ * Category: Variables and scopes
+ * Type: Setting binding values
+ * Operands: uint32_t nameIndex
+ * Stack: env, val => val
+ */ \
+ MACRO(SetGName, set_g_name, NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_PROPSET|JOF_GNAME|JOF_CHECKSLOPPY|JOF_IC) \
+ /*
+ * Like `JSOp::StrictSetGName`, but for assigning to globals. `env` must be
+ * an environment pushed by `JSOp::BindGName`.
+ *
+ * Category: Variables and scopes
+ * Type: Setting binding values
+ * Operands: uint32_t nameIndex
+ * Stack: env, val => val
+ */ \
+ MACRO(StrictSetGName, strict_set_g_name, NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_PROPSET|JOF_GNAME|JOF_CHECKSTRICT|JOF_IC) \
+ /*
+ * Assign `val` to an argument binding that's stored in the stack frame or
+ * in an `ArgumentsObject`.
+ *
+ * Category: Variables and scopes
+ * Type: Setting binding values
+ * Operands: uint16_t argno
+ * Stack: val => val
+ */ \
+ MACRO(SetArg, set_arg, NULL, 3, 1, 1, JOF_QARG|JOF_NAME) \
+ /*
+ * Assign to an optimized local binding.
+ *
+ * Category: Variables and scopes
+ * Type: Setting binding values
+ * Operands: uint24_t localno
+ * Stack: v => v
+ */ \
+ MACRO(SetLocal, set_local, NULL, 4, 1, 1, JOF_LOCAL|JOF_NAME) \
+ /*
+ * Assign to an aliased binding.
+ *
+ * Implements: [SetMutableBinding for declarative Environment Records][1],
+ * in certain cases where it's known that the binding exists, is mutable,
+ * and has been initialized.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-declarative-environment-records-setmutablebinding-n-v-s
+ *
+ * Category: Variables and scopes
+ * Type: Setting binding values
+ * Operands: uint8_t hops, uint24_t slot
+ * Stack: val => val
+ */ \
+ MACRO(SetAliasedVar, set_aliased_var, NULL, 5, 1, 1, JOF_ENVCOORD|JOF_NAME|JOF_PROPSET|JOF_USES_ENV) \
+ /*
+ * Assign to an intrinsic.
+ *
+ * Nonstandard. Intrinsics are used in lieu of global bindings in self-
+ * hosted code. The value is actually stored in the intrinsics holder
+ * object, `GlobalObject::getIntrinsicsHolder`. (Self-hosted code doesn't
+ * have many global `var`s, but it has many `function`s.)
+ *
+ * Category: Variables and scopes
+ * Type: Setting binding values
+ * Operands: uint32_t nameIndex
+ * Stack: val => val
+ */ \
+ MACRO(SetIntrinsic, set_intrinsic, NULL, 5, 1, 1, JOF_ATOM|JOF_NAME) \
+ /*
+ * Push a lexical environment onto the environment chain.
+ *
+ * The `LexicalScope` indicated by `lexicalScopeIndex` determines the shape
+ * of the new `BlockLexicalEnvironmentObject`. All bindings in the new
+ * environment are marked as uninitialized.
+ *
+ * Implements: [Evaluation of *Block*][1], steps 1-4.
+ *
+ * #### Fine print for environment chain instructions
+ *
+ * The following rules for `JSOp::{Push,Pop}LexicalEnv` also apply to
+ * `JSOp::PushClassBodyEnv`, `JSOp::PushVarEnv`, and
+ * `JSOp::{Enter,Leave}With`.
+ *
+ * Each `JSOp::PopLexicalEnv` instruction matches a particular
+ * `JSOp::PushLexicalEnv` instruction in the same script and must have the
+ * same scope and stack depth as the instruction immediately after that
+ * `PushLexicalEnv`.
+ *
+ * `JSOp::PushLexicalEnv` enters a scope that extends to some set of
+ * instructions in the script. Code must not jump into or out of this
+ * region: control can enter only by executing `PushLexicalEnv` and can
+ * exit only by executing a `PopLexicalEnv` or by exception unwinding. (A
+ * `JSOp::PopLexicalEnv` is always emitted at the end of the block, and
+ * extra copies are emitted on "exit slides", where a `break`, `continue`,
+ * or `return` statement exits the scope.)
+ *
+ * The script's `JSScript::scopeNotes()` must identify exactly which
+ * instructions begin executing in this scope. Typically this means a
+ * single entry marking the contiguous chunk of bytecode from the
+ * instruction after `JSOp::PushLexicalEnv` to `JSOp::PopLexicalEnv`
+ * (inclusive); but if that range contains any instructions on exit slides,
+ * after a `JSOp::PopLexicalEnv`, then those must be correctly noted as
+ * *outside* the scope.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-block-runtime-semantics-evaluation
+ *
+ * Category: Variables and scopes
+ * Type: Entering and leaving environments
+ * Operands: uint32_t lexicalScopeIndex
+ * Stack: =>
+ */ \
+ MACRO(PushLexicalEnv, push_lexical_env, NULL, 5, 0, 0, JOF_SCOPE|JOF_USES_ENV) \
+ /*
+ * Pop a lexical or class-body environment from the environment chain.
+ *
+ * See `JSOp::PushLexicalEnv` for the fine print.
+ *
+ * Category: Variables and scopes
+ * Type: Entering and leaving environments
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(PopLexicalEnv, pop_lexical_env, NULL, 1, 0, 0, JOF_BYTE|JOF_USES_ENV) \
+ /*
+ * No-op instruction that indicates leaving an optimized lexical scope.
+ *
+ * If all bindings in a lexical scope are optimized into stack slots, then
+ * the runtime environment objects for that scope are optimized away. No
+ * `JSOp::{Push,Pop}LexicalEnv` instructions are emitted. However, the
+ * debugger still needs to be notified when control exits a scope; that's
+ * what this instruction does.
+ *
+ * The last instruction in a lexical or class-body scope, as indicated by
+ * scope notes, must be either this instruction (if the scope is optimized)
+ * or `JSOp::PopLexicalEnv` (if not).
+ *
+ * Category: Variables and scopes
+ * Type: Entering and leaving environments
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(DebugLeaveLexicalEnv, debug_leave_lexical_env, NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Replace the current block on the environment chain with a fresh block
+ * with uninitialized bindings. This implements the behavior of inducing a
+ * fresh lexical environment for every iteration of a for-in/of loop whose
+ * loop-head declares lexical variables that may be captured.
+ *
+ * The current environment must be a BlockLexicalEnvironmentObject.
+ *
+ * Category: Variables and scopes
+ * Type: Entering and leaving environments
+ * Operands: uint32_t lexicalScopeIndex
+ * Stack: =>
+ */ \
+ MACRO(RecreateLexicalEnv, recreate_lexical_env, NULL, 5, 0, 0, JOF_SCOPE) \
+ /*
+ * Like `JSOp::RecreateLexicalEnv`, but the values of all the bindings are
+ * copied from the old block to the new one. This is used for C-style
+ * `for(let ...; ...; ...)` loops.
+ *
+ * Category: Variables and scopes
+ * Type: Entering and leaving environments
+ * Operands: uint32_t lexicalScopeIndex
+ * Stack: =>
+ */ \
+ MACRO(FreshenLexicalEnv, freshen_lexical_env, NULL, 5, 0, 0, JOF_SCOPE) \
+ /*
+ * Push a ClassBody environment onto the environment chain.
+ *
+ * Like `JSOp::PushLexicalEnv`, but pushes a `ClassBodyEnvironmentObject`
+ * rather than a `BlockLexicalEnvironmentObject`. `JSOp::PopLexicalEnv` is
+ * used to pop class-body environments as well as lexical environments.
+ *
+ * See `JSOp::PushLexicalEnv` for the fine print.
+ *
+ * Category: Variables and scopes
+ * Type: Entering and leaving environments
+ * Operands: uint32_t lexicalScopeIndex
+ * Stack: =>
+ */ \
+ MACRO(PushClassBodyEnv, push_class_body_env, NULL, 5, 0, 0, JOF_SCOPE) \
+ /*
+ * Push a var environment onto the environment chain.
+ *
+ * Like `JSOp::PushLexicalEnv`, but pushes a `VarEnvironmentObject` rather
+ * than a `BlockLexicalEnvironmentObject`. The difference is that
+ * non-strict direct `eval` can add bindings to a var environment; see
+ * `VarScope` in Scope.h.
+ *
+ * See `JSOp::PushLexicalEnv` for the fine print.
+ *
+ * There is no corresponding `JSOp::PopVarEnv` operation, because a
+ * `VarEnvironmentObject` is never popped from the environment chain.
+ *
+ * Implements: Places in the spec where the VariableEnvironment is set:
+ *
+ * - The bit in [PerformEval][1] where, in strict direct eval, the new
+ * eval scope is taken as *varEnv* and becomes "*runningContext*'s
+ * VariableEnvironment".
+ *
+ * - The weird scoping rules for functions with default parameter
+ * expressions, as specified in [FunctionDeclarationInstantiation][2]
+ * step 28 ("NOTE: A separate Environment Record is needed...").
+ *
+ * Note: The spec also pushes a new VariableEnvironment on entry to every
+ * function, but the VM takes care of that as part of pushing the stack
+ * frame, before the function script starts to run, so `JSOp::PushVarEnv` is
+ * not needed.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-performeval
+ * [2]: https://tc39.es/ecma262/#sec-functiondeclarationinstantiation
+ *
+ * Category: Variables and scopes
+ * Type: Entering and leaving environments
+ * Operands: uint32_t scopeIndex
+ * Stack: =>
+ */ \
+ MACRO(PushVarEnv, push_var_env, NULL, 5, 0, 0, JOF_SCOPE|JOF_USES_ENV) \
+ /*
+ * Push a `WithEnvironmentObject` wrapping ToObject(`val`) to the
+ * environment chain.
+ *
+ * Implements: [Evaluation of `with` statements][1], steps 2-6.
+ *
+ * Operations that may need to consult a WithEnvironment can't be correctly
+ * implemented using optimized instructions like `JSOp::GetLocal`. A script
+ * must use the deoptimized `JSOp::GetName`, `BindName`, `SetName`, and
+ * `DelName` instead. Since those instructions don't work correctly with
+ * optimized locals and arguments, all bindings in scopes enclosing a
+ * `with` statement are marked as "aliased" and deoptimized too.
+ *
+ * See `JSOp::PushLexicalEnv` for the fine print.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-with-statement-runtime-semantics-evaluation
+ *
+ * Category: Variables and scopes
+ * Type: Entering and leaving environments
+ * Operands: uint32_t staticWithIndex
+ * Stack: val =>
+ */ \
+ MACRO(EnterWith, enter_with, NULL, 5, 1, 0, JOF_SCOPE) \
+ /*
+ * Pop a `WithEnvironmentObject` from the environment chain.
+ *
+ * See `JSOp::PushLexicalEnv` for the fine print.
+ *
+ * Implements: [Evaluation of `with` statements][1], step 8.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-with-statement-runtime-semantics-evaluation
+ *
+ * Category: Variables and scopes
+ * Type: Entering and leaving environments
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(LeaveWith, leave_with, NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Push the current VariableEnvironment (the environment on the environment
+ * chain designated to receive new variables).
+ *
+ * Implements: [Annex B.3.3.1, changes to FunctionDeclarationInstantiation
+ * for block-level functions][1], step 1.a.ii.3.a, and similar steps in
+ * other Annex B.3.3 algorithms, when setting the function's second binding
+ * can't be optimized.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-web-compat-functiondeclarationinstantiation
+ *
+ * Category: Variables and scopes
+ * Type: Creating and deleting bindings
+ * Operands:
+ * Stack: => env
+ */ \
+ MACRO(BindVar, bind_var, NULL, 1, 0, 1, JOF_BYTE|JOF_USES_ENV) \
+ /*
+ * Check for conflicting bindings and then initialize them in global or
+ * sloppy eval scripts. This is required for global scripts with any
+ * top-level bindings, or any sloppy-eval scripts with any non-lexical
+ * top-level bindings.
+ *
+ * Implements: [GlobalDeclarationInstantiation][1] and
+ * [EvalDeclarationInstantiation][2] (except step 12).
+ *
+ * The `lastFun` argument is a GCThingIndex of the last hoisted top-level
+ * function that is part of top-level script initialization. The gcthings
+ * from index `0` thru `lastFun` contain only scopes and hoisted functions.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
+ * [2]: https://tc39.es/ecma262/#sec-evaldeclarationinstantiation
+ *
+ * Category: Variables and scopes
+ * Type: Creating and deleting bindings
+ * Operands: uint32_t lastFun
+ * Stack: =>
+ */ \
+ MACRO(GlobalOrEvalDeclInstantiation, global_or_eval_decl_instantiation, NULL, 5, 0, 0, JOF_GCTHING|JOF_USES_ENV) \
+ /*
+ * Look up a variable on the environment chain and delete it. Push `true`
+ * on success (if a binding was deleted, or if no such binding existed in
+ * the first place), `false` otherwise (most kinds of bindings can't be
+ * deleted).
+ *
+ * Implements: [`delete` *Identifier*][1], which [is a SyntaxError][2] in
+ * strict mode code.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-delete-operator-runtime-semantics-evaluation
+ * [2]: https://tc39.es/ecma262/#sec-delete-operator-static-semantics-early-errors
+ *
+ * Category: Variables and scopes
+ * Type: Creating and deleting bindings
+ * Operands: uint32_t nameIndex
+ * Stack: => succeeded
+ */ \
+ MACRO(DelName, del_name, NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_CHECKSLOPPY|JOF_USES_ENV) \
+ /*
+ * Create and push the `arguments` object for the current function activation.
+ *
+ * When it exists, `arguments` is stored in an ordinary local variable.
+ * `JSOp::Arguments` is used in function preludes, to populate that variable
+ * before the function body runs, *not* each time `arguments` appears in a
+ * function.
+ *
+ * If a function clearly doesn't use `arguments`, we optimize it away when
+ * emitting bytecode. The function's script won't use `JSOp::Arguments` at
+ * all.
+ *
+ * The current script must be a function script. This instruction must
+ * execute at most once per function activation.
+ *
+ * Category: Variables and scopes
+ * Type: Function environment setup
+ * Operands:
+ * Stack: => arguments
+ */ \
+ MACRO(Arguments, arguments, NULL, 1, 0, 1, JOF_BYTE|JOF_USES_ENV) \
+ /*
+ * Create and push the rest parameter array for current function call.
+ *
+ * This must appear only in a script for a function that has a rest
+ * parameter.
+ *
+ * Category: Variables and scopes
+ * Type: Function environment setup
+ * Operands:
+ * Stack: => rest
+ */ \
+ MACRO(Rest, rest, NULL, 1, 0, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * Determines the `this` value for current function frame and pushes it
+ * onto the stack.
+ *
+ * In functions, `this` is stored in a local variable. This instruction is
+ * used in the function prologue to get the value to initialize that
+ * variable. (This doesn't apply to arrow functions, becauses they don't
+ * have a `this` binding; also, `this` is optimized away if it's unused.)
+ *
+ * Functions that have a `this` binding have a local variable named
+ * `".this"`, which is initialized using this instruction in the function
+ * prologue.
+ *
+ * In non-strict functions, `this` is always an object. Undefined/null
+ * `this` is converted into the global `this` value. Other primitive values
+ * are boxed. See `js::BoxNonStrictThis`.
+ *
+ * Category: Variables and scopes
+ * Type: Function environment setup
+ * Operands:
+ * Stack: => this
+ */ \
+ MACRO(FunctionThis, function_this, NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Pop the top value from the stack and discard it.
+ *
+ * Category: Stack operations
+ * Operands:
+ * Stack: v =>
+ */ \
+ MACRO(Pop, pop, NULL, 1, 1, 0, JOF_BYTE) \
+ /*
+ * Pop the top `n` values from the stack. `n` must be <= the current stack
+ * depth.
+ *
+ * Category: Stack operations
+ * Operands: uint16_t n
+ * Stack: v[n-1], ..., v[1], v[0] =>
+ */ \
+ MACRO(PopN, pop_n, NULL, 3, -1, 0, JOF_UINT16) \
+ /*
+ * Push a copy of the top value on the stack.
+ *
+ * Category: Stack operations
+ * Operands:
+ * Stack: v => v, v
+ */ \
+ MACRO(Dup, dup, NULL, 1, 1, 2, JOF_BYTE) \
+ /*
+ * Duplicate the top two values on the stack.
+ *
+ * Category: Stack operations
+ * Operands:
+ * Stack: v1, v2 => v1, v2, v1, v2
+ */ \
+ MACRO(Dup2, dup2, NULL, 1, 2, 4, JOF_BYTE) \
+ /*
+ * Push a copy of the nth value from the top of the stack.
+ *
+ * `n` must be less than the current stack depth.
+ *
+ * Category: Stack operations
+ * Operands: uint24_t n
+ * Stack: v[n], v[n-1], ..., v[1], v[0] =>
+ * v[n], v[n-1], ..., v[1], v[0], v[n]
+ */ \
+ MACRO(DupAt, dup_at, NULL, 4, 0, 1, JOF_UINT24) \
+ /*
+ * Swap the top two values on the stack.
+ *
+ * Category: Stack operations
+ * Operands:
+ * Stack: v1, v2 => v2, v1
+ */ \
+ MACRO(Swap, swap, NULL, 1, 2, 2, JOF_BYTE) \
+ /*
+ * Pick the nth element from the stack and move it to the top of the stack.
+ *
+ * Category: Stack operations
+ * Operands: uint8_t n
+ * Stack: v[n], v[n-1], ..., v[1], v[0] => v[n-1], ..., v[1], v[0], v[n]
+ */ \
+ MACRO(Pick, pick, NULL, 2, 0, 0, JOF_UINT8) \
+ /*
+ * Move the top of the stack value under the `n`th element of the stack.
+ * `n` must not be 0.
+ *
+ * Category: Stack operations
+ * Operands: uint8_t n
+ * Stack: v[n], v[n-1], ..., v[1], v[0] => v[0], v[n], v[n-1], ..., v[1]
+ */ \
+ MACRO(Unpick, unpick, NULL, 2, 0, 0, JOF_UINT8) \
+ /*
+ * Do nothing. This is used when we need distinct bytecode locations for
+ * various mechanisms.
+ *
+ * Category: Other
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(Nop, nop, NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * No-op instruction emitted immediately after `JSOp::*Eval` so that direct
+ * eval does not have to do slow pc-to-line mapping.
+ *
+ * The `lineno` operand should agree with this script's source notes about
+ * the line number of the preceding `*Eval` instruction.
+ *
+ * Category: Other
+ * Operands: uint32_t lineno
+ * Stack: =>
+ */ \
+ MACRO(Lineno, lineno, NULL, 5, 0, 0, JOF_UINT32) \
+ /*
+ * No-op instruction to hint that the top stack value is uninteresting.
+ *
+ * This affects only debug output and some error messages.
+ * In array destructuring, we emit bytecode that is roughly equivalent to
+ * `result.done ? undefined : result.value`.
+ * `NopDestructuring` is emitted after the `undefined`, so that the
+ * expression decompiler and disassembler know to casually ignore the
+ * possibility of `undefined`, and render the result of the conditional
+ * expression simply as "`result.value`".
+ *
+ * Category: Other
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(NopDestructuring, nop_destructuring, NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * No-op instruction only emitted in some self-hosted functions. Not
+ * handled by the JITs or Baseline Interpreter so the script always runs in
+ * the C++ interpreter.
+ *
+ * Category: Other
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(ForceInterpreter, force_interpreter, NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Examine the top stack value, asserting that it's either a self-hosted
+ * function or a self-hosted intrinsic. This does nothing in a non-debug
+ * build.
+ *
+ * Category: Other
+ * Operands:
+ * Stack: checkVal => checkVal
+ */ \
+ MACRO(DebugCheckSelfHosted, debug_check_self_hosted, NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Break in the debugger, if one is attached. Otherwise this is a no-op.
+ *
+ * The [`Debugger` API][1] offers a way to hook into this instruction.
+ *
+ * Implements: [Evaluation for *DebuggerStatement*][2].
+ *
+ * [1]: https://developer.mozilla.org/en-US/docs/Tools/Debugger-API/Debugger
+ * [2]: https://tc39.es/ecma262/#sec-debugger-statement-runtime-semantics-evaluation
+ *
+ * Category: Other
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(Debugger, debugger, NULL, 1, 0, 0, JOF_BYTE)
+
+// clang-format on
+
+/*
+ * In certain circumstances it may be useful to "pad out" the opcode space to
+ * a power of two. Use this macro to do so.
+ */
+#define FOR_EACH_TRAILING_UNUSED_OPCODE(MACRO) \
+ IF_RECORD_TUPLE(/* empty */, MACRO(230)) \
+ IF_RECORD_TUPLE(/* empty */, MACRO(231)) \
+ IF_RECORD_TUPLE(/* empty */, MACRO(232)) \
+ IF_RECORD_TUPLE(/* empty */, MACRO(233)) \
+ IF_RECORD_TUPLE(/* empty */, MACRO(234)) \
+ IF_RECORD_TUPLE(/* empty */, MACRO(235)) \
+ IF_RECORD_TUPLE(/* empty */, MACRO(236)) \
+ MACRO(237) \
+ MACRO(238) \
+ MACRO(239) \
+ MACRO(240) \
+ MACRO(241) \
+ MACRO(242) \
+ MACRO(243) \
+ MACRO(244) \
+ MACRO(245) \
+ MACRO(246) \
+ MACRO(247) \
+ MACRO(248) \
+ MACRO(249) \
+ MACRO(250) \
+ MACRO(251) \
+ MACRO(252) \
+ MACRO(253) \
+ MACRO(254) \
+ MACRO(255)
+
+namespace js {
+
+// Sanity check that opcode values and trailing unused opcodes completely cover
+// the [0, 256) range. Avert your eyes! You don't want to know how the
+// sausage gets made.
+
+// clang-format off
+#define PLUS_ONE(...) \
+ + 1
+constexpr int JSOP_LIMIT = 0 FOR_EACH_OPCODE(PLUS_ONE);
+#undef PLUS_ONE
+
+#define TRAILING_VALUE_AND_VALUE_PLUS_ONE(val) \
+ val) && (val + 1 ==
+static_assert((JSOP_LIMIT ==
+ FOR_EACH_TRAILING_UNUSED_OPCODE(TRAILING_VALUE_AND_VALUE_PLUS_ONE)
+ 256),
+ "trailing unused opcode values monotonically increase "
+ "from JSOP_LIMIT to 255");
+#undef TRAILING_VALUE_AND_VALUE_PLUS_ONE
+// clang-format on
+
+// Define JSOpLength_* constants for all ops.
+#define DEFINE_LENGTH_CONSTANT(op, op_snake, image, len, ...) \
+ constexpr size_t JSOpLength_##op = len;
+FOR_EACH_OPCODE(DEFINE_LENGTH_CONSTANT)
+#undef DEFINE_LENGTH_CONSTANT
+
+} // namespace js
+
+/*
+ * JS operation bytecodes.
+ */
+enum class JSOp : uint8_t {
+#define ENUMERATE_OPCODE(op, ...) op,
+ FOR_EACH_OPCODE(ENUMERATE_OPCODE)
+#undef ENUMERATE_OPCODE
+};
+
+#endif // vm_Opcodes_h