Skip to content

Instantly share code, notes, and snippets.

@lancejpollard
Created September 26, 2020 05:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lancejpollard/3561afecd3d2593b335341beb47477c9 to your computer and use it in GitHub Desktop.
Save lancejpollard/3561afecd3d2593b335341beb47477c9 to your computer and use it in GitHub Desktop.
Virtual Machine Version 8
const START = 256
const I_INSTRUCTION_POSITION = 0
const I_PARAM_1 = 1
const I_PARAM_2 = 2
const I_PARAM_3 = 3
const I_PARAM_4 = 4
const I_PARAM_5 = 5
const I_PARAM_6 = 6
const I_PARAM_7 = 7
const I_PARAM_8 = 8
const I_SYSCALL_ARITY = 10
const I_SYSCALL_HAS_RETURN_MULTIPLIER = 11
const I_SYSCALL_CURRENT_PARAM = 12
const I_SYSCALL_RETURN_VALUE = 13
const I_SYSCALL_FETCH_STORAGE = 14
const I_SYSCALL_BLOCK_START = 15
const I_MEMORY_ARRAY = 32
const I_MAIN_THRESHOLD_TIME = 26
const I_MAIN_THRESHOLD_ITERATION = 27
const I_MAIN_ITERATION_START_TIME = 28
const I_MAIN_ITERATION_END_TIME = 29
const I_MAIN_ITERATION = 30
const I_MAIN_IS_PAST_TIME = 31
const INST_SIZE_NATIVE = 0
const INST_CONNECT_NATIVE = 1
const INST_PUSH_NATIVE = 2
const INST_CALL_NATIVE = 3
const SYS_EXIT = 0
const SYS_ADD = 1
const SYS_SUB = 2
const SYS_MUL = 3
const SYS_LOG = 4
const instructions = [
inst_size_native,
inst_connect_native,
inst_push_native,
inst_call_native,
]
const syscall_types = [
syscall0,
syscall1,
syscall2,
syscall3,
syscall4,
syscall5,
syscall6,
syscall7,
syscall0_with_return,
syscall1_with_return,
syscall2_with_return,
syscall3_with_return,
syscall4_with_return,
syscall5_with_return,
syscall6_with_return,
syscall7_with_return
]
const syscalls = [
sys_exit,
sys_add,
sys_sub,
sys_mul,
sys_log
]
const db = new Uint32Array(65536)
// initialize memory
db[I_SYSCALL_CURRENT_PARAM] = 1
db[I_SYSCALL_HAS_RETURN_MULTIPLIER] = 1
db[0] = START + 32 // start instruction
// console.log(219)
db[START + 32] = INST_SIZE_NATIVE
db[START + 32 + 1] = 1
db[START + 34] = INST_PUSH_NATIVE
db[START + 34 + 1] = 219 // input
db[START + 36] = INST_CALL_NATIVE
db[START + 36 + 1] = SYS_LOG
// exit(0)
db[START + 38] = INST_SIZE_NATIVE
db[START + 40 + 1] = 1
db[START + 42] = INST_PUSH_NATIVE
db[START + 42 + 1] = 0 // input
db[START + 44] = INST_CALL_NATIVE
db[START + 44 + 1] = SYS_EXIT
start()
function start() {
db[I_MAIN_THRESHOLD_TIME] = 8
db[I_MAIN_THRESHOLD_ITERATION] = 65536
db[I_MAIN_ITERATION_START_TIME] = Date.now()
db[I_MAIN_ITERATION] = 0
db[I_MAIN_IS_PAST_TIME] = 0
// loop for a specific amount of time
while (!db[I_MAIN_IS_PAST_TIME]) {
// loop up to a specific number of iterations
while (db[I_MAIN_ITERATION] < db[I_MAIN_THRESHOLD_ITERATION]) {
db[I_MAIN_ITERATION]++
step()
}
// check if we can break out of the main loop
// to allow for events to interrupt.
db[I_MAIN_ITERATION_END_TIME] = Date.now()
db[I_MAIN_IS_PAST_TIME] = db[I_MAIN_ITERATION_END_TIME]
- db[I_MAIN_ITERATION_START_TIME]
> db[I_MAIN_THRESHOLD_TIME]
}
// allow for events to interrupt.
setImmediate(start)
}
function step() {
let next = db[I_INSTRUCTION_POSITION]
let instruction = db[next]
let input = db[next + 1]
// console.log(`${instruction}(${input})`)
instructions[instruction](input)
db[I_INSTRUCTION_POSITION] = next + 2
}
// create nested call stack
function inst_nest() {
db[I_SYSCALL_BLOCK_START + 1] = next
}
function inst_fetch(index) {
db[I_SYSCALL_FETCH_STORAGE] = index
}
function inst_store(index) {
db[index] = db[db[I_SYSCALL_FETCH_STORAGE]]
}
function inst_store_on_stack(index) {
db[db[I_SYSCALL_BLOCK_START] + index] = db[db[I_SYSCALL_FETCH_STORAGE]]
}
function allocate(size) {
db[MEMORY_START]
}
// size(2)
// connect(1) // returns
// push(1)
// push(100)
// call(100)
function inst_push_native(value) {
db[db[I_SYSCALL_CURRENT_PARAM]] = value
db[I_SYSCALL_CURRENT_PARAM]++
}
function inst_size_native(x) {
db[I_SYSCALL_ARITY] = x
}
function inst_connect_native(multiplier) {
db[I_SYSCALL_HAS_RETURN_MULTIPLIER] = multiplier
}
function inst_call_native(index) {
const syscall_type = db[I_SYSCALL_ARITY] * db[I_SYSCALL_HAS_RETURN_MULTIPLIER]
syscall_types[syscall_type](index)
db[I_SYSCALL_CURRENT_PARAM] = 1
db[I_SYSCALL_HAS_RETURN_MULTIPLIER] = 1
}
function syscall0(index) {
syscalls[index]()
}
function syscall1(index) {
let i1 = db[I_PARAM_1]
syscalls[index](i1)
}
function syscall2(index) {
let i1 = db[I_PARAM_1]
let i2 = db[I_PARAM_2]
syscalls[index]()
}
function syscall3(index) {
let i1 = db[I_PARAM_1]
let i2 = db[I_PARAM_2]
let i3 = db[I_PARAM_3]
syscalls[index]()
}
function syscall4(index) {
// ...
syscalls[index]()
}
function syscall5(index) {
// ...
syscalls[index]()
}
function syscall6(index) {
// ...
syscalls[index]()
}
function syscall7(index) {
// ...
syscalls[index]()
}
function syscall0_with_return(index) {
db[I_SYSCALL_RETURN_VALUE] = syscalls[index]()
}
function syscall1_with_return(index) {
const i1 = db[I_PARAM_1]
db[I_SYSCALL_RETURN_VALUE] = syscalls[index](i1)
}
function syscall2_with_return(index) {
const i1 = db[I_PARAM_1]
const i2 = db[I_PARAM_2]
db[I_SYSCALL_RETURN_VALUE] = syscalls[index](i1, i2)
}
function syscall3_with_return(index) {
const i1 = db[I_PARAM_1]
const i2 = db[I_PARAM_2]
const i3 = db[I_PARAM_3]
db[I_SYSCALL_RETURN_VALUE] = syscalls[index](i1, i2, i3)
}
function syscall4_with_return(index) {
// ...
db[I_SYSCALL_RETURN_VALUE] = syscalls[index]()
}
function syscall5_with_return(index) {
// ...
db[I_SYSCALL_RETURN_VALUE] = syscalls[index]()
}
function syscall6_with_return(index) {
// ...
db[I_SYSCALL_RETURN_VALUE] = syscalls[index]()
}
function syscall7_with_return(index) {
// ...
db[I_SYSCALL_RETURN_VALUE] = syscalls[index]()
}
function sys_exit(code) {
process.exit(code)
}
function sys_add(a, b) {
return a + b
}
function sys_sub(a, b) {
return a - b
}
function sys_mul(a, b) {
return a * b
}
function sys_log(str) {
console.log(str)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment