Bytecode Descriptions 编辑
Bytecode Listing
This document is automatically generated from Opcodes.h by make_opcode_doc.py.
Constants
Undefined
- Stack: ⇒
undefined
Push
undefined
. Null
- Stack: ⇒
null
Push
null
. False
,True
- Stack: ⇒
true/false
Push a boolean constant.
Int32
- Operands:
(int32_t val)
Stack: ⇒val
Push the
int32_t
immediate operand as anInt32Value
.JSOp::Zero
,JSOp::One
,JSOp::Int8
,JSOp::Uint16
, andJSOp::Uint24
are all compact encodings forJSOp::Int32
. Zero
- Stack: ⇒
0
Push the number
0
. One
- Stack: ⇒
1
Push the number
1
. Int8
- Operands:
(int8_t val)
Stack: ⇒val
Push the
int8_t
immediate operand as anInt32Value
. Uint16
- Operands:
(uint16_t val)
Stack: ⇒val
Push the
uint16_t
immediate operand as anInt32Value
. Uint24
- Operands:
(uint24_t val)
Stack: ⇒val
Push the
uint24_t
immediate operand as anInt32Value
. Double
- 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
). BigInt
- Operands:
(uint32_t bigIntIndex)
Stack: ⇒bigint
Push the BigInt constant
script->getBigInt(bigIntIndex)
. String
- Operands:
(uint32_t atomIndex)
Stack: ⇒string
Push the string constant
Format: JOF_ATOMscript->getAtom(atomIndex)
. Symbol
- Operands:
(uint8_t symbol (the JS::SymbolCode of the symbol to use))
Stack: ⇒symbol
Push a well-known symbol.
symbol
must be in range forJS::SymbolCode
.
Expressions
Unary operators
Void
- Stack:
val
⇒undefined
Pop the top value on the stack, discard it, and push
undefined
.Implements: The
void
operator, step 3. Typeof
,TypeofExpr
- Stack:
val
⇒(typeof val)
Infallible. The result is always a string that depends on the type of
val
.JSOp::Typeof
andJSOp::TypeofExpr
are the same except that--amazingly--JSOp::Typeof
affects the behavior of an immediately precedingJSOp::GetName
orJSOp::GetGName
instruction! This is how we implementtypeof
step 2, makingtypeof nonExistingVariable
return"undefined"
instead of throwing a ReferenceError.In a global scope:
typeof x
compiles 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
Format: JOF_ICx
doesn't exist. Pos
- Stack:
val
⇒(+val)
+val
doesn't do any actual math. It just calls ToNumber(val).The conversion can call
Format: JOF_IC.toString()
/.valueOf()
methods and can throw. The result on success is always a Number. (Per spec, unary-
supports BigInts, but unary+
does not.) Neg
- Stack:
val
⇒(-val)
Convert
Format: JOF_ICval
to a numeric value, then push-val
. The conversion can call.toString()
/.valueOf()
methods and can throw. The result on success is always numeric. BitNot
- Stack:
val
⇒(~val)
Format: JOF_ICval
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. Not
- Stack:
val
⇒(!val)
Format: JOF_ICval
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.
Binary operators
BitOr
,BitXor
,BitAnd
- Stack:
lval, rval
⇒(lval OP rval)
Binary bitwise operations (
|
,^
,&
).The arguments are converted to integers first. The conversion can call
Format: JOF_IC.toString()
/.valueOf()
methods and can throw. The result on success is always an Int32 or BigInt Value. Eq
,Ne
- 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 StrictEq
,StrictNe
- 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 Lt
,Gt
,Le
,Ge
- 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 Instanceof
- Stack:
value, target
⇒(value instanceof target)
This throws a
Format: JOF_ICTypeError
iftarget
is not an object. It callstarget[Symbol.hasInstance](value)
if the method exists. On success, the result is always a boolean value. In
- Stack:
id, obj
⇒(id in obj)
Push
true
ifobj
has a property with the keyid
. Otherwise pushfalse
.This throws a
Format: JOF_ICTypeError
ifobj
is not an object. This can fire proxy hooks and can throw. On success, the result is always a boolean value. Lsh
,Rsh
,Ursh
- 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
Format: JOF_IC.toString()
/.valueOf()
methods and can throw. The result on success is always an Int32 or BigInt Value. Add
- 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
Format: JOF_IC.toString()
/.valueOf()
methods and can throw. Sub
- 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
Format: JOF_IC.toString()
/.valueOf()
methods and can throw. On success, the result is always numeric. Inc
,Dec
- Stack:
val
⇒(val +/- 1)
Add or subtract 1.
val
must already be a numeric value, such as the result ofJSOp::ToNumeric
.Implements: The
Format: JOF_IC++
and--
operators, step 3 of each algorithm. Mul
,Div
,Mod
- 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
Format: JOF_IC.toString()
/.valueOf()
methods and can throw. On success, the result is always numeric. Pow
- 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
Format: JOF_IC.toString()
/.valueOf()
methods and can throw. This throws a RangeError if both values are BigInts and the exponent is negative.
Conversions
ToPropertyKey
- 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 aJSOp::GetElem
and aJSOp::SetElem
with the same property key. Both instructions would convertindex
to a property key for us, but the spec says to convert it only once.The conversion can call
Format: JOF_IC.toString()
/.valueOf()
methods and can throw. ToNumeric
,ToString
- Stack:
val
⇒ToNumeric(val)
Convert a value to a numeric value (a Number or BigInt).
Implements: ToNumeric(val).
Note: This is used to implement
Format: JOF_IC++
and--
. Surprisingly, it's not possible to get the right behavior usingJSOp::Add
andJSOp::Sub
alone. For one thing,JSOp::Add
sometimes does string concatenation, while++
always does numeric addition. More fundamentally, the result of evaluatingx--
is ToNumeric(old value ofx
), a value that the sequenceGetLocal "x"; One; Sub; SetLocal "x"
does not give us.
Other expressions
GlobalThis
- Stack: ⇒
this
Push the global
this
value. Not to be confused with theglobalThis
property on the global.This must be used only in scopes where
this
refers to the globalthis
. NewTarget
- Stack: ⇒
new.target
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.
DynamicImport
- Stack:
moduleId
⇒promise
Dynamic import of the module specified by the string value on the top of the stack.
Implements: Import Calls.
ImportMeta
- Stack: ⇒
import.meta
Push the
import.meta
object.This must be used only in module code.
Objects
Creating objects
NewInit
- Stack: ⇒
obj
Create and push a new object with no properties.
Format: JOF_IC NewObject
,NewObjectWithGroup
- Operands:
(uint32_t baseobjIndex)
Stack: ⇒obj
Create and push a new object of a predetermined shape.
The new object has the shape of the template object
script->getObject(baseobjIndex)
. SubsequentInitProp
instructions must fill in all slots of the new object before it is used in any other way.For
Format: JOF_OBJECT, JOF_ICJSOp::NewObject
, the new object has a group based on the allocation site (or a new group if the template's group is a singleton). ForJSOp::NewObjectWithGroup
, the new object has the same group as the template object. Object
- 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 objectscript->getObject(objectIndex)
right onto the stack. The object must be a singletonPlainObject
orArrayObject
.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,
Format: JOF_OBJECTnewGlobal({cloneSingletons: true})
, that makes this instruction do a deep copy of the object. A few tests use it. ObjWithProto
- 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.
Defining properties
InitProp
- 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 InitLockedProp
- 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
- Stack:
obj, id, val
⇒obj
Define a data property on
obj
with property keyid
and valueval
.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]() {}
.
Format: JOF_ELEM, JOF_PROPINIT, JOF_ICJSOp::InitHiddenElem
is the same but defines a non-enumerable property, for class methods. InitPropGetter
,InitHiddenPropGetter
- Operands:
(uint32_t nameIndex)
Stack:obj, getter
⇒obj
Define an accessor property on
obj
with the givengetter
.nameIndex
gives the property name.obj
must be an object andgetter
must be a function.
Format: JOF_ATOM, JOF_PROP, JOF_PROPINITJSOp::InitHiddenPropGetter
is the same but defines a non-enumerable property, for getters in classes. InitElemGetter
,InitHiddenElemGetter
- Stack:
obj, id, getter
⇒obj
Define an accessor property on
obj
with property keyid
and the givengetter
.This is used to implement getters like
get [id]() {}
orget 0() {}
.obj
must be an object andgetter
must be a function.
Format: JOF_ELEM, JOF_PROPINITJSOp::InitHiddenElemGetter
is the same but defines a non-enumerable property, for getters in classes. InitPropSetter
,InitHiddenPropSetter
- Operands:
(uint32_t nameIndex)
Stack:obj, setter
⇒obj
Define an accessor property on
obj
with the givensetter
.This is used to implement ordinary setters like
set foo(v) {}
.obj
must be an object andsetter
must be a function.
Format: JOF_ATOM, JOF_PROP, JOF_PROPINITJSOp::InitHiddenPropSetter
is the same but defines a non-enumerable property, for setters in classes. InitElemSetter
,InitHiddenElemSetter
- Stack:
obj, id, setter
⇒obj
Define an accesssor property on
obj
with property keyid
and the givensetter
.This is used to implement setters with computed property keys or numeric keys.
Format: JOF_ELEM, JOF_PROPINITJSOp::InitHiddenElemSetter
is the same but defines a non-enumerable property, for setters in classes.
Accessing properties
GetProp
,CallProp
- Operands:
(uint32_t nameIndex)
Stack:obj
⇒obj[name]
Get the value of the property
obj.name
. This can call getters and proxy traps.
Format: JOF_ATOM, JOF_PROP, JOF_TYPESET, JOF_ICJSOp::CallProp
is exactly likeJSOp::GetProp
but hints to the VM that we're getting a method in order to call it. GetElem
,CallElem
- Stack:
obj, key
⇒obj[key]
Get the value of the property
obj[key]
.
Format: JOF_ELEM, JOF_TYPESET, JOF_ICJSOp::CallElem
is exactly likeJSOp::GetElem
but hints to the VM that we're getting a method in order to call it. Length
- Operands:
(uint32_t nameIndex)
Stack:obj
⇒obj.length
Push the value of
obj.length
.
Format: JOF_ATOM, JOF_PROP, JOF_TYPESET, JOF_ICnameIndex
must be the index of the atom"length"
. This then behaves exactly likeJSOp::GetProp
. SetProp
- 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 StrictSetProp
- Operands:
(uint32_t nameIndex)
Stack:obj, val
⇒val
Like
Format: JOF_ATOM, JOF_PROP, JOF_PROPSET, JOF_CHECKSTRICT, JOF_ICJSOp::SetProp
, but for strict mode code. Throw a TypeError ifobj[key]
exists but is non-writable, if it's an accessor property with no setter, or ifobj
is a primitive value. SetElem
- 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 StrictSetElem
- Stack:
obj, key, val
⇒val
Like
Format: JOF_ELEM, JOF_PROPSET, JOF_CHECKSTRICT, JOF_ICJSOp::SetElem
, but for strict mode code. Throw a TypeError ifobj[key]
exists but is non-writable, if it's an accessor property with no setter, or ifobj
is a primitive value. DelProp
- 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 implementsdelete obj.name
in non-strict code.Throws if
obj
is null or undefined. Can call proxy traps.Implements:
Format: JOF_ATOM, JOF_PROP, JOF_CHECKSLOPPYdelete obj.propname
step 5 in non-strict code. StrictDelProp
- Operands:
(uint32_t nameIndex)
Stack:obj
⇒succeeded
Like
Format: JOF_ATOM, JOF_PROP, JOF_CHECKSTRICTJSOp::DelProp
, but for strict mode code. Pushtrue
on success, else throw a TypeError. DelElem
- Stack:
obj, key
⇒succeeded
Delete the property
obj[key]
and pushtrue
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:
Format: JOF_ELEM, JOF_CHECKSLOPPYdelete obj[key]
step 5 in non-strict code. StrictDelElem
- Stack:
obj, key
⇒succeeded
Like
Format: JOF_ELEM, JOF_CHECKSTRICTJSOp::DelElem, but for strict mode code. Push
true` on success, else throw a TypeError. HasOwn
- Stack:
id, obj
⇒(obj.hasOwnProperty(id))
Push true if
obj
has an own propertyid
.Note that
obj
is the top value, likeJSOp::In
.This opcode is not used for normal JS. Self-hosted code uses it by calling the intrinsic
Format: JOF_IChasOwn(id, obj)
. For example,Object.prototype.hasOwnProperty
is implemented this way (see js/src/builtin/Object.js).
Super
SuperBase
- Stack:
callee
⇒superBase
Push the SuperBase of the method
callee
. The SuperBase iscallee.[[HomeObject]].[[GetPrototypeOf]]()
, the object wheresuper
property lookups should begin.callee
must be a function that has a HomeObject that's an object, typically produced byJSOp::Callee
orJSOp::EnvCallee
.Implements: GetSuperBase, except that instead of the environment, the argument supplies the callee.
GetPropSuper
- Operands:
(uint32_t nameIndex)
Stack:receiver, obj
⇒super.name
Get the value of
receiver.name
, starting the property search atobj
. In spec terms,obj.[[Get]](name, receiver)
.Implements: GetValue for references created by
Format: JOF_ATOM, JOF_PROP, JOF_TYPESET, JOF_ICsuper.name
. Thereceiver
isthis
andobj
is the SuperBase of the enclosing method. GetElemSuper
- Stack:
receiver, key, obj
⇒super[key]
Get the value of
receiver[key]
, starting the property search atobj
. In spec terms,obj.[[Get]](key, receiver)
.Implements: GetValue for references created by
Format: JOF_ELEM, JOF_TYPESET, JOF_ICsuper[key]
(where thereceiver
isthis
andobj
is the SuperBase of the enclosing method);Reflect.get(obj, key, receiver)
. SetPropSuper
- Operands:
(uint32_t nameIndex)
Stack:receiver, obj, val
⇒val
Assign
val
toreceiver.name
, starting the search for an existing property atobj
. In spec terms,obj.[[Set]](name, val, receiver)
.Implements: PutValue for references created by
Format: JOF_ATOM, JOF_PROP, JOF_PROPSET, JOF_CHECKSLOPPYsuper.name
in non-strict code. Thereceiver
isthis
andobj
is the SuperBase of the enclosing method. StrictSetPropSuper
- Operands:
(uint32_t nameIndex)
Stack:receiver, obj, val
⇒val
Like
Format: JOF_ATOM, JOF_PROP, JOF_PROPSET, JOF_CHECKSTRICTJSOp::SetPropSuper
, but for strict mode code. SetElemSuper
- Stack:
receiver, key, obj, val
⇒val
Assign
val
toreceiver[key]
, strating the search for an existing property atobj
. In spec terms,obj.[[Set]](key, val, receiver)
.Implements: PutValue for references created by
Format: JOF_ELEM, JOF_PROPSET, JOF_CHECKSLOPPYsuper[key]
in non-strict code. Thereceiver
isthis
andobj
is the SuperBase of the enclosing method. StrictSetElemSuper
- Stack:
receiver, key, obj, val
⇒val
Like
Format: JOF_ELEM, JOF_PROPSET, JOF_CHECKSTRICTJSOp::SetElemSuper
, but for strict mode code.
Enumeration
Iter
- Stack:
val
⇒iter
Set up a for-in loop by pushing a
PropertyIteratorObject
over the enumerable properties ofval
.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 byJSOp::MoreIter
andJSOp::EndIter
, or by error handling.The script's
JSScript::trynotes()
must mark the body of thefor-in
loop, i.e. exactly those instructions that begin executing withiter
on the stack, starting with the next instruction (alwaysJSOp::LoopHead
). Code must not jump into or out of this region: control can enter only by executingJSOp::Iter
and can exit only by executing aJSOp::EndIter
or by exception unwinding. (AJSOp::EndIter
is always emitted at the end of the loop, and extra copies are emitted on "exit slides", where abreak
,continue
, orreturn
statement exits the loop.)Typically a single try note entry marks the contiguous chunk of bytecode from the instruction after
Format: JOF_ICJSOp::Iter
toJSOp::EndIter
(inclusive); but if that range contains any instructions on exit slides, after aJSOp::EndIter
, then those must be correctly noted as outside the loop. MoreIter
- Stack:
iter
⇒iter, name
Get the next property name for a for-in loop.
iter
must be aPropertyIteratorObject
produced byJSOp::Iter
. This pushes the property name for the next loop iteration, orMagicValue(JS_NO_ITER_VALUE)
if there are no more enumerable properties to iterate over. The magic value must be used only byJSOp::IsNoIter
andJSOp::EndIter
. IsNoIter
- Stack:
val
⇒val, done
Test whether the value on top of the stack is
MagicValue(JS_NO_ITER_VALUE)
and push the boolean result. IterNext
- Stack:
val
⇒val
No-op instruction to hint to IonBuilder that the value on top of the stack is the string key in a for-in loop.
EndIter
- Stack:
iter, iterval
⇒Exit a for-in loop, closing the iterator.
iter
must be aPropertyIteratorObject
pushed byJSOp::Iter
.
Iteration
CheckIsObj
- 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.
CheckObjCoercible
- Stack:
val
⇒val
Throw a TypeError if
val
isnull
orundefined
.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.
ToAsyncIter
- Stack:
iter, next
⇒asynciter
Create and push an async iterator wrapping the sync iterator
iter
.next
should beiter
'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.
SetPrototype
MutateProto
- 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.
Array literals
NewArray
- Operands:
(uint32_t length)
Stack: ⇒array
Create and push a new Array object with the given
Format: JOF_IClength
, preallocating enough memory to hold that many elements. InitElemArray
- Operands:
(uint32_t index)
Stack:array, val
⇒array
Initialize an array element
array[index]
with valueval
.val
may beMagicValue(JS_ELEMENTS_HOLE)
. If it is, this does nothing.This never calls setters or proxy traps.
array
must be an Array object created byJSOp::NewArray
with length >index
, and never used except byJSOp::InitElemArray
.Implements: ArrayAccumulation, the third algorithm, step 4, in the common case where nextIndex is known.
Format: JOF_ELEM, JOF_PROPINIT, JOF_IC InitElemInc
- Stack:
array, index, val
⇒array, (index + 1)
Initialize an array element
array[index++]
with valueval
.val
may beMagicValue(JS_ELEMENTS_HOLE)
. If it is, no element is defined, but the array length and the stack valueindex
are still incremented.This never calls setters or proxy traps.
array
must be an Array object created byJSOp::NewArray
and never used except byJSOp::InitElemArray
andJSOp::InitElemInc
.index
must be an integer,0 <= index <= INT32_MAX
. Ifindex
isINT32_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 puta
into the array, butInitElemInc
is used for the elements ofb
and forc
.Implements: Several steps in ArrayAccumulation that call CreateDataProperty, set the array length, and/or increment nextIndex.
Format: JOF_ELEM, JOF_PROPINIT, JOF_IC Hole
- 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
orJSOp::InitElemInc
. NewArrayCopyOnWrite
- Operands:
(uint32_t objectIndex)
Stack: ⇒array
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
Format: JOF_OBJECTJSOp::NewArray
and a series ofJSOp::InitElem
instructions.
RegExp literals
RegExp
- Operands:
(uint32_t regexpIndex)
Stack: ⇒regexp
Clone and push a new RegExp object.
Implements: Evaluation for RegularExpressionLiteral.
Functions
Creating functions
Lambda
- Operands:
(uint32_t funcIndex)
Stack: ⇒fn
Push a function object.
This clones the function unless it's a singleton; see
CanReuseFunctionForClone
. The new function inherits the current environment chain.Used to create most JS functions. Notable exceptions are arrow functions and derived or default class constructors.
The function indicated by
funcIndex
must be a non-arrow function.Implements: InstantiateFunctionObject, Evaluation for FunctionExpression, and so on.
Format: JOF_OBJECT LambdaArrow
- Operands:
(uint32_t funcIndex)
Stack:newTarget
⇒arrowFn
Push a new arrow function.
newTarget
matters only if the arrow function uses the expressionnew.target
. It should be the current value ofnew.target
, so that the arrow function inheritsnew.target
from the enclosing scope. (Ifnew.target
is illegal here, the value doesn't matter; usenull
.)The function indicated by
Format: JOF_OBJECTfuncIndex
must be an arrow function. SetFunName
- 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 ofJSOp::ToId
).Implements: SetFunctionName, used e.g. to name methods with computed property names.
InitHomeObject
- 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.
Creating constructors
CheckClassHeritage
- Stack:
baseClass
⇒baseClass
Throw a TypeError if
baseClass
isn't eithernull
or a constructor.Implements: ClassDefinitionEvaluation step 6.f.
FunWithProto
- Operands:
(uint32_t funcIndex)
Stack:proto
⇒obj
Like
JSOp::Lambda
, but usingproto
as the new function's[[Prototype]]
(or%FunctionPrototype%
ifproto
isnull
).proto
must be either a constructor ornull
. We useJSOp::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 ClassConstructor
- Operands:
(uint32_t nameIndex, uint32_t sourceStart, uint32_t sourceEnd)
Stack: ⇒constructor
Create and push a default constructor for a base class.
A default constructor behaves like
constructor() {}
.Implements: ClassDefinitionEvaluation for ClassTail, steps 10.b. and 12-17.
The
Format: JOF_CLASS_CTORsourceStart
/sourceEnd
offsets are the start/end offsets of the class definition in the source buffer, used fortoString()
. They must be valid offsets into the source buffer, measured in code units, such thatscriptSource->substring(cx, start, end)
is valid. DerivedConstructor
- Operands:
(uint32_t nameIndex, uint32_t sourceStart, uint32_t sourceEnd)
Stack:proto
⇒constructor
Create and push a default constructor for a derived class.
A default derived-class constructor behaves like
constructor(...args) { super(...args); }
.Implements: ClassDefinitionEvaluation for ClassTail, steps 10.a. and 12-17.
Format: JOF_CLASS_CTORsourceStart
andsourceEnd
follow the same rules as forJSOp::ClassConstructor
. FunctionProto
- Stack: ⇒
%FunctionPrototype%
Pushes the current global's FunctionPrototype.
kind
must be in range forJSProtoKey
(and must not beJSProto_LIMIT
).
Calls
Call
,CallIter
,FunApply
,FunCall
,CallIgnoresRv
- Operands:
(uint16_t argc)
Stack:callee, this, args[0], ..., args[argc-1]
⇒rval
Invoke
callee
withthis
andargs
, and push the return value. Throw a TypeError ifcallee
isn't a function.JSOp::CallIter
is used for implicit calls to @@iterator methods, to ensure error messages are formatted withJSMSG_NOT_ITERABLE
("x is not iterable") rather thanJSMSG_NOT_FUNCTION
("x[Symbol.iterator] is not a function"). Theargc
operand must be 0 for this variation.JSOp::FunApply
hints to the VM that this is likely a call to the builtin methodFunction.prototype.apply
, an easy optimization target.JSOp::FunCall
similarly hints to the VM that the callee is likelyFunction.prototype.call
.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_TYPESET, JOF_IC SpreadCall
- 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)
.
Format: JOF_INVOKE, JOF_SPREAD, JOF_TYPESET, JOF_ICargs
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 withJSOp::NewArray
and populating it usingJSOp::InitElemArray
. OptimizeSpreadCall
- Stack:
arr
⇒arr, optimized
Push true if
arr
is an array object that can be passed directly as theargs
argument toJSOp::SpreadCall
.This instruction and the branch around the iterator loop are emitted only when
arr
is itself a rest parameter, as in(...arr) => f(...arr)
, a strong hint that it's a packed Array whose prototype isArray.prototype
.See
js::OptimizeSpreadCall
. Eval
- 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 builtineval
function, otherwise follow same behaviour asJSOp::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 beJSOp::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_TYPESET, JOF_CHECKSLOPPY, JOF_IC SpreadEval
- Stack:
callee, this, args
⇒rval
Spread-call variant of
JSOp::Eval
.See
Format: JOF_INVOKE, JOF_SPREAD, JOF_TYPESET, JOF_CHECKSLOPPY, JOF_ICJSOp::SpreadCall
for restrictions onargs
. StrictEval
- Operands:
(uint16_t argc)
Stack:evalFn, this, args[0], ..., args[argc-1]
⇒rval
Like
Format: JOF_ARGC, JOF_INVOKE, JOF_TYPESET, JOF_CHECKSTRICT, JOF_ICJSOp::Eval
, but for strict mode code. StrictSpreadEval
- Stack:
callee, this, args
⇒rval
Spread-call variant of
JSOp::StrictEval
.See
Format: JOF_INVOKE, JOF_SPREAD, JOF_TYPESET, JOF_CHECKSTRICT, JOF_ICJSOp::SpreadCall
for restrictions onargs
. ImplicitThis
- Operands:
(uint32_t nameIndex)
Stack: ⇒this
Push the implicit
this
value for an unqualified function call, likefoo()
.nameIndex
gives the name of the function we're calling.The result is always
undefined
except when the name refers to awith
binding. For example, inwith (date) { getFullYear(); }
, the implicitthis
passed togetFullYear
isdate
, notundefined
.This walks the run-time environment chain looking for the environment record that contains the function. If the function call is not inside a
with
statement, useJSOp::GImplicitThis
instead. If the function call definitely refers to a local binding, useJSOp::Undefined
.Implements: EvaluateCall step 1.b. But not entirely correctly. See bug 1166408.
Format: JOF_ATOM GImplicitThis
- Operands:
(uint32_t nameIndex)
Stack: ⇒this
Like
JSOp::ImplicitThis
, but the name must not be bound in any local environments.The result is always
undefined
except when the name refers to a binding in a non-syntacticwith
environment.Note: The frontend has to emit
Format: JOF_ATOMJSOp::GImplicitThis
(and notJSOp::Undefined
) for global unqualified function calls, even whenCompileOptions::nonSyntacticScope == false
, because laterjs::CloneGlobalScript
can be called withScopeKind::NonSyntactic
to clone the script into a non-syntactic environment, with the bytecode reused, unchanged. CallSiteObj
- 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 IsConstructing
- Stack: ⇒
JS_IS_CONSTRUCTING
Push
MagicValue(JS_IS_CONSTRUCTING)
.This magic value is a required argument to the
JSOp::New
andJSOp::SuperCall
instructions and must not be used any other way. New
,SuperCall
- Operands:
(uint16_t argc)
Stack:callee, isConstructing, args[0], ..., args[argc-1], newTarget
⇒rval
Invoke
callee
as a constructor withargs
andnewTarget
, and push the return value. Throw a TypeError ifcallee
isn't a constructor.isConstructing
must be the value pushed byJSOp::IsConstructing
.JSOp::SuperCall
behaves exactly likeJSOp::New
, but is used for SuperCall expressions, to allow JITs to distinguish them fromnew
expressions.Implements: EvaluateConstruct steps 7 and 8.
Format: JOF_ARGC, JOF_INVOKE, JOF_CONSTRUCT, JOF_TYPESET, JOF_IC SpreadNew
,SpreadSuperCall
- Stack:
callee, isConstructing, args, newTarget
⇒rval
Spread-call variant of
JSOp::New
.Invokes
callee
as a constructor withargs
andnewTarget
, and pushes the return value onto the stack.isConstructing
must be the value pushed byJSOp::IsConstructing
. SeeJSOp::SpreadCall
for restrictions onargs
.
Format: JOF_INVOKE, JOF_CONSTRUCT, JOF_SPREAD, JOF_TYPESET, JOF_ICJSOp::SpreadSuperCall
behaves exactly likeJSOp::SpreadNew
, but is used for SuperCall expressions. SuperFun
- Stack:
callee
⇒superFun
Push the prototype of
callee
in preparation for callingsuper()
.callee
must be a derived class constructor.Implements: GetSuperConstructor, steps 4-7.
CheckThisReinit
- Stack:
thisval
⇒thisval
Throw a ReferenceError if
thisval
is notMagicValue(JS_UNINITIALIZED_LEXICAL)
. Used in derived class constructors to prohibit callingsuper
more than once.Implements: BindThisValue, step 3.
Generators and async functions
Generator
- 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).
InitialYield
- 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
andresumeKind
will receive the values passed in byJSOp::Resume
.resumeKind
is theGeneratorResumeKind
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 byresumeIndex
must be the next instruction in the script, which must beAfterYield
.Implements: GeneratorStart, steps 4-7.
Format: JOF_RESUMEINDEX AfterYield
- Operands:
(uint32_t icIndex)
Bytecode emitted after
yield
expressions. This is useful for the Debugger andAbstractGeneratorObject::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
Format: JOF_ICINDEXYield
,InitialYield
, orAwait
. FinalYieldRval
- 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.
Yield
- 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 (underjs::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 byresumeIndex
must be the next instruction in the script, which must beAfterYield
.When resuming execution,
rval2
,gen
andresumeKind
receive the values passed in byJSOp::Resume
.Implements: GeneratorYield and AsyncGeneratorYield.
Format: JOF_RESUMEINDEX IsGenClosing
- Stack:
val
⇒val, res
Pushes a boolean indicating whether the top of the stack is
MagicValue(JS_GENERATOR_CLOSING)
. AsyncAwait
- 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 awaitedvalue
to a promise and effectively calls.then()
on it, passing handler functions that will resume this async function call later. Seejs::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 withAwait
(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.
AsyncResolve
- 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.
Await
- 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
andresumeKind
receive the values passed in byJSOp::Resume
, and execution continues at the next instruction, which must beAfterYield
.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 AfterYield
AsyncAwait
arranges for this frame to be resumed later and pushes its result promise.Await
then suspends the frame and removes it from the stack, returning the result promise to the caller. (If this async call hasn't awaited before, the caller may be user code. Otherwise, the caller is self-hosted code usingresumeGenerator
.)In async generators:
... # valueToAwait GetAliasedVar ".generator" # valueToAwait gen Await # resolved gen resumeKind AfterYield
AsyncAwait
is not used, so (1) the value returned to the caller byAwait
isvalueToAwait
, notresultPromise
; and (2) the caller is responsible for doing the async-generator equivalent ofAsyncAwait
(namely,js::AsyncGeneratorAwait
, called fromjs::AsyncGeneratorResume
afterjs::CallSelfHostedFunction
returns).
Implements: Await, steps 10-12.
Format: JOF_RESUMEINDEX TrySkipAwait
- Stack:
value
⇒value_or_resolved, can_skip
Decide whether awaiting 'value' can 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,TrySkipAwait
replacesvalue
with the result of theawait
expression (unwrapping the resolved promise, if any) and pushestrue
. Otherwise, it leavesvalue
unchanged and pushes 'false'. ResumeKind
- Operands:
(GeneratorResumeKind resumeKind (encoded as uint8_t))
Stack: ⇒resumeKind
Pushes one of the GeneratorResumeKind values as Int32Value.
CheckResumeKind
- Stack:
rval, gen, resumeKind
⇒rval
Handle Throw and Return resumption.
gen
must be the generator object for the current frame.resumeKind
must be aGeneratorResumeKind
stored as anInt32
value. If it isNext
, continue to the next instruction. IfresumeKind
isThrow
orReturn
, these completions are handled by throwing an exception. SeeGeneratorThrowOrReturn
. Resume
- 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. Oncegen
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
.
Format: JOF_INVOKEgen
must be a suspended generator object.resumeKind
must be in range forGeneratorResumeKind
.
Control flow
Jump targets
JumpTarget
- Operands:
(uint32_t icIndex)
No-op instruction marking the target of a jump instruction.
This instruction and a few others (see
Format: JOF_ICINDEXjs::BytecodeIsJumpTarget
) are jump target instructions. The Baseline Interpreter uses these instructions to sync the frame'sinterpreterICEntry
after a jump. Ion uses them to find block boundaries when translating bytecode to MIR. LoopHead
- 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.
Jumps
Goto
- Operands:
(int32_t offset)
Jump to a 32-bit offset from the current bytecode.
See "Jump instructions" above for details.
Format: JOF_JUMP IfEq
- Operands:
(int32_t forwardOffset)
Stack:cond
⇒If ToBoolean(
Format: JOF_JUMP, JOF_ICcond
) is false, jumps to a 32-bit offset from the current instruction. IfNe
- Operands:
(int32_t offset)
Stack:cond
⇒If ToBoolean(
cond
) is true, jump to a 32-bit offset from the current instruction.
Format: JOF_JUMP, JOF_ICoffset
may be positive or negative. This is the instruction used at the end of a do-while loop to jump back to the top. And
- Operands:
(int32_t forwardOffset)
Stack:cond
⇒cond
Short-circuit for logical AND.
If ToBoolean(
Format: JOF_JUMP, JOF_ICcond
) is false, jump to a 32-bit offset from the current instruction. The value remains on the stack. Or
- Operands:
(int32_t forwardOffset)
Stack:cond
⇒cond
Short-circuit for logical OR.
If ToBoolean(
Format: JOF_JUMP, JOF_ICcond
) is true, jump to a 32-bit offset from the current instruction. The value remains on the stack. Coalesce
- Operands:
(int32_t forwardOffset)
Stack:val
⇒val
Short-circuiting for nullish coalescing.
If
Format: JOF_JUMPval
is not null or undefined, jump to a 32-bit offset from the current instruction. Case
- Operands:
(int32_t forwardOffset)
Stack:val, cond
⇒val (if !cond)
Like
JSOp::IfNe
("jump if true"), but if the branch is taken, pop and discard an additional stack value.This is used to implement
switch
statements when theJSOp::TableSwitch
optimization is not possible. The switch statementswitch (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
Format: JOF_JUMPJSOp::IfNe
andJSOp::Pop
, but that would also be awkward--putting theJSOp::Pop
inside theswitch
body would complicate fallthrough. Default
- 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
Format: JOF_JUMPswitch
statement. If there's adefault:
label, it jumps to that point in the body; otherwise it jumps to the next statement. TableSwitch
- 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 byscript->resumeOffsets()[firstResumeIndex + i - low]
, in bytes from the start of the current script's bytecode. Otherwise, jump to the instruction atdefaultOffset
from the current instruction. All of these offsets must be in range for the current script and must point toJSOp::JumpTarget
instructions.The following inequalities must hold:
low <= high
andfirstResumeIndex + high - low < resumeOffsets().size()
.
Return
Return
- Stack:
rval
⇒Return
rval
.This must not be used in derived class constructors. Instead use
JSOp::SetRval
,JSOp::CheckReturn
, andJSOp::RetRval
. GetRval
- Stack: ⇒
rval
Push the current stack frame's
returnValue
. If noJSOp::SetRval
instruction has been executed in this stack frame, this isundefined
.Every stack frame has a
returnValue
slot, used by top-level scripts, generators, async functions, and derived class constructors. Plain functions usually useJSOp::Return
instead. SetRval
- Stack:
rval
⇒Store
rval
in the current stack frame'sreturnValue
slot.This instruction must not be used in a toplevel script compiled with the
noScriptRval
option. RetRval
Stop execution and return the current stack frame's
returnValue
. If noJSOp::SetRval
instruction has been executed in this stack frame, this isundefined
.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 useJSOp::CheckReturn
to ensure this.CheckReturn
- Stack:
thisval
⇒Check the return value in a derived class constructor.
If the current stack frame's
returnValue
is an object, do nothing.Otherwise, if the
returnValue
is undefined andthisval
is an object, storethisval
in thereturnValue
slot.Otherwise, throw a TypeError.
This is exactly what has to happen when a derived class constructor returns.
thisval
should be the current value ofthis
, orMagicValue(JS_UNINITIALIZED_LEXICAL)
ifthis
is uninitialized.Implements: The [[Construct]] internal method of JS functions, steps 13 and 15.
Exceptions
Throw
- Stack:
exc
⇒Throw
exc
. (ノಠ益ಠ)ノ彡┴──┴This sets the pending exception to
exc
and jumps to error-handling code. If we're in atry
block, error handling adjusts the stack and environment chain and resumes execution at the top of thecatch
orfinally
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. ThrowMsg
- 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
must be one of the error codes listed in js/src/js.msg; it determines the.message
and [[Prototype]] of the new Error object. The number of arguments in the error message must be 0. ThrowSetConst
- Operands:
(uint32_t nameIndex)
Throws a runtime TypeError for invalid assignment to a
Format: JOF_ATOM, JOF_NAMEconst
binding. Try
- Operands:
(int32_t jumpAtEndOffset)
No-op instruction that marks the top of the bytecode for a TryStatement.
The
jumpAtEndOffset
operand must be the offset (relative to the current op) of theJSOp::Goto
at the end of the try-block body. This is used by bytecode analysis and JIT compilation.Location information for catch/finally blocks is stored in a side table,
Format: JOF_CODE_OFFSETscript->trynotes()
. TryDestructuring
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.Exception
- 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.
ResumeIndex
- Operands:
(uint24_t resumeIndex)
Stack: ⇒resumeIndex
Push
resumeIndex
.This value must be used only by
Format: JOF_RESUMEINDEXJSOp::Gosub
,JSOp::Finally
, andJSOp::Retsub
. Gosub
- Operands:
(int32_t forwardOffset)
Stack:false, resumeIndex
⇒Jump to the start of a
finally
block.JSOp::Gosub
is unusual: if the finally block finishes normally, it will reach theJSOp::Retsub
instruction at the end, and control then "returns" to theJSOp::Gosub
and picks up at the next instruction, like a function call but within a single script and stack frame. (It's named after the thing in BASIC.)We need this because a
try
block can terminate in several different ways: control can flow off the end, return, throw an exception,break
with or without a label, orcontinue
. Exceptions are handled separately; but all those success paths are written as bytecode, and each one needs to run thefinally
block before continuing with whatever they were doing. They useJSOp::Gosub
for this. It is thus normal for multipleGosub
instructions in a script to target the samefinally
block.Rules:
forwardOffset
must be positive and must target aJSOp::JumpTarget
instruction followed byJSOp::Finally
. The instruction immediately followingJSOp::Gosub
in the script must be aJSOp::JumpTarget
instruction, andresumeIndex
must be the index intoscript->resumeOffsets()
that points to that instruction.Note: This op doesn't actually push or pop any values. Its use count of 2 is a lie to make the stack depth math work for this very odd control flow instruction.
JSOp::Gosub
is considered to have two "successors": the target ofoffset
, which is the actual next instruction to run; and the instruction immediately followingJSOp::Gosub
, even though it won't run until later. We define the successor graph this way in order to support knowing the stack depth at that instruction without first reading the wholefinally
block.The stack depth at that instruction is, as it happens, the current stack depth minus 2. So this instruction gets nuses == 2.
Unfortunately there is a price to be paid in horribleness. When
Format: JOF_JUMPJSOp::Gosub
runs, it leaves two values on the stack that the stack depth math doesn't know about. It jumps to the finally block, whereJSOp::Finally
again does nothing to the stack, but with a bogus def count of 2, restoring balance to the accounting. IfJSOp::Retsub
is reached, it pops the two values (for real this time) and control resumes at the instruction that follows JSOp::Gosub in memory. Finally
- Stack: ⇒
false, resumeIndex
No-op instruction that marks the start of a
finally
block. This has a def count of 2, but the values are already on the stack (they're actually left on the stack byJSOp::Gosub
).These two values must not be used except by
JSOp::Retsub
. Retsub
- Stack:
throwing, v
⇒Jump back to the next instruction, or rethrow an exception, at the end of a
finally
block. SeeJSOp::Gosub
for the explanation.If
throwing
is true, throwv
. Otherwise,v
must be a resume index; jump to the corresponding offset within the script.The two values popped must be the ones notionally pushed by
JSOp::Finally
.
Variables and scopes
Initialization
Uninitialized
- 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
. 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 slotlocalno
in the current stack frame. Ifv
is the magic value produced byJSOp::Uninitialized
, this marks the binding as uninitialized. Otherwise this initializes the binding with valuev
.Implements: CreateMutableBinding step 3, substep "record that it is uninitialized", and InitializeBinding, for optimized locals. (Note: this is how
Format: JOF_LOCAL, JOF_NAMEconst
bindings are initialized.) InitGLexical
- Operands:
(uint32_t nameIndex)
Stack:val
⇒val
Initialize a global lexical binding.
The binding must already have been created by
DefLet
orDefConst
and must be uninitialized.Like
Format: JOF_ATOM, JOF_NAME, JOF_PROPINIT, JOF_GNAME, JOF_ICJSOp::InitLexical
but for global lexicals. UnlikeInitLexical
this can't be used to mark a binding as uninitialized. InitAliasedLexical
- 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.
Format: JOF_ENVCOORD, JOF_NAME, JOF_PROPINIThops
is usually 0, but infunction f(a=eval("var b;")) { }
, the argumenta
is initialized from inside a nested scope, sohops == 1
. CheckLexical
- 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 samelocalno
.Implements: GetBindingValue step 3 and SetMutableBinding step 4 for declarative Environment Records.
Format: JOF_LOCAL, JOF_NAME CheckAliasedLexical
- 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
Format: JOF_ENVCOORD, JOF_NAMECheckName
orCheckGName
instructions because they're unnecessary.JSOp::{Get,Set}{Name,GName}
all check for uninitialized lexicals and throw if needed. CheckThis
- 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 checkthis
(which needs to be initialized before use, by callingsuper()
).Implements: GetThisBinding step 3.
Looking up bindings
BindGName
- Operands:
(uint32_t nameIndex)
Stack: ⇒global
Push the global environment onto the stack, unless the script has a non-syntactic global scope. In that case, this acts like JSOp::BindName.
Format: JOF_ATOM, JOF_NAME, JOF_GNAME, JOF_ICnameIndex
is only used when acting like JSOp::BindName. BindName
- 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
Getting binding values
GetName
- 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 pushundefined
.Implements: ResolveBinding followed by GetValue (adjusted hackily for
typeof
).This is the fallback
Format: JOF_ATOM, JOF_NAME, JOF_TYPESET, JOF_ICGet
instruction that handles all unoptimized cases. Optimized instructions follow. GetGName
- 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.NonSyntacticVariablesObject
s break this optimization, so if the current script has a non-syntactic global scope, this acts likeJSOp::GetName
.Like
Format: JOF_ATOM, JOF_NAME, JOF_TYPESET, JOF_GNAME, JOF_ICJSOp::GetName
, this throws a ReferenceError if no such binding is found (unless the next instruction isJSOp::Typeof
) or if the binding is an uninitialized lexical. GetArg
- Operands:
(uint16_t argno)
Stack: ⇒arguments[argno]
Push the value of an argument that is stored in the stack frame or in an
Format: JOF_QARG, JOF_NAMEArgumentsObject
. GetLocal
- Operands:
(uint24_t localno)
Stack: ⇒val
Push the value of an optimized local variable.
If the variable is an uninitialized lexical, push
Format: JOF_LOCAL, JOF_NAMEMagicValue(JS_UNINIITALIZED_LEXICAL)
. GetAliasedVar
- 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 inEnvironmentObject
s.Where possible,
Aliased
instructions are used to access aliased bindings. (There's no difference in meaning betweenAliasedVar
andAliasedLexical
.) Each of these instructions has operandshops
andslot
that encode anEnvironmentCoordinate
, directions to the binding from the current environment object.
Format: JOF_ENVCOORD, JOF_NAME, JOF_TYPESET, JOF_ICAliased
instructions can't be used when there's a dynamic scope (due to non-stricteval
orwith
) that might shadow the aliased binding. GetImport
- 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, JOF_TYPESET, JOF_IC GetBoundName
- Operands:
(uint32_t nameIndex)
Stack:env
⇒v
Get the value of a binding from the environment
env
. If the name is not bound inenv
, throw a ReferenceError.env
must be an environment currently on the environment chain, pushed byJSOp::BindName
orJSOp::BindVar
.Note:
JSOp::BindName
andJSOp::GetBoundName
are the two halves of theJSOp::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_TYPESET, JOF_IC GetIntrinsic
- 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
Format: JOF_ATOM, JOF_NAME, JOF_TYPESET, JOF_ICGlobalObject::getIntrinsicsHolder
), which is used in lieu of global bindings in self-hosting code. Callee
- 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 (viawith
,eval
, or a nested closure). EnvCallee
- 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 bynumHops
must be a CallObject.
Setting binding values
SetName
- Operands:
(uint32_t nameIndex)
Stack:env, val
⇒val
Assign
val
to the binding inenv
with the name given bynameIndex
. 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 byJSOp::BindName
orJSOp::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:
Format: JOF_ATOM, JOF_NAME, JOF_PROPSET, JOF_CHECKSLOPPY, JOF_ICJSOp::BindName
andJSOp::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 aBind
instruction because the "finding" is done statically. StrictSetName
- Operands:
(uint32_t nameIndex)
Stack:env, val
⇒val
Like
JSOp::SetName
, but throw a TypeError if there is no binding for the specified name inenv
, or if the binding is immutable (aconst
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 SetGName
- Operands:
(uint32_t nameIndex)
Stack:env, val
⇒val
Like
Format: JOF_ATOM, JOF_NAME, JOF_PROPSET, JOF_GNAME, JOF_CHECKSLOPPY, JOF_ICJSOp::SetName
, but for assigning to globals.env
must be an environment pushed byJSOp::BindGName
. StrictSetGName
- Operands:
(uint32_t nameIndex)
Stack:env, val
⇒val
Like
Format: JOF_ATOM, JOF_NAME, JOF_PROPSET, JOF_GNAME, JOF_CHECKSTRICT, JOF_ICJSOp::StrictSetGName
, but for assigning to globals.env
must be an environment pushed byJSOp::BindGName
. SetArg
- Operands:
(uint16_t argno)
Stack:val
⇒val
Assign
Format: JOF_QARG, JOF_NAMEval
to an argument binding that's stored in the stack frame or in anArgumentsObject
. SetLocal
- Operands:
(uint24_t localno)
Stack:v
⇒v
Assign to an optimized local binding.
Format: JOF_LOCAL, JOF_NAME SetAliasedVar
- 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 SetIntrinsic
- 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,
Format: JOF_ATOM, JOF_NAMEGlobalObject::getIntrinsicsHolder
. (Self-hosted code doesn't have many globalvar
s, but it has manyfunction
s.)
Entering and leaving environments
PushLexicalEnv
- Operands:
(uint32_t lexicalScopeIndex)
Push a lexical environment onto the environment chain.
The
LexicalScope
indicated bylexicalScopeIndex
determines the shape of the newLexicalEnvironmentObject
. All bindings in the new environment are marked as uninitialized.Implements: Evaluation of Block, steps 1-4.
Fine print for environment chain instructions
The following rules for
JSOp::{Push,Pop}LexicalEnv
also apply toJSOp::PushVarEnv
andJSOp::{Enter,Leave}With
.Each
JSOp::PopLexicalEnv
instruction matches a particularJSOp::PushLexicalEnv
instruction in the same script and must have the same scope and stack depth as the instruction immediately after thatPushLexicalEnv
.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 executingPushLexicalEnv
and can exit only by executing aPopLexicalEnv
or by exception unwinding. (AJSOp::PopLexicalEnv
is always emitted at the end of the block, and extra copies are emitted on "exit slides", where abreak
,continue
, orreturn
statement exits the scope.)The script's
Format: JOF_SCOPEJSScript::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 afterJSOp::PushLexicalEnv
toJSOp::PopLexicalEnv
(inclusive); but if that range contains any instructions on exit slides, after aJSOp::PopLexicalEnv
, then those must be correctly noted as outside the scope. PopLexicalEnv
Pop a lexical environment from the environment chain.
See
JSOp::PushLexicalEnv
for the fine print.DebugLeaveLexicalEnv
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 either this instruction (if the scope is optimized) or
JSOp::PopLexicalEnv
(if not).RecreateLexicalEnv
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.
The current environment must be a LexicalEnvironmentObject.
FreshenLexicalEnv
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.The current environment must be a LexicalEnvironmentObject.
PushVarEnv
- Operands:
(uint32_t scopeIndex)
Push a var environment onto the environment chain.
Like
JSOp::PushLexicalEnv
, but pushes aVarEnvironmentObject
rather than aLexicalEnvironmentObject
. The difference is that non-strict directeval
can add bindings to a var environment; seeVarScope
in Scope.h.See
JSOp::PushLexicalEnv
for the fine print.There is no corresponding
JSOp::PopVarEnv
operation, because aVarEnvironmentObject
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
Format: JOF_SCOPEJSOp::PushVarEnv
is not needed. EnterWith
- 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 deoptimizedJSOp::GetName
,BindName
,SetName
, andDelName
instead. Since those instructions don't work correctly with optimized locals and arguments, all bindings in scopes enclosing awith
statement are marked as "aliased" and deoptimized too.See
Format: JOF_SCOPEJSOp::PushLexicalEnv
for the fine print. LeaveWith
Pop a
WithEnvironmentObject
from the environment chain.See
JSOp::PushLexicalEnv
for the fine print.Implements: Evaluation of
with
statements, step 8.
Creating and deleting bindings
BindVar
- 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.
DefVar
- Operands:
(uint32_t nameIndex)
Create a new binding on the current VariableEnvironment (the environment on the environment chain designated to receive new variables).
JSOp::Def{Var,Let,Const,Fun}
instructions must appear in the script before anything else that might add bindings to the environment, and only once per binding. There must be a correct entry for the new binding inscript->bodyScope()
. (All this ensures that at run time, there is no existing conflicting binding. This is checked by theJSOp::CheckGlobalOrEvalDecl
bytecode instruction that must appear beforeJSOp::Def{Var,Let,Const,Fun}
.)Throw a SyntaxError if the current VariableEnvironment is the global environment 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.
Format: JOF_ATOM DefFun
- Stack:
fun
⇒Create a new binding for the given function on the current scope.
fun
must be a function object with an explicit name. The new variable's name isfun->explicitName()
, and its value isfun
. In global scope, this creates a new property on the global object.Implements: The body of the loop in GlobalDeclarationInstantiation step 17 ("For each Parse Node f in functionsToInitialize...") and the corresponding loop in EvalDeclarationInstantiation.
DefLet
- Operands:
(uint32_t nameIndex)
Create a new uninitialized 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.
Format: JOF_ATOM DefConst
- Operands:
(uint32_t nameIndex)
Like
Format: JOF_ATOMDefLet
, but create an uninitialized constant binding. CheckGlobalOrEvalDecl
Check for conflicting bindings before
JSOp::Def{Var,Let,Const,Fun}
in global or sloppy eval scripts.Implements: GlobalDeclarationInstantiation steps 5, 6, 10 and 12, and EvalDeclarationInstantiation steps 5 and 8.
DelName
- 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:
Format: JOF_ATOM, JOF_NAME, JOF_CHECKSLOPPYdelete
Identifier, which is a SyntaxError in strict mode code.
Function environment setup
Arguments
- 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 timearguments
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 useJSOp::Arguments
at all.The current script must be a function script. 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 ofarguments
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 ofJSOp::GetElem
checks for optimized arguments (seeGetElemOptimizedArguments
).Example 2:
f.apply(this, arguments)
is supported; therefore our implementation ofFunction.prototype.apply
checks for optimized arguments (see js::fun_apply
), and allJSOp::FunApply
implementations must check for cases wheref.apply
turns out to be any other function (seeGuardFunApplyArgumentsOptimization
).It's not documented anywhere exactly which opcodes support
JS_OPTIMIZED_ARGUMENTS
; see the source ofAnalyzeArgumentsUsage
. Rest
- 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_TYPESET, JOF_IC FunctionThis
- 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 athis
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/nullthis
is converted into the globalthis
value. Other primitive values are boxed. Seejs::BoxNonStrictThis
.
Stack operations
Pop
- Stack:
v
⇒Pop the top value from the stack and discard it.
PopN
- 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. Dup
- Stack:
v
⇒v, v
Push a copy of the top value on the stack.
Dup2
- Stack:
v1, v2
⇒v1, v2, v1, v2
Duplicate the top two values on the stack.
DupAt
- 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. Swap
- Stack:
v1, v2
⇒v2, v1
Swap the top two values on the stack.
Pick
- 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.
Unpick
- 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
n
th element of the stack.n
must not be 0.
Other
Nop
Do nothing. This is used when we need distinct bytecode locations for various mechanisms.
Lineno
- 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. NopDestructuring
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 theundefined
, so that the expression decompiler and disassembler know to casually ignore the possibility ofundefined
, and render the result of the conditional expression simply as "result.value
".ForceInterpreter
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.
DebugCheckSelfHosted
- 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.
InstrumentationActive
- Stack: ⇒
val
Push a boolean indicating if instrumentation is active.
InstrumentationCallback
- Stack: ⇒
val
Push the instrumentation callback for the current realm.
InstrumentationScriptId
- Stack: ⇒
val
Push the current script's instrumentation ID.
Debugger
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论