SlideShare uma empresa Scribd logo
1 de 89
golightly
a customisable virtual machine written in Go
Eleanor McHugh
http://slides.games-with-brains.net/
Thursday, 30 May 13
portrait of an artist...
physics major
embedded controllers
software reliability
dynamic languages
network scaling
questionable taste in music
http://github.com/feyeleanor
Eleanor McHugh
Thursday, 30 May 13
go...
small, safety-conscious systems language
concurrency, closures & garbage collection
consistently fast compilation
Thursday, 30 May 13
...lightly
agnostic virtual machine networks
application performance matters
non-viral open source license
Thursday, 30 May 13
agnostic
no blessed programming languages
flexible platform abstractions
write once, run everywhere it matters
Thursday, 30 May 13
heterogeneous
a system comprises many components
components may differ in purpose and design
but they cooperate to solve problems
Thursday, 30 May 13
networks
machines cooperate by sending messages
machine states can be serialised as messages
messages transcend process and host boundaries
Thursday, 30 May 13
inspiration
hardware design
sensor and control networks
field-programmable gate arrays
Thursday, 30 May 13
virtual machine
emulate an existing system
simulate an imagined system
have dynamic control of system state
Thursday, 30 May 13
stack-based lambda calculus processor
threaded value cells in a von neumann memory
all operations are expressions are values
lisp
Thursday, 30 May 13
stack-based processor
threaded word definitions in a von neumann memory
words thread primitives, word pointers and data
forth
Thursday, 30 May 13
stack-based processor with instruction set
harvard memory separates code and data
class loaders convert bytecode to machine state
jvm
Thursday, 30 May 13
linux kernel hypervisor
intel X86 virtualisation with hardware execution
QEMU virtual machine runs in user space
kvm
Thursday, 30 May 13
hello world
Thursday, 30 May 13
package main
import "fmt"
const(
HELLO string = "hello"
WORLD string = "world"
)
func main() {
fmt.Println(HELLO, WORLD)
}
Thursday, 30 May 13
user-defined type
Thursday, 30 May 13
package Integer
type Int int
func (i *Int) Add(x int) {
*i += Int(x)
}
Thursday, 30 May 13
package Integer
type Buffer []Int
func (b Buffer) Eq(o Buffer) (r bool) {
if len(b) == len(o) {
for i := len(b) - 1; i > 0; i-- {
if b[i] != o[i] {
return
}
}
r = true
}
return
}
func (b Buffer) Swap(i, j int) {
b[i], b[j] = b[j], b[i]
}
func (b Buffer) Clone() Buffer {
s := make(Buffer, len(b))
copy(s, b)
return s
}
func (b Buffer) Move(i, n int) {
if n > len(b) - i {
n = len(b) - i
}
segment_to_move := b[:i].Clone()
copy(b, b[i:i + n])
copy(b[n:i + n], segment_to_move)
}
Thursday, 30 May 13
package main
import "Integer"
func main() {
i := Integer.Buffer{0, 1, 2, 3, 4, 5}
b := i.Clone()
b.Swap(1, 2)
b.Move(3, 2)
b[0].Add(3)
println("b[:2] = {", b[0], ",", b[1], "}")
}
produces:
b[0:2] = { 6, 4 }
Thursday, 30 May 13
package Integer
import "testing"
func TestSwap(t *testing.T) {
i := Buffer{0, 1, 2, 3, 4, 5}
b := i.Clone()
b.Swap(1, 2)
if !b[1:3].Eq(Buffer{2, 1}) {
t.Fatalf("b[:5] = %v", b)
}
}
func TestMove(t *testing.T) {
i := Buffer{0, 1, 2, 3, 4, 5}
b := i.Clone()
b.Move(3, 2)
if !b.Eq(Buffer{3, 4, 0, 1, 2, 5}) {
t.Fatalf("b[:5] = %v", b)
}
}
func TestAdd(t *testing.T) {
i := Buffer{0, 1, 2, 3, 4, 5}
b := i.Clone()
b[0].Add(3)
if b[0] != i[0] + 3 {
t.Fatalf("b[:5] = %v", b)
}
}
Thursday, 30 May 13
embedding
Thursday, 30 May 13
package Vector
import . "Integer"
type Vector struct {
Buffer
}
func (v *Vector) Clone() Vector {
return Vector{v.Buffer.Clone()}
}
func (v *Vector) Slice(i, j int) Buffer {
return v.Buffer[i:j]
}
Thursday, 30 May 13
package Integer
import "testing"
func TestVectorSwap(t *testing.T) {
i := Vector{Buffer{0, 1, 2, 3, 4, 5}}
v := i.Clone()
v.Swap(1, 2)
r := Vector{Buffer{0, 2, 1, 3, 4, 5}}
switch {
case !v.Match(&r):
fallthrough
case !v.Buffer.Match(r.Buffer):
t.Fatalf("b[:5] = %v", v)
}
}
Thursday, 30 May 13
package integer
import "testing"
func BenchmarkVectorClone6(b *testing.B) {
v := Vector{Buffer{0, 1, 2, 3, 4, 5}}
for i := 0; i < b.N; i++ {
_ = v.Clone()
}
}
func BenchmarkVectorSwap(b *testing.B) {
b.StopTimer()
v := Vector{Buffer{0, 1, 2, 3, 4, 5}}
b.StartTimer()
for i := 0; i < b.N; i++ {
v.Swap(1, 2)
}
}
Thursday, 30 May 13
$ go test -test.bench="Benchmark"
PASS
integer.BenchmarkVectorSwap 200000000 8 ns/op
integer.BenchmarkVectorClone6 10000000 300 ns/op
Thursday, 30 May 13
inference
Thursday, 30 May 13
package adder
type Adder interface {
Add(j int)
Subtract(j int)
Result() interface{}
}
type Calculator interface {
Adder
Reset()
}
type AddingMachine struct {
Memory interface{}
Adder
}
Thursday, 30 May 13
package adder
type IAdder []int
func (i IAdder) Add(j int) {
i[0] += i[j]
}
func (i IAdder) Subtract(j int) {
i[0] -= i[j]
}
func (i IAdder) Result() interface{} {
return i[0]
}
func (i IAdder) Reset() {
i[0] = *new(int)
}
Thursday, 30 May 13
package adder
import "testing"
func TestIAdder(t *testing.T) {
error := "Result %v != %v"
i := IAdder{0, 1, 2}
i.Add(1)
if i.Result().(int) != 1 { t.Fatalf(error, i.Result(), 1) }
i.Subtract(2)
if i.Result().(int) != -1 { t.Fatalf(error, i.Result()), -1 }
var r Calculator = IAdder{-1, 1, 2}
for n, v := range r.(IAdder) {
if i[n] != v { t.Fatalf("Adder %v should be %v", i, r) }
}
r.Reset()
if r.Result().(int) != *new(int) {
t.Fatalf(error, r.Result(), *new(int))
}
}
Thursday, 30 May 13
package adder
import "testing"
func TestIAdder(t *testing.T) {
error := "Result %v != %v"
i := IAdder{0, 1, 2}
i.Add(1)
if i.Result() != 1 { t.Fatalf(error, i.Result(), 1) }
i.Subtract(2)
if i.Result() != -1 { t.Fatalf(error, i.Result()), -1 }
var r Calculator = IAdder{-1, 1, 2}
for n, v := range r.(IAdder) {
if i[n] != v { t.Fatalf("Adder %v should be %v", i, r) }
}
r.Reset()
if r.Result() != *new(int) {
t.Fatalf(error, r.Result(), *new(int))
}
}
Thursday, 30 May 13
package adder
type FAdder []float32
func (f FAdder) Add(j int) {
f[0] += f[j]
}
func (f FAdder) Subtract(j int) {
f[0] -= f[j]
}
func (f FAdder) Result() interface{} {
return f[0]
}
func (f FAdder) Reset() {
f[0] = *new(float32)
}
Thursday, 30 May 13
package adder
import "testing"
func TestFAdder(t *testing.T) {
error := "Result %v != %v"
f := FAdder{0.0, 1.0, 2.0}
f.Add(1)
if f.Result() != 1.0 { t.Fatalf(error, f.Result(), 1.0) }
f.Subtract(2)
if i.Result() != -1.0 { t.Fatalf(error, i.Result()), -1.0 }
var r Calculator = FAdder{-1.0, 1.0, 2.0}
for n, v := range r.(FAdder) {
if f[n] != v { t.Fatalf("Adder %v should be %v", f, r) }
}
r.Reset()
if r.Result() != *new(float32) {
t.Fatalf(error, r.Result(), *new(float32))
}
}
Thursday, 30 May 13
package adder
import "testing"
func TestAddingMachine(t *testing.T) {
error := "Result %v != %v"
a := &AddingMachine{ Adder: FAdder{0.0, 1.0, 2.0} }
a.Add(1)
if f, ok := a.Result().(float32); !ok {
t.Fatal("Result should be a float32")
} else if f != 1.0 {
t.Fatalf(error, a.Result(), 1.0)
}
a.Subtract(2)
if a.Result().(float32) != -1.0 { t.Fatalf(error, a.Result(), -1.0) }
r := FAdder{-1.0, 1.0, 2.0}
for n, v := range a.Adder.(FAdder) {
if r[n] != v { t.Fatalf("Adder %v should be %v", a, r) }
}
}
Thursday, 30 May 13
concurrency
Thursday, 30 May 13
goroutines
concurrent execution stacks
initialised with a closure
scheduled automatically by the runtime
Thursday, 30 May 13
package main
import "fmt"
func main() {
var c chan int
c = make(chan int)
go func() {
for {
fmt.Print(<-c)
}
}()
for {
select {
case c <- 0:
case c <- 1:
}
}
} produces:
01100111010110...
Thursday, 30 May 13
package main
import "fmt"
func main() {
var c chan int
c = make(chan int, 16)
go func() {
for {
fmt.Print(<-c)
}
}()
go func() {
select {
case c <- 0:
case c <- 1:
}
}()
for {}
}
produces:
01100111010110...
Thursday, 30 May 13
package map_reduce
type SignalSource func(status chan bool)
func Wait(s SignalSource) {
done := make(chan bool)
defer close(done)
go s(done)
<-done
}
func WaitCount(count int, s SignalSource) {
done := make(chan bool)
defer close(done)
go s(done)
for i := 0; i < count; i++ {
<- done
}
}
Thursday, 30 May 13
package map_reduce
type Iteration func(k, x interface{})
func (i Iteration) apply(k, v interface{}, c chan bool) {
go func() {
i(k, v)
c <- true
}()
}
Thursday, 30 May 13
package map_reduce
func Each(c interface{}, f Iteration) {
switch c := c.(type) {
case []int: WaitCount(len(c), func(done chan bool) {
for i, v := range c {
f.apply(i, v, done)
}
})
case map[int] int: WaitCount(len(c), func(done chan bool) {
for k, v := range c {
f.apply(k, v, done)
}
})
}
}
Thursday, 30 May 13
package map_reduce
type Results chan interface{}
type Combination func(x, y interface{}) interface{}
func (f Combination) Reduce(c, s interface{}) (r Results) {
r = make(Results)
go func() {
Each(c, func(k, x interface{}) {
s = f(s, x)
})
r <- s
}()
return
}
Thursday, 30 May 13
package map_reduce
type Transformation func(x interface{}) interface{}
func (t Transformation) GetValue(x interface{}) interface{} {
return t(x)
}
Thursday, 30 May 13
func Map(c interface{}, t Transformation) (n interface{}) {
var i Iteration
switch c := c.(type) {
case []int: m := make([]int, len(c))
i = func(k, x interface{}) { m[k] = t.GetValue(x) }
n = m
case map[int] int: m := make(map[int] int)
i = func(k, x interface{}) { m[k] = t.GetValue(x) }
n = m
}
if i != nil {
Wait(func(done chan bool) {
Each(c, i)
done <- true
})
}
return
}
Thursday, 30 May 13
package main
import "fmt"
import . "map_reduce"
func main() {
m := "%v = %v, sum = %vn"
s := []int{0, 1, 2, 3, 4, 5}
sum := func(x, y interface{}) interface{} { return x.(int) + y.(int) }
d := Map(s, func(x interface{}) interface{} { return x.(int) * 2 })
x := <- Combination(sum).Reduce(s, 0)
fmt.Printf("s", s, x)
x = <- Combination(sum).Reduce(d, 0)
fmt.Printf("d", d, x)
}
produces:
s = [0 1 2 3 4 5], sum = 15
c = [0 2 4 6 8 10], sum = 30
Thursday, 30 May 13
software machines
Thursday, 30 May 13
synchronisation
Thursday, 30 May 13
package clock
import "syscall"
type Clock struct {
Period int64
Count chan int64
Control chan bool
active bool
}
Thursday, 30 May 13
package clock
import "syscall"
func (c *Clock) Start() {
if !c.active {
go func() {
c.active = true
for i := int64(0); ; i++ {
select {
case c.active = <- c.Control:
default:
if c.active {
c.Count <- i
}
syscall.Sleep(c.Period)
}
}
}()
}
}
Thursday, 30 May 13
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")
}
Thursday, 30 May 13
OSX 10.6.2 Intel Atom 270 @ 1.6GHz:
pulse value 0 from clock
pulse value 1 from clock
pulse value 2 from clock
disabling clock
restarting clock
pulse value 106 from clock
OSX 10.6.7 Intel Core 2 Duo @ 2.4GHz:
pulse value 0 from clock
pulse value 1 from clock
pulse value 2 from clock
disabling clock
restarting clock
pulse value 154 from clock
Thursday, 30 May 13
instruction set
Thursday, 30 May 13
operations
CISC
RISC
VLIW
Thursday, 30 May 13
package instructions
import "fmt"
type Operation func(o []int)
type Executable interface {
Opcode() int
Operands() []int
Execute(op Operation)
}
const INVALID_OPCODE = -1
type Program []Executable
func (p Program) Disassemble(a Assembler) {
for _, v := range p {
fmt.Println(a.Disassemble(v))
}
}
Thursday, 30 May 13
package instructions
type Instruction []int
func (i Instruction) Opcode() int {
if len(i) == 0 {
return INVALID_OPCODE
}
return i[0]
}
func (i Instruction) Operands() []int {
if len(i) < 2 {
return []int{}
}
return i[1:]
}
func (i Instruction) Execute(op Operation) {
op(i.Operands())
}
Thursday, 30 May 13
package instructions
type Assembler struct {
opcodes map[string] int
names map[int] string
}
func NewAssember(names... string) (a Assembler) {
a = Assembler{
opcodes: make(map[string] int),
names:make(map[int] string),
}
a.Define(names...)
return
}
func (a Assembler) Define(names... string) {
for _, name := range names {
a.opcodes[name] = len(a.names)
a.names[len(a.names)] = name
}
}
Thursday, 30 May 13
package instructions
func (a Assembler) Assemble(name string, params... int) (i Instruction) {
i = make(Instruction, len(params) + 1)
if opcode, ok := a.opcodes[name]; ok {
i[0] = opcode
} else {
i[0] = INVALID_OPCODE
}
copy(i[1:], params)
return
}
Thursday, 30 May 13
package instructions
import "fmt"
func (a Assembler) Disassemble(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 = "unknown"
}
return
}
Thursday, 30 May 13
package main
import . "instructions"
func main() {
a := NewAssembler("noop", "load", "store")
p := Program{ a.Assemble("noop"),
a.Assemble("load", 1),
a.Assemble("store", 1, 2),
a.Assemble("invalid", 3, 4, 5) }
p.Disassemble(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])
}
}
}
Thursday, 30 May 13
produces:
noop
load 1
store 1, 2
unknown
op = 2 result = 3
Thursday, 30 May 13
processor core
Thursday, 30 May 13
package processor
import . "instructions"
const PROCESSOR_READY = 0
const PROCESSOR_BUSY = 1
const CALL_STACK_UNDERFLOW = 2
const CALL_STACK_OVERFLOW = 4
const ILLEGAL_OPERATION = 8
const INVALID_ADDRESS = 16
type Processor interface {
Run(p []Executable)
}
type Core struct {
Running bool
PC, Flags, Ticks int
CS, M []int
OP Executable "Loaded OpCode"
I chan Executable "Interrupts"
}
Thursday, 30 May 13
package processor
import . "instructions"
func NewCore(CSS, MSS int, I chan Executable) *Core {
return &Core{
CS:make([]int, CSS)},
M: make([]int, MSS),
I: I,
}
}
func (c *Core) Reset() {
c.Running = false
c.Flags = PROCESSOR_READY
}
func (c *Core) Goto(addr int) {
c.PC = addr
}
Thursday, 30 May 13
package processor
func (c *Core) Call(addr int) {
top := len(c.CS)
if top >= cap(c.CS) - 1 { panic(CALL_STACK_OVERFLOW) }
c.CS = c.CS[:top + 1]
c.CS[top] = c.PC
c.PC = addr
}
func (c *Core) TailCall(addr int) {
c.CS[len(c.CS) - 1] = c.PC
c.PC = addr
}
func (c *Core) Return() {
top := len(c.CS)
if top == 0 { panic(CALL_STACK_UNDERFLOW) }
c.PC, c.CS = c.CS[top - 1], c.CS[:top]
}
Thursday, 30 May 13
package processor
import . "instructions"
func (c *Core) Run(p []Executable, dispatchers... func(c *Core)) {
defer func() {
c.Running = false
if x := recover(); x != nil { c.Flags &= x.(int) }
}()
switch {
case c.Running: panic(PROCESSOR_BUSY)
case len(dispatchers) == 0: panic(PROCESSOR_READY)
default:
c.Running = true
c.BusyLoop(dispatchers...)
}
}
func (c *Core) LoadInstruction(program []Executable) {
if c.PC >= len(program) { panic(PROCESSOR_READY) }
c.Executable = program[c.PC]
c.PC++
}
Thursday, 30 May 13
package processor
import . "instructions"
func (c *Core) BusyLoop(p []Executable, dispatchers... func(c *Core)) {
select {
case interrupt <- c.I:
op, pc := c.OP, c.PC
for c.PC = 0; c.Running; c.Ticks++ {
for _, f := range dispatchers { f(c) }
c.LoadInstruction(p)
}
c.OP, c.PC = op, pc
default:
for c.PC = 0; c.Running; c.Ticks++ {
c.LoadInstruction(p)
for _, f := range dispatchers { f(c) }
}
}
}
Thursday, 30 May 13
package processor
import . "instructions"
func (c *Core) RunExclusive(p []Executable, tracers... func(c *Core)) {
defer func() {
c.Running = false
if x := recover(); x != nil { c.Flags &= x.(int) }
}()
if c.Running { panic(PROCESSOR_BUSY) }
case len(dispatchers) == 0: panic(PROCESSOR_READY)
c.Running = true
for c.PC = 0; c.Running; c.Ticks++ {
c.LoadInstruction(p)
for _, f := range tracers { f(c) }
}
}
Thursday, 30 May 13
package main
import . "processor"
import . "instructions"
const( CALL = iota
GOTO
MOVE
RETURN
)
c := NewCore(10, 8, nil)
var dispatcher = func(c *Core) {
switch c.Opcode() {
case CALL: c.Execute(func(o []int) { c.Call(o[0]) })
case GOTO: c.Execute(func(o []int) { c.Goto(o[0]) })
case MOVE: c.Execute(func(o []int) { c.Goto(c.PC + o[0]) })
case RETURN: c.Execute(func(o []int) { c.Return() })
default: panic(ILLEGAL_OPERATION)
}
}
Thursday, 30 May 13
func main() {
p := []Executable{ Instruction{ CALL, 2 },
Instruction{ GOTO, 5 },
Instruction{ MOVE, 2 },
Instruction{ RETURN },
Instruction{ MOVE, -1 } }
c.RunExclusive(p, dispatcher)
fmt.Printf("Instructions Executed: %vnPC = %vn", c.Ticks, c.PC)
if c.Flags | PROCESSOR_READY == PROCESSOR_READY {
fmt.Println("Core Ready")
} else {
fmt.Println("Core Error:", c.Flags)
}
}
produces:
Instructions Executed: 2
PC = 5
Core Ready
Thursday, 30 May 13
accumulator machine
1-operand instructions
data from memory combined with accumulator
result stored in accumulator
Thursday, 30 May 13
package accmachine
import . "processor"
const (
CONSTANT = iota
LOAD_VALUE
STORE_VALUE
ADD
)
type AccMachine struct {
Core
AC int
}
func NewAccMachine(CSSize, MSize int, I chan Executable) *AccMachine {
return &AccMachine{ Core: NewCore(CSSize, MSize, I) }
}
Thursday, 30 May 13
package accmachine
import . "processor"
func (a *AccMachine) Run(program []Executable) {
a.RunExclusive(program, func() {
switch a.Opcode() {
case CONSTANT: a.Execute(func(o []int) { a.AC = o[0] })
case LOAD_VALUE: a.Execute(func(o []int) { a.AC = a.M[o[0]] })
case STORE_VALUE: a.Execute(func(o []int) { a.M[o[0]] = a.AC })
case ADD: a.Execute(func(o []int) { a.AC += a.M[o[0]] })
default: panic(ILLEGAL_OPERATION)
}
})
}
Thursday, 30 May 13
package main
import . "accmachine"
import . "instructions"
func main() {
a := NewAccMachine(10, 8, nil)
p := []Executable{ Instruction{CONSTANT, 27},
Instruction{STORE_VALUE, 0},
Instruction{CONSTANT, 13},
Instruction{STORE_VALUE, 1},
Instruction{CONSTANT, 10},
Instruction{ADD, 1},
Instruction{ADD, 0},
Instruction{STORE_VALUE, 2} }
a.Run(p)
fmt.Println("accumulated value =", a.AC)
}
produces:
accumulated value = 50
Thursday, 30 May 13
stack machine
0-operand instructions
data popped from stack
results pushed on stack
Thursday, 30 May 13
package smachine
import . "processor"
const (
CONSTANT = iota
PUSH_VALUE
POP_VALUE
ADD
)
type StackMachine struct {
Core
DS []int
}
func NewStackM(CSSize, DSSize, MSize int, I chan Executable) *StackMachine {
return &StackMachine{DS: make([]int, 0, DSSize),
Core: NewCore(CSSize, MSize, I) }
}
Thursday, 30 May 13
package smachine
import . "processor"
func (s *StackMachine) Push(v int) {
top := len(s.DS)
s.DS, s.DS[top] = s.DS[:top + 1], v
}
func (s *StackMachine) Pop(addr int) {
top := len(s.DS) - 1
s.M[addr], s.DS = s.DS[top], s.DS[:top]
}
Thursday, 30 May 13
package smachine
import . "processor"
func (s *StackMachine) Run(program []Executable) {
s.RunExclusive(program, func() {
switch s.Opcode() {
case CONSTANT: s.Execute(func(o []int) { s.Push(o[0]) })
case PUSH_VALUE: s.Execute(func(o []int) { s.Push(s.M[o[0]]) })
case POP_VALUE: s.Execute(func(o []int) { s.Pop(s.M[o[0]]) })
case ADD: s.Execute(func(o []int) {
l := len(s.DS)
s.DS[l - 2] += s.DS[l - 1]
s.DS = s.DS[:l - 1]
})
default: panic(ILLEGAL_OPERATION)
}
})
}
Thursday, 30 May 13
package main
import . "smachine"
import . "instructions"
func main() {
s := NewStackM(10, 10, 8, nil)
p := []Executable{ Instruction{CONSTANT, 27},
Instruction{CONSTANT, 13},
Instruction{CONSTANT, 10},
Instruction{ADD},
Instruction{ADD} }
s.Run(p)
fmt.Println("data stack =", s.DS)
}
produces:
registers = [50 13 10 0 0 0 0 0 0 0]
Thursday, 30 May 13
register machine
multi-operand instructions
data read from memory into registers
operator combines registers and stores
Thursday, 30 May 13
package rmachine
import . "processor"
const (
CONSTANT = iota
LOAD_VALUE
STORE_VALUE
ADD
)
type RMachine struct {
Core
R []int
}
func NewRMachine(CSSize, RSize, MSize int, I chan Executable) *RMachine {
return &RMachine{ Core: NewCore(CSSize, MSize, I),
R: make([]int, RSize) }
}
Thursday, 30 May 13
package rmachine
import . "processor"
func (r *RMachine) Run(program []Executable) {
r.RunExclusive(program, func() {
switch r.Opcode() {
case CONSTANT: r.Execute(func(o []int) { r.R[o[0]] = o[1] })
case LOAD_VALUE: r.Execute(func(o []int) { r.R[o[0]] = r.M[o[1]] })
case STORE_VALUE: r.Execute(func(o []int) { r.M[o[0]] = r.R[o[1]] })
case ADD: r.Execute(func(o []int) { r.R[o[0]] += r.R[o[1]] })
default: panic(ILLEGAL_OPERATION)
}
})
}
Thursday, 30 May 13
package main
import . "rmachine"
import . "instructions"
func main() {
r := NewRMachine(10, 10, 8, nil)
p := []Executable{ Instruction{CONSTANT, 0, 27},
Instruction{CONSTANT, 1, 13},
Instruction{CONSTANT, 2, 10},
Instruction{ADD, 0, 1},
Instruction{ADD, 0, 2} }
r.Run(p)
fmt.Println("registers =", r.R)
}
produces:
registers = [50 13 10 0 0 0 0 0 0 0]
Thursday, 30 May 13
vector machine
multi-operand instructions
data vectors read from memory into registers
operations combine registers
Thursday, 30 May 13
package vmachine
import . "processor"
const (
CONSTANT = iota
LOAD_VALUE
STORE_VALUE
ADD
)
type VMachine struct {
Core
R [][]int
}
func NewVMachine(CSSize, RSize, MSize int, I chan Executable) *VMachine {
return &VectorMachine{ Core: NewCore(CSSize, MSize),
make([][]int, RSize) }
}
Thursday, 30 May 13
package vmachine
import . "processor"
func (v *VMachine) Load(r int, m []int) {
v.R[r] = make([]int, len(m))
copy(v.R[r], m)
}
Thursday, 30 May 13
package vmachine
import . "processor"
func (v *VMachine) Run(program []Executable) {
v.RunExclusive(program, func() {
switch v.Opcode() {
case CONSTANT: v.Execute(func(o []int) { v.Load(o[0], o[1:]) })
case STORE_VALUE: v.Execute(func(o []int) { copy(v.M[o[0]:], v.R[o[1]]) })
case LOAD_VALUE: v.Execute(func(o []int) {
v.Load(o[0], v.M[o[1]:o[1] + o[2]])
})
case ADD: v.Execute(func(o []int) {
a, b := v.R[o[0]], v.R[o[1]]
count := len(a)
if len(b) < len(a) { count := len(b) }
for ; count > 0; count-- { a[i] += b[i] }
})
default: panic(ILLEGAL_OPERATION)
}
})
}
Thursday, 30 May 13
package main
import . "vmachine"
import . "instructions"
func main() {
r := NewVMachine(10, 10, 8, nil)
p := []Executable{ Instruction{CONSTANT, 0, 27},
Instruction{CONSTANT, 1, 13},
Instruction{CONSTANT, 2, 10},
Instruction{ADD, 0, 1},
Instruction{ADD, 0, 2} }
r.Run(p)
fmt.Println("registers =", r.R)
}
produces:
vectors = [[50 50 50] [13 10 27] [10 27 13] [] [] [] [] [] [] []]
Thursday, 30 May 13
related projects
gospeed
raw - slices - lists - chains - sexp
wendigo
Thursday, 30 May 13
related projects
gospeed
typelib
wendigo
Thursday, 30 May 13
finding out more
http://golang.org/
twitter://#golang
http://slides.games-with-brains.net/
http://github.com/feyeleanor/
wikipedia or google
Thursday, 30 May 13

Mais conteúdo relacionado

Mais procurados

Mais procurados (20)

TensorFlow in Practice
TensorFlow in PracticeTensorFlow in Practice
TensorFlow in Practice
 
Gentlest Introduction to Tensorflow
Gentlest Introduction to TensorflowGentlest Introduction to Tensorflow
Gentlest Introduction to Tensorflow
 
Python легко и просто. Красиво решаем повседневные задачи
Python легко и просто. Красиво решаем повседневные задачиPython легко и просто. Красиво решаем повседневные задачи
Python легко и просто. Красиво решаем повседневные задачи
 
Explanation on Tensorflow example -Deep mnist for expert
Explanation on Tensorflow example -Deep mnist for expertExplanation on Tensorflow example -Deep mnist for expert
Explanation on Tensorflow example -Deep mnist for expert
 
Gentlest Introduction to Tensorflow - Part 3
Gentlest Introduction to Tensorflow - Part 3Gentlest Introduction to Tensorflow - Part 3
Gentlest Introduction to Tensorflow - Part 3
 
Gentlest Introduction to Tensorflow - Part 2
Gentlest Introduction to Tensorflow - Part 2Gentlest Introduction to Tensorflow - Part 2
Gentlest Introduction to Tensorflow - Part 2
 
파이썬으로 해보는 이미지 처리
파이썬으로 해보는 이미지 처리파이썬으로 해보는 이미지 처리
파이썬으로 해보는 이미지 처리
 
Excel function
Excel functionExcel function
Excel function
 
imager package in R and examples..
imager package in R and examples..imager package in R and examples..
imager package in R and examples..
 
NTU ML TENSORFLOW
NTU ML TENSORFLOWNTU ML TENSORFLOW
NTU ML TENSORFLOW
 
ProgrammingwithGOLang
ProgrammingwithGOLangProgrammingwithGOLang
ProgrammingwithGOLang
 
GANs
GANsGANs
GANs
 
Drinking the free kool-aid
Drinking the free kool-aidDrinking the free kool-aid
Drinking the free kool-aid
 
The groovy puzzlers (as Presented at Gr8Conf US 2014)
The groovy puzzlers (as Presented at Gr8Conf US 2014)The groovy puzzlers (as Presented at Gr8Conf US 2014)
The groovy puzzlers (as Presented at Gr8Conf US 2014)
 
Programming in lua STRING AND ARRAY
Programming in lua STRING AND ARRAYProgramming in lua STRING AND ARRAY
Programming in lua STRING AND ARRAY
 
662305 LAB13
662305 LAB13662305 LAB13
662305 LAB13
 
Basic Calculus in R.
Basic Calculus in R. Basic Calculus in R.
Basic Calculus in R.
 
The Ring programming language version 1.5.1 book - Part 61 of 180
The Ring programming language version 1.5.1 book - Part 61 of 180The Ring programming language version 1.5.1 book - Part 61 of 180
The Ring programming language version 1.5.1 book - Part 61 of 180
 
Python collections
Python collectionsPython collections
Python collections
 
Python Cheat Sheet
Python Cheat SheetPython Cheat Sheet
Python Cheat Sheet
 

Semelhante a GoLightly - a customisable virtual machine written in Go

Semelhante a GoLightly - a customisable virtual machine written in Go (20)

Something about Golang
Something about GolangSomething about Golang
Something about Golang
 
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
 
Python programming workshop session 3
Python programming workshop session 3Python programming workshop session 3
Python programming workshop session 3
 
Python avanzado - parte 1
Python avanzado - parte 1Python avanzado - parte 1
Python avanzado - parte 1
 
About Go
About GoAbout Go
About Go
 
Gentle Introduction to Functional Programming
Gentle Introduction to Functional ProgrammingGentle Introduction to Functional Programming
Gentle Introduction to Functional Programming
 
Use Applicative where applicable!
Use Applicative where applicable!Use Applicative where applicable!
Use Applicative where applicable!
 
Kristhyan kurtlazartezubia evidencia1-metodosnumericos
Kristhyan kurtlazartezubia evidencia1-metodosnumericosKristhyan kurtlazartezubia evidencia1-metodosnumericos
Kristhyan kurtlazartezubia evidencia1-metodosnumericos
 
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...
 
07012023.pptx
07012023.pptx07012023.pptx
07012023.pptx
 
Geeks Anonymes - Le langage Go
Geeks Anonymes - Le langage GoGeeks Anonymes - Le langage Go
Geeks Anonymes - Le langage Go
 
Implementing Virtual Machines in Go & C
Implementing Virtual Machines in Go & CImplementing Virtual Machines in Go & C
Implementing Virtual Machines in Go & C
 
Blocks+gcd入門
Blocks+gcd入門Blocks+gcd入門
Blocks+gcd入門
 
20181020 advanced higher-order function
20181020 advanced higher-order function20181020 advanced higher-order function
20181020 advanced higher-order function
 
Arrow 101 - Kotlin funcional com Arrow
Arrow 101 - Kotlin funcional com ArrowArrow 101 - Kotlin funcional com Arrow
Arrow 101 - Kotlin funcional com Arrow
 
Functional JS for everyone - 4Developers
Functional JS for everyone - 4DevelopersFunctional JS for everyone - 4Developers
Functional JS for everyone - 4Developers
 
Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6
 
TDC2016SP - Código funcional em Java: superando o hype
TDC2016SP - Código funcional em Java: superando o hypeTDC2016SP - Código funcional em Java: superando o hype
TDC2016SP - Código funcional em Java: superando o hype
 
Python cheatsheat.pdf
Python cheatsheat.pdfPython cheatsheat.pdf
Python cheatsheat.pdf
 
Implementing Software Machines in Go and C
Implementing Software Machines in Go and CImplementing Software Machines in Go and C
Implementing Software Machines in Go and C
 

Mais de Eleanor McHugh

Mais 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]
 
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
 
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
 
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
 
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
 
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
 
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
 

Último

Último (20)

Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 

GoLightly - a customisable virtual machine written in Go

  • 1. golightly a customisable virtual machine written in Go Eleanor McHugh http://slides.games-with-brains.net/ Thursday, 30 May 13
  • 2. portrait of an artist... physics major embedded controllers software reliability dynamic languages network scaling questionable taste in music http://github.com/feyeleanor Eleanor McHugh Thursday, 30 May 13
  • 3. go... small, safety-conscious systems language concurrency, closures & garbage collection consistently fast compilation Thursday, 30 May 13
  • 4. ...lightly agnostic virtual machine networks application performance matters non-viral open source license Thursday, 30 May 13
  • 5. agnostic no blessed programming languages flexible platform abstractions write once, run everywhere it matters Thursday, 30 May 13
  • 6. heterogeneous a system comprises many components components may differ in purpose and design but they cooperate to solve problems Thursday, 30 May 13
  • 7. networks machines cooperate by sending messages machine states can be serialised as messages messages transcend process and host boundaries Thursday, 30 May 13
  • 8. inspiration hardware design sensor and control networks field-programmable gate arrays Thursday, 30 May 13
  • 9. virtual machine emulate an existing system simulate an imagined system have dynamic control of system state Thursday, 30 May 13
  • 10. stack-based lambda calculus processor threaded value cells in a von neumann memory all operations are expressions are values lisp Thursday, 30 May 13
  • 11. stack-based processor threaded word definitions in a von neumann memory words thread primitives, word pointers and data forth Thursday, 30 May 13
  • 12. stack-based processor with instruction set harvard memory separates code and data class loaders convert bytecode to machine state jvm Thursday, 30 May 13
  • 13. linux kernel hypervisor intel X86 virtualisation with hardware execution QEMU virtual machine runs in user space kvm Thursday, 30 May 13
  • 15. package main import "fmt" const( HELLO string = "hello" WORLD string = "world" ) func main() { fmt.Println(HELLO, WORLD) } Thursday, 30 May 13
  • 17. package Integer type Int int func (i *Int) Add(x int) { *i += Int(x) } Thursday, 30 May 13
  • 18. package Integer type Buffer []Int func (b Buffer) Eq(o Buffer) (r bool) { if len(b) == len(o) { for i := len(b) - 1; i > 0; i-- { if b[i] != o[i] { return } } r = true } return } func (b Buffer) Swap(i, j int) { b[i], b[j] = b[j], b[i] } func (b Buffer) Clone() Buffer { s := make(Buffer, len(b)) copy(s, b) return s } func (b Buffer) Move(i, n int) { if n > len(b) - i { n = len(b) - i } segment_to_move := b[:i].Clone() copy(b, b[i:i + n]) copy(b[n:i + n], segment_to_move) } Thursday, 30 May 13
  • 19. package main import "Integer" func main() { i := Integer.Buffer{0, 1, 2, 3, 4, 5} b := i.Clone() b.Swap(1, 2) b.Move(3, 2) b[0].Add(3) println("b[:2] = {", b[0], ",", b[1], "}") } produces: b[0:2] = { 6, 4 } Thursday, 30 May 13
  • 20. package Integer import "testing" func TestSwap(t *testing.T) { i := Buffer{0, 1, 2, 3, 4, 5} b := i.Clone() b.Swap(1, 2) if !b[1:3].Eq(Buffer{2, 1}) { t.Fatalf("b[:5] = %v", b) } } func TestMove(t *testing.T) { i := Buffer{0, 1, 2, 3, 4, 5} b := i.Clone() b.Move(3, 2) if !b.Eq(Buffer{3, 4, 0, 1, 2, 5}) { t.Fatalf("b[:5] = %v", b) } } func TestAdd(t *testing.T) { i := Buffer{0, 1, 2, 3, 4, 5} b := i.Clone() b[0].Add(3) if b[0] != i[0] + 3 { t.Fatalf("b[:5] = %v", b) } } Thursday, 30 May 13
  • 22. package Vector import . "Integer" type Vector struct { Buffer } func (v *Vector) Clone() Vector { return Vector{v.Buffer.Clone()} } func (v *Vector) Slice(i, j int) Buffer { return v.Buffer[i:j] } Thursday, 30 May 13
  • 23. package Integer import "testing" func TestVectorSwap(t *testing.T) { i := Vector{Buffer{0, 1, 2, 3, 4, 5}} v := i.Clone() v.Swap(1, 2) r := Vector{Buffer{0, 2, 1, 3, 4, 5}} switch { case !v.Match(&r): fallthrough case !v.Buffer.Match(r.Buffer): t.Fatalf("b[:5] = %v", v) } } Thursday, 30 May 13
  • 24. package integer import "testing" func BenchmarkVectorClone6(b *testing.B) { v := Vector{Buffer{0, 1, 2, 3, 4, 5}} for i := 0; i < b.N; i++ { _ = v.Clone() } } func BenchmarkVectorSwap(b *testing.B) { b.StopTimer() v := Vector{Buffer{0, 1, 2, 3, 4, 5}} b.StartTimer() for i := 0; i < b.N; i++ { v.Swap(1, 2) } } Thursday, 30 May 13
  • 25. $ go test -test.bench="Benchmark" PASS integer.BenchmarkVectorSwap 200000000 8 ns/op integer.BenchmarkVectorClone6 10000000 300 ns/op Thursday, 30 May 13
  • 27. package adder type Adder interface { Add(j int) Subtract(j int) Result() interface{} } type Calculator interface { Adder Reset() } type AddingMachine struct { Memory interface{} Adder } Thursday, 30 May 13
  • 28. package adder type IAdder []int func (i IAdder) Add(j int) { i[0] += i[j] } func (i IAdder) Subtract(j int) { i[0] -= i[j] } func (i IAdder) Result() interface{} { return i[0] } func (i IAdder) Reset() { i[0] = *new(int) } Thursday, 30 May 13
  • 29. package adder import "testing" func TestIAdder(t *testing.T) { error := "Result %v != %v" i := IAdder{0, 1, 2} i.Add(1) if i.Result().(int) != 1 { t.Fatalf(error, i.Result(), 1) } i.Subtract(2) if i.Result().(int) != -1 { t.Fatalf(error, i.Result()), -1 } var r Calculator = IAdder{-1, 1, 2} for n, v := range r.(IAdder) { if i[n] != v { t.Fatalf("Adder %v should be %v", i, r) } } r.Reset() if r.Result().(int) != *new(int) { t.Fatalf(error, r.Result(), *new(int)) } } Thursday, 30 May 13
  • 30. package adder import "testing" func TestIAdder(t *testing.T) { error := "Result %v != %v" i := IAdder{0, 1, 2} i.Add(1) if i.Result() != 1 { t.Fatalf(error, i.Result(), 1) } i.Subtract(2) if i.Result() != -1 { t.Fatalf(error, i.Result()), -1 } var r Calculator = IAdder{-1, 1, 2} for n, v := range r.(IAdder) { if i[n] != v { t.Fatalf("Adder %v should be %v", i, r) } } r.Reset() if r.Result() != *new(int) { t.Fatalf(error, r.Result(), *new(int)) } } Thursday, 30 May 13
  • 31. package adder type FAdder []float32 func (f FAdder) Add(j int) { f[0] += f[j] } func (f FAdder) Subtract(j int) { f[0] -= f[j] } func (f FAdder) Result() interface{} { return f[0] } func (f FAdder) Reset() { f[0] = *new(float32) } Thursday, 30 May 13
  • 32. package adder import "testing" func TestFAdder(t *testing.T) { error := "Result %v != %v" f := FAdder{0.0, 1.0, 2.0} f.Add(1) if f.Result() != 1.0 { t.Fatalf(error, f.Result(), 1.0) } f.Subtract(2) if i.Result() != -1.0 { t.Fatalf(error, i.Result()), -1.0 } var r Calculator = FAdder{-1.0, 1.0, 2.0} for n, v := range r.(FAdder) { if f[n] != v { t.Fatalf("Adder %v should be %v", f, r) } } r.Reset() if r.Result() != *new(float32) { t.Fatalf(error, r.Result(), *new(float32)) } } Thursday, 30 May 13
  • 33. package adder import "testing" func TestAddingMachine(t *testing.T) { error := "Result %v != %v" a := &AddingMachine{ Adder: FAdder{0.0, 1.0, 2.0} } a.Add(1) if f, ok := a.Result().(float32); !ok { t.Fatal("Result should be a float32") } else if f != 1.0 { t.Fatalf(error, a.Result(), 1.0) } a.Subtract(2) if a.Result().(float32) != -1.0 { t.Fatalf(error, a.Result(), -1.0) } r := FAdder{-1.0, 1.0, 2.0} for n, v := range a.Adder.(FAdder) { if r[n] != v { t.Fatalf("Adder %v should be %v", a, r) } } } Thursday, 30 May 13
  • 35. goroutines concurrent execution stacks initialised with a closure scheduled automatically by the runtime Thursday, 30 May 13
  • 36. package main import "fmt" func main() { var c chan int c = make(chan int) go func() { for { fmt.Print(<-c) } }() for { select { case c <- 0: case c <- 1: } } } produces: 01100111010110... Thursday, 30 May 13
  • 37. package main import "fmt" func main() { var c chan int c = make(chan int, 16) go func() { for { fmt.Print(<-c) } }() go func() { select { case c <- 0: case c <- 1: } }() for {} } produces: 01100111010110... Thursday, 30 May 13
  • 38. package map_reduce type SignalSource func(status chan bool) func Wait(s SignalSource) { done := make(chan bool) defer close(done) go s(done) <-done } func WaitCount(count int, s SignalSource) { done := make(chan bool) defer close(done) go s(done) for i := 0; i < count; i++ { <- done } } Thursday, 30 May 13
  • 39. package map_reduce type Iteration func(k, x interface{}) func (i Iteration) apply(k, v interface{}, c chan bool) { go func() { i(k, v) c <- true }() } Thursday, 30 May 13
  • 40. package map_reduce func Each(c interface{}, f Iteration) { switch c := c.(type) { case []int: WaitCount(len(c), func(done chan bool) { for i, v := range c { f.apply(i, v, done) } }) case map[int] int: WaitCount(len(c), func(done chan bool) { for k, v := range c { f.apply(k, v, done) } }) } } Thursday, 30 May 13
  • 41. package map_reduce type Results chan interface{} type Combination func(x, y interface{}) interface{} func (f Combination) Reduce(c, s interface{}) (r Results) { r = make(Results) go func() { Each(c, func(k, x interface{}) { s = f(s, x) }) r <- s }() return } Thursday, 30 May 13
  • 42. package map_reduce type Transformation func(x interface{}) interface{} func (t Transformation) GetValue(x interface{}) interface{} { return t(x) } Thursday, 30 May 13
  • 43. func Map(c interface{}, t Transformation) (n interface{}) { var i Iteration switch c := c.(type) { case []int: m := make([]int, len(c)) i = func(k, x interface{}) { m[k] = t.GetValue(x) } n = m case map[int] int: m := make(map[int] int) i = func(k, x interface{}) { m[k] = t.GetValue(x) } n = m } if i != nil { Wait(func(done chan bool) { Each(c, i) done <- true }) } return } Thursday, 30 May 13
  • 44. package main import "fmt" import . "map_reduce" func main() { m := "%v = %v, sum = %vn" s := []int{0, 1, 2, 3, 4, 5} sum := func(x, y interface{}) interface{} { return x.(int) + y.(int) } d := Map(s, func(x interface{}) interface{} { return x.(int) * 2 }) x := <- Combination(sum).Reduce(s, 0) fmt.Printf("s", s, x) x = <- Combination(sum).Reduce(d, 0) fmt.Printf("d", d, x) } produces: s = [0 1 2 3 4 5], sum = 15 c = [0 2 4 6 8 10], sum = 30 Thursday, 30 May 13
  • 47. package clock import "syscall" type Clock struct { Period int64 Count chan int64 Control chan bool active bool } Thursday, 30 May 13
  • 48. package clock import "syscall" func (c *Clock) Start() { if !c.active { go func() { c.active = true for i := int64(0); ; i++ { select { case c.active = <- c.Control: default: if c.active { c.Count <- i } syscall.Sleep(c.Period) } } }() } } Thursday, 30 May 13
  • 49. 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") } Thursday, 30 May 13
  • 50. OSX 10.6.2 Intel Atom 270 @ 1.6GHz: pulse value 0 from clock pulse value 1 from clock pulse value 2 from clock disabling clock restarting clock pulse value 106 from clock OSX 10.6.7 Intel Core 2 Duo @ 2.4GHz: pulse value 0 from clock pulse value 1 from clock pulse value 2 from clock disabling clock restarting clock pulse value 154 from clock Thursday, 30 May 13
  • 53. package instructions import "fmt" type Operation func(o []int) type Executable interface { Opcode() int Operands() []int Execute(op Operation) } const INVALID_OPCODE = -1 type Program []Executable func (p Program) Disassemble(a Assembler) { for _, v := range p { fmt.Println(a.Disassemble(v)) } } Thursday, 30 May 13
  • 54. package instructions type Instruction []int func (i Instruction) Opcode() int { if len(i) == 0 { return INVALID_OPCODE } return i[0] } func (i Instruction) Operands() []int { if len(i) < 2 { return []int{} } return i[1:] } func (i Instruction) Execute(op Operation) { op(i.Operands()) } Thursday, 30 May 13
  • 55. package instructions type Assembler struct { opcodes map[string] int names map[int] string } func NewAssember(names... string) (a Assembler) { a = Assembler{ opcodes: make(map[string] int), names:make(map[int] string), } a.Define(names...) return } func (a Assembler) Define(names... string) { for _, name := range names { a.opcodes[name] = len(a.names) a.names[len(a.names)] = name } } Thursday, 30 May 13
  • 56. package instructions func (a Assembler) Assemble(name string, params... int) (i Instruction) { i = make(Instruction, len(params) + 1) if opcode, ok := a.opcodes[name]; ok { i[0] = opcode } else { i[0] = INVALID_OPCODE } copy(i[1:], params) return } Thursday, 30 May 13
  • 57. package instructions import "fmt" func (a Assembler) Disassemble(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 = "unknown" } return } Thursday, 30 May 13
  • 58. package main import . "instructions" func main() { a := NewAssembler("noop", "load", "store") p := Program{ a.Assemble("noop"), a.Assemble("load", 1), a.Assemble("store", 1, 2), a.Assemble("invalid", 3, 4, 5) } p.Disassemble(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]) } } } Thursday, 30 May 13
  • 59. produces: noop load 1 store 1, 2 unknown op = 2 result = 3 Thursday, 30 May 13
  • 61. package processor import . "instructions" const PROCESSOR_READY = 0 const PROCESSOR_BUSY = 1 const CALL_STACK_UNDERFLOW = 2 const CALL_STACK_OVERFLOW = 4 const ILLEGAL_OPERATION = 8 const INVALID_ADDRESS = 16 type Processor interface { Run(p []Executable) } type Core struct { Running bool PC, Flags, Ticks int CS, M []int OP Executable "Loaded OpCode" I chan Executable "Interrupts" } Thursday, 30 May 13
  • 62. package processor import . "instructions" func NewCore(CSS, MSS int, I chan Executable) *Core { return &Core{ CS:make([]int, CSS)}, M: make([]int, MSS), I: I, } } func (c *Core) Reset() { c.Running = false c.Flags = PROCESSOR_READY } func (c *Core) Goto(addr int) { c.PC = addr } Thursday, 30 May 13
  • 63. package processor func (c *Core) Call(addr int) { top := len(c.CS) if top >= cap(c.CS) - 1 { panic(CALL_STACK_OVERFLOW) } c.CS = c.CS[:top + 1] c.CS[top] = c.PC c.PC = addr } func (c *Core) TailCall(addr int) { c.CS[len(c.CS) - 1] = c.PC c.PC = addr } func (c *Core) Return() { top := len(c.CS) if top == 0 { panic(CALL_STACK_UNDERFLOW) } c.PC, c.CS = c.CS[top - 1], c.CS[:top] } Thursday, 30 May 13
  • 64. package processor import . "instructions" func (c *Core) Run(p []Executable, dispatchers... func(c *Core)) { defer func() { c.Running = false if x := recover(); x != nil { c.Flags &= x.(int) } }() switch { case c.Running: panic(PROCESSOR_BUSY) case len(dispatchers) == 0: panic(PROCESSOR_READY) default: c.Running = true c.BusyLoop(dispatchers...) } } func (c *Core) LoadInstruction(program []Executable) { if c.PC >= len(program) { panic(PROCESSOR_READY) } c.Executable = program[c.PC] c.PC++ } Thursday, 30 May 13
  • 65. package processor import . "instructions" func (c *Core) BusyLoop(p []Executable, dispatchers... func(c *Core)) { select { case interrupt <- c.I: op, pc := c.OP, c.PC for c.PC = 0; c.Running; c.Ticks++ { for _, f := range dispatchers { f(c) } c.LoadInstruction(p) } c.OP, c.PC = op, pc default: for c.PC = 0; c.Running; c.Ticks++ { c.LoadInstruction(p) for _, f := range dispatchers { f(c) } } } } Thursday, 30 May 13
  • 66. package processor import . "instructions" func (c *Core) RunExclusive(p []Executable, tracers... func(c *Core)) { defer func() { c.Running = false if x := recover(); x != nil { c.Flags &= x.(int) } }() if c.Running { panic(PROCESSOR_BUSY) } case len(dispatchers) == 0: panic(PROCESSOR_READY) c.Running = true for c.PC = 0; c.Running; c.Ticks++ { c.LoadInstruction(p) for _, f := range tracers { f(c) } } } Thursday, 30 May 13
  • 67. package main import . "processor" import . "instructions" const( CALL = iota GOTO MOVE RETURN ) c := NewCore(10, 8, nil) var dispatcher = func(c *Core) { switch c.Opcode() { case CALL: c.Execute(func(o []int) { c.Call(o[0]) }) case GOTO: c.Execute(func(o []int) { c.Goto(o[0]) }) case MOVE: c.Execute(func(o []int) { c.Goto(c.PC + o[0]) }) case RETURN: c.Execute(func(o []int) { c.Return() }) default: panic(ILLEGAL_OPERATION) } } Thursday, 30 May 13
  • 68. func main() { p := []Executable{ Instruction{ CALL, 2 }, Instruction{ GOTO, 5 }, Instruction{ MOVE, 2 }, Instruction{ RETURN }, Instruction{ MOVE, -1 } } c.RunExclusive(p, dispatcher) fmt.Printf("Instructions Executed: %vnPC = %vn", c.Ticks, c.PC) if c.Flags | PROCESSOR_READY == PROCESSOR_READY { fmt.Println("Core Ready") } else { fmt.Println("Core Error:", c.Flags) } } produces: Instructions Executed: 2 PC = 5 Core Ready Thursday, 30 May 13
  • 69. accumulator machine 1-operand instructions data from memory combined with accumulator result stored in accumulator Thursday, 30 May 13
  • 70. package accmachine import . "processor" const ( CONSTANT = iota LOAD_VALUE STORE_VALUE ADD ) type AccMachine struct { Core AC int } func NewAccMachine(CSSize, MSize int, I chan Executable) *AccMachine { return &AccMachine{ Core: NewCore(CSSize, MSize, I) } } Thursday, 30 May 13
  • 71. package accmachine import . "processor" func (a *AccMachine) Run(program []Executable) { a.RunExclusive(program, func() { switch a.Opcode() { case CONSTANT: a.Execute(func(o []int) { a.AC = o[0] }) case LOAD_VALUE: a.Execute(func(o []int) { a.AC = a.M[o[0]] }) case STORE_VALUE: a.Execute(func(o []int) { a.M[o[0]] = a.AC }) case ADD: a.Execute(func(o []int) { a.AC += a.M[o[0]] }) default: panic(ILLEGAL_OPERATION) } }) } Thursday, 30 May 13
  • 72. package main import . "accmachine" import . "instructions" func main() { a := NewAccMachine(10, 8, nil) p := []Executable{ Instruction{CONSTANT, 27}, Instruction{STORE_VALUE, 0}, Instruction{CONSTANT, 13}, Instruction{STORE_VALUE, 1}, Instruction{CONSTANT, 10}, Instruction{ADD, 1}, Instruction{ADD, 0}, Instruction{STORE_VALUE, 2} } a.Run(p) fmt.Println("accumulated value =", a.AC) } produces: accumulated value = 50 Thursday, 30 May 13
  • 73. stack machine 0-operand instructions data popped from stack results pushed on stack Thursday, 30 May 13
  • 74. package smachine import . "processor" const ( CONSTANT = iota PUSH_VALUE POP_VALUE ADD ) type StackMachine struct { Core DS []int } func NewStackM(CSSize, DSSize, MSize int, I chan Executable) *StackMachine { return &StackMachine{DS: make([]int, 0, DSSize), Core: NewCore(CSSize, MSize, I) } } Thursday, 30 May 13
  • 75. package smachine import . "processor" func (s *StackMachine) Push(v int) { top := len(s.DS) s.DS, s.DS[top] = s.DS[:top + 1], v } func (s *StackMachine) Pop(addr int) { top := len(s.DS) - 1 s.M[addr], s.DS = s.DS[top], s.DS[:top] } Thursday, 30 May 13
  • 76. package smachine import . "processor" func (s *StackMachine) Run(program []Executable) { s.RunExclusive(program, func() { switch s.Opcode() { case CONSTANT: s.Execute(func(o []int) { s.Push(o[0]) }) case PUSH_VALUE: s.Execute(func(o []int) { s.Push(s.M[o[0]]) }) case POP_VALUE: s.Execute(func(o []int) { s.Pop(s.M[o[0]]) }) case ADD: s.Execute(func(o []int) { l := len(s.DS) s.DS[l - 2] += s.DS[l - 1] s.DS = s.DS[:l - 1] }) default: panic(ILLEGAL_OPERATION) } }) } Thursday, 30 May 13
  • 77. package main import . "smachine" import . "instructions" func main() { s := NewStackM(10, 10, 8, nil) p := []Executable{ Instruction{CONSTANT, 27}, Instruction{CONSTANT, 13}, Instruction{CONSTANT, 10}, Instruction{ADD}, Instruction{ADD} } s.Run(p) fmt.Println("data stack =", s.DS) } produces: registers = [50 13 10 0 0 0 0 0 0 0] Thursday, 30 May 13
  • 78. register machine multi-operand instructions data read from memory into registers operator combines registers and stores Thursday, 30 May 13
  • 79. package rmachine import . "processor" const ( CONSTANT = iota LOAD_VALUE STORE_VALUE ADD ) type RMachine struct { Core R []int } func NewRMachine(CSSize, RSize, MSize int, I chan Executable) *RMachine { return &RMachine{ Core: NewCore(CSSize, MSize, I), R: make([]int, RSize) } } Thursday, 30 May 13
  • 80. package rmachine import . "processor" func (r *RMachine) Run(program []Executable) { r.RunExclusive(program, func() { switch r.Opcode() { case CONSTANT: r.Execute(func(o []int) { r.R[o[0]] = o[1] }) case LOAD_VALUE: r.Execute(func(o []int) { r.R[o[0]] = r.M[o[1]] }) case STORE_VALUE: r.Execute(func(o []int) { r.M[o[0]] = r.R[o[1]] }) case ADD: r.Execute(func(o []int) { r.R[o[0]] += r.R[o[1]] }) default: panic(ILLEGAL_OPERATION) } }) } Thursday, 30 May 13
  • 81. package main import . "rmachine" import . "instructions" func main() { r := NewRMachine(10, 10, 8, nil) p := []Executable{ Instruction{CONSTANT, 0, 27}, Instruction{CONSTANT, 1, 13}, Instruction{CONSTANT, 2, 10}, Instruction{ADD, 0, 1}, Instruction{ADD, 0, 2} } r.Run(p) fmt.Println("registers =", r.R) } produces: registers = [50 13 10 0 0 0 0 0 0 0] Thursday, 30 May 13
  • 82. vector machine multi-operand instructions data vectors read from memory into registers operations combine registers Thursday, 30 May 13
  • 83. package vmachine import . "processor" const ( CONSTANT = iota LOAD_VALUE STORE_VALUE ADD ) type VMachine struct { Core R [][]int } func NewVMachine(CSSize, RSize, MSize int, I chan Executable) *VMachine { return &VectorMachine{ Core: NewCore(CSSize, MSize), make([][]int, RSize) } } Thursday, 30 May 13
  • 84. package vmachine import . "processor" func (v *VMachine) Load(r int, m []int) { v.R[r] = make([]int, len(m)) copy(v.R[r], m) } Thursday, 30 May 13
  • 85. package vmachine import . "processor" func (v *VMachine) Run(program []Executable) { v.RunExclusive(program, func() { switch v.Opcode() { case CONSTANT: v.Execute(func(o []int) { v.Load(o[0], o[1:]) }) case STORE_VALUE: v.Execute(func(o []int) { copy(v.M[o[0]:], v.R[o[1]]) }) case LOAD_VALUE: v.Execute(func(o []int) { v.Load(o[0], v.M[o[1]:o[1] + o[2]]) }) case ADD: v.Execute(func(o []int) { a, b := v.R[o[0]], v.R[o[1]] count := len(a) if len(b) < len(a) { count := len(b) } for ; count > 0; count-- { a[i] += b[i] } }) default: panic(ILLEGAL_OPERATION) } }) } Thursday, 30 May 13
  • 86. package main import . "vmachine" import . "instructions" func main() { r := NewVMachine(10, 10, 8, nil) p := []Executable{ Instruction{CONSTANT, 0, 27}, Instruction{CONSTANT, 1, 13}, Instruction{CONSTANT, 2, 10}, Instruction{ADD, 0, 1}, Instruction{ADD, 0, 2} } r.Run(p) fmt.Println("registers =", r.R) } produces: vectors = [[50 50 50] [13 10 27] [10 27 13] [] [] [] [] [] [] []] Thursday, 30 May 13
  • 87. related projects gospeed raw - slices - lists - chains - sexp wendigo Thursday, 30 May 13