Last active
December 16, 2019 14:48
-
-
Save jorendorff/48ad16a5240187d72f6bc77d556fe522 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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