blob: ec9bb799677856bb271481e7d0efb063cf6877b5 [file] [log] [blame] [view] [edit]
# Dart Bytecode File Format
## Overview
This file describes the binary format of Dart bytecode files.
Dart bytecode is a binary representation of dynamic modules
on the VM/AOT. It is generated by dart2bytecode tools and
can be executed by the VM and AOT runtime (built with dynamic modules support).
## Basic types
This document uses notation similar to [Dart kernel binary format](https://github.com/dart-lang/sdk/blob/main/pkg/kernel/binary.md).
The follow basic data types are used to describe bytecode format.
```
type Byte = a byte
type UInt = packed (variable-length) unsigned integer, same format as kernel binary
type SLEB128 = packed (variable-length) signed integer
type UInt32 = little-endian 32-bit unsigned integer
type List<T> {
UInt length
T[length] items
}
type Pair<T0, T1> {
T0 first
T1 second
}
// Offset in the source file + 1.
type FileOffset = UInt
```
## Bytecode file
Each bytecode file describes a dynamic module, a set of Dart libraries
which can be loaded at runtime.
All declarations in the Dart bytecode file are sliced into several layers,
which reside in different sections such as libraries, classes, members, code, etc.
```
type BytecodeFile {
UInt32 magic = 0x44424333; // 'DBC3'
UInt32 formatVersion = 1;
// Descriptors of the sections below.
// Each section has a fixed index in the descriptors array.
Section[] sections;
// Sections. The contents of the sections can occur in arbitrary
// order and with gaps between sections, so they should be located only via
// section descriptor.
StringTable stringTable;
ObjectTable objectTable;
EntryPoint entryPoint;
LibraryUriAndOffset[] libraryIndex;
LibraryDeclaration[] libraries;
ClassDeclaration[] classes;
Members[] members;
Code[] codes;
SourcePositions[] sourcePositions;
SourceFile[] sourceFiles;
LineStarts[] lineStarts;
LocalVariables[] localVariables;
PackedObject[] annotations;
}
type Section {
// Number of items in the section.
// Zero for string table, object table and entry point sections.
UInt32 numItems;
// Offset of the section relative to the beginning of the bytecode file, in bytes.
UInt32 offset;
}
```
### String table
String table section contains strings encoded as 1-byte (Latin1) and 2-byte (UTF-16) characters.
Strings are not zero-terminated.
This representation is aligned with Dart VM and allows VM to avoid extra copying and
decoding of string characters when loading a string.
```
type StringTable = {
UInt32 numOneByteStrings;
UInt32 numTwoByteStrings;
// Offsets are relative to stringContents.
UInt32[numOneByteStrings] oneByteStringEndOffsets;
UInt32[numTwoByteStrings] twoByteStringEndOffsets;
// Contains string characters of one-byte strings and then two-byte strings.
Byte[] stringContents;
}
// Reference to a string in string table.
type PackedString {
// Bit 0: set for two-byte string
// Bits 1+: index of string in one-byte strings (0..numOneByteStrings-1)
// or two-byte strings (0..numTwoByteStrings-1).
UInt indexAndKind;
}
```
### Object table
Object table section contains various objects referenced by declarations and constant pools.
Object included into the object table can be shared by multiple constant pools,
so object table provides a way to de-duplicate objects, reducing bytecode file
size and bytecode loading time.
Bytecode generator can choose to include particular object into the object table or write it inline.
Object is written inline (not included into object table) if there are only a few references to that object or
it is small and can be created efficiently (for example, int and bool constants are always written inline).
```
type ObjectTable {
UInt numEntries;
// Total size of ‘objects’ in bytes.
UInt objectsSize;
ObjectContents[numEntries] objects;
// Offsets relative to ‘objects’.
UInt[numEntries] objectOffsets;
}
// Either reference to an object in the object table, or object contents
// written inline (determined by bit 0).
PackedObject = ObjectReference | ObjectContents;
type ObjectReference {
// Bit 0 (reference bit): 1
// Bits 1+: index in the object table
UInt reference;
}
type ObjectContents {
// Bit 0 (reference bit): 0
// Bits 1-4: object kind
// Bits 5+ object flags
UInt header;
}
// Invalid/null object. Always present at index 0 of object table.
type InvalidObject extends ObjectContents {
kind = 0;
}
type Library extends ObjectContents {
kind = 1;
PackedObject importUri;
}
type Script extends ObjectContents {
kind = 2;
flags = (hasSourceFile);
PackedObject uri;
if hasSourceFile
// Offset of source file in ‘sourceFiles’ section of BytecodeFile.
UInt sourceFileOffset;
}
type Class extends ObjectContents {
kind = 3;
PackedObject library;
// Empty name is used for artificial class containing top-level
// members of a library.
PackedObject name;
}
type Member extends ObjectContents {
kind = 4;
flags = (isField, isConstructor);
PackedObject class;
PackedObject name;
}
type Closure extends ObjectContents {
kind = 5;
PackedObject enclosingMember;
UInt closureIndex;
}
type Name extends ObjectContents {
kind = 6;
flags = (isPublic);
if !isPublic
PackedObject library;
// Getters are prefixed with 'get:'.
// Setters are prefixed with 'set:'.
PackedString name;
}
abstract type ConstObject extends ObjectContents {
kind = 7;
flags = constantTag (4 bits);
}
type ConstInt extends ConstValue {
kind = 7;
constantTag = 1;
SLEB128 value;
}
type ConstDouble extends ConstValue {
kind = 7;
constantTag = 2;
// double bits are reinterpreted as 64-bit int
SLEB128 value;
}
type ConstBool extends ConstValue {
kind = 7;
constantTag = 3;
Byte isTrue;
}
type ConstString extends ConstObject {
kind = 7;
constantTag = 4;
PackedString string;
}
type ConstSymbol extends ConstObject {
kind = 7;
constantTag = 5;
PackedObject name;
}
type ConstInstance extends ConstObject {
kind = 7;
constantTag = 6;
PackedObject type;
List<Pair<PackedObject, PackedObject>> fieldValues;
}
type ConstList extends ConstObject {
kind = 7;
constantTag = 7;
PackedObject elementType;
List<PackedObject> elements;
}
type ConstMap extends ConstObject {
kind = 7;
constantTag = 8;
// Map<K, V> type.
PackedObject mapType;
// [key1, value1, key2, value2, ....]
List<PackedObject> elements;
}
type ConstSet extends ConstObject {
kind = 7;
constantTag = 9;
PackedObject elementType;
List<PackedObject> elements;
}
type ConstRecord extends ConstObject {
kind = 7;
constantTag = 10;
PackedObject recordType;
// Values of positional, then named fields.
List<PackedObject> fieldValues;
}
type ConstTearOff extends ConstObject {
kind = 7;
constantTag = 11;
PackedObject target;
}
type ConstTearOffInstantiation extends ConstObject {
kind = 7;
constantTag = 12;
PackedObject tearOff;
PackedObject typeArguments;
}
abstract type Type extends ObjectContents {
kind = 8;
flags = (typeTag (4 bits), isNullable);
}
type DynamicType extends Type {
kind = 8;
typeTag = 1;
}
type VoidType extends Type {
kind = 8;
typeTag = 2;
}
type NullType extends Type {
kind = 8;
typeTag = 3;
}
type NeverType extends Type {
kind = 8;
typeTag = 4;
}
// Interface type without type arguments.
type SimpleType extends Type {
kind = 8;
typeTag = 5;
PackedObject class;
}
// Generic interface type.
type GenericType extends Type {
kind = 8;
typeTag = 6;
PackedObject class;
PackedObject typeArguments;
}
type TypeParameter extends Type {
kind = 8;
typeTag = 7;
// Class, Member or Closure declaring this type parameter.
// Null (Invalid) if declared by function type.
PackedObject parent;
// For type parameters declared by function types this index is in a concatenation
// of type parameters of all enclosing function types.
UInt indexInParent;
}
type FunctionType extends Type {
kind = 8;
typeTag = 8;
UInt functionTypeFlags = (hasOptionalPositionalParams,
hasOptionalNamedParams,
hasTypeParams,
hasEnclosingTypeParameters,
hasParameterFlags);
if hasEnclosingTypeParameters
UInt numEnclosingTypeParameters;
if hasTypeParams
TypeParametersDeclaration typeParameters;
UInt numParameters;
if hasOptionalPositionalParams || hasOptionalNamedParams
UInt numRequiredParameters;
Type[] positionalParameters;
NameAndType[] namedParameters;
if hasParameterFlags
// For named parameters: (isRequired)
List<UInt> parameterFlags;
PackedObject returnType;
}
type TypeParametersDeclaration {
UInt numTypeParameters;
PackedObject[numTypeParameters] names;
BoundAndDefaultType[numTypeParameters] boundsAndDefaultTypes;
}
type BoundAndDefaultType {
PackedObject bound;
PackedObject defaultType;
}
type NameAndType {
PackedObject name;
PackedObject type;
}
type RecordType extends Type {
kind = 8;
typeTag = 9;
UInt numPositionalFields;
UInt numNamedFields;
Type[numPositionalFields] positionalFields;
NameAndType[numNamedFields] namedFields;
}
// Type arguments vector.
type TypeArguments extends ObjectContents {
kind = 6;
List<PackedObject> args;
}
// Describes shape of arguments passed to a call.
type ArgDesc extends ObjectContents {
kind = 8;
flags = (hasNamedArgs, hasTypeArgs);
UInt numArguments;
if hasTypeArgs
UInt numTypeArguments;
if hasNamedArgs
List<PackedObject> argNames;
}
```
### Entry point
Entry point section contains a reference to a dynamic module entry point function.
```
type EntryPoint {
PackedObject member;
}
```
### Library index
Library index section contains the list of library "forward declarations"
in the form of library URI and offset of its full declaration.
```
type LibraryUriAndOffset {
PackedObject uri;
// Offset of library declaration in the ‘libraries’ section of BytecodeFile.
UInt libraryOffset
}
```
### Libraries
Libraries section contains declarations of libraries included into a dynamic module.
Number of items in the library index section and libraries section should be the same.
```
type LibraryDeclaration {
UInt flags = (usesDartMirrors, usesDartFfi);
PackedObject name;
PackedObject script;
// Classes declared in this library.
// The first class is an artificial ‘top-level’ class containing top-level
// fields and functions, as well as library annotations.
List<ClassNameAndOffset> classes;
}
type ClassNameAndOffset {
PackedObject className;
// Offset of class declaration in the ‘classes’ section of BytecodeFile.
UInt classOffset;
}
```
### Classes
Classes section contains declarations of classes included into a dynamic module.
Each class in the classes section should be mentioned in its library declaration.
```
type ClassDeclaration {
UInt flags = (isAbstract, isEnum,
hasTypeParams, hasTypeArguments,
isTransformedMixinApplication,
hasSourcePositions, hasAnnotations, hasPragma,
hasConstConstructor, isSealed, isMixinClass,
isBaseClass, isInterface, isFinal);
PackedObject script;
if hasSourcePositions
FileOffset position;
FileOffset endPosition;
if hasTypeArguments
UInt numTypeArguments;
if hasTypeParams
TypeParametersDeclaration typeParameters;
PackedObject superType;
List<PackedObject> interfaces;
if hasAnnotations
UInt annotationsOffset;
// Offset of class members in the ‘members’ section of BytecodeFile.
UInt membersOffset;
}
```
### Members
Members section contains declaration of members (fields, methods and constructors).
Member declarations are organized per class.
```
type Members {
// Total number of functions, including field getters and setters.
UInt numFunctions;
List<FieldDeclaration> fields;
List<FunctionDeclaration> functions;
}
type FieldDeclaration {
UInt flags = (isStatic, isConst, isFinal, isLate,
isCovariant, isCovariantByClass,
isExtensionMember, isReflectable,
hasGetter, hasSetter,
hasInitializer, hasNontrivialInitializer, hasInitializerCode,
hasSourcePositions, hasAnnotations, hasPragma,
hasCustomScript);
PackedObject name;
PackedObject type;
if hasCustomScript
PackedObject script;
if hasSourcePositions
FileOffset position;
FileOffset endPosition;
if hasInitializerCode
// Offset of initializer code in the ‘code’ section of BytecodeFile.
UInt initializerCodeOffset;
if !hasNontrivialInitializer
PackedObject value;
if hasGetter
PackedObject getterName;
if hasSetter
PackedObject setterName;
if hasAnnotations
UInt annotationsOffset;
}
type FunctionDeclaration {
UInt flags = (isStatic, isAbstract, isGetter, isSetter,
isConstructor, isFactory, isConst,
hasOptionalPositionalParams, hasOptionalNamedParams,
hasTypeParams, hasParameterFlags,
isExtensionMember, isReflectable, isDebuggable,
isAsync, isAsyncStar, isSyncStar,
isNoSuchMethodForwarder, isExternal, isNative,
hasSourcePositions, hasAnnotations, hasPragma,
hasCustomScript);
PackedObject name;
if hasCustomScript
PackedObject script;
if hasSourcePositions
FileOffset position;
FileOffset endPosition;
if hasTypeParams
TypeParametersDeclaration typeParameters;
UInt numParameters;
if hasOptionalPositionalParams || hasOptionalNamedParams
UInt numRequiredParameters;
NameAndType[numParameters] parameters;
if hasParameterFlags
// For named parameters: (isRequired)
List<UInt> parameterFlags;
PackedObject returnType;
if isNative
PackedObject nativeName;
if !isAbstract
// Offset of code in the ‘code’ section of BytecodeFile.
UInt codeOffset;
if hasAnnotations
// Offset of function annotations in ‘annotations’ section of
// component, followed by parameter annotations.
UInt annotationsOffset;
}
```
### Code
Code section contains bodies of members (including field initializers).
```
type Code {
UInt flags = (hasExceptionsTable, hasSourcePositions, hasNullableFields,
hasClosures, hasParameterFlags, hasForwardingStubTarget,
hasDefaultFunctionTypeArgs, hasLocalVariables)
if hasParameterFlags
// For all parameters: (isCovariant, isCovariantByClass)
List<UInt> flags;
if hasForwardingStubTarget
ConstantIndex forwardingStubTarget;
if hasDefaultFunctionTypeArgs
ConstantIndex defaultFunctionTypeArgs;
if hasClosures
List<ClosureDeclaration> closureDeclarations;
ConstantPool constantPool;
UInt bytecodeSizeInBytes
Byte[bytecodeSizeInBytes] bytecodes;
if hasExceptionsTable
ExceptionsTable exceptionsTable;
if hasSourcePositions
// Offset of SourcePositions in ‘sourcePositions’ section of BytecodeFile.
UInt sourcePositionsOffset;
if hasLocalVariables
// Offset of LocalVariables in ‘localVariables’ section of BytecodeFile.
UInt localVariablesOffset;
if hasNullableFields
List<PackedObject> nullableFields;
if hasClosures
// Parallel to closureDeclarations.
ClosureCode[] closures;
}
type ClosureDeclaration {
UInt flags = (hasOptionalPositionalParams, hasOptionalNamedParams,
hasTypeParams, hasSourcePositions,
isAsync, isAsyncStar, isSyncStar, isDebuggable,
hasParameterFlags)
// Member or Closure.
PackedObject parent;
PackedObject name;
if hasSourcePositions
FileOffset position;
FileOffset endPosition;
if hasTypeParams
TypeParametersDeclaration typeParameters;
UInt numParameters;
if hasOptionalPositionalParams || hasOptionalNamedParams
UInt numRequiredParameters;
NameAndType[numParameters] parameters;
if hasParameterFlags
// For named parameters: (isRequired)
List<UInt> parameterFlags;
PackedObject returnType;
}
type ClosureCode {
UInt flags = (hasExceptionsTable, hasSourcePositions, hasLocalVariables)
UInt bytecodeSizeInBytes;
Byte[bytecodeSizeInBytes] bytecodes;
if hasExceptionsTable
ExceptionsTable exceptionsTable;
if hasSourcePositions
// Offset of SourcePositions in ‘sourcePositions’ section of BytecodeFile.
UInt sourcePositionsOffset;
if hasLocalVariables
// Offset of LocalVariables in ‘localVariables’ section of BytecodeFile.
UInt localVariablesOffset;
}
```
### Constant Pool
Each member code has its own constant pool which describes an array of objects
used by the interpreter at runtime along with bytecode instructions.
Member constant pool is shared by all closure functions declared in the member.
Bytecode instructions reference constant pool entries by index.
```
type ConstantPool {
List<ConstantPoolEntry> entries;
}
// Index of entry in the constant pool.
type ConstantIndex = UInt;
abstract type ConstantPoolEntry {
Byte tag;
}
type ConstantObjectRef extends ConstantPoolEntry {
Byte tag = 1;
PackedObject object;
}
type ConstantClass extends ConstantPoolEntry {
Byte tag = 2;
PackedObject class;
}
type ConstantType extends ConstantPoolEntry {
Byte tag = 3;
PackedObject type;
}
type ConstantStaticField extends ConstantPoolEntry {
Byte tag = 4;
PackedObject field;
}
// Occupies 2 entries in the constant pool.
// (to hold offset and field object).
type ConstantInstanceField extends ConstantPoolEntry {
Byte tag = 5;
PackedObject field;
}
type ConstantTypeArgumentsField extends ConstantPoolEntry {
Byte tag = 6;
PackedObject class;
}
type ConstantClosureFunction extends ConstantPoolEntry {
Byte tag = 7;
UInt closureIndex;
}
type ConstantEndClosureFunctionScope extends ConstantPoolEntry {
Byte tag = 8;
}
type ConstantSubtypeTestCache extends ConstantPoolEntry {
Byte tag = 9;
}
type ConstantEmptyTypeArguments extends ConstantPoolEntry {
Byte tag = 10;
}
// Occupies 2 entries in the constant pool
// (to hold target and arguments descriptor).
type ConstantDirectCall extends ConstantPoolEntry {
Byte tag = 11;
PackedObject target;
PackedObject argDesc;
}
// Occupies 2 entries in the constant pool
// (to hold interface target and arguments descriptor).
type ConstantInterfaceCall extends ConstantPoolEntry {
Byte tag = 12;
PackedObject target;
PackedObject argDesc;
}
// Occupies 3 entries in the constant pool.
type ConstantInstantiatedInterfaceCall extends ConstantPoolEntry {
Byte tag = 13;
PackedObject target;
PackedObject argDesc;
PackedObject staticReceiverType;
}
// Occupies 2 entries in the constant pool
type ConstantDynamicCall extends ConstantPoolEntry {
Byte tag = 14;
PackedObject selectorName;
PackedObject argDesc;
}
// Occupies 2 entries in the constant pool
type ConstantExternalCall extends ConstantPoolEntry {
Byte tag = 15;
}
```
### Exceptions table
Each Code and ClosureCode may have an optional table of try blocks
which maps ranges of bytecode instructions to corresponding exception handlers.
```
// Offset of a bytecode instruction in 'bytecodes'.
type BytecodeOffset = UInt;
type TryBlock {
UInt outerTryIndexPlus1;
BytecodeOffset startPC; // Inclusive.
BytecodeOffset endPC; // Exclusive.
BytecodeOffset handlerPC;
Byte flags = (needsStackTrace, isSynthetic);
List<ConstantIndex> types;
}
type ExceptionsTable {
// Ordered by startPC, then by nesting (outer precedes inner).
// Try blocks are properly nested. It means there are no partially
// overlapping try blocks - each pair of try block regions either
// has no intersection or one try block region encloses another.
List<TryBlock> tryBlocks;
}
```
### Source positions
Source positions information maps ranges of bytecode instructions to
corresponding source positions. This information is optional and resides in
the 'sourcePositions' section of BytecodeFile.
```
type SourcePositions {
UInt numEntries;
// Encoded list of pairs (PC, FileOffset), ordered by PC (offset of bytecode instruction).
// For two consecutive entries (PC1, FileOffset1), (PC2, FileOffset2) all
// bytecode instructions in range [PC1,PC2) correspond to a source
// position FileOffset1.
SourcePositionEntry[numEntries] entries
}
type SourcePositionEntry = {
// Delta-encoded PC (delta from the PC of previous entry).
UInt PCDelta;
// Delta-encoded FileOffset (delta from the FileOffset of previous entry).
SLEB128 FileOffsetDelta;
}
```
### Source files and line starts
```
type SourceFile {
UInt flags = (hasLineStarts, hasSource)
PackedObject importUri;
if hasLineStarts
// Offset of line starts in ‘lineStarts’ section of BytecodeFile.
UInt lineStartsOffset;
if hasSource
PackedString source;
}
type LineStarts {
// Can be also treated as line lengths.
List<UInt> deltaEncodedLineStarts;
}
```
### Local variables
```
type LocalVariables {
UInt numEntries;
// Encoded list of entries ordered by PC (offset of bytecode instruction).
LocalVariableEntry[numEntries] entries;
}
abstract type LocalVariableEntry = {
// Bits 0-3: kind
// Bits 4-7: flags
Byte kindAndFlags;
// Delta-encoded start PC.
SLEB128 startPCDelta;
}
type Scope extends LocalVariableEntry {
kind = 1
// Offset to the end PC relative to startPC.
UInt endPCDelta;
// Level of context containing captured variables in this scope.
// -1 if there is no context.
SLEB128 contextLevel;
FileOffset position;
FileOffset endPosition;
}
// Variable declarations immediately follow their corresponding Scope
type VariableDeclaration extends LocalVariableEntry {
kind = 2
flags = (isCaptured)
// Index of local variable in the stack frame or in the context.
SLEB128 index;
ConstantIndex name;
ConstantIndex type;
// Source position where variable is declared.
FileOffset position;
// Source position after variable is initialized.
FileOffset initializedPosition;
}
type ContextVariable extends LocalVariableEntry {
kind = 3
// Index of a local variable holding context (in the stack frame).
SLEB128 index;
}
```
## Bytecode instructions
### Execution state
Dart bytecode interpreter is a stack machine with local variables.
Bytecode instructions should begin by creating a frame using
`Entry`, `EntryOptional` or `EntrySuspendable` instruction.
After creating a frame, local variables and parameters can be referenced as `Locals[i]` up to the size of the frame.
For frames created with `Entry` instruction, parameter n is accessible via `Locals[-numParams-kParamEndSlotFromFp+n]`
(where `kParamEndSlotFromFp == 4`). For frames created with `EntryOptional` or `EntrySuspendable` instructions,
parameter n is copied to `Locals[n]`.
Most bytecode instructions take values from the expression stack or push values onto the stack.
Stack and local variables are disjoint, e.g. instructions operating with locals cannot be used to access stack and vice versa.
Stack pointer is referred as `SP`, stack grows up. `SP[0]` is the value on top of the stack, `SP[-1]`, `SP[-2]` etc are values pushed previously.
Stack can be used after frame setup and initially empty.
Data flow merges are not allowed on the stack: at each PC and stack location,
there should be exactly one bytecode instructions which could have pushed a value into that stack location,
regardless of how control reached that PC.
Bytecode instructions can reference constant pool via `ConstantPool[i]`.
### Instruction encoding
Each instruction starts with opcode byte. Certain instructions have
wide encoding variant. In such case, the least significant bit of opcode is
0 for compact variant and 1 for wide variant.
The following operand encodings are used:
```
0........8.......16.......24.......32.......40.......48
+--------+
| opcode | 0: no operands
+--------+
+--------+--------+
| opcode | A | A: unsigned 8-bit operand
+--------+--------+
+--------+--------+
| opcode | D | D: unsigned 8/32-bit operand
+--------+--------+
+--------+----------------------------------+
| opcode | D | D (wide)
+--------+----------------------------------+
+--------+--------+
| opcode | X | X: signed 8/32-bit operand
+--------+--------+
+--------+----------------------------------+
| opcode | X | X (wide)
+--------+----------------------------------+
+--------+--------+
| opcode | T | T: signed 8/24-bit operand
+--------+--------+
+--------+--------------------------+
| opcode | T | T (wide)
+--------+--------------------------+
+--------+--------+--------+
| opcode | A | E | A_E: unsigned 8-bit operand and
+--------+--------+--------+ unsigned 8/32-bit operand
+--------+--------+----------------------------------+
| opcode | A | E | A_E (wide)
+--------+--------+----------------------------------+
+--------+--------+--------+
| opcode | A | Y | A_Y: unsigned 8-bit operand and
+--------+--------+--------+ signed 8/32-bit operand
+--------+--------+----------------------------------+
| opcode | A | Y | A_Y (wide)
+--------+--------+----------------------------------+
+--------+--------+--------+
| opcode | D | F | D_F: unsigned 8/32-bit operand and
+--------+--------+--------+ unsigned 8-bit operand
+--------+----------------------------------+--------+
| opcode | D | F | D_F (wide)
+--------+----------------------------------+--------+
+--------+--------+--------+--------+
| opcode | A | B | C | A_B_C: 3 unsigned 8-bit operands
+--------+--------+--------+--------+
```
### Instruction Set
#### Trap
Unreachable instruction.
#### Entry D
Function prologue for the function.
D - number of local slots to reserve.
#### EntryOptional A, B, C
Function prologue for the function with optional or named arguments.
A - expected number of positional arguments.
B - number of optional positional arguments.
C - number of named arguments.
Only one of B and C can be not 0.
If B is not 0 then EntryOptional bytecode is followed by B LoadConstant
bytecodes specifying default values for optional positional arguments.
If C is not 0 then EntryOptional is followed by 2 * C LoadConstant
bytecodes.
Bytecode at 2 * i specifies name of the i-th named argument and at
2 * i + 1 default value. ‘A’ operand of the LoadConstant bytecode specifies
the location of the parameter on the stack. Named arguments are
sorted alphabetically.
Note: Unlike Entry bytecode EntryOptional does not setup the frame for
local variables. This is done by a separate bytecode Frame, which should
follow EntryOptional and its LoadConstant instructions.
#### EntrySuspendable A, B, C
Similar to EntryOptional, but also reserves a local variable slot
for suspend state variable.
#### LoadConstant A, E
Used in conjunction with EntryOptional and EntrySuspendable instructions to
describe names and default values of optional parameters.
#### Frame D
Reserve space for D local variables. Local variables are
initially initialized with null.
#### CheckFunctionTypeArgs A, E
Check for a passed-in type argument vector of length A and
store it at Locals[E].
#### CheckStack A
Compare SP against stack limit and call stack overflow or interrupt handler if
necessary. Should be used in prologue (A = 0), or at the beginning of
a loop with depth A.
#### Allocate D
Allocate object of class ConstantPool[D] with no type arguments.
#### AllocateT
Allocate object of class SP[0] with type arguments SP[-1].
#### CreateArrayTOS
Allocate array of length SP[0] with type arguments SP[-1].
#### AllocateContext A, E
Allocate Context object holding E context variables.
A is a static ID of the context. Static ID of a context may be used to
disambiguate accesses to different context objects.
Context objects with the same ID should have the same number of
context variables.
#### CloneContext A, E
Clone Context object SP[0] holding E context variables.
A is a static ID of the context. Cloned context has the same ID.
#### LoadContextParent
Load parent from context SP[0].
#### StoreContextParent
Store context SP[0] into `parent` field of context SP[-1].
#### LoadContextVar A, E
Load value from context SP[0] at index E.
A is a static ID of the context.
#### StoreContextVar A, E
Store value SP[0] into context SP[-1] at index E.
A is a static ID of the context.
#### PushConstant D
Push value ConstantPool[D] onto the stack.
#### PushNull
Push `null` onto the stack.
#### PushTrue
Push `true` onto the stack.
#### PushFalse
Push `false` onto the stack.
#### PushInt X
Push int X onto the stack.
#### Drop1
Drop 1 value from the stack
#### Push X
Push Locals[X] to the stack.
#### StoreLocal X; PopLocal X
Store top of the stack into Locals[X] and pop it if needed.
#### LoadFieldTOS D
Push value of field ConstantPool[D] from object SP[0].
#### StoreFieldTOS D
Store value SP[0] into field ConstantPool[D] of object SP[-1].
#### StoreIndexedTOS
Store SP[0] into array SP[-2] at index SP[-1]. No type or index checking is done.
SP[-2] is assumed to be an array (created with CreateArrayTOS), SP[-1] is an int.
#### PushStatic D
Pushes value of the static field ConstantPool[D] on to the stack.
#### StoreStaticTOS D
Stores SP[0] into the static field ConstantPool[D].
#### Jump target
Jump to the given target. Target is specified as offset from the PC of the
jump instruction.
#### JumpIfNoAsserts target
Jump to the given target if assertions are not enabled.
Target is specified as offset from the PC of the jump instruction.
#### JumpIfNotZeroTypeArgs target
Jump to the given target if number of passed function type
arguments is not zero.
Target is specified as offset from the PC of the jump instruction.
#### JumpIfUnchecked target
May jump to the given target if current function was called through unchecked
call instruction (UncheckedInterfaceCall, UncheckedClosureCall).
This instruction can be used to skip checking of type argument bounds and
types of generic-covariant parameters.
This is an optimization, so it is valid to treat this instruction as a no-op.
Target is specified as offset from the PC of the jump instruction.
#### JumpIfEqStrict target; JumpIfNeStrict target
Jump to the given target if SP[-1] is the same (JumpIfEqStrict) /
not the same (JumpIfNeStrict) object as SP[0].
#### JumpIfTrue target; JumpIfFalse target; JumpIfNull target; JumpIfNotNull target
Jump to the given target if SP[0] is true/false/null/not null.
#### Suspend target
Create a snapshot of the current frame and store it in the suspend
state object. Execution can be resumed from the suspend state
at the given target PC.
Target is specified as offset from the PC of the suspend instruction.
The filled suspend state object is stored into the reserved suspend
state local variable. Current function frame should be created with
EntrySuspendable instruction.
#### DirectCall D, F
Invoke the target function with arguments SP[-(F-1)], ..., SP[0].
ContantPool[D] is a ConstantDirectCall specifying target and
arguments descriptor.
#### InterfaceCall D, F
Lookup and invoke instance method with arguments SP[-(F-1)], ..., SP[0].
ContantPool[D] is a ConstantInterfaceCall specifying interface target and
arguments descriptor.
Method has to be declared (explicitly or implicitly) in an interface
implemented by a receiver SP[0], and passed arguments are valid for the
interface method declaration.
#### UncheckedInterfaceCall D, F
Same as InterfaceCall, but can omit type checks of generic-covariant
parameters.
#### InstantiatedInterfaceCall D, F
Same as InterfaceCall, but provides additional information about instantiated static
type of a (generic) receiver via ConstantInstantiatedInterfaceCall. At run time, if
actual type of receiver matches static type, then type checks of generic-covariant
Parameters can be omitted.
#### UncheckedClosureCall D, F
Call closure SP[0] with arguments SP[-F], ..., SP[-1].
ContantPool[D] is a ConstantObjectRef with ArgDesc object specifying arguments
descriptor.
Closure should have a statically known function type; parameters should have
correct types according to the closure’s function type, so parameter type checks
can be omitted.
#### DynamicCall D, F
Lookup and invoke instance method with arguments SP[-(F-1)], ..., SP[0].
ContantPool[D] is a ConstantDynamicCall specifying selector and
arguments descriptor.
#### ExternalCall D
Invoke body of an external method.
ContantPool[D] is a ConstantExternalCall.
#### ReturnTOS
Return to the caller using SP[0] as a result.
#### AssertAssignable A, E
Assert that instance SP[-4] is assignable to variable named SP[0] of
type SP[-1] with instantiator type arguments SP[-3] and function type
arguments SP[-2] using ConstantSubtypeTestCache at ConstantPool[E].
If A is 1, then the instance may be an int.
Instance remains on stack. Other arguments are consumed.
#### AssertSubtype
Assert that one type is a subtype of another. Throws a TypeError
otherwise. The stack has the following arguments on it:
```
SP[-4] instantiator type args
SP[-3] function type args
SP[-2] sub-type
SP[-1] super-type
SP[-0] destination name
```
All 5 arguments are consumed from the stack and no results is pushed.
#### LoadTypeArgumentsField D
Load instantiator type arguments from an instance SP[0].
ConstantPool[D] should be a ConstantTypeArgumentsField corresponding
to an instance's generic (base) class.
#### InstantiateType D
Instantiate type ConstantPool[D] with instantiator type arguments SP[-1] and
function type arguments SP[0].
#### InstantiateTypeArgumentsTOS A, E
Instantiate type arguments ConstantPool[E] with instantiator type arguments SP[-1]
and function type arguments SP[0]. A != 0 indicates that resulting type
arguments are all dynamic if both instantiator and function type arguments are
all dynamic.
#### Throw A
Throw (Rethrow if A != 0) exception. Exception object and stack object
are taken from the top of the stack.
#### MoveSpecial A, Y
Copy value from special variable to Locals[Y]. Currently only
used to pass exception object (A = 0) and stack trace object (A = 1) to
catch handler.
#### SetFrame A
Reset expression stack to empty.
‘A’ should be equal to the frame size allocated by prologue instructions.
Used to drop temporaries from the stack in the exception handler.
#### BooleanNegateTOS
SP[0] = !SP[0]
#### EqualsNull
SP[0] = (SP[0] == null) ? true : false
#### NegateInt
Equivalent to invocation of unary int operator-.
Receiver should have static type int.
SP[0] = -SP[0]
#### AddInt; SubInt; MulInt; TruncDivInt; ModInt; BitAndInt; BitOrInt; BitXorInt; ShlInt; ShrInt
Equivalent to invocation of binary int operator +, -, *, ~/, %, &, |,
^, << or >>. Receiver and argument should have static type int.
SP[0] = SP[-1] <op> SP[0]
#### CompareIntEq; CompareIntGt; CompareIntLt; CompareIntGe; CompareIntLe
Equivalent to invocation of binary int operator ==, >, <, >= or <=.
Receiver and argument should have static type int.
SP[0] = SP[-1] <op> SP[0] ? true : false
#### NegateDouble
Equivalent to invocation of unary double operator-.
Receiver should have static type double.
SP[0] = -SP[0]
#### AddDouble; SubDouble; MulDouble; DivDouble
Equivalent to invocation of binary double operator +, -, *, /
Receiver and argument should have static type double.
SP[0] = SP[-1] <op> SP[0]
#### CompareDoubleEq; CompareDoubleGt; CompareDoubleLt; CompareDoubleGe; CompareDoubleLe
Equivalent to invocation of binary double operator ==, >, <, >= or <=.
Receiver and argument should have static type double.
SP[0] = SP[-1] <op> SP[0] ? true : false
#### AllocateClosure D
Allocate closure object for closure function ConstantPool[D].
#### DebugCheck
No-op. Provides a point where debugger can stop executing code when single stepping
or when it hits a breakpoint.