Skip to content

Instantly share code, notes, and snippets.

@jorendorff
Last active December 16, 2019 14:48
Show Gist options
  • Save jorendorff/48ad16a5240187d72f6bc77d556fe522 to your computer and use it in GitHub Desktop.
Save jorendorff/48ad16a5240187d72f6bc77d556fe522 to your computer and use it in GitHub Desktop.
diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -10,38 +10,199 @@
#include "mozilla/Attributes.h"
#include <stddef.h>
/*
* [SMDOC] Bytecode Definitions
*
- * JavaScript operation bytecodes. Add a new bytecode by claiming one of the
- * JSOP_UNUSED* here or by extracting the first unused opcode from
- * FOR_EACH_TRAILING_UNUSED_OPCODE.
+ * JavaScript operation bytecodes.
+ *
+ * To use this header, define a macro of the form:
*
- * Includers must define a macro with the following form:
+ * #define MACRO(op, name, token, length, nuses, ndefs, format) ...
*
- * #define MACRO(op, val, name, token, length, nuses, ndefs, format) ...
- *
- * Then simply use FOR_EACH_OPCODE(MACRO) to invoke MACRO for every opcode.
- * Selected arguments can be expanded in initializers.
+ * Then `FOR_EACH_OPCODE(MACRO)` invokes `MACRO` for every opcode.
*
* Field Description
* ----- -----------
* op Bytecode name, which is the JSOp enumerator name
- * value Bytecode value, which is the JSOp enumerator value
* name C string containing name for disassembler
* 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, -1 if variadic
- * format Bytecode plus immediate operand encoding format
+ * 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 sequence of valid instructions
+ * from start to end.
+ *
+ * ## Jump instructions
+ *
+ * Operands named `offset` are jump offsets, the distance in bytes from the
+ * start of the current instruction to the start of another instruction in the
+ * same script. Forward jumps must jump to a JUMPTARGET instruction. Backward
+ * jumps, indicated by negative offsets, must jump to a 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` instruction
+ * immediately after it. (Typically no instructions jump to that `JUMPTARGET`,
+ * but the VM puts us there on exception.)
+ *
+ * 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 ndefs 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()`.
+ *
+ * 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_INDEX`) 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*`
+ * - `scopeIndex` (`JOF_SCOPE`): `Scope*`
+ * - `lexicalScopeIndex` (`JOF_SCOPE`): `LexicalScope*`
+ * - `withScopeIndex` (`JOF_SCOPE`): `WithScope*`
+ * - `bigIntIndex` (`JOF_BIGINT`): `BigInt*`
+ *
+ * Operands named `icIndex` (`JOF_INDEX`) 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, unless X is
+ * `JSOP_GOTO`, `RETURN`, `RETRVAL`, `THROW`, or `RETSUB`; one or more
+ * `JUMPTARGET`s elsewhere, if X is a forward jump or `TABLESWITCH`; and/or
+ * a `LOOPHEAD` if it's a backward jump.
+ *
+ * Intuitively, successors are the instructions that might run next, on
+ * success; except the successors relation is deliberately "stupid"--an
+ * IFEQ instruction has two successors even if you can tell by looking
+ * at the code that one branch is never taken. It's defined this way
+ * because bytecode consumers shouldn't have to be smart enough to
+ * figure that out.
+ *
+ * - `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.
+ *
+ * - See `JSOP_GOSUB` for another special case.
+ *
+ * - 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 the instructions 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
+ *
+ * Instructions with the `JOF_CHECKSLOPPY` flag must not be used in strict mode
+ * code. `JOF_CHECKSTRICT` instructions must not be used in nonstrict code.
+ *
+ * We intend to add this rule: All reachable code is reachable without taking
+ * any backward edges. Bug 1601072 is the only known exception to this rule.
+ *
+ * Many instructions have their own additional rules. These are documented on
+ * the various opcodes below (look for the word "must").
*/
// clang-format off
/*
* SpiderMonkey bytecode categorization (as used in generated documentation):
*
* [Index]
* [Statements]
@@ -82,1020 +243,1431 @@
* Class
* [Other]
*/
// clang-format on
// clang-format off
#define FOR_EACH_OPCODE(MACRO) \
/*
- * No operation is performed.
- *
- * Category: Other
- * Operands:
- * Stack: =>
- */ \
- MACRO(JSOP_NOP, 0, "nop", NULL, 1, 0, 0, JOF_BYTE) \
- /*
- * Pushes 'undefined' onto the stack.
+ * Push `undefined`.
*
* Category: Literals
* Type: Constants
* Operands:
* Stack: => undefined
*/ \
- MACRO(JSOP_UNDEFINED, 1, js_undefined_str, "", 1, 0, 1, JOF_BYTE) \
+ MACRO(JSOP_UNDEFINED, js_undefined_str, "", 1, 0, 1, JOF_BYTE) \
+ /*
+ * Push `null`.
+ *
+ * Category: Literals
+ * Type: Constants
+ * Operands:
+ * Stack: => null
+ */ \
+ MACRO(JSOP_NULL, js_null_str, js_null_str, 1, 0, 1, JOF_BYTE) \
/*
- * Pushes stack frame's 'rval' onto the stack.
- *
- * Category: Statements
- * Type: Function
+ * Push a boolean constant.
+ *
+ * Category: Literals
+ * Type: Constants
* Operands:
- * Stack: => rval
+ * Stack: => true/false
*/ \
- MACRO(JSOP_GETRVAL, 2, "getrval", NULL, 1, 0, 1, JOF_BYTE) \
+ MACRO(JSOP_FALSE, js_false_str, js_false_str, 1, 0, 1, JOF_BYTE) \
+ MACRO(JSOP_TRUE, js_true_str, js_true_str, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Push the number `0`.
+ *
+ * Category: Literals
+ * Type: Constants
+ * Operands:
+ * Stack: => 0
+ */ \
+ MACRO(JSOP_ZERO, "zero", "0", 1, 0, 1, JOF_BYTE) \
/*
- * Pops the top of stack value, converts it to an object, and adds a
- * 'WithEnvironmentObject' wrapping that object to the environment chain.
- *
- * There is a matching JSOP_LEAVEWITH instruction later. All name
- * lookups between the two that may need to consult the With object
- * are deoptimized.
- *
- * Category: Statements
- * Type: With Statement
- * Operands: uint32_t staticWithIndex
- * Stack: val =>
+ * Push the number `1`.
+ *
+ * Category: Literals
+ * Type: Constants
+ * Operands:
+ * Stack: => 1
*/ \
- MACRO(JSOP_ENTERWITH, 3, "enterwith", NULL, 5, 1, 0, JOF_SCOPE) \
+ MACRO(JSOP_ONE, "one", "1", 1, 0, 1, JOF_BYTE) \
/*
- * Pops the environment chain object pushed by JSOP_ENTERWITH.
- *
- * Category: Statements
- * Type: With Statement
- * Operands:
- * Stack: =>
+ * Push the `int8_t` immediate operand as an `Int32Value`.
+ *
+ * `JSOP_ZERO`, `ONE`, `INT8`, `UINT16`, and `UINT24` are all shorthand for
+ * `JSOP_INT32`.
+ *
+ * Category: Literals
+ * Type: Constants
+ * Operands: int8_t val
+ * Stack: => val
*/ \
- MACRO(JSOP_LEAVEWITH, 4, "leavewith", NULL, 1, 0, 0, JOF_BYTE) \
+ MACRO(JSOP_INT8, "int8", NULL, 2, 0, 1, JOF_INT8) \
/*
- * Pops the top of stack value as 'rval', stops interpretation of current
- * script and returns 'rval'.
- *
- * Category: Statements
- * Type: Function
- * Operands:
- * Stack: rval =>
+ * Push the `uint16_t` immediate operand as an `Int32Value`.
+ *
+ * Category: Literals
+ * Type: Constants
+ * Operands: uint16_t val
+ * Stack: => val
*/ \
- MACRO(JSOP_RETURN, 5, "return", NULL, 1, 1, 0, JOF_BYTE) \
+ MACRO(JSOP_UINT16, "uint16", NULL, 3, 0, 1, JOF_UINT16) \
/*
- * Jumps to a 32-bit offset from the current bytecode.
- *
- * Category: Statements
- * Type: Jumps
- * Operands: int32_t offset
- * Stack: =>
+ * Push the `uint24_t` immediate operand as an `Int32Value`.
+ *
+ * Category: Literals
+ * Type: Constants
+ * Operands: uint24_t val
+ * Stack: => val
*/ \
- MACRO(JSOP_GOTO, 6, "goto", NULL, 5, 0, 0, JOF_JUMP) \
+ MACRO(JSOP_UINT24, "uint24", NULL, 4, 0, 1, JOF_UINT24) \
/*
- * Pops the top of stack value, converts it into a boolean, if the result
- * is 'false', jumps to a 32-bit offset from the current bytecode.
- *
- * The idea is that a sequence like
- * JSOP_ZERO; JSOP_ZERO; JSOP_EQ; JSOP_IFEQ; JSOP_RETURN;
- * reads like a nice linear sequence that will execute the return.
- *
- * Category: Statements
- * Type: Jumps
- * Operands: int32_t offset
- * Stack: cond =>
+ * Push the `int32_t` immediate operand as an `Int32Value`.
+ *
+ * Category: Literals
+ * Type: Constants
+ * Operands: int32_t val
+ * Stack: => val
*/ \
- MACRO(JSOP_IFEQ, 7, "ifeq", NULL, 5, 1, 0, JOF_JUMP|JOF_DETECTING|JOF_IC) \
+ MACRO(JSOP_INT32, "int32", NULL, 5, 0, 1, JOF_INT32) \
+ /*
+ * 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: Literals
+ * Type: Constants
+ * Operands: double val
+ * Stack: => val
+ */ \
+ MACRO(JSOP_DOUBLE, "double", NULL, 9, 0, 1, JOF_DOUBLE) \
/*
- * Pops the top of stack value, converts it into a boolean, if the result
- * is 'true', jumps to a 32-bit offset from the current bytecode.
- *
- * Category: Statements
- * Type: Jumps
- * Operands: int32_t offset
- * Stack: cond =>
+ * Push a BigInt constant.
+ *
+ * Category: Literals
+ * Type: Constants
+ * Operands: uint32_t bigIntIndex
+ * Stack: => bigint
*/ \
- MACRO(JSOP_IFNE, 8, "ifne", NULL, 5, 1, 0, JOF_JUMP|JOF_IC) \
+ MACRO(JSOP_BIGINT, "bigint", NULL, 5, 0, 1, JOF_BIGINT) \
/*
- * Pushes the 'arguments' object for the current function activation.
- *
- * If 'JSScript' is not marked 'needsArgsObj', then a
- * JS_OPTIMIZED_ARGUMENTS magic value is pushed. Otherwise, a proper
- * arguments object is constructed and pushed.
- *
- * This opcode requires that the function does not have rest parameter.
- *
- * Category: Variables and Scopes
- * Type: Arguments
- * Operands:
- * Stack: => arguments
+ * Push the string constant `script->getAtom(atomIndex)`.
+ *
+ * Category: Literals
+ * Type: Constants
+ * Operands: uint32_t atomIndex
+ * Stack: => string
*/ \
- MACRO(JSOP_ARGUMENTS, 9, "arguments", NULL, 1, 0, 1, JOF_BYTE) \
+ MACRO(JSOP_STRING, "string", NULL, 5, 0, 1, JOF_ATOM) \
/*
- * Swaps the top two values on the stack. This is useful for things like
- * post-increment/decrement.
+ * Push a well-known symbol.
+ *
+ * `symbol` must be in range for `JS::SymbolCode`.
+ *
+ * Category: Literals
+ * Type: Constants
+ * Operands: uint8_t symbol (the JS::SymbolCode of the symbol to use)
+ * Stack: => symbol
+ */ \
+ MACRO(JSOP_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: Operators
- * Type: Stack Operations
+ * Type: Special Operators
* Operands:
- * Stack: v1, v2 => v2, v1
+ * Stack: val => undefined
*/ \
- MACRO(JSOP_SWAP, 10, "swap", NULL, 1, 2, 2, JOF_BYTE) \
+ MACRO(JSOP_VOID, js_void_str, NULL, 1, 1, 1, JOF_BYTE) \
/*
- * Pops the top 'n' values from the stack.
+ * [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: Operators
- * Type: Stack Operations
- * Operands: uint16_t n
- * Stack: v[n-1], ..., v[1], v[0] =>
- * nuses: n
+ * Type: Special Operators
+ * Operands:
+ * Stack: val => (typeof val)
*/ \
- MACRO(JSOP_POPN, 11, "popn", NULL, 3, -1, 0, JOF_UINT16) \
+ MACRO(JSOP_TYPEOF, js_typeof_str, NULL, 1, 1, 1, JOF_BYTE|JOF_DETECTING|JOF_IC) \
+ MACRO(JSOP_TYPEOFEXPR, "typeofexpr", NULL, 1, 1, 1, JOF_BYTE|JOF_DETECTING|JOF_IC) \
/*
- * Pushes a copy of the top value on the stack.
+ * [The unary `+` operator][1].
+ *
+ * `+val` doesn't do much. It just calls [ToNumber][2](val).
+ *
+ * The conversion can call `.toString()`/`.valueOf()` methods and can
+ * throw. The result on success is always a Number.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-unary-plus-operator
+ * [2]: https://tc39.es/ecma262/#sec-tonumber
*
* Category: Operators
- * Type: Stack Operations
+ * Type: Arithmetic Operators
* Operands:
- * Stack: v => v, v
+ * Stack: val => (+val)
*/ \
- MACRO(JSOP_DUP, 12, "dup", NULL, 1, 1, 2, JOF_BYTE) \
+ MACRO(JSOP_POS, "pos", "+ ", 1, 1, 1, JOF_BYTE) \
/*
- * Duplicates the top two values on the stack.
+ * [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: Operators
+ * Type: Arithmetic Operators
+ * Operands:
+ * Stack: val => (-val)
+ */ \
+ MACRO(JSOP_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: Operators
- * Type: Stack Operations
+ * Type: Bitwise Logical Operators
* Operands:
- * Stack: v1, v2 => v1, v2, v1, v2
+ * Stack: val => (~val)
*/ \
- MACRO(JSOP_DUP2, 13, "dup2", NULL, 1, 2, 4, JOF_BYTE) \
+ MACRO(JSOP_BITNOT, "bitnot", "~", 1, 1, 1, JOF_BYTE|JOF_IC) \
/*
- * Checks that the top value on the stack is an object, and throws a
- * TypeError if not. The operand 'kind' is used only to generate an
- * appropriate error message.
- *
- * Category: Statements
- * Type: Generator
- * Operands: uint8_t kind
- * Stack: result => result
+ * [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: Operators
+ * Type: Logical Operators
+ * Operands:
+ * Stack: val => (!val)
*/ \
- MACRO(JSOP_CHECKISOBJ, 14, "checkisobj", NULL, 2, 1, 1, JOF_UINT8) \
+ MACRO(JSOP_NOT, "not", "!", 1, 1, 1, JOF_BYTE|JOF_DETECTING|JOF_IC) \
/*
- * Pops the top two values 'lval' and 'rval' from the stack, then pushes
- * the result of the operation applied to the two operands, converting both
- * to 32-bit signed integers if necessary.
+ * [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: Operators
* Type: Bitwise Logical Operators
* Operands:
* Stack: lval, rval => (lval OP rval)
*/ \
- MACRO(JSOP_BITOR, 15, "bitor", "|", 1, 2, 1, JOF_BYTE|JOF_IC) \
- MACRO(JSOP_BITXOR, 16, "bitxor", "^", 1, 2, 1, JOF_BYTE|JOF_IC) \
- MACRO(JSOP_BITAND, 17, "bitand", "&", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(JSOP_BITOR, "bitor", "|", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(JSOP_BITXOR, "bitxor", "^", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(JSOP_BITAND, "bitand", "&", 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: Operators
+ * Type: Comparison Operators
+ * Operands:
+ * Stack: lval, rval => (lval OP rval)
+ */ \
+ MACRO(JSOP_EQ, "eq", "==", 1, 2, 1, JOF_BYTE|JOF_DETECTING|JOF_IC) \
+ MACRO(JSOP_NE, "ne", "!=", 1, 2, 1, JOF_BYTE|JOF_DETECTING|JOF_IC) \
/*
- * Pops the top two values from the stack and pushes the result of
- * comparing them.
+ * 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: Operators
+ * Type: Comparison Operators
+ * Operands:
+ * Stack: lval, rval => (lval OP rval)
+ */ \
+ MACRO(JSOP_STRICTEQ, "stricteq", "===", 1, 2, 1, JOF_BYTE|JOF_DETECTING|JOF_IC) \
+ MACRO(JSOP_STRICTNE, "strictne", "!==", 1, 2, 1, JOF_BYTE|JOF_DETECTING|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: Operators
* Type: Comparison Operators
* Operands:
* Stack: lval, rval => (lval OP rval)
*/ \
- MACRO(JSOP_EQ, 18, "eq", "==", 1, 2, 1, JOF_BYTE|JOF_DETECTING|JOF_IC) \
- MACRO(JSOP_NE, 19, "ne", "!=", 1, 2, 1, JOF_BYTE|JOF_DETECTING|JOF_IC) \
- MACRO(JSOP_LT, 20, "lt", "<", 1, 2, 1, JOF_BYTE|JOF_IC) \
- MACRO(JSOP_LE, 21, "le", "<=", 1, 2, 1, JOF_BYTE|JOF_IC) \
- MACRO(JSOP_GT, 22, "gt", ">", 1, 2, 1, JOF_BYTE|JOF_IC) \
- MACRO(JSOP_GE, 23, "ge", ">=", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(JSOP_LT, "lt", "<", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(JSOP_GT, "gt", ">", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(JSOP_LE, "le", "<=", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(JSOP_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: Operators
+ * Type: Special Operators
+ * Operands:
+ * Stack: value, target => (value instanceof target)
+ */ \
+ MACRO(JSOP_INSTANCEOF, js_instanceof_str, js_instanceof_str, 1, 2, 1, JOF_BYTE|JOF_IC) \
/*
- * Pops the top two values 'lval' and 'rval' from the stack, then pushes
- * the result of the operation applied to the operands.
+ * [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: Operators
+ * Type: Special Operators
+ * Operands:
+ * Stack: id, obj => (id in obj)
+ */ \
+ MACRO(JSOP_IN, js_in_str, js_in_str, 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: Operators
* Type: Bitwise Shift Operators
* Operands:
* Stack: lval, rval => (lval OP rval)
*/ \
- MACRO(JSOP_LSH, 24, "lsh", "<<", 1, 2, 1, JOF_BYTE|JOF_IC) \
- MACRO(JSOP_RSH, 25, "rsh", ">>", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(JSOP_LSH, "lsh", "<<", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(JSOP_RSH, "rsh", ">>", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(JSOP_URSH, "ursh", ">>>", 1, 2, 1, JOF_BYTE|JOF_IC) \
/*
- * Pops the top two values 'lval' and 'rval' from the stack, then pushes
- * 'lval >>> rval'.
- *
- * Category: Operators
- * Type: Bitwise Shift Operators
- * Operands:
- * Stack: lval, rval => (lval >>> rval)
- */ \
- MACRO(JSOP_URSH, 26, "ursh", ">>>", 1, 2, 1, JOF_BYTE|JOF_IC) \
- /*
- * Pops the top two values 'lval' and 'rval' from the stack, then pushes
- * the result of 'lval + rval'.
+ * [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: Operators
* Type: Arithmetic Operators
* Operands:
* Stack: lval, rval => (lval + rval)
*/ \
- MACRO(JSOP_ADD, 27, "add", "+", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(JSOP_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: Operators
+ * Type: Arithmetic Operators
+ * Operands:
+ * Stack: lval, rval => (lval - rval)
+ */ \
+ MACRO(JSOP_SUB, "sub", "-", 1, 2, 1, JOF_BYTE|JOF_IC) \
/*
- * Pops the top two values 'lval' and 'rval' from the stack, then pushes
- * the result of applying the arithmetic operation to them.
+ * 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: Operators
+ * Type: Arithmetic Operators
+ * Operands:
+ * Stack: val => (val +/- 1)
+ */ \
+ MACRO(JSOP_INC, "inc", NULL, 1, 1, 1, JOF_BYTE|JOF_IC) \
+ MACRO(JSOP_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: Operators
* Type: Arithmetic Operators
* Operands:
* Stack: lval, rval => (lval OP rval)
*/ \
- MACRO(JSOP_SUB, 28, "sub", "-", 1, 2, 1, JOF_BYTE|JOF_IC) \
- MACRO(JSOP_MUL, 29, "mul", "*", 1, 2, 1, JOF_BYTE|JOF_IC) \
- MACRO(JSOP_DIV, 30, "div", "/", 1, 2, 1, JOF_BYTE|JOF_IC) \
- MACRO(JSOP_MOD, 31, "mod", "%", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(JSOP_MUL, "mul", "*", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(JSOP_DIV, "div", "/", 1, 2, 1, JOF_BYTE|JOF_IC) \
+ MACRO(JSOP_MOD, "mod", "%", 1, 2, 1, JOF_BYTE|JOF_IC) \
/*
- * Pops the value 'val' from the stack, then pushes '!val'.
+ * [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: Operators
- * Type: Logical Operators
+ * Type: Arithmetic Operators
* Operands:
- * Stack: val => (!val)
+ * Stack: lval, rval => (lval ** rval)
*/ \
- MACRO(JSOP_NOT, 32, "not", "!", 1, 1, 1, JOF_BYTE|JOF_DETECTING|JOF_IC) \
+ MACRO(JSOP_POW, "pow", "**", 1, 2, 1, JOF_BYTE|JOF_IC) \
/*
- * Pops the value 'val' from the stack, then pushes '~val'.
- *
- * Category: Operators
- * Type: Bitwise Logical Operators
+ * 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: Literals
+ * Type: Object
* Operands:
- * Stack: val => (~val)
+ * Stack: propertyNameValue => propertyKey
*/ \
- MACRO(JSOP_BITNOT, 33, "bitnot", "~", 1, 1, 1, JOF_BYTE|JOF_IC) \
+ MACRO(JSOP_TOID, "toid", NULL, 1, 1, 1, JOF_BYTE) \
/*
- * Pops the value 'val' from the stack, then pushes '-val'.
+ * 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: Operators
* Type: Arithmetic Operators
* Operands:
- * Stack: val => (-val)
+ * Stack: val => ToNumeric(val)
*/ \
- MACRO(JSOP_NEG, 34, "neg", "- ", 1, 1, 1, JOF_BYTE|JOF_IC) \
+ MACRO(JSOP_TONUMERIC, "tonumeric", NULL, 1, 1, 1, JOF_BYTE) \
/*
- * Pops the value 'val' from the stack, then pushes '+val'.
- * ('+val' is the value converted to a number.)
- *
- * Category: Operators
- * Type: Arithmetic Operators
+ * 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: Other
+ * Operands:
+ * Stack: val => ToString(val)
+ */ \
+ MACRO(JSOP_TOSTRING, "tostring", NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Push the global `this` value.
+ *
+ * This must be used only in scopes where `this` refers to the global
+ * `this`.
+ *
+ * Category: Variables and Scopes
+ * Type: This
* Operands:
- * Stack: val => (+val)
+ * Stack: => this
*/ \
- MACRO(JSOP_POS, 35, "pos", "+ ", 1, 1, 1, JOF_BYTE) \
+ MACRO(JSOP_GLOBALTHIS, "globalthis", NULL, 1, 0, 1, JOF_BYTE) \
/*
- * Looks up name on the environment chain and deletes it, pushes 'true'
- * onto the stack if succeeded (if the property was present and deleted or
- * if the property wasn't present in the first place), 'false' if not.
- *
- * Strict mode code should never contain this opcode.
+ * Push the value of `new.target`.
+ *
+ * The result is a constructor or `undefined`.
+ *
+ * This must be used only in scripts where `new.target` is allowed:
+ * non-arrow function scripts and other scripts that have a non-arrow
+ * function script on the scope chain.
+ *
+ * Implements: [GetNewTarget][1].
+ *
+ * [1]: https://tc39.es/ecma262/#sec-getnewtarget
+ *
+ * Category: Variables and Scopes
+ * Type: Arguments
+ * Operands:
+ * Stack: => new.target
+ */ \
+ MACRO(JSOP_NEWTARGET, "newtarget", 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: Variables and Scopes
+ * Type: Modules
+ * Operands:
+ * Stack: moduleId => promise
+ */ \
+ MACRO(JSOP_DYNAMIC_IMPORT, "dynamic-import", NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Push the `import.meta` object.
+ *
+ * This must be used only in module code.
*
* Category: Variables and Scopes
- * Type: Variables
+ * Type: Modules
+ * Operands:
+ * Stack: => import.meta
+ */ \
+ MACRO(JSOP_IMPORTMETA, "importmeta", NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Create and push a new object with no properties.
+ *
+ * (This opcode has 4 unused bytes so it can be easily turned into
+ * `JSOP_NEWOBJECT` during emit.)
+ *
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t _unused
+ * Stack: => obj
+ */ \
+ MACRO(JSOP_NEWINIT, "newinit", NULL, 5, 0, 1, JOF_UINT32|JOF_IC) \
+ /*
+ * Create and push a new object of a predetermined shape.
+ *
+ * The new object has the shape of the template object
+ * `script->getObject(baseobjIndex)`. Subsequent `INITPROP` instructions
+ * must fill in all slots of the new object before it is used in any other
+ * way.
+ *
+ * For `JSOP_NEWOBJECT`, the new object has a group based on the allocation
+ * site (or a new group if the template's group is a singleton). For
+ * `JSOP_NEWOBJECT_WITHGROUP`, the new object has the same group as the
+ * template object.
+ *
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t baseobjIndex
+ * Stack: => obj
+ */ \
+ MACRO(JSOP_NEWOBJECT, "newobject", NULL, 5, 0, 1, JOF_OBJECT|JOF_IC) \
+ MACRO(JSOP_NEWOBJECT_WITHGROUP, "newobjectwithgroup", NULL, 5, 0, 1, JOF_OBJECT|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.
+ *
+ * There's a shell-only option, `newGlobal({cloneSingletons: true})`, that
+ * makes this instruction do a deep copy of the object. A few tests use it.
+ *
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t objectIndex
+ * Stack: => obj
+ */ \
+ MACRO(JSOP_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: Literals
+ * Type: Object
+ * Operands:
+ * Stack: proto => obj
+ */ \
+ MACRO(JSOP_OBJWITHPROTO, "objwithproto", 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: Literals
+ * Type: Object
* Operands: uint32_t nameIndex
- * Stack: => succeeded
+ * Stack: obj, val => obj
+ */ \
+ MACRO(JSOP_INITPROP, "initprop", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT|JOF_DETECTING|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: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj, val => obj
+ */ \
+ MACRO(JSOP_INITHIDDENPROP, "inithiddenprop", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT|JOF_DETECTING|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: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj, val => obj
+ */ \
+ MACRO(JSOP_INITLOCKEDPROP, "initlockedprop", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT|JOF_DETECTING|JOF_IC) \
+ /*
+ * Define a data property on `obj` with property key `id` and value `val`.
+ *
+ * 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.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-createdatapropertyorthrow
+ *
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, id, val => obj
+ */ \
+ MACRO(JSOP_INITELEM, "initelem", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_DETECTING|JOF_IC) \
+ MACRO(JSOP_INITHIDDENELEM, "inithiddenelem", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_DETECTING|JOF_IC) \
+ /*
+ * Define an accessor property on `obj` with the given `getter`.
+ * `nameIndex` gives the property name.
+ *
+ * `JSOP_INITHIDDENPROP_GETTER` is the same but defines a non-enumerable
+ * property, for getters in classes.
+ *
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj, getter => obj
*/ \
- MACRO(JSOP_DELNAME, 36, "delname", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_CHECKSLOPPY) \
+ MACRO(JSOP_INITPROP_GETTER, "initprop_getter", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT|JOF_DETECTING) \
+ MACRO(JSOP_INITHIDDENPROP_GETTER, "inithiddenprop_getter", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT|JOF_DETECTING) \
+ /*
+ * 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() {}`.
+ *
+ * `JSOP_INITHIDDENELEM_GETTER` is the same but defines a non-enumerable
+ * property, for getters in classes.
+ *
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, id, getter => obj
+ */ \
+ MACRO(JSOP_INITELEM_GETTER, "initelem_getter", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_DETECTING) \
+ MACRO(JSOP_INITHIDDENELEM_GETTER, "inithiddenelem_getter", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_DETECTING) \
+ /*
+ * Define an accessor property on `obj` with the given `setter`.
+ *
+ * This is used to implement ordinary setters like `set foo(v) {}`.
+ *
+ * `JSOP_INITHIDDENPROP_SETTER` is the same but defines a non-enumerable
+ * property, for setters in classes.
+ *
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj, setter => obj
+ */ \
+ MACRO(JSOP_INITPROP_SETTER, "initprop_setter", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT|JOF_DETECTING) \
+ MACRO(JSOP_INITHIDDENPROP_SETTER, "inithiddenprop_setter", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT|JOF_DETECTING) \
+ /*
+ * 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_INITHIDDENELEM_SETTER` is the same but defines a non-enumerable
+ * property, for setters in classes.
+ *
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, id, setter => obj
+ */ \
+ MACRO(JSOP_INITELEM_SETTER, "initelem_setter", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_DETECTING) \
+ MACRO(JSOP_INITHIDDENELEM_SETTER, "inithiddenelem_setter", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_DETECTING) \
+ /*
+ * 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: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj => obj[name]
+ */ \
+ MACRO(JSOP_GETPROP, "getprop", NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_TYPESET|JOF_IC) \
/*
- * Pops the top of stack value, deletes property from it, pushes 'true'
- * onto the stack if succeeded, 'false' if not.
+ * 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: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, propval => obj[propval]
+ */ \
+ MACRO(JSOP_GETELEM, "getelem", NULL, 1, 2, 1, JOF_BYTE|JOF_ELEM|JOF_TYPESET|JOF_IC) \
+ /*
+ * Push the value of `obj.length`.
+ *
+ * `nameIndex` must be the index of the atom `"length"`. This then behaves
+ * exactly like `JSOP_GETPROP`.
+ *
+ * Category: Literals
+ * Type: Array
+ * Operands: uint32_t nameIndex
+ * Stack: obj => obj.length
+ */ \
+ MACRO(JSOP_LENGTH, "length", NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_TYPESET|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: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj, val => val
+ */ \
+ MACRO(JSOP_SETPROP, "setprop", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPSET|JOF_DETECTING|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: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj, val => val
+ */ \
+ MACRO(JSOP_STRICTSETPROP, "strict-setprop", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPSET|JOF_DETECTING|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: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, key, val => val
+ */ \
+ MACRO(JSOP_SETELEM, "setelem", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPSET|JOF_DETECTING|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: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, propval, val => val
+ */ \
+ MACRO(JSOP_STRICTSETELEM, "strict-setelem", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSTRICT|JOF_IC) \
+ /*
+ * Delete a property from `obj`. Push true on success, false if the
+ * property was non-configurable. 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: Operators
* Type: Special Operators
* Operands: uint32_t nameIndex
* Stack: obj => succeeded
*/ \
- MACRO(JSOP_DELPROP, 37, "delprop", NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_CHECKSLOPPY) \
+ MACRO(JSOP_DELPROP, "delprop", NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_CHECKSLOPPY) \
/*
- * Pops the top two values on the stack as 'propval' and 'obj', deletes
- * 'propval' property from 'obj', pushes 'true' onto the stack if
- * succeeded, 'false' if not.
+ * Like `JSOP_DELPROP`, but for strict mode code. Push `true` on success,
+ * else throw a TypeError.
+ *
+ * Category: Operators
+ * Type: Special Operators
+ * Operands: uint32_t nameIndex
+ * Stack: obj => succeeded
+ */ \
+ MACRO(JSOP_STRICTDELPROP, "strict-delprop", NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_CHECKSTRICT) \
+ /*
+ * Delete the property `obj[propval]` and push `true` on success, `false`
+ * if the property was non-configurable.
+ *
+ * Throws if `obj` is null or undefined. Can call proxy traps.
+ *
+ * In strict mode code, use `JSOP_STRICTDELELEM` instead.
+ *
+ * Implements: [`delete obj[propval]`][1] step 5 in non-strict code.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-delete-operator-runtime-semantics-evaluation
*
* Category: Operators
* Type: Special Operators
* Operands:
* Stack: obj, propval => succeeded
*/ \
- MACRO(JSOP_DELELEM, 38, "delelem", NULL, 1, 2, 1, JOF_BYTE|JOF_ELEM|JOF_CHECKSLOPPY) \
- /*
- * Pops the value 'val' from the stack, then pushes 'typeof val'.
- *
- * Category: Operators
- * Type: Special Operators
- * Operands:
- * Stack: val => (typeof val)
- */ \
- MACRO(JSOP_TYPEOF, 39, js_typeof_str, NULL, 1, 1, 1, JOF_BYTE|JOF_DETECTING|JOF_IC) \
- /*
- * Pops the top value on the stack and pushes 'undefined'.
- *
- * Category: Operators
- * Type: Special Operators
- * Operands:
- * Stack: val => undefined
- */ \
- MACRO(JSOP_VOID, 40, js_void_str, NULL, 1, 1, 1, JOF_BYTE) \
- /*
- * spreadcall variant of JSOP_CALL.
- *
- * Invokes 'callee' with 'this' and 'args', pushes the return value onto
- * the stack.
- *
- * 'args' is an Array object which contains actual arguments.
- *
- * Category: Statements
- * Type: Function
- * Operands:
- * Stack: callee, this, args => rval
- */ \
- MACRO(JSOP_SPREADCALL, 41, "spreadcall", NULL, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET|JOF_IC) \
- /*
- * spreadcall variant of JSOP_NEW
- *
- * Invokes 'callee' as a constructor with 'this' and 'args', pushes the
- * return value onto the stack.
- *
- * Category: Statements
- * Type: Function
- * Operands:
- * Stack: callee, this, args, newTarget => rval
- */ \
- MACRO(JSOP_SPREADNEW, 42, "spreadnew", NULL, 1, 4, 1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET|JOF_IC) \
+ MACRO(JSOP_DELELEM, "delelem", NULL, 1, 2, 1, JOF_BYTE|JOF_ELEM|JOF_CHECKSLOPPY) \
/*
- * spreadcall variant of JSOP_EVAL
- *
- * Invokes 'eval' with 'args' and pushes the return value onto the stack.
- *
- * If 'eval' in global scope is not original one, invokes the function with
- * 'this' and 'args', and pushes return value onto the stack.
- *
- * Category: Statements
- * Type: Function
- * Operands:
- * Stack: callee, this, args => rval
- */ \
- MACRO(JSOP_SPREADEVAL, 43, "spreadeval", NULL, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET|JOF_CHECKSLOPPY|JOF_IC) \
- /*
- * Duplicates the Nth value from the top onto the stack.
- *
- * Category: Operators
- * Type: 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(JSOP_DUPAT, 44, "dupat", NULL, 4, 0, 1, JOF_UINT24) \
- /*
- * Push a well-known symbol onto the operand stack.
- *
- * Category: Literals
- * Type: Constants
- * Operands: uint8_t symbol (the JS::SymbolCode of the symbol to use)
- * Stack: => symbol
- */ \
- MACRO(JSOP_SYMBOL, 45, "symbol", NULL, 2, 0, 1, JOF_UINT8) \
- /*
- * Pops the top of stack value and attempts to delete the given property
- * from it. Pushes 'true' onto success, else throws a TypeError per strict
- * mode property-deletion requirements.
- *
- * Category: Operators
- * Type: Special Operators
- * Operands: uint32_t nameIndex
- * Stack: obj => succeeded
- */ \
- MACRO(JSOP_STRICTDELPROP, 46, "strict-delprop", NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_CHECKSTRICT) \
- /*
- * Pops the top two values on the stack as 'propval' and 'obj', and
- * attempts to delete 'propval' property from 'obj'. Pushes 'true' onto the
- * stack on success, else throws a TypeError per strict mode property
- * deletion requirements.
+ * Like `JSOP_DELELEM, but for strict mode code. Push `true` on success,
+ * else throw a TypeError.
*
* Category: Literals
* Type: Object
* Operands:
* Stack: obj, propval => succeeded
*/ \
- MACRO(JSOP_STRICTDELELEM, 47, "strict-delelem", NULL, 1, 2, 1, JOF_BYTE|JOF_ELEM|JOF_CHECKSTRICT) \
+ MACRO(JSOP_STRICTDELELEM, "strict-delelem", 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: Other
+ * Type:
+ * Operands:
+ * Stack: id, obj => (obj.hasOwnProperty(id))
+ */ \
+ MACRO(JSOP_HASOWN, "hasown", NULL, 1, 2, 1, JOF_BYTE|JOF_IC) \
+ /*
+ * Push the prototype of the home object for `callee` onto the
+ * stack.
+ *
+ * Category: Variables and Scopes
+ * Type: Super
+ * Operands:
+ * Stack: callee => homeObjectProto
+ */ \
+ MACRO(JSOP_SUPERBASE, "superbase", NULL, 1, 1, 1, JOF_BYTE) \
/*
- * Pops the top two values on the stack as 'val' and 'obj', and performs
- * 'obj.prop = val', pushing 'val' back onto the stack. Throws a TypeError
- * if the set-operation failed (per strict mode semantics).
+ * 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 prototype of this method's
+ * HomeObject.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-getvalue
+ * [2]: https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
+ *
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: receiver, obj => super.name
+ */ \
+ MACRO(JSOP_GETPROP_SUPER, "getprop-super", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_TYPESET|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].
+ * The `receiver` is `this` and `obj` is the prototype of this
+ * method's HomeObject.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-getvalue
+ * [2]: https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
+ *
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: receiver, key, obj => super[key]
+ */ \
+ MACRO(JSOP_GETELEM_SUPER, "getelem-super", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_TYPESET|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 prototype of
+ * this method's HomeObject.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-putvalue
+ * [2]: https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
+ *
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: receiver, obj, val => val
+ */ \
+ MACRO(JSOP_SETPROP_SUPER, "setprop-super", NULL, 5, 3, 1, JOF_ATOM|JOF_PROP|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSLOPPY) \
+ /*
+ * Like `JSOP_SETPROP_SUPER`, but for strict mode code.
*
* Category: Literals
* Type: Object
* Operands: uint32_t nameIndex
- * Stack: obj, val => val
+ * Stack: receiver, obj, val => val
+ */ \
+ MACRO(JSOP_STRICTSETPROP_SUPER, "strictsetprop-super", NULL, 5, 3, 1, JOF_ATOM|JOF_PROP|JOF_PROPSET|JOF_DETECTING|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 prototype of
+ * this method's HomeObject.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-putvalue
+ * [2]: https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
+ *
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: receiver, key, obj, val => val
+ */ \
+ MACRO(JSOP_SETELEM_SUPER, "setelem-super", NULL, 1, 4, 1, JOF_BYTE|JOF_ELEM|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSLOPPY) \
+ /*
+ * Like `JSOP_SETELEM_SUPER`, but for strict mode code.
+ *
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: receiver, propval, obj, val => val
*/ \
- MACRO(JSOP_STRICTSETPROP, 48, "strict-setprop", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSTRICT|JOF_IC) \
+ MACRO(JSOP_STRICTSETELEM_SUPER, "strict-setelem-super", NULL, 1, 4, 1, JOF_BYTE|JOF_ELEM|JOF_PROPSET|JOF_DETECTING|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: Statements
+ * Type: For-In Statement
+ * Operands:
+ * Stack: val => iter
+ */ \
+ MACRO(JSOP_ITER, "iter", NULL, 1, 1, 1, JOF_BYTE|JOF_IC) \
/*
- * Pops a environment and value from the stack, assigns value to the given
- * name, and pushes the value back on the stack. If the set failed, then
- * throw a TypeError, per usual strict mode semantics.
- *
- * Category: Variables and Scopes
- * Type: Variables
- * Operands: uint32_t nameIndex
- * Stack: env, val => val
+ * 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: Statements
+ * Type: For-In Statement
+ * Operands:
+ * Stack: iter => iter, name
+ */ \
+ MACRO(JSOP_MOREITER, "moreiter", 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: Statements
+ * Type: For-In Statement
+ * Operands:
+ * Stack: val => val, done
+ */ \
+ MACRO(JSOP_ISNOITER, "isnoiter", NULL, 1, 1, 2, JOF_BYTE) \
+ /*
+ * No-op instruction to hint to IonBuilder that the value on top of the
+ * stack is the (likely string) key in a for-in loop.
+ *
+ * Category: Other
+ * Operands:
+ * Stack: val => val
*/ \
- MACRO(JSOP_STRICTSETNAME, 49, "strict-setname", NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSTRICT|JOF_IC) \
+ MACRO(JSOP_ITERNEXT, "iternext", NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Exit a for-in loop, closing the iterator.
+ *
+ * `iter` must be a `PropertyIteratorObject` pushed by `JSOP_ITER`.
+ *
+ * Category: Statements
+ * Type: For-In Statement
+ * Operands:
+ * Stack: iter, iterval =>
+ */ \
+ MACRO(JSOP_ENDITER, "enditer", NULL, 1, 2, 0, JOF_BYTE) \
/*
- * spreadcall variant of JSOP_EVAL
- *
- * Invokes 'eval' with 'args' and pushes the return value onto the stack.
- *
- * If 'eval' in global scope is not original one, invokes the function with
- * 'this' and 'args', and pushes return value onto the stack.
+ * Like JSOP_CALL, but used for the implicit method calls to
+ * `iterable[Symbol.iterator]()` and `iterator.next()` in for-of loops,
+ * spread syntax, etc., to provide better error messages.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands: uint16_t argc (must be 0)
+ * Stack: callee, this => rval
+ * nuses: 2
+ */ \
+ MACRO(JSOP_CALLITER, "calliter", NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_TYPESET|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. It must be in range for `js::CheckIsObjectKind`.
+ *
+ * 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: Statements
+ * Type: Generator
+ * Operands: uint8_t kind
+ * Stack: result => result
+ */ \
+ MACRO(JSOP_CHECKISOBJ, "checkisobj", NULL, 2, 1, 1, JOF_UINT8) \
+ /*
+ * Check that the top value on the stack is callable, and throw a
+ * TypeError if not. The operand `kind` is used only to generate an
+ * appropriate error message. It must be in range for
+ * `js::CheckIsCallableKind`.
*
* Category: Statements
* Type: Function
+ * Operands: uint8_t kind
+ * Stack: obj => obj
+ */ \
+ MACRO(JSOP_CHECKISCALLABLE, "checkiscallable", 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: Literals
+ * Type: Object
* Operands:
- * Stack: callee, this, args => rval
+ * Stack: val => val
+ */ \
+ MACRO(JSOP_CHECKOBJCOERCIBLE, "checkobjcoercible", 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: Statements
+ * Type: Generator
+ * Operands:
+ * Stack: iter, next => asynciter
+ */ \
+ MACRO(JSOP_TOASYNCITER, "toasynciter", 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: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, protoVal => obj
+ */ \
+ MACRO(JSOP_MUTATEPROTO, "mutateproto", 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: Literals
+ * Type: Array
+ * Operands: uint32_t length
+ * Stack: => array
+ */ \
+ MACRO(JSOP_NEWARRAY, "newarray", NULL, 5, 0, 1, JOF_UINT32|JOF_IC) \
+ /*
+ * Initialize an array element `array[index]` with value `val`.
+ *
+ * `val` may be `MagicValue(JS_ELEMENTS_HOLE)`. If it is, this does nothing.
+ *
+ * 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_INITELEM_ARRAY`.
+ *
+ * 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: Literals
+ * Type: Array
+ * Operands: uint32_t index
+ * Stack: array, val => array
*/ \
- MACRO(JSOP_STRICTSPREADEVAL, 50, "strict-spreadeval", NULL, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET|JOF_CHECKSTRICT|JOF_IC) \
+ MACRO(JSOP_INITELEM_ARRAY, "initelem_array", NULL, 5, 2, 1, JOF_UINT32|JOF_ELEM|JOF_PROPINIT|JOF_DETECTING|JOF_IC) \
+ /*
+ * Initialize an array element `array[index++]` with value `val`.
+ *
+ * `val` may be `MagicValue(JS_ELEMENTS_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_INITELEM_ARRAY` and `JSOP_INITELEM_INC`.
+ *
+ * `index` must be an integer, `0 <= index <= INT32_MAX`. If `index` is
+ * `INT32_MAX`, this throws a RangeError.
+ *
+ * This instruction is used when an array literal contains a
+ * *SpreadElement*. In `[a, ...b, c]`, `INITELEM_ARRAY 0` is used to put
+ * `a` into the array, but `INITELEM_INC` 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: Literals
+ * Type: Array
+ * Operands:
+ * Stack: array, index, val => array, (index + 1)
+ */ \
+ MACRO(JSOP_INITELEM_INC, "initelem_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 (e.g. property 0 in the array '[, 1]').
+ *
+ * This magic value must be used only by `JSOP_INITELEM_ARRAY` or
+ * `JSOP_INITELEM_INC`.
+ *
+ * Category: Literals
+ * Type: Array
+ * Operands:
+ * Stack: => hole
+ */ \
+ MACRO(JSOP_HOLE, "hole", NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Create and push a new array that shares the elements of a template
+ * object.
+ *
+ * `script->getObject(objectIndex)` must be a copy-on-write array whose
+ * elements are all primitive values.
+ *
+ * This is an optimization. This single instruction implements an entire
+ * array literal, saving run time, code, and memory compared to
+ * `JSOP_NEWARRAY` and a series of `JSOP_INITELEM` instructions.
+ *
+ * Category: Literals
+ * Type: Array
+ * Operands: uint32_t objectIndex
+ * Stack: => array
+ */ \
+ MACRO(JSOP_NEWARRAY_COPYONWRITE, "newarray_copyonwrite", NULL, 5, 0, 1, JOF_OBJECT) \
+ /*
+ * 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: Literals
+ * Type: RegExp
+ * Operands: uint32_t regexpIndex
+ * Stack: => regexp
+ */ \
+ MACRO(JSOP_REGEXP, "regexp", NULL, 5, 0, 1, JOF_REGEXP) \
+ /*
+ * Push a function object.
+ *
+ * This clones the function unless it's a singleton. Used to implement
+ * function definitions, function expressions, methods, and class field
+ * initializers.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands: uint32_t funcIndex
+ * Stack: => obj
+ */ \
+ MACRO(JSOP_LAMBDA, "lambda", NULL, 5, 0, 1, JOF_OBJECT) \
+ /*
+ * Push a new arrow function.
+ *
+ * Pops the top of stack value as 'new.target', pushes an arrow function
+ * with lexical 'new.target' onto the stack.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands: uint32_t funcIndex
+ * Stack: new.target => obj
+ */ \
+ MACRO(JSOP_LAMBDA_ARROW, "lambda_arrow", NULL, 5, 1, 1, JOF_OBJECT) \
+ /*
+ * Pops the top two values on the stack as 'name' and 'fun', defines the
+ * name of 'fun' to 'name' with prefix if any, and pushes 'fun' back onto
+ * the stack.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands: uint8_t prefixKind
+ * Stack: fun, name => fun
+ */ \
+ MACRO(JSOP_SETFUNNAME, "setfunname", NULL, 2, 2, 1, JOF_UINT8) \
+ /*
+ * Initialize the home object for functions with super bindings.
+ *
+ * This opcode takes the function and the object to be the home object,
+ * does the set, and leaves the function on the stack.
+ *
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: fun, homeObject => fun
+ */ \
+ MACRO(JSOP_INITHOMEOBJECT, "inithomeobject", NULL, 1, 2, 1, JOF_BYTE) \
/*
* Ensures the result of a class's heritage expression is either null or a
* constructor.
*
* Category: Literals
* Type: Object
* Operands:
* Stack: heritage => heritage
*/ \
- MACRO(JSOP_CHECKCLASSHERITAGE, 51, "checkclassheritage", NULL, 1, 1, 1, JOF_BYTE) \
+ MACRO(JSOP_CHECKCLASSHERITAGE, "checkclassheritage", NULL, 1, 1, 1, JOF_BYTE) \
/*
* Pushes a clone of a function with a given [[Prototype]] onto the stack.
*
* Category: Statements
* Type: Function
* Operands: uint32_t funcIndex
* Stack: proto => obj
*/ \
- MACRO(JSOP_FUNWITHPROTO, 52, "funwithproto", NULL, 5, 1, 1, JOF_OBJECT) \
+ MACRO(JSOP_FUNWITHPROTO, "funwithproto", NULL, 5, 1, 1, JOF_OBJECT) \
/*
- * Pops the top of stack value, pushes property of it onto the stack.
+ * Push a default constructor for a base class literal.
*
* Category: Literals
- * Type: Object
+ * Type: Class
* Operands: uint32_t nameIndex
- * Stack: obj => obj[name]
+ * Stack: => constructor
*/ \
- MACRO(JSOP_GETPROP, 53, "getprop", NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_TYPESET|JOF_IC) \
+ MACRO(JSOP_CLASSCONSTRUCTOR, "classconstructor", NULL, 5, 0, 1, JOF_ATOM) \
/*
- * Pops the top two values on the stack as 'val' and 'obj' and performs
- * 'obj.prop = val', pushing 'val' back onto the stack.
- *
- * Category: Literals
- * Type: Object
- * Operands: uint32_t nameIndex
- * Stack: obj, val => val
- */ \
- MACRO(JSOP_SETPROP, 54, "setprop", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSLOPPY|JOF_IC) \
- /*
- * Pops the top two values on the stack as 'propval' and 'obj', pushes
- * 'propval' property of 'obj' onto the stack.
+ * Push a default constructor for a derived class literal.
*
* Category: Literals
- * Type: Object
- * Operands:
- * Stack: obj, propval => obj[propval]
+ * Type: Class
+ * Operands: uin32_t nameIndex
+ * Stack: proto => constructor
*/ \
- MACRO(JSOP_GETELEM, 55, "getelem", NULL, 1, 2, 1, JOF_BYTE|JOF_ELEM|JOF_TYPESET|JOF_IC) \
+ MACRO(JSOP_DERIVEDCONSTRUCTOR, "derivedconstructor", NULL, 5, 1, 1, JOF_ATOM) \
/*
- * Pops the top three values on the stack as 'val', 'propval' and 'obj',
- * sets 'propval' property of 'obj' as 'val', pushes 'val' onto the stack.
+ * Pushes the current global's builtin prototype for a given proto key.
*
* Category: Literals
- * Type: Object
- * Operands:
- * Stack: obj, propval, val => val
+ * Type: Constants
+ * Operands: uint8_t kind
+ * Stack: => %BuiltinPrototype%
*/ \
- MACRO(JSOP_SETELEM, 56, "setelem", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSLOPPY|JOF_IC) \
- /*
- * Pops the top three values on the stack as 'val', 'propval' and 'obj',
- * sets 'propval' property of 'obj' as 'val', pushes 'val' onto the stack.
- * Throws a TypeError if the set fails, per strict mode semantics.
- *
- * Category: Literals
- * Type: Object
- * Operands:
- * Stack: obj, propval, val => val
- */ \
- MACRO(JSOP_STRICTSETELEM, 57, "strict-setelem", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSTRICT|JOF_IC) \
+ MACRO(JSOP_BUILTINPROTO, "builtinproto", NULL, 2, 0, 1, JOF_UINT8) \
/*
* Invokes 'callee' with 'this' and 'args', pushes return value onto the
* stack.
*
* Category: Statements
* Type: Function
* Operands: uint16_t argc
* Stack: callee, this, args[0], ..., args[argc-1] => rval
* nuses: (argc+2)
*/ \
- MACRO(JSOP_CALL, 58, "call", NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_TYPESET|JOF_IC) \
- /*
- * Looks up name on the environment chain and pushes its value onto the
- * stack.
- *
- * Category: Variables and Scopes
- * Type: Variables
- * Operands: uint32_t nameIndex
- * Stack: => val
- */ \
- MACRO(JSOP_GETNAME, 59, "getname", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_IC) \
- /*
- * Pushes numeric constant onto the stack.
- *
- * Category: Literals
- * Type: Constants
- * Operands: DoubleValue literal
- * Stack: => val
- */ \
- MACRO(JSOP_DOUBLE, 60, "double", NULL, 9, 0, 1, JOF_DOUBLE) \
- /*
- * Pushes string constant onto the stack.
- *
- * Category: Literals
- * Type: Constants
- * Operands: uint32_t atomIndex
- * Stack: => atom
- */ \
- MACRO(JSOP_STRING, 61, "string", NULL, 5, 0, 1, JOF_ATOM) \
- /*
- * Pushes '0' onto the stack.
- *
- * Category: Literals
- * Type: Constants
- * Operands:
- * Stack: => 0
- */ \
- MACRO(JSOP_ZERO, 62, "zero", "0", 1, 0, 1, JOF_BYTE) \
- /*
- * Pushes '1' onto the stack.
- *
- * Category: Literals
- * Type: Constants
- * Operands:
- * Stack: => 1
- */ \
- MACRO(JSOP_ONE, 63, "one", "1", 1, 0, 1, JOF_BYTE) \
- /*
- * Pushes 'null' onto the stack.
- *
- * Category: Literals
- * Type: Constants
- * Operands:
- * Stack: => null
- */ \
- MACRO(JSOP_NULL, 64, js_null_str, js_null_str, 1, 0, 1, JOF_BYTE) \
- /*
- * Pushes 'JS_IS_CONSTRUCTING'
- *
- * Category: Literals
- * Type: Constants
- * Operands:
- * Stack: => JS_IS_CONSTRUCTING
- */ \
- MACRO(JSOP_IS_CONSTRUCTING, 65, "is-constructing", NULL, 1, 0, 1, JOF_BYTE) \
- /*
- * Pushes boolean value onto the stack.
- *
- * Category: Literals
- * Type: Constants
- * Operands:
- * Stack: => true/false
- */ \
- MACRO(JSOP_FALSE, 66, js_false_str, js_false_str, 1, 0, 1, JOF_BYTE) \
- MACRO(JSOP_TRUE, 67, js_true_str, js_true_str, 1, 0, 1, JOF_BYTE) \
- /*
- * Converts the top of stack value into a boolean, if the result is 'true',
- * jumps to a 32-bit offset from the current bytecode.
- *
- * Category: Statements
- * Type: Jumps
- * Operands: int32_t offset
- * Stack: cond => cond
- */ \
- MACRO(JSOP_OR, 68, "or", NULL, 5, 1, 1, JOF_JUMP|JOF_DETECTING|JOF_IC) \
- /*
- * Converts the top of stack value into a boolean, if the result is
- * 'false', jumps to a 32-bit offset from the current bytecode.
- *
- * Category: Statements
- * Type: Jumps
- * Operands: int32_t offset
- * Stack: cond => cond
- */ \
- MACRO(JSOP_AND, 69, "and", NULL, 5, 1, 1, JOF_JUMP|JOF_DETECTING|JOF_IC) \
- /*
- * Pops the top of stack value as 'i', if 'low <= i <= high',
- * jumps to a 32-bit offset: offset is stored in the script's resumeOffsets
- * list at index 'firstResumeIndex + (i - low)'
- * jumps to a 32-bit offset: 'len' from the current bytecode otherwise
- *
- * Category: Statements
- * Type: Switch Statement
- * Operands: int32_t len, int32_t low, int32_t high,
- * uint24_t firstResumeIndex
- * Stack: i =>
- * len: len
- */ \
- MACRO(JSOP_TABLESWITCH, 70, "tableswitch", NULL, 16, 1, 0, JOF_TABLESWITCH|JOF_DETECTING) \
- /*
- */ \
- MACRO(JSOP_UNUSED71, 71, "unused71", NULL, 1, 0, 0, JOF_BYTE) \
- /*
- * Pops the top two values from the stack, then pushes the result of
- * applying the operator to the two values.
- *
- * Category: Operators
- * Type: Comparison Operators
- * Operands:
- * Stack: lval, rval => (lval OP rval)
- */ \
- MACRO(JSOP_STRICTEQ, 72, "stricteq", "===", 1, 2, 1, JOF_BYTE|JOF_DETECTING|JOF_IC) \
- MACRO(JSOP_STRICTNE, 73, "strictne", "!==", 1, 2, 1, JOF_BYTE|JOF_DETECTING|JOF_IC) \
- /*
- * Sometimes we know when emitting that an operation will always throw.
- *
- * Throws the indicated JSMSG.
- *
- * Category: Statements
- * Type: Exception Handling
- * Operands: uint16_t msgNumber
- * Stack: =>
- */ \
- MACRO(JSOP_THROWMSG, 74, "throwmsg", NULL, 3, 0, 0, JOF_UINT16) \
- /*
- * Sets up a for-in loop. It pops the top of stack value as 'val' and
- * pushes 'iter' which is an iterator for 'val'.
- *
- * Category: Statements
- * Type: For-In Statement
- * Operands:
- * Stack: val => iter
- */ \
- MACRO(JSOP_ITER, 75, "iter", NULL, 1, 1, 1, JOF_BYTE|JOF_IC) \
- /*
- * Pushes the next iterated value onto the stack. If no value is available,
- * MagicValue(JS_NO_ITER_VALUE) is pushed.
- *
- * Category: Statements
- * Type: For-In Statement
- * Operands:
- * Stack: iter => iter, val
- */ \
- MACRO(JSOP_MOREITER, 76, "moreiter", NULL, 1, 1, 2, JOF_BYTE) \
- /*
- * Pushes a boolean indicating whether the value on top of the stack is
- * MagicValue(JS_NO_ITER_VALUE).
- *
- * Category: Statements
- * Type: For-In Statement
- * Operands:
- * Stack: val => val, res
- */ \
- MACRO(JSOP_ISNOITER, 77, "isnoiter", NULL, 1, 1, 2, JOF_BYTE) \
- /*
- * Exits a for-in loop by popping the iteration value and the iterator
- * object from the stack and closing the iterator object.
- *
- * Category: Statements
- * Type: For-In Statement
- * Operands:
- * Stack: iter, iterval =>
- */ \
- MACRO(JSOP_ENDITER, 78, "enditer", NULL, 1, 2, 0, JOF_BYTE) \
+ MACRO(JSOP_CALL, "call", NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_TYPESET|JOF_IC) \
/*
* Invokes 'callee' with 'this' and 'args', pushes return value onto the
* stack.
*
* This is for 'f.apply'.
*
* Category: Statements
* Type: Function
* Operands: uint16_t argc
* Stack: callee, this, args[0], ..., args[argc-1] => rval
* nuses: (argc+2)
*/ \
- MACRO(JSOP_FUNAPPLY, 79, "funapply", NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_TYPESET|JOF_IC) \
- /*
- * Pushes deep-cloned object literal or singleton onto the stack.
- *
- * Category: Literals
- * Type: Object
- * Operands: uint32_t objectIndex
- * Stack: => obj
- */ \
- MACRO(JSOP_OBJECT, 80, "object", NULL, 5, 0, 1, JOF_OBJECT) \
- /*
- * Pops the top value off the stack.
- *
- * Category: Operators
- * Type: Stack Operations
- * Operands:
- * Stack: v =>
- */ \
- MACRO(JSOP_POP, 81, "pop", NULL, 1, 1, 0, JOF_BYTE) \
- /*
- * Invokes 'callee' as a constructor with 'this' and 'args', pushes return
- * value onto the stack.
- *
- * Category: Statements
- * Type: Function
- * Operands: uint16_t argc
- * Stack: callee, this, args[0], ..., args[argc-1], newTarget => rval
- * nuses: (argc+3)
- */ \
- MACRO(JSOP_NEW, 82, "new", NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_TYPESET|JOF_IC|JOF_IC) \
- /*
- * Pushes newly created object onto the stack with provided [[Prototype]].
- *
- * Category: Literals
- * Type: Object
- * Operands:
- * Stack: proto => obj
- */ \
- MACRO(JSOP_OBJWITHPROTO, 83, "objwithproto", NULL, 1, 1, 1, JOF_BYTE) \
- /*
- * Fast get op for function arguments and local variables.
- *
- * Pushes 'arguments[argno]' onto the stack.
- *
- * Category: Variables and Scopes
- * Type: Arguments
- * Operands: uint16_t argno
- * Stack: => arguments[argno]
- */ \
- MACRO(JSOP_GETARG, 84, "getarg", NULL, 3, 0, 1, JOF_QARG|JOF_NAME) \
- /*
- * Fast set op for function arguments and local variables.
- *
- * Sets 'arguments[argno]' as the top of stack value.
- *
- * Category: Variables and Scopes
- * Type: Arguments
- * Operands: uint16_t argno
- * Stack: v => v
- */ \
- MACRO(JSOP_SETARG, 85, "setarg", NULL, 3, 1, 1, JOF_QARG|JOF_NAME) \
- /*
- * Pushes the value of local variable onto the stack.
- *
- * Category: Variables and Scopes
- * Type: Local Variables
- * Operands: uint24_t localno
- * Stack: => val
- */ \
- MACRO(JSOP_GETLOCAL, 86, "getlocal", NULL, 4, 0, 1, JOF_LOCAL|JOF_NAME) \
- /*
- * Stores the top stack value to the given local.
- *
- * Category: Variables and Scopes
- * Type: Local Variables
- * Operands: uint24_t localno
- * Stack: v => v
- */ \
- MACRO(JSOP_SETLOCAL, 87, "setlocal", NULL, 4, 1, 1, JOF_LOCAL|JOF_NAME|JOF_DETECTING) \
- /*
- * Pushes unsigned 16-bit int immediate integer operand onto the stack.
- *
- * Category: Literals
- * Type: Constants
- * Operands: uint16_t val
- * Stack: => val
- */ \
- MACRO(JSOP_UINT16, 88, "uint16", NULL, 3, 0, 1, JOF_UINT16) \
- /*
- * Pushes newly created object onto the stack.
- *
- * This opcode has four extra bytes so it can be exchanged with
- * JSOP_NEWOBJECT during emit.
- *
- * Category: Literals
- * Type: Object
- * Operands: (uint32_t extra)
- * Stack: => obj
- */ \
- MACRO(JSOP_NEWINIT, 89, "newinit", NULL, 5, 0, 1, JOF_UINT32|JOF_IC) \
- /*
- * Pushes newly created array onto the stack.
- *
- * This opcode takes the final length, which is preallocated.
- *
- * Category: Literals
- * Type: Array
- * Operands: uint32_t length
- * Stack: => obj
- */ \
- MACRO(JSOP_NEWARRAY, 90, "newarray", NULL, 5, 0, 1, JOF_UINT32|JOF_IC) \
- /*
- * Pushes newly created object onto the stack.
- *
- * This opcode takes an object with the final shape, which can be set at
- * the start and slots then filled in directly. We compute a group based on
- * allocation site (or new group if the template's group is a singleton);
- * see JSOP_NEWOBJECT_WITHGROUP for a variant that uses the same group as
- * the template object.
- *
- * Category: Literals
- * Type: Object
- * Operands: uint32_t baseobjIndex
- * Stack: => obj
- */ \
- MACRO(JSOP_NEWOBJECT, 91, "newobject", NULL, 5, 0, 1, JOF_OBJECT|JOF_IC) \
- /*
- * Initialize the home object for functions with super bindings.
- *
- * This opcode takes the function and the object to be the home object,
- * does the set, and leaves the function on the stack.
- *
- * Category: Literals
- * Type: Object
- * Operands:
- * Stack: fun, homeObject => fun
- */ \
- MACRO(JSOP_INITHOMEOBJECT, 92, "inithomeobject", NULL, 1, 2, 1, JOF_BYTE) \
- /*
- * Initialize a named property in an object literal, like '{a: x}'.
- *
- * Pops the top two values on the stack as 'val' and 'obj', defines
- * 'nameIndex' property of 'obj' as 'val', pushes 'obj' onto the stack.
- *
- * Category: Literals
- * Type: Object
- * Operands: uint32_t nameIndex
- * Stack: obj, val => obj
- */ \
- MACRO(JSOP_INITPROP, 93, "initprop", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT|JOF_DETECTING|JOF_IC) \
- /*
- * Initialize a numeric property in an object literal, like '{1: x}'.
- *
- * Pops the top three values on the stack as 'val', 'id' and 'obj', defines
- * 'id' property of 'obj' as 'val', pushes 'obj' onto the stack.
- *
- * Category: Literals
- * Type: Object
- * Operands:
- * Stack: obj, id, val => obj
- */ \
- MACRO(JSOP_INITELEM, 94, "initelem", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_DETECTING|JOF_IC) \
- /*
- * Pops the top three values on the stack as 'val', 'index' and 'obj', sets
- * 'index' property of 'obj' as 'val', pushes 'obj' and 'index + 1' onto
- * the stack.
- *
- * This opcode is used in Array literals with spread and spreadcall
- * arguments.
- *
- * Category: Literals
- * Type: Array
- * Operands:
- * Stack: obj, index, val => obj, (index + 1)
- */ \
- MACRO(JSOP_INITELEM_INC, 95, "initelem_inc", NULL, 1, 3, 2, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_IC) \
- /*
- * Initialize an array element.
- *
- * Pops the top two values on the stack as 'val' and 'obj', sets 'index'
- * property of 'obj' as 'val', pushes 'obj' onto the stack.
- *
- * Category: Literals
- * Type: Array
- * Operands: uint32_t index
- * Stack: obj, val => obj
- */ \
- MACRO(JSOP_INITELEM_ARRAY, 96, "initelem_array", NULL, 5, 2, 1, JOF_UINT32|JOF_ELEM|JOF_PROPINIT|JOF_DETECTING|JOF_IC) \
- /*
- * Initialize a getter in an object literal.
- *
- * Pops the top two values on the stack as 'val' and 'obj', defines getter
- * of 'obj' as 'val', pushes 'obj' onto the stack.
- *
- * Category: Literals
- * Type: Object
- * Operands: uint32_t nameIndex
- * Stack: obj, val => obj
- */ \
- MACRO(JSOP_INITPROP_GETTER, 97, "initprop_getter", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT|JOF_DETECTING) \
- /*
- * Initialize a setter in an object literal.
- *
- * Pops the top two values on the stack as 'val' and 'obj', defines setter
- * of 'obj' as 'val', pushes 'obj' onto the stack.
- *
- * Category: Literals
- * Type: Object
- * Operands: uint32_t nameIndex
- * Stack: obj, val => obj
- */ \
- MACRO(JSOP_INITPROP_SETTER, 98, "initprop_setter", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT|JOF_DETECTING) \
- /*
- * Initialize a numeric getter in an object literal like
- * '{get 2() {}}'.
- *
- * Pops the top three values on the stack as 'val', 'id' and 'obj', defines
- * 'id' getter of 'obj' as 'val', pushes 'obj' onto the stack.
- *
- * Category: Literals
- * Type: Object
- * Operands:
- * Stack: obj, id, val => obj
- */ \
- MACRO(JSOP_INITELEM_GETTER, 99, "initelem_getter", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_DETECTING) \
- /*
- * Initialize a numeric setter in an object literal like
- * '{set 2(v) {}}'.
- *
- * Pops the top three values on the stack as 'val', 'id' and 'obj', defines
- * 'id' setter of 'obj' as 'val', pushes 'obj' onto the stack.
- *
- * Category: Literals
- * Type: Object
- * Operands:
- * Stack: obj, id, val => obj
- */ \
- MACRO(JSOP_INITELEM_SETTER, 100, "initelem_setter", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_DETECTING) \
- /*
- * Pushes the call site object specified by objectIndex onto the stack.
- * Defines the raw property specified by objectIndex + 1 on the call site
- * object and freezes both the call site object as well as its raw
- * property.
- *
- * Category: Literals
- * Type: Object
- * Operands: uint32_t objectIndex
- * Stack: => obj
- */ \
- MACRO(JSOP_CALLSITEOBJ, 101, "callsiteobj", NULL, 5, 0, 1, JOF_OBJECT) \
- /*
- * Pushes a newly created array onto the stack, whose elements are the same
- * as that of a template object's copy on write elements.
- *
- * Category: Literals
- * Type: Array
- * Operands: uint32_t objectIndex
- * Stack: => obj
- */ \
- MACRO(JSOP_NEWARRAY_COPYONWRITE, 102, "newarray_copyonwrite", NULL, 5, 0, 1, JOF_OBJECT) \
- /*
- * Pushes the prototype of the home object for |callee| onto the
- * stack.
- *
- * Category: Variables and Scopes
- * Type: Super
- * Operands:
- * Stack: callee => homeObjectProto
- */ \
- MACRO(JSOP_SUPERBASE, 103, "superbase", NULL, 1, 1, 1, JOF_BYTE) \
- /*
- * Pops the top two values, and pushes the property of one, using the other
- * as the receiver.
- *
- * Category: Literals
- * Type: Object
- * Operands: uint32_t nameIndex
- * Stack: receiver, obj => obj[name]
- */ \
- MACRO(JSOP_GETPROP_SUPER, 104, "getprop-super", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_TYPESET|JOF_IC) \
- /*
- * Pops the top three values on the stack as 'val' and 'obj', and
- * 'receiver', and performs 'obj.prop = val', pushing 'val' back onto the
- * stack. Throws a TypeError if the set-operation failed (per strict mode
- * semantics).
- *
- * Category: Literals
- * Type: Object
- * Operands: uint32_t nameIndex
- * Stack: receiver, obj, val => val
- */ \
- MACRO(JSOP_STRICTSETPROP_SUPER, 105, "strictsetprop-super", NULL, 5, 3, 1, JOF_ATOM|JOF_PROP|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSTRICT) \
- /*
- */ \
- MACRO(JSOP_UNUSED106, 106, "unused", NULL, 1, 0, 0, JOF_BYTE) \
- /*
- * Pops the top three values on the stack as 'val', 'obj' and 'receiver',
- * and performs 'obj.prop = val', pushing 'val' back onto the stack.
- *
- * Category: Literals
- * Type: Object
- * Operands: uint32_t nameIndex
- * Stack: receiver, obj, val => val
- */ \
- MACRO(JSOP_SETPROP_SUPER, 107, "setprop-super", NULL, 5, 3, 1, JOF_ATOM|JOF_PROP|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSLOPPY) \
+ MACRO(JSOP_FUNAPPLY, "funapply", NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_TYPESET|JOF_IC) \
/*
* Invokes 'callee' with 'this' and 'args', pushes return value onto the
* stack.
*
* If 'callee' is determined to be the canonical 'Function.prototype.call'
* function, then this operation is optimized to directly call 'callee'
* with 'args[0]' as 'this', and the remaining arguments as formal args to
* 'callee'.
@@ -1103,97 +1675,645 @@
* Like JSOP_FUNAPPLY but for 'f.call' instead of 'f.apply'.
*
* Category: Statements
* Type: Function
* Operands: uint16_t argc
* Stack: callee, this, args[0], ..., args[argc-1] => rval
* nuses: (argc+2)
*/ \
- MACRO(JSOP_FUNCALL, 108, "funcall", NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_TYPESET|JOF_IC) \
+ MACRO(JSOP_FUNCALL, "funcall", NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_TYPESET|JOF_IC) \
+ /*
+ * Like JSOP_CALL, but tells the function that the return value is ignored.
+ * stack.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands: uint16_t argc
+ * Stack: callee, this, args[0], ..., args[argc-1] => rval
+ * nuses: (argc+2)
+ */ \
+ MACRO(JSOP_CALL_IGNORES_RV, "call-ignores-rv", NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_TYPESET|JOF_IC) \
+ /*
+ * spreadcall variant of JSOP_CALL.
+ *
+ * Invokes 'callee' with 'this' and 'args', pushes the return value onto
+ * the stack.
+ *
+ * 'args' is an Array object which contains actual arguments.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: callee, this, args => rval
+ */ \
+ MACRO(JSOP_SPREADCALL, "spreadcall", NULL, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET|JOF_IC) \
+ /*
+ * Pops the top stack value, pushes the value and a boolean value that
+ * indicates whether the spread operation for the value can be optimized in
+ * spread call.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: arr => arr, optimized
+ */ \
+ MACRO(JSOP_OPTIMIZE_SPREADCALL, "optimize-spreadcall", NULL, 1, 1, 2, JOF_BYTE) \
+ /*
+ * Invokes 'eval' with 'args' and pushes return value onto the stack.
+ *
+ * If 'eval' in global scope is not original one, invokes the function with
+ * 'this' and 'args', and pushes return value onto the stack.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands: uint16_t argc
+ * Stack: callee, this, args[0], ..., args[argc-1] => rval
+ * nuses: (argc+2)
+ */ \
+ MACRO(JSOP_EVAL, "eval", NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_TYPESET|JOF_CHECKSLOPPY|JOF_IC) \
+ /*
+ * spreadcall variant of JSOP_EVAL
+ *
+ * Invokes 'eval' with 'args' and pushes the return value onto the stack.
+ *
+ * If 'eval' in global scope is not original one, invokes the function with
+ * 'this' and 'args', and pushes return value onto the stack.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: callee, this, args => rval
+ */ \
+ MACRO(JSOP_SPREADEVAL, "spreadeval", NULL, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET|JOF_CHECKSLOPPY|JOF_IC) \
+ /*
+ * Invokes 'eval' with 'args' and pushes return value onto the stack.
+ *
+ * If 'eval' in global scope is not original one, invokes the function with
+ * 'this' and 'args', and pushes return value onto the stack.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands: uint16_t argc
+ * Stack: callee, this, args[0], ..., args[argc-1] => rval
+ * nuses: (argc+2)
+ */ \
+ MACRO(JSOP_STRICTEVAL, "strict-eval", NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_TYPESET|JOF_CHECKSTRICT|JOF_IC) \
+ /*
+ * spreadcall variant of JSOP_EVAL
+ *
+ * Invokes 'eval' with 'args' and pushes the return value onto the stack.
+ *
+ * If 'eval' in global scope is not original one, invokes the function with
+ * 'this' and 'args', and pushes return value onto the stack.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: callee, this, args => rval
+ */ \
+ MACRO(JSOP_STRICTSPREADEVAL, "strict-spreadeval", NULL, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET|JOF_CHECKSTRICT|JOF_IC) \
+ /*
+ * Pushes the implicit 'this' value for calls to the associated name onto
+ * the stack.
+ *
+ * Category: Variables and Scopes
+ * Type: This
+ * Operands: uint32_t nameIndex
+ * Stack: => this
+ */ \
+ MACRO(JSOP_IMPLICITTHIS, "implicitthis", "", 5, 0, 1, JOF_ATOM) \
+ /*
+ * Pushes the implicit 'this' value for calls to the associated name onto
+ * the stack; only used when the implicit this might be derived from a
+ * non-syntactic scope (instead of the global itself).
+ *
+ * Note that code evaluated via the Debugger API uses DebugEnvironmentProxy
+ * objects on its scope chain, which are non-syntactic environments that
+ * refer to syntactic environments. As a result, the binding we want may be
+ * held by a syntactic environments such as CallObject or
+ * VarEnvrionmentObject.
+ *
+ * Category: Variables and Scopes
+ * Type: This
+ * Operands: uint32_t nameIndex
+ * Stack: => this
+ */ \
+ MACRO(JSOP_GIMPLICITTHIS, "gimplicitthis", "", 5, 0, 1, JOF_ATOM) \
+ /*
+ * Pops the top of stack value, pushes property of it onto the stack.
+ * Requires the value under 'obj' to be the receiver of the following call.
+ *
+ * Like JSOP_GETPROP but for call context.
+ *
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj => obj[name]
+ */ \
+ MACRO(JSOP_CALLPROP, "callprop", NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_TYPESET|JOF_IC) \
+ /*
+ * Pops the top two values on the stack as 'propval' and 'obj', pushes
+ * 'propval' property of 'obj' onto the stack. Requires the value under
+ * 'obj' to be the receiver of the following call.
+ *
+ * Like JSOP_GETELEM but for call context.
+ *
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, propval => obj[propval]
+ */ \
+ MACRO(JSOP_CALLELEM, "callelem", NULL, 1, 2, 1, JOF_BYTE|JOF_ELEM|JOF_TYPESET|JOF_IC) \
+ /*
+ * Pushes the call site object specified by objectIndex onto the stack.
+ * Defines the raw property specified by objectIndex + 1 on the call site
+ * object and freezes both the call site object as well as its raw
+ * property.
+ *
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t objectIndex
+ * Stack: => obj
+ */ \
+ MACRO(JSOP_CALLSITEOBJ, "callsiteobj", NULL, 5, 0, 1, JOF_OBJECT) \
+ /*
+ * Pushes 'JS_IS_CONSTRUCTING'
+ *
+ * Category: Literals
+ * Type: Constants
+ * Operands:
+ * Stack: => JS_IS_CONSTRUCTING
+ */ \
+ MACRO(JSOP_IS_CONSTRUCTING, "is-constructing", NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Invokes 'callee' as a constructor with 'this' and 'args', pushes return
+ * value onto the stack.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands: uint16_t argc
+ * Stack: callee, this, args[0], ..., args[argc-1], newTarget => rval
+ * nuses: (argc+3)
+ */ \
+ MACRO(JSOP_NEW, "new", NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_TYPESET|JOF_IC|JOF_IC) \
+ /*
+ * spreadcall variant of JSOP_NEW
+ *
+ * Invokes 'callee' as a constructor with 'this' and 'args', pushes the
+ * return value onto the stack.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: callee, this, args, newTarget => rval
+ */ \
+ MACRO(JSOP_SPREADNEW, "spreadnew", NULL, 1, 4, 1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET|JOF_IC) \
+ /*
+ * Push the function to invoke with |super()|. This is the prototype of the
+ * function passed in as |callee|.
+ *
+ * Category: Variables and Scopes
+ * Type: Super
+ * Operands:
+ * Stack: callee => superFun
+ */ \
+ MACRO(JSOP_SUPERFUN, "superfun", NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Behaves exactly like JSOP_NEW, but allows JITs to distinguish the two
+ * cases.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands: uint16_t argc
+ * Stack: callee, this, args[0], ..., args[argc-1], newTarget => rval
+ * nuses: (argc+3)
+ */ \
+ MACRO(JSOP_SUPERCALL, "supercall", NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_TYPESET|JOF_IC) \
+ /*
+ * spreadcall variant of JSOP_SUPERCALL.
+ *
+ * Behaves exactly like JSOP_SPREADNEW.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: callee, this, args, newTarget => rval
+ */ \
+ MACRO(JSOP_SPREADSUPERCALL, "spreadsupercall", NULL, 1, 4, 1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET|JOF_IC) \
+ /*
+ * Throw an exception if the value on top of the stack is not the TDZ
+ * MagicValue. Used in derived class constructors.
+ *
+ * Category: Variables and Scopes
+ * Type: This
+ * Operands:
+ * Stack: this => this
+ */ \
+ MACRO(JSOP_CHECKTHISREINIT, "checkthisreinit", NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Initializes generator frame, creates a generator and pushes it on the
+ * stack.
+ *
+ * Category: Statements
+ * Type: Generator
+ * Operands:
+ * Stack: => generator
+ */ \
+ MACRO(JSOP_GENERATOR, "generator", NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Pops the generator from the top of the stack, suspends it and stops
+ * interpretation.
+ *
+ * Category: Statements
+ * Type: Generator
+ * Operands: uint24_t resumeIndex
+ * Stack: generator => generator
+ */ \
+ MACRO(JSOP_INITIALYIELD, "initialyield", NULL, 4, 1, 1, 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.
+ *
+ * Category: Statements
+ * Type: Generator
+ * Operands: uint32_t icIndex
+ * Stack: =>
+ */ \
+ MACRO(JSOP_AFTERYIELD, "afteryield", NULL, 5, 0, 0, JOF_ICINDEX) \
+ /*
+ * Pops the generator and suspends and closes it. Yields the value in the
+ * frame's return value slot.
+ *
+ * Category: Statements
+ * Type: Generator
+ * Operands:
+ * Stack: gen =>
+ */ \
+ MACRO(JSOP_FINALYIELDRVAL, "finalyieldrval", NULL, 1, 1, 0, JOF_BYTE) \
+ /*
+ * Pops the generator and the return value 'rval1', stops interpretation
+ * and returns 'rval1'. Pushes sent value from 'send()' onto the stack.
+ *
+ * Category: Statements
+ * Type: Generator
+ * Operands: uint24_t resumeIndex
+ * Stack: rval1, gen => rval2
+ */ \
+ MACRO(JSOP_YIELD, "yield", NULL, 4, 2, 1, JOF_RESUMEINDEX) \
+ /*
+ * Pushes a boolean indicating whether the top of the stack is
+ * MagicValue(JS_GENERATOR_CLOSING).
+ *
+ * Category: Statements
+ * Type: For-In Statement
+ * Operands:
+ * Stack: val => val, res
+ */ \
+ MACRO(JSOP_ISGENCLOSING, "isgenclosing", NULL, 1, 1, 2, JOF_BYTE) \
+ /*
+ * Pops the top two values 'value' and 'gen' from the stack, then starts
+ * "awaiting" for 'value' to be resolved, which will then resume the
+ * execution of 'gen'. Pushes the async function promise on the stack, so
+ * that it'll be returned to the caller on the very first "await".
+ *
+ * Category: Statements
+ * Type: Generator
+ * Operands:
+ * Stack: value, gen => promise
+ */ \
+ MACRO(JSOP_ASYNCAWAIT, "async-await", NULL, 1, 2, 1, JOF_BYTE) \
+ /*
+ * Pops the top two values 'valueOrReason' and 'gen' from the stack, then
+ * pushes the promise resolved with 'valueOrReason'. `gen` must be the
+ * internal generator object created in async functions. The pushed promise
+ * is the async function's result promise, which is stored in `gen`.
+ *
+ * Category: Statements
+ * Type: Generator
+ * Operands: uint8_t fulfillOrReject
+ * Stack: valueOrReason, gen => promise
+ */ \
+ MACRO(JSOP_ASYNCRESOLVE, "async-resolve", NULL, 2, 2, 1, JOF_UINT8) \
+ /*
+ * Pops the generator and the return value 'promise', stops interpretation
+ * and returns 'promise'. Pushes resolved value onto the stack.
+ *
+ * Category: Statements
+ * Type: Generator
+ * Operands: uint24_t resumeIndex
+ * Stack: promise, gen => resolved
+ */ \
+ MACRO(JSOP_AWAIT, "await", NULL, 4, 2, 1, JOF_RESUMEINDEX) \
+ /*
+ * Pops the top of stack value as 'value', checks if the await for 'value'
+ * can be skipped. If the await operation can be skipped and the resolution
+ * value for 'value' can be acquired, pushes the resolution value and
+ * 'true' onto the stack. Otherwise, pushes 'value' and 'false' on the
+ * stack.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: value => value_or_resolved, canskip
+ */ \
+ MACRO(JSOP_TRYSKIPAWAIT, "tryskipawait", NULL, 1, 1, 2, JOF_BYTE) \
+ /*
+ * Pops the generator and argument from the stack, pushes a new generator
+ * frame and resumes execution of it. Pushes the return value after the
+ * generator yields.
+ *
+ * Category: Statements
+ * Type: Generator
+ * Operands: resume kind (AbstractGeneratorObject::ResumeKind)
+ * Stack: gen, val => rval
+ */ \
+ MACRO(JSOP_RESUME, "resume", NULL, 2, 2, 1, JOF_UINT8|JOF_INVOKE) \
+ /*
+ * This opcode is a no-op and it indicates the location of a jump
+ * instruction target. Some other opcodes act as jump targets as well, see
+ * BytecodeIsJumpTarget. The IC index is used by the Baseline interpreter.
+ *
+ * Category: Other
+ * Operands: uint32_t icIndex
+ * Stack: =>
+ */ \
+ MACRO(JSOP_JUMPTARGET, "jumptarget", NULL, 5, 0, 0, JOF_ICINDEX) \
/*
* This opcode is the target of the backwards jump for some loop.
*
* The uint8 argument is a bitfield. The lower 7 bits of the argument
* indicate the loop depth. This value starts at 1 and is just a hint:
* deeply nested loops all have the same value. The upper bit is set if Ion
* should be able to OSR at this point, which is true unless there is
* non-loop state on the stack.
*
* See JSOP_JUMPTARGET for the icIndex operand.
*
* Category: Statements
* Type: Jumps
* Operands: uint32_t icIndex, uint8_t BITFIELD
* Stack: =>
*/ \
- MACRO(JSOP_LOOPHEAD, 109, "loophead", NULL, 6, 0, 0, JOF_LOOPHEAD) \
+ MACRO(JSOP_LOOPHEAD, "loophead", NULL, 6, 0, 0, JOF_LOOPHEAD) \
+ /*
+ * Jumps to a 32-bit offset from the current bytecode.
+ *
+ * Category: Statements
+ * Type: Jumps
+ * Operands: int32_t offset
+ * Stack: =>
+ */ \
+ MACRO(JSOP_GOTO, "goto", NULL, 5, 0, 0, JOF_JUMP) \
+ /*
+ * Pops the top of stack value, converts it into a boolean, if the result
+ * is 'false', jumps to a 32-bit offset from the current bytecode.
+ *
+ * The idea is that a sequence like
+ * JSOP_ZERO; JSOP_ZERO; JSOP_EQ; JSOP_IFEQ; JSOP_RETURN;
+ * reads like a nice linear sequence that will execute the return.
+ *
+ * Category: Statements
+ * Type: Jumps
+ * Operands: int32_t offset
+ * Stack: cond =>
+ */ \
+ MACRO(JSOP_IFEQ, "ifeq", NULL, 5, 1, 0, JOF_JUMP|JOF_DETECTING|JOF_IC) \
+ /*
+ * Pops the top of stack value, converts it into a boolean, if the result
+ * is 'true', jumps to a 32-bit offset from the current bytecode.
+ *
+ * Category: Statements
+ * Type: Jumps
+ * Operands: int32_t offset
+ * Stack: cond =>
+ */ \
+ MACRO(JSOP_IFNE, "ifne", NULL, 5, 1, 0, JOF_JUMP|JOF_IC) \
+ /*
+ * Converts the top of stack value into a boolean, if the result is
+ * 'false', jumps to a 32-bit offset from the current bytecode.
+ *
+ * Category: Statements
+ * Type: Jumps
+ * Operands: int32_t offset
+ * Stack: cond => cond
+ */ \
+ MACRO(JSOP_AND, "and", NULL, 5, 1, 1, JOF_JUMP|JOF_DETECTING|JOF_IC) \
+ /*
+ * Converts the top of stack value into a boolean, if the result is 'true',
+ * jumps to a 32-bit offset from the current bytecode.
+ *
+ * Category: Statements
+ * Type: Jumps
+ * Operands: int32_t offset
+ * Stack: cond => cond
+ */ \
+ MACRO(JSOP_OR, "or", NULL, 5, 1, 1, JOF_JUMP|JOF_DETECTING|JOF_IC) \
+ /*
+ * If the value on top of the stack is not null or undefined, jumps to a 32-bit offset from the
+ * current bytecode.
+ *
+ * Category: Statements
+ * Type: Jumps
+ * Operands: int32_t offset
+ * Stack: cond => cond
+ */ \
+ MACRO(JSOP_COALESCE, "coalesce", NULL, 5, 1, 1, JOF_JUMP|JOF_DETECTING) \
/*
- * Looks up name on the environment chain and pushes the environment which
- * contains the name onto the stack. If not found, pushes global lexical
- * environment onto the stack.
+ * Pops the top two values on the stack as 'val' and 'cond'. If 'cond' is
+ * 'true', jumps to a 32-bit offset from the current bytecode, re-pushes
+ * 'val' onto the stack if 'false'.
+ *
+ * Category: Statements
+ * Type: Switch Statement
+ * Operands: int32_t offset
+ * Stack: val, cond => val(if !cond)
+ */ \
+ MACRO(JSOP_CASE, "case", NULL, 5, 2, 1, JOF_JUMP) \
+ /*
+ * This appears after all cases in a JSOP_CONDSWITCH, whether there is a
+ * 'default:' label in the switch statement or not. Pop the switch operand
+ * from the stack and jump to a 32-bit offset from the current bytecode.
+ * offset from the current bytecode.
+ *
+ * Category: Statements
+ * Type: Switch Statement
+ * Operands: int32_t offset
+ * Stack: lval =>
+ */ \
+ MACRO(JSOP_DEFAULT, "default", NULL, 5, 1, 0, JOF_JUMP) \
+ /*
+ * Pops the top of stack value as 'i', if 'low <= i <= high',
+ * jumps to a 32-bit offset: offset is stored in the script's resumeOffsets
+ * list at index 'firstResumeIndex + (i - low)'
+ * jumps to a 32-bit offset: 'len' from the current bytecode otherwise
+ *
+ * Category: Statements
+ * Type: Switch Statement
+ * Operands: int32_t len, int32_t low, int32_t high,
+ * uint24_t firstResumeIndex
+ * Stack: i =>
+ * len: len
+ */ \
+ MACRO(JSOP_TABLESWITCH, "tableswitch", NULL, 16, 1, 0, JOF_TABLESWITCH|JOF_DETECTING) \
+ /*
+ * Pops the top of stack value as 'rval', stops interpretation of current
+ * script and returns 'rval'.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: rval =>
+ */ \
+ MACRO(JSOP_RETURN, "return", NULL, 1, 1, 0, JOF_BYTE) \
+ /*
+ * Pushes stack frame's 'rval' onto the stack.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: => rval
+ */ \
+ MACRO(JSOP_GETRVAL, "getrval", NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Pops the top of stack value as 'rval', sets the return value in stack
+ * frame as 'rval'.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: rval =>
+ */ \
+ MACRO(JSOP_SETRVAL, "setrval", NULL, 1, 1, 0, JOF_BYTE) \
+ /*
+ * Stops interpretation and returns value set by JSOP_SETRVAL. When not
+ * set, returns 'undefined'.
+ *
+ * Also emitted at end of script so interpreter don't need to check if
+ * opcode is still in script range.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(JSOP_RETRVAL, "retrval", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Check if a derived class constructor has a valid return value and 'this'
+ * value before it returns. If the return value is not an object, stores
+ * the 'this' value to the return value slot.
*
* Category: Variables and Scopes
- * Type: Variables
- * Operands: uint32_t nameIndex
- * Stack: => env
+ * Type: This
+ * Operands:
+ * Stack: this =>
*/ \
- MACRO(JSOP_BINDNAME, 110, "bindname", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_IC) \
- /*
- * Pops an environment and value from the stack, assigns value to the given
- * name, and pushes the value back on the stack
- *
- * Category: Variables and Scopes
- * Type: Variables
- * Operands: uint32_t nameIndex
- * Stack: env, val => val
- */ \
- MACRO(JSOP_SETNAME, 111, "setname", NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSLOPPY|JOF_IC) \
+ MACRO(JSOP_CHECKRETURN, "checkreturn", NULL, 1, 1, 0, JOF_BYTE) \
/*
* Pops the top of stack value as 'v', sets pending exception as 'v', then
* raises error.
*
* Category: Statements
* Type: Exception Handling
* Operands:
* Stack: v =>
*/ \
- MACRO(JSOP_THROW, 112, js_throw_str, NULL, 1, 1, 0, JOF_BYTE) \
+ MACRO(JSOP_THROW, js_throw_str, NULL, 1, 1, 0, JOF_BYTE) \
/*
- * Pops the top two values 'id' and 'obj' from the stack, then pushes
- * 'id in obj'. This will throw a 'TypeError' if 'obj' is not an object.
- *
- * Note that 'obj' is the top value.
- *
- * Category: Operators
- * Type: Special Operators
- * Operands:
- * Stack: id, obj => (id in obj)
- */ \
- MACRO(JSOP_IN, 113, js_in_str, js_in_str, 1, 2, 1, JOF_BYTE|JOF_IC) \
- /*
- * Pops the top two values 'obj' and 'ctor' from the stack, then pushes
- * 'obj instanceof ctor'. This will throw a 'TypeError' if 'obj' is not an
- * object.
- *
- * Category: Operators
- * Type: Special Operators
- * Operands:
- * Stack: obj, ctor => (obj instanceof ctor)
- */ \
- MACRO(JSOP_INSTANCEOF, 114, js_instanceof_str, js_instanceof_str, 1, 2, 1, JOF_BYTE|JOF_IC) \
- /*
- * Invokes debugger.
+ * Sometimes we know when emitting that an operation will always throw.
+ *
+ * Throws the indicated JSMSG.
*
* Category: Statements
- * Type: Debugger
+ * Type: Exception Handling
+ * Operands: uint16_t msgNumber
+ * Stack: =>
+ */ \
+ MACRO(JSOP_THROWMSG, "throwmsg", NULL, 3, 0, 0, JOF_UINT16) \
+ /*
+ * Throws a runtime TypeError for invalid assignment to 'const'. The
+ * environment coordinate is used for better error messages.
+ *
+ * Category: Variables and Scopes
+ * Type: Aliased Variables
+ * Operands: uint8_t hops, uint24_t slot
+ * Stack: v => v
+ */ \
+ MACRO(JSOP_THROWSETALIASEDCONST, "throwsetaliasedconst", NULL, 5, 1, 1, JOF_ENVCOORD|JOF_NAME|JOF_DETECTING) \
+ /*
+ * Throws a runtime TypeError for invalid assignment to the callee in a
+ * named lambda, which is always a 'const' binding. This is a different
+ * bytecode than JSOP_SETCONST because the named lambda callee, if not
+ * closed over, does not have a frame slot to look up the name with for the
+ * error message.
+ *
+ * Category: Variables and Scopes
+ * Type: Local Variables
+ * Operands:
+ * Stack: v => v
+ */ \
+ MACRO(JSOP_THROWSETCALLEE, "throwsetcallee", NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Throws a runtime TypeError for invalid assignment to 'const'. The
+ * localno is used for better error messages.
+ *
+ * Category: Variables and Scopes
+ * Type: Local Variables
+ * Operands: uint24_t localno
+ * Stack: v => v
+ */ \
+ MACRO(JSOP_THROWSETCONST, "throwsetconst", NULL, 4, 1, 1, JOF_LOCAL|JOF_NAME|JOF_DETECTING) \
+ /*
+ * This no-op appears at the top of the bytecode for a 'TryStatement'.
+ *
+ * Location information for catch/finally blocks is stored in a side table,
+ * 'script->trynotes()'.
+ *
+ * Category: Statements
+ * Type: Exception Handling
* Operands:
* Stack: =>
*/ \
- MACRO(JSOP_DEBUGGER, 115, "debugger", NULL, 1, 0, 0, JOF_BYTE) \
+ MACRO(JSOP_TRY, "try", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * No-op used by the exception unwinder to determine the correct
+ * environment to unwind to when performing IteratorClose due to
+ * destructuring.
+ *
+ * Category: Other
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(JSOP_TRY_DESTRUCTURING, "try-destructuring", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Pushes the current pending exception onto the stack and clears the
+ * pending exception. This is only emitted at the beginning of code for a
+ * catch-block, so it is known that an exception is pending. It is used to
+ * implement catch-blocks and 'yield*'.
+ *
+ * Category: Statements
+ * Type: Exception Handling
+ * Operands:
+ * Stack: => exception
+ */ \
+ MACRO(JSOP_EXCEPTION, "exception", NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Pushes a resumeIndex (stored as 24-bit operand) on the stack.
+ *
+ * Resume indexes are used for ops like JSOP_YIELD and JSOP_GOSUB.
+ * JSScript and BaselineScript have lists of resume entries (one for each
+ * resumeIndex); this lets the JIT resume at these ops from JIT code.
+ *
+ * Category: Other
+ * Operands: uint24_t resumeIndex
+ * Stack: => resumeIndex
+ */ \
+ MACRO(JSOP_RESUMEINDEX, "resume-index", NULL, 4, 0, 1, JOF_RESUMEINDEX) \
/*
* This opcode is used for entering a 'finally' block. Jumps to a 32-bit
* offset from the current pc.
*
* Note: this op doesn't actually push/pop any values, but it has a use
* count of 2 (for the 'false' + resumeIndex values pushed by preceding
* bytecode ops) because the 'finally' entry point does not expect these
* values on the stack. See also JSOP_FINALLY (it has a def count of 2).
@@ -1201,1367 +2321,978 @@
* When the execution resumes from 'finally' block, those stack values are
* popped.
*
* Category: Statements
* Type: Exception Handling
* Operands: int32_t offset
* Stack: false, resumeIndex =>
*/ \
- MACRO(JSOP_GOSUB, 116, "gosub", NULL, 5, 2, 0, JOF_JUMP) \
+ MACRO(JSOP_GOSUB, "gosub", NULL, 5, 2, 0, JOF_JUMP) \
+ /*
+ * This opcode has a def count of 2, but these values are already on the
+ * stack (they're pushed by JSOP_GOSUB).
+ *
+ * Category: Statements
+ * Type: Exception Handling
+ * Operands:
+ * Stack: => false, resumeIndex
+ */ \
+ MACRO(JSOP_FINALLY, "finally", NULL, 1, 0, 2, JOF_BYTE) \
/*
* This opcode is used for returning from a 'finally' block.
*
* Pops the top two values on the stack as 'rval' and 'lval'. Then:
* - If 'lval' is true, throws 'rval'.
* - If 'lval' is false, jumps to the resumeIndex stored in 'lval'.
*
* Category: Statements
* Type: Exception Handling
* Operands:
* Stack: lval, rval =>
*/ \
- MACRO(JSOP_RETSUB, 117, "retsub", NULL, 1, 2, 0, JOF_BYTE) \
+ MACRO(JSOP_RETSUB, "retsub", NULL, 1, 2, 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_INIT*LEXICAL`.
+ *
+ * Category: Literals
+ * Type: Constants
+ * Operands:
+ * Stack: => uninitialized
+ */ \
+ MACRO(JSOP_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 value produced by `JSOP_UNINITIALIZED`, this
+ * marks the binding as uninitialized. Otherwise this marks the binding as
+ * initialized and assigns the value `v` to it.
+ *
+ * Implements: [CreateMutableBinding][1] step 3, substep "record that it is
+ * uninitialized", and [InitializeBinding][2], for optimized locals.
+ *
+ * [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: Local Variables
+ * Operands: uint24_t localno
+ * Stack: v => v
+ */ \
+ MACRO(JSOP_INITLEXICAL, "initlexical", NULL, 4, 1, 1, JOF_LOCAL|JOF_NAME|JOF_DETECTING) \
/*
- * Pushes the current pending exception onto the stack and clears the
- * pending exception. This is only emitted at the beginning of code for a
- * catch-block, so it is known that an exception is pending. It is used to
- * implement catch-blocks and 'yield*'.
- *
- * Category: Statements
- * Type: Exception Handling
- * Operands:
- * Stack: => exception
+ * Initialize a global lexical binding; or mark it as uninitialized.
+ *
+ * Like `JSOP_INITLEXICAL` but for global lexicals.
+ *
+ * Category: Variables and Scopes
+ * Type: Free Variables
+ * Operands: uint32_t nameIndex
+ * Stack: val => val
*/ \
- MACRO(JSOP_EXCEPTION, 118, "exception", NULL, 1, 0, 1, JOF_BYTE) \
+ MACRO(JSOP_INITGLEXICAL, "initglexical", 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. JS doesn't
+ * need it; at the point where a binding is initialized, it's impossible
+ * for it to be shadowed.
+ *
+ * Category: Variables and Scopes
+ * Type: Aliased Variables
+ * Operands: uint8_t hops, uint24_t slot
+ * Stack: v => v
+ */ \
+ MACRO(JSOP_INITALIASEDLEXICAL, "initaliasedlexical", NULL, 5, 1, 1, JOF_ENVCOORD|JOF_NAME|JOF_PROPINIT|JOF_DETECTING) \
/*
- * Embedded lineno to speedup 'pc->line' mapping.
- *
- * Category: Other
- * Operands: uint32_t lineno
+ * Throw a ReferenceError if the optimized local `localno` is
+ * uninitialized.
+ *
+ * `localno` must be the number of a fixed slot in the current stack frame
+ * previously initialized or marked uninitialized using `JSOP_INITLEXICAL`.
+ *
+ * Typically used before `JSOP_GETLOCAL` or `JSOP_SETLOCAL`.
+ *
+ * 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: Local Variables
+ * Operands: uint24_t localno
* Stack: =>
*/ \
- MACRO(JSOP_LINENO, 119, "lineno", NULL, 5, 0, 0, JOF_UINT32) \
- /*
- */ \
- MACRO(JSOP_UNUSED120, 120, "unused", NULL, 1, 0, 0, JOF_BYTE) \
- /*
- * Pops the top two values on the stack as 'val' and 'cond'. If 'cond' is
- * 'true', jumps to a 32-bit offset from the current bytecode, re-pushes
- * 'val' onto the stack if 'false'.
- *
- * Category: Statements
- * Type: Switch Statement
- * Operands: int32_t offset
- * Stack: val, cond => val(if !cond)
- */ \
- MACRO(JSOP_CASE, 121, "case", NULL, 5, 2, 1, JOF_JUMP) \
+ MACRO(JSOP_CHECKLEXICAL, "checklexical", NULL, 4, 0, 0, JOF_LOCAL|JOF_NAME) \
/*
- * This appears after all cases in a JSOP_CONDSWITCH, whether there is a
- * 'default:' label in the switch statement or not. Pop the switch operand
- * from the stack and jump to a 32-bit offset from the current bytecode.
- * offset from the current bytecode.
- *
- * Category: Statements
- * Type: Switch Statement
- * Operands: int32_t offset
- * Stack: lval =>
- */ \
- MACRO(JSOP_DEFAULT, 122, "default", NULL, 5, 1, 0, JOF_JUMP) \
- /*
- * Invokes 'eval' with 'args' and pushes return value onto the stack.
- *
- * If 'eval' in global scope is not original one, invokes the function with
- * 'this' and 'args', and pushes return value onto the stack.
- *
- * Category: Statements
- * Type: Function
- * Operands: uint16_t argc
- * Stack: callee, this, args[0], ..., args[argc-1] => rval
- * nuses: (argc+2)
+ * Like `JSOP_CHECKLEXICAL` but for aliased bindings.
+ *
+ * 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: Aliased Variables
+ * Operands: uint8_t hops, uint24_t slot
+ * Stack: =>
*/ \
- MACRO(JSOP_EVAL, 123, "eval", NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_TYPESET|JOF_CHECKSLOPPY|JOF_IC) \
+ MACRO(JSOP_CHECKALIASEDLEXICAL, "checkaliasedlexical", NULL, 5, 0, 0, JOF_ENVCOORD|JOF_NAME) \
/*
- * Invokes 'eval' with 'args' and pushes return value onto the stack.
- *
- * If 'eval' in global scope is not original one, invokes the function with
- * 'this' and 'args', and pushes return value onto the stack.
- *
- * Category: Statements
- * Type: Function
- * Operands: uint16_t argc
- * Stack: callee, this, args[0], ..., args[argc-1] => rval
- * nuses: (argc+2)
- */ \
- MACRO(JSOP_STRICTEVAL, 124, "strict-eval", NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_TYPESET|JOF_CHECKSTRICT|JOF_IC) \
- /*
- * LIKE JSOP_GETELEM but takes receiver on stack, and the propval is
- * evaluated before the obj.
- *
- * Category: Literals
- * Type: Object
+ * 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: This
* Operands:
- * Stack: receiver, propval, obj => obj[propval]
+ * Stack: this => this
*/ \
- MACRO(JSOP_GETELEM_SUPER, 125, "getelem-super", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_TYPESET|JOF_IC) \
+ MACRO(JSOP_CHECKTHIS, "checkthis", NULL, 1, 1, 1, JOF_BYTE) \
/*
- * Pushes a resumeIndex (stored as 24-bit operand) on the stack.
- *
- * Resume indexes are used for ops like JSOP_YIELD and JSOP_GOSUB.
- * JSScript and BaselineScript have lists of resume entries (one for each
- * resumeIndex); this lets the JIT resume at these ops from JIT code.
- *
- * Category: Other
- * Operands: uint24_t resumeIndex
- * Stack: => resumeIndex
+ * Push the global environment onto the stack, unless the script has a
+ * non-syntactic global scope. In that case, this acts like JSOP_BINDNAME.
+ *
+ * 'nameIndex' is only used when acting like JSOP_BINDNAME.
+ *
+ * Category: Variables and Scopes
+ * Type: Free Variables
+ * Operands: uint32_t nameIndex
+ * Stack: => global
*/ \
- MACRO(JSOP_RESUMEINDEX, 126, "resume-index", NULL, 4, 0, 1, JOF_RESUMEINDEX) \
+ MACRO(JSOP_BINDGNAME, "bindgname", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_GNAME|JOF_IC) \
/*
- * Defines the given function on the current scope.
- *
- * This is used for global scripts and also in some cases for function
- * scripts where use of dynamic scoping inhibits optimization.
+ * 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: Variables
- * Operands:
- * Stack: fun =>
+ * Operands: uint32_t nameIndex
+ * Stack: => env
+ */ \
+ MACRO(JSOP_BINDNAME, "bindname", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_IC) \
+ /*
+ * 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: Variables
+ * Operands: uint32_t nameIndex
+ * Stack: => val
*/ \
- MACRO(JSOP_DEFFUN, 127, "deffun", NULL, 1, 1, 0, JOF_BYTE) \
+ MACRO(JSOP_GETNAME, "getname", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_IC) \
+ /*
+ * 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, this acts like
+ * `JSOP_GETNAME`.
+ *
+ * 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: Free Variables
+ * Operands: uint32_t nameIndex
+ * Stack: => val
+ */ \
+ MACRO(JSOP_GETGNAME, "getgname", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_GNAME|JOF_IC) \
/*
- * Defines the new constant binding on global lexical environment.
- *
- * Throws if a binding with the same name already exists on the
- * environment, or if a var binding with the same name exists on the
- * global.
+ * Push the value of an argument that is stored in the stack frame
+ * or in an `ArgumentsObject`.
+ *
+ * Category: Variables and Scopes
+ * Type: Arguments
+ * Operands: uint16_t argno
+ * Stack: => arguments[argno]
+ */ \
+ MACRO(JSOP_GETARG, "getarg", 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: Local Variables
+ * Operands: uint24_t localno
+ * Stack: => val
+ */ \
+ MACRO(JSOP_GETLOCAL, "getlocal", NULL, 4, 0, 1, JOF_LOCAL|JOF_NAME) \
+ /*
+ * 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.
+ *
+ * `hops` and `slot` must be valid for the current scope.
+ *
+ * `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: Aliased Variables
+ * Operands: uint8_t hops, uint24_t slot
+ * Stack: => aliasedVar
+ */ \
+ MACRO(JSOP_GETALIASEDVAR, "getaliasedvar", NULL, 5, 0, 1, JOF_ENVCOORD|JOF_NAME|JOF_TYPESET|JOF_IC) \
+ /*
+ * Get the value of a module import by name and pushes it onto the stack.
*
* Category: Variables and Scopes
* Type: Variables
* Operands: uint32_t nameIndex
+ * Stack: => val
+ */ \
+ MACRO(JSOP_GETIMPORT, "getimport", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_IC) \
+ /*
+ * 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`.
+ *
+ * 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: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: env => v
+ */ \
+ MACRO(JSOP_GETBOUNDNAME, "getboundname", NULL, 5, 1, 1, JOF_ATOM|JOF_NAME|JOF_TYPESET|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: Intrinsics
+ * Operands: uint32_t nameIndex
+ * Stack: => intrinsic[name]
+ */ \
+ MACRO(JSOP_GETINTRINSIC, "getintrinsic", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_TYPESET|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: Arguments
+ * Operands:
+ * Stack: => callee
+ */ \
+ MACRO(JSOP_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.
+ *
+ * Category: Variables and Scopes
+ * Type: Arguments
+ * Operands: uint8_t numHops
+ * Stack: => callee
+ */ \
+ MACRO(JSOP_ENVCALLEE, "envcallee", 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`.
+ *
+ * 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: Variables
+ * Operands: uint32_t nameIndex
+ * Stack: env, val => val
+ */ \
+ MACRO(JSOP_SETNAME, "setname", NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSLOPPY|JOF_IC) \
+ /*
+ * 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: Variables
+ * Operands: uint32_t nameIndex
+ * Stack: env, val => val
+ */ \
+ MACRO(JSOP_STRICTSETNAME, "strict-setname", NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSTRICT|JOF_IC) \
+ /*
+ * Like `JSOP_SETNAME`, but for assigning to globals. `env` must be an
+ * environment pushed by `JSOP_BINDGNAME`.
+ *
+ * Category: Variables and Scopes
+ * Type: Free Variables
+ * Operands: uint32_t nameIndex
+ * Stack: env, val => val
+ */ \
+ MACRO(JSOP_SETGNAME, "setgname", NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_PROPSET|JOF_DETECTING|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: Free Variables
+ * Operands: uint32_t nameIndex
+ * Stack: env, val => val
+ */ \
+ MACRO(JSOP_STRICTSETGNAME, "strict-setgname", NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_PROPSET|JOF_DETECTING|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: Arguments
+ * Operands: uint16_t argno
+ * Stack: val => val
+ */ \
+ MACRO(JSOP_SETARG, "setarg", NULL, 3, 1, 1, JOF_QARG|JOF_NAME) \
+ /*
+ * Assign to an optimized local binding.
+ *
+ * Category: Variables and Scopes
+ * Type: Local Variables
+ * Operands: uint24_t localno
+ * Stack: v => v
+ */ \
+ MACRO(JSOP_SETLOCAL, "setlocal", NULL, 4, 1, 1, JOF_LOCAL|JOF_NAME|JOF_DETECTING) \
+ /*
+ * 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: Aliased Variables
+ * Operands: uint8_t hops, uint24_t slot
+ * Stack: val => val
+ */ \
+ MACRO(JSOP_SETALIASEDVAR, "setaliasedvar", NULL, 5, 1, 1, JOF_ENVCOORD|JOF_NAME|JOF_PROPSET|JOF_DETECTING) \
+ /*
+ * 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: Intrinsics
+ * Operands: uint32_t nameIndex
+ * Stack: val => val
+ */ \
+ MACRO(JSOP_SETINTRINSIC, "setintrinsic", NULL, 5, 1, 1, JOF_ATOM|JOF_NAME|JOF_DETECTING) \
+ /*
+ * Push a lexical environment onto the environment chain.
+ *
+ * The `LexicalScope` indicated by `lexicalScopeIndex` determines the shape
+ * of the new `LexicalEnvironmentObject`. 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_{PUSH,POP}VARENV` 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: Block-local Scope
+ * Operands: uint32_t lexicalScopeIndex
* Stack: =>
*/ \
- MACRO(JSOP_DEFCONST, 128, "defconst", NULL, 5, 0, 0, JOF_ATOM) \
+ MACRO(JSOP_PUSHLEXICALENV, "pushlexicalenv", NULL, 5, 0, 0, JOF_SCOPE) \
+ /*
+ * Pop a lexical environment from the environment chain.
+ *
+ * See `JSOP_PUSHLEXICALENV` for the fine print.
+ *
+ * Category: Variables and Scopes
+ * Type: Block-local Scope
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(JSOP_POPLEXICALENV, "poplexicalenv", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * 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 scope, as indicated by scope notes,
+ * must be marked with either this instruction (if the scope is optimized)
+ * or `JSOP_POPLEXICALENV` (if not).
+ *
+ * Category: Statements
+ * Type: Debugger
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(JSOP_DEBUGLEAVELEXICALENV, "debugleavelexicalenv", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Recreate 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 has a (captured) lexical declaration.
+ *
+ * Category: Variables and Scopes
+ * Type: Block-local Scope
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(JSOP_RECREATELEXICALENV, "recreatelexicalenv", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Replace the current block on the environment chain with a fresh block
+ * that copies all the bindings in the block. This implements the behavior
+ * of inducing a fresh lexical environment for every iteration of a
+ * `for(let ...; ...; ...)` loop, if any declarations induced by such a
+ * loop are captured within the loop.
+ *
+ * Category: Variables and Scopes
+ * Type: Block-local Scope
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(JSOP_FRESHENLEXICALENV, "freshenlexicalenv", NULL, 1, 0, 0, JOF_BYTE) \
/*
- * Defines the new binding on the frame's current variables-object (the
+ * Push a var environment onto the environment chain.
+ *
+ * Like `JSOP_PUSHLEXICALENV`, but pushes a `VarEnvironmentObject` rather
+ * than a `LexicalEnvironmentObject`. 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.
+ *
+ * Implements: Places in [FunctionDeclarationInstantiation][1] step 28
+ * (when *hasParameterExpressions* is true) and
+ * [IteratorBindingInitialization][2] where the "VariableEnvironment" of
+ * the "running execution context" is set to a new environment. These are
+ * all related to the weird scoping for functions that have expressions in
+ * the *FormalParameters*.
+ *
+ * Note: The spec also pushes a new VariableEnvironment on entry to every
+ * function and every strict direct `eval`, but `JSOP_PUSHVARENV` is not
+ * needed in those cases because SpiderMonkey does it as part of pushing
+ * the stack frame, before the function or eval script begins executing.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-functiondeclarationinstantiation
+ * [2]: https://tc39.es/ecma262/#sec-function-definitions-runtime-semantics-iteratorbindinginitialization
+ *
+ * Category: Variables and Scopes
+ * Type: Var Scope
+ * Operands: uint32_t scopeIndex
+ * Stack: =>
+ */ \
+ MACRO(JSOP_PUSHVARENV, "pushvarenv", NULL, 5, 0, 0, JOF_SCOPE) \
+ /*
+ * Pop a `VarEnvironmentObject` from the environment chain.
+ *
+ * See `JSOP_PUSHLEXICALENV` for the fine print.
+ *
+ * Category: Variables and Scopes
+ * Type: Var Scope
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(JSOP_POPVARENV, "popvarenv", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * 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.
+ *
+ * See `JSOP_PUSHLEXICALENV` for the fine print.
+ *
+ * [1]: https://tc39.es/ecma262/#sec-with-statement-runtime-semantics-evaluation
+ *
+ * Category: Variables and Scopes
+ * Type: With Statement
+ * Operands: uint32_t staticWithIndex
+ * Stack: val =>
+ */ \
+ MACRO(JSOP_ENTERWITH, "enterwith", 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: With Statement
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(JSOP_LEAVEWITH, "leavewith", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Push the nearest 'var' environment.
+ *
+ * Category: Variables and Scopes
+ * Type: Free Variables
+ * Operands:
+ * Stack: => env
+ */ \
+ MACRO(JSOP_BINDVAR, "bindvar", NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Create a new binding on the frame's current variables-object (the
* environment on the environment chain designated to receive new
* variables).
*
* Throws if the current variables-object is the global object and a
* binding with the same name exists on the global lexical environment.
*
* This is used for global scripts and also in some cases for function
* scripts where use of dynamic scoping inhibits optimization.
*
* Category: Variables and Scopes
* Type: Variables
* Operands: uint32_t nameIndex
* Stack: =>
*/ \
- MACRO(JSOP_DEFVAR, 129, "defvar", NULL, 5, 0, 0, JOF_ATOM) \
- /*
- * Pushes a closure for a named or anonymous function expression onto the
- * stack.
- *
- * Category: Statements
- * Type: Function
- * Operands: uint32_t funcIndex
- * Stack: => obj
- */ \
- MACRO(JSOP_LAMBDA, 130, "lambda", NULL, 5, 0, 1, JOF_OBJECT) \
- /*
- * Pops the top of stack value as 'new.target', pushes an arrow function
- * with lexical 'new.target' onto the stack.
- *
- * Category: Statements
- * Type: Function
- * Operands: uint32_t funcIndex
- * Stack: new.target => obj
- */ \
- MACRO(JSOP_LAMBDA_ARROW, 131, "lambda_arrow", NULL, 5, 1, 1, JOF_OBJECT) \
- /*
- * Pushes current callee onto the stack.
- *
- * Used for named function expression self-naming, if lightweight.
- *
- * Category: Variables and Scopes
- * Type: Arguments
- * Operands:
- * Stack: => callee
- */ \
- MACRO(JSOP_CALLEE, 132, "callee", NULL, 1, 0, 1, JOF_BYTE) \
- /*
- * Picks the nth element from the stack and moves it to the top of the
- * stack.
- *
- * Category: Operators
- * Type: 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(JSOP_PICK, 133, "pick", NULL, 2, 0, 0, JOF_UINT8) \
- /*
- * This no-op appears at the top of the bytecode for a 'TryStatement'.
- *
- * Location information for catch/finally blocks is stored in a side table,
- * 'script->trynotes()'.
- *
- * Category: Statements
- * Type: Exception Handling
- * Operands:
- * Stack: =>
- */ \
- MACRO(JSOP_TRY, 134, "try", NULL, 1, 0, 0, JOF_BYTE) \
- /*
- * This opcode has a def count of 2, but these values are already on the
- * stack (they're pushed by JSOP_GOSUB).
- *
- * Category: Statements
- * Type: Exception Handling
- * Operands:
- * Stack: => false, resumeIndex
- */ \
- MACRO(JSOP_FINALLY, 135, "finally", NULL, 1, 0, 2, JOF_BYTE) \
+ MACRO(JSOP_DEFVAR, "defvar", NULL, 5, 0, 0, JOF_ATOM) \
/*
- * Pushes aliased variable onto the stack.
- *
- * An "aliased variable" is a var, let, or formal arg that is aliased.
- * Sources of aliasing include: nested functions accessing the vars of an
- * enclosing function, function statements that are conditionally executed,
- * 'eval', 'with', and 'arguments'. All of these cases require creating a
- * CallObject to own the aliased variable.
- *
- * An ALIASEDVAR opcode contains the following immediates:
- * uint8 hops: the number of environment objects to skip to find the
- * EnvironmentObject containing the variable being accessed
- * uint24 slot: the slot containing the variable in the EnvironmentObject
- * (this 'slot' does not include RESERVED_SLOTS).
- *
- * Category: Variables and Scopes
- * Type: Aliased Variables
- * Operands: uint8_t hops, uint24_t slot
- * Stack: => aliasedVar
- */ \
- MACRO(JSOP_GETALIASEDVAR, 136, "getaliasedvar", NULL, 5, 0, 1, JOF_ENVCOORD|JOF_NAME|JOF_TYPESET|JOF_IC) \
- /*
- * Sets aliased variable as the top of stack value.
- *
- * Category: Variables and Scopes
- * Type: Aliased Variables
- * Operands: uint8_t hops, uint24_t slot
- * Stack: v => v
- */ \
- MACRO(JSOP_SETALIASEDVAR, 137, "setaliasedvar", NULL, 5, 1, 1, JOF_ENVCOORD|JOF_NAME|JOF_PROPSET|JOF_DETECTING) \
- /*
- * Checks if the value of the local variable is the
- * JS_UNINITIALIZED_LEXICAL magic, throwing an error if so.
- *
- * Category: Variables and Scopes
- * Type: Local Variables
- * Operands: uint24_t localno
- * Stack: =>
- */ \
- MACRO(JSOP_CHECKLEXICAL, 138, "checklexical", NULL, 4, 0, 0, JOF_LOCAL|JOF_NAME) \
- /*
- * Initializes an uninitialized local lexical binding with the top of stack
- * value.
- *
- * Category: Variables and Scopes
- * Type: Local Variables
- * Operands: uint24_t localno
- * Stack: v => v
- */ \
- MACRO(JSOP_INITLEXICAL, 139, "initlexical", NULL, 4, 1, 1, JOF_LOCAL|JOF_NAME|JOF_DETECTING) \
- /*
- * Checks if the value of the aliased variable is the
- * JS_UNINITIALIZED_LEXICAL magic, throwing an error if so.
- *
- * Category: Variables and Scopes
- * Type: Aliased Variables
- * Operands: uint8_t hops, uint24_t slot
- * Stack: =>
- */ \
- MACRO(JSOP_CHECKALIASEDLEXICAL, 140, "checkaliasedlexical", NULL, 5, 0, 0, JOF_ENVCOORD|JOF_NAME) \
- /*
- * Initializes an uninitialized aliased lexical binding with the top of
- * stack value.
- *
- * Category: Variables and Scopes
- * Type: Aliased Variables
- * Operands: uint8_t hops, uint24_t slot
- * Stack: v => v
- */ \
- MACRO(JSOP_INITALIASEDLEXICAL, 141, "initaliasedlexical", NULL, 5, 1, 1, JOF_ENVCOORD|JOF_NAME|JOF_PROPINIT|JOF_DETECTING) \
- /*
- * Pushes a JS_UNINITIALIZED_LEXICAL value onto the stack, representing an
- * uninitialized lexical binding.
- *
- * This opcode is used with the JSOP_INITLEXICAL opcode.
- *
- * Category: Literals
- * Type: Constants
- * Operands:
- * Stack: => uninitialized
- */ \
- MACRO(JSOP_UNINITIALIZED, 142, "uninitialized", NULL, 1, 0, 1, JOF_BYTE) \
- /*
- * Pushes the value of the intrinsic onto the stack.
- *
- * Intrinsic names are emitted instead of JSOP_*NAME ops when the
- * 'CompileOptions' flag 'selfHostingMode' is set.
- *
- * They are used in self-hosted code to access other self-hosted values and
- * intrinsic functions the runtime doesn't give client JS code access to.
- *
- * Category: Variables and Scopes
- * Type: Intrinsics
- * Operands: uint32_t nameIndex
- * Stack: => intrinsic[name]
- */ \
- MACRO(JSOP_GETINTRINSIC, 143, "getintrinsic", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_IC) \
- /*
- * Stores the top stack value in the specified intrinsic.
+ * Create a new binding for the given function on the current scope.
+ *
+ * This is used for global scripts and also in some cases for function
+ * scripts where use of dynamic scoping inhibits optimization.
*
* Category: Variables and Scopes
- * Type: Intrinsics
- * Operands: uint32_t nameIndex
- * Stack: val => val
+ * Type: Variables
+ * Operands:
+ * Stack: fun =>
*/ \
- MACRO(JSOP_SETINTRINSIC, 144, "setintrinsic", NULL, 5, 1, 1, JOF_ATOM|JOF_NAME|JOF_DETECTING) \
- /*
- * Like JSOP_CALL, but used as part of for-of and destructuring bytecode to
- * provide better error messages.
- *
- * Category: Statements
- * Type: Function
- * Operands: uint16_t argc (must be 0)
- * Stack: callee, this => rval
- * nuses: 2
- */ \
- MACRO(JSOP_CALLITER, 145, "calliter", NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_TYPESET|JOF_IC) \
+ MACRO(JSOP_DEFFUN, "deffun", NULL, 1, 1, 0, JOF_BYTE) \
/*
- * Initialize a non-configurable, non-writable, non-enumerable
- * data-property on an object.
- *
- * Pops the top two values on the stack as 'val' and 'obj', defines
- * 'nameIndex' property of 'obj' as 'val', pushes 'obj' onto the stack.
- *
- * Category: Literals
- * Type: Object
- * Operands: uint32_t nameIndex
- * Stack: obj, val => obj
- */ \
- MACRO(JSOP_INITLOCKEDPROP, 146, "initlockedprop", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT|JOF_DETECTING|JOF_IC) \
- /*
- * Initialize a non-enumerable data-property on an object.
- *
- * Pops the top two values on the stack as 'val' and 'obj', defines
- * 'nameIndex' property of 'obj' as 'val', pushes 'obj' onto the stack.
- *
- * Category: Literals
- * Type: Object
- * Operands: uint32_t nameIndex
- * Stack: obj, val => obj
- */ \
- MACRO(JSOP_INITHIDDENPROP, 147, "inithiddenprop", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT|JOF_DETECTING|JOF_IC) \
- /*
- * Push "new.target"
+ * Create a new mutable binding in the global lexical environment. Throw a
+ * SyntaxError if a binding with the same name already exists on that
+ * environment, or if a var binding with the same name exists on the
+ * global.
*
* Category: Variables and Scopes
- * Type: Arguments
- * Operands:
- * Stack: => new.target
- */ \
- MACRO(JSOP_NEWTARGET, 148, "newtarget", NULL, 1, 0, 1, JOF_BYTE) \
- /*
- */ \
- MACRO(JSOP_UNUSED149, 149, "unused149", NULL, 1, 0, 0, JOF_BYTE) \
- /*
- * Pops the top two values 'lval' and 'rval' from the stack, then pushes
- * the result of 'Math.pow(lval, rval)'.
- *
- * Category: Operators
- * Type: Arithmetic Operators
- * Operands:
- * Stack: lval, rval => (lval ** rval)
- */ \
- MACRO(JSOP_POW, 150, "pow", "**", 1, 2, 1, JOF_BYTE|JOF_IC) \
- /*
- * Pops the top two values 'value' and 'gen' from the stack, then starts
- * "awaiting" for 'value' to be resolved, which will then resume the
- * execution of 'gen'. Pushes the async function promise on the stack, so
- * that it'll be returned to the caller on the very first "await".
- *
- * Category: Statements
- * Type: Generator
- * Operands:
- * Stack: value, gen => promise
- */ \
- MACRO(JSOP_ASYNCAWAIT, 151, "async-await", NULL, 1, 2, 1, JOF_BYTE) \
- /*
- * Pops the top of stack value as 'rval', sets the return value in stack
- * frame as 'rval'.
- *
- * Category: Statements
- * Type: Function
- * Operands:
- * Stack: rval =>
- */ \
- MACRO(JSOP_SETRVAL, 152, "setrval", NULL, 1, 1, 0, JOF_BYTE) \
- /*
- * Stops interpretation and returns value set by JSOP_SETRVAL. When not
- * set, returns 'undefined'.
- *
- * Also emitted at end of script so interpreter don't need to check if
- * opcode is still in script range.
- *
- * Category: Statements
- * Type: Function
- * Operands:
+ * Type: Variables
+ * Operands: uint32_t nameIndex
* Stack: =>
*/ \
- MACRO(JSOP_RETRVAL, 153, "retrval", NULL, 1, 0, 0, JOF_BYTE) \
- /*
- * Looks up name on global environment and pushes its value onto the stack,
- * unless the script has a non-syntactic global scope, in which case it
- * acts just like JSOP_NAME.
- *
- * Free variable references that must either be found on the global or a
- * ReferenceError.
- *
- * Category: Variables and Scopes
- * Type: Free Variables
- * Operands: uint32_t nameIndex
- * Stack: => val
- */ \
- MACRO(JSOP_GETGNAME, 154, "getgname", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_GNAME|JOF_IC) \
- /*
- * Pops the top two values on the stack as 'val' and 'env', sets property
- * of 'env' as 'val' and pushes 'val' back on the stack.
- *
- * 'env' should be the global lexical environment unless the script has a
- * non-syntactic global scope, in which case acts like JSOP_SETNAME.
- *
- * Category: Variables and Scopes
- * Type: Free Variables
- * Operands: uint32_t nameIndex
- * Stack: env, val => val
- */ \
- MACRO(JSOP_SETGNAME, 155, "setgname", NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_PROPSET|JOF_DETECTING|JOF_GNAME|JOF_CHECKSLOPPY|JOF_IC) \
- /*
- * Pops the top two values on the stack as 'val' and 'env', sets property
- * of 'env' as 'val' and pushes 'val' back on the stack. Throws a TypeError
- * if the set fails, per strict mode semantics.
- *
- * 'env' should be the global lexical environment unless the script has a
- * non-syntactic global scope, in which case acts like JSOP_STRICTSETNAME.
- *
- * Category: Variables and Scopes
- * Type: Free Variables
- * Operands: uint32_t nameIndex
- * Stack: env, val => val
- */ \
- MACRO(JSOP_STRICTSETGNAME, 156, "strict-setgname", NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_PROPSET|JOF_DETECTING|JOF_GNAME|JOF_CHECKSTRICT|JOF_IC) \
+ MACRO(JSOP_DEFLET, "deflet", NULL, 5, 0, 0, JOF_ATOM) \
/*
- * Pushes the implicit 'this' value for calls to the associated name onto
- * the stack; only used when the implicit this might be derived from a
- * non-syntactic scope (instead of the global itself).
- *
- * Note that code evaluated via the Debugger API uses DebugEnvironmentProxy
- * objects on its scope chain, which are non-syntactic environments that
- * refer to syntactic environments. As a result, the binding we want may be
- * held by a syntactic environments such as CallObject or
- * VarEnvrionmentObject.
- *
- * Category: Variables and Scopes
- * Type: This
- * Operands: uint32_t nameIndex
- * Stack: => this
- */ \
- MACRO(JSOP_GIMPLICITTHIS, 157, "gimplicitthis", "", 5, 0, 1, JOF_ATOM) \
- /*
- * LIKE JSOP_SETELEM, but takes receiver on the stack, and the propval is
- * evaluated before the base.
- *
- * Category: Literals
- * Type: Object
- * Operands:
- * Stack: receiver, propval, obj, val => val
- */ \
- MACRO(JSOP_SETELEM_SUPER, 158, "setelem-super", NULL, 1, 4, 1, JOF_BYTE|JOF_ELEM|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSLOPPY) \
- /*
- * LIKE JSOP_STRICTSETELEM, but takes receiver on the stack, and the
- * propval is evaluated before the base.
- *
- * Category: Literals
- * Type: Object
- * Operands:
- * Stack: receiver, propval, obj, val => val
- */ \
- MACRO(JSOP_STRICTSETELEM_SUPER, 159, "strict-setelem-super", NULL, 1, 4, 1, JOF_BYTE|JOF_ELEM|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSTRICT) \
- /*
- * Pushes a regular expression literal onto the stack. It requires special
- * "clone on exec" handling.
- *
- * Category: Literals
- * Type: RegExp
- * Operands: uint32_t regexpIndex
- * Stack: => regexp
- */ \
- MACRO(JSOP_REGEXP, 160, "regexp", NULL, 5, 0, 1, JOF_REGEXP) \
- /*
- * Initializes an uninitialized global lexical binding with the top of
- * stack value.
- *
- * Category: Variables and Scopes
- * Type: Free Variables
- * Operands: uint32_t nameIndex
- * Stack: val => val
- */ \
- MACRO(JSOP_INITGLEXICAL, 161, "initglexical", NULL, 5, 1, 1, JOF_ATOM|JOF_NAME|JOF_PROPINIT|JOF_GNAME|JOF_IC) \
- /*
- * Defines the new mutable binding on global lexical environment.
+ * Create a new constant binding in the global lexical environment.
*
* Throws if a binding with the same name already exists on the
* environment, or if a var binding with the same name exists on the
* global.
*
* Category: Variables and Scopes
* Type: Variables
* Operands: uint32_t nameIndex
* Stack: =>
*/ \
- MACRO(JSOP_DEFLET, 162, "deflet", NULL, 5, 0, 0, JOF_ATOM) \
- /*
- * Throw if the value on the stack is not coerscible to an object (is
- * |null| or |undefined|).
- *
- * Category: Literals
- * Type: Object
- * Operands:
- * Stack: val => val
- */ \
- MACRO(JSOP_CHECKOBJCOERCIBLE, 163, "checkobjcoercible", NULL, 1, 1, 1, JOF_BYTE) \
- /*
- * Push the function to invoke with |super()|. This is the prototype of the
- * function passed in as |callee|.
- *
- * Category: Variables and Scopes
- * Type: Super
- * Operands:
- * Stack: callee => superFun
- */ \
- MACRO(JSOP_SUPERFUN, 164, "superfun", NULL, 1, 1, 1, JOF_BYTE) \
- /*
- * Behaves exactly like JSOP_NEW, but allows JITs to distinguish the two
- * cases.
- *
- * Category: Statements
- * Type: Function
- * Operands: uint16_t argc
- * Stack: callee, this, args[0], ..., args[argc-1], newTarget => rval
- * nuses: (argc+3)
- */ \
- MACRO(JSOP_SUPERCALL, 165, "supercall", NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_TYPESET|JOF_IC) \
- /*
- * spreadcall variant of JSOP_SUPERCALL.
- *
- * Behaves exactly like JSOP_SPREADNEW.
- *
- * Category: Statements
- * Type: Function
- * Operands:
- * Stack: callee, this, args, newTarget => rval
- */ \
- MACRO(JSOP_SPREADSUPERCALL, 166, "spreadsupercall", NULL, 1, 4, 1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET|JOF_IC) \
- /*
- * Push a default constructor for a base class literal.
- *
- * Category: Literals
- * Type: Class
- * Operands: atom className
- * Stack: => constructor
- */ \
- MACRO(JSOP_CLASSCONSTRUCTOR, 167, "classconstructor", NULL, 5, 0, 1, JOF_ATOM) \
- /*
- * Push a default constructor for a derived class literal.
- *
- * Category: Literals
- * Type: Class
- * Operands: atom className
- * Stack: proto => constructor
- */ \
- MACRO(JSOP_DERIVEDCONSTRUCTOR, 168, "derivedconstructor", NULL, 5, 1, 1, JOF_ATOM) \
- /*
- * Throws a runtime TypeError for invalid assignment to 'const'. The
- * localno is used for better error messages.
- *
- * Category: Variables and Scopes
- * Type: Local Variables
- * Operands: uint24_t localno
- * Stack: v => v
- */ \
- MACRO(JSOP_THROWSETCONST, 169, "throwsetconst", NULL, 4, 1, 1, JOF_LOCAL|JOF_NAME|JOF_DETECTING) \
+ MACRO(JSOP_DEFCONST, "defconst", NULL, 5, 0, 0, JOF_ATOM) \
/*
- * Throws a runtime TypeError for invalid assignment to 'const'. The
- * environment coordinate is used for better error messages.
- *
- * Category: Variables and Scopes
- * Type: Aliased Variables
- * Operands: uint8_t hops, uint24_t slot
- * Stack: v => v
- */ \
- MACRO(JSOP_THROWSETALIASEDCONST, 170, "throwsetaliasedconst", NULL, 5, 1, 1, JOF_ENVCOORD|JOF_NAME|JOF_DETECTING) \
- /*
- * Initialize a non-enumerable getter in an object literal.
- *
- * Pops the top two values on the stack as 'val' and 'obj', defines getter
- * of 'obj' as 'val', pushes 'obj' onto the stack.
- *
- * Category: Literals
- * Type: Object
- * Operands: uint32_t nameIndex
- * Stack: obj, val => obj
- */ \
- MACRO(JSOP_INITHIDDENPROP_GETTER, 171, "inithiddenprop_getter", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT|JOF_DETECTING) \
- /*
- * Initialize a non-enumerable setter in an object literal.
- *
- * Pops the top two values on the stack as 'val' and 'obj', defines setter
- * of 'obj' as 'val', pushes 'obj' onto the stack.
- *
- * Category: Literals
- * Type: Object
- * Operands: uint32_t nameIndex
- * Stack: obj, val => obj
- */ \
- MACRO(JSOP_INITHIDDENPROP_SETTER, 172, "inithiddenprop_setter", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_PROPINIT|JOF_DETECTING) \
- /*
- * Initialize a non-enumerable numeric getter in an object literal like
- * '{get 2() {}}'.
- *
- * Pops the top three values on the stack as 'val', 'id' and 'obj', defines
- * 'id' getter of 'obj' as 'val', pushes 'obj' onto the stack.
- *
- * Category: Literals
- * Type: Object
- * Operands:
- * Stack: obj, id, val => obj
- */ \
- MACRO(JSOP_INITHIDDENELEM_GETTER, 173, "inithiddenelem_getter", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_DETECTING) \
- /*
- * Initialize a non-enumerable numeric setter in an object literal like
- * '{set 2(v) {}}'.
- *
- * Pops the top three values on the stack as 'val', 'id' and 'obj', defines
- * 'id' setter of 'obj' as 'val', pushes 'obj' onto the stack.
- *
- * Category: Literals
- * Type: Object
- * Operands:
- * Stack: obj, id, val => obj
- */ \
- MACRO(JSOP_INITHIDDENELEM_SETTER, 174, "inithiddenelem_setter", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_DETECTING) \
- /*
- * Initialize a non-enumerable numeric property in an object literal, like
- * '{1: x}'.
- *
- * Pops the top three values on the stack as 'val', 'id' and 'obj', defines
- * 'id' property of 'obj' as 'val', pushes 'obj' onto the stack.
- *
- * Category: Literals
- * Type: Object
- * Operands:
- * Stack: obj, id, val => obj
- */ \
- MACRO(JSOP_INITHIDDENELEM, 175, "inithiddenelem", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_DETECTING|JOF_IC) \
- /*
- * Gets the value of a module import by name and pushes it onto the stack.
+ * 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: Variables
* Operands: uint32_t nameIndex
- * Stack: => val
- */ \
- MACRO(JSOP_GETIMPORT, 176, "getimport", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_IC) \
- /*
- * Examines the top stack value, asserting that it's either a self-hosted
- * function or a self-hosted intrinsic. This opcode does nothing in a
- * non-debug build.
- *
- * Category: Other
- * Operands:
- * Stack: checkVal => checkVal
- */ \
- MACRO(JSOP_DEBUGCHECKSELFHOSTED, 177, "debug-checkselfhosted", NULL, 1, 1, 1, JOF_BYTE) \
- /*
- * Pops the top stack value, pushes the value and a boolean value that
- * indicates whether the spread operation for the value can be optimized in
- * spread call.
- *
- * Category: Statements
- * Type: Function
- * Operands:
- * Stack: arr => arr, optimized
+ * Stack: => succeeded
*/ \
- MACRO(JSOP_OPTIMIZE_SPREADCALL, 178, "optimize-spreadcall", NULL, 1, 1, 2, JOF_BYTE) \
+ MACRO(JSOP_DELNAME, "delname", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_CHECKSLOPPY) \
/*
- * Throws a runtime TypeError for invalid assignment to the callee in a
- * named lambda, which is always a 'const' binding. This is a different
- * bytecode than JSOP_SETCONST because the named lambda callee, if not
- * closed over, does not have a frame slot to look up the name with for the
- * error message.
- *
- * Category: Variables and Scopes
- * Type: Local Variables
- * Operands:
- * Stack: v => v
- */ \
- MACRO(JSOP_THROWSETCALLEE, 179, "throwsetcallee", NULL, 1, 1, 1, JOF_BYTE) \
- /*
- * Pushes a var environment onto the env chain.
- *
- * Category: Variables and Scopes
- * Type: Var Scope
- * Operands: uint32_t scopeIndex
- * Stack: =>
- */ \
- MACRO(JSOP_PUSHVARENV, 180, "pushvarenv", NULL, 5, 0, 0, JOF_SCOPE) \
- /*
- * Pops a var environment from the env chain.
+ * 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. The function must not have
+ * a rest parameter. This instruction must execute at most once per
+ * function activation.
+ *
+ * #### Optimized arguments
+ *
+ * If `script->needsArgsObj()` is false, no ArgumentsObject is created.
+ * Instead, `MagicValue(JS_OPTIMIZED_ARGUMENTS)` is pushed.
+ *
+ * This optimization imposes no restrictions on bytecode. Rather,
+ * `js::jit::AnalyzeArgumentsUsage` examines the bytecode and enables the
+ * optimization only if all uses of `arguments` are optimizable. Each
+ * execution engine must know what the analysis considers optimizable and
+ * cope with the magic value when it is used in those ways.
+ *
+ * Example 1: `arguments[0]` is supported; therefore the interpreter's
+ * implementation of `JSOP_GETELEM` checks for optimized arguments (see
+ * `GetElemOptimizedArguments`).
+ *
+ * Example 2: `f.apply(this, arguments)` is supported; therefore our
+ * implementation of `Function.prototype.apply` checks for optimized
+ * arguments (`see js::fun_apply`), and all `JSOP_FUNAPPLY` implementations
+ * must check for cases where `f.apply` turns out to be any other function
+ * (see `GuardFunApplyArgumentsOptimization`).
+ *
+ * It's not documented anywhere exactly which opcodes support
+ * `JS_OPTIMIZED_ARGUMENTS`; see the source of `AnalyzeArgumentsUsage`.
*
* Category: Variables and Scopes
- * Type: Var Scope
+ * Type: Arguments
* Operands:
- * Stack: =>
+ * Stack: => arguments
*/ \
- MACRO(JSOP_POPVARENV, 181, "popvarenv", NULL, 1, 0, 0, JOF_BYTE) \
- /*
- * Pops the top two values on the stack as 'name' and 'fun', defines the
- * name of 'fun' to 'name' with prefix if any, and pushes 'fun' back onto
- * the stack.
- *
- * Category: Statements
- * Type: Function
- * Operands: uint8_t prefixKind
- * Stack: fun, name => fun
- */ \
- MACRO(JSOP_SETFUNNAME, 182, "setfunname", NULL, 2, 2, 1, JOF_UINT8) \
+ MACRO(JSOP_ARGUMENTS, "arguments", NULL, 1, 0, 1, JOF_BYTE) \
/*
- * Moves the top of the stack value under the nth element of the stack.
- * Note: n must NOT be 0.
- *
- * Category: Operators
- * Type: 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(JSOP_UNPICK, 183, "unpick", NULL, 2, 0, 0, JOF_UINT8) \
- /*
- * Pops the top of stack value, pushes property of it onto the stack.
- * Requires the value under 'obj' to be the receiver of the following call.
- *
- * Like JSOP_GETPROP but for call context.
- *
- * Category: Literals
- * Type: Object
- * Operands: uint32_t nameIndex
- * Stack: obj => obj[name]
- */ \
- MACRO(JSOP_CALLPROP, 184, "callprop", NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_TYPESET|JOF_IC) \
- /*
- * Determines the 'this' value for current function frame and pushes it
- * onto the stack. Emitted in the prologue of functions with a
- * this-binding.
+ * Create and push the rest parameter array for current function call.
+ *
+ * This must appear only in function scripts.
*
* Category: Variables and Scopes
- * Type: This
+ * Type: Arguments
* Operands:
- * Stack: => this
+ * Stack: => rest
*/ \
- MACRO(JSOP_FUNCTIONTHIS, 185, "functionthis", NULL, 1, 0, 1, JOF_BYTE) \
+ MACRO(JSOP_REST, "rest", NULL, 1, 0, 1, JOF_BYTE|JOF_TYPESET|JOF_IC) \
/*
- * Pushes 'this' value for current stack frame onto the stack. Emitted when
- * 'this' refers to the global 'this'.
+ * 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.
*
* Category: Variables and Scopes
* Type: This
* Operands:
* Stack: => this
*/ \
- MACRO(JSOP_GLOBALTHIS, 186, "globalthis", NULL, 1, 0, 1, JOF_BYTE) \
+ MACRO(JSOP_FUNCTIONTHIS, "functionthis", NULL, 1, 0, 1, JOF_BYTE) \
/*
- * Pushes a boolean indicating whether the top of the stack is
- * MagicValue(JS_GENERATOR_CLOSING).
- *
- * Category: Statements
- * Type: For-In Statement
+ * Pop the top value from the stack and discard it.
+ *
+ * Category: Operators
+ * Type: Stack Operations
* Operands:
- * Stack: val => val, res
+ * Stack: v =>
*/ \
- MACRO(JSOP_ISGENCLOSING, 187, "isgenclosing", NULL, 1, 1, 2, JOF_BYTE) \
- /*
- * Pushes unsigned 24-bit int immediate integer operand onto the stack.
- *
- * Category: Literals
- * Type: Constants
- * Operands: uint24_t val
- * Stack: => val
- */ \
- MACRO(JSOP_UINT24, 188, "uint24", NULL, 4, 0, 1, JOF_UINT24) \
+ MACRO(JSOP_POP, "pop", NULL, 1, 1, 0, JOF_BYTE) \
/*
- * Throw if the value on top of the stack is the TDZ MagicValue. Used in
- * derived class constructors.
- *
- * Category: Variables and Scopes
- * Type: This
- * Operands:
- * Stack: this => this
+ * Pop the top `n` values from the stack. `n` must be <= the current stack
+ * depth.
+ *
+ * Category: Operators
+ * Type: Stack Operations
+ * Operands: uint16_t n
+ * Stack: v[n-1], ..., v[1], v[0] =>
+ * nuses: n
*/ \
- MACRO(JSOP_CHECKTHIS, 189, "checkthis", NULL, 1, 1, 1, JOF_BYTE) \
- /*
- * Check if a derived class constructor has a valid return value and 'this'
- * value before it returns. If the return value is not an object, stores
- * the 'this' value to the return value slot.
- *
- * Category: Variables and Scopes
- * Type: This
- * Operands:
- * Stack: this =>
- */ \
- MACRO(JSOP_CHECKRETURN, 190, "checkreturn", NULL, 1, 1, 0, JOF_BYTE) \
- /*
- * Throw an exception if the value on top of the stack is not the TDZ
- * MagicValue. Used in derived class constructors.
- *
- * Category: Variables and Scopes
- * Type: This
- * Operands:
- * Stack: this => this
- */ \
- MACRO(JSOP_CHECKTHISREINIT, 191, "checkthisreinit", NULL, 1, 1, 1, JOF_BYTE) \
+ MACRO(JSOP_POPN, "popn", NULL, 3, -1, 0, JOF_UINT16) \
/*
- * Pops the top two values 'valueOrReason' and 'gen' from the stack, then
- * pushes the promise resolved with 'valueOrReason'. `gen` must be the
- * internal generator object created in async functions. The pushed promise
- * is the async function's result promise, which is stored in `gen`.
- *
- * Category: Statements
- * Type: Generator
- * Operands: uint8_t fulfillOrReject
- * Stack: valueOrReason, gen => promise
+ * Push a copy of the top value on the stack.
+ *
+ * See the comment on JSOP_SWAP for an example.
+ *
+ * Category: Operators
+ * Type: Stack Operations
+ * Operands:
+ * Stack: v => v, v
*/ \
- MACRO(JSOP_ASYNCRESOLVE, 192, "async-resolve", NULL, 2, 2, 1, JOF_UINT8) \
- /*
- * Pops the top two values on the stack as 'propval' and 'obj', pushes
- * 'propval' property of 'obj' onto the stack. Requires the value under
- * 'obj' to be the receiver of the following call.
- *
- * Like JSOP_GETELEM but for call context.
- *
- * Category: Literals
- * Type: Object
- * Operands:
- * Stack: obj, propval => obj[propval]
- */ \
- MACRO(JSOP_CALLELEM, 193, "callelem", NULL, 1, 2, 1, JOF_BYTE|JOF_ELEM|JOF_TYPESET|JOF_IC) \
+ MACRO(JSOP_DUP, "dup", NULL, 1, 1, 2, JOF_BYTE) \
/*
- * '__proto__: v' inside an object initializer.
- *
- * Pops the top two values on the stack as 'newProto' and 'obj', sets
- * prototype of 'obj' as 'newProto', pushes 'true' onto the stack if
- * succeeded, 'false' if not.
- *
- * Category: Literals
- * Type: Object
+ * Duplicate the top two values on the stack.
+ *
+ * Category: Operators
+ * Type: Stack Operations
* Operands:
- * Stack: obj, newProto => succeeded
+ * Stack: v1, v2 => v1, v2, v1, v2
*/ \
- MACRO(JSOP_MUTATEPROTO, 194, "mutateproto", NULL, 1, 2, 1, JOF_BYTE) \
+ MACRO(JSOP_DUP2, "dup2", NULL, 1, 2, 4, JOF_BYTE) \
/*
- * Pops an environment, gets the value of a bound name on it. If the name
- * is not bound to the environment, throw a ReferenceError. Used in
- * conjunction with BINDNAME.
- *
- * Category: Literals
- * Type: Object
- * Operands: uint32_t nameIndex
- * Stack: env => v
- */ \
- MACRO(JSOP_GETBOUNDNAME, 195, "getboundname", NULL, 5, 1, 1, JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_IC) \
- /*
- * Pops the top stack value as 'val' and pushes 'typeof val'. Note that
- * this opcode isn't used when, in the original source code, 'val' is a
- * name -- see 'JSOP_TYPEOF' for that.
- * (This is because 'typeof undefinedName === "undefined"'.)
+ * Push a copy of the nth value from the top of the stack.
+ *
+ * `n` must be less than the current stack depth.
*
* Category: Operators
- * Type: Special Operators
- * Operands:
- * Stack: val => (typeof val)
+ * Type: 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(JSOP_TYPEOFEXPR, 196, "typeofexpr", NULL, 1, 1, 1, JOF_BYTE|JOF_DETECTING|JOF_IC) \
+ MACRO(JSOP_DUPAT, "dupat", NULL, 4, 0, 1, JOF_UINT24) \
/*
- * Replaces the current block on the env chain with a fresh block that
- * copies all the bindings in the block. This operation implements the
- * behavior of inducing a fresh lexical environment for every iteration of
- * a for(let ...; ...; ...) loop, if any declarations induced by such a
- * loop are captured within the loop.
- *
- * Category: Variables and Scopes
- * Type: Block-local Scope
+ * Swap the top two values on the stack.
+ *
+ * Stack machines are well suited to arithmetic, but anything more advanced
+ * inevitably involves multiple temporary values that are not used in
+ * strict FIFO order. Stack operations such as JSOP_SWAP exist to get the
+ * stack values in the desired order for a later instruction.
+ *
+ * One use of JSOP_SWAP is to implement JS method calls like `obj.m()`.
+ * Since the JSOP_CALL instruction requires the stack to look like `func,
+ * obj`, with `obj` on top, the bytecode for this is: `GETLOCAL obj; DUP;
+ * CALLPROP "m"; SWAP; CALL 0`.
+ *
+ * Category: Operators
+ * Type: Stack Operations
+ * Operands:
+ * Stack: v1, v2 => v2, v1
+ */ \
+ MACRO(JSOP_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: Operators
+ * Type: 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(JSOP_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: Operators
+ * Type: 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(JSOP_UNPICK, "unpick", NULL, 2, 0, 0, JOF_UINT8) \
+ /*
+ * Do nothing.
+ *
+ * Category: Other
* Operands:
* Stack: =>
*/ \
- MACRO(JSOP_FRESHENLEXICALENV, 197, "freshenlexicalenv", NULL, 1, 0, 0, JOF_BYTE) \
+ MACRO(JSOP_NOP, "nop", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * No-op instruction used to speed up 'pc->line' mapping.
+ *
+ * Category: Other
+ * Operands: uint32_t lineno
+ * Stack: =>
+ */ \
+ MACRO(JSOP_LINENO, "lineno", NULL, 5, 0, 0, JOF_UINT32) \
/*
- * Recreates the current block on the env chain with a fresh block with
- * uninitialized bindings. This operation implements the behavior of
- * inducing a fresh lexical environment for every iteration of a for-in/of
- * loop whose loop-head has a (captured) lexical declaration.
- *
- * Category: Variables and Scopes
- * Type: Block-local Scope
+ * No-op instruction used by the decompiler to produce nicer error messages
+ * about destructuring code.
+ *
+ * Category: Other
+ * Operands:
+ * Stack: =>
+ */ \
+ MACRO(JSOP_NOP_DESTRUCTURING, "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(JSOP_RECREATELEXICALENV, 198, "recreatelexicalenv", NULL, 1, 0, 0, JOF_BYTE) \
+ MACRO(JSOP_FORCEINTERPRETER, "forceinterpreter", NULL, 1, 0, 0, JOF_BYTE) \
/*
- * Pushes lexical environment onto the env chain.
- *
- * Category: Variables and Scopes
- * Type: Block-local Scope
- * Operands: uint32_t scopeIndex
- * Stack: =>
+ * 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(JSOP_PUSHLEXICALENV, 199, "pushlexicalenv", NULL, 5, 0, 0, JOF_SCOPE) \
+ MACRO(JSOP_DEBUGCHECKSELFHOSTED, "debug-checkselfhosted", NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Push a boolean indicating if instrumentation is active.
+ *
+ * Category: Other
+ * Operands:
+ * Stack: => val
+ */ \
+ MACRO(JSOP_INSTRUMENTATION_ACTIVE, "instrumentationActive", NULL, 1, 0, 1, JOF_BYTE) \
/*
- * Pops lexical environment from the env chain.
- *
- * Category: Variables and Scopes
- * Type: Block-local Scope
+ * Push the instrumentation callback for the current realm.
+ *
+ * Category: Other
+ * Operands:
+ * Stack: => val
+ */ \
+ MACRO(JSOP_INSTRUMENTATION_CALLBACK, "instrumentationCallback", NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Push the current script's instrumentation ID.
+ *
+ * Category: Other
* Operands:
- * Stack: =>
+ * Stack: => val
*/ \
- MACRO(JSOP_POPLEXICALENV, 200, "poplexicalenv", NULL, 1, 0, 0, JOF_BYTE) \
+ MACRO(JSOP_INSTRUMENTATION_SCRIPT_ID, "instrumentationScriptId", NULL, 1, 0, 1, JOF_BYTE) \
/*
- * The opcode to assist the debugger.
+ * Invoke the debugger.
+ *
+ * The [`Debugger` API][1] offers a way to pause execution and get a
+ * callback when this instruction runs.
+ *
+ * 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: Statements
* Type: Debugger
* Operands:
* Stack: =>
*/ \
- MACRO(JSOP_DEBUGLEAVELEXICALENV, 201, "debugleavelexicalenv", NULL, 1, 0, 0, JOF_BYTE) \
- /*
- * Pops the generator from the top of the stack, suspends it and stops
- * interpretation.
- *
- * Category: Statements
- * Type: Generator
- * Operands: uint24_t resumeIndex
- * Stack: generator => generator
- */ \
- MACRO(JSOP_INITIALYIELD, 202, "initialyield", NULL, 4, 1, 1, JOF_RESUMEINDEX) \
- /*
- * Pops the generator and the return value 'rval1', stops interpretation
- * and returns 'rval1'. Pushes sent value from 'send()' onto the stack.
- *
- * Category: Statements
- * Type: Generator
- * Operands: uint24_t resumeIndex
- * Stack: rval1, gen => rval2
- */ \
- MACRO(JSOP_YIELD, 203, "yield", NULL, 4, 2, 1, JOF_RESUMEINDEX) \
- /*
- * Pops the generator and suspends and closes it. Yields the value in the
- * frame's return value slot.
- *
- * Category: Statements
- * Type: Generator
- * Operands:
- * Stack: gen =>
- */ \
- MACRO(JSOP_FINALYIELDRVAL, 204, "finalyieldrval", NULL, 1, 1, 0, JOF_BYTE) \
- /*
- * Pops the generator and argument from the stack, pushes a new generator
- * frame and resumes execution of it. Pushes the return value after the
- * generator yields.
- *
- * Category: Statements
- * Type: Generator
- * Operands: resume kind (AbstractGeneratorObject::ResumeKind)
- * Stack: gen, val => rval
- */ \
- MACRO(JSOP_RESUME, 205, "resume", NULL, 2, 2, 1, JOF_UINT8|JOF_INVOKE) \
- /*
- * 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.
- *
- * Category: Variables and Scopes
- * Type: Arguments
- * Operands: uint8_t numHops
- * Stack: => callee
- */ \
- MACRO(JSOP_ENVCALLEE, 206, "envcallee", NULL, 2, 0, 1, JOF_UINT8) \
- /*
- * No-op bytecode 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(JSOP_FORCEINTERPRETER, 207, "forceinterpreter", NULL, 1, 0, 0, JOF_BYTE) \
- /*
- * 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.
- *
- * Category: Statements
- * Type: Generator
- * Operands: uint32_t icIndex
- * Stack: =>
- */ \
- MACRO(JSOP_AFTERYIELD, 208, "afteryield", NULL, 5, 0, 0, JOF_ICINDEX) \
- /*
- * Pops the generator and the return value 'promise', stops interpretation
- * and returns 'promise'. Pushes resolved value onto the stack.
- *
- * Category: Statements
- * Type: Generator
- * Operands: uint24_t resumeIndex
- * Stack: promise, gen => resolved
- */ \
- MACRO(JSOP_AWAIT, 209, "await", NULL, 4, 2, 1, JOF_RESUMEINDEX) \
- /*
- * Pops the iterator and its next method from the top of the stack, and
- * create async iterator from it and push the async iterator back onto the
- * stack.
- *
- * Category: Statements
- * Type: Generator
- * Operands:
- * Stack: iter, next => asynciter
- */ \
- MACRO(JSOP_TOASYNCITER, 210, "toasynciter", NULL, 1, 2, 1, JOF_BYTE) \
- /*
- * Pops the top two values 'id' and 'obj' from the stack, then pushes
- * obj.hasOwnProperty(id)
- *
- * Note that 'obj' is the top value.
- *
- * Category: Other
- * Type:
- * Operands:
- * Stack: id, obj => (obj.hasOwnProperty(id))
- */ \
- MACRO(JSOP_HASOWN, 211, "hasown", NULL, 1, 2, 1, JOF_BYTE|JOF_IC) \
- /*
- * Initializes generator frame, creates a generator and pushes it on the
- * stack.
- *
- * Category: Statements
- * Type: Generator
- * Operands:
- * Stack: => generator
- */ \
- MACRO(JSOP_GENERATOR, 212, "generator", NULL, 1, 0, 1, JOF_BYTE) \
- /*
- * Pushes the nearest 'var' environment.
- *
- * Category: Variables and Scopes
- * Type: Free Variables
- * Operands:
- * Stack: => env
- */ \
- MACRO(JSOP_BINDVAR, 213, "bindvar", NULL, 1, 0, 1, JOF_BYTE) \
- /*
- * Pushes the global environment onto the stack if the script doesn't have
- * a non-syntactic global scope. Otherwise will act like JSOP_BINDNAME.
- *
- * 'nameIndex' is only used when acting like JSOP_BINDNAME.
- *
- * Category: Variables and Scopes
- * Type: Free Variables
- * Operands: uint32_t nameIndex
- * Stack: => global
- */ \
- MACRO(JSOP_BINDGNAME, 214, "bindgname", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_GNAME|JOF_IC) \
- /*
- * Pushes 8-bit int immediate integer operand onto the stack.
- *
- * Category: Literals
- * Type: Constants
- * Operands: int8_t val
- * Stack: => val
- */ \
- MACRO(JSOP_INT8, 215, "int8", NULL, 2, 0, 1, JOF_INT8) \
- /*
- * Pushes 32-bit int immediate integer operand onto the stack.
- *
- * Category: Literals
- * Type: Constants
- * Operands: int32_t val
- * Stack: => val
- */ \
- MACRO(JSOP_INT32, 216, "int32", NULL, 5, 0, 1, JOF_INT32) \
- /*
- * Pops the top of stack value, pushes the 'length' property of it onto the
- * stack.
- *
- * Category: Literals
- * Type: Array
- * Operands: uint32_t nameIndex
- * Stack: obj => obj['length']
- */ \
- MACRO(JSOP_LENGTH, 217, "length", NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_TYPESET|JOF_IC) \
- /*
- * Pushes a JS_ELEMENTS_HOLE value onto the stack, representing an omitted
- * property in an array literal (e.g. property 0 in the array '[, 1]').
- *
- * This opcode is used with the JSOP_NEWARRAY opcode.
- *
- * Category: Literals
- * Type: Array
- * Operands:
- * Stack: => hole
- */ \
- MACRO(JSOP_HOLE, 218, "hole", NULL, 1, 0, 1, JOF_BYTE) \
- /*
- * Checks that the top value on the stack is callable, and throws a
- * TypeError if not. The operand 'kind' is used only to generate an
- * appropriate error message.
- *
- * Category: Statements
- * Type: Function
- * Operands: uint8_t kind
- * Stack: obj => obj
- */ \
- MACRO(JSOP_CHECKISCALLABLE, 219, "checkiscallable", NULL, 2, 1, 1, JOF_UINT8) \
- /*
- * No-op used by the exception unwinder to determine the correct
- * environment to unwind to when performing IteratorClose due to
- * destructuring.
- *
- * Category: Other
- * Operands:
- * Stack: =>
- */ \
- MACRO(JSOP_TRY_DESTRUCTURING, 220, "try-destructuring", NULL, 1, 0, 0, JOF_BYTE) \
- /*
- * Pushes the current global's builtin prototype for a given proto key.
- *
- * Category: Literals
- * Type: Constants
- * Operands: uint8_t kind
- * Stack: => %BuiltinPrototype%
- */ \
- MACRO(JSOP_BUILTINPROTO, 221, "builtinproto", NULL, 2, 0, 1, JOF_UINT8) \
- /*
- * NOP opcode to hint to IonBuilder that the value on top of the stack is
- * the (likely string) key in a for-in loop.
- *
- * Category: Other
- * Operands:
- * Stack: val => val
- */ \
- MACRO(JSOP_ITERNEXT, 222, "iternext", NULL, 1, 1, 1, JOF_BYTE) \
- /*
- * Pops the top of stack value as 'value', checks if the await for 'value'
- * can be skipped. If the await operation can be skipped and the resolution
- * value for 'value' can be acquired, pushes the resolution value and
- * 'true' onto the stack. Otherwise, pushes 'value' and 'false' on the
- * stack.
- *
- * Category: Statements
- * Type: Function
- * Operands:
- * Stack: value => value_or_resolved, canskip
- */ \
- MACRO(JSOP_TRYSKIPAWAIT, 223, "tryskipawait", NULL, 1, 1, 2, JOF_BYTE) \
- /*
- * Creates rest parameter array for current function call, and pushes it
- * onto the stack.
- *
- * Category: Variables and Scopes
- * Type: Arguments
- * Operands:
- * Stack: => rest
- */ \
- MACRO(JSOP_REST, 224, "rest", NULL, 1, 0, 1, JOF_BYTE|JOF_TYPESET|JOF_IC) \
- /*
- * Replace the top-of-stack value propertyNameValue with
- * ToPropertyKey(propertyNameValue).
- *
- * Category: Literals
- * Type: Object
- * Operands:
- * Stack: propertyNameValue => propertyKey
- */ \
- MACRO(JSOP_TOID, 225, "toid", NULL, 1, 1, 1, JOF_BYTE) \
- /*
- * Pushes the implicit 'this' value for calls to the associated name onto
- * the stack.
- *
- * Category: Variables and Scopes
- * Type: This
- * Operands: uint32_t nameIndex
- * Stack: => this
- */ \
- MACRO(JSOP_IMPLICITTHIS, 226, "implicitthis", "", 5, 0, 1, JOF_ATOM) \
- /*
- */ \
- MACRO(JSOP_UNUSED227, 227, "unused", NULL, 1, 0, 0, JOF_BYTE) \
- /*
- * Converts the value on the top of the stack to a String.
- *
- * Category: Other
- * Operands:
- * Stack: val => ToString(val)
- */ \
- MACRO(JSOP_TOSTRING, 228, "tostring", NULL, 1, 1, 1, JOF_BYTE) \
- /*
- * No-op used by the decompiler to produce nicer error messages about
- * destructuring code.
- *
- * Category: Other
- * Operands:
- * Stack: =>
- */ \
- MACRO(JSOP_NOP_DESTRUCTURING, 229, "nop-destructuring", NULL, 1, 0, 0, JOF_BYTE) \
- /*
- * This opcode is a no-op and it indicates the location of a jump
- * instruction target. Some other opcodes act as jump targets as well, see
- * BytecodeIsJumpTarget. The IC index is used by the Baseline interpreter.
- *
- * Category: Other
- * Operands: uint32_t icIndex
- * Stack: =>
- */ \
- MACRO(JSOP_JUMPTARGET, 230, "jumptarget", NULL, 5, 0, 0, JOF_ICINDEX) \
- /*
- * Like JSOP_CALL, but tells the function that the return value is ignored.
- * stack.
- *
- * Category: Statements
- * Type: Function
- * Operands: uint16_t argc
- * Stack: callee, this, args[0], ..., args[argc-1] => rval
- * nuses: (argc+2)
- */ \
- MACRO(JSOP_CALL_IGNORES_RV, 231, "call-ignores-rv", NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_TYPESET|JOF_IC) \
- /*
- * Push "import.meta"
- *
- * Category: Variables and Scopes
- * Type: Modules
- * Operands:
- * Stack: => import.meta
- */ \
- MACRO(JSOP_IMPORTMETA, 232, "importmeta", NULL, 1, 0, 1, JOF_BYTE) \
- /*
- * Dynamic import of the module specified by the string value on the top of
- * the stack.
- *
- * Category: Variables and Scopes
- * Type: Modules
- * Operands:
- * Stack: arg => rval
- */ \
- MACRO(JSOP_DYNAMIC_IMPORT, 233, "call-import", NULL, 1, 1, 1, JOF_BYTE) \
- /*
- * Pops the numeric value 'val' from the stack, then pushes 'val + 1'.
- *
- * Category: Operators
- * Type: Arithmetic Operators
- * Operands:
- * Stack: val => (val + 1)
- */ \
- MACRO(JSOP_INC, 234, "inc", NULL, 1, 1, 1, JOF_BYTE|JOF_IC) \
- /*
- * Pops the numeric value 'val' from the stack, then pushes 'val - 1'.
- *
- * Category: Operators
- * Type: Arithmetic Operators
- * Operands:
- * Stack: val => (val - 1)
- */ \
- MACRO(JSOP_DEC, 235, "dec", NULL, 1, 1, 1, JOF_BYTE|JOF_IC) \
- /*
- * Pop 'val' from the stack, then push the result of 'ToNumeric(val)'.
- * Category: Operators
- * Type: Arithmetic Operators
- * Operands:
- * Stack: val => ToNumeric(val)
- */ \
- MACRO(JSOP_TONUMERIC, 236, "tonumeric", NULL, 1, 1, 1, JOF_BYTE) \
- /*
- * Pushes a BigInt constant onto the stack.
- * Category: Literals
- * Type: Constants
- * Operands: uint32_t constIndex
- * Stack: => val
- */ \
- MACRO(JSOP_BIGINT, 237, "bigint", NULL, 5, 0, 1, JOF_BIGINT) \
- /*
- * Pushes a boolean indicating if instrumentation is active.
- * Category: Other
- * Operands:
- * Stack: => val
- */ \
- MACRO(JSOP_INSTRUMENTATION_ACTIVE, 238, "instrumentationActive", NULL, 1, 0, 1, JOF_BYTE) \
- /*
- * Pushes the instrumentation callback for the current realm.
- * Category: Other
- * Operands:
- * Stack: => val
- */ \
- MACRO(JSOP_INSTRUMENTATION_CALLBACK, 239, "instrumentationCallback", NULL, 1, 0, 1, JOF_BYTE) \
- /*
- * Pushes the current script's instrumentation ID.
- * Category: Other
- * Operands:
- * Stack: => val
- */ \
- MACRO(JSOP_INSTRUMENTATION_SCRIPT_ID, 240, "instrumentationScriptId", NULL, 1, 0, 1, JOF_BYTE) \
- /*
- * If the value on top of the stack is not null or undefined, jumps to a 32-bit offset from the
- * current bytecode.
- *
- * Category: Statements
- * Type: Jumps
- * Operands: int32_t offset
- * Stack: cond => cond
- */ \
- MACRO(JSOP_COALESCE, 241, "coalesce", NULL, 5, 1, 1, JOF_JUMP|JOF_DETECTING) \
- /*
- * Pushes newly created object onto the stack.
- *
- * This opcode takes an object with the final shape, which can be set at
- * the start and slots then filled in directly. Uses the group from the
- * template object; see JSOP_NEWOBJECT for a variant with different
- * heuristics.
- *
- * Category: Literals
- * Type: Object
- * Operands: uint32_t baseobjIndex
- * Stack: => obj
- */ \
- MACRO(JSOP_NEWOBJECT_WITHGROUP, 242, "newobjectwithgroup", NULL, 5, 0, 1, JOF_OBJECT|JOF_IC)
+ MACRO(JSOP_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) \
+ 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) \
@@ -2573,31 +3304,30 @@
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 VALUE_AND_VALUE_PLUS_ONE(op, val, ...) \
- val) && (val + 1 ==
+#define PLUS_ONE(...) \
+ + 1
#define TRAILING_VALUE_AND_VALUE_PLUS_ONE(val) \
val) && (val + 1 ==
-static_assert((0 ==
- FOR_EACH_OPCODE(VALUE_AND_VALUE_PLUS_ONE)
+static_assert((0 FOR_EACH_OPCODE(PLUS_ONE) ==
FOR_EACH_TRAILING_UNUSED_OPCODE(TRAILING_VALUE_AND_VALUE_PLUS_ONE)
256),
- "opcode values and trailing unused opcode values monotonically "
- "increase from zero to 255");
+ "trailing unused opcode values monotonically increase "
+ "from JSOP_LIMIT to 255");
#undef TRAILING_VALUE_AND_VALUE_PLUS_ONE
-#undef VALUE_AND_VALUE_PLUS_ONE
+#undef PLUS_ONE
// clang-format on
// Define JSOP_*_LENGTH constants for all ops.
-#define DEFINE_LENGTH_CONSTANT(op, val, name, image, len, ...) \
+#define DEFINE_LENGTH_CONSTANT(op, name, image, len, ...) \
constexpr size_t op##_LENGTH = len;
FOR_EACH_OPCODE(DEFINE_LENGTH_CONSTANT)
#undef DEFINE_LENGTH_CONSTANT
} // namespace js
#endif // vm_Opcodes_h
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment