Skip to content
This repository has been archived by the owner on Jul 8, 2021. It is now read-only.

Bytecode

WarlockD edited this page Feb 26, 2016 · 61 revisions

The GameMaker: Studio virtual machine interprets bytecode which represents the user defined portion of game logic. This page is dedicated to formally documenting the exact format of this bytecode.

Reading Bytecode

The easiest way to read GM:S bytecode is to run a game using the newer debugger (post-Early Access program commencing). In the Source pane, right click a tab and select Display VMASM to swap to bytecode view.

There are a few things to note about this display;

  • The view is divided into three columns. From left to right these are; the instruction addresses, the byte representation of instructions (what the machine can see) and the textual representation of instructions (easier for a human to read).
  • The byte representation of instructions are in little-endian 32-bit blocks of little-endian byte order. That is; when reading blocks, read them from left to right, however induvidual bytes in blocks should be read from right to left. This leads to a degree of confusion when identifying opcodes.

Implicit Returns

There is an implicit ret inserted by the runtime after the last instruction of a script. This is not shown in the GM:S debugger. As a result, some jumps may appear to jump outside the disassembled area, when they are actually jumping to this implicit instruction.

Optimization Passes

An analysis of the GM:S Bytecode reveals that contrary to what people would believe, a number of passes touch the bytecode before it is finalized. These can be responsible for VMASM which differs slightly to the original code. The passes discovered are as follows;

  • Constant propagation: operations on constants are folded into single constants, ie 3 + 3 becomes 6 at compile time.

VM Types

Most instructions will encode one or more types for their operation. The following table shows all the types GM:S will correctly decode from instructions and their corresponding byte representation.

Byte Internal Symbol Type
0x00 eVMT_Double d 64-bit double
0x01 eVMT_Float f 32-bit float
0x02 eVMT_Int i 32-bit signed integer
0x03 eVMT_Long l 64-bit signed long
0x04 eVMT_Bool b bool
0x05 eVMT_Variable v variable reference
0x06 eVMT_String s string
0x07 eVMT_Instance n/a instance
0x0f eVMT_Error e 16-bit signed integer

Instance Identifiers

Some instructions encode object identifiers. This is usually encoded as a 16-bit field.

Value Equivalence Description
0 n/a The instance with ID specified by the stack head as an integer
-1 self The current instance
-2 other The other instance
-3 all All instances in the room
-4 noone Nobody
-5 global The global instance
n/a n/a A specific instance ID

Calling Convention

The GM:S calling convention is as follows;

  • Arguments are converted to type variable and placed on the stack from right to left, that is, the first argument is at the top of the stack
  • When a function returns, it places its return value at the top of the stack where the calling scope can access it via pop or discard it via popz.

Arrays

Arrays are not considered as a concrete type. Arrays are all handled as 1-dimensional; 2-dimensional arrays are first converted to 1-dimensional arrays by multiplying the first index by 32000.

As such, the upper bound of arrays are 32000. The runner does not automatically check array indices to be positive; these checks are inserted as break instructions and can be disabled in the compile options for higher performance.

Instructions

Instructions for GameMaker: Studio are formatted in 32-bit blocks. The first byte of each instruction is an opcode and following bytes are instruction specific. Some instructions span more than a single 32-bit block.

To decipher an opcode using the following table, lookup the byte nibbles horizontally and then vertically.

0x 0 1 2 3 4 5 6 7 8 9 a b c d e f
0 sar push
1 slt pop
2 sle dup
3 conv seq
4 mul sne
5 div sge
6 rem sgt
7 mod b
8 add bt
9 sub bf
a and call
b or pushenv
c xor popenv
d ret
e not exit
f sal popz break

0x03: conv

The conv instruction converts the type on the top of the stack into another type. The structure of this instruction is as follows;

Bits Description
4 Type to be converted into
4 Type of stack head

0x04: mul

The mul instruction multiplies the two values on the top of the stack together. The result is pushed onto the top of the stack as a variable and the two slots on the top of the stack are removed. The structure of this instruction is as follows;

Bits Description
4 Type of first stack slot (top)
4 Type of second stack slot

Since this instruction is analogous to the * operator, it's also used to repeat strings.

0x05: div

The div instruction divides the second value on the stack by the value at the top of the stack. The result is pushed onto the top of the stack as a variable and the two slots are removed. The structure of this instruction is as follows;

Bits Description
4 Type of first stack slot (top)
4 Type of second stack slot

This instruction is analogous to the / operator.

0x06: rem

The rem instruction calculates the remainder of the second value on the stack when divided by the value at the top of the stack. The result is pushed onto the top of the stack as a variable and the two slots are removed. The structure of this instruction is as follows;

Bits Description
4 Type of first stack slot (top)
4 Type of second stack slot

This instruction is analogous to the rem operator.

0x07: mod

The mod instruction performs the modulo of the second value on the stack by the value at the top of the stack. The result is pushed onto the top of the stack as a variable and the two slots are removed. The structure of this instruction is as follows;

Bits Description
4 Type of first stack slot (top)
4 Type of second stack slot

This instruction is analogous to the % operator.

0x08: add

The add instruction adds the two values on the top of the stack together. The result is pushed onto the top of the stack as a variable and the two slots on the stack are removed. The structure of this instruction is as follows;

Bits Description
4 Type of first stack slot (top)
4 Type of second stack slot

Since this instruction is analogous to the + operator, it's also used to concatenate strings.

0x09: sub

The sub instruction subtracts the second value on the stack by the value on the top of the stack. The result is pushed onto the top of the stack as a variable and the two slots on the stack are removed. The structure of this instruction is as follows;

Bits Description
4 Type of first stack slot (top)
4 Type of second stack slot

This instruction is analogous to the - operator.

0x0a: and

The and instruction performs a bitwise AND operation on the two values at the top of the stack. The result is pushed onto the top of the stack as the type of the left operand and the two slots on the stack are removed. The structure of this instruction is as follows;

Bits Description
4 Type of first stack slot (top)
4 Type of second stack slot

This instruction is analogous to the & operator.

0x0b: or

The or instruction performs a bitwise OR operation on the two values at the top of the stack. The result is pushed onto the top of the stack as the type of the left operand and the two slots on the stack are removed. The structure of this instruction is as follows;

Bits Description
4 Type of first stack slot (top)
4 Type of second stack slot

This instruction is analogous to the | operator.

0x0c: xor

The xor instruction performs a bitwise XOR operation on the two values at the top of the stack. The result is pushed onto the top of the stack as the type of the left operand and the two slots on the stack are removed. The structure of this instruction is as follows;

Bits Description
4 Type of first stack slot (top)
4 Type of second stack slot

This instruction is analogous to the ^ operator.

0x0e: not

The not instruction performs a bitwise NOT operation on the value at the top of the stack. The result is pushed onto the top of the stack in the indicated type and the slot previously on the stack is removed. The structure of the instruction is as follows;

Bits Description
4 Type of top of stack
4 Type of result

This instruction is analogous to the ! operator.

0x0f: sal

The sal instruction arithmetic left-shifts the second value on the stack by the value on the top of the stack. If the second value on the stack is a float or a double, it does a left rotation instead. The result is pushed onto the top of the stack as a variable and the two slots on the stack are removed. The structure of this instruction is as follows;

Bits Description
4 Type of first stack slot (top)
4 Type of second stack slot

This instruction is analogous to the << operator.

0x10: sar

The sar instruction arithmetic right-shifts the second value on the stack by the value on the top of the stack. If the second value on the stack is a float or a double, it does a right rotation instead. The result is pushed onto the top of the stack as a variable and the two slots on the stack are removed. The structure of this instruction is as follows;

Bits Description
4 Type of first stack slot (top)
4 Type of second stack slot

This instruction is analogous to the >> operator.

0x11: slt

The slt instruction checks whether the second value on the stack is less than the top of the stack, with the property that both are signed. The result is pushed onto the top of the stack as a boolean and the two slots on the stack are removed. The structure of this instruction is as follows;

Bits Description
4 Type of first stack slot (top)
4 Type of second stack slot

Since this instruction is analogous to the < operator, it's also used in lexicographical string comparison, i.e str < "foo".

0x12: sle

The sle instruction checks whether the second value on the stack is less than or equal to the top of the stack, with the property that both are signed. The result is pushed onto the top of the stack as a boolean and the two slots on the stack are removed. The structure of this instruction is as follows;

Bits Description
4 Type of first stack slot (top)
4 Type of second stack slot

Since this instruction is analogous to the <= operator, it's also used in lexicographical string comparison, i.e str < "foo".

0x13: seq

The seq instruction checks whether the two values on the top of the stack are equal, with the property that both are signed. The result is pushed onto the top of the stack as a boolean and the two slots on the stack are removed. The structure of this instruction is as follows;

Bits Description
4 Type of first stack slot (top)
4 Type of second stack slot

Since this instruction is analogous to the == operator, it's also used in lexicographical string comparison, i.e str == "foo".

0x14: sne

The sne instruction checks whether the two values on the top of the stack are not equal, with the property that both are signed. The result is pushed onto the top of the stack as a boolean and the two slots on the stack are removed. The structure of this instruction is as follows;

Bits Description
4 Type of first stack slot (top)
4 Type of second stack slot

Since this instruction is analogous to the != operator, it's also used in lexicographical string comparison, i.e str != "foo".

0x15: sge

The sge instruction checks whether the second value on the stack is greater than or equal to the top of the stack, with the property that both are signed. The result is pushed onto the top of the stack as a boolean and the two slots on the stack are removed. The structure of this instruction is as follows;

Bits Description
4 Type of first stack slot (top)
4 Type of second stack slot

Since this instruction is analogous to the >= operator, it's also used in lexicographical string comparison, i.e str > "foo".

0x16: sgt

The sgt instruction checks whether the second value on the stack is greater than the top of the stack, with the property that both are signed. The result is pushed onto the top of the stack as a boolean and the two slots on the stack are removed. The structure of this instruction is as follows;

Bits Description
4 Type of first stack slot (top)
4 Type of second stack slot

Since this instruction is analogous to the > operator, it's also used in lexicographical string comparison, i.e str > "foo".

0x41: pop

The pop instruction moves a value from the stack into the destination specified. The structure of this instruction is as follows;

Bits Description
4 Type of destination
4 Type of source
16 Instance
16 Unknown
16 Metadata; usually a variable identifier

0x82: dup

The dup instruction duplicates the value at the top of the stack, consuming another stack slot. The structure of this instruction is as follows;

Bits Description
8 Type of top of stack
16 0 = Dup only the top item of the stack, 1 = Dup the top two items on the stack

0x9d: ret

The ret instruction returns from the current scope with the value on the top of the stack.

Bits Description
8 Type of top of stack

Note that GM:S will only emit ret.v instructions.

0x9e: exit

The exit instruction exits the current scope. If the current scope is a script, it will return 0. The structure of this instruction is as follows;

Bits Description
8 Type to return

Note that GM:S will only emit exit.i instructions.

0x9f: popz

The popz instruction discards the value on the top of the stack. This is used to i.e. discard the return value of a function. The structure of this instruction is as follows;

Bits Description
8 Type of top of stack

0xb7: b

The b instruction is an uncondition branch. The structure of this instruction is as follows;

Bits Description
24 24-bit signed integer number of standard size instructions (32-bits each) to jump

If the second parameter of this instruction is zero, an infinite loop is produced.

0xb8: bt

The bt instruction branches if the boolean at the top of the stack is true. The structure of this instruction is as follows;

Bits Description
24 24-bit signed integer number of standard size instructions (32-bits each) to jump

0xb9: bf

The bf instruction branches if the boolean on the top of the stack is false. The structure of this instruction is as follows;

Bits Description
24 24-bit signed integer number of standard size instructions (32-bits each) to jump

0xbb: pushenv

Pushes the current environment onto the environmental stack and creates a new environment in the context of the instance on the top of the stack. This is the start of the "with" statement.

The structure of this instruction is as follows;

Bits Description
24 24-bit signed integer number of standard size instructions to jump on exit of the environment push

0xbc: popenv

Discards the current environment and restores the previous environment from the environmental stack. It points to a branch that will jump to the old environment.

The structure of this instruction is as follows;

Bits Description
24 24-bit signed integer number of standard size instructions (32-bits each) to corresponding pushenv or a branch to continue the old enviroment

0xc0: push

The push instruction moves a value onto the stack. The next byte indicates the kind of push as a VM Type, and the proceeding bytes are type-specific;

push.d

Push a floating point double onto the stack.

Bits Description
16 Alignment padding (ignored)
64 64-bit IEEE754 floating point double

push.i

Push an integer onto the stack.

Bits Description
16 Alignment padding (ignored)
32 32-bit signed integer

push.l

Push a long onto the stack.

Bits Description
16 Alignment padding (ignored)
32 64-bit signed long

push.v

Push a variable onto the stack. The variable can be scoped to another object.

Bits Description
16 Instance
16 Variable load type
16 Variable identifier

If the variable load type is 0x1, then the target is treated as an array and the array index is loaded from the top of the stack (see Arrays). In other cases this field is often 0xa001 and the variable is treated as a regular variable.

push.s

Push a string onto the stack.

Bits Description
16 Alignment padding (ignored)
32 String identifier

push.e

Push a 16-bit error identifier onto the stack. GameMaker: Studio uses this instruction to push small values onto the stack.

Bits Description
16 16-bit signed integer

0xda: call

The call instruction dispatches control to a function or script. The structure of this instruction is as follows;

Bits Description
8 Type of return (always i)
16 16-bit unsigned number of arguments supplied on the stack
32 A unique function identifier

See the Calling Convention for more information.

0xff: break

The break instruction will break if the top of the stack contains the specified value. The structure of this instruction is as follows;

Bits Description
8 Type of top of stack (always e)
16 16-bit signed integer to break upon

When enabled, GM:S will emit this instruction to guard on invalid array access.