93 lines
2.6 KiB
Markdown
93 lines
2.6 KiB
Markdown
# Virtual machine stacks
|
|
|
|
While running, the FZLang virtual machine relies on three stacks: the data stack, the environment stack, and the call stack. Each stack is initialized as an array of 256 values and then zeroed. All three share the same basic property: the most recently added value is at the top and is the first one removed, decrementing the stack-top pointer.
|
|
|
|
## Data stack
|
|
|
|
The data stack is an array of 256 `fzl_value_t` elements. The `fzl_value_t` structure is a container for values used while a program runs.
|
|
|
|
```c
|
|
typedef struct
|
|
{
|
|
fzl_type_t type;
|
|
|
|
union
|
|
{
|
|
void *obj;
|
|
|
|
struct
|
|
{
|
|
const char *value;
|
|
size_t length;
|
|
} s;
|
|
|
|
char c;
|
|
bool b;
|
|
|
|
int8_t i8;
|
|
uint8_t u8;
|
|
|
|
int16_t i16;
|
|
uint16_t u16;
|
|
|
|
int32_t i32;
|
|
uint32_t u32;
|
|
|
|
int64_t i64;
|
|
uint64_t u64;
|
|
|
|
intptr_t i;
|
|
uintptr_t u;
|
|
} as;
|
|
} fzl_value_t;
|
|
```
|
|
|
|
The VM uses this stack to store and retrieve intermediate values while the program runs. The stack should be empty when execution finishes.
|
|
|
|
## Environment stack
|
|
|
|
The environment stack tracks the lexical environment in which evaluation and instructions are currently taking place. It is an array of 256 `fzl_vm_env_t` elements.
|
|
|
|
```c
|
|
typedef struct
|
|
{
|
|
size_t size;
|
|
size_t remainder;
|
|
|
|
fzl_vm_env_entry_t *table;
|
|
|
|
fzl_vm_object_t **owned_objects;
|
|
size_t owned_objects_remainder;
|
|
size_t owned_objects_count;
|
|
} fzl_vm_env_t;
|
|
```
|
|
|
|
Each stack element stores a table of local names (`fzl_vm_env_entry_t`) and the objects owned by the current environment. A local name is a container that wraps an `fzl_value_t` and gives it a name:
|
|
|
|
```c
|
|
typedef struct
|
|
{
|
|
char *name;
|
|
fzl_value_t value;
|
|
} fzl_vm_env_entry_t;
|
|
```
|
|
|
|
An object is an array of its fields. The number of fields is set when the object is allocated by the `FZL_OPCODE_ALLOC_OBJECT N` opcode (see the [opcode reference](./opcodes.md) for details).
|
|
|
|
```c
|
|
typedef struct
|
|
{
|
|
fzl_value_t *values;
|
|
size_t values_count;
|
|
} fzl_vm_object_t;
|
|
```
|
|
|
|
An environment is created or removed by the `FZL_OPCODE_MK_ENVTABLE` and `FZL_OPCODE_RM_ENVTABLE` opcodes, respectively. If the compiler sees a value of type `FZL_TYPE_OBJECT` being returned from a function, it inserts `FZL_OPCODE_ESCAPE_OBJECT` before `FZL_OPCODE_RET` and `FZL_OPCODE_RM_ENVTABLE`. This moves ownership of the object to the parent environment.
|
|
|
|
## Call stack
|
|
|
|
The call stack stores instruction addresses when entering a function through the `FZL_OPCODE_CALL` opcode. `FZL_OPCODE_RET` pops an address from the call stack and jumps to it.
|
|
|
|
The stack itself is an array of 256 `size_t` elements.
|
|
|