Skip to main content

Bytecode

DeviceScript bytecode spec

This file documents bytecode format for DeviceScript. A C header file and a TypeScript file are generated from it. Additional structures are defined in devs_format.h.

A DeviceScript bytecode file contains magic and version numbers followed by a number of binary sections defining functions, various literals (floats, ASCII strings, Unicode strings, buffers), Jacdac service specifications, and runtime configuration (configureHardware() and built-in servers).

Functions are sequences of opcodes defined below. Opcodes are divided into expressions (with return type) which do not modify state, and statements (no return type; ret_val() expression is used to retrieve the logical result of a last statement). Many opcodes (both expressions and statements) can also throw an exception.

For a more highlevel description of runtime and bytecode, see Runtime implementation page.

Format Constants

img_version_major = 2
img_version_minor = 16
img_version_patch = 3
img_version = $version
magic0 = 0x53766544 // "DevS"
magic1 = 0xf1296e0a
num_img_sections = 10
fix_header_size = 32
section_header_size = 8
function_header_size = 16
ascii_header_size = 2
utf8_header_size = 4
utf8_table_shift = 4
binary_size_align = 32
max_stack_depth = 16
max_call_depth = 100
direct_const_op = 0x80
direct_const_offset = 16
first_multibyte_int = 0xf8
first_non_opcode = 0x10000
first_builtin_function = 50000
max_args_short_call = 8
service_spec_header_size = 16
service_spec_packet_size = 8
service_spec_field_size = 4
role_bits = 15

Ops

Control flow

call0(func) = 2                                   // CALL func()
call1(func, v0) = 3 // CALL func(v0)
call2(func, v0, v1) = 4 // CALL func(v0, v1)
call3(func, v0, v1, v2) = 5 // CALL func(v0, v1, v2)
call4(func, v0, v1, v2, v3) = 6 // CALL func(v0, v1, v2, v3)
call5(func, v0, v1, v2, v3, v4) = 7 // CALL func(v0, v1, v2, v3, v4)
call6(func, v0, v1, v2, v3, v4, v5) = 8 // CALL func(v0, v1, v2, v3, v4, v5)
call7(func, v0, v1, v2, v3, v4, v5, v6) = 9 // CALL func(v0, v1, v2, v3, v4, v5, v6)
call8(func, v0, v1, v2, v3, v4, v5, v6, v7) = 10 // CALL func(v0, v1, v2, v3, v4, v5, v6, v7)

Call a function with given number of parameters.

call_array(func, args) = 79                        // CALL func(...args)

Passes arguments to a function as an array. The array can be at most max_stack_depth - 1 elements long.

final return(value) = 12

final jmp(*jmpoffset) = 13 // JMP jmpoffset

jmp_z(*jmpoffset, x) = 14 // JMP jmpoffset IF NOT x

Jump if condition is false.

jmp_ret_val_z(*jmpoffset) = 78            // JMP jmpoffset IF ret_val is nullish

Used in compilation of ?..

try(*jmpoffset) = 80                // TRY jmpoffset

Start try-catch block - catch/finally handler is at the jmpoffset.

final end_try(*jmpoffset) = 81

Try block has to end with this. jmpoffset is for continuation code.

catch() = 82

Has to be the first opcode in the catch handler. Causes error elsewhere. If value throw is JMP rethrows immediately.

finally() = 83

Has to be the first opcode in the finally handler. Finally block should be followed by storing exception value in a local and finish with re_throw of the exception. retval set to null when block executed not due to an exception.

final throw(value) = 84

Throw an exception.

final re_throw(value) = 85

Throw an exception without setting the __stack__ field. Does nothing if value is null.

final throw_jmp(*jmpoffset, level) = 86

Jump to given offset popping level try blocks, activating the finally blocks on the way.

debugger() = 87

Trigger breakpoint when debugger connected. No-op otherwise.

Variables

store_local(*local_idx, value) = 17      // local_idx := value

store_global(*global_idx, value) = 18 // global_idx := value

store_buffer(buffer, numfmt, offset, value) = 19

load_local(*local_idx): any = 21

load_global(*global_idx): any = 22

store_closure(*local_clo_idx, levels, value) = 73

load_closure(*local_clo_idx, levels): any = 74

make_closure(*func_idx): function = 75 // CLOSURE(func_idx)

store_ret_val(x) = 93 // ret_val := x

Field access

index(object, idx): any = 24              // object[idx]

Read named field or sequence member (depending on type of idx).

index_set(object, index, value) = 25         // object[index] := value

Write named field or sequence member (depending on type of idx).

index_delete(object, index) = 11              // delete object[index]

Remove a named field from an object.

builtin_field(*builtin_idx, obj): any = 26  // {swap}obj.builtin_idx

Shorthand to index(obj, static_builtin_string(builtin_idx))

ascii_field(*ascii_idx, obj): any = 27      // {swap}obj.ascii_idx

Shorthand to index(obj, static_ascii_string(ascii_idx))

utf8_field(*utf8_idx, obj): any = 28        // {swap}obj.utf8_idx

Shorthand to index(obj, static_utf8_string(utf8_idx))

fun math_field(*builtin_idx): any = 29      // Math.builtin_idx

fun ds_field(*builtin_idx): any = 30 // ds.builtin_idx

fun object_field(*builtin_idx): any = 16 // Object.builtin_idx

fun new(func): function = 88 // new func

fun bind(func, obj): function = 15 // func.bind(obj)

Objects

alloc_map() = 31

alloc_array(initial_size) = 32

alloc_buffer(size) = 33

Statics

fun static_spec_proto(*spec_idx): any = 34  // spec_idx.prototype

fun static_buffer(*buffer_idx): buffer = 35

fun static_builtin_string(*builtin_idx): string = 36

fun static_ascii_string(*ascii_idx): string = 37

fun static_utf8_string(*utf8_idx): string = 38

fun static_function(*func_idx): function = 39

fun static_spec(*spec_idx): any = 94

fun literal(*value): number = 40

fun literal_f64(*f64_idx): number = 41

fun builtin_object(*builtin_object): number = 1

Misc

removed_42() = 42

load_buffer(buffer, numfmt, offset): number = 43

ret_val(): any = 44

Return value of query register, call, etc.

fun typeof(object): number = 45

Returns Object_Type enum.

fun typeof_str(object): number = 76

Returns JS-compatible string.

fun undefined(): null = 46  // undefined

Returns undefined value.

fun null(): null = 90        // null

Returns null value.

fun is_undefined(x): bool = 47

Check if object is exactly undefined.

fun instance_of(obj, cls): bool = 89

Check if obj has cls.prototype in its prototype chain.

fun is_nullish(x): bool = 72

Check if value is precisely null or undefined.

Booleans

fun true(): bool = 48

fun false(): bool = 49

fun to_bool(x): bool = 50 // !!x

Math operations

fun nan(): number = 51

fun inf(): number = 20

fun abs(x): number = 52

fun bit_not(x): number = 53 // ~x

fun is_nan(x): bool = 54

fun neg(x): number = 55 // -x

fun uplus(x): number = 23 // +x

fun not(x): bool = 56 // !x

fun to_int(x): number = 57

Same as x | 0.

fun add(x, y): number = 58     // x + y

Note that this also works on strings, etc.

fun sub(x, y): number = 59     // x - y

fun mul(x, y): number = 60 // x * y

fun div(x, y): number = 61 // x / y

fun bit_and(x, y): number = 62 // x & y

fun bit_or(x, y): number = 63 // x | y

fun bit_xor(x, y): number = 64 // x ^ y

fun shift_left(x, y): number = 65 // x << y

fun shift_right(x, y): number = 66 // x >> y

fun shift_right_unsigned(x, y): number = 67 // x >>> y

fun eq(x, y): bool = 68 // x === y

fun le(x, y): bool = 69 // x <= y

fun lt(x, y): bool = 70 // x < y

fun ne(x, y): bool = 71 // x !== y

fun approx_eq(x, y): bool = 91 // x == y

fun approx_ne(x, y): bool = 92 // x != y

To be removed (soon)

removed_77() = 77

Enum: StrIdx

buffer = 0
builtin = 1
ascii = 2
utf8 = 3
_shift = 14

Enum: OpCall

sync = 0

Regular call. Unused.

bg = 1

Always start new fiber.

bg_max1 = 2

Start new fiber unless one is already running.

bg_max1_pend1 = 3

If fiber is already running, set a flag for it to be restarted when it finishes. Otherwise, start new fiber.

bg_max1_replace = 4

Start new fiber. If it's already running, replace it.

Enum: BytecodeFlag

num_args_mask = 0xf
is_stmt = 0x10
takes_number = 0x20
is_stateless = 0x40 // fun modifier - only valid when !is_stmt
is_final_stmt = 0x40 // final modifier - only valid when is_stmt

Enum: FunctionFlag

needs_this = 0x01
is_ctor = 0x02
has_rest_arg = 0x04

Enum: NumFmt

Size in bits is: 8 << (fmt & 0b11). Format is ["u", "i", "f", "reserved"](fmt >> 2)

U8 = 0b0000
U16 = 0b0001
U32 = 0b0010
U64 = 0b0011
I8 = 0b0100
I16 = 0b0101
I32 = 0b0110
I64 = 0b0111
F8 = 0b1000 // not supported
F16 = 0b1001 // not supported
F32 = 0b1010
F64 = 0b1011
Special = 0b1100

Enum: NumFmt_Special

empty = 0
bytes = 1
string = 2
string0 = 3
bool = 4
pipe = 5
pipe_port = 6

Enum: PacketSpec_Code

register = 0x1000
event = 0x8000
command = 0x0000
report = 0x2000
MASK = 0xf000

Enum: ServiceSpec_Flag

derive_mask = 0x000f
derive_base = 0x0000
derive_sensor = 0x0001
derive_last = 0x0001

Enum: PacketSpec_Flag

multi_field = 0x01

Enum: FieldSpec_Flag

is_bytes = 0x01
starts_repeats = 0x02

Enum: Object_Type

undefined = 0

Only the undefined value.

number = 1

Integers, doubles, infinity, nan.

map = 2

array = 3

buffer = 4

role = 5

bool = 6

Only true and false values.

fiber = 7

function = 8

string = 9

packet = 10

exotic = 11

null = 12

image = 13

Object_Types only used in static type info

any = 14

void = 15

Enum: BuiltIn_Object

Math = 0
Object = 1
Object_prototype = 2
Array = 3
Array_prototype = 4
Buffer = 5
Buffer_prototype = 6
String = 7
String_prototype = 8
Number = 9
Number_prototype = 10
DsFiber = 11
DsFiber_prototype = 12
DsRole = 13
DsRole_prototype = 14
Function = 15
Function_prototype = 16
Boolean = 17
Boolean_prototype = 18
DsPacket = 19
DsPacket_prototype = 20
DeviceScript = 21
DsPacketInfo_prototype = 22
DsRegister_prototype = 23
DsCommand_prototype = 24
DsEvent_prototype = 25
DsReport_prototype = 26
Error = 27
Error_prototype = 28
TypeError = 29
TypeError_prototype = 30
RangeError = 31
RangeError_prototype = 32
SyntaxError = 33
SyntaxError_prototype = 34
JSON = 35
DsServiceSpec = 36
DsServiceSpec_prototype = 37
DsPacketSpec = 38
DsPacketSpec_prototype = 39
Image = 40
Image_prototype = 41
GPIO = 42
GPIO_prototype = 43

Enum: BuiltIn_String

_empty = 0
MInfinity = 1 // -Infinity
DeviceScript = 2
E = 3
Infinity = 4
LN10 = 5
LN2 = 6
LOG10E = 7
LOG2E = 8
NaN = 9
PI = 10
SQRT1_2 = 11
SQRT2 = 12
abs = 13
alloc = 14
array = 15
blitAt = 16
boolean = 17
buffer = 18
cbrt = 19
ceil = 20
charCodeAt = 21
clamp = 22
exp = 23
false = 24
fillAt = 25
floor = 26
forEach = 27
function = 28
getAt = 29
idiv = 30
imul = 31
isBound = 32
join = 33
length = 34
log = 35
log10 = 36
log2 = 37
map = 38
max = 39
min = 40
next = 41
null = 42
number = 43
onChange = 44
onConnected = 45
onDisconnected = 46
packet = 47
_panic = 48
pop = 49
pow = 50
prev = 51
prototype = 52
push = 53
random = 54
randomInt = 55
read = 56
restart = 57
round = 58
setAt = 59
setLength = 60
shift = 61
signal = 62
slice = 63
splice = 64
sqrt = 65
string = 66
subscribe = 67
toString = 68
true = 69
undefined = 70
unshift = 71
wait = 72
write = 73

sleep = 74
imod = 75
format = 76
insert = 77
start = 78
cloud = 79
main = 80
charAt = 81
object = 82
parseInt = 83
parseFloat = 84
assign = 85
keys = 86
values = 87
__func__ = 88
role = 89
deviceIdentifier = 90
shortId = 91
serviceIndex = 92
serviceCommand = 93
payload = 94
decode = 95
encode = 96
_onPacket = 97
code = 98
name = 99
isEvent = 100
eventCode = 101
isRegSet = 102
isRegGet = 103
regCode = 104
flags = 105
isReport = 106
isCommand = 107
isArray = 108
inline = 109
assert = 110
pushRange = 111
sendCommand = 112
__stack__ = 113
Error = 114
TypeError = 115
RangeError = 116
stack = 117
message = 118
cause = 119
__new__ = 120
setPrototypeOf = 121
getPrototypeOf = 122
constructor = 123
__proto__ = 124
_logRepr = 125
print = 126
everyMs = 127
setInterval = 128
setTimeout = 129
clearInterval = 130
clearTimeout = 131
SyntaxError = 132
JSON = 133
parse = 134
stringify = 135
_dcfgString = 136
isSimulator = 137
_Role = 138 // Role
Fiber = 139
suspend = 140
resume = 141
terminate = 142
self = 143
current = 144
id = 145
_commandResponse = 146
isAction = 147
millis = 148
from = 149
hex = 150
utf8 = 151
utf_8 = 152 // utf-8
suspended = 153
reboot = 154
server = 155
spec = 156
ServiceSpec = 157
classIdentifier = 158
lookup = 159
PacketSpec = 160
parent = 161
response = 162
ServerInterface = 163
_onServerPacket = 164
_serverSend = 165
notImplemented = 166
delay = 167
fromCharCode = 168
_allocRole = 169
spiConfigure = 170
spiXfer = 171
_socketOpen = 172
_socketClose = 173
_socketWrite = 174
_socketOnEvent = 175
open = 176
close = 177
error_ = 178 // error
data = 179
toUpperCase = 180
toLowerCase = 181
indexOf = 182
byteLength = 183
Image = 184
width = 185
height = 186
bpp = 187
get = 188
clone = 189
set = 190
fill = 191
flipX = 192
flipY = 193
transposed = 194
drawImage = 195
drawTransparentImage = 196
overlapsWith = 197
fillRect = 198
drawLine = 199
equals = 200
isReadOnly = 201
fillCircle = 202
blitRow = 203
blit = 204
_i2cTransaction = 205
_twinMessage = 206
spiSendImage = 207
gpio = 208
label = 209
mode = 210
capabilities = 211
value = 212
setMode = 213
fillRandom = 214
encrypt = 215
decrypt = 216
digest = 217
ledStripSend = 218
rotate = 219
register = 220
event = 221
action = 222
report = 223
type = 224
byCode = 225