This document is automatically generated from
Opcodes.h by
make_opcode_doc.py.
SpiderMonkey bytecodes are the canonical form of code representation that is
used in the JavaScript engine.
The JavaScript frontend constructs an AST from the source text, then emits
stack-based bytecodes from that AST as a part of the JSScript data structure.
Bytecodes can reference atoms and objects (typically by array index) which are
also contained in the JSScript data structure.
Within the engine, all bytecode executed within a stack frame — even global (top-level) and eval code — has a stack frame associated with it. A frame on the stack has space for JavaScript Values (the tagged value format) in a few different categories. The space for a single JavaScript value is called a "slot", so the categories are:
- Argument slots: holds the actual arguments passed to the current frame.
- Local slots: holds the local variables used by the current code.
- Expression slots: holds the temporary space that you need to calculate
expressions on a stack. For example, in
(a + b) + cyou would push a, then push b, then add, then push c, then add, which requires a maximum depth of two expression slots.
There are also some slots reserved for dedicated functionality, holding values
like this and the callee / return value.
There is always a "Top of Stack" (TOS) that corresponds to the latest value pushed onto the expression stack. All bytecodes implicitly operate in terms of this location.
Stack: ⇒ undefined
Push undefined.
Stack: ⇒ null
Push null.
Stack: ⇒ true/false
Push a boolean constant.
Operands: (int32_t val)
Stack: ⇒ val
Push the int32_t immediate operand as an Int32Value.
JSOp::Zero, JSOp::One, JSOp::Int8, JSOp::Uint16, and JSOp::Uint24
are all compact encodings for JSOp::Int32.
Stack: ⇒ 0
Push the number 0.
Stack: ⇒ 1
Push the number 1.
Operands: (int8_t val)
Stack: ⇒ val
Push the int8_t immediate operand as an Int32Value.
Operands: (uint16_t val)
Stack: ⇒ val
Push the uint16_t immediate operand as an Int32Value.
Operands: (uint24_t val)
Stack: ⇒ val
Push the uint24_t immediate operand as an Int32Value.
Operands: (double val)
Stack: ⇒ val
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).
Operands: (uint32_t bigIntIndex)
Stack: ⇒ bigint
Push the BigInt constant script->getBigInt(bigIntIndex).
Operands: (uint32_t atomIndex)
Stack: ⇒ string
Push the string constant script->getAtom(atomIndex).
Format: JOF_STRING
Operands: (uint8_t symbol (the JS::SymbolCode of the symbol to use))
Stack: ⇒ symbol
Push a well-known symbol.
symbol must be in range for JS::SymbolCode.
Operands: (uint32_t length)
Stack: ⇒ rval
Initialize a new record, preallocating length memory slots. length can still grow
if needed, for example when using the spread operator.
Implements: RecordLiteral Evaluation step 1.
Stack: record, key, value ⇒ record
Add the last element in the stack to the preceding tuple.
Implements: AddPropertyIntoRecordEntriesList.
Stack: record, value ⇒ record
Add the last element in the stack to the preceding tuple.
Implements: RecordPropertyDefinitionEvaluation for RecordPropertyDefinition : ... AssignmentExpression
Stack: record ⇒ record
Mark a record as "initialized", going from "write-only" mode to "read-only" mode.
Operands: (uint32_t length)
Stack: ⇒ rval
Initialize a new tuple, preallocating length memory slots. length can still grow
if needed, for example when using the spread operator.
Implements: TupleLiteral Evaluation step 1.
Stack: tuple, element ⇒ tuple
Add the last element in the stack to the preceding tuple.
Implements: AddValueToTupleSequenceList.
Stack: tuple ⇒ tuple
Mark a tuple as "initialized", going from "write-only" mode to "read-only" mode.
Stack: val ⇒ undefined
Pop the top value on the stack, discard it, and push undefined.
Implements: The void operator, step 3.
Stack: val ⇒ (typeof val)
Infallible. The result is always a string that depends on the type
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 step 2, making typeof nonExistingVariable
return "undefined" instead of throwing a ReferenceError.
In a global scope:
typeof xcompiles toGetGName "x"; Typeof.typeof (0, x)compiles toGetGName "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.
Format: JOF_IC
Stack: val ⇒ (+val)
+val doesn't do any actual math. It just calls ToNumber(val).
The conversion can call .toString()/.valueOf() methods and can
throw. The result on success is always a Number. (Per spec, unary -
supports BigInts, but unary + does not.)
Format: JOF_IC
Stack: val ⇒ (-val)
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.
Format: JOF_IC
Stack: val ⇒ (~val)
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.
Format: JOF_IC
Stack: val ⇒ (!val)
val is first converted with ToBoolean, then logically
negated. The result is always a boolean value. This does not call
user-defined methods and can't throw.
Format: JOF_IC
Stack: lval, rval ⇒ (lval OP rval)
Binary bitwise operations (|, ^, &).
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.
Format: JOF_IC
Stack: lval, rval ⇒ (lval OP rval)
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.
Format: JOF_IC
Stack: lval, rval ⇒ (lval OP rval)
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.
Format: JOF_IC
Stack: lval, rval ⇒ (lval OP rval)
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.
Format: JOF_IC
Stack: value, target ⇒ (value instanceof target)
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.
Format: JOF_IC
Stack: id, obj ⇒ (id in obj)
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.
Format: JOF_IC
Stack: lval, rval ⇒ (lval OP rval)
Bitwise shift operators (<<, >>, >>>).
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.
Format: JOF_IC
Stack: lval, rval ⇒ (lval + rval)
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.
Format: JOF_IC
Stack: lval, rval ⇒ (lval - rval)
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.
Format: JOF_IC
Stack: val ⇒ (val +/- 1)
Add or subtract 1.
val must already be a numeric value, such as the result of
JSOp::ToNumeric.
Implements: The ++ and -- operators, step 3 of each algorithm.
Format: JOF_IC
Stack: lval, rval ⇒ (lval OP rval)
The multiplicative operators (*, /, %).
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.
Format: JOF_IC
Stack: lval, rval ⇒ (lval ** rval)
The exponentiation operator (**).
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.
Format: JOF_IC
Stack: propertyNameValue ⇒ propertyKey
Convert a value to a property key.
Implements: ToPropertyKey, 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.
Format: JOF_IC
Stack: val ⇒ ToNumeric(val)
Convert a value to a numeric value (a Number or BigInt).
Implements: ToNumeric(val).
Note: This is used to implement ++ and --. 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.
Format: JOF_IC
Stack: val ⇒ val, IsNullOrUndefined(val)
Test whether the value on top of the stack is NullValue or
UndefinedValue and push the boolean result.
Stack: ⇒ this
Push the global this value. Not to be confused with the globalThis
property on the global.
This must be used only in scopes where this refers to the global
this.
Stack: ⇒ this
Push the global this value for non-syntactic scope. Not to be confused
with the globalThis property on the global.
This must be used only in scopes where this refers to the global
this.
Stack: ⇒ new.target
Push the value of new.target.
The result is a constructor or undefined.
This must be used only in non-arrow function scripts.
Implements: GetNewTarget.
Stack: moduleId, options ⇒ promise
Dynamic import of the module specified by the string value on the top of the stack.
Implements: Import Calls.
Stack: ⇒ import.meta
Push the import.meta object.
This must be used only in module code.
Stack: ⇒ obj
Create and push a new object with no properties.
Format: JOF_IC
Operands: (uint32_t shapeIndex)
Stack: ⇒ obj
Create and push a new object of a predetermined shape.
The new object has the shape script->getShape(shapeIndex).
Subsequent InitProp instructions must fill in all slots of the new
object before it is used in any other way.
Format: JOF_SHAPE, JOF_IC
Operands: (uint32_t objectIndex)
Stack: ⇒ obj
Push a preconstructed object.
Going one step further than JSOp::NewObject, this instruction doesn't
just reuse the shape--it actually pushes the preconstructed object
script->getObject(objectIndex) right onto the stack. The object must
be a singleton PlainObject or ArrayObject.
The spec requires that an ObjectLiteral or ArrayLiteral creates a new object every time it's evaluated, so this instruction must not be used anywhere it might be executed more than once.
This may only be used in non-function run-once scripts. Care also must be taken to not emit in loops or other constructs where it could run more than once.
Format: JOF_OBJECT
Stack: proto ⇒ obj
Create and push a new ordinary object with the provided [[Prototype]].
This is used to create the .prototype object for derived classes.
Operands: (uint32_t nameIndex)
Stack: obj, val ⇒ obj
Define a data property on an object.
obj must be an object.
Implements: CreateDataPropertyOrThrow as used in PropertyDefinitionEvaluation of regular and shorthand PropertyDefinitions.
Format: JOF_ATOM, JOF_PROP, JOF_PROPINIT, JOF_IC
InitHiddenProp
Operands: (uint32_t nameIndex)
Stack: obj, val ⇒ obj
Like JSOp::InitProp, but define a non-enumerable property.
This is used to define class methods.
Implements: PropertyDefinitionEvaluation for methods, steps 3 and 4, when enumerable is false.
Format: JOF_ATOM, JOF_PROP, JOF_PROPINIT, JOF_IC
Operands: (uint32_t nameIndex)
Stack: obj, val ⇒ obj
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, step 8, when writablePrototype is false.
Format: JOF_ATOM, JOF_PROP, JOF_PROPINIT, JOF_IC
InitElem, InitHiddenElem, InitLockedElem
Stack: obj, id, val ⇒ obj
Define a data property on obj with property key id and value val.
obj must be an object.
Implements: CreateDataPropertyOrThrow. This instruction is used for
object literals like {0: val} and {[id]: val}, and methods like
*[Symbol.iterator]() {}.
JSOp::InitHiddenElem is the same but defines a non-enumerable property,
for class methods.
JSOp::InitLockedElem is the same but defines a non-enumerable, non-writable, non-configurable property,
for private class methods.
Format: JOF_ELEM, JOF_PROPINIT, JOF_IC
InitPropGetter, InitHiddenPropGetter
Operands: (uint32_t nameIndex)
Stack: obj, getter ⇒ obj
Define an accessor property on obj with the given getter.
nameIndex gives the property name.
obj must be an object and getter must be a function.
JSOp::InitHiddenPropGetter is the same but defines a non-enumerable
property, for getters in classes.
Format: JOF_ATOM, JOF_PROP, JOF_PROPINIT
InitElemGetter, InitHiddenElemGetter
Stack: obj, id, getter ⇒ obj
Define an accessor property on obj with property key id and the given getter.
This is used to implement getters like get [id]() {} or get 0() {}.
obj must be an object and getter must be a function.
JSOp::InitHiddenElemGetter is the same but defines a non-enumerable
property, for getters in classes.
Format: JOF_ELEM, JOF_PROPINIT
InitPropSetter, InitHiddenPropSetter
Operands: (uint32_t nameIndex)
Stack: obj, setter ⇒ obj
Define an accessor property on obj with the given setter.
This is used to implement ordinary setters like set foo(v) {}.
obj must be an object and setter must be a function.
JSOp::InitHiddenPropSetter is the same but defines a non-enumerable
property, for setters in classes.
Format: JOF_ATOM, JOF_PROP, JOF_PROPINIT
InitElemSetter, InitHiddenElemSetter
Stack: obj, id, setter ⇒ obj
Define an accesssor property on obj with property key id and the
given setter.
This is used to implement setters with computed property keys or numeric keys.
JSOp::InitHiddenElemSetter is the same but defines a non-enumerable
property, for setters in classes.
Format: JOF_ELEM, JOF_PROPINIT
Operands: (uint32_t nameIndex)
Stack: obj ⇒ obj[name]
Get the value of the property obj.name. This can call getters and
proxy traps.
Implements: GetV, GetValue step 5.
Format: JOF_ATOM, JOF_PROP, JOF_IC
Stack: obj, key ⇒ obj[key]
Get the value of the property obj[key].
Implements: GetV, GetValue step 5.
Format: JOF_ELEM, JOF_IC
Operands: (uint32_t nameIndex)
Stack: obj, val ⇒ val
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 step 6 for non-strict code.
Format: JOF_ATOM, JOF_PROP, JOF_PROPSET, JOF_CHECKSLOPPY, JOF_IC
Operands: (uint32_t nameIndex)
Stack: obj, val ⇒ val
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.
Format: JOF_ATOM, JOF_PROP, JOF_PROPSET, JOF_CHECKSTRICT, JOF_IC
Stack: obj, key, val ⇒ val
Non-strict assignment to a property, obj[key] = val.
Implements: PutValue step 6 for non-strict code.
Format: JOF_ELEM, JOF_PROPSET, JOF_CHECKSLOPPY, JOF_IC
Stack: obj, key, val ⇒ val
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.
Format: JOF_ELEM, JOF_PROPSET, JOF_CHECKSTRICT, JOF_IC
Operands: (uint32_t nameIndex)
Stack: obj ⇒ succeeded
Delete a property from obj. Push true on success, false if the
property existed but could not be deleted. This implements delete obj.name in non-strict code.
Throws if obj is null or undefined. Can call proxy traps.
Implements: delete obj.propname step 5 in non-strict code.
Format: JOF_ATOM, JOF_PROP, JOF_CHECKSLOPPY
Operands: (uint32_t nameIndex)
Stack: obj ⇒ succeeded
Like JSOp::DelProp, but for strict mode code. Push true on success,
else throw a TypeError.
Format: JOF_ATOM, JOF_PROP, JOF_CHECKSTRICT
Stack: obj, key ⇒ succeeded
Delete the property obj[key] and push true on success, false
if the property existed but could not be deleted.
This throws if obj is null or undefined. Can call proxy traps.
Implements: delete obj[key] step 5 in non-strict code.
Format: JOF_ELEM, JOF_CHECKSLOPPY
Stack: obj, key ⇒ succeeded
Like JSOp::DelElem, but for strict mode code. Push true` on success,
else throw a TypeError.
Format: JOF_ELEM, JOF_CHECKSTRICT
Stack: id, obj ⇒ (obj.hasOwnProperty(id))
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).
Format: JOF_IC
Operands: (ThrowCondition throwCondition, ThrowMsgKind msgKind)
Stack: obj, key ⇒ obj, key, (obj.hasOwnProperty(id))
Push a bool representing the presence of private field id on obj. May throw, depending on the ThrowCondition.
Two arguments:
- throwCondition: One of the ThrowConditions defined in ThrowMsgKind.h. Determines why (or if) this op will throw.
- msgKind: One of the ThrowMsgKinds defined in ThrowMsgKind.h, which maps to one of the messages in js.msg. Note: It's not possible to pass arguments to the message at the moment.
Format: JOF_TWO_UINT8, JOF_CHECKSTRICT, JOF_IC
Operands: (uint32_t nameIndex)
Stack: ⇒ private_name
Push a new private name.
Format: JOF_ATOM
Stack: callee ⇒ superBase
Push the SuperBase of the method callee. The SuperBase is
callee.[[HomeObject]].[[GetPrototypeOf]](), the object where super
property lookups should begin.
callee must be a function that has a HomeObject that's an object,
typically produced by JSOp::Callee or JSOp::EnvCallee.
Implements: GetSuperBase, except that instead of the environment, the argument supplies the callee.
Operands: (uint32_t nameIndex)
Stack: receiver, obj ⇒ super.name
Get the value of receiver.name, starting the property search at obj.
In spec terms, obj.[[Get]](name, receiver).
Implements: GetValue for references created by super.name.
The receiver is this and obj is the SuperBase of the enclosing
method.
Format: JOF_ATOM, JOF_PROP, JOF_IC
Stack: receiver, key, obj ⇒ super[key]
Get the value of receiver[key], starting the property search at obj.
In spec terms, obj.[[Get]](key, receiver).
Implements: GetValue for references created by super[key]
(where the receiver is this and obj is the SuperBase of the enclosing
method); Reflect.get(obj, key, receiver).
Format: JOF_ELEM, JOF_IC
Operands: (uint32_t nameIndex)
Stack: receiver, obj, val ⇒ val
Assign val to receiver.name, starting the search for an existing
property at obj. In spec terms, obj.[[Set]](name, val, receiver).
Implements: PutValue for references created by super.name in
non-strict code. The receiver is this and obj is the SuperBase of
the enclosing method.
Format: JOF_ATOM, JOF_PROP, JOF_PROPSET, JOF_CHECKSLOPPY
Operands: (uint32_t nameIndex)
Stack: receiver, obj, val ⇒ val
Like JSOp::SetPropSuper, but for strict mode code.
Format: JOF_ATOM, JOF_PROP, JOF_PROPSET, JOF_CHECKSTRICT
Stack: receiver, key, obj, val ⇒ val
Assign val to receiver[key], strating the search for an existing
property at obj. In spec terms, obj.[[Set]](key, val, receiver).
Implements: PutValue for references created by super[key] in
non-strict code. The receiver is this and obj is the SuperBase of
the enclosing method.
Format: JOF_ELEM, JOF_PROPSET, JOF_CHECKSLOPPY
Stack: receiver, key, obj, val ⇒ val
Like JSOp::SetElemSuper, but for strict mode code.
Format: JOF_ELEM, JOF_PROPSET, JOF_CHECKSTRICT
Stack: val ⇒ iter
Set up a for-in loop by pushing a PropertyIteratorObject over the
enumerable properties of val.
Implements: ForIn/OfHeadEvaluation step 6,
EnumerateObjectProperties. (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.
Format: JOF_IC
Stack: iter ⇒ iter, name
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.
Stack: val ⇒ val, done
Test whether the value on top of the stack is
MagicValue(JS_NO_ITER_VALUE) and push the boolean result.
Stack: iter, iterval ⇒
Exit a for-in loop, closing the iterator.
iter must be a PropertyIteratorObject pushed by JSOp::Iter.
Operands: (CheckIsObjectKind kind)
Stack: result ⇒ result
Check that the top value on the stack is an object, and throw a
TypeError if not. kind is used only to generate an appropriate error
message.
Implements: GetIterator step 5, IteratorNext 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.
Stack: val ⇒ val
Throw a TypeError if val is null or undefined.
Implements: RequireObjectCoercible. 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 and initialization.
Stack: iter, next ⇒ asynciter
Create and push an async iterator wrapping the sync iterator iter.
next should be iter's .next method.
Implements: CreateAsyncToSyncIterator. 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.
Stack: obj, protoVal ⇒ obj
Set the prototype of obj.
obj must be an object.
Implements: B.3.1 proto Property Names in Object Initializers, step 7.a.
Operands: (uint32_t length)
Stack: ⇒ array
Create and push a new Array object with the given length,
preallocating enough memory to hold that many elements.
Format: JOF_IC
Operands: (uint32_t index)
Stack: array, val ⇒ array
Initialize an array element array[index] with value val.
val may be MagicValue(JS_ELEMENTS_HOLE) pushed by JSOp::Hole.
This never calls setters or proxy traps.
array must be an Array object created by JSOp::NewArray with length >
index, and never used except by JSOp::InitElemArray.
Implements: ArrayAccumulation, the third algorithm, step 4, in the common case where nextIndex is known.
Format: JOF_ELEM, JOF_PROPINIT
Stack: array, index, val ⇒ array, (index + 1)
Initialize an array element array[index++] with value val.
val may be MagicValue(JS_ELEMENTS_HOLE) pushed by JSOp::Hole. If it
is, no element is defined, but the array length and the stack value
index are still incremented.
This never calls setters or proxy traps.
array must be an Array object created by JSOp::NewArray and never used
except by JSOp::InitElemArray and JSOp::InitElemInc.
index must be an integer, 0 <= index <= INT32_MAX. If index is
INT32_MAX, this throws a RangeError.
This instruction is used when an array literal contains a
SpreadElement. In [a, ...b, c], InitElemArray 0 is used to put
a into the array, but InitElemInc is used for the elements of b
and for c.
Implements: Several steps in ArrayAccumulation that call CreateDataProperty, set the array length, and/or increment nextIndex.
Format: JOF_ELEM, JOF_PROPINIT, JOF_IC
Stack: ⇒ hole
Push MagicValue(JS_ELEMENTS_HOLE), representing an Elision in an
array literal (like the missing property 0 in the array [, 1]).
This magic value must be used only by JSOp::InitElemArray or
JSOp::InitElemInc.
Operands: (uint32_t regexpIndex)
Stack: ⇒ regexp
Clone and push a new RegExp object.
Implements: Evaluation for RegularExpressionLiteral.
Operands: (uint8_t kind)
Stack: ⇒ %BuiltinObject%
Pushes the current global's %BuiltinObject%.
kind must be a valid BuiltinObjectKind (and must not be
BuiltinObjectKind::None).
Operands: (uint32_t funcIndex)
Stack: ⇒ fn
Push a new function object.
The new function inherits the current environment chain.
Used to create most JS functions. Notable exceptions are derived or default class constructors.
Implements: InstantiateFunctionObject, Evaluation for FunctionExpression, and so on.
Format: JOF_OBJECT
Operands: (FunctionPrefixKind prefixKind)
Stack: fun, name ⇒ fun
Set the name of a function.
fun must be a function object. name must be a string, Int32 value,
or symbol (like the result of JSOp::ToId).
Implements: SetFunctionName, used e.g. to name methods with computed property names.
Stack: fun, homeObject ⇒ fun
Initialize the home object for functions with super bindings.
fun must be a method, getter, or setter, so that it has a
[[HomeObject]] slot. homeObject must be a plain object or (for static
methods) a constructor.
Stack: baseClass ⇒ baseClass
Throw a TypeError if baseClass isn't either null or a constructor.
Implements: ClassDefinitionEvaluation step 6.f.
Operands: (uint32_t funcIndex)
Stack: proto ⇒ obj
Like JSOp::Lambda, but using proto as the new function's
[[Prototype]] (or %FunctionPrototype% if proto is null).
proto must be either a constructor or null. We use
JSOp::CheckClassHeritage to check.
This is used to create the constructor for a derived class.
Implements: ClassDefinitionEvaluation steps 6.e.ii, 6.g.iii, and 12 for derived classes.
Format: JOF_OBJECT
Operands: (uint16_t argc)
Stack: callee, this, args[0], ..., args[argc-1] ⇒ rval
Invoke callee with this and args, and push the return value. Throw
a TypeError if callee isn't a function.
JSOp::CallIter is used for implicit calls to @@iterator methods, to
ensure error messages are formatted with JSMSG_NOT_ITERABLE ("x is not
iterable") rather than JSMSG_NOT_FUNCTION ("x[Symbol.iterator] is not
a function"). The argc operand must be 0 for this variation.
JSOp::CallIgnoresRv hints to the VM that the return value is ignored.
This allows alternate faster implementations to be used that avoid
unnecesary allocations.
Implements: EvaluateCall steps 4, 5, and 7.
Format: JOF_ARGC, JOF_INVOKE, JOF_IC
Stack: callee, this, args ⇒ rval
Like JSOp::Call, but the arguments are provided in an array rather than
a span of stack slots. Used to implement spread-call syntax:
f(...args).
args must be an Array object containing the actual arguments. The
array must be packed (dense and free of holes; see IsPackedArray).
This can be ensured by creating the array with JSOp::NewArray and
populating it using JSOp::InitElemArray.
Format: JOF_INVOKE, JOF_SPREAD, JOF_IC
Stack: iterable ⇒ array_or_undefined
Push an array object that can be passed directly as the args argument
to JSOp::SpreadCall. If the operation can't be optimized, push
undefined instead.
This instruction and the branch around the iterator loop are emitted
only when iterable is the sole argument in a call, as in f(...arr).
See js::OptimizeSpreadCall.
Format: JOF_IC
Operands: (uint16_t argc)
Stack: callee, this, args[0], ..., args[argc-1] ⇒ rval
Perform a direct eval in the current environment if callee is the
builtin eval function, otherwise follow same behaviour as JSOp::Call.
All direct evals use one of the JSOp::*Eval instructions here and these
opcodes are only used when the syntactic conditions for a direct eval
are met. If the builtin eval function is called though other means, it
becomes an indirect eval.
Direct eval causes all bindings in enclosing non-global scopes to be
marked "aliased". The optimization that puts bindings in stack slots has
to prove that the bindings won't need to be captured by closures or
accessed using JSOp::{Get,Bind,Set,Del}Name instructions. Direct eval
makes that analysis impossible.
The instruction immediately following any JSOp::*Eval instruction must
be JSOp::Lineno.
Implements: Function Call Evaluation, steps 5-7 and 9, when the syntactic critera for direct eval in step 6 are all met.
Format: JOF_ARGC, JOF_INVOKE, JOF_CHECKSLOPPY, JOF_IC
Stack: callee, this, args ⇒ rval
Spread-call variant of JSOp::Eval.
See JSOp::SpreadCall for restrictions on args.
Format: JOF_INVOKE, JOF_SPREAD, JOF_CHECKSLOPPY, JOF_IC
Operands: (uint16_t argc)
Stack: evalFn, this, args[0], ..., args[argc-1] ⇒ rval
Like JSOp::Eval, but for strict mode code.
Format: JOF_ARGC, JOF_INVOKE, JOF_CHECKSTRICT, JOF_IC
Stack: callee, this, args ⇒ rval
Spread-call variant of JSOp::StrictEval.
See JSOp::SpreadCall for restrictions on args.
Format: JOF_INVOKE, JOF_SPREAD, JOF_CHECKSTRICT, JOF_IC
Operands: (uint32_t nameIndex)
Stack: ⇒ this
Push the implicit this value for an unqualified function call, like
foo(). nameIndex gives the name of the function we're calling.
The result is always undefined except when the name refers to a with
binding. For example, in with (date) { getFullYear(); }, the
implicit this passed to getFullYear is date, not undefined.
This walks the run-time environment chain looking for the environment
record that contains the function. If the function call definitely
refers to a local binding, use JSOp::Undefined.
Implements: EvaluateCall step 1.b. But not entirely correctly. See bug 1166408.
Format: JOF_ATOM
Operands: (uint32_t objectIndex)
Stack: ⇒ callSiteObj
Push the call site object for a tagged template call.
script->getObject(objectIndex) is the call site object;
script->getObject(objectIndex + 1) is the raw object.
The first time this instruction runs for a given template, it assembles
the final value, defining the .raw property on the call site object
and freezing both objects.
Implements: GetTemplateObject, steps 4 and 12-16.
Format: JOF_OBJECT
Stack: ⇒ JS_IS_CONSTRUCTING
Push MagicValue(JS_IS_CONSTRUCTING).
This magic value is a required argument to the JSOp::New and
JSOp::SuperCall instructions and must not be used any other way.
Operands: (uint16_t argc)
Stack: callee, isConstructing, args[0], ..., args[argc-1], newTarget ⇒ rval
Invoke callee as a constructor with args and newTarget, and push
the return value. Throw a TypeError if callee isn't a constructor.
isConstructing must be the value pushed by JSOp::IsConstructing.
JSOp::SuperCall behaves exactly like JSOp::New, but is used for
SuperCall expressions, to allow JITs to distinguish them from new
expressions.
Implements: EvaluateConstruct steps 7 and 8.
Format: JOF_ARGC, JOF_INVOKE, JOF_CONSTRUCT, JOF_IC
Stack: callee, isConstructing, args, newTarget ⇒ rval
Spread-call variant of JSOp::New.
Invokes callee as a constructor with args and newTarget, and
pushes the return value onto the stack.
isConstructing must be the value pushed by JSOp::IsConstructing.
See JSOp::SpreadCall for restrictions on args.
JSOp::SpreadSuperCall behaves exactly like JSOp::SpreadNew, but is
used for SuperCall expressions.
Format: JOF_INVOKE, JOF_CONSTRUCT, JOF_SPREAD, JOF_IC
Stack: callee ⇒ superFun
Push the prototype of callee in preparation for calling super().
callee must be a derived class constructor.
Implements: GetSuperConstructor, steps 4-7.
Stack: thisval ⇒ thisval
Throw a ReferenceError if thisval is not
MagicValue(JS_UNINITIALIZED_LEXICAL). Used in derived class
constructors to prohibit calling super more than once.
Implements: BindThisValue, step 3.
Stack: ⇒ gen
Create and push a generator object for the current frame.
This instruction must appear only in scripts for generators, async functions, and async generators. There must not already be a generator object for the current frame (that is, this instruction must execute at most once per generator or async call).
Operands: (uint24_t resumeIndex)
Stack: gen ⇒ rval, gen, resumeKind
Suspend the current generator and return to the caller.
When a generator is called, its script starts running, like any other JS
function, because FunctionDeclarationInstantation and other
generator object setup are implemented mostly in bytecode. However,
the FunctionBody of the generator is not supposed to start running
until the first .next() call, so after setup the script suspends
itself: the "initial yield".
Later, when resuming execution, rval, gen and resumeKind will
receive the values passed in by JSOp::Resume. resumeKind is the
GeneratorResumeKind stored as an Int32 value.
This instruction must appear only in scripts for generators and async
generators. gen must be the generator object for the current frame. It
must not have been previously suspended. The resume point indicated by
resumeIndex must be the next instruction in the script, which must be
AfterYield.
Implements: GeneratorStart, steps 4-7.
Format: JOF_RESUMEINDEX
Operands: (uint32_t icIndex)
Bytecode emitted after yield expressions. This is useful for the
Debugger and AbstractGeneratorObject::isAfterYieldOrAwait. It's
treated as jump target op so that the Baseline Interpreter can
efficiently restore the frame's interpreterICEntry when resuming a
generator.
The preceding instruction in the script must be Yield, InitialYield,
or Await.
Format: JOF_ICINDEX
Stack: gen ⇒
Suspend and close the current generator, async function, or async generator.
gen must be the generator object for the current frame.
If the current function is a non-async generator, then the value in the
frame's return value slot is returned to the caller. It should be an
object of the form {value: returnValue, done: true}.
If the current function is an async function or async generator, the frame's return value slot must contain the current frame's result promise, which must already be resolved or rejected.
Operands: (uint24_t resumeIndex)
Stack: rval1, gen ⇒ rval2, gen, resumeKind
Suspend execution of the current generator or async generator, returning
rval1.
For non-async generators, rval1 should be an object of the form
{value: valueToYield, done: true}. For async generators, rval1
should be the value to yield, and the caller is responsible for creating
the iterator result object (under js::AsyncGeneratorYield).
This instruction must appear only in scripts for generators and async
generators. gen must be the generator object for the current stack
frame. The resume point indicated by resumeIndex must be the next
instruction in the script, which must be AfterYield.
When resuming execution, rval2, gen and resumeKind receive the
values passed in by JSOp::Resume.
Implements: GeneratorYield and AsyncGeneratorYield.
Format: JOF_RESUMEINDEX
Stack: val ⇒ val, res
Pushes a boolean indicating whether the top of the stack is
MagicValue(JS_GENERATOR_CLOSING).
Stack: value, gen ⇒ promise
Arrange for this async function to resume asynchronously when value
becomes resolved.
This is the last thing an async function does before suspending for an
await expression. It coerces the awaited value to a promise and
effectively calls .then() on it, passing handler functions that will
resume this async function call later. See js::AsyncFunctionAwait.
This instruction must appear only in non-generator async function
scripts. gen must be the internal generator object for the current
frame. After this instruction, the script should suspend itself with
Await (rather than exiting any other way).
The result promise is the async function's result promise,
gen->as<AsyncFunctionGeneratorObject>().promise().
Implements: Await, steps 2-9.
Operands: (AsyncFunctionResolveKind fulfillOrReject)
Stack: valueOrReason, gen ⇒ promise
Resolve or reject the current async function's result promise with 'valueOrReason'.
This instruction must appear only in non-generator async function
scripts. gen must be the internal generator object for the current
frame. This instruction must run at most once per async function call,
as resolving/rejecting an already resolved/rejected promise is not
permitted.
The result promise is the async function's result promise,
gen->as<AsyncFunctionGeneratorObject>().promise().
Implements: AsyncFunctionStart, step 4.d.i. and 4.e.i.
Operands: (uint24_t resumeIndex)
Stack: promise, gen ⇒ resolved, gen, resumeKind
Suspend the current frame for an await expression.
This instruction must appear only in scripts for async functions and
async generators. gen must be the internal generator object for the
current frame.
This returns promise to the caller. Later, when this async call is
resumed, resolved, gen and resumeKind receive the values passed in
by JSOp::Resume, and execution continues at the next instruction,
which must be AfterYield.
This instruction is used in two subtly different ways.
-
In async functions:
... # valueToAwait GetAliasedVar ".generator" # valueToAwait gen AsyncAwait # resultPromise GetAliasedVar ".generator" # resultPromise gen Await # resolved gen resumeKind AfterYieldAsyncAwaitarranges for this frame to be resumed later and pushes its result promise.Awaitthen suspends the frame and removes it from the stack, returning the result promise to the caller. (If this async call hasn't awaited before, the caller may be user code. Otherwise, the caller is self-hosted code usingresumeGenerator.) -
In async generators:
... # valueToAwait GetAliasedVar ".generator" # valueToAwait gen Await # resolved gen resumeKind AfterYieldAsyncAwaitis not used, so (1) the value returned to the caller byAwaitisvalueToAwait, notresultPromise; and (2) the caller is responsible for doing the async-generator equivalent ofAsyncAwait(namely,js::AsyncGeneratorAwait, called fromjs::AsyncGeneratorResumeafterjs::CallSelfHostedFunctionreturns).
Implements: Await, steps 10-12.
Format: JOF_RESUMEINDEX
Stack: value ⇒ value, can_skip
Test if the re-entry to the microtask loop may be skipped.
This is part of an optimization for await expressions. Programs very
often await values that aren't promises, or promises that are already
resolved. We can then sometimes skip suspending the current frame and
returning to the microtask loop. If the circumstances permit the
optimization, CanSkipAwait pushes true if the optimization is allowed,
and false otherwise.
Stack: value, can_skip ⇒ value_or_resolved, can_skip
Potentially extract an awaited value, if the await is skippable
If re-entering the microtask loop is skippable (as checked by CanSkipAwait)
if can_skip is true, MaybeExtractAwaitValue replaces value with the result of the
await expression (unwrapping the resolved promise, if any). Otherwise, value remains
as is.
In both cases, can_skip remains the same.
Operands: (GeneratorResumeKind resumeKind (encoded as uint8_t))
Stack: ⇒ resumeKind
Pushes one of the GeneratorResumeKind values as Int32Value.
Stack: rval, gen, resumeKind ⇒ rval
Handle Throw and Return resumption.
gen must be the generator object for the current frame. resumeKind
must be a GeneratorResumeKind stored as an Int32 value. If it is
Next, continue to the next instruction. If resumeKind is Throw or
Return, these completions are handled by throwing an exception. See
GeneratorThrowOrReturn.
Stack: gen, val, resumeKind ⇒ rval
Resume execution of a generator, async function, or async generator.
This behaves something like a call instruction. It pushes a stack frame
(the one saved when gen was suspended, rather than a fresh one) and
runs instructions in it. Once gen returns or yields, its return value
is pushed to this frame's stack and execution continues in this script.
This instruction is emitted only for the resumeGenerator self-hosting
intrinsic. It is used in the implementation of
%GeneratorPrototype%.next, .throw, and .return.
gen must be a suspended generator object. resumeKind must be in
range for GeneratorResumeKind.
Format: JOF_INVOKE
Operands: (uint32_t icIndex)
No-op instruction marking the target of a jump instruction.
This instruction and a few others (see js::BytecodeIsJumpTarget) are
jump target instructions. The Baseline Interpreter uses these
instructions to sync the frame's interpreterICEntry after a jump. Ion
uses them to find block boundaries when translating bytecode to MIR.
Format: JOF_ICINDEX
Operands: (uint32_t icIndex, uint8_t depthHint)
Marks the target of the backwards jump for some loop.
This is a jump target instruction (see JSOp::JumpTarget). Additionally,
it checks for interrupts and handles JIT tiering.
The depthHint operand is a loop depth hint for Ion. It starts at 1 and
deeply nested loops all have the same value.
For the convenience of the JITs, scripts must not start with this instruction. See bug 1602390.
Operands: (int32_t offset)
Jump to a 32-bit offset from the current bytecode.
See "Jump instructions" above for details.
Format: JOF_JUMP
Operands: (int32_t forwardOffset)
Stack: cond ⇒
If ToBoolean(cond) is false, jumps to a 32-bit offset from the current
instruction.
Format: JOF_JUMP, JOF_IC
Operands: (int32_t offset)
Stack: cond ⇒
If ToBoolean(cond) is true, jump to a 32-bit offset from the current
instruction.
offset may be positive or negative. This is the instruction used at the
end of a do-while loop to jump back to the top.
Format: JOF_JUMP, JOF_IC
Operands: (int32_t forwardOffset)
Stack: cond ⇒ cond
Short-circuit for logical AND.
If ToBoolean(cond) is false, jump to a 32-bit offset from the current
instruction. The value remains on the stack.
Format: JOF_JUMP, JOF_IC
Operands: (int32_t forwardOffset)
Stack: cond ⇒ cond
Short-circuit for logical OR.
If ToBoolean(cond) is true, jump to a 32-bit offset from the current
instruction. The value remains on the stack.
Format: JOF_JUMP, JOF_IC
Operands: (int32_t forwardOffset)
Stack: val ⇒ val
Short-circuiting for nullish coalescing.
If val is not null or undefined, jump to a 32-bit offset from the
current instruction.
Format: JOF_JUMP
Operands: (int32_t forwardOffset)
Stack: val, cond ⇒ val (if !cond)
Like JSOp::JumpIfTrue, but if the branch is taken, pop and discard an
additional stack value.
This is used to implement switch statements when the
JSOp::TableSwitch optimization is not possible. The switch statement
switch (expr) {
case A: stmt1;
case B: stmt2;
}
compiles to this bytecode:
# dispatch code - evaluate expr, check it against each `case`,
# jump to the right place in the body or to the end.
<expr>
Dup; <A>; StrictEq; Case L1; JumpTarget
Dup; <B>; StrictEq; Case L2; JumpTarget
Default LE
# body code
L1: JumpTarget; <stmt1>
L2: JumpTarget; <stmt2>
LE: JumpTarget
This opcode is weird: it's the only one whose ndefs varies depending on
which way a conditional branch goes. We could implement switch
statements using JSOp::JumpIfTrue and JSOp::Pop, but that would also
be awkward--putting the JSOp::Pop inside the switch body would
complicate fallthrough.
Format: JOF_JUMP
Operands: (int32_t forwardOffset)
Stack: lval ⇒
Like JSOp::Goto, but pop and discard an additional stack value.
This appears after all cases for a non-optimized switch statement. If
there's a default: label, it jumps to that point in the body;
otherwise it jumps to the next statement.
Format: JOF_JUMP
Operands: (int32_t defaultOffset, int32_t low, int32_t high, uint24_t firstResumeIndex)
Stack: i ⇒
Optimized switch-statement dispatch, used when all case labels are
small integer constants.
If low <= i <= high, jump to the instruction at the offset given by
script->resumeOffsets()[firstResumeIndex + i - low], in bytes from the
start of the current script's bytecode. Otherwise, jump to the
instruction at defaultOffset from the current instruction. All of
these offsets must be in range for the current script and must point to
JSOp::JumpTarget instructions.
The following inequalities must hold: low <= high and
firstResumeIndex + high - low < resumeOffsets().size().
Stack: rval ⇒
Return rval.
This must not be used in derived class constructors. Instead use
JSOp::SetRval, JSOp::CheckReturn, and JSOp::RetRval.
Stack: ⇒ rval
Push the current stack frame's returnValue. If no JSOp::SetRval
instruction has been executed in this stack frame, this is undefined.
Every stack frame has a returnValue slot, used by top-level scripts,
generators, async functions, and derived class constructors. Plain
functions usually use JSOp::Return instead.
Stack: rval ⇒
Store rval in the current stack frame's returnValue slot.
This instruction must not be used in a toplevel script compiled with the
noScriptRval option.
Stop execution and return the current stack frame's returnValue. If no
JSOp::SetRval instruction has been executed in this stack frame, this
is undefined.
Also emitted at end of every script so consumers don't need to worry about running off the end.
If the current script is a derived class constructor, returnValue must
be an object. The script can use JSOp::CheckReturn to ensure this.
Stack: thisval ⇒ rval
Check the return value in a derived class constructor.
-
If the current stack frame's
returnValueis an object, pushreturnValueonto the stack. -
Otherwise, if the
returnValueis undefined andthisvalis an object, pushthisvalonto the stack. -
Otherwise, throw a TypeError.
This is exactly what has to happen when a derived class constructor
returns. thisval should be the current value of this, or
MagicValue(JS_UNINITIALIZED_LEXICAL) if this is uninitialized.
Implements: The [[Construct]] internal method of JS functions, steps 13 and 15.
Stack: exc ⇒
Throw exc. (ノಠ益ಠ)ノ彡┴──┴
This sets the pending exception to exc and jumps to error-handling
code. If we're in a try block, error handling adjusts the stack and
environment chain and resumes execution at the top of the catch or
finally block. Otherwise it starts unwinding the stack.
Implements: ThrowStatement Evaluation, step 3.
This is also used in for-of loops. If the body of the loop throws an
exception, we catch it, close the iterator, then use JSOp::Throw to
rethrow.
Operands: (ThrowMsgKind msgNumber)
Create and throw an Error object.
Sometimes we know at emit time that an operation always throws. For
example, delete super.prop; is allowed in methods, but always throws a
ReferenceError.
msgNumber determines the .message and [[Prototype]] of the new Error
object. It must be an error number in js/public/friend/ErrorNumbers.msg.
The number of arguments in the error message must be 0.
Operands: (uint32_t nameIndex)
Throws a runtime TypeError for invalid assignment to a const binding.
Format: JOF_ATOM, JOF_NAME
No-op instruction that marks the top of the bytecode for a TryStatement.
Location information for catch/finally blocks is stored in a side table,
script->trynotes().
No-op instruction used by the exception unwinder to determine the correct environment to unwind to when performing IteratorClose due to destructuring.
This instruction must appear immediately before each
JSTRY_DESTRUCTURING span in a script's try notes.
Stack: ⇒ exception
Push and clear the pending exception. ┬──┬◡ノ(° -°ノ)
This must be used only in the fixed sequence of instructions following a
JSTRY_CATCH span (see "Bytecode Invariants" above), as that's the only
way instructions would run with an exception pending.
Used to implement catch-blocks, including the implicit ones generated as part of for-of iteration.
No-op instruction that marks the start of a finally block.
Stack: ⇒ uninitialized
Push MagicValue(JS_UNINITIALIZED_LEXICAL), a magic value used to mark
a binding as uninitialized.
This magic value must be used only by JSOp::InitLexical.
Operands: (uint24_t localno)
Stack: v ⇒ v
Initialize an optimized local lexical binding; or mark it as uninitialized.
This stores the value v in the fixed slot localno in the current
stack frame. If v is the magic value produced by JSOp::Uninitialized,
this marks the binding as uninitialized. Otherwise this initializes the
binding with value v.
Implements: CreateMutableBinding step 3, substep "record that it is
uninitialized", and InitializeBinding, for optimized locals. (Note:
this is how const bindings are initialized.)
Format: JOF_LOCAL, JOF_NAME
Operands: (uint32_t nameIndex)
Stack: val ⇒ val
Initialize a global lexical binding.
The binding must already have been created by
GlobalOrEvalDeclInstantiation and must be uninitialized.
Like JSOp::InitLexical but for global lexicals. Unlike InitLexical
this can't be used to mark a binding as uninitialized.
Format: JOF_ATOM, JOF_NAME, JOF_PROPINIT, JOF_GNAME, JOF_IC
Operands: (uint8_t hops, uint24_t slot)
Stack: v ⇒ v
Initialize an aliased lexical binding; or mark it as uninitialized.
Like JSOp::InitLexical but for aliased bindings.
Note: There is no even-less-optimized InitName instruction because JS
doesn't need it. We always know statically which binding we're
initializing.
hops is usually 0, but in function f(a=eval("var b;")) { }, the
argument a is initialized from inside a nested scope, so hops == 1.
Format: JOF_ENVCOORD, JOF_NAME, JOF_PROPINIT
Operands: (uint24_t localno)
Stack: v ⇒ v
Throw a ReferenceError if the value on top of the stack is uninitialized.
Typically used after JSOp::GetLocal with the same localno.
Implements: GetBindingValue step 3 and SetMutableBinding step 4 for declarative Environment Records.
Format: JOF_LOCAL, JOF_NAME
Operands: (uint8_t hops, uint24_t slot)
Stack: v ⇒ v
Like JSOp::CheckLexical but for aliased bindings.
Typically used after JSOp::GetAliasedVar with the same hops/slot.
Note: There are no CheckName or CheckGName instructions because
they're unnecessary. JSOp::{Get,Set}{Name,GName} all check for
uninitialized lexicals and throw if needed.
Format: JOF_ENVCOORD, JOF_NAME
Stack: this ⇒ this
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 step 3.
Operands: (uint32_t nameIndex)
Stack: ⇒ global
Look up a name on the global lexical environment's chain and push the environment which contains a binding for that name. If no such binding exists, push the global lexical environment.
Format: JOF_ATOM, JOF_NAME, JOF_GNAME, JOF_IC
Operands: (uint32_t nameIndex)
Stack: ⇒ env
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.
Format: JOF_ATOM, JOF_NAME, JOF_IC
Operands: (uint32_t nameIndex)
Stack: ⇒ val
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 followed by GetValue
(adjusted hackily for typeof).
This is the fallback Get instruction that handles all unoptimized
cases. Optimized instructions follow.
Format: JOF_ATOM, JOF_NAME, JOF_IC
Operands: (uint32_t nameIndex)
Stack: ⇒ val
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.
NonSyntacticVariablesObjects break this optimization, so if the
current script has a non-syntactic global scope, use JSOp::GetName
instead.
Like JSOp::GetName, this throws a ReferenceError if no such binding is
found (unless the next instruction is JSOp::Typeof) or if the binding
is an uninitialized lexical.
Format: JOF_ATOM, JOF_NAME, JOF_GNAME, JOF_IC
Operands: (uint16_t argno)
Stack: ⇒ arguments[argno]
Push the value of an argument that is stored in the stack frame
or in an ArgumentsObject.
Format: JOF_QARG, JOF_NAME
Operands: (uint24_t localno)
Stack: ⇒ val
Push the value of an optimized local variable.
If the variable is an uninitialized lexical, push
MagicValue(JS_UNINIITALIZED_LEXICAL).
Format: JOF_LOCAL, JOF_NAME
Operands: (uint8_t hops, uint24_t slot)
Stack: ⇒ aliasedVar
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
EnvironmentObjects.
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, directions to the
binding from the current environment object.
Aliased instructions can't be used when there's a dynamic scope (due
to non-strict eval or with) that might shadow the aliased binding.
Format: JOF_ENVCOORD, JOF_NAME
Operands: (uint8_t hops, uint24_t slot)
Stack: ⇒ aliasedVar
Push the value of an aliased binding, which may have to bypass a DebugEnvironmentProxy on the environment chain.
Format: JOF_DEBUGCOORD, JOF_NAME
Operands: (uint32_t nameIndex)
Stack: ⇒ val
Get the value of a module import by name and pushes it onto the stack.
Format: JOF_ATOM, JOF_NAME
Operands: (uint32_t nameIndex)
Stack: env ⇒ v
Get the value of a binding from the environment env. If the name is
not bound in env, throw a ReferenceError.
env must be an environment currently on the environment chain, pushed
by JSOp::BindName or JSOp::BindVar.
Note: JSOp::BindName and JSOp::GetBoundName are the two halves of the
JSOp::GetName operation: finding and reading a variable. This
decomposed version is needed to implement the compound assignment and
increment/decrement operators, which get and then set a variable. The
spec says the variable lookup is done only once. If we did the lookup
twice, there would be observable bugs, thanks to dynamic scoping. We
could set the wrong variable or call proxy traps incorrectly.
Implements: GetValue steps 4 and 6.
Format: JOF_ATOM, JOF_NAME, JOF_IC
Operands: (uint32_t nameIndex)
Stack: ⇒ intrinsic[name]
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.
Format: JOF_ATOM, JOF_NAME, JOF_IC
Stack: ⇒ callee
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).
Operands: (uint8_t numHops)
Stack: ⇒ callee
Load the callee stored in a CallObject on the environment chain. The
numHops operand is the number of environment objects to skip on the
environment chain. The environment chain element indicated by numHops
must be a CallObject.
Operands: (uint32_t nameIndex)
Stack: env, val ⇒ val
Assign val to the binding in env with the name given by nameIndex.
Throw a ReferenceError if the binding is an uninitialized lexical.
This can call setters and/or proxy traps.
env must be an environment currently on the environment chain,
pushed by JSOp::BindName or JSOp::BindVar.
This is the fallback Set instruction that handles all unoptimized
cases. Optimized instructions follow.
Implements: PutValue 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.
Format: JOF_ATOM, JOF_NAME, JOF_PROPSET, JOF_CHECKSLOPPY, JOF_IC
Operands: (uint32_t nameIndex)
Stack: env, val ⇒ val
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 steps 5 and 7 for strict mode code.
Format: JOF_ATOM, JOF_NAME, JOF_PROPSET, JOF_CHECKSTRICT, JOF_IC
Operands: (uint32_t nameIndex)
Stack: env, val ⇒ val
Like JSOp::SetName, but for assigning to globals. env must be an
environment pushed by JSOp::BindGName.
Format: JOF_ATOM, JOF_NAME, JOF_PROPSET, JOF_GNAME, JOF_CHECKSLOPPY, JOF_IC
Operands: (uint32_t nameIndex)
Stack: env, val ⇒ val
Like JSOp::StrictSetGName, but for assigning to globals. env must be
an environment pushed by JSOp::BindGName.
Format: JOF_ATOM, JOF_NAME, JOF_PROPSET, JOF_GNAME, JOF_CHECKSTRICT, JOF_IC
Operands: (uint16_t argno)
Stack: val ⇒ val
Assign val to an argument binding that's stored in the stack frame or
in an ArgumentsObject.
Format: JOF_QARG, JOF_NAME
Operands: (uint24_t localno)
Stack: v ⇒ v
Assign to an optimized local binding.
Format: JOF_LOCAL, JOF_NAME
Operands: (uint8_t hops, uint24_t slot)
Stack: val ⇒ val
Assign to an aliased binding.
Implements: SetMutableBinding for declarative Environment Records, in certain cases where it's known that the binding exists, is mutable, and has been initialized.
Format: JOF_ENVCOORD, JOF_NAME, JOF_PROPSET
Operands: (uint32_t nameIndex)
Stack: val ⇒ val
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 vars, but it has many functions.)
Format: JOF_ATOM, JOF_NAME
Operands: (uint32_t lexicalScopeIndex)
Push a lexical environment onto the environment chain.
The LexicalScope indicated by lexicalScopeIndex determines the shape
of the new BlockLexicalEnvironmentObject. All bindings in the new
environment are marked as uninitialized.
Implements: Evaluation of Block, steps 1-4.
The following rules for JSOp::{Push,Pop}LexicalEnv also apply to
JSOp::PushClassBodyEnv, JSOp::PushVarEnv, and
JSOp::{Enter,Leave}With.
Each JSOp::PopLexicalEnv instruction matches a particular
JSOp::PushLexicalEnv instruction in the same script and must have the
same scope and stack depth as the instruction immediately after that
PushLexicalEnv.
JSOp::PushLexicalEnv enters a scope that extends to some set of
instructions in the script. Code must not jump into or out of this
region: control can enter only by executing PushLexicalEnv and can
exit only by executing a PopLexicalEnv or by exception unwinding. (A
JSOp::PopLexicalEnv is always emitted at the end of the block, and
extra copies are emitted on "exit slides", where a break, continue,
or return statement exits the scope.)
The script's JSScript::scopeNotes() must identify exactly which
instructions begin executing in this scope. Typically this means a
single entry marking the contiguous chunk of bytecode from the
instruction after JSOp::PushLexicalEnv to JSOp::PopLexicalEnv
(inclusive); but if that range contains any instructions on exit slides,
after a JSOp::PopLexicalEnv, then those must be correctly noted as
outside the scope.
Format: JOF_SCOPE
Pop a lexical or class-body environment from the environment chain.
See JSOp::PushLexicalEnv for the fine print.
No-op instruction that indicates leaving an optimized lexical scope.
If all bindings in a lexical scope are optimized into stack slots, then
the runtime environment objects for that scope are optimized away. No
JSOp::{Push,Pop}LexicalEnv instructions are emitted. However, the
debugger still needs to be notified when control exits a scope; that's
what this instruction does.
The last instruction in a lexical or class-body scope, as indicated by
scope notes, must be either this instruction (if the scope is optimized)
or JSOp::PopLexicalEnv (if not).
Replace the current block on the environment chain with a fresh block with uninitialized bindings. This implements the behavior of inducing a fresh lexical environment for every iteration of a for-in/of loop whose loop-head declares lexical variables that may be captured.
The current environment must be a BlockLexicalEnvironmentObject.
Like JSOp::RecreateLexicalEnv, but the values of all the bindings are
copied from the old block to the new one. This is used for C-style
for(let ...; ...; ...) loops.
Operands: (uint32_t lexicalScopeIndex)
Push a ClassBody environment onto the environment chain.
Like JSOp::PushLexicalEnv, but pushes a ClassBodyEnvironmentObject
rather than a BlockLexicalEnvironmentObject. JSOp::PopLexicalEnv is
used to pop class-body environments as well as lexical environments.
See JSOp::PushLexicalEnv for the fine print.
Format: JOF_SCOPE
Operands: (uint32_t scopeIndex)
Push a var environment onto the environment chain.
Like JSOp::PushLexicalEnv, but pushes a VarEnvironmentObject rather
than a BlockLexicalEnvironmentObject. The difference is that
non-strict direct eval can add bindings to a var environment; see
VarScope in Scope.h.
See JSOp::PushLexicalEnv for the fine print.
There is no corresponding JSOp::PopVarEnv operation, because a
VarEnvironmentObject is never popped from the environment chain.
Implements: Places in the spec where the VariableEnvironment is set:
-
The bit in PerformEval where, in strict direct eval, the new eval scope is taken as varEnv and becomes "runningContext's VariableEnvironment".
-
The weird scoping rules for functions with default parameter expressions, as specified in FunctionDeclarationInstantiation step 28 ("NOTE: A separate Environment Record is needed...").
Note: The spec also pushes a new VariableEnvironment on entry to every
function, but the VM takes care of that as part of pushing the stack
frame, before the function script starts to run, so JSOp::PushVarEnv is
not needed.
Format: JOF_SCOPE
Operands: (uint32_t staticWithIndex)
Stack: val ⇒
Push a WithEnvironmentObject wrapping ToObject(val) to the
environment chain.
Implements: Evaluation of with statements, steps 2-6.
Operations that may need to consult a WithEnvironment can't be correctly
implemented using optimized instructions like JSOp::GetLocal. A script
must use the deoptimized JSOp::GetName, BindName, SetName, and
DelName instead. Since those instructions don't work correctly with
optimized locals and arguments, all bindings in scopes enclosing a
with statement are marked as "aliased" and deoptimized too.
See JSOp::PushLexicalEnv for the fine print.
Format: JOF_SCOPE
Pop a WithEnvironmentObject from the environment chain.
See JSOp::PushLexicalEnv for the fine print.
Implements: Evaluation of with statements, step 8.
Stack: ⇒ env
Push the current VariableEnvironment (the environment on the environment chain designated to receive new variables).
Implements: Annex B.3.3.1, changes to FunctionDeclarationInstantiation for block-level functions, step 1.a.ii.3.a, and similar steps in other Annex B.3.3 algorithms, when setting the function's second binding can't be optimized.
Operands: (uint32_t lastFun)
Check for conflicting bindings and then initialize them in global or sloppy eval scripts. This is required for global scripts with any top-level bindings, or any sloppy-eval scripts with any non-lexical top-level bindings.
Implements: GlobalDeclarationInstantiation and EvalDeclarationInstantiation (except step 12).
The lastFun argument is a GCThingIndex of the last hoisted top-level
function that is part of top-level script initialization. The gcthings
from index 0 thru lastFun contain only scopes and hoisted functions.
Format: JOF_GCTHING
Operands: (uint32_t nameIndex)
Stack: ⇒ succeeded
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, which is a SyntaxError in
strict mode code.
Format: JOF_ATOM, JOF_NAME, JOF_CHECKSLOPPY
Stack: ⇒ arguments
Create and push the arguments object for the current function activation.
When it exists, arguments is stored in an ordinary local variable.
JSOp::Arguments is used in function preludes, to populate that variable
before the function body runs, not each time arguments appears in a
function.
If a function clearly doesn't use arguments, we optimize it away when
emitting bytecode. The function's script won't use JSOp::Arguments at
all.
The current script must be a function script. This instruction must execute at most once per function activation.
Stack: ⇒ rest
Create and push the rest parameter array for current function call.
This must appear only in a script for a function that has a rest parameter.
Format: JOF_IC
Stack: ⇒ 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.
In non-strict functions, this is always an object. Undefined/null
this is converted into the global this value. Other primitive values
are boxed. See js::BoxNonStrictThis.
Stack: v ⇒
Pop the top value from the stack and discard it.
Operands: (uint16_t n)
Stack: v[n-1], ..., v[1], v[0] ⇒
Pop the top n values from the stack. n must be <= the current stack
depth.
Stack: v ⇒ v, v
Push a copy of the top value on the stack.
Stack: v1, v2 ⇒ v1, v2, v1, v2
Duplicate the top two values on the stack.
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]
Push a copy of the nth value from the top of the stack.
n must be less than the current stack depth.
Stack: v1, v2 ⇒ v2, v1
Swap the top two values on the stack.
Operands: (uint8_t n)
Stack: v[n], v[n-1], ..., v[1], v[0] ⇒ v[n-1], ..., v[1], v[0], v[n]
Pick the nth element from the stack and move it to the top of the stack.
Operands: (uint8_t n)
Stack: v[n], v[n-1], ..., v[1], v[0] ⇒ v[0], v[n], v[n-1], ..., v[1]
Move the top of the stack value under the nth element of the stack.
n must not be 0.
Do nothing. This is used when we need distinct bytecode locations for various mechanisms.
Operands: (uint32_t lineno)
No-op instruction emitted immediately after JSOp::*Eval so that direct
eval does not have to do slow pc-to-line mapping.
The lineno operand should agree with this script's source notes about
the line number of the preceding *Eval instruction.
No-op instruction to hint that the top stack value is uninteresting.
This affects only debug output and some error messages.
In array destructuring, we emit bytecode that is roughly equivalent to
result.done ? undefined : result.value.
NopDestructuring is emitted after the undefined, so that the
expression decompiler and disassembler know to casually ignore the
possibility of undefined, and render the result of the conditional
expression simply as "result.value".
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.
Stack: checkVal ⇒ checkVal
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.
Break in the debugger, if one is attached. Otherwise this is a no-op.
The Debugger API offers a way to hook into this instruction.
Implements: Evaluation for DebuggerStatement.