Add bytecode example

This commit is contained in:
Andrew Morris
2022-04-25 14:19:52 +10:00
parent 887b900559
commit c056b5a78d
2 changed files with 167 additions and 0 deletions

104
concept-code/bytecode.md Normal file
View File

@@ -0,0 +1,104 @@
# Bytecode Notes
The bytecode is also a serialization format, able to represent any value that
can ever exist within ValueScript (and in ValueScript, everything is a value).
Serialization is 'batteries included' - meaning that it includes everything
contained by that entity.
- Notably, when it comes to functions, this means that the format must provide
everything needed to execute that function in another context without any
further communication with the original context. This contrasts with
JavaScript's Function.prototype.toString which only returns the source code,
which usually includes unresolved references to other entities.
Interpreting bytecode always starts with parsing a value, and the value parsed
at the beginning is the overall value being represented.
## Values
These are the values that can currently be represented along with the leading
byte that indicates them:
```
01 void
02 undefined
03 null
04 false
05 true
06 signed byte (as a number)
07 number
08 string
09 array
0a object
0b function
0c instance
```
The following bytes can also be encountered when decoding a value.
```
00 end
0d pointer
0e register
0f external
```
These aren't valid in all contexts. For example, when decoding an array, we keep
decoding values until encountering `end`, but it would not be valid to have
`end` immediately when decoding a top-level value.
## Instructions
```
00 end
01 mov
02 op++
03 op--
04 op+
05 op-
06 op*
07 op/
08 op%
09 op**
0a op==
0b op!=
0c op===
0d op!==
0e op&&
0f op||
10 op!
11 op<
12 op<=
13 op>
14 op>=
15 op??
16 op?.
17 op&
18 op|
19 op~
1a op^
1b op<<
1c op>>
1d op>>>
1e typeof
1f instanceof
20 in
21 call
22 apply
23 bind
24 sub
25 submov
26 subcall
27 jmp
28 jmpif
```

63
concept-code/eg1.vsxxd Normal file
View File

@@ -0,0 +1,63 @@
00: 0b03 0021 0d1c 0706 0106 0206 0300 0222
10: 0d2c 0e02 0700 0301 0e02 0000 0b07 0306
20: 0e03 0e04 0504 0e02 0e05 0000 0b03 0002
30: 0100
---
// Pointers occupy a single byte in this example because it is so small. The
// length of the bytecode implicitly indicates the byte width needed for
// pointers (1, 2, 4, or 8, whichever is smallest and sufficient).
// @main = function() {
00: 0b 03 00 // function with 4 registers and 0 parameters
// 0: %return
// 1: %this
// 2: %x
// 3: %ignore (so only actually allocate 3 registers)
// declaring the number of registers implicitly indicates
// the byte width for representing registers in this
// function
// call @f1 [ 1, 2, 3 ] %x
03: 21 0d1c 07 0601 0602 0603 00 02
// apply @f2 %x [ ] %ignore
0f: 22 0d2c 0e02 07 00 03
// mov %x %return
17: 01 0e02 00
// }
1b: 00
// @f1 = function(%a, %b, %c) {
1c: 0b 07 03 // function with 7 registers and 3 parameters
// 0: %return
// 1: %this
// 2: %a
// 3: %b
// 4: %c
// 5: %_tmp0
// 6: %ignore
// op* %b %c %_tmp0
1f: 06 0e03 0e04 05
// op+ %a %_tmp0 %return
25: 04 0e02 0e05 00
// }
2b: 00
// @f2 = function() {
2c: 0b 03 00 // function with 3 registers and 0 parameters
// 0: %return
// 1: %this
// 2: %ignore
// op++ %this
2f: 02 01
// }
31: 00