SlideShare a Scribd company logo
implementing
virtual machines
in
Go & C
Eleanor McHugh
@feyeleanor
slideshare://feyeleanor github://feyeleanor
just enough
CANSI
to get going
embrace
gopher
our inner
I made my own machine
Yes, we're building steam
I hate the same routine
— Building Steam, Abney Park
software is where
machine meets thought
and as programmers we
think a lot about thinking
whilst thinking very little
about machines
we style ourselves
philosophers & wizards
when machines need us
to be engineers & analysts
so this is a talk about
machine philosophy
framed in a language we
humans can understand
let's learn to understand
our Turing machines
by building new Turing
machines in their image
system virtualisation
hardware emulation
program execution
hardware
hardware
timely
stateful
conversational
main memory
main memory
stacks
heap
opcodes
stacks
sequential
bounded depth
push & pop
array stacks
contiguous
bounded depth
fixed allocation
c: array stack
contiguous
bounded depth
fixed allocation
#include <stdlib.h>
#define STACK_MAX 100
typedef enum {
STACK_OK = 0,
STACK_OVERFLOW,
STACK_UNDERFLOW
} STACK_STATUS;
typedef struct stack STACK;
struct stack {
int data[STACK_MAX];
int depth;
};
STACK *NewStack() {
STACK *s;
s = malloc(sizeof(STACK));
s->depth = 0;
return s;
}
STACK_STATUS push(STACK *s, int data) {
if (s->depth < STACK_MAX) {
s->data[s->depth++] = data;
return STACK_OK;
}
return STACK_OVERFLOW;
}
STACK_STATUS pop(STACK *s, int *r) {
if (s->depth > -1) {
*r = s->data[s->depth - 1];
s->depth--;
return STACK_OK;
}
return STACK_UNDERFLOW;
}
int main() {
int l, r;
STACK *s = NewStack();
push(s, 1);
push(s, 3);
printf("depth = %dn", s->depth);
pop(s, &l);
pop(s, &r);
printf("%d + %d = %dn", l, r, l + r);
printf("depth = %dn", s->depth);
}
go: slice stack
contiguous
bounded depth
fixed allocation
package main
import "fmt"
type stack []int
func (s *stack) Push(data int) {
*s = append(*s, data)
}
func (s *stack) Pop() (r int) {
sp := len(*s) - 1
r = (*s)[sp]
*s = (*s)[:sp]
return
}
func main() {
s := new(stack)
s.Push(1)
s.Push(3)
fmt.Printf("depth = %dn", len(s))
l := s.Pop()
r := s.Pop()
fmt.Printf("%d + %d = %dn", l, r, l+r)
fmt.Printf("depth = %dn", len(s))
}
go: slice stack
contiguous
bounded depth
fixed allocation
package main
import "fmt"
type stack []int
func (s stack) Pop() (int, stack) {
sp := len(s) - 1
return s[sp], s[:sp]
}
func main() {
s := make(stack, 0)
s = append(s, 1, 3)
fmt.Printf("depth = %dn", len(s))
var l, r int
l, s = s.Pop()
r, s = s.Pop()
fmt.Printf("%d + %d = %dn", l, r, l+r)
fmt.Printf("depth = %dn", len(s))
}
cactus stacks
singly-linked
sequential
per item allocation
c: cactus stack
singly-linked
sequential
per-item allocation
#include <stdio.h>
#include <stdlib.h>
typedef struct stack STACK;
struct stack {
int data;
STACK *next;
};
STACK *push(STACK *s, int data) {
STACK *r = malloc(sizeof(STACK));
r->data = data;
r->next = s;
return r;
}
STACK *pop(STACK *s, int *r) {
if (s == NULL)
exit(1);
*r = s->data;
return s->next;
}
int depth(STACK *s) {
int r = 0;
for (STACK *t = s; t != NULL; t = t->next) {
r++;
}
return r;
}
void gc(STACK **old, int items) {
STACK *t;
for (; items > 0 && *old != NULL; items--) {
t = *old;
*old = (*old)->next;
free(t);
}
}
int sum(STACK *tos) {
int a = 0;
for (int p = 0; tos != NULL;) {
tos = pop(tos, &p);
a += p;
}
return a;
}
void print_sum(STACK *s) {
printf("%d items: sum = %dn", depth(s), sum(s));
}
int main() {
STACK *s1 = push(NULL, 7);
STACK *s2 = push(push(s1, 7), 11);
s1 = push(push(push(s1, 2), 9), 4);
STACK *s3 = push(s1, 17);
s1 = push(s1, 3);
print_sum(s1);
print_sum(s2);
print_sum(s3);
}
go: cactus stack
nil is empty
grows on push
automatic GC
package main
import "fmt"
type stack struct {
int
*stack
}
func (s stack) Push(v int) (r stack) {
r = stack{v,&s}
return
}
func (s stack) Pop() (v int, r stack) {
return s.int, *s.stack
}
func (s stack) Depth() (r int) {
for t := s.stack; t != nil; t = t.stack {
r++
}
return
}
func (s *stack) PrintSum() {
fmt.Printf("sum(%v): %vn", s.Depth(), s.Sum())
}
func (s stack) Sum() (r int) {
for t, n := s, 0; t.stack != nil; r += n {
n, t = t.Pop()
}
return
}
func main() {
s1 := new(stack).Push(7)
s2 := s1.Push(7).Push(11)
s1 = s1.Push(2).Push(9).Push(4)
s3 := s1.Push(17)
s1 = s1.Push(3)
s1.PrintSum()
s2.PrintSum()
s3.PrintSum()
}
caches
discontiguous
label-addressable
outside memory
c: hash map
data array
associative arrays
search
#include <limits.h>
struct map {
int size;
assoc_array_t **chains;
};
typedef struct map map_t;
map_t *map_new(int size) {
map_t *m = malloc(sizeof(map_t));
m->chains = malloc(sizeof(assoc_array_t*) * size);
for (int i = 0; i < size; i++) {
m->chains[i] = NULL;
}
m->size = size;
return m;
}
int map_chain(map_t *m, char *k) {
unsigned long int b;
for (int i = strlen(k) - 1; b < ULONG_MAX && i > 0; i--) {
b = b << 8;
b += k[i];
}
return b % m->size;
}
char *map_get(map_t *m, char *k) {
search_t *s = search_find(m->chains[map_chain(m, k)], k);
if (s != NULL) {
return s->value;
}
return NULL;
}
void map_set(map_t *m, char *k, char *v) {
int b = map_chain(m, k);
assoc_array_t *a = m->chains[b];
search_t *s = search_find(a, k);
if (s->value != NULL) {
s->cursor->value = strdup(v);
} else {
assoc_array_t *n = assoc_array_new(k, v);
if (s->cursor == a) {
n->next = s->cursor;
m->chains[b] = n;
} else if (s->cursor == NULL) {
s->memo->next = n;
} else {
n->next = s->cursor;
s->memo->next = n;
}
}
free(s);
}
c: hash map
data array
search
associative arrays
struct search {
char *term, *value;
assoc_array_t *cursor, *memo;
};
typedef struct search search_t;
search_t *search_new(assoc_array_t *a, char *k) {
search_t *s = malloc(sizeof(search_t));
s->term = k;
s->value = NULL;
s->cursor = a;
s->memo = NULL;
return s;
}
void search_step(search_t *s) {
s->value = assoc_array_get_if(s->cursor, s->term);
}
int searching(search_t *s) {
return s->value == NULL && s->cursor != NULL;
}
search_t *search_find(assoc_array_t *a, char *k) {
search_t *s = search_new(a, k);
for (search_step(s); searching(s); search_step(s)) {
s->memo = s->cursor;
s->cursor = s->cursor->next;
}
return s;
}
c: hash map
data array
search
associative arrays
#include <stdlib.h>
#include <string.h>
struct assoc_array {
char *key;
void *value;
struct assoc_array *next;
};
typedef struct assoc_array assoc_array_t;
assoc_array_t *assoc_array_new(char *k, char *v) {
assoc_array_t *a = malloc(sizeof(assoc_array_t));
a->key = strdup(k);
a->value = strdup(v);
a->next = NULL;
return a;
}
char *assoc_array_get_if(assoc_array_t *a, char *k) {
char *r = NULL;
if (a != NULL && strcmp(a->key, k) == 0) {
r = strdup(a->value);
}
return r;
}
c: hash map
data array
search
associative arrays
#include <stdio.h>
#include "map.h"
int main( int argc, char **argv ) {
map_t *m = map_new(1024);
map_set(m, "apple", "rosy");
printf("%sn", map_get(m, "apple"));
map_set(m, "blueberry", "sweet");
printf("%sn", map_get(m, "blueberry"));
map_set(m, "cherry", "pie");
printf("%sn", map_get(m, "cherry"));
map_set(m, "cherry", "tart");
printf("%sn", map_get(m, "cherry"));
printf("%sn", map_get(m, “tart"));
}
rosy
sweet
pie
tart
(null)
go: hash map
associative array
searcher
slice of arrays
package main
type AssocArray struct {
Key string
Value interface{}
Next *AssocArray
};
func Find(a *AssocArray, k string) (s *Search) {
s = &Search{ Term: k, Cursor: a }
for s.Step(); s.Searching(); s.Step() {
s.Memo = s.Cursor
s.Cursor = s.Cursor.Next
}
return
}
func (a *AssocArray) GetIf(k string) (r interface{}) {
if a != nil && a.Key == k {
r = a.Value
}
return
}
type Search struct {
Term string
Value interface{}
Cursor, Memo *AssocArray
};
func (s *Search) Step() *Search {
s.Value = s.Cursor.GetIf(s.Term)
return s
}
func (s *Search) Searching() bool {
return s.Value == nil && s.Cursor != nil
}
go: hash map
associative array
searcher
slice of arrays
package main
type AssocArray struct {
Key string
Value interface{}
Next *AssocArray
};
func Find(a *AssocArray, k string) (s *Search) {
s = &Search{ Term: k, Cursor: a }
for s.Step(); s.Searching(); s.Step() {
s.Memo = s.Cursor
s.Cursor = s.Cursor.Next
}
return
}
func (a *AssocArray) GetIf(k string) (r interface{}) {
if a != nil && a.Key == k {
r = a.Value
}
return
}
type Search struct {
Term string
Value interface{}
Cursor, Memo *AssocArray
};
func (s *Search) Step() *Search {
s.Value = s.Cursor.GetIf(s.Term)
return s
}
func (s *Search) Searching() bool {
return s.Value == nil && s.Cursor != nil
}
go: hash map
associative array
searcher
slice of arrays
type Map []*AssocArray
func (m Map) Chain(k string) int {
var c uint
for i := len(k) - 1; i > 0; i-- {
c = c << 8
c += (uint)(k[i])
}
return int(c) % len(m)
}
func (m Map) Set(k string, v interface{}) {
c := m.Chain(k)
a := m[c]
s := Find(a, k)
if s.Value != nil {
s.Cursor.Value = v
} else {
n := &AssocArray{ Key: k, Value: v }
switch {
case s.Cursor == a:
n.Next = s.Cursor
m[c] = n
case s.Cursor == nil:
s.Memo.Next = n
default:
n.Next = s.Cursor
s.Memo.Next = n
}
}
}
func (m Map) Get(k string) (r interface{}) {
if s := Find(m[m.Chain(k)], k); s != nil {
r = s.Value
}
return
}
go: hash map
hashmap
vs
native map
package main
import "fmt"
func main() {
v := make(map[string] interface{})
v["apple"] = "rosy"
v["blueberry"] = "sweet"
v["cherry"] = "pie"
fmt.Printf("%vn", v["apple"])
fmt.Printf("%vn", v["blueberry"])
fmt.Printf("%vn", v["cherry"])
v["cherry"] = "tart"
fmt.Printf("%vn", v["cherry"])
fmt.Printf("%vn", v["tart"])
m := make(Map, 1024)
m.Set("apple", "rosy")
m.Set("blueberry", "sweet")
m.Set("cherry", "pie")
fmt.Printf("%vn", m.Get("apple"))
fmt.Printf("%vn", m.Get("blueberry"))
fmt.Printf("%vn", m.Get("cherry"))
m.Set("cherry", "tart")
fmt.Printf("%vn", m.Get("cherry"))
fmt.Printf("%vn", m.Get("tart"))
}
rosy
sweet
pie
tart
(null)
rosy
sweet
pie
tart
(null)
heaps
word-aligned
contiguous
byte-addressable
go: slice heap
array of pointers
reflect
unsafe
package main
import "fmt"
import r "reflect"
import "unsafe"
type Memory []uintptr
var _BYTE_SLICE = r.TypeOf([]byte(nil))
var _MEMORY = r.TypeOf(Memory{})
var _MEMORY_BYTES = int(_MEMORY.Elem().Size())
func (m Memory) newHeader() (h r.SliceHeader) {
h = *(*r.SliceHeader)(unsafe.Pointer(&m))
h.Len = len(m) * _MEMORY_BYTES
h.Cap = cap(m) * _MEMORY_BYTES
return
}
func (m *Memory) Serialise() (b []byte) {
h := m.newHeader()
b = make([]byte, h.Len)
copy(b, *(*[]byte)(unsafe.Pointer(&h)))
return
}
func (m *Memory) Overwrite(i interface{}) {
switch i := i.(type) {
case Memory:
copy(*m, i)
case []byte:
h := m.newHeader()
b := *(*[]byte)(unsafe.Pointer(&h))
copy(b, i)
}
}
func (m *Memory) Bytes() (b []byte) {
h := m.newHeader()
return *(*[]byte)(unsafe.Pointer(&h))
}
func main() {
m := make(Memory, 2)
b := m.Bytes()
s := m.Serialise()
fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m)
fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b)
fmt.Println("s (bytes) =", len(s), "of", cap(s), ":", s)
m.Overwrite(Memory{3, 5})
fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m)
fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b)
fmt.Println("s (bytes) =", len(s), "of", cap(s), ":", s)
s = m.Serialise()
m.Overwrite([]byte{8, 7, 6, 5, 4, 3, 2, 1})
fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m)
fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b)
fmt.Println("s (bytes) =", len(s), "of", cap(s), ":", s)
}
go: slice heap
array of pointers
reflect
unsafe
package main
import r "reflect"
import "unsafe"
type Memory []uintptr
var _BYTE_SLICE = r.TypeOf([]byte(nil))
var _MEMORY = r.TypeOf(Memory{})
var _MEMORY_BYTES = int(_MEMORY.Elem().Size())
func (m Memory) newHeader() (h r.SliceHeader) {
h = *(*r.SliceHeader)(unsafe.Pointer(&m))
h.Len = len(m) * _MEMORY_BYTES
h.Cap = cap(m) * _MEMORY_BYTES
return
}
func (m *Memory) Serialise() (b []byte) {
h := m.newHeader()
b = make([]byte, h.Len)
copy(b, *(*[]byte)(unsafe.Pointer(&h)))
return
}
func (m *Memory) Overwrite(i interface{}) {
switch i := i.(type) {
case Memory:
copy(*m, i)
case []byte:
h := m.newHeader()
b := *(*[]byte)(unsafe.Pointer(&h))
copy(b, i)
}
}
func (m *Memory) Bytes() (b []byte) {
h := m.newHeader()
return *(*[]byte)(unsafe.Pointer(&h))
}
func main() {
m := make(Memory, 2)
b := m.Bytes()
s := m.Serialise()
fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m)
fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b)
fmt.Println("s (bytes) =", len(s), "of", cap(s), ":", s)
m.Overwrite(Memory{3, 5})
fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m)
fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b)
fmt.Println("s (bytes) =", len(s), "of", cap(s), ":", s)
s = m.Serialise()
m.Overwrite([]byte{8, 7, 6, 5, 4, 3, 2, 1})
fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m)
fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b)
fmt.Println("s (bytes) =", len(s), "of", cap(s), ":", s)
}
go: slice heap
array of pointers
reflect
unsafe
package main
import r "reflect"
import "unsafe"
type Memory []uintptr
var _BYTE_SLICE = r.TypeOf([]byte(nil))
var _MEMORY = r.TypeOf(Memory{})
var _MEMORY_BYTES = int(_MEMORY.Elem().Size())
func (m Memory) newHeader() (h r.SliceHeader) {
h = *(*r.SliceHeader)(unsafe.Pointer(&m))
h.Len = len(m) * _MEMORY_BYTES
h.Cap = cap(m) * _MEMORY_BYTES
return
}
func (m *Memory) Serialise() (b []byte) {
h := m.newHeader()
b = make([]byte, h.Len)
copy(b, *(*[]byte)(unsafe.Pointer(&h)))
return
}
func (m *Memory) Overwrite(i interface{}) {
switch i := i.(type) {
case Memory:
copy(*m, i)
case []byte:
h := m.newHeader()
b := *(*[]byte)(unsafe.Pointer(&h))
copy(b, i)
}
}
func (m *Memory) Bytes() (b []byte) {
h := m.newHeader()
return *(*[]byte)(unsafe.Pointer(&h))
}
func main() {
m := make(Memory, 2)
b := m.Bytes()
s := m.Serialise()
fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m)
fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b)
fmt.Println("s (bytes) =", len(s), "of", cap(s), ":", s)
m.Overwrite(Memory{3, 5})
fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m)
fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b)
fmt.Println("s (bytes) =", len(s), "of", cap(s), ":", s)
s = m.Serialise()
m.Overwrite([]byte{8, 7, 6, 5, 4, 3, 2, 1})
fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m)
fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b)
fmt.Println("s (bytes) =", len(s), "of", cap(s), ":", s)
}
despatch loops
fetch instruction
decode
execute
c: switch
portable
slow
byte tokens
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
#define READ_OPCODE *PC++
typedef enum { PUSH = 0, ADD, PRINT, EXIT } opcodes;
STACK *S;
void interpret(int *PC) {
int l, r;
while (1) {
switch(READ_OPCODE) {
case PUSH:
S = push(S, READ_OPCODE);
break;
case ADD:
S = pop(S, &l);
S = pop(S, &r);
S = push(S, l + r);
break;
case PRINT:
printf(“%d + %d = %dn, l, r, S->data);
break;
case EXIT:
return;
}
}
}
int main() {
int program [] = {
(int)PUSH, 13,
(int)PUSH, 28,
(int)ADD,
PRINT,
EXIT,
};
interpret(program);
}
c: direct call
portable
pointer to function
multi-byte
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
#define READ_OPCODE *PC++
typedef void (*opcode)();
STACK *S;
opcode *PC;
void op_push() {
S = push(S, (int)(long)(READ_OPCODE));
}
void op_add_and_print() {
int l, r;
S = pop(S, &l);
S = pop(S, &r);
S = push(S, l + r);
printf("%d + %d = %dn", l, r, S->data);
}
void op_exit() {
exit(0);
}
void interpret(opcode *program) {
PC = program;
while (1) {
(READ_OPCODE)();
}
}
int main() {
opcode program [] = {
op_push, (opcode)(long)13,
op_push, (opcode)(long)28,
op_add_and_print,
op_exit
};
interpret(program);
}
c: indirect thread
gcc/clang specific
local jumps
indirect loading
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
typedef enum {
PUSH = 0, ADD, PRINT, EXIT
} opcodes;
void interpret(int *program) {
static void *opcodes [] = {
&&op_push, &&op_add, &&op_print, &&op_exit
};
int l, r;
STACK *S;
int *PC = program;
goto *opcodes[*PC++];
op_push:
S = push(S, *PC++);
goto *opcodes[*PC++];
op_add:
S = pop(S, &l);
S = pop(S, &r);
S = push(S, l + r);
goto *opcodes[*PC++];
op_print:
printf("%d + %d = %dn", l, r, S->data);
goto *opcodes[*PC++];
op_exit:
return;
}
int main() {
int program [] = {
PUSH, 13,
PUSH, 28,
ADD,
PRINT,
EXIT
};
interpret(program);
}
c: indirect thread
gcc/clang specific
local jumps
indirect loading
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
#define READ_OPCODE *PC++
#define EXECUTE_OPCODE 
goto *opcodes[READ_OPCODE];
#define PRIMITIVE(name, body) 
name: 
body; 
EXECUTE_OPCODE
typedef enum { PUSH = 0, ADD, PRINT, EXIT } opcodes;
STACK *S;
void interpret(int *program) {
static void *opcodes [] = {
&&op_push,
&&op_add,
&&op_print,
&&op_exit
};
int l, r;
int *PC = program;
EXECUTE_OPCODE;
PRIMITIVE(op_push, 
S = push(S, READ_OPCODE) 
)
PRIMITIVE(op_print, 
printf("%d + %d = %dn", l, r, S->data) 
)
PRIMITIVE(op_add, 
S = pop(S, &l); 
S = pop(S, &r); 
S = push(S, l + r) 
)
PRIMITIVE(op_exit, 
return
)
}
int main() {
int program [] = {
PUSH, 13,
PUSH, 28,
ADD,
PRINT,
EXIT
};
interpret(program);
}
c: direct thread
void **compile(int *PC, int words, void *despatch_table[]) {
static void *compiler [] = {
&&c_push, &&c_add, &&c_print, &&c_exit
};
if (words < 1) return NULL;
void **program = malloc(sizeof(void *) * words);
void **cp = program;
goto *compiler[*PC++];
c_number:
*cp++ = (void *)(long)*PC++;
words—;
if (words == 0) return program;
goto *compiler[*PC++];
c_push:
*cp++ = despatch_table[PUSH];
*cp++ = (void *)(long)*PC++;
words—;
goto c_number;
c_add:
*cp++ = despatch_table[ADD];
words--;
if (words == 0) return program;
goto *compiler[*PC++];
c_print:
*cp++ = despatch_table[PRINT];
words--;
if (words == 0) return program;
goto *compiler[*PC++];
c_exit:
*cp++ = despatch_table[EXIT];
words--;
if (words == 0) return program;
goto *compiler[*PC++];
}
void interpret(int *PC, int words) {
static void *despatch_table[] = {
&&op_push, &&op_add, &&op_print, &&op_exit
};
int l, r;
void **program = compile(PC, words, despatch_table);
if (program == NULL) exit(1);
goto **program++;
op_push:
S = push(S, (int)(long)*program++);
goto **program++;
op_add:
S = pop(S, &l);
S = pop(S, &r);
S = push(S, l + r);
goto **program++;
op_print:
printf("%d + %d = %dn", l, r, S->data);
goto **program++;
op_exit:
return;
}
c: direct thread
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
#define COMPILE_NEXT_OPCODE goto *compiler[*PC++];
#define COMPILE_NUMBER 
*cp++ = (void *)(long)*PC++; 
words--;
#define PRIMITIVE_ADDRESS(op) *cp++ = despatch_table[op];
#define COMPILE_PRIMITIVE(name, body) 
c_##name: 
PRIMITIVE_ADDRESS(name) 
body; 
words--; 
if (words == 0) return program; 
COMPILE_NEXT_OPCODE
void **compile(int *PC, int words, void *despatch_table[]) {
static void *compiler [] = {
&&c_push, &&c_add, &&c_print, &&c_exit
};
if (words < 1) return NULL;
void **program = malloc(sizeof(void *) * words);
void **cp = program;
COMPILE_NEXT_OPCODE
COMPILE_PRIMITIVE(PUSH, COMPILE_NUMBER)
COMPILE_PRIMITIVE(ADD, ;)
COMPILE_PRIMITIVE(PRINT, ;)
COMPILE_PRIMITIVE(EXIT, ;)
}
#define NEXT_OPCODE goto **program++;
#define PRIMITIVE(name, body) 
op_##name: 
body; 
NEXT_OPCODE
void interpret(int *PC, int words) {
static void *despatch_table[] = {
&&op_push, &&op_add, &&op_print, &&op_exit
};
int l, r;
void **program = compile(PC, words, despatch_table);
if (program == NULL) exit(1);
NEXT_OPCODE
PRIMITIVE(push, S = push(S, (int)(long)*program++))
PRIMITIVE(add, 
S = pop(S, &l); 
S = pop(S, &r); 
S = push(S, l + r); 
)
PRIMITIVE(print, printf("%d + %d = %dn", l, r, S->data))
PRIMITIVE(exit, return)
}
int main() {
int program[] = {
PUSH, 13,
PUSH, 28,
ADD,
PRINT,
EXIT
};
interpret(program, 7);
}
go: switch
constants
package main
import "fmt"
type stack struct {
int
*stack
}
func (s *stack) Push(v int) *stack {
return &stack{v, s}
}
func (s *stack) Pop() (int, *stack) {
return s.int, s.stack
}
type OPCODE int
const (
PUSH = OPCODE(iota)
ADD
PRINT
EXIT
)
func main() {
interpret([]interface{}{
PUSH, 13,
PUSH, 28,
ADD,
PRINT,
EXIT,
})
}
func interpret(p []interface{}) {
var l, r int
S := new(stack)
for PC := 0; ; PC++ {
if op, ok := p[PC].(OPCODE); ok {
switch op {
case PUSH:
PC++
S = S.Push(p[PC].(int))
case ADD:
l, S = S.Pop()
r, S = S.Pop()
S = S.Push(l + r)
case PRINT:
fmt.Printf("%v + %v = %vn", l, r, S.int)
case EXIT:
return
}
} else {
return
}
}
}
go: direct call
function pointers
package main
import "fmt"
import "os"
type stack struct {
int
*stack
}
func (s *stack) Push(v int) *stack {
return &stack{v, s}
}
func (s *stack) Pop() (int, *stack) {
return s.int, s.stack
}
func main() {
p := new(Interpreter)
p.Load(
p.Push, 13,
p.Push, 28,
p.Add,
p.Print,
p.Exit,
)
p.Run()
}
type Interpreter struct {
S *stack
l, r, PC int
m []interface{}
}
func (i *Interpreter) read_program() (r interface{}) {
return i.m[i.PC]
}
func (i *Interpreter) Load(p ...interface{}) {
i.m = p
}
func (i *Interpreter) Run() {
for {
i.read_program().(func())()
i.PC++
}
}
func (i *Interpreter) Push() {
i.PC++
i.S = i.S.Push(i.read_program().(int))
}
func (i *Interpreter) Add() {
i.l, i.S = i.S.Pop()
i.r, i.S = i.S.Pop()
i.S = i.S.Push(i.l + i.r)
}
func (i *Interpreter) Print() {
fmt.Printf("%v + %v = %vn", i.l, i.r, i.S.int)
}
func (i *Interpreter) Exit() {
os.Exit(0)
}
go: direct call
function literals
package main
import "fmt"
import "os"
type stack struct {
int
*stack
}
func (s *stack) Push(v int) *stack {
return &stack{v, s}
}
func (s *stack) Pop() (int, *stack) {
return s.int, s.stack
}
type Primitive func(*Interpreter)
type Interpreter struct {
S *stack
l, r, PC int
m []Primitive
}
func (i *Interpreter) read_program() Primitive {
return i.m[i.PC]
}
func (i *Interpreter) Run() {
for {
i.read_program()(i)
i.PC++
}
}
func main() {
p := &Interpreter{
m: []Primitive{
func(i *Interpreter) {
i.S = i.S.Push(13)
},
func(i *Interpreter) {
i.S = i.S.Push(28)
},
func(i *Interpreter) {
i.l, i.S = i.S.Pop()
i.r, i.S = i.S.Pop()
i.S = i.S.Push(i.l + i.r)
},
func(i *Interpreter) {
fmt.Printf("%v + %v = %vn", i.l, i.r, i.S.int)
},
func (i *Interpreter) {
os.Exit(0)
},
},
}
p.Run()
}
go: direct call
closures
package main
import "fmt"
import "os"
type stack struct {
int
*stack
}
func (s *stack) Push(v int) *stack {
return &stack{v, s}
}
func (s *stack) Pop() (int, *stack) {
return s.int, s.stack
}
type Primitive func(*Interpreter)
type Interpreter struct {
S *stack
l, r, PC int
m []Primitive
}
func (i *Interpreter) read_program() Primitive {
return i.m[i.PC]
}
func (i *Interpreter) Run() {
for {
i.read_program()
i.PC++
}
}
func main() {
var p *Interpreter
p := &Interpreter{
m: []Primitive{
func() {
p.S = p.S.Push(13)
},
func() {
p.S = p.S.Push(28)
},
func() {
p.l, p.S = p.S.Pop()
p.r, p.S = p.S.Pop()
p.S = p.S.Push(p.l + p.r)
},
func() {
fmt.Printf("%v + %v = %vn", p.l, p.r, p.S.int)
},
func () {
os.Exit(0)
},
},
}
p.Run()
}
go: direct call
closures
compilation
package main
import "fmt"
import "os"
type stack struct {
int
*stack
}
func (s *stack) Push(v int) *stack {
return &stack{v, s}
}
func (s *stack) Pop() (int, *stack) {
return s.int, s.stack
}
type Primitive func()
type Label string
type labels []Label
type VM struct {
PC int
m []interface{}
labels
}
func (v *VM) Load(program ...interface{}) {
v.labels = make(labels)
v.PC = -1
for _, token := range program {
v.assemble(token)
}
}
func (v *VM) assemble(token interface{}) {
switch t := token.(type) {
case Label:
if i, ok := v.labels[t]; ok {
v.m = append(v.m, i)
} else {
v.labels[t] = v.PC
}
default:
v.m = append(v.m, token)
v.PC++
}
}
func (v *VM) Run() {
v.PC = -1
for {
v.PC++
v.read_program().(Primitive)()
}
}
func (v *VM) read_program() interface{} {
return v.m[v.PC]
}
type Interpreter struct {
VM
S *stack
l, r int
}
go: direct call
closures
compilation
func main() {
p := new(Interpreter)
p.Load(
Label("start"),
Primitive(func() { p.S = p.S.Push(13) }),
Primitive(func() { p.S = p.S.Push(28) }),
Primitive(func() {
p.l, p.S = p.S.Pop()
p.r, p.S = p.S.Pop()
p.S = p.S.Push(p.l + p.r)
}),
Primitive(func() {
fmt.Printf("%v + %v = %vn", p.l, p.r, p.S.int)
}),
Primitive(func() { os.Exit(0) }),
Label("end"),
)
p.Run()
}
processing units
registers
operands
local caching
go: vm harness
closures
compilation
package main
import "fmt"
import "os"
type stack struct {
int
*stack
}
func (s *stack) Push(v int) *stack {
return &stack{v, s}
}
func (s *stack) Pop() (int, *stack) {
return s.int, s.stack
}
type Primitive func()
type Label string
type labels map[Label]int
type VM struct {
PC int
m []interface{}
labels
}
func (v *VM) Load(program ...interface{}) {
v.labels = make(labels)
v.PC = -1
for _, token := range program {
v.assemble(token)
}
}
func (v *VM) assemble(token interface{}) {
switch t := token.(type) {
case Label:
if i, ok := v.labels[t]; ok {
v.m = append(v.m, i)
} else {
v.labels[t] = v.PC
}
default:
v.m = append(v.m, token)
v.PC++
}
}
func (v *VM) Run() {
v.PC = -1
for {
v.PC++
v.read_program().(Primitive)()
}
}
func (v *VM) read_program() interface{} {
return v.m[v.PC]
}
stack machine
zero operands
type StackMachine struct {
*stack
VM
}
func (s *StackMachine) Push() {
s.PC++
s.S = s.S.Push(s.read_program().(int))
}
func (s *StackMachine) Add() {
s.l, s.S = s.S.Pop()
s.r, s.S = s.S.Pop()
s.S = s.S.Push(s.l + s.r)
}
func (s *StackMachine) JumpIfNotZero() {
s.PC++
if s.int != 0 {
s.PC = s.m[s.PC].(int)
}
}
func main() {
s := new(StackMachine)
print_state := Primitive(func() {
fmt.Printf("pc[%v]: %v, TOS: %vn",
s.PC,
s.m[s.PC],
s.int,
)
})
s.Load(
Primitive(s.Push), 13,
Label("dec"),
Primitive(func() {
s.stack = s.stack.Push(-1)
}),
Primitive(s.Add),
print_state,
Primitive(s.JumpIfNotZero), Label("dec"),
print_state,
Primitive(func() {
os.Exit(0)
}),
).Run()
}
the accumulator
single register
single operand
type AccMachine struct {
int
VM
}
func (a *AccMachine) Clear() {
a.int = 0
}
func (a *AccMachine) LoadValue() {
a.PC++
a.int = a.read_program().(int)
}
func (a *AccMachine) Add() {
a.PC++
a.int += a.read_program().(int)
}
func (a *AccMachine) JumpIfNotZero() {
a.PC++
if a.int != 0 {
a.PC = a.m[a.PC].(int)
}
}
func main() {
a := new(AccMachine)
print_state := Primitive(func() {
fmt.Printf("pc[%v]: %v, Acc: %vn",
a.PC,
a.m[a.PC],
a.int,
)
})
a.Load(
Primitive(a.Clear),
Primitive(a.LoadValue), 13,
Label("dec"),
Primitive(a.Add), -1,
print_state,
Primitive(a.JumpIfNotZero), Label("dec"),
print_state,
Primitive(func() {
os.Exit(0)
}),
).Run()
}
register machine
multi-register
multi-operand
type RegMachine struct {
R []int
VM
}
func (r *RegMachine) Clear() {
r.R = make([]int, 2, 2)
}
func (r *RegMachine) read_value() int {
r.PC++
return r.read_program().(int)
}
func (r *RegMachine) LoadValue() {
r.R[r.read_value()] = r.read_value()
}
func (r *RegMachine) Add() {
i := r.read_value()
j := r.read_value()
r.R[i] += r.R[j]
}
func (r *RegMachine) JumpIfNotZero() {
if r.R[r.read_value()] != 0 {
r.PC = r.read_value()
} else {
r.PC++
}
}
func main() {
r := new(RegMachine)
print_state := Primitive(func() {
fmt.Printf("pc[%v]: %v, Acc: %vn",
r.PC,
r.m[r.PC],
r.R,
)
})
r.Load(
Primitive(r.Clear),
Primitive(r.LoadValue), 0, 13,
Primitive(r.LoadValue), 1, -1,
Label("dec"),
Primitive(r.Add), 0, 1,
print_state,
Primitive(r.JumpIfNotZero), 0, Label("dec"),
print_state,
Primitive(func() {
os.Exit(0)
}),
).Run()
}
vector & matrices
hypercubes
graphs
quaternions
any datatype can be a register
Go & cgo: integrating
existing C code with Go
Andreas Krennmair <ak@synflood.at>
Golang User Group Berlin
Twitter: @der_ak
cgo
inline c
Feb 5, 2013 at 10:28PM
Caleb DoxseyCaleb Doxsey // BlogBlog // Go & AssemblyGo & Assembly
Go & AssemblyGo & Assembly
Caleb Doxsey
One of my favorite parts about Go is its unwavering focus on utility. Sometimes we place
so much emphasis on language design that we forget all the other things programming
involves. For example:
Go's compiler is fast
Go comes with a robust standard library
Go works on a multitude of platforms
Go comes with a complete set of documentation available from the command line /
a local web server / the internet
All Go code is statically compiled so deployment is trivial
The entirety of the Go source code is available for perusal in an easy format online
(like this)
Go has a well defined (and documented) grammar for parsing. (unlike C++ or Ruby)
Go comes with a package management tool. go get X (for example go get
code.google.com/p/go.net/websocket )
assembly
SIMD
branch prediction
cache misses
memory latency
This repository Pull requests Issues Gist
No description or website provided. — Edit
00 memory experiments with Fiddle::Pointer exploring use of C-style memory mana… 5 days ago
01 stacks stacks in Go 5 days ago
02 hashes roll-your-own hash maps in Go 5 days ago
03 dispatcher Go versions of dispatch loops 5 days ago
04 architecture implementations of popular VM architectural styles 5 days ago
LICENSE Initial commit 5 days ago
README.md added links for slides and video of talks based on this code 5 days ago
Search
feyeleanor / vm-fragments
Code Issues 0 Pull requests 0 Projects 0 Wiki Pulse Graphs Settings
13 commits 1 branch 0 releases 1 contributor MIT
Clone or downloadClone or downloadCreate new file Upload files Find filemasterBranch: New pull request
Latest commit 9ee7fe0 5 days agofeyeleanor implementations of popular VM architectural styles
README.md
vm-fragments
A collection of code fragments for talks I've given around implementing simple virtual machine internals in C, Go and Ruby.
The slides for these talks are available at:
1 01Unwatch Star Fork
source code
Implementing virtual machines in go & c 2018 redux
implementing
virtual machines
in
Go & C
Eleanor McHugh
@feyeleanor
slideshare://feyeleanor github://feyeleanor
Ad

More Related Content

What's hot (20)

Kotlin collections
Kotlin collectionsKotlin collections
Kotlin collections
Myeongin Woo
 
Python Performance 101
Python Performance 101Python Performance 101
Python Performance 101
Ankur Gupta
 
Python легко и просто. Красиво решаем повседневные задачи
Python легко и просто. Красиво решаем повседневные задачиPython легко и просто. Красиво решаем повседневные задачи
Python легко и просто. Красиво решаем повседневные задачи
Maxim Kulsha
 
Going Loopy: Adventures in Iteration with Go
Going Loopy: Adventures in Iteration with GoGoing Loopy: Adventures in Iteration with Go
Going Loopy: Adventures in Iteration with Go
Eleanor McHugh
 
Imugi: Compiler made with Python
Imugi: Compiler made with PythonImugi: Compiler made with Python
Imugi: Compiler made with Python
Han Lee
 
20180310 functional programming
20180310 functional programming20180310 functional programming
20180310 functional programming
Chiwon Song
 
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italyFrom java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
Fabio Collini
 
The basics and design of lua table
The basics and design of lua tableThe basics and design of lua table
The basics and design of lua table
Shuai Yuan
 
Why Learn Python?
Why Learn Python?Why Learn Python?
Why Learn Python?
Christine Cheung
 
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFrom Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
Fabio Collini
 
Java VS Python
Java VS PythonJava VS Python
Java VS Python
Simone Federici
 
ProgrammingwithGOLang
ProgrammingwithGOLangProgrammingwithGOLang
ProgrammingwithGOLang
Shishir Dwivedi
 
Hello Swift 3/5 - Function
Hello Swift 3/5 - FunctionHello Swift 3/5 - Function
Hello Swift 3/5 - Function
Cody Yun
 
Implementing Virtual Machines in Go & C
Implementing Virtual Machines in Go & CImplementing Virtual Machines in Go & C
Implementing Virtual Machines in Go & C
Eleanor McHugh
 
Hands on lua
Hands on luaHands on lua
Hands on lua
Javier Arauz
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my day
Tor Ivry
 
Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night TurinAsync code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Fabio Collini
 
20181020 advanced higher-order function
20181020 advanced higher-order function20181020 advanced higher-order function
20181020 advanced higher-order function
Chiwon Song
 
Mozilla とブラウザゲーム
Mozilla とブラウザゲームMozilla とブラウザゲーム
Mozilla とブラウザゲーム
Noritada Shimizu
 
Go vs C++ - CppRussia 2019 Piter BoF
Go vs C++ - CppRussia 2019 Piter BoFGo vs C++ - CppRussia 2019 Piter BoF
Go vs C++ - CppRussia 2019 Piter BoF
Timur Safin
 
Kotlin collections
Kotlin collectionsKotlin collections
Kotlin collections
Myeongin Woo
 
Python Performance 101
Python Performance 101Python Performance 101
Python Performance 101
Ankur Gupta
 
Python легко и просто. Красиво решаем повседневные задачи
Python легко и просто. Красиво решаем повседневные задачиPython легко и просто. Красиво решаем повседневные задачи
Python легко и просто. Красиво решаем повседневные задачи
Maxim Kulsha
 
Going Loopy: Adventures in Iteration with Go
Going Loopy: Adventures in Iteration with GoGoing Loopy: Adventures in Iteration with Go
Going Loopy: Adventures in Iteration with Go
Eleanor McHugh
 
Imugi: Compiler made with Python
Imugi: Compiler made with PythonImugi: Compiler made with Python
Imugi: Compiler made with Python
Han Lee
 
20180310 functional programming
20180310 functional programming20180310 functional programming
20180310 functional programming
Chiwon Song
 
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italyFrom java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
Fabio Collini
 
The basics and design of lua table
The basics and design of lua tableThe basics and design of lua table
The basics and design of lua table
Shuai Yuan
 
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFrom Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
Fabio Collini
 
Hello Swift 3/5 - Function
Hello Swift 3/5 - FunctionHello Swift 3/5 - Function
Hello Swift 3/5 - Function
Cody Yun
 
Implementing Virtual Machines in Go & C
Implementing Virtual Machines in Go & CImplementing Virtual Machines in Go & C
Implementing Virtual Machines in Go & C
Eleanor McHugh
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my day
Tor Ivry
 
Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night TurinAsync code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Fabio Collini
 
20181020 advanced higher-order function
20181020 advanced higher-order function20181020 advanced higher-order function
20181020 advanced higher-order function
Chiwon Song
 
Mozilla とブラウザゲーム
Mozilla とブラウザゲームMozilla とブラウザゲーム
Mozilla とブラウザゲーム
Noritada Shimizu
 
Go vs C++ - CppRussia 2019 Piter BoF
Go vs C++ - CppRussia 2019 Piter BoFGo vs C++ - CppRussia 2019 Piter BoF
Go vs C++ - CppRussia 2019 Piter BoF
Timur Safin
 

Similar to Implementing virtual machines in go & c 2018 redux (20)

Go: It's Not Just For Google
Go: It's Not Just For GoogleGo: It's Not Just For Google
Go: It's Not Just For Google
Eleanor McHugh
 
lab03build.bat@echo offclsset DRIVE_LETTER=1set.docx
lab03build.bat@echo offclsset DRIVE_LETTER=1set.docxlab03build.bat@echo offclsset DRIVE_LETTER=1set.docx
lab03build.bat@echo offclsset DRIVE_LETTER=1set.docx
DIPESH30
 
purrr.pdf
purrr.pdfpurrr.pdf
purrr.pdf
Mateus S. Xavier
 
1sequences and sampling. Suppose we went to sample the x-axis from X.pdf
1sequences and sampling. Suppose we went to sample the x-axis from X.pdf1sequences and sampling. Suppose we went to sample the x-axis from X.pdf
1sequences and sampling. Suppose we went to sample the x-axis from X.pdf
rushabhshah600
 
Pointers [compatibility mode]
Pointers [compatibility mode]Pointers [compatibility mode]
Pointers [compatibility mode]
Kathmandu University
 
Pointer
PointerPointer
Pointer
Shankar Gangaju
 
I want help in the following C++ programming task. Please do coding .pdf
I want help in the following C++ programming task. Please do coding .pdfI want help in the following C++ programming task. Please do coding .pdf
I want help in the following C++ programming task. Please do coding .pdf
bermanbeancolungak45
 
Oh Composable World!
Oh Composable World!Oh Composable World!
Oh Composable World!
Brian Lonsdorf
 
Input output functions
Input output functionsInput output functions
Input output functions
hyderali123
 
Ch8a
Ch8aCh8a
Ch8a
kinnarshah8888
 
The groovy puzzlers (as Presented at JavaOne 2014)
The groovy puzzlers (as Presented at JavaOne 2014)The groovy puzzlers (as Presented at JavaOne 2014)
The groovy puzzlers (as Presented at JavaOne 2014)
GroovyPuzzlers
 
Some Examples in R- [Data Visualization--R graphics]
 Some Examples in R- [Data Visualization--R graphics] Some Examples in R- [Data Visualization--R graphics]
Some Examples in R- [Data Visualization--R graphics]
Dr. Volkan OBAN
 
Spark_Documentation_Template1
Spark_Documentation_Template1Spark_Documentation_Template1
Spark_Documentation_Template1
Nagavarunkumar Kolla
 
unit-5 String Math Date Time AI presentation
unit-5 String Math Date Time AI presentationunit-5 String Math Date Time AI presentation
unit-5 String Math Date Time AI presentation
MukeshTheLioner
 
Scala 2 + 2 > 4
Scala 2 + 2 > 4Scala 2 + 2 > 4
Scala 2 + 2 > 4
Emil Vladev
 
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kirill Rozov
 
Stupid Awesome Python Tricks
Stupid Awesome Python TricksStupid Awesome Python Tricks
Stupid Awesome Python Tricks
Bryan Helmig
 
VTU Data Structures Lab Manual
VTU Data Structures Lab ManualVTU Data Structures Lab Manual
VTU Data Structures Lab Manual
Nithin Kumar,VVCE, Mysuru
 
talk at Virginia Bioinformatics Institute, December 5, 2013
talk at Virginia Bioinformatics Institute, December 5, 2013talk at Virginia Bioinformatics Institute, December 5, 2013
talk at Virginia Bioinformatics Institute, December 5, 2013
ericupnorth
 
DS Assignment Presentation 20242024.pptx
DS Assignment Presentation 20242024.pptxDS Assignment Presentation 20242024.pptx
DS Assignment Presentation 20242024.pptx
sanjeevijesh
 
Go: It's Not Just For Google
Go: It's Not Just For GoogleGo: It's Not Just For Google
Go: It's Not Just For Google
Eleanor McHugh
 
lab03build.bat@echo offclsset DRIVE_LETTER=1set.docx
lab03build.bat@echo offclsset DRIVE_LETTER=1set.docxlab03build.bat@echo offclsset DRIVE_LETTER=1set.docx
lab03build.bat@echo offclsset DRIVE_LETTER=1set.docx
DIPESH30
 
1sequences and sampling. Suppose we went to sample the x-axis from X.pdf
1sequences and sampling. Suppose we went to sample the x-axis from X.pdf1sequences and sampling. Suppose we went to sample the x-axis from X.pdf
1sequences and sampling. Suppose we went to sample the x-axis from X.pdf
rushabhshah600
 
I want help in the following C++ programming task. Please do coding .pdf
I want help in the following C++ programming task. Please do coding .pdfI want help in the following C++ programming task. Please do coding .pdf
I want help in the following C++ programming task. Please do coding .pdf
bermanbeancolungak45
 
Input output functions
Input output functionsInput output functions
Input output functions
hyderali123
 
The groovy puzzlers (as Presented at JavaOne 2014)
The groovy puzzlers (as Presented at JavaOne 2014)The groovy puzzlers (as Presented at JavaOne 2014)
The groovy puzzlers (as Presented at JavaOne 2014)
GroovyPuzzlers
 
Some Examples in R- [Data Visualization--R graphics]
 Some Examples in R- [Data Visualization--R graphics] Some Examples in R- [Data Visualization--R graphics]
Some Examples in R- [Data Visualization--R graphics]
Dr. Volkan OBAN
 
unit-5 String Math Date Time AI presentation
unit-5 String Math Date Time AI presentationunit-5 String Math Date Time AI presentation
unit-5 String Math Date Time AI presentation
MukeshTheLioner
 
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kirill Rozov
 
Stupid Awesome Python Tricks
Stupid Awesome Python TricksStupid Awesome Python Tricks
Stupid Awesome Python Tricks
Bryan Helmig
 
talk at Virginia Bioinformatics Institute, December 5, 2013
talk at Virginia Bioinformatics Institute, December 5, 2013talk at Virginia Bioinformatics Institute, December 5, 2013
talk at Virginia Bioinformatics Institute, December 5, 2013
ericupnorth
 
DS Assignment Presentation 20242024.pptx
DS Assignment Presentation 20242024.pptxDS Assignment Presentation 20242024.pptx
DS Assignment Presentation 20242024.pptx
sanjeevijesh
 
Ad

More from Eleanor McHugh (20)

Never Say, Never Say Die! - the art of low-level Ruby and other Macabre Tales
Never Say, Never Say Die! - the art of low-level Ruby and other Macabre TalesNever Say, Never Say Die! - the art of low-level Ruby and other Macabre Tales
Never Say, Never Say Die! - the art of low-level Ruby and other Macabre Tales
Eleanor McHugh
 
[2024] An Introduction to Functional Programming with Go [Y Combinator Remix]...
[2024] An Introduction to Functional Programming with Go [Y Combinator Remix]...[2024] An Introduction to Functional Programming with Go [Y Combinator Remix]...
[2024] An Introduction to Functional Programming with Go [Y Combinator Remix]...
Eleanor McHugh
 
[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf
Eleanor McHugh
 
Generics, Reflection, and Efficient Collections
Generics, Reflection, and Efficient CollectionsGenerics, Reflection, and Efficient Collections
Generics, Reflection, and Efficient Collections
Eleanor McHugh
 
The Relevance of Liveness - Biometrics and Data Integrity
The Relevance of Liveness - Biometrics and Data IntegrityThe Relevance of Liveness - Biometrics and Data Integrity
The Relevance of Liveness - Biometrics and Data Integrity
Eleanor McHugh
 
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
Eleanor McHugh
 
An introduction to functional programming with Go [redux]
An introduction to functional programming with Go [redux]An introduction to functional programming with Go [redux]
An introduction to functional programming with Go [redux]
Eleanor McHugh
 
Identity & trust in Monitored Spaces
Identity & trust in Monitored SpacesIdentity & trust in Monitored Spaces
Identity & trust in Monitored Spaces
Eleanor McHugh
 
Don't Ask, Don't Tell - The Virtues of Privacy By Design
Don't Ask, Don't Tell - The Virtues of Privacy By DesignDon't Ask, Don't Tell - The Virtues of Privacy By Design
Don't Ask, Don't Tell - The Virtues of Privacy By Design
Eleanor McHugh
 
Don't ask, don't tell the virtues of privacy by design
Don't ask, don't tell   the virtues of privacy by designDon't ask, don't tell   the virtues of privacy by design
Don't ask, don't tell the virtues of privacy by design
Eleanor McHugh
 
Anonymity, identity, trust
Anonymity, identity, trustAnonymity, identity, trust
Anonymity, identity, trust
Eleanor McHugh
 
Going Loopy - Adventures in Iteration with Google Go
Going Loopy - Adventures in Iteration with Google GoGoing Loopy - Adventures in Iteration with Google Go
Going Loopy - Adventures in Iteration with Google Go
Eleanor McHugh
 
Distributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at ScaleDistributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at Scale
Eleanor McHugh
 
Hello Go
Hello GoHello Go
Hello Go
Eleanor McHugh
 
Go for the paranoid network programmer, 2nd edition
Go for the paranoid network programmer, 2nd editionGo for the paranoid network programmer, 2nd edition
Go for the paranoid network programmer, 2nd edition
Eleanor McHugh
 
Finding a useful outlet for my many Adventures in go
Finding a useful outlet for my many Adventures in goFinding a useful outlet for my many Adventures in go
Finding a useful outlet for my many Adventures in go
Eleanor McHugh
 
Anonymity, trust, accountability
Anonymity, trust, accountabilityAnonymity, trust, accountability
Anonymity, trust, accountability
Eleanor McHugh
 
Implementing Virtual Machines in Ruby & C
Implementing Virtual Machines in Ruby & CImplementing Virtual Machines in Ruby & C
Implementing Virtual Machines in Ruby & C
Eleanor McHugh
 
Encrypt all transports
Encrypt all transportsEncrypt all transports
Encrypt all transports
Eleanor McHugh
 
Whispered secrets
Whispered secretsWhispered secrets
Whispered secrets
Eleanor McHugh
 
Never Say, Never Say Die! - the art of low-level Ruby and other Macabre Tales
Never Say, Never Say Die! - the art of low-level Ruby and other Macabre TalesNever Say, Never Say Die! - the art of low-level Ruby and other Macabre Tales
Never Say, Never Say Die! - the art of low-level Ruby and other Macabre Tales
Eleanor McHugh
 
[2024] An Introduction to Functional Programming with Go [Y Combinator Remix]...
[2024] An Introduction to Functional Programming with Go [Y Combinator Remix]...[2024] An Introduction to Functional Programming with Go [Y Combinator Remix]...
[2024] An Introduction to Functional Programming with Go [Y Combinator Remix]...
Eleanor McHugh
 
[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf
Eleanor McHugh
 
Generics, Reflection, and Efficient Collections
Generics, Reflection, and Efficient CollectionsGenerics, Reflection, and Efficient Collections
Generics, Reflection, and Efficient Collections
Eleanor McHugh
 
The Relevance of Liveness - Biometrics and Data Integrity
The Relevance of Liveness - Biometrics and Data IntegrityThe Relevance of Liveness - Biometrics and Data Integrity
The Relevance of Liveness - Biometrics and Data Integrity
Eleanor McHugh
 
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
Eleanor McHugh
 
An introduction to functional programming with Go [redux]
An introduction to functional programming with Go [redux]An introduction to functional programming with Go [redux]
An introduction to functional programming with Go [redux]
Eleanor McHugh
 
Identity & trust in Monitored Spaces
Identity & trust in Monitored SpacesIdentity & trust in Monitored Spaces
Identity & trust in Monitored Spaces
Eleanor McHugh
 
Don't Ask, Don't Tell - The Virtues of Privacy By Design
Don't Ask, Don't Tell - The Virtues of Privacy By DesignDon't Ask, Don't Tell - The Virtues of Privacy By Design
Don't Ask, Don't Tell - The Virtues of Privacy By Design
Eleanor McHugh
 
Don't ask, don't tell the virtues of privacy by design
Don't ask, don't tell   the virtues of privacy by designDon't ask, don't tell   the virtues of privacy by design
Don't ask, don't tell the virtues of privacy by design
Eleanor McHugh
 
Anonymity, identity, trust
Anonymity, identity, trustAnonymity, identity, trust
Anonymity, identity, trust
Eleanor McHugh
 
Going Loopy - Adventures in Iteration with Google Go
Going Loopy - Adventures in Iteration with Google GoGoing Loopy - Adventures in Iteration with Google Go
Going Loopy - Adventures in Iteration with Google Go
Eleanor McHugh
 
Distributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at ScaleDistributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at Scale
Eleanor McHugh
 
Go for the paranoid network programmer, 2nd edition
Go for the paranoid network programmer, 2nd editionGo for the paranoid network programmer, 2nd edition
Go for the paranoid network programmer, 2nd edition
Eleanor McHugh
 
Finding a useful outlet for my many Adventures in go
Finding a useful outlet for my many Adventures in goFinding a useful outlet for my many Adventures in go
Finding a useful outlet for my many Adventures in go
Eleanor McHugh
 
Anonymity, trust, accountability
Anonymity, trust, accountabilityAnonymity, trust, accountability
Anonymity, trust, accountability
Eleanor McHugh
 
Implementing Virtual Machines in Ruby & C
Implementing Virtual Machines in Ruby & CImplementing Virtual Machines in Ruby & C
Implementing Virtual Machines in Ruby & C
Eleanor McHugh
 
Encrypt all transports
Encrypt all transportsEncrypt all transports
Encrypt all transports
Eleanor McHugh
 
Ad

Recently uploaded (20)

AI 3-in-1: Agents, RAG, and Local Models - Brent Laster
AI 3-in-1: Agents, RAG, and Local Models - Brent LasterAI 3-in-1: Agents, RAG, and Local Models - Brent Laster
AI 3-in-1: Agents, RAG, and Local Models - Brent Laster
All Things Open
 
AI x Accessibility UXPA by Stew Smith and Olivier Vroom
AI x Accessibility UXPA by Stew Smith and Olivier VroomAI x Accessibility UXPA by Stew Smith and Olivier Vroom
AI x Accessibility UXPA by Stew Smith and Olivier Vroom
UXPA Boston
 
Mastering Testing in the Modern F&B Landscape
Mastering Testing in the Modern F&B LandscapeMastering Testing in the Modern F&B Landscape
Mastering Testing in the Modern F&B Landscape
marketing943205
 
Bepents tech services - a premier cybersecurity consulting firm
Bepents tech services - a premier cybersecurity consulting firmBepents tech services - a premier cybersecurity consulting firm
Bepents tech services - a premier cybersecurity consulting firm
Benard76
 
Design pattern talk by Kaya Weers - 2025 (v2)
Design pattern talk by Kaya Weers - 2025 (v2)Design pattern talk by Kaya Weers - 2025 (v2)
Design pattern talk by Kaya Weers - 2025 (v2)
Kaya Weers
 
Kit-Works Team Study_팀스터디_김한솔_nuqs_20250509.pdf
Kit-Works Team Study_팀스터디_김한솔_nuqs_20250509.pdfKit-Works Team Study_팀스터디_김한솔_nuqs_20250509.pdf
Kit-Works Team Study_팀스터디_김한솔_nuqs_20250509.pdf
Wonjun Hwang
 
Optima Cyber - Maritime Cyber Security - MSSP Services - Manolis Sfakianakis ...
Optima Cyber - Maritime Cyber Security - MSSP Services - Manolis Sfakianakis ...Optima Cyber - Maritime Cyber Security - MSSP Services - Manolis Sfakianakis ...
Optima Cyber - Maritime Cyber Security - MSSP Services - Manolis Sfakianakis ...
Mike Mingos
 
The Future of Cisco Cloud Security: Innovations and AI Integration
The Future of Cisco Cloud Security: Innovations and AI IntegrationThe Future of Cisco Cloud Security: Innovations and AI Integration
The Future of Cisco Cloud Security: Innovations and AI Integration
Re-solution Data Ltd
 
UiPath Agentic Automation: Community Developer Opportunities
UiPath Agentic Automation: Community Developer OpportunitiesUiPath Agentic Automation: Community Developer Opportunities
UiPath Agentic Automation: Community Developer Opportunities
DianaGray10
 
The Changing Compliance Landscape in 2025.pdf
The Changing Compliance Landscape in 2025.pdfThe Changing Compliance Landscape in 2025.pdf
The Changing Compliance Landscape in 2025.pdf
Precisely
 
IT484 Cyber Forensics_Information Technology
IT484 Cyber Forensics_Information TechnologyIT484 Cyber Forensics_Information Technology
IT484 Cyber Forensics_Information Technology
SHEHABALYAMANI
 
Canadian book publishing: Insights from the latest salary survey - Tech Forum...
Canadian book publishing: Insights from the latest salary survey - Tech Forum...Canadian book publishing: Insights from the latest salary survey - Tech Forum...
Canadian book publishing: Insights from the latest salary survey - Tech Forum...
BookNet Canada
 
Enterprise Integration Is Dead! Long Live AI-Driven Integration with Apache C...
Enterprise Integration Is Dead! Long Live AI-Driven Integration with Apache C...Enterprise Integration Is Dead! Long Live AI-Driven Integration with Apache C...
Enterprise Integration Is Dead! Long Live AI-Driven Integration with Apache C...
Markus Eisele
 
UiPath Automation Suite – Cas d'usage d'une NGO internationale basée à Genève
UiPath Automation Suite – Cas d'usage d'une NGO internationale basée à GenèveUiPath Automation Suite – Cas d'usage d'une NGO internationale basée à Genève
UiPath Automation Suite – Cas d'usage d'une NGO internationale basée à Genève
UiPathCommunity
 
Unlocking Generative AI in your Web Apps
Unlocking Generative AI in your Web AppsUnlocking Generative AI in your Web Apps
Unlocking Generative AI in your Web Apps
Maximiliano Firtman
 
Kit-Works Team Study_아직도 Dockefile.pdf_김성호
Kit-Works Team Study_아직도 Dockefile.pdf_김성호Kit-Works Team Study_아직도 Dockefile.pdf_김성호
Kit-Works Team Study_아직도 Dockefile.pdf_김성호
Wonjun Hwang
 
Financial Services Technology Summit 2025
Financial Services Technology Summit 2025Financial Services Technology Summit 2025
Financial Services Technology Summit 2025
Ray Bugg
 
Agentic Automation - Delhi UiPath Community Meetup
Agentic Automation - Delhi UiPath Community MeetupAgentic Automation - Delhi UiPath Community Meetup
Agentic Automation - Delhi UiPath Community Meetup
Manoj Batra (1600 + Connections)
 
AsyncAPI v3 : Streamlining Event-Driven API Design
AsyncAPI v3 : Streamlining Event-Driven API DesignAsyncAPI v3 : Streamlining Event-Driven API Design
AsyncAPI v3 : Streamlining Event-Driven API Design
leonid54
 
GDG Cloud Southlake #42: Suresh Mathew: Autonomous Resource Optimization: How...
GDG Cloud Southlake #42: Suresh Mathew: Autonomous Resource Optimization: How...GDG Cloud Southlake #42: Suresh Mathew: Autonomous Resource Optimization: How...
GDG Cloud Southlake #42: Suresh Mathew: Autonomous Resource Optimization: How...
James Anderson
 
AI 3-in-1: Agents, RAG, and Local Models - Brent Laster
AI 3-in-1: Agents, RAG, and Local Models - Brent LasterAI 3-in-1: Agents, RAG, and Local Models - Brent Laster
AI 3-in-1: Agents, RAG, and Local Models - Brent Laster
All Things Open
 
AI x Accessibility UXPA by Stew Smith and Olivier Vroom
AI x Accessibility UXPA by Stew Smith and Olivier VroomAI x Accessibility UXPA by Stew Smith and Olivier Vroom
AI x Accessibility UXPA by Stew Smith and Olivier Vroom
UXPA Boston
 
Mastering Testing in the Modern F&B Landscape
Mastering Testing in the Modern F&B LandscapeMastering Testing in the Modern F&B Landscape
Mastering Testing in the Modern F&B Landscape
marketing943205
 
Bepents tech services - a premier cybersecurity consulting firm
Bepents tech services - a premier cybersecurity consulting firmBepents tech services - a premier cybersecurity consulting firm
Bepents tech services - a premier cybersecurity consulting firm
Benard76
 
Design pattern talk by Kaya Weers - 2025 (v2)
Design pattern talk by Kaya Weers - 2025 (v2)Design pattern talk by Kaya Weers - 2025 (v2)
Design pattern talk by Kaya Weers - 2025 (v2)
Kaya Weers
 
Kit-Works Team Study_팀스터디_김한솔_nuqs_20250509.pdf
Kit-Works Team Study_팀스터디_김한솔_nuqs_20250509.pdfKit-Works Team Study_팀스터디_김한솔_nuqs_20250509.pdf
Kit-Works Team Study_팀스터디_김한솔_nuqs_20250509.pdf
Wonjun Hwang
 
Optima Cyber - Maritime Cyber Security - MSSP Services - Manolis Sfakianakis ...
Optima Cyber - Maritime Cyber Security - MSSP Services - Manolis Sfakianakis ...Optima Cyber - Maritime Cyber Security - MSSP Services - Manolis Sfakianakis ...
Optima Cyber - Maritime Cyber Security - MSSP Services - Manolis Sfakianakis ...
Mike Mingos
 
The Future of Cisco Cloud Security: Innovations and AI Integration
The Future of Cisco Cloud Security: Innovations and AI IntegrationThe Future of Cisco Cloud Security: Innovations and AI Integration
The Future of Cisco Cloud Security: Innovations and AI Integration
Re-solution Data Ltd
 
UiPath Agentic Automation: Community Developer Opportunities
UiPath Agentic Automation: Community Developer OpportunitiesUiPath Agentic Automation: Community Developer Opportunities
UiPath Agentic Automation: Community Developer Opportunities
DianaGray10
 
The Changing Compliance Landscape in 2025.pdf
The Changing Compliance Landscape in 2025.pdfThe Changing Compliance Landscape in 2025.pdf
The Changing Compliance Landscape in 2025.pdf
Precisely
 
IT484 Cyber Forensics_Information Technology
IT484 Cyber Forensics_Information TechnologyIT484 Cyber Forensics_Information Technology
IT484 Cyber Forensics_Information Technology
SHEHABALYAMANI
 
Canadian book publishing: Insights from the latest salary survey - Tech Forum...
Canadian book publishing: Insights from the latest salary survey - Tech Forum...Canadian book publishing: Insights from the latest salary survey - Tech Forum...
Canadian book publishing: Insights from the latest salary survey - Tech Forum...
BookNet Canada
 
Enterprise Integration Is Dead! Long Live AI-Driven Integration with Apache C...
Enterprise Integration Is Dead! Long Live AI-Driven Integration with Apache C...Enterprise Integration Is Dead! Long Live AI-Driven Integration with Apache C...
Enterprise Integration Is Dead! Long Live AI-Driven Integration with Apache C...
Markus Eisele
 
UiPath Automation Suite – Cas d'usage d'une NGO internationale basée à Genève
UiPath Automation Suite – Cas d'usage d'une NGO internationale basée à GenèveUiPath Automation Suite – Cas d'usage d'une NGO internationale basée à Genève
UiPath Automation Suite – Cas d'usage d'une NGO internationale basée à Genève
UiPathCommunity
 
Unlocking Generative AI in your Web Apps
Unlocking Generative AI in your Web AppsUnlocking Generative AI in your Web Apps
Unlocking Generative AI in your Web Apps
Maximiliano Firtman
 
Kit-Works Team Study_아직도 Dockefile.pdf_김성호
Kit-Works Team Study_아직도 Dockefile.pdf_김성호Kit-Works Team Study_아직도 Dockefile.pdf_김성호
Kit-Works Team Study_아직도 Dockefile.pdf_김성호
Wonjun Hwang
 
Financial Services Technology Summit 2025
Financial Services Technology Summit 2025Financial Services Technology Summit 2025
Financial Services Technology Summit 2025
Ray Bugg
 
AsyncAPI v3 : Streamlining Event-Driven API Design
AsyncAPI v3 : Streamlining Event-Driven API DesignAsyncAPI v3 : Streamlining Event-Driven API Design
AsyncAPI v3 : Streamlining Event-Driven API Design
leonid54
 
GDG Cloud Southlake #42: Suresh Mathew: Autonomous Resource Optimization: How...
GDG Cloud Southlake #42: Suresh Mathew: Autonomous Resource Optimization: How...GDG Cloud Southlake #42: Suresh Mathew: Autonomous Resource Optimization: How...
GDG Cloud Southlake #42: Suresh Mathew: Autonomous Resource Optimization: How...
James Anderson
 

Implementing virtual machines in go & c 2018 redux

  • 1. implementing virtual machines in Go & C Eleanor McHugh @feyeleanor slideshare://feyeleanor github://feyeleanor
  • 4. I made my own machine Yes, we're building steam I hate the same routine — Building Steam, Abney Park
  • 6. and as programmers we think a lot about thinking
  • 7. whilst thinking very little about machines
  • 9. when machines need us to be engineers & analysts
  • 10. so this is a talk about machine philosophy
  • 11. framed in a language we humans can understand
  • 12. let's learn to understand our Turing machines
  • 13. by building new Turing machines in their image
  • 23. c: array stack contiguous bounded depth fixed allocation #include <stdlib.h> #define STACK_MAX 100 typedef enum { STACK_OK = 0, STACK_OVERFLOW, STACK_UNDERFLOW } STACK_STATUS; typedef struct stack STACK; struct stack { int data[STACK_MAX]; int depth; }; STACK *NewStack() { STACK *s; s = malloc(sizeof(STACK)); s->depth = 0; return s; } STACK_STATUS push(STACK *s, int data) { if (s->depth < STACK_MAX) { s->data[s->depth++] = data; return STACK_OK; } return STACK_OVERFLOW; } STACK_STATUS pop(STACK *s, int *r) { if (s->depth > -1) { *r = s->data[s->depth - 1]; s->depth--; return STACK_OK; } return STACK_UNDERFLOW; } int main() { int l, r; STACK *s = NewStack(); push(s, 1); push(s, 3); printf("depth = %dn", s->depth); pop(s, &l); pop(s, &r); printf("%d + %d = %dn", l, r, l + r); printf("depth = %dn", s->depth); }
  • 24. go: slice stack contiguous bounded depth fixed allocation package main import "fmt" type stack []int func (s *stack) Push(data int) { *s = append(*s, data) } func (s *stack) Pop() (r int) { sp := len(*s) - 1 r = (*s)[sp] *s = (*s)[:sp] return } func main() { s := new(stack) s.Push(1) s.Push(3) fmt.Printf("depth = %dn", len(s)) l := s.Pop() r := s.Pop() fmt.Printf("%d + %d = %dn", l, r, l+r) fmt.Printf("depth = %dn", len(s)) }
  • 25. go: slice stack contiguous bounded depth fixed allocation package main import "fmt" type stack []int func (s stack) Pop() (int, stack) { sp := len(s) - 1 return s[sp], s[:sp] } func main() { s := make(stack, 0) s = append(s, 1, 3) fmt.Printf("depth = %dn", len(s)) var l, r int l, s = s.Pop() r, s = s.Pop() fmt.Printf("%d + %d = %dn", l, r, l+r) fmt.Printf("depth = %dn", len(s)) }
  • 27. c: cactus stack singly-linked sequential per-item allocation #include <stdio.h> #include <stdlib.h> typedef struct stack STACK; struct stack { int data; STACK *next; }; STACK *push(STACK *s, int data) { STACK *r = malloc(sizeof(STACK)); r->data = data; r->next = s; return r; } STACK *pop(STACK *s, int *r) { if (s == NULL) exit(1); *r = s->data; return s->next; } int depth(STACK *s) { int r = 0; for (STACK *t = s; t != NULL; t = t->next) { r++; } return r; } void gc(STACK **old, int items) { STACK *t; for (; items > 0 && *old != NULL; items--) { t = *old; *old = (*old)->next; free(t); } } int sum(STACK *tos) { int a = 0; for (int p = 0; tos != NULL;) { tos = pop(tos, &p); a += p; } return a; } void print_sum(STACK *s) { printf("%d items: sum = %dn", depth(s), sum(s)); } int main() { STACK *s1 = push(NULL, 7); STACK *s2 = push(push(s1, 7), 11); s1 = push(push(push(s1, 2), 9), 4); STACK *s3 = push(s1, 17); s1 = push(s1, 3); print_sum(s1); print_sum(s2); print_sum(s3); }
  • 28. go: cactus stack nil is empty grows on push automatic GC package main import "fmt" type stack struct { int *stack } func (s stack) Push(v int) (r stack) { r = stack{v,&s} return } func (s stack) Pop() (v int, r stack) { return s.int, *s.stack } func (s stack) Depth() (r int) { for t := s.stack; t != nil; t = t.stack { r++ } return } func (s *stack) PrintSum() { fmt.Printf("sum(%v): %vn", s.Depth(), s.Sum()) } func (s stack) Sum() (r int) { for t, n := s, 0; t.stack != nil; r += n { n, t = t.Pop() } return } func main() { s1 := new(stack).Push(7) s2 := s1.Push(7).Push(11) s1 = s1.Push(2).Push(9).Push(4) s3 := s1.Push(17) s1 = s1.Push(3) s1.PrintSum() s2.PrintSum() s3.PrintSum() }
  • 30. c: hash map data array associative arrays search #include <limits.h> struct map { int size; assoc_array_t **chains; }; typedef struct map map_t; map_t *map_new(int size) { map_t *m = malloc(sizeof(map_t)); m->chains = malloc(sizeof(assoc_array_t*) * size); for (int i = 0; i < size; i++) { m->chains[i] = NULL; } m->size = size; return m; } int map_chain(map_t *m, char *k) { unsigned long int b; for (int i = strlen(k) - 1; b < ULONG_MAX && i > 0; i--) { b = b << 8; b += k[i]; } return b % m->size; } char *map_get(map_t *m, char *k) { search_t *s = search_find(m->chains[map_chain(m, k)], k); if (s != NULL) { return s->value; } return NULL; } void map_set(map_t *m, char *k, char *v) { int b = map_chain(m, k); assoc_array_t *a = m->chains[b]; search_t *s = search_find(a, k); if (s->value != NULL) { s->cursor->value = strdup(v); } else { assoc_array_t *n = assoc_array_new(k, v); if (s->cursor == a) { n->next = s->cursor; m->chains[b] = n; } else if (s->cursor == NULL) { s->memo->next = n; } else { n->next = s->cursor; s->memo->next = n; } } free(s); }
  • 31. c: hash map data array search associative arrays struct search { char *term, *value; assoc_array_t *cursor, *memo; }; typedef struct search search_t; search_t *search_new(assoc_array_t *a, char *k) { search_t *s = malloc(sizeof(search_t)); s->term = k; s->value = NULL; s->cursor = a; s->memo = NULL; return s; } void search_step(search_t *s) { s->value = assoc_array_get_if(s->cursor, s->term); } int searching(search_t *s) { return s->value == NULL && s->cursor != NULL; } search_t *search_find(assoc_array_t *a, char *k) { search_t *s = search_new(a, k); for (search_step(s); searching(s); search_step(s)) { s->memo = s->cursor; s->cursor = s->cursor->next; } return s; }
  • 32. c: hash map data array search associative arrays #include <stdlib.h> #include <string.h> struct assoc_array { char *key; void *value; struct assoc_array *next; }; typedef struct assoc_array assoc_array_t; assoc_array_t *assoc_array_new(char *k, char *v) { assoc_array_t *a = malloc(sizeof(assoc_array_t)); a->key = strdup(k); a->value = strdup(v); a->next = NULL; return a; } char *assoc_array_get_if(assoc_array_t *a, char *k) { char *r = NULL; if (a != NULL && strcmp(a->key, k) == 0) { r = strdup(a->value); } return r; }
  • 33. c: hash map data array search associative arrays #include <stdio.h> #include "map.h" int main( int argc, char **argv ) { map_t *m = map_new(1024); map_set(m, "apple", "rosy"); printf("%sn", map_get(m, "apple")); map_set(m, "blueberry", "sweet"); printf("%sn", map_get(m, "blueberry")); map_set(m, "cherry", "pie"); printf("%sn", map_get(m, "cherry")); map_set(m, "cherry", "tart"); printf("%sn", map_get(m, "cherry")); printf("%sn", map_get(m, “tart")); } rosy sweet pie tart (null)
  • 34. go: hash map associative array searcher slice of arrays package main type AssocArray struct { Key string Value interface{} Next *AssocArray }; func Find(a *AssocArray, k string) (s *Search) { s = &Search{ Term: k, Cursor: a } for s.Step(); s.Searching(); s.Step() { s.Memo = s.Cursor s.Cursor = s.Cursor.Next } return } func (a *AssocArray) GetIf(k string) (r interface{}) { if a != nil && a.Key == k { r = a.Value } return } type Search struct { Term string Value interface{} Cursor, Memo *AssocArray }; func (s *Search) Step() *Search { s.Value = s.Cursor.GetIf(s.Term) return s } func (s *Search) Searching() bool { return s.Value == nil && s.Cursor != nil }
  • 35. go: hash map associative array searcher slice of arrays package main type AssocArray struct { Key string Value interface{} Next *AssocArray }; func Find(a *AssocArray, k string) (s *Search) { s = &Search{ Term: k, Cursor: a } for s.Step(); s.Searching(); s.Step() { s.Memo = s.Cursor s.Cursor = s.Cursor.Next } return } func (a *AssocArray) GetIf(k string) (r interface{}) { if a != nil && a.Key == k { r = a.Value } return } type Search struct { Term string Value interface{} Cursor, Memo *AssocArray }; func (s *Search) Step() *Search { s.Value = s.Cursor.GetIf(s.Term) return s } func (s *Search) Searching() bool { return s.Value == nil && s.Cursor != nil }
  • 36. go: hash map associative array searcher slice of arrays type Map []*AssocArray func (m Map) Chain(k string) int { var c uint for i := len(k) - 1; i > 0; i-- { c = c << 8 c += (uint)(k[i]) } return int(c) % len(m) } func (m Map) Set(k string, v interface{}) { c := m.Chain(k) a := m[c] s := Find(a, k) if s.Value != nil { s.Cursor.Value = v } else { n := &AssocArray{ Key: k, Value: v } switch { case s.Cursor == a: n.Next = s.Cursor m[c] = n case s.Cursor == nil: s.Memo.Next = n default: n.Next = s.Cursor s.Memo.Next = n } } } func (m Map) Get(k string) (r interface{}) { if s := Find(m[m.Chain(k)], k); s != nil { r = s.Value } return }
  • 37. go: hash map hashmap vs native map package main import "fmt" func main() { v := make(map[string] interface{}) v["apple"] = "rosy" v["blueberry"] = "sweet" v["cherry"] = "pie" fmt.Printf("%vn", v["apple"]) fmt.Printf("%vn", v["blueberry"]) fmt.Printf("%vn", v["cherry"]) v["cherry"] = "tart" fmt.Printf("%vn", v["cherry"]) fmt.Printf("%vn", v["tart"]) m := make(Map, 1024) m.Set("apple", "rosy") m.Set("blueberry", "sweet") m.Set("cherry", "pie") fmt.Printf("%vn", m.Get("apple")) fmt.Printf("%vn", m.Get("blueberry")) fmt.Printf("%vn", m.Get("cherry")) m.Set("cherry", "tart") fmt.Printf("%vn", m.Get("cherry")) fmt.Printf("%vn", m.Get("tart")) } rosy sweet pie tart (null) rosy sweet pie tart (null)
  • 39. go: slice heap array of pointers reflect unsafe package main import "fmt" import r "reflect" import "unsafe" type Memory []uintptr var _BYTE_SLICE = r.TypeOf([]byte(nil)) var _MEMORY = r.TypeOf(Memory{}) var _MEMORY_BYTES = int(_MEMORY.Elem().Size()) func (m Memory) newHeader() (h r.SliceHeader) { h = *(*r.SliceHeader)(unsafe.Pointer(&m)) h.Len = len(m) * _MEMORY_BYTES h.Cap = cap(m) * _MEMORY_BYTES return } func (m *Memory) Serialise() (b []byte) { h := m.newHeader() b = make([]byte, h.Len) copy(b, *(*[]byte)(unsafe.Pointer(&h))) return } func (m *Memory) Overwrite(i interface{}) { switch i := i.(type) { case Memory: copy(*m, i) case []byte: h := m.newHeader() b := *(*[]byte)(unsafe.Pointer(&h)) copy(b, i) } } func (m *Memory) Bytes() (b []byte) { h := m.newHeader() return *(*[]byte)(unsafe.Pointer(&h)) } func main() { m := make(Memory, 2) b := m.Bytes() s := m.Serialise() fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m) fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b) fmt.Println("s (bytes) =", len(s), "of", cap(s), ":", s) m.Overwrite(Memory{3, 5}) fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m) fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b) fmt.Println("s (bytes) =", len(s), "of", cap(s), ":", s) s = m.Serialise() m.Overwrite([]byte{8, 7, 6, 5, 4, 3, 2, 1}) fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m) fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b) fmt.Println("s (bytes) =", len(s), "of", cap(s), ":", s) }
  • 40. go: slice heap array of pointers reflect unsafe package main import r "reflect" import "unsafe" type Memory []uintptr var _BYTE_SLICE = r.TypeOf([]byte(nil)) var _MEMORY = r.TypeOf(Memory{}) var _MEMORY_BYTES = int(_MEMORY.Elem().Size()) func (m Memory) newHeader() (h r.SliceHeader) { h = *(*r.SliceHeader)(unsafe.Pointer(&m)) h.Len = len(m) * _MEMORY_BYTES h.Cap = cap(m) * _MEMORY_BYTES return } func (m *Memory) Serialise() (b []byte) { h := m.newHeader() b = make([]byte, h.Len) copy(b, *(*[]byte)(unsafe.Pointer(&h))) return } func (m *Memory) Overwrite(i interface{}) { switch i := i.(type) { case Memory: copy(*m, i) case []byte: h := m.newHeader() b := *(*[]byte)(unsafe.Pointer(&h)) copy(b, i) } } func (m *Memory) Bytes() (b []byte) { h := m.newHeader() return *(*[]byte)(unsafe.Pointer(&h)) } func main() { m := make(Memory, 2) b := m.Bytes() s := m.Serialise() fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m) fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b) fmt.Println("s (bytes) =", len(s), "of", cap(s), ":", s) m.Overwrite(Memory{3, 5}) fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m) fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b) fmt.Println("s (bytes) =", len(s), "of", cap(s), ":", s) s = m.Serialise() m.Overwrite([]byte{8, 7, 6, 5, 4, 3, 2, 1}) fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m) fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b) fmt.Println("s (bytes) =", len(s), "of", cap(s), ":", s) }
  • 41. go: slice heap array of pointers reflect unsafe package main import r "reflect" import "unsafe" type Memory []uintptr var _BYTE_SLICE = r.TypeOf([]byte(nil)) var _MEMORY = r.TypeOf(Memory{}) var _MEMORY_BYTES = int(_MEMORY.Elem().Size()) func (m Memory) newHeader() (h r.SliceHeader) { h = *(*r.SliceHeader)(unsafe.Pointer(&m)) h.Len = len(m) * _MEMORY_BYTES h.Cap = cap(m) * _MEMORY_BYTES return } func (m *Memory) Serialise() (b []byte) { h := m.newHeader() b = make([]byte, h.Len) copy(b, *(*[]byte)(unsafe.Pointer(&h))) return } func (m *Memory) Overwrite(i interface{}) { switch i := i.(type) { case Memory: copy(*m, i) case []byte: h := m.newHeader() b := *(*[]byte)(unsafe.Pointer(&h)) copy(b, i) } } func (m *Memory) Bytes() (b []byte) { h := m.newHeader() return *(*[]byte)(unsafe.Pointer(&h)) } func main() { m := make(Memory, 2) b := m.Bytes() s := m.Serialise() fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m) fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b) fmt.Println("s (bytes) =", len(s), "of", cap(s), ":", s) m.Overwrite(Memory{3, 5}) fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m) fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b) fmt.Println("s (bytes) =", len(s), "of", cap(s), ":", s) s = m.Serialise() m.Overwrite([]byte{8, 7, 6, 5, 4, 3, 2, 1}) fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m) fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b) fmt.Println("s (bytes) =", len(s), "of", cap(s), ":", s) }
  • 43. c: switch portable slow byte tokens #include <stdio.h> #include <stdlib.h> #include "stack.h" #define READ_OPCODE *PC++ typedef enum { PUSH = 0, ADD, PRINT, EXIT } opcodes; STACK *S; void interpret(int *PC) { int l, r; while (1) { switch(READ_OPCODE) { case PUSH: S = push(S, READ_OPCODE); break; case ADD: S = pop(S, &l); S = pop(S, &r); S = push(S, l + r); break; case PRINT: printf(“%d + %d = %dn, l, r, S->data); break; case EXIT: return; } } } int main() { int program [] = { (int)PUSH, 13, (int)PUSH, 28, (int)ADD, PRINT, EXIT, }; interpret(program); }
  • 44. c: direct call portable pointer to function multi-byte #include <stdio.h> #include <stdlib.h> #include "stack.h" #define READ_OPCODE *PC++ typedef void (*opcode)(); STACK *S; opcode *PC; void op_push() { S = push(S, (int)(long)(READ_OPCODE)); } void op_add_and_print() { int l, r; S = pop(S, &l); S = pop(S, &r); S = push(S, l + r); printf("%d + %d = %dn", l, r, S->data); } void op_exit() { exit(0); } void interpret(opcode *program) { PC = program; while (1) { (READ_OPCODE)(); } } int main() { opcode program [] = { op_push, (opcode)(long)13, op_push, (opcode)(long)28, op_add_and_print, op_exit }; interpret(program); }
  • 45. c: indirect thread gcc/clang specific local jumps indirect loading #include <stdio.h> #include <stdlib.h> #include "stack.h" typedef enum { PUSH = 0, ADD, PRINT, EXIT } opcodes; void interpret(int *program) { static void *opcodes [] = { &&op_push, &&op_add, &&op_print, &&op_exit }; int l, r; STACK *S; int *PC = program; goto *opcodes[*PC++]; op_push: S = push(S, *PC++); goto *opcodes[*PC++]; op_add: S = pop(S, &l); S = pop(S, &r); S = push(S, l + r); goto *opcodes[*PC++]; op_print: printf("%d + %d = %dn", l, r, S->data); goto *opcodes[*PC++]; op_exit: return; } int main() { int program [] = { PUSH, 13, PUSH, 28, ADD, PRINT, EXIT }; interpret(program); }
  • 46. c: indirect thread gcc/clang specific local jumps indirect loading #include <stdio.h> #include <stdlib.h> #include "stack.h" #define READ_OPCODE *PC++ #define EXECUTE_OPCODE goto *opcodes[READ_OPCODE]; #define PRIMITIVE(name, body) name: body; EXECUTE_OPCODE typedef enum { PUSH = 0, ADD, PRINT, EXIT } opcodes; STACK *S; void interpret(int *program) { static void *opcodes [] = { &&op_push, &&op_add, &&op_print, &&op_exit }; int l, r; int *PC = program; EXECUTE_OPCODE; PRIMITIVE(op_push, S = push(S, READ_OPCODE) ) PRIMITIVE(op_print, printf("%d + %d = %dn", l, r, S->data) ) PRIMITIVE(op_add, S = pop(S, &l); S = pop(S, &r); S = push(S, l + r) ) PRIMITIVE(op_exit, return ) } int main() { int program [] = { PUSH, 13, PUSH, 28, ADD, PRINT, EXIT }; interpret(program); }
  • 47. c: direct thread void **compile(int *PC, int words, void *despatch_table[]) { static void *compiler [] = { &&c_push, &&c_add, &&c_print, &&c_exit }; if (words < 1) return NULL; void **program = malloc(sizeof(void *) * words); void **cp = program; goto *compiler[*PC++]; c_number: *cp++ = (void *)(long)*PC++; words—; if (words == 0) return program; goto *compiler[*PC++]; c_push: *cp++ = despatch_table[PUSH]; *cp++ = (void *)(long)*PC++; words—; goto c_number; c_add: *cp++ = despatch_table[ADD]; words--; if (words == 0) return program; goto *compiler[*PC++]; c_print: *cp++ = despatch_table[PRINT]; words--; if (words == 0) return program; goto *compiler[*PC++]; c_exit: *cp++ = despatch_table[EXIT]; words--; if (words == 0) return program; goto *compiler[*PC++]; } void interpret(int *PC, int words) { static void *despatch_table[] = { &&op_push, &&op_add, &&op_print, &&op_exit }; int l, r; void **program = compile(PC, words, despatch_table); if (program == NULL) exit(1); goto **program++; op_push: S = push(S, (int)(long)*program++); goto **program++; op_add: S = pop(S, &l); S = pop(S, &r); S = push(S, l + r); goto **program++; op_print: printf("%d + %d = %dn", l, r, S->data); goto **program++; op_exit: return; }
  • 48. c: direct thread #include <stdio.h> #include <stdlib.h> #include "stack.h" #define COMPILE_NEXT_OPCODE goto *compiler[*PC++]; #define COMPILE_NUMBER *cp++ = (void *)(long)*PC++; words--; #define PRIMITIVE_ADDRESS(op) *cp++ = despatch_table[op]; #define COMPILE_PRIMITIVE(name, body) c_##name: PRIMITIVE_ADDRESS(name) body; words--; if (words == 0) return program; COMPILE_NEXT_OPCODE void **compile(int *PC, int words, void *despatch_table[]) { static void *compiler [] = { &&c_push, &&c_add, &&c_print, &&c_exit }; if (words < 1) return NULL; void **program = malloc(sizeof(void *) * words); void **cp = program; COMPILE_NEXT_OPCODE COMPILE_PRIMITIVE(PUSH, COMPILE_NUMBER) COMPILE_PRIMITIVE(ADD, ;) COMPILE_PRIMITIVE(PRINT, ;) COMPILE_PRIMITIVE(EXIT, ;) } #define NEXT_OPCODE goto **program++; #define PRIMITIVE(name, body) op_##name: body; NEXT_OPCODE void interpret(int *PC, int words) { static void *despatch_table[] = { &&op_push, &&op_add, &&op_print, &&op_exit }; int l, r; void **program = compile(PC, words, despatch_table); if (program == NULL) exit(1); NEXT_OPCODE PRIMITIVE(push, S = push(S, (int)(long)*program++)) PRIMITIVE(add, S = pop(S, &l); S = pop(S, &r); S = push(S, l + r); ) PRIMITIVE(print, printf("%d + %d = %dn", l, r, S->data)) PRIMITIVE(exit, return) } int main() { int program[] = { PUSH, 13, PUSH, 28, ADD, PRINT, EXIT }; interpret(program, 7); }
  • 49. go: switch constants package main import "fmt" type stack struct { int *stack } func (s *stack) Push(v int) *stack { return &stack{v, s} } func (s *stack) Pop() (int, *stack) { return s.int, s.stack } type OPCODE int const ( PUSH = OPCODE(iota) ADD PRINT EXIT ) func main() { interpret([]interface{}{ PUSH, 13, PUSH, 28, ADD, PRINT, EXIT, }) } func interpret(p []interface{}) { var l, r int S := new(stack) for PC := 0; ; PC++ { if op, ok := p[PC].(OPCODE); ok { switch op { case PUSH: PC++ S = S.Push(p[PC].(int)) case ADD: l, S = S.Pop() r, S = S.Pop() S = S.Push(l + r) case PRINT: fmt.Printf("%v + %v = %vn", l, r, S.int) case EXIT: return } } else { return } } }
  • 50. go: direct call function pointers package main import "fmt" import "os" type stack struct { int *stack } func (s *stack) Push(v int) *stack { return &stack{v, s} } func (s *stack) Pop() (int, *stack) { return s.int, s.stack } func main() { p := new(Interpreter) p.Load( p.Push, 13, p.Push, 28, p.Add, p.Print, p.Exit, ) p.Run() } type Interpreter struct { S *stack l, r, PC int m []interface{} } func (i *Interpreter) read_program() (r interface{}) { return i.m[i.PC] } func (i *Interpreter) Load(p ...interface{}) { i.m = p } func (i *Interpreter) Run() { for { i.read_program().(func())() i.PC++ } } func (i *Interpreter) Push() { i.PC++ i.S = i.S.Push(i.read_program().(int)) } func (i *Interpreter) Add() { i.l, i.S = i.S.Pop() i.r, i.S = i.S.Pop() i.S = i.S.Push(i.l + i.r) } func (i *Interpreter) Print() { fmt.Printf("%v + %v = %vn", i.l, i.r, i.S.int) } func (i *Interpreter) Exit() { os.Exit(0) }
  • 51. go: direct call function literals package main import "fmt" import "os" type stack struct { int *stack } func (s *stack) Push(v int) *stack { return &stack{v, s} } func (s *stack) Pop() (int, *stack) { return s.int, s.stack } type Primitive func(*Interpreter) type Interpreter struct { S *stack l, r, PC int m []Primitive } func (i *Interpreter) read_program() Primitive { return i.m[i.PC] } func (i *Interpreter) Run() { for { i.read_program()(i) i.PC++ } } func main() { p := &Interpreter{ m: []Primitive{ func(i *Interpreter) { i.S = i.S.Push(13) }, func(i *Interpreter) { i.S = i.S.Push(28) }, func(i *Interpreter) { i.l, i.S = i.S.Pop() i.r, i.S = i.S.Pop() i.S = i.S.Push(i.l + i.r) }, func(i *Interpreter) { fmt.Printf("%v + %v = %vn", i.l, i.r, i.S.int) }, func (i *Interpreter) { os.Exit(0) }, }, } p.Run() }
  • 52. go: direct call closures package main import "fmt" import "os" type stack struct { int *stack } func (s *stack) Push(v int) *stack { return &stack{v, s} } func (s *stack) Pop() (int, *stack) { return s.int, s.stack } type Primitive func(*Interpreter) type Interpreter struct { S *stack l, r, PC int m []Primitive } func (i *Interpreter) read_program() Primitive { return i.m[i.PC] } func (i *Interpreter) Run() { for { i.read_program() i.PC++ } } func main() { var p *Interpreter p := &Interpreter{ m: []Primitive{ func() { p.S = p.S.Push(13) }, func() { p.S = p.S.Push(28) }, func() { p.l, p.S = p.S.Pop() p.r, p.S = p.S.Pop() p.S = p.S.Push(p.l + p.r) }, func() { fmt.Printf("%v + %v = %vn", p.l, p.r, p.S.int) }, func () { os.Exit(0) }, }, } p.Run() }
  • 53. go: direct call closures compilation package main import "fmt" import "os" type stack struct { int *stack } func (s *stack) Push(v int) *stack { return &stack{v, s} } func (s *stack) Pop() (int, *stack) { return s.int, s.stack } type Primitive func() type Label string type labels []Label type VM struct { PC int m []interface{} labels } func (v *VM) Load(program ...interface{}) { v.labels = make(labels) v.PC = -1 for _, token := range program { v.assemble(token) } } func (v *VM) assemble(token interface{}) { switch t := token.(type) { case Label: if i, ok := v.labels[t]; ok { v.m = append(v.m, i) } else { v.labels[t] = v.PC } default: v.m = append(v.m, token) v.PC++ } } func (v *VM) Run() { v.PC = -1 for { v.PC++ v.read_program().(Primitive)() } } func (v *VM) read_program() interface{} { return v.m[v.PC] } type Interpreter struct { VM S *stack l, r int }
  • 54. go: direct call closures compilation func main() { p := new(Interpreter) p.Load( Label("start"), Primitive(func() { p.S = p.S.Push(13) }), Primitive(func() { p.S = p.S.Push(28) }), Primitive(func() { p.l, p.S = p.S.Pop() p.r, p.S = p.S.Pop() p.S = p.S.Push(p.l + p.r) }), Primitive(func() { fmt.Printf("%v + %v = %vn", p.l, p.r, p.S.int) }), Primitive(func() { os.Exit(0) }), Label("end"), ) p.Run() }
  • 56. go: vm harness closures compilation package main import "fmt" import "os" type stack struct { int *stack } func (s *stack) Push(v int) *stack { return &stack{v, s} } func (s *stack) Pop() (int, *stack) { return s.int, s.stack } type Primitive func() type Label string type labels map[Label]int type VM struct { PC int m []interface{} labels } func (v *VM) Load(program ...interface{}) { v.labels = make(labels) v.PC = -1 for _, token := range program { v.assemble(token) } } func (v *VM) assemble(token interface{}) { switch t := token.(type) { case Label: if i, ok := v.labels[t]; ok { v.m = append(v.m, i) } else { v.labels[t] = v.PC } default: v.m = append(v.m, token) v.PC++ } } func (v *VM) Run() { v.PC = -1 for { v.PC++ v.read_program().(Primitive)() } } func (v *VM) read_program() interface{} { return v.m[v.PC] }
  • 57. stack machine zero operands type StackMachine struct { *stack VM } func (s *StackMachine) Push() { s.PC++ s.S = s.S.Push(s.read_program().(int)) } func (s *StackMachine) Add() { s.l, s.S = s.S.Pop() s.r, s.S = s.S.Pop() s.S = s.S.Push(s.l + s.r) } func (s *StackMachine) JumpIfNotZero() { s.PC++ if s.int != 0 { s.PC = s.m[s.PC].(int) } } func main() { s := new(StackMachine) print_state := Primitive(func() { fmt.Printf("pc[%v]: %v, TOS: %vn", s.PC, s.m[s.PC], s.int, ) }) s.Load( Primitive(s.Push), 13, Label("dec"), Primitive(func() { s.stack = s.stack.Push(-1) }), Primitive(s.Add), print_state, Primitive(s.JumpIfNotZero), Label("dec"), print_state, Primitive(func() { os.Exit(0) }), ).Run() }
  • 58. the accumulator single register single operand type AccMachine struct { int VM } func (a *AccMachine) Clear() { a.int = 0 } func (a *AccMachine) LoadValue() { a.PC++ a.int = a.read_program().(int) } func (a *AccMachine) Add() { a.PC++ a.int += a.read_program().(int) } func (a *AccMachine) JumpIfNotZero() { a.PC++ if a.int != 0 { a.PC = a.m[a.PC].(int) } } func main() { a := new(AccMachine) print_state := Primitive(func() { fmt.Printf("pc[%v]: %v, Acc: %vn", a.PC, a.m[a.PC], a.int, ) }) a.Load( Primitive(a.Clear), Primitive(a.LoadValue), 13, Label("dec"), Primitive(a.Add), -1, print_state, Primitive(a.JumpIfNotZero), Label("dec"), print_state, Primitive(func() { os.Exit(0) }), ).Run() }
  • 59. register machine multi-register multi-operand type RegMachine struct { R []int VM } func (r *RegMachine) Clear() { r.R = make([]int, 2, 2) } func (r *RegMachine) read_value() int { r.PC++ return r.read_program().(int) } func (r *RegMachine) LoadValue() { r.R[r.read_value()] = r.read_value() } func (r *RegMachine) Add() { i := r.read_value() j := r.read_value() r.R[i] += r.R[j] } func (r *RegMachine) JumpIfNotZero() { if r.R[r.read_value()] != 0 { r.PC = r.read_value() } else { r.PC++ } } func main() { r := new(RegMachine) print_state := Primitive(func() { fmt.Printf("pc[%v]: %v, Acc: %vn", r.PC, r.m[r.PC], r.R, ) }) r.Load( Primitive(r.Clear), Primitive(r.LoadValue), 0, 13, Primitive(r.LoadValue), 1, -1, Label("dec"), Primitive(r.Add), 0, 1, print_state, Primitive(r.JumpIfNotZero), 0, Label("dec"), print_state, Primitive(func() { os.Exit(0) }), ).Run() }
  • 61. Go & cgo: integrating existing C code with Go Andreas Krennmair <ak@synflood.at> Golang User Group Berlin Twitter: @der_ak cgo inline c
  • 62. Feb 5, 2013 at 10:28PM Caleb DoxseyCaleb Doxsey // BlogBlog // Go & AssemblyGo & Assembly Go & AssemblyGo & Assembly Caleb Doxsey One of my favorite parts about Go is its unwavering focus on utility. Sometimes we place so much emphasis on language design that we forget all the other things programming involves. For example: Go's compiler is fast Go comes with a robust standard library Go works on a multitude of platforms Go comes with a complete set of documentation available from the command line / a local web server / the internet All Go code is statically compiled so deployment is trivial The entirety of the Go source code is available for perusal in an easy format online (like this) Go has a well defined (and documented) grammar for parsing. (unlike C++ or Ruby) Go comes with a package management tool. go get X (for example go get code.google.com/p/go.net/websocket ) assembly
  • 64. This repository Pull requests Issues Gist No description or website provided. — Edit 00 memory experiments with Fiddle::Pointer exploring use of C-style memory mana… 5 days ago 01 stacks stacks in Go 5 days ago 02 hashes roll-your-own hash maps in Go 5 days ago 03 dispatcher Go versions of dispatch loops 5 days ago 04 architecture implementations of popular VM architectural styles 5 days ago LICENSE Initial commit 5 days ago README.md added links for slides and video of talks based on this code 5 days ago Search feyeleanor / vm-fragments Code Issues 0 Pull requests 0 Projects 0 Wiki Pulse Graphs Settings 13 commits 1 branch 0 releases 1 contributor MIT Clone or downloadClone or downloadCreate new file Upload files Find filemasterBranch: New pull request Latest commit 9ee7fe0 5 days agofeyeleanor implementations of popular VM architectural styles README.md vm-fragments A collection of code fragments for talks I've given around implementing simple virtual machine internals in C, Go and Ruby. The slides for these talks are available at: 1 01Unwatch Star Fork source code
  • 66. implementing virtual machines in Go & C Eleanor McHugh @feyeleanor slideshare://feyeleanor github://feyeleanor
  翻译: