SlideShare une entreprise Scribd logo
1  sur  85
Télécharger pour lire hors ligne
implementing
software
machines
in
Go & C
Eleanor McHugh
@feyeleanor
this is a talk about VMs
system virtualisation
hardware emulation
abstract virtual machines
system virtualisation
this is a talk about VMs
system virtualisation
hardware emulation
abstract virtual machines
hardware emulation
this is a talk about VMs
system virtualisation
? hardware emulation ?
abstract virtual machines
program execution
this is a talk about VMs
system virtualisation
? hardware emulation ?
abstract virtual machines
inspired by hardware
discrete components
processors
storage
communications
software machines
timely
stateful
scriptable
memory
storing data & instructions
addressing
protection
go: heap
word-aligned
contiguous
byte-addressable
package memory
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) Bytes() (b []byte) {
h := m.newHeader()
return *(*[]byte)(unsafe.Pointer(&h))
}
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)
}
}
package memory
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) Bytes() (b []byte) {
h := m.newHeader()
return *(*[]byte)(unsafe.Pointer(&h))
}
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)
}
}
package memory
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) Bytes() (b []byte) {
h := m.newHeader()
return *(*[]byte)(unsafe.Pointer(&h))
}
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)
}
}
package main
import "fmt"
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 run 01.go
Allegra:00 memory eleanor$ ./01
m (cells) = 2 of 2 : [0 0]
b (bytes) = 16 of 16 : [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
s (bytes) = 16 of 16 : [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
m (cells) = 2 of 2 : [3 5]
b (bytes) = 16 of 16 : [3 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0]
s (bytes) = 16 of 16 : [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
m (cells) = 2 of 2 : [72623859790382856 5]
b (bytes) = 16 of 16 : [8 7 6 5 4 3 2 1 5 0 0 0 0 0 0 0]
s (bytes) = 16 of 16 : [3 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0]
c: array stack
uses fixed amount of memory
[grow | shrink]ing stack requires explicit realloc()
stack pointer is an offset into the array
#include <stdio.h>
#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 size;
};
STACK *NewStack() {
STACK *s;
s = malloc(sizeof(STACK));
s->size = 0;
return s;
}
STACK_STATUS push(STACK *s, int data) {
if (s->size < STACK_MAX) {
s->data[s->size++] = data;
return STACK_OK;
}
return STACK_OVERFLOW;
}
STACK_STATUS pop(STACK *s, int *r) {
if (s->size > 0) {
*r = s->data[s->size - 1];
s->size--;
return STACK_OK;
}
return STACK_UNDERFLOW;
}
int depth(STACK *s) {
return s->size;
}
int main() {
int l, r;
STACK *s = NewStack();
push(s, 1);
push(s, 3);
printf("depth = %dn", depth(s));
pop(s, &l);
pop(s, &r);
printf("%d + %d = %dn", l, r, l + r);
printf("depth = %dn", depth(s));
}
c: array stack
$ cc 01.c
$ ./a.out
depth = 2
3 + 1 = 4
depth = 0
go: slice stack
maps directly to [] slice types
[grow | shrink]ing stack automatic via append()
doesn’t require initialization
package main
import "fmt"
type stack_status int
const (
STACK_OK = stack_status(iota)
STACK_OVERFLOW
STACK_UNDERFLOW
)
type stack struct {
data []int
}
func (s *stack) Push(data int) {
s.data = append(s.data, data)
}
func (s *stack) Pop() (int, stack_status) {
if s == nil || len(s.data) < 1 {
return 0, STACK_UNDERFLOW
}
sp := len(s.data) - 1
r := s.data[sp]
s.data = s.data[:sp]
return r, STACK_OK
}
func (s *stack) Depth() int {
return len(s.data)
}
func main() {
s := new(stack)
s.Push(1)
s.Push(3)
fmt.Printf("depth = %dn", s.Depth())
l, _ := s.Pop()
r, _ := s.Pop()
fmt.Printf("%d + %d = %dn", l, r, l+r)
fmt.Printf("depth = %dn", s.Depth())
}
go: slice stack
$ go run 01a.go
depth = 2
3 + 1 = 4
depth = 0
package main
import "fmt"
type stack_status int
const (
STACK_OK = stack_status(iota)
STACK_OVERFLOW
STACK_UNDERFLOW
)
type stack struct {
data []int
}
func (s *stack) Push(data int) {
s.data = append(s.data, data)
}
func (s *stack) Pop() (int, stack_status) {
if s == nil || len(s.data) < 1 {
return 0, STACK_UNDERFLOW
}
sp := len(s.data) - 1
r := s.data[sp]
s.data = s.data[:sp]
return r, STACK_OK
}
func (s *stack) Depth() int {
return len(s.data)
}
func main() {
s := new(stack)
s.Push(1)
s.Push(3)
fmt.Printf("depth = %dn", s.Depth())
l, _ := s.Pop()
r, _ := s.Pop()
fmt.Printf("%d + %d = %dn", l, r, l+r)
fmt.Printf("depth = %dn", s.Depth())
}
go: slice stack
$ go run 01a.go
depth = 2
3 + 1 = 4
depth = 0
package main
import "fmt"
type stack_status int
const (
STACK_OK = stack_status(iota)
STACK_OVERFLOW
STACK_UNDERFLOW
)
type stack struct {
data []int
}
func (s *stack) Push(data int) {
s.data = append(s.data, data)
}
func (s *stack) Pop() (int, stack_status) {
if s == nil || len(s.data) < 1 {
return 0, STACK_UNDERFLOW
}
sp := len(s.data) - 1
r := s.data[sp]
s.data = s.data[:sp]
return r, STACK_OK
}
func (s *stack) Depth() int {
return len(s.data)
}
func main() {
s := new(stack)
s.Push(1)
s.Push(3)
fmt.Printf("depth = %dn", s.Depth())
l, _ := s.Pop()
r, _ := s.Pop()
fmt.Printf("%d + %d = %dn", l, r, l+r)
fmt.Printf("depth = %dn", s.Depth())
}
go: slice stack
$ go run 01a.go
depth = 2
3 + 1 = 4
depth = 0
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 (s stack) Depth() int {
return len(s)
}
func main() {
s := new(stack)
s.Push(1)
s.Push(3)
fmt.Printf("depth = %dn", s.Depth())
l := s.Pop()
r := s.Pop()
fmt.Printf("%d + %d = %dn", l, r, l+r)
fmt.Printf("depth = %dn", s.Depth())
}
go: slice stack
$ go run 01b.go
depth = 2
3 + 1 = 4
depth = 0
c: cactus stack
doesn’t require initialization
automatic stack growth on push()
potentially leaks memory on pop()
#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 main() {
int l, r;
STACK *s = push(NULL, 1);
s = push(s, 3);
printf("depth = %dn", depth(s));
STACK *t = pop(pop(s, &r), &l);
printf("%d + %d = %dn", l, r, l + r);
printf("depth pre-gc = %dn", depth(s));
gc(&s, 2);
printf("depth post-gc = %dn", depth(s));
}
c: functional cactus stack
$ cc 02.c
$ ./a.out
depth = 2
1 + 3 = 4
depth pre-gc = 2
depth post-gc = 0
#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 main() {
int l, r;
STACK *s = push(NULL, 1);
s = push(s, 3);
printf("depth = %dn", depth(s));
STACK *t = pop(pop(s, &r), &l);
printf("%d + %d = %dn", l, r, l + r);
printf("depth pre-gc = %dn", depth(s));
gc(&s, 2);
printf("depth post-gc = %dn", depth(s));
}
c: functional cactus stack
$ cc 02.c
$ ./a.out
depth = 2
1 + 3 = 4
depth pre-gc = 2
depth post-gc = 0
#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;
}
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);
}
c: cactus stack in action
$ cc 03.c
$ ./a.out
5 items: sum = 25
3 items: sum = 25
5 items: sum = 39
go: cactus stack
doesn’t need initialization
automatic stack growth on push()
garbage collection removes need for free()
package main
import "fmt"
type stack struct {
data int
tail *stack
}
func (s *stack) Push(v int) (r *stack) {
r = &stack{data: v, tail: s}
return
}
func (s *stack) Pop() (v int, r *stack) {
return s.data, s.tail
}
func (s *stack) Depth() (r int) {
for t := s; t != nil; t = t.tail {
r++
}
return
}
func main() {
var l, r int
var s *stack
s = s.Push(1).Push(3)
fmt.Printf("depth = %dn", s.Depth())
l, s = s.Pop()
r, s = s.Pop()
fmt.Printf("%d + %d = %dn", l, r, l+r)
fmt.Printf("depth = %dn", s.Depth())
}
go: functional cactus stack
$ go run 02a.go
depth = 2
3 + 1 = 4
depth = 0
package main
import "fmt"
type stack struct {
data int
tail *stack
}
func (s stack) Push(v int) (r stack) {
r = stack{data: v, tail: &s}
return
}
func (s stack) Pop() (v int, r stack) {
return s.data, *s.tail
}
func (s stack) Depth() (r int) {
for t := s.tail; t != nil; t = t.tail {
r++
}
return
}
func main() {
var l, r int
var s stack
s = s.Push(1).Push(3)
fmt.Printf("depth = %dn", s.Depth())
l, s = s.Pop()
r, s = s.Pop()
fmt.Printf("%d + %d = %dn", l, r, l+r)
fmt.Printf("depth = %dn", s.Depth())
}
go: functional cactus stack
$ go run 02b.go
depth = 2
3 + 1 = 4
depth = 0
package main
import "fmt"
type stack struct {
data int
tail *stack
}
func (s stack) Push(v int) (r stack) {
r = stack{data: v, tail: &s}
return
}
func (s stack) Pop() (v int, r stack) {
return s.data, *s.tail
}
func (s stack) Depth() (r int) {
for t := s.tail; t != nil; t = t.tail {
r++
}
return
}
func (s *stack) append(n int) {
t := s
for ; t.tail != nil; t = t.tail {}
*t = stack{data: n, tail: new(stack)}
}
func main() {
var l, r int
var s stack
s = s.Push(1).Push(3)
fmt.Printf("depth = %dn", s.Depth())
s.append(20)
fmt.Printf("depth = %dn", s.Depth())
l, s = s.Pop()
r, s = s.Pop()
fmt.Printf("%d + %d = %dn", l, r, l+r)
l, s = s.Pop()
fmt.Printf("l = %dn", l)
fmt.Printf("depth = %dn", s.Depth())
s.append(5)
l, s = s.Pop()
fmt.Printf("l = %dn", l)
fmt.Printf("depth = %dn", s.Depth())
}
go: functional cactus stack
$ go run 02c.go
depth = 2
depth = 3
3 + 1 = 4
l = 20
depth = 0
l = 5
depth = 0
package main
import "fmt"
type stack struct {
data int
tail *stack
}
func (s *stack) Push(v int) (r *stack) {
r = &stack{data: v, tail: s}
return
}
func (s *stack) Pop() (v int, r *stack) {
return s.data, s.tail
}
func (s stack) Depth() (r int) {
for t := s.tail; t != nil; t = t.tail {
r++
}
return
}
func (s stack) Sum() (r int) {
for t := &s; t.tail != nil; t = t.tail {
r += t.data
}
return
}
func (s *stack) PrintSum() {
fmt.Printf("%d items: sum = %dn", s.Depth(),
s.Sum())
}
func main() {
s1 := 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()
}
go: cactus stack in action
$ go run 03a.go
5 items: sum = 25
3 items: sum = 25
5 items: sum = 39
package main
import "fmt"
type stack struct {
data int
tail *stack
}
func (s *stack) Push(v int) (r *stack) {
r = &stack{data: v, tail: s}
return
}
func (s *stack) Pop() (v int, r *stack) {
return s.data, s.tail
}
func (s stack) Depth() (r int) {
for t := s.tail; t != nil; t = t.tail {
r++
}
return
}
func (s stack) Sum() (r int) {
for t, n := s, 0; t.tail != nil; r += n {
n, t = t.Pop()
}
return
}
func (s *stack) PrintSum() {
fmt.Printf("%d items: sum = %dn", s.Depth(),
s.Sum())
}
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()
}
go: cactus stack in action
$ go run 03b.go
5 items: sum = 25
3 items: sum = 25
5 items: sum = 39
c: map
#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: map
$ cc 04.c
$ ./a.out
rosy
sweet
pie
tart
(null)
#include <stdlib.h>
#include "assoc_array.c"
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: map
$ cc 04.c
$ ./a.out
rosy
sweet
pie
tart
(null)
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include "search.c"
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);
}
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"));
return 0;
}
c: map
$ cc 04.c
$ ./a.out
rosy
sweet
pie
tart
(null)
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;
}
c: map
$ cc 04.c
$ ./a.out
rosy
sweet
pie
tart
(null)
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;
}
c: map
$ cc 04.c
$ ./a.out
rosy
sweet
pie
tart
(null)
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;
}
c: map
$ cc 04.c
$ ./a.out
rosy
sweet
pie
tart
(null)
go: map
package assoc_array
type AssocArray struct {
Key string
Value interface{}
Next *AssocArray
};
func (a *AssocArray) GetIf(k string) (r interface{}) {
if a != nil && a.Key == k {
r = a.Value
}
return
}
go: map
$ cc 04.c
$ ./a.out
rosy
sweet
pie
tart
(null)
package search
import . "assoc_array"
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
}
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
}
go: map
$ cc 04.c
$ ./a.out
rosy
sweet
pie
tart
(null)
package main
import "fmt"
import . "assoc_array"
import "search"
type Map []*AssocArray
func (m Map) Set(k string, v interface{}) {
c := m.Chain(k)
a := m[c]
s := search.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) 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) Get(k string) (r interface{}) {
if s := search.Find(m[m.Chain(k)], k); s != nil {
r = s.Value
}
return
}
func main() {
m := make(Map, 1024)
m.Set("apple", "rosy")
fmt.Printf("%vn", m.Get("apple"))
m.Set("blueberry", "sweet")
fmt.Printf("%vn", m.Get("blueberry"))
m.Set("cherry", "pie")
fmt.Printf("%vn", m.Get("cherry"))
m.Set("cherry", "tart")
fmt.Printf("%vn", m.Get("cherry"))
fmt.Printf("%vn", m.Get("tart"))
}
go: map
$ go run 04.go
rosy
sweet
pie
tart
<nil>
package main
import "fmt"
func main() {
m := make(map[string] interface{})
m["apple"] = "rosy"
fmt.Printf("%vn", m["apple"])
m["blueberry"] = "sweet"
fmt.Printf("%vn", m["blueberry"])
m["cherry"] = "pie"
fmt.Printf("%vn", m["cherry"])
m["cherry"] = "tart"
fmt.Printf("%vn", m["cherry"])
fmt.Printf("%vn", m["tart"])
}
go: map
$ go run 05.go
rosy
sweet
pie
tart
<nil>
dispatch loops
fetch
decode
execute
dispatch loops
read next instruction via a program counter
determine the operation to perform
execute the operation and adjust machine state
switch interpreter
instructions stored sequentially in memory
each represented by a token or opcode
available in all implementation languages
tokens can be compact - often single bytes
#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;
}
typedef enum { PUSH = 0, ADD, PRINT, EXIT } opcodes;
STACK *S;
void interpret(int *PC) {
int l, r;
while (1) {
switch(*PC++) {
case PUSH:
S = push(S, *PC++);
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: switch interpreter
#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;
}
typedef enum { PUSH = 0, ADD, PRINT, EXIT } opcodes;
STACK *S;
#define READ_OPCODE *PC++
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: switch interpreter
package main
import "fmt"
func main() {
var program = []interface{}{
PUSH, 13,
PUSH, 28,
ADD,
PRINT,
EXIT,
}
interpret(program)
}
type stack struct {
data int
tail *stack
}
func (s *stack) Push(v int) (r *stack) {
r = &stack{data: v, tail: s}
return
}
func (s *stack) Pop() (v int, r *stack) {
return s.data, s.tail
}
type OPCODE int
const (
PUSH = OPCODE(iota)
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.data)
case EXIT:
return
}
} else {
return
}
}
}
go: switch interpreter
direct call threading
instructions stored sequentially in memory
each represented by a pointer to a function
not available in all languages
instructions each require a machine word
#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;
}
typedef void (*opcode)();
STACK *S;
opcode *PC;
void op_push() {
S = push(S, (int)(long)(*PC++));
}
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);
}
int main() {
opcode program [] = {
op_push, (opcode)(long)13,
op_push, (opcode)(long)28,
op_add_and_print,
op_exit
};
PC = program;
while (1) {
(*PC++)();
}
}
c: direct call-threaded interpreter
#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;
}
typedef void (*opcode)();
STACK *S;
opcode *PC;
#define READ_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);
}
int main() {
opcode program [] = {
op_push, (opcode)(long)13,
op_push, (opcode)(long)28,
op_add_and_print,
op_exit
};
PC = program;
while (1) {
(READ_OPCODE)();
}
}
c: direct call-threaded interpreter
package main
import "fmt"
import "os"
func main() {
p := new(Interpreter)
p.m = []interface{}{
p.Push, 13,
p.Push, 28,
p.Add,
p.Print,
p.Exit,
}
p.Run()
}
type stack struct {
data int
tail *stack
}
func (s *stack) Push(v int) (r *stack) {
r = &stack{data: v, tail: s}
return
}
func (s *stack) Pop() (v int, r *stack) {
return s.data, s.tail
}
type Interpreter struct {
S *stack
l, r, PC int
m []interface{}
}
func (i *Interpreter) opcode() func() {
return i.m[i.PC].(func())
}
func (i *Interpreter) operand() int {
return i.m[i.PC].(int)
}
func (i *Interpreter) Run() {
for {
i.opcode()()
i.PC++
}
}
func (i *Interpreter) Push() {
i.PC++
i.S = i.S.Push(i.operand())
}
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.data)
}
func (i *Interpreter) Exit() {
os.Exit(0)
}
go: direct call-threaded interpreter
indirect threading
instructions stored sequentially in memory
each represented by a local jump label
gcc/clang specific C extension
instructions indirectly load successor
#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;
}
typedef enum { PUSH = 0, ADD, 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;
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,
EXIT
};
interpret(program);
}
c: indirect-threaded interpreter
#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;
}
typedef enum { PUSH = 0, ADD, PRINT, EXIT } opcodes;
STACK *S;
#define READ_OPCODE *PC++
#define EXECUTE_OPCODE goto *opcodes[READ_OPCODE];
#define PRIMITIVE(name, body) 
name: 
body; 
EXECUTE_OPCODE
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_add, 
S = pop(S, &l); 
S = pop(S, &r); 
S = push(S, l + r); 
)
PRIMITIVE(op_print, printf("%d + %d = %dn", l, r, S->data))
PRIMITIVE(op_exit, return)
}
int main() {
int program [] = {
PUSH, 13,
PUSH, 28,
ADD,
PRINT,
EXIT
};
interpret(program);
}
c: indirect-threaded interpreter
direct threading
instructions stored sequentially in memory
each represented by a local jump label
gcc/clang specific C extension
instructions directly load successors
#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;
}
typedef enum { PUSH = 0, ADD, PRINT, EXIT } opcodes;
STACK *S;
void **compile(int *PC, int words, void *despatch_table[]) {
static void *compiler [] = {
&&comp_push,
&&comp_add,
&&comp_print,
&&comp_exit
};
if (words < 1)
return NULL;
void **program = malloc(sizeof(void *) * words);
void **cp = program;
goto *compiler[*PC++];
comp_push:
*cp++ = despatch_table[PUSH];
*cp++ = (void *)(long)*PC++;
words -= 2;
if (words == 0) return program;
goto *compiler[*PC++];
comp_add:
*cp++ = despatch_table[ADD];
words--;
if (words == 0) return program;
goto *compiler[*PC++];
comp_print:
*cp++ = despatch_table[PRINT];
words--;
if (words == 0) return program;
goto *compiler[*PC++];
comp_exit:
*cp++ = despatch_table[EXIT];
words--;
if (words == 0) return program;
goto *compiler[*PC++];
}
c: direct-threaded interpreter (1)
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;
}
int main() {
int program[] = {
PUSH, 13,
PUSH, 28,
ADD,
PRINT,
EXIT
};
interpret(program, 7);
}
c: direct-threaded interpreter (2)
#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;
}
typedef enum { PUSH = 0, ADD, PRINT, EXIT } opcodes;
STACK *S;
#define COMPILE(body) 
COMPILE_NEXT_OPCODE 
body
#define COMPILE_NEXT_OPCODE 
if (words < 1) 
return program; 
goto *compiler[*PC++];
#define DESCRIBE_PRIMITIVE(name, body) 
name: 
body; 
COMPILE_NEXT_OPCODE
#define WRITE_OPCODE(value) 
*cp++ = value; 
words--;
void **compile(int *PC, int words, void *despatch_table[]) {
static void *compiler[] = {
&&push,
&&add,
&&print,
&&exit
};
void **program = malloc(sizeof(void *) * words);
void **cp = program;
COMPILE( 
DESCRIBE_PRIMITIVE(push, 
WRITE_OPCODE(despatch_table[PUSH]) 
WRITE_OPCODE((void *)(long)*PC++)) 
DESCRIBE_PRIMITIVE(add, 
WRITE_OPCODE(despatch_table[ADD])) 
DESCRIBE_PRIMITIVE(print, 
WRITE_OPCODE(despatch_table[PRINT])) 
DESCRIBE_PRIMITIVE(exit, 
WRITE_OPCODE(despatch_table[EXIT])) 
)
}
c: direct-threaded interpreter (1)
#define READ_OPCODE *program++
#define EXECUTE_OPCODE goto *READ_OPCODE;
#define PRIMITIVE(name, body) 
name: 
body; 
EXECUTE_OPCODE
void interpret(int *PC, int words) {
static void *despatch_table[] = {
&&push,
&&add,
&&print,
&&exit
};
int l, r;
void **program = compile(PC, words, despatch_table);
if (program == NULL)
exit(1);
EXECUTE( 
PRIMITIVE(push, S = push(S, (int)(long)READ_OPCODE)) 
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);
}
c: direct-threaded interpreter (2)
timing
clock pulse
synchronisation
package clock
import "syscall"
type Clock struct {
Period int64
Count chan int64
Control chan bool
active bool
}
func (c *Clock) Start() {
if !c.active {
go func() {
c.active = true
for i := int64(0); ; i++ {
select {
case status := <- c.Control:
c.active = status
default:
if c.active {
c.Count <- i
}
syscall.Sleep(c.Period)
}
}
}()
}
}
package main
import . “clock”
func main() {
c := Clock{1000, make(chan int64), make(chan bool),
false}
c.Start()
for i := 0; i < 3; i++ {
println("pulse value", <-c.Count, "from clock")
}
println("disabling clock")
c.Control <- false
syscall.Sleep(1000000)
println("restarting clock")
c.Control <- true
println("pulse value", <-c.Count, "from clock")
}
produces:
pulse value 0 from clock
pulse value 1 from clock
pulse value 2 from clock
disabling clock
restarting clock
pulse value 106 from clock
instructions
operations
operands
execution
package instructions
type Op func(o []int)
type Executable interface {
Opcode() int
Operands() []int
Execute(Op)
}
const INVALID_OPCODE = -1
type Instr []int
func (i Instr) Opcode() int {
if len(i) == 0 {
return INVALID_OPCODE
}
return i[0]
}
func (i Instr) Operands() (r []int) {
if len(i) > 1 {
r = i[1:]
}
return
}
func (i Instr) Execute(op Operation) {
op(i.Operands())
}
package assembler
import "fmt"
import . "instructions"
type Asm struct {
opcodes map[string] int
names map[int] string
}
func NewAsm(names... string) (a Asm) {
a = Asm{
make(map[string] int),
make(map[int] string),
}
a.Define(names...)
return
}
func (a Asm) Asm(n string, p... int) (i Instr) {
if opcode, ok := a.opcodes[name]; ok {
i = make(Instruction, len(params) + 1)
i[0] = opcode
copy(i[1:], params)
}
return
}
func (a Asm) Define(n... string) {
for _, name := range names {
a.opcodes[name] = len(a.names)
a.names[len(a.names)] = name
}
}
func (a Asm) Disasm(e Executable) (s string) {
if name, ok := a.names[e.Opcode()]; ok {
s = name
if params := e.Operands(); len(params) > 0 {
s = fmt.Sprintf("%vt%v", s, params[0])
for _, v := range params[1:] {
s = fmt.Sprintf("%v, %v", s, v)
}
}
} else {
s = "INVALID"
}
return
}
package main
import "fmt"
import "assembler"
type Program []Executable
func (p Program) Rip(a Asm) {
for _, v := range p {
fmt.Println(a.Rip(v))
}
}
func main() {
a := NewAsm("noop", "load", "store")
p := Program{
a.Asm("noop"),
a.Asm("load", 1),
a.Asm("store", 1, 2),
a.Asm("invalid", 3, 4, 5),
}
p.Disasm(a)
for _, v := range p {
if len(v.Operands()) == 2 {
v.Execute(func(o []int) {
o[0] += o[1]
})
println("op =“,
v.Opcode(),
"result =“,
v.Operands()[0],
)
}
}
}
produces:
noop
load 1
store 1, 2
unknown
op = 2 result = 3
CISC
semantically rich instructions
complex memory addressing modes
compact binary code
RISC
separate IO and data processing
register-to-register instructions
load/store memory access
VLIW
multiple operations per instruction
compiler statically determines parallelism
simplifies control logic
processor core
sends & receives signals on external buses
maintains internal computation state
executes sequences of instructions
accumulator machine
1-operand instructions
data from memory combined with accumulator
result stored in accumulator
stack machine
0-operand instructions
data popped from stack
results pushed on stack
register machine
multi-operand instructions
data read from memory into registers
operator combines memory and store ops
transport triggering
register machine architecture
exposes internal buses as components
operations are side-effects of internal writes
vector machine
multi-operand instruction
data vectors read from memory into registers
operator combines registers and store ops
superscalar
multiple execution units
processor caching
out-of-order execution
Implementing Software Machines in C and Go

Contenu connexe

Tendances

Implementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxImplementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxEleanor McHugh
 
The Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's PerspectiveThe Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's PerspectiveEleanor McHugh
 
All I know about rsc.io/c2go
All I know about rsc.io/c2goAll I know about rsc.io/c2go
All I know about rsc.io/c2goMoriyoshi Koizumi
 
Allison Kaptur: Bytes in the Machine: Inside the CPython interpreter, PyGotha...
Allison Kaptur: Bytes in the Machine: Inside the CPython interpreter, PyGotha...Allison Kaptur: Bytes in the Machine: Inside the CPython interpreter, PyGotha...
Allison Kaptur: Bytes in the Machine: Inside the CPython interpreter, PyGotha...akaptur
 
Diving into byte code optimization in python
Diving into byte code optimization in python Diving into byte code optimization in python
Diving into byte code optimization in python Chetan Giridhar
 
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPythonByterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPythonakaptur
 
Bytes in the Machine: Inside the CPython interpreter
Bytes in the Machine: Inside the CPython interpreterBytes in the Machine: Inside the CPython interpreter
Bytes in the Machine: Inside the CPython interpreterakaptur
 
Python opcodes
Python opcodesPython opcodes
Python opcodesalexgolec
 
.NET 2015: Будущее рядом
.NET 2015: Будущее рядом.NET 2015: Будущее рядом
.NET 2015: Будущее рядомAndrey Akinshin
 
Что нам готовит грядущий C#7?
Что нам готовит грядущий C#7?Что нам готовит грядущий C#7?
Что нам готовит грядущий C#7?Andrey Akinshin
 
"A 1,500 line (!!) switch statement powers your Python!" - Allison Kaptur, !!...
"A 1,500 line (!!) switch statement powers your Python!" - Allison Kaptur, !!..."A 1,500 line (!!) switch statement powers your Python!" - Allison Kaptur, !!...
"A 1,500 line (!!) switch statement powers your Python!" - Allison Kaptur, !!...akaptur
 
Assignment no39
Assignment no39Assignment no39
Assignment no39Jay Patel
 
C++ Lambda and concurrency
C++ Lambda and concurrencyC++ Lambda and concurrency
C++ Lambda and concurrency명신 김
 
Python postgre sql a wonderful wedding
Python postgre sql   a wonderful weddingPython postgre sql   a wonderful wedding
Python postgre sql a wonderful weddingStéphane Wirtel
 
Kotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functionsKotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functionsFranco Lombardo
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my dayTor Ivry
 
Are we ready to Go?
Are we ready to Go?Are we ready to Go?
Are we ready to Go?Adam Dudczak
 
"PostgreSQL and Python" Lightning Talk @EuroPython2014
"PostgreSQL and Python" Lightning Talk @EuroPython2014"PostgreSQL and Python" Lightning Talk @EuroPython2014
"PostgreSQL and Python" Lightning Talk @EuroPython2014Henning Jacobs
 
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 GoEleanor McHugh
 

Tendances (20)

Implementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxImplementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 redux
 
The Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's PerspectiveThe Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's Perspective
 
All I know about rsc.io/c2go
All I know about rsc.io/c2goAll I know about rsc.io/c2go
All I know about rsc.io/c2go
 
Allison Kaptur: Bytes in the Machine: Inside the CPython interpreter, PyGotha...
Allison Kaptur: Bytes in the Machine: Inside the CPython interpreter, PyGotha...Allison Kaptur: Bytes in the Machine: Inside the CPython interpreter, PyGotha...
Allison Kaptur: Bytes in the Machine: Inside the CPython interpreter, PyGotha...
 
Diving into byte code optimization in python
Diving into byte code optimization in python Diving into byte code optimization in python
Diving into byte code optimization in python
 
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPythonByterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
 
Bytes in the Machine: Inside the CPython interpreter
Bytes in the Machine: Inside the CPython interpreterBytes in the Machine: Inside the CPython interpreter
Bytes in the Machine: Inside the CPython interpreter
 
Python opcodes
Python opcodesPython opcodes
Python opcodes
 
.NET 2015: Будущее рядом
.NET 2015: Будущее рядом.NET 2015: Будущее рядом
.NET 2015: Будущее рядом
 
Что нам готовит грядущий C#7?
Что нам готовит грядущий C#7?Что нам готовит грядущий C#7?
Что нам готовит грядущий C#7?
 
"A 1,500 line (!!) switch statement powers your Python!" - Allison Kaptur, !!...
"A 1,500 line (!!) switch statement powers your Python!" - Allison Kaptur, !!..."A 1,500 line (!!) switch statement powers your Python!" - Allison Kaptur, !!...
"A 1,500 line (!!) switch statement powers your Python!" - Allison Kaptur, !!...
 
Assignment no39
Assignment no39Assignment no39
Assignment no39
 
Let's golang
Let's golangLet's golang
Let's golang
 
C++ Lambda and concurrency
C++ Lambda and concurrencyC++ Lambda and concurrency
C++ Lambda and concurrency
 
Python postgre sql a wonderful wedding
Python postgre sql   a wonderful weddingPython postgre sql   a wonderful wedding
Python postgre sql a wonderful wedding
 
Kotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functionsKotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functions
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my day
 
Are we ready to Go?
Are we ready to Go?Are we ready to Go?
Are we ready to Go?
 
"PostgreSQL and Python" Lightning Talk @EuroPython2014
"PostgreSQL and Python" Lightning Talk @EuroPython2014"PostgreSQL and Python" Lightning Talk @EuroPython2014
"PostgreSQL and Python" Lightning Talk @EuroPython2014
 
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
 

En vedette

RSPH - Transcipt
RSPH - TransciptRSPH - Transcipt
RSPH - TransciptKate Nelson
 
Solving the TEF through Student Centricity
Solving the TEF through Student Centricity Solving the TEF through Student Centricity
Solving the TEF through Student Centricity Hobsons
 
Активно Граѓанско Учество
Активно Граѓанско УчествоАктивно Граѓанско Учество
Активно Граѓанско УчествоMetamorphosis
 
Все работы хороши, а библиотекарь лучше!
Все работы хороши, а библиотекарь лучше!Все работы хороши, а библиотекарь лучше!
Все работы хороши, а библиотекарь лучше!Lyuba Krasnikova
 
Comment construire un plan de continuité d'activité ?
Comment construire un plan de continuité d'activité ?Comment construire un plan de continuité d'activité ?
Comment construire un plan de continuité d'activité ?BRIVA
 
集合知プログラミング勉強会 第五章 最適化
集合知プログラミング勉強会 第五章 最適化集合知プログラミング勉強会 第五章 最適化
集合知プログラミング勉強会 第五章 最適化Ikuo Degawa
 
20150303続パタ5章後半
20150303続パタ5章後半20150303続パタ5章後半
20150303続パタ5章後半tetsuro ito
 
中の人が語る seekR.jp の裏側
中の人が語る seekR.jp の裏側中の人が語る seekR.jp の裏側
中の人が語る seekR.jp の裏側Takekatsu Hiramura
 
Distributed systems in practice, in theory
Distributed systems in practice, in theoryDistributed systems in practice, in theory
Distributed systems in practice, in theoryAysylu Greenberg
 
CFD ANALYSIS OF GAS METAL ARC WELDING1
CFD ANALYSIS OF GAS METAL ARC WELDING1CFD ANALYSIS OF GAS METAL ARC WELDING1
CFD ANALYSIS OF GAS METAL ARC WELDING1Pratik Joshi
 

En vedette (14)

Unycloud
UnycloudUnycloud
Unycloud
 
RSPH - Transcipt
RSPH - TransciptRSPH - Transcipt
RSPH - Transcipt
 
Solving the TEF through Student Centricity
Solving the TEF through Student Centricity Solving the TEF through Student Centricity
Solving the TEF through Student Centricity
 
Активно Граѓанско Учество
Активно Граѓанско УчествоАктивно Граѓанско Учество
Активно Граѓанско Учество
 
Все работы хороши, а библиотекарь лучше!
Все работы хороши, а библиотекарь лучше!Все работы хороши, а библиотекарь лучше!
Все работы хороши, а библиотекарь лучше!
 
Comment construire un plan de continuité d'activité ?
Comment construire un plan de continuité d'activité ?Comment construire un plan de continuité d'activité ?
Comment construire un plan de continuité d'activité ?
 
集合知プログラミング勉強会 第五章 最適化
集合知プログラミング勉強会 第五章 最適化集合知プログラミング勉強会 第五章 最適化
集合知プログラミング勉強会 第五章 最適化
 
Estrategias de lectura
Estrategias de lecturaEstrategias de lectura
Estrategias de lectura
 
20150303続パタ5章後半
20150303続パタ5章後半20150303続パタ5章後半
20150303続パタ5章後半
 
Gaurav Kumar - MBA Degree Certificate in English Language
Gaurav Kumar - MBA Degree Certificate in English LanguageGaurav Kumar - MBA Degree Certificate in English Language
Gaurav Kumar - MBA Degree Certificate in English Language
 
中の人が語る seekR.jp の裏側
中の人が語る seekR.jp の裏側中の人が語る seekR.jp の裏側
中の人が語る seekR.jp の裏側
 
Distributed systems in practice, in theory
Distributed systems in practice, in theoryDistributed systems in practice, in theory
Distributed systems in practice, in theory
 
エクセル統計の使い方(記述統計量編)
エクセル統計の使い方(記述統計量編)エクセル統計の使い方(記述統計量編)
エクセル統計の使い方(記述統計量編)
 
CFD ANALYSIS OF GAS METAL ARC WELDING1
CFD ANALYSIS OF GAS METAL ARC WELDING1CFD ANALYSIS OF GAS METAL ARC WELDING1
CFD ANALYSIS OF GAS METAL ARC WELDING1
 

Similaire à Implementing Software Machines in C and Go

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 GoogleEleanor McHugh
 
Imugi: Compiler made with Python
Imugi: Compiler made with PythonImugi: Compiler made with Python
Imugi: Compiler made with PythonHan Lee
 
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.pdfrushabhshah600
 
Swift 함수 커링 사용하기
Swift 함수 커링 사용하기Swift 함수 커링 사용하기
Swift 함수 커링 사용하기진성 오
 
Python basic
Python basic Python basic
Python basic sewoo lee
 
Haskellで学ぶ関数型言語
Haskellで学ぶ関数型言語Haskellで学ぶ関数型言語
Haskellで学ぶ関数型言語ikdysfm
 
Postgresql 9.3 overview
Postgresql 9.3 overviewPostgresql 9.3 overview
Postgresql 9.3 overviewAveic
 
Dynamic memory allocation
Dynamic memory allocationDynamic memory allocation
Dynamic memory allocationNaveen Gupta
 
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.docxDIPESH30
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
 
booksoncprogramminglanguage-anintroductiontobeginnersbyarunumrao4-21101016591...
booksoncprogramminglanguage-anintroductiontobeginnersbyarunumrao4-21101016591...booksoncprogramminglanguage-anintroductiontobeginnersbyarunumrao4-21101016591...
booksoncprogramminglanguage-anintroductiontobeginnersbyarunumrao4-21101016591...GkhanGirgin3
 
Notes for C Programming for MCA, BCA, B. Tech CSE, ECE and MSC (CS) 4 of 5 by...
Notes for C Programming for MCA, BCA, B. Tech CSE, ECE and MSC (CS) 4 of 5 by...Notes for C Programming for MCA, BCA, B. Tech CSE, ECE and MSC (CS) 4 of 5 by...
Notes for C Programming for MCA, BCA, B. Tech CSE, ECE and MSC (CS) 4 of 5 by...ssuserd6b1fd
 

Similaire à Implementing Software Machines in C and Go (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
 
Imugi: Compiler made with Python
Imugi: Compiler made with PythonImugi: Compiler made with Python
Imugi: Compiler made with Python
 
Scala 2 + 2 > 4
Scala 2 + 2 > 4Scala 2 + 2 > 4
Scala 2 + 2 > 4
 
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
 
Oh Composable World!
Oh Composable World!Oh Composable World!
Oh Composable World!
 
Introduction to Go for Java Programmers
Introduction to Go for Java ProgrammersIntroduction to Go for Java Programmers
Introduction to Go for Java Programmers
 
Swift 함수 커링 사용하기
Swift 함수 커링 사용하기Swift 함수 커링 사용하기
Swift 함수 커링 사용하기
 
Java VS Python
Java VS PythonJava VS Python
Java VS Python
 
VTU Data Structures Lab Manual
VTU Data Structures Lab ManualVTU Data Structures Lab Manual
VTU Data Structures Lab Manual
 
Python basic
Python basic Python basic
Python basic
 
SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
 
Haskellで学ぶ関数型言語
Haskellで学ぶ関数型言語Haskellで学ぶ関数型言語
Haskellで学ぶ関数型言語
 
c programming
c programmingc programming
c programming
 
Blocks+gcd入門
Blocks+gcd入門Blocks+gcd入門
Blocks+gcd入門
 
Postgresql 9.3 overview
Postgresql 9.3 overviewPostgresql 9.3 overview
Postgresql 9.3 overview
 
Dynamic memory allocation
Dynamic memory allocationDynamic memory allocation
Dynamic memory allocation
 
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
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
booksoncprogramminglanguage-anintroductiontobeginnersbyarunumrao4-21101016591...
booksoncprogramminglanguage-anintroductiontobeginnersbyarunumrao4-21101016591...booksoncprogramminglanguage-anintroductiontobeginnersbyarunumrao4-21101016591...
booksoncprogramminglanguage-anintroductiontobeginnersbyarunumrao4-21101016591...
 
Notes for C Programming for MCA, BCA, B. Tech CSE, ECE and MSC (CS) 4 of 5 by...
Notes for C Programming for MCA, BCA, B. Tech CSE, ECE and MSC (CS) 4 of 5 by...Notes for C Programming for MCA, BCA, B. Tech CSE, ECE and MSC (CS) 4 of 5 by...
Notes for C Programming for MCA, BCA, B. Tech CSE, ECE and MSC (CS) 4 of 5 by...
 

Plus de 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.pdfEleanor McHugh
 
Generics, Reflection, and Efficient Collections
Generics, Reflection, and Efficient CollectionsGenerics, Reflection, and Efficient Collections
Generics, Reflection, and Efficient CollectionsEleanor 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 IntegrityEleanor 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
 
Go for the paranoid network programmer, 3rd edition
Go for the paranoid network programmer, 3rd editionGo for the paranoid network programmer, 3rd edition
Go for the paranoid network programmer, 3rd editionEleanor 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
 
An introduction to functional programming with go
An introduction to functional programming with goAn introduction to functional programming with go
An introduction to functional programming with goEleanor McHugh
 
Identity & trust in Monitored Spaces
Identity & trust in Monitored SpacesIdentity & trust in Monitored Spaces
Identity & trust in Monitored SpacesEleanor 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 DesignEleanor 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 designEleanor McHugh
 
Anonymity, identity, trust
Anonymity, identity, trustAnonymity, identity, trust
Anonymity, identity, trustEleanor 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 GoEleanor McHugh
 
Distributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at ScaleDistributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at ScaleEleanor 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 editionEleanor 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 goEleanor McHugh
 
Anonymity, trust, accountability
Anonymity, trust, accountabilityAnonymity, trust, accountability
Anonymity, trust, accountabilityEleanor McHugh
 
Implementing Virtual Machines in Go & C
Implementing Virtual Machines in Go & CImplementing Virtual Machines in Go & C
Implementing Virtual Machines in Go & CEleanor McHugh
 
Implementing Virtual Machines in Ruby & C
Implementing Virtual Machines in Ruby & CImplementing Virtual Machines in Ruby & C
Implementing Virtual Machines in Ruby & CEleanor McHugh
 
Privacy is always a requirement
Privacy is always a requirementPrivacy is always a requirement
Privacy is always a requirementEleanor McHugh
 

Plus de Eleanor McHugh (20)

[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
 
Generics, Reflection, and Efficient Collections
Generics, Reflection, and Efficient CollectionsGenerics, Reflection, and Efficient Collections
Generics, Reflection, and Efficient Collections
 
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
 
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]
 
Go for the paranoid network programmer, 3rd edition
Go for the paranoid network programmer, 3rd editionGo for the paranoid network programmer, 3rd edition
Go for the paranoid network programmer, 3rd edition
 
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]
 
An introduction to functional programming with go
An introduction to functional programming with goAn introduction to functional programming with go
An introduction to functional programming with go
 
Identity & trust in Monitored Spaces
Identity & trust in Monitored SpacesIdentity & trust in Monitored Spaces
Identity & trust in Monitored Spaces
 
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
 
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
 
Anonymity, identity, trust
Anonymity, identity, trustAnonymity, identity, trust
Anonymity, identity, trust
 
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
 
Distributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at ScaleDistributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at Scale
 
Hello Go
Hello GoHello Go
Hello Go
 
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
 
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
 
Anonymity, trust, accountability
Anonymity, trust, accountabilityAnonymity, trust, accountability
Anonymity, trust, accountability
 
Implementing Virtual Machines in Go & C
Implementing Virtual Machines in Go & CImplementing Virtual Machines in Go & C
Implementing Virtual Machines in Go & C
 
Implementing Virtual Machines in Ruby & C
Implementing Virtual Machines in Ruby & CImplementing Virtual Machines in Ruby & C
Implementing Virtual Machines in Ruby & C
 
Privacy is always a requirement
Privacy is always a requirementPrivacy is always a requirement
Privacy is always a requirement
 

Dernier

Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 

Dernier (20)

E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 

Implementing Software Machines in C and Go

  • 2. this is a talk about VMs system virtualisation hardware emulation abstract virtual machines
  • 4. this is a talk about VMs system virtualisation hardware emulation abstract virtual machines
  • 6. this is a talk about VMs system virtualisation ? hardware emulation ? abstract virtual machines
  • 8. this is a talk about VMs system virtualisation ? hardware emulation ? abstract virtual machines
  • 9. inspired by hardware discrete components processors storage communications
  • 11.
  • 12. memory storing data & instructions addressing protection
  • 13.
  • 15. package memory 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) Bytes() (b []byte) { h := m.newHeader() return *(*[]byte)(unsafe.Pointer(&h)) } 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) } }
  • 16. package memory 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) Bytes() (b []byte) { h := m.newHeader() return *(*[]byte)(unsafe.Pointer(&h)) } 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) } }
  • 17. package memory 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) Bytes() (b []byte) { h := m.newHeader() return *(*[]byte)(unsafe.Pointer(&h)) } 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) } }
  • 18. package main import "fmt" 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 run 01.go Allegra:00 memory eleanor$ ./01 m (cells) = 2 of 2 : [0 0] b (bytes) = 16 of 16 : [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] s (bytes) = 16 of 16 : [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] m (cells) = 2 of 2 : [3 5] b (bytes) = 16 of 16 : [3 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0] s (bytes) = 16 of 16 : [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] m (cells) = 2 of 2 : [72623859790382856 5] b (bytes) = 16 of 16 : [8 7 6 5 4 3 2 1 5 0 0 0 0 0 0 0] s (bytes) = 16 of 16 : [3 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0]
  • 19.
  • 20.
  • 21. c: array stack uses fixed amount of memory [grow | shrink]ing stack requires explicit realloc() stack pointer is an offset into the array
  • 22. #include <stdio.h> #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 size; }; STACK *NewStack() { STACK *s; s = malloc(sizeof(STACK)); s->size = 0; return s; } STACK_STATUS push(STACK *s, int data) { if (s->size < STACK_MAX) { s->data[s->size++] = data; return STACK_OK; } return STACK_OVERFLOW; } STACK_STATUS pop(STACK *s, int *r) { if (s->size > 0) { *r = s->data[s->size - 1]; s->size--; return STACK_OK; } return STACK_UNDERFLOW; } int depth(STACK *s) { return s->size; } int main() { int l, r; STACK *s = NewStack(); push(s, 1); push(s, 3); printf("depth = %dn", depth(s)); pop(s, &l); pop(s, &r); printf("%d + %d = %dn", l, r, l + r); printf("depth = %dn", depth(s)); } c: array stack $ cc 01.c $ ./a.out depth = 2 3 + 1 = 4 depth = 0
  • 23. go: slice stack maps directly to [] slice types [grow | shrink]ing stack automatic via append() doesn’t require initialization
  • 24. package main import "fmt" type stack_status int const ( STACK_OK = stack_status(iota) STACK_OVERFLOW STACK_UNDERFLOW ) type stack struct { data []int } func (s *stack) Push(data int) { s.data = append(s.data, data) } func (s *stack) Pop() (int, stack_status) { if s == nil || len(s.data) < 1 { return 0, STACK_UNDERFLOW } sp := len(s.data) - 1 r := s.data[sp] s.data = s.data[:sp] return r, STACK_OK } func (s *stack) Depth() int { return len(s.data) } func main() { s := new(stack) s.Push(1) s.Push(3) fmt.Printf("depth = %dn", s.Depth()) l, _ := s.Pop() r, _ := s.Pop() fmt.Printf("%d + %d = %dn", l, r, l+r) fmt.Printf("depth = %dn", s.Depth()) } go: slice stack $ go run 01a.go depth = 2 3 + 1 = 4 depth = 0
  • 25. package main import "fmt" type stack_status int const ( STACK_OK = stack_status(iota) STACK_OVERFLOW STACK_UNDERFLOW ) type stack struct { data []int } func (s *stack) Push(data int) { s.data = append(s.data, data) } func (s *stack) Pop() (int, stack_status) { if s == nil || len(s.data) < 1 { return 0, STACK_UNDERFLOW } sp := len(s.data) - 1 r := s.data[sp] s.data = s.data[:sp] return r, STACK_OK } func (s *stack) Depth() int { return len(s.data) } func main() { s := new(stack) s.Push(1) s.Push(3) fmt.Printf("depth = %dn", s.Depth()) l, _ := s.Pop() r, _ := s.Pop() fmt.Printf("%d + %d = %dn", l, r, l+r) fmt.Printf("depth = %dn", s.Depth()) } go: slice stack $ go run 01a.go depth = 2 3 + 1 = 4 depth = 0
  • 26. package main import "fmt" type stack_status int const ( STACK_OK = stack_status(iota) STACK_OVERFLOW STACK_UNDERFLOW ) type stack struct { data []int } func (s *stack) Push(data int) { s.data = append(s.data, data) } func (s *stack) Pop() (int, stack_status) { if s == nil || len(s.data) < 1 { return 0, STACK_UNDERFLOW } sp := len(s.data) - 1 r := s.data[sp] s.data = s.data[:sp] return r, STACK_OK } func (s *stack) Depth() int { return len(s.data) } func main() { s := new(stack) s.Push(1) s.Push(3) fmt.Printf("depth = %dn", s.Depth()) l, _ := s.Pop() r, _ := s.Pop() fmt.Printf("%d + %d = %dn", l, r, l+r) fmt.Printf("depth = %dn", s.Depth()) } go: slice stack $ go run 01a.go depth = 2 3 + 1 = 4 depth = 0
  • 27. 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 (s stack) Depth() int { return len(s) } func main() { s := new(stack) s.Push(1) s.Push(3) fmt.Printf("depth = %dn", s.Depth()) l := s.Pop() r := s.Pop() fmt.Printf("%d + %d = %dn", l, r, l+r) fmt.Printf("depth = %dn", s.Depth()) } go: slice stack $ go run 01b.go depth = 2 3 + 1 = 4 depth = 0
  • 28.
  • 29. c: cactus stack doesn’t require initialization automatic stack growth on push() potentially leaks memory on pop()
  • 30. #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 main() { int l, r; STACK *s = push(NULL, 1); s = push(s, 3); printf("depth = %dn", depth(s)); STACK *t = pop(pop(s, &r), &l); printf("%d + %d = %dn", l, r, l + r); printf("depth pre-gc = %dn", depth(s)); gc(&s, 2); printf("depth post-gc = %dn", depth(s)); } c: functional cactus stack $ cc 02.c $ ./a.out depth = 2 1 + 3 = 4 depth pre-gc = 2 depth post-gc = 0
  • 31. #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 main() { int l, r; STACK *s = push(NULL, 1); s = push(s, 3); printf("depth = %dn", depth(s)); STACK *t = pop(pop(s, &r), &l); printf("%d + %d = %dn", l, r, l + r); printf("depth pre-gc = %dn", depth(s)); gc(&s, 2); printf("depth post-gc = %dn", depth(s)); } c: functional cactus stack $ cc 02.c $ ./a.out depth = 2 1 + 3 = 4 depth pre-gc = 2 depth post-gc = 0
  • 32. #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; } 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); } c: cactus stack in action $ cc 03.c $ ./a.out 5 items: sum = 25 3 items: sum = 25 5 items: sum = 39
  • 33. go: cactus stack doesn’t need initialization automatic stack growth on push() garbage collection removes need for free()
  • 34. package main import "fmt" type stack struct { data int tail *stack } func (s *stack) Push(v int) (r *stack) { r = &stack{data: v, tail: s} return } func (s *stack) Pop() (v int, r *stack) { return s.data, s.tail } func (s *stack) Depth() (r int) { for t := s; t != nil; t = t.tail { r++ } return } func main() { var l, r int var s *stack s = s.Push(1).Push(3) fmt.Printf("depth = %dn", s.Depth()) l, s = s.Pop() r, s = s.Pop() fmt.Printf("%d + %d = %dn", l, r, l+r) fmt.Printf("depth = %dn", s.Depth()) } go: functional cactus stack $ go run 02a.go depth = 2 3 + 1 = 4 depth = 0
  • 35. package main import "fmt" type stack struct { data int tail *stack } func (s stack) Push(v int) (r stack) { r = stack{data: v, tail: &s} return } func (s stack) Pop() (v int, r stack) { return s.data, *s.tail } func (s stack) Depth() (r int) { for t := s.tail; t != nil; t = t.tail { r++ } return } func main() { var l, r int var s stack s = s.Push(1).Push(3) fmt.Printf("depth = %dn", s.Depth()) l, s = s.Pop() r, s = s.Pop() fmt.Printf("%d + %d = %dn", l, r, l+r) fmt.Printf("depth = %dn", s.Depth()) } go: functional cactus stack $ go run 02b.go depth = 2 3 + 1 = 4 depth = 0
  • 36. package main import "fmt" type stack struct { data int tail *stack } func (s stack) Push(v int) (r stack) { r = stack{data: v, tail: &s} return } func (s stack) Pop() (v int, r stack) { return s.data, *s.tail } func (s stack) Depth() (r int) { for t := s.tail; t != nil; t = t.tail { r++ } return } func (s *stack) append(n int) { t := s for ; t.tail != nil; t = t.tail {} *t = stack{data: n, tail: new(stack)} } func main() { var l, r int var s stack s = s.Push(1).Push(3) fmt.Printf("depth = %dn", s.Depth()) s.append(20) fmt.Printf("depth = %dn", s.Depth()) l, s = s.Pop() r, s = s.Pop() fmt.Printf("%d + %d = %dn", l, r, l+r) l, s = s.Pop() fmt.Printf("l = %dn", l) fmt.Printf("depth = %dn", s.Depth()) s.append(5) l, s = s.Pop() fmt.Printf("l = %dn", l) fmt.Printf("depth = %dn", s.Depth()) } go: functional cactus stack $ go run 02c.go depth = 2 depth = 3 3 + 1 = 4 l = 20 depth = 0 l = 5 depth = 0
  • 37. package main import "fmt" type stack struct { data int tail *stack } func (s *stack) Push(v int) (r *stack) { r = &stack{data: v, tail: s} return } func (s *stack) Pop() (v int, r *stack) { return s.data, s.tail } func (s stack) Depth() (r int) { for t := s.tail; t != nil; t = t.tail { r++ } return } func (s stack) Sum() (r int) { for t := &s; t.tail != nil; t = t.tail { r += t.data } return } func (s *stack) PrintSum() { fmt.Printf("%d items: sum = %dn", s.Depth(), s.Sum()) } func main() { s1 := 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() } go: cactus stack in action $ go run 03a.go 5 items: sum = 25 3 items: sum = 25 5 items: sum = 39
  • 38. package main import "fmt" type stack struct { data int tail *stack } func (s *stack) Push(v int) (r *stack) { r = &stack{data: v, tail: s} return } func (s *stack) Pop() (v int, r *stack) { return s.data, s.tail } func (s stack) Depth() (r int) { for t := s.tail; t != nil; t = t.tail { r++ } return } func (s stack) Sum() (r int) { for t, n := s, 0; t.tail != nil; r += n { n, t = t.Pop() } return } func (s *stack) PrintSum() { fmt.Printf("%d items: sum = %dn", s.Depth(), s.Sum()) } 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() } go: cactus stack in action $ go run 03b.go 5 items: sum = 25 3 items: sum = 25 5 items: sum = 39
  • 40. #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: map $ cc 04.c $ ./a.out rosy sweet pie tart (null)
  • 41. #include <stdlib.h> #include "assoc_array.c" 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: map $ cc 04.c $ ./a.out rosy sweet pie tart (null)
  • 42. #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <string.h> #include "search.c" 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); } 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")); return 0; } c: map $ cc 04.c $ ./a.out rosy sweet pie tart (null)
  • 43. 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; } c: map $ cc 04.c $ ./a.out rosy sweet pie tart (null)
  • 44. 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; } c: map $ cc 04.c $ ./a.out rosy sweet pie tart (null)
  • 45. 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; } c: map $ cc 04.c $ ./a.out rosy sweet pie tart (null)
  • 47. package assoc_array type AssocArray struct { Key string Value interface{} Next *AssocArray }; func (a *AssocArray) GetIf(k string) (r interface{}) { if a != nil && a.Key == k { r = a.Value } return } go: map $ cc 04.c $ ./a.out rosy sweet pie tart (null)
  • 48. package search import . "assoc_array" 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 } 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 } go: map $ cc 04.c $ ./a.out rosy sweet pie tart (null)
  • 49. package main import "fmt" import . "assoc_array" import "search" type Map []*AssocArray func (m Map) Set(k string, v interface{}) { c := m.Chain(k) a := m[c] s := search.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) 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) Get(k string) (r interface{}) { if s := search.Find(m[m.Chain(k)], k); s != nil { r = s.Value } return } func main() { m := make(Map, 1024) m.Set("apple", "rosy") fmt.Printf("%vn", m.Get("apple")) m.Set("blueberry", "sweet") fmt.Printf("%vn", m.Get("blueberry")) m.Set("cherry", "pie") fmt.Printf("%vn", m.Get("cherry")) m.Set("cherry", "tart") fmt.Printf("%vn", m.Get("cherry")) fmt.Printf("%vn", m.Get("tart")) } go: map $ go run 04.go rosy sweet pie tart <nil>
  • 50. package main import "fmt" func main() { m := make(map[string] interface{}) m["apple"] = "rosy" fmt.Printf("%vn", m["apple"]) m["blueberry"] = "sweet" fmt.Printf("%vn", m["blueberry"]) m["cherry"] = "pie" fmt.Printf("%vn", m["cherry"]) m["cherry"] = "tart" fmt.Printf("%vn", m["cherry"]) fmt.Printf("%vn", m["tart"]) } go: map $ go run 05.go rosy sweet pie tart <nil>
  • 52. dispatch loops read next instruction via a program counter determine the operation to perform execute the operation and adjust machine state
  • 53. switch interpreter instructions stored sequentially in memory each represented by a token or opcode available in all implementation languages tokens can be compact - often single bytes
  • 54. #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; } typedef enum { PUSH = 0, ADD, PRINT, EXIT } opcodes; STACK *S; void interpret(int *PC) { int l, r; while (1) { switch(*PC++) { case PUSH: S = push(S, *PC++); 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: switch interpreter
  • 55. #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; } typedef enum { PUSH = 0, ADD, PRINT, EXIT } opcodes; STACK *S; #define READ_OPCODE *PC++ 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: switch interpreter
  • 56. package main import "fmt" func main() { var program = []interface{}{ PUSH, 13, PUSH, 28, ADD, PRINT, EXIT, } interpret(program) } type stack struct { data int tail *stack } func (s *stack) Push(v int) (r *stack) { r = &stack{data: v, tail: s} return } func (s *stack) Pop() (v int, r *stack) { return s.data, s.tail } type OPCODE int const ( PUSH = OPCODE(iota) 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.data) case EXIT: return } } else { return } } } go: switch interpreter
  • 57. direct call threading instructions stored sequentially in memory each represented by a pointer to a function not available in all languages instructions each require a machine word
  • 58. #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; } typedef void (*opcode)(); STACK *S; opcode *PC; void op_push() { S = push(S, (int)(long)(*PC++)); } 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); } int main() { opcode program [] = { op_push, (opcode)(long)13, op_push, (opcode)(long)28, op_add_and_print, op_exit }; PC = program; while (1) { (*PC++)(); } } c: direct call-threaded interpreter
  • 59. #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; } typedef void (*opcode)(); STACK *S; opcode *PC; #define READ_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); } int main() { opcode program [] = { op_push, (opcode)(long)13, op_push, (opcode)(long)28, op_add_and_print, op_exit }; PC = program; while (1) { (READ_OPCODE)(); } } c: direct call-threaded interpreter
  • 60. package main import "fmt" import "os" func main() { p := new(Interpreter) p.m = []interface{}{ p.Push, 13, p.Push, 28, p.Add, p.Print, p.Exit, } p.Run() } type stack struct { data int tail *stack } func (s *stack) Push(v int) (r *stack) { r = &stack{data: v, tail: s} return } func (s *stack) Pop() (v int, r *stack) { return s.data, s.tail } type Interpreter struct { S *stack l, r, PC int m []interface{} } func (i *Interpreter) opcode() func() { return i.m[i.PC].(func()) } func (i *Interpreter) operand() int { return i.m[i.PC].(int) } func (i *Interpreter) Run() { for { i.opcode()() i.PC++ } } func (i *Interpreter) Push() { i.PC++ i.S = i.S.Push(i.operand()) } 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.data) } func (i *Interpreter) Exit() { os.Exit(0) } go: direct call-threaded interpreter
  • 61. indirect threading instructions stored sequentially in memory each represented by a local jump label gcc/clang specific C extension instructions indirectly load successor
  • 62. #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; } typedef enum { PUSH = 0, ADD, 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; 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, EXIT }; interpret(program); } c: indirect-threaded interpreter
  • 63. #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; } typedef enum { PUSH = 0, ADD, PRINT, EXIT } opcodes; STACK *S; #define READ_OPCODE *PC++ #define EXECUTE_OPCODE goto *opcodes[READ_OPCODE]; #define PRIMITIVE(name, body) name: body; EXECUTE_OPCODE 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_add, S = pop(S, &l); S = pop(S, &r); S = push(S, l + r); ) PRIMITIVE(op_print, printf("%d + %d = %dn", l, r, S->data)) PRIMITIVE(op_exit, return) } int main() { int program [] = { PUSH, 13, PUSH, 28, ADD, PRINT, EXIT }; interpret(program); } c: indirect-threaded interpreter
  • 64. direct threading instructions stored sequentially in memory each represented by a local jump label gcc/clang specific C extension instructions directly load successors
  • 65. #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; } typedef enum { PUSH = 0, ADD, PRINT, EXIT } opcodes; STACK *S; void **compile(int *PC, int words, void *despatch_table[]) { static void *compiler [] = { &&comp_push, &&comp_add, &&comp_print, &&comp_exit }; if (words < 1) return NULL; void **program = malloc(sizeof(void *) * words); void **cp = program; goto *compiler[*PC++]; comp_push: *cp++ = despatch_table[PUSH]; *cp++ = (void *)(long)*PC++; words -= 2; if (words == 0) return program; goto *compiler[*PC++]; comp_add: *cp++ = despatch_table[ADD]; words--; if (words == 0) return program; goto *compiler[*PC++]; comp_print: *cp++ = despatch_table[PRINT]; words--; if (words == 0) return program; goto *compiler[*PC++]; comp_exit: *cp++ = despatch_table[EXIT]; words--; if (words == 0) return program; goto *compiler[*PC++]; } c: direct-threaded interpreter (1)
  • 66. 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; } int main() { int program[] = { PUSH, 13, PUSH, 28, ADD, PRINT, EXIT }; interpret(program, 7); } c: direct-threaded interpreter (2)
  • 67. #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; } typedef enum { PUSH = 0, ADD, PRINT, EXIT } opcodes; STACK *S; #define COMPILE(body) COMPILE_NEXT_OPCODE body #define COMPILE_NEXT_OPCODE if (words < 1) return program; goto *compiler[*PC++]; #define DESCRIBE_PRIMITIVE(name, body) name: body; COMPILE_NEXT_OPCODE #define WRITE_OPCODE(value) *cp++ = value; words--; void **compile(int *PC, int words, void *despatch_table[]) { static void *compiler[] = { &&push, &&add, &&print, &&exit }; void **program = malloc(sizeof(void *) * words); void **cp = program; COMPILE( DESCRIBE_PRIMITIVE(push, WRITE_OPCODE(despatch_table[PUSH]) WRITE_OPCODE((void *)(long)*PC++)) DESCRIBE_PRIMITIVE(add, WRITE_OPCODE(despatch_table[ADD])) DESCRIBE_PRIMITIVE(print, WRITE_OPCODE(despatch_table[PRINT])) DESCRIBE_PRIMITIVE(exit, WRITE_OPCODE(despatch_table[EXIT])) ) } c: direct-threaded interpreter (1)
  • 68. #define READ_OPCODE *program++ #define EXECUTE_OPCODE goto *READ_OPCODE; #define PRIMITIVE(name, body) name: body; EXECUTE_OPCODE void interpret(int *PC, int words) { static void *despatch_table[] = { &&push, &&add, &&print, &&exit }; int l, r; void **program = compile(PC, words, despatch_table); if (program == NULL) exit(1); EXECUTE( PRIMITIVE(push, S = push(S, (int)(long)READ_OPCODE)) 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); } c: direct-threaded interpreter (2)
  • 70. package clock import "syscall" type Clock struct { Period int64 Count chan int64 Control chan bool active bool } func (c *Clock) Start() { if !c.active { go func() { c.active = true for i := int64(0); ; i++ { select { case status := <- c.Control: c.active = status default: if c.active { c.Count <- i } syscall.Sleep(c.Period) } } }() } } package main import . “clock” func main() { c := Clock{1000, make(chan int64), make(chan bool), false} c.Start() for i := 0; i < 3; i++ { println("pulse value", <-c.Count, "from clock") } println("disabling clock") c.Control <- false syscall.Sleep(1000000) println("restarting clock") c.Control <- true println("pulse value", <-c.Count, "from clock") } produces: pulse value 0 from clock pulse value 1 from clock pulse value 2 from clock disabling clock restarting clock pulse value 106 from clock
  • 72. package instructions type Op func(o []int) type Executable interface { Opcode() int Operands() []int Execute(Op) } const INVALID_OPCODE = -1 type Instr []int func (i Instr) Opcode() int { if len(i) == 0 { return INVALID_OPCODE } return i[0] } func (i Instr) Operands() (r []int) { if len(i) > 1 { r = i[1:] } return } func (i Instr) Execute(op Operation) { op(i.Operands()) }
  • 73. package assembler import "fmt" import . "instructions" type Asm struct { opcodes map[string] int names map[int] string } func NewAsm(names... string) (a Asm) { a = Asm{ make(map[string] int), make(map[int] string), } a.Define(names...) return } func (a Asm) Asm(n string, p... int) (i Instr) { if opcode, ok := a.opcodes[name]; ok { i = make(Instruction, len(params) + 1) i[0] = opcode copy(i[1:], params) } return } func (a Asm) Define(n... string) { for _, name := range names { a.opcodes[name] = len(a.names) a.names[len(a.names)] = name } } func (a Asm) Disasm(e Executable) (s string) { if name, ok := a.names[e.Opcode()]; ok { s = name if params := e.Operands(); len(params) > 0 { s = fmt.Sprintf("%vt%v", s, params[0]) for _, v := range params[1:] { s = fmt.Sprintf("%v, %v", s, v) } } } else { s = "INVALID" } return }
  • 74. package main import "fmt" import "assembler" type Program []Executable func (p Program) Rip(a Asm) { for _, v := range p { fmt.Println(a.Rip(v)) } } func main() { a := NewAsm("noop", "load", "store") p := Program{ a.Asm("noop"), a.Asm("load", 1), a.Asm("store", 1, 2), a.Asm("invalid", 3, 4, 5), } p.Disasm(a) for _, v := range p { if len(v.Operands()) == 2 { v.Execute(func(o []int) { o[0] += o[1] }) println("op =“, v.Opcode(), "result =“, v.Operands()[0], ) } } } produces: noop load 1 store 1, 2 unknown op = 2 result = 3
  • 75. CISC semantically rich instructions complex memory addressing modes compact binary code
  • 76. RISC separate IO and data processing register-to-register instructions load/store memory access
  • 77. VLIW multiple operations per instruction compiler statically determines parallelism simplifies control logic
  • 78. processor core sends & receives signals on external buses maintains internal computation state executes sequences of instructions
  • 79. accumulator machine 1-operand instructions data from memory combined with accumulator result stored in accumulator
  • 80. stack machine 0-operand instructions data popped from stack results pushed on stack
  • 81. register machine multi-operand instructions data read from memory into registers operator combines memory and store ops
  • 82. transport triggering register machine architecture exposes internal buses as components operations are side-effects of internal writes
  • 83. vector machine multi-operand instruction data vectors read from memory into registers operator combines registers and store ops
  • 84. superscalar multiple execution units processor caching out-of-order execution