![Page 1: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/1.jpg)
GoLightlyBuilding VM-based language runtimes in Go
Eleanor McHugh
http://golightly.games-with-brains.net
1Friday, 15 October 2010
![Page 2: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/2.jpg)
portrait of an artist...
physics major
embedded systems
dynamic languages
dns provisioning
network scaling
questionable taste in music
http://feyeleanor.tel
Eleanor McHugh
2Friday, 15 October 2010
![Page 3: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/3.jpg)
today’s menu
an overview of golightly
a crash course in go programming
application virtualisation & soft machines
3Friday, 15 October 2010
![Page 4: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/4.jpg)
caveat lector
danger! we’re entering strange territory
our map is missing major landmarks
and will be riddled with inaccuracies
so please tread carefully
try not to disturb the local wildlife
and don’t be put off by the pages of code
4Friday, 15 October 2010
![Page 5: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/5.jpg)
golightlyagnostic heterogenous virtualisation networks
5Friday, 15 October 2010
![Page 6: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/6.jpg)
go...a systems language by google
productivity, performance, concurrency
lighter than Java, safer than C
6Friday, 15 October 2010
![Page 7: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/7.jpg)
...lightlyclean abstractions
geared to performance
non-viral open source license
7Friday, 15 October 2010
![Page 8: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/8.jpg)
inspirationprocessor design
sensor and control networks
field-programmable gate arrays
8Friday, 15 October 2010
![Page 9: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/9.jpg)
perspirationiterative empirical development
explore -> implement -> test -> benchmark
evolve towards elegance
9Friday, 15 October 2010
![Page 10: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/10.jpg)
principlesdecoupling improves scalability
coherence simplifies organisation
optimisations are application specific
10Friday, 15 October 2010
![Page 11: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/11.jpg)
agnosticno blessed programming languages
flexible platform abstractions
write once, run everywhere it matters
11Friday, 15 October 2010
![Page 12: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/12.jpg)
heterogeneousa system comprises many components
components may differ in purpose and design
but they cooperate to solve problems
12Friday, 15 October 2010
![Page 13: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/13.jpg)
virtualisationdesign discrete Turing machines
implement these machines in software
compile programs to run on them
13Friday, 15 October 2010
![Page 14: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/14.jpg)
networksmachines cooperate by sending messages
machine states can be serialised as messages
messages transcend process and host boundaries
14Friday, 15 October 2010
![Page 15: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/15.jpg)
goa crash course
15Friday, 15 October 2010
![Page 16: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/16.jpg)
behind the hype
a statically-typed compiled language
class-free object-orientation
nominal type declaration
structural type inference
garbage collection
concurrency via communication (CSP)
16Friday, 15 October 2010
![Page 17: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/17.jpg)
an elegant tool
the safety of a static type system
the feel of a dynamic runtime
the performance of a compiled language
no dependence on runtime libraries
17Friday, 15 October 2010
![Page 18: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/18.jpg)
nominal types
primitive (boolean, numeric, pointer)
aggregate (array, slice, map, struct)
functional (closure, channel)
all types can underpin user-defined types
methods are declared on user-defined types
types can be embedded in struct types
18Friday, 15 October 2010
![Page 19: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/19.jpg)
package Integer
type Int int
func (i *Int) Add(x int) {*i += Int(x)
}
type Buffer []Int
func (b Buffer) Clone() Buffer {s := make(Buffer, len(b))copy(s, b)return s
}
func (b Buffer) Swap(i, j int) {b[i], b[j] = b[j], b[i]
}
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)
}
package mainimport “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[0:2] = {”, b[0], “,”, b[1], “}”)
}
produces:b[0:2] = { 6, 4 }
19Friday, 15 October 2010
![Page 20: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/20.jpg)
package Vectorimport . “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]
}
func (v *Vector) Replace(o interface{}) {switch o := o.(type) {case Vector:
v = ocase Buffer:
v.Buffer = o}
}
package mainimport “Integer”
func main() {i := Vector{Buffer{0, 1, 2, 3, 4, 5}}b := i.Clone()b.Swap(1, 2)b.Move(3, 2)s := b.Slice(0, 2)s[0].Add(3)b.Replace(s)println(“b[0:2] = {”, b.Buffer[0], “,”, b.Buffer[1], “}”)
}
produces:b[0:2] = { 6, 4 }
20Friday, 15 October 2010
![Page 21: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/21.jpg)
structural types
interfaces define method sets
they can be embedded within each other
but do not implement methods
a type can implement many interfaces
type inference determines which if any
all types implement the blank interface
21Friday, 15 October 2010
![Page 22: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/22.jpg)
package main
type Adder interface { Add(j int) Subtract(j int) Result() interface{}}
type IntAdder []intfunc (i IntAdder) Add(j int) { i[0] += i[j]}func (i IntAdder) Subtract(j int) { i[0] -= i[j]}func (i IntAdder) Result() interface{} { return i[0]}
type FloatAdder []floatfunc (f FloatAdder) Add(j int) { f[0] += f[j]}func (f FloatAdder) Subtract(j int) { f[0] -= f[j]}func (f FloatAdder) Result() interface{} { return f[0]}
type Calculator struct { Adder}
func main() {c := Calculator{}c.Adder = IntAdder{0, 1, 2, 3, 4, 5}c.Add(1) c.Add(2)c.Subtract(3)println("c.Result() =", c.Result().(int))
c.Adder = FloatAdder{0.0, 1.1, 2.2, 3.3, 4.4, 5.5}c.Add(1)c.Add(2)c.Subtract(3)println("c.Result() =", c.Result())
}
produces:c.Result() = 0c.Result() = (0x10f94,0x34800000)
22Friday, 15 October 2010
![Page 23: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/23.jpg)
dynamic typing
type assertions
type switches
runtime reflection
23Friday, 15 October 2010
![Page 24: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/24.jpg)
package generaliseimport "fmt"import . "reflect"
func Allocate(i interface{}, limit... int) (n interface{}) {switch v := NewValue(i).(type) {case *SliceValue:
l := v.Cap()if len(limit) > 0 { l = limit[0] }t := v.Type().(*SliceType)n = MakeSlice(t, l, l).Interface()
case *MapValue:n = MakeMap(v.Type().(*MapType)).Interface()
}return
}
func SwapSlices(i interface{}, d, s, n int) {if v, ok := NewValue(i).(*SliceValue); ok {
source := v.Slice(s, s + n)destination := v.Slice(d, d + n)temp := NewValue(Allocate(i, n)).(*SliceValue)ArrayCopy(temp, destination)ArrayCopy(destination, source)ArrayCopy(source, temp)
}}
func Duplicate(i interface{}) (clone interface{}) {if clone = Allocate(i); clone != nil {
switch clone := NewValue(clone).(type) {case *SliceValue:
s := NewValue(i).(*SliceValue)ArrayCopy(clone, s)
case *MapValue:m := NewValue(i).(*MapValue)for _, k := range m.Keys() {
clone.SetElem(k, m.Elem(k))}
}}return
}
24Friday, 15 October 2010
![Page 25: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/25.jpg)
package mainimport . “generalise”
func main() {error_text := “panic caused by”defer func() {
if x := recover(); x != nil {fmt.Println(error_text, x)
}}()
s1 := []int{0, 1, 2, 3, 4, 5}fmt.Println("s1 =", s1)s2 := Duplicate(s1)fmt.Println("s2 =", s2, "Duplicate(s1)")SwapSlices(s2, 0, 3, 3)fmt.Println("s2 =", s2, "SwapSlices(s2, 0, 3, 3)")s3 := Allocate(s1, 1)fmt.Println("s3 =", s3, "Allocate(s1, 1)")
m := map[int] int{1: 1, 2: 2, 3: 3, 0: 0, 4: 4, 5: 5}fmt.Println("m =", m)n := Allocate(m)fmt.Println("n =", n, "Allocate(m)")SwapSlices(m, 0, 3, 3)
}
produces:s1 = [0 1 2 3 4 5]s2 = [0 1 2 3 4 5] Duplicate(s1)s2 = [3 4 5 0 1 2] SwapSlices(s2, 0, 3, 3)s3 = [0] Allocate(s1, 1)m = map[3:3 0:0 1:1 4:4 5:5 2:2]n = map[]panic caused by map[3:3 0:0 1:1 4:4 5:5 2:2]
25Friday, 15 October 2010
![Page 26: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/26.jpg)
goroutines
concurrent threads of control
launched by the go statement
which returns immediately
each may be a function call or method call
and can communicate via channels
26Friday, 15 October 2010
![Page 27: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/27.jpg)
channels
link concurrently executing functions
support sending and/or receiving
only accept items of a specified type
synchronous channels are unbuffered
asynchronous channels are buffered
27Friday, 15 October 2010
![Page 28: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/28.jpg)
package generaliseimport . "reflect"
type Results chan interface{}
type SignalSource func(status chan bool)func (s SignalSource) Pipeline() {
done := make(chan bool)defer close(done)go s(done)<-done
}
func (s SignalSource) Multiplex(count int) {done := make(chan bool)defer close(done)go s(done)for i := 0; i < count; i++ {
<- done}
}
type Iteration func(k, x interface{})func (i Iteration) apply(k, v interface{}, c chan bool) {
go func() {i(k, v)c <- true
}()}
func (f Iteration) Each(c interface{}) {switch c := NewValue(c).(type) {case *SliceValue:
count := c.Len()SignalSource(func(done chan bool) {
for i := 0; i < count; i++ {f.apply(i, c.Elem(i).Interface(), done)
}}).Multiplex(count)
case *MapValue:SignalSource(func(done chan bool) {
for _, k := range c.Keys() {f.apply(k, c.Elem(k).Interface(), done)
}}).Multiplex(c.Len())
}}
type Combination func(x, y interface{}) interface{} func (f Combination) Reduce(c, s interface{}) (r Results) {
r = make(Results)go func() {
Iteration(func(k, x interface{}) {s = f(s, x)
}).Each(c)r <- s
}()return
}
28Friday, 15 October 2010
![Page 29: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/29.jpg)
type Transformation func(x interface{}) interface{} func (t Transformation) GetValue(x interface{}) Value {
return NewValue(t(x))}
func (t Transformation) Map(c interface{}) interface{} {switch n := NewValue(Allocate(c)).(type) {case *SliceValue:
SignalSource(func(done chan bool) {Iteration(func(k, x interface{}) {
n.Elem(k.(int)).SetValue(t.GetValue(x))}).Each(c)done <- true
}).Pipeline()return n.Interface()
case *MapValue:SignalSource(func(done chan bool) {
Iteration(func(k, x interface{}) {n.SetElem(NewValue(k), t.GetValue(x))
}).Each(c)done <- true
}).Pipeline()return n.Interface()
}return Duplicate(c)
}
package mainimport “fmt”import . “generalise”
var adder Combination = func(x, y interface{}) interface{} { return x.(int) + y.(int)}
var multiplier Transformation = func(x interface{}) interface{} { return x.(int) * 2}
func main() {s := []int{0, 1, 2, 3, 4, 5}fmt.Println("s =", s)fmt.Println("sum s =", (<- adder.Reduce(s, 0)).(int))
c := multiplier.Map(s)fmt.Println("c =", c)fmt.Println("sum c =", (<- adder.Reduce(c, 0)).(int))
}
produces:s = [0 1 2 3 4 5]sum s = 15c = [0 2 4 6 8 10]sum c = 30
29Friday, 15 October 2010
![Page 30: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/30.jpg)
tooling
gotest is a testing framework
which also supports benchmarking
gofmt standardises code layout
godoc formats and serves documentation
goinstall is an automatic package installer
cgo integrates C code with go
30Friday, 15 October 2010
![Page 31: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/31.jpg)
software machinesapplication virtualisation 101
31Friday, 15 October 2010
![Page 32: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/32.jpg)
system clocksynchronising components
32Friday, 15 October 2010
![Page 33: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/33.jpg)
package clockimport "syscall"
type Clock struct {Period int64Count chan int64Control chan boolactive bool
}
func (c *Clock) Start() {if !c.active {
go func() {c.active = truefor i := int64(0); ; i++ {
select {case status := <- c.Control:
c.active = statusdefault:
if c.active {c.Count <- i
}syscall.Sleep(c.Period)
}}
}()}
}
package mainimport . “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 <- falsesyscall.Sleep(1000000)println("restarting clock")c.Control <- trueprintln("pulse value", <-c.Count, "from clock")
}
produces:pulse value 0 from clockpulse value 1 from clockpulse value 2 from clockdisabling clockrestarting clockpulse value 106 from clock
33Friday, 15 October 2010
![Page 34: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/34.jpg)
instruction setspecifying operation sequences
34Friday, 15 October 2010
![Page 35: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/35.jpg)
package instructionsimport "fmt"
type Operation func(o []int)
type Executable interface {Opcode() intOperands() []intExecute(op Operation)
}
const INVALID_OPCODE = -1
type Instruction []intfunc (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())
}
type Assembler struct {opcodes map[string] intnames map[int] string
}
func NewAssember(names... string) (a Assembler) {a = Assembler{ make(map[string] int), make(map[int] string) }a.Define(names...)return
}
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 }
35Friday, 15 October 2010
![Page 36: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/36.jpg)
func (a Assembler) Define(names... string) {for _, name := range names {
a.opcodes[name] = len(a.names)a.names[len(a.names)] = name
}}
func (a Assembler) Disassemble(e Executable) (s string) {if name, ok := a.names[e.Opcode()]; ok {
s = nameif params := e.Operands(); len(params) > 0 {
s = fmt.Sprintf("%v\t%v", s, params[0])for _, v := range params[1:] {
s = fmt.Sprintf("%v, %v", s, v)}
}} else {
s = "unknown"}return
}
type Program []Executablefunc (p Program) Disassemble(a Assembler) {
for _, v := range p {fmt.Println(a.Disassemble(v))
}}
package mainimport . “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])
}}
}
produces:noopload!! 1store! 1, 2unknownop = 2 result = 3
36Friday, 15 October 2010
![Page 37: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/37.jpg)
CISCsemantically rich instructions
complex memory addressing modes
compact binary code
37Friday, 15 October 2010
![Page 38: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/38.jpg)
RISCseparate IO and data processing
register-to-register instructions
load/store memory access
38Friday, 15 October 2010
![Page 39: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/39.jpg)
VLIWmultiple operations per instruction
compiler statically determines parallelism
simplifies control logic
39Friday, 15 October 2010
![Page 40: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/40.jpg)
memorystoring data and instructions
40Friday, 15 October 2010
![Page 41: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/41.jpg)
subtletiesvon Neumann
Harvard
indirection bits
41Friday, 15 October 2010
![Page 42: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/42.jpg)
package memoryimport "fmt"import . "reflect"import "unsafe"
var _BYTE_SLICE = Typeof([]byte(nil))var _SLICE_TYPE = Typeof(SliceHeader{})
func Data(addr unsafe.Pointer) []byte {return unsafe.Unreflect(_BYTE_SLICE, addr).([]byte)
}
func Resize(h *SliceHeader, d, m int) {h.Len /= dh.Len *= m
}
func Serialise(i interface{}) []byte {switch i := NewValue(i).(type) {case *SliceValue:
h := Header(unsafe.Pointer(i.Addr()))t := i.Type().(*SliceType)Resize(&h, 1, int(t.Elem().Size()))return Data(unsafe.Pointer(&h))
}return nil
}
func Overwrite(i interface{}, b []byte) interface{} {switch i := NewValue(i).(type) {case *SliceValue:
h := Header(unsafe.Pointer(&b))t := i.Type().(*SliceType)Resize(&h, int(t.Elem().Size()), 1)return unsafe.Unreflect(t, unsafe.Pointer(&h))
}return nil
}
42Friday, 15 October 2010
![Page 43: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/43.jpg)
package mainimport “fmt”import . "memory"
type Memory []int
func main() { m := make(Memory, 2) fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m) b := Serialise(m) fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b)
n := Overwrite(m, []byte{0, 0, 0, 1, 0, 0, 0, 1}).(Memory) fmt.Println("n (cells) =", len(n), "of", cap(n), ":", n)
b = Serialise(n) fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b)}
produces:m (cells) = 2 of 2 : [0 0]b (bytes) = 8 of 2 : [0 0 0 0 0 0 0 0]n (cells) = 2 of 8 : [16777216 16777216]b (bytes) = 8 of 8 : [0 0 0 1 0 0 0 1]
43Friday, 15 October 2010
![Page 44: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/44.jpg)
processor coretying it all together
44Friday, 15 October 2010
![Page 45: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/45.jpg)
package processorimport . “instructions”import . “memory”
const PROCESSOR_READY = 0const PROCESSOR_BUSY = 1const CALL_STACK_UNDERFLOW = 2const CALL_STACK_OVERFLOW = 4const ILLEGAL_OPERATION = 8const INVALID_ADDRESS = 16
type Processor interface {! Run(p []Executable)}
type Core struct {Ticks! ! intRunning! boolPC, Flags! intCS! ! []intM! ! MemoryOP! ! Executable
}
func NewCore(CSSize, MSize int) ProcessorCore {return Core{
CS: make([]int, 0, Calls)},M: make(Memory, MSize),
}}
func (p *Core) Reset() {p.Running = falsep.Flags = PROCESSOR_READY
}
func (c *Core) RunExclusive(p []Executable, f func()) {defer func() {
c.Running = falseif x := recover(); x != nil {
c.Flags &= x.(int)}
}()if c.Running {
panic(PROCESSOR_BUSY)}c.Running = truefor c.PC = 0; c.Running; {
c.LoadInstruction(p)f()c.Ticks++
}}
func (c *Core) LoadInstruction(program []Executable) {if c.PC >= len(program) {
panic(PROCESSOR_READY)}c.Executable = program[c.PC]c.PC++
}
45Friday, 15 October 2010
![Page 46: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/46.jpg)
package processor
func (c *Core) Goto(addr int) {! c.PC = addr}
func (c *Core) Call(addr int) {if top := len(c.CS); top < cap(c.CS) - 1 {
c.CS = c.CS[:top + 1]c.CS[top] = c.PCc.PC = addr
} else {panic(CALL_STACK_OVERFLOW)
}}
func (c *Core) TailCall(addr int) {! c.CS[len(c.CS) - 1] = c.PC! c.PC = addr}
func (c *Core) Return() {! if top := len(c.CS); top > 0 {! ! c.PC, c.CS = c.CS[top - 1], c.CS[:top]! } else {! ! panic(CALL_STACK_UNDERFLOW)! }}
46Friday, 15 October 2010
![Page 47: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/47.jpg)
package mainimport . “processor”import . “instructions”
const (CALL = iotaGOTOMOVERETURN
)
var dispatcher = func() {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)}
}
func main() {c := NewCore(10, 8)p := []Executable{
Instruction{CALL, 2},Instruction{GOTO, 5},Instruction{MOVE, 2},Instruction{RETURN},Instruction{MOVE, -1},
}c.RunExclusive(p, dispatcher)fmt.Println("Instructions Executed:", c.Ticks)fmt.Println("PC =", c.PC)if c.Flags | PROCESSOR_READY == PROCESSOR_READY {
fmt.Println("Core Ready")} else {
fmt.Println("Core Error:", c.Flags)}
}
produces:top = 0cap(c.CS) -1 = 9Instructions Executed: 2PC = 5Core Ready
47Friday, 15 October 2010
![Page 48: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/48.jpg)
accumulator machine1-operand instructions
data from memory combined with accumulator
result stored in accumulator
48Friday, 15 October 2010
![Page 49: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/49.jpg)
package accmachineimport . “processor”import . “memory”
const (CONSTANT = iotaLOAD_VALUESTORE_VALUEADD
)
type AccMachine struct {! Core! AC! ! ! ! int}
func NewAccMachine(CSSize, MSize int) *AccMachine {! return &AccMachine{NewCore(CSSize, MSize), 0}}
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)}
})}
49Friday, 15 October 2010
![Page 50: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/50.jpg)
package mainimport . “accmachine”import . “instructions”
func main() {a := NewAccMachine(10, 8)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
50Friday, 15 October 2010
![Page 51: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/51.jpg)
stack machine0-operand instructions
data popped from stack
results pushed on stack
51Friday, 15 October 2010
![Page 52: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/52.jpg)
package smachineimport . “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)}
})}
type StackMachine struct {CoreDS! []int
}
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) - 1s.M[addr], s.DS = s.DS[top], s.DS[:top]
}
const (CONSTANT = iotaPUSH_VALUEPOP_VALUEADD
)
func NewStackM(CSSize, DSSize, MSize int) *StackMachine {return &StackMachine{
DS: make([]int, 0, DSSize),Core: NewCore(CSSize, MSize),
}}
52Friday, 15 October 2010
![Page 53: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/53.jpg)
package mainimport . “smachine”import . “instructions”
func main() {s := NewStackM(10, 10, 8)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]
53Friday, 15 October 2010
![Page 54: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/54.jpg)
register machinemulti-operand instructions
data read from memory into registers
operator combines registers and stores
54Friday, 15 October 2010
![Page 55: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/55.jpg)
package rmachineimport . “processor”
func (r *RegisterMachine) 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)! ! }! })}
type RegisterMachine struct {! Core! R! ! Memory}
const (CONSTANT = iotaLOAD_VALUESTORE_VALUEADD
)
func NewRMachine(CSSize, RSize, MSize int) *RegisterMachine {return &RegisterMachine{
NewCore(CSSize, MSize),make([]int, RSize)
}}
55Friday, 15 October 2010
![Page 56: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/56.jpg)
package mainimport . “rmachine”import . “instructions”
func main() {r := NewRMachine(10, 10, 8)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]
56Friday, 15 October 2010
![Page 57: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/57.jpg)
transport triggeringregister machine architecture
exposes internal buses and components
operations are side-effects of internal writes
57Friday, 15 October 2010
![Page 58: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/58.jpg)
vector machinemulti-operand instructions
data vectors read from memory into registers
operations combine registers
58Friday, 15 October 2010
![Page 59: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/59.jpg)
package vmachineimport . “processor”
func (v *VectorMachine) Run(program []Executable) {v.RunExclusive(program, func() {
switch v.Opcode() {case CONSTANT:
v.Execute(func(o []int) { v.Load(o[0], o[1:]) })case LOAD_VALUE:
v.Execute(func(o []int) {v.Load(o[0], v.M[o[1]:o[1] + o[2]])
})case STORE_VALUE:
v.Execute(func(o []int) {copy(v.M[o[0]:], v.R[o[1]])
})case ADD:
v.Execute(func(o []int) {a, b := v.R[o[0]], v.R[o[1]]if len(a) < len(b) {
for i, x := range a { a[i] = x + b[i] }} else {
for i, x := range b { a[i] += x }}
})! ! default:! ! ! panic(ILLEGAL_OPERATION)! ! }! })}
type VectorMachine struct {! Core! R! ! []Memory}
func (v *VectorMachine) Load(r int, m Memory) {! v.R[r] = make(Memory, len(m))! copy(v.R[r], m)}
func NewVMachine(CSSize, RSize, MSize int) *VectorMachine {! return &VectorMachine{
NewCore(CSSize, MSize),make([]Memory, RSize)
}}
const (CONSTANT = iotaLOAD_VALUESTORE_VALUEADD
)
59Friday, 15 October 2010
![Page 60: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/60.jpg)
package mainimport . “vmachine”import . “instructions”
func main() {r := NewVMachine(10, 10, 8)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] [] [] [] [] [] [] []]
60Friday, 15 October 2010
![Page 61: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/61.jpg)
superscalarmultiple execution units
processor caching
out-of-order execution
61Friday, 15 October 2010
![Page 62: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/62.jpg)
close to the machineinterrupts
transport buses
peripheral drivers
62Friday, 15 October 2010
![Page 63: GoLightly: Building VM-based language runtimes in Go](https://reader033.vdocuments.us/reader033/viewer/2022061200/5477c329b4af9fd5138b4668/html5/thumbnails/63.jpg)
finding out more
http://golightly.games-with-brains.net
http://github.com/feyeleanor/GoLightly
twitter://#golightly
wikipedia
63Friday, 15 October 2010