SlideShare a Scribd company logo
1 of 134
GoLightly
Building VM-based language runtimes in Go


            Eleanor McHugh

   http://slides.games-with-brains.net/
portrait of an artist...
physics major




                         http:/ feyele
embedded controllers




                               /
software reliability

dynamic languages

network scaling               or.tel   an

questionable taste in music                 Elean or McHugh
Languages             Project

    ?       fluid-dynamics simulation

    ?       cockpit autopilot controller

    ?        paramilitary cockpit C4I

    ?         broadcast automation

    ?            encrypted RDBM

    ?          Unix kernel scripting
Language                 Project

     ICON         fluid-dynamics simulation

     ASM          cockpit autopilot controller

     VB5           paramilitary cockpit C4I

VB5, ASM, K&R C     broadcast automation

  RUBY, DNS            encrypted RDBM

     RUBY            Unix kernel scripting
software
a tutorial on Google Go
wizardry
simulating machines in software
wild romance
    golightly
Elric sent his mind into twisting tunnels of logic,
across endless plains of ideas, through mountains
 of symbolism and endless universes of alternate
truths; he sent his mind out further and further
 and as it went he sent with it the words which
 issued from his writhing lips -- words that few
    of his contemporaries would understand...

     - Elric of Melniboné, Michael Moorcock
golightly
agnostic heterogenous virtualisation networks
go...
    a systems language by google

productivity, performance, concurrency

   lighter than Java, safer than C
...lightly
     clean abstractions

  geared to performance

non-viral open source license
inspiration
      processor design

 sensor and control networks

field-programmable gate arrays
perspiration
     iterative empirical development

explore -> implement -> test -> benchmark

         evolve towards elegance
principles
   decoupling improves scalability

 coherence simplifies organisation

optimisations are application specific
agnostic
 no blessed programming languages

    flexible platform abstractions

write once, run everywhere it matters
heterogeneous
   a system comprises many components

components may differ in purpose and design

   but they cooperate to solve problems
virtualisation
   design discrete Turing machines

implement these machines in software

  compile programs to run on them
networks
   machines cooperate by sending messages

 machine states can be serialised as messages

messages transcend process and host boundaries
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
go
an elegant language
a statically-typed compiled language

object-oriented

static type declaration

dynamic type inference

garbage collection

concurrency via communication (CSP)
hello world
package main

import “fmt”

const(
  HELLO string = “hello”
  WORLD string = “world”
)

func main() {
  fmt.Println(HELLO, WORLD)
}
objects
boolean, numeric, array
  value
                   structure, interface


reference   pointer, slice, string, map, channel


function        function, method, closure
underlying               method
  type                    set
             expressed
               type
underlying               method
  type                    set
             expressed
               type




             embedded
               types
user-defined type
package Integer

type Int int

func (i *Int) Add(x int) {
  *i += Int(x)
}
package Integer                         func (b Buffer) Clone() Buffer {
                                          s := make(Buffer, len(b))
type Buffer []Int                         copy(s, b)
                                          return s
func (b Buffer) Eq(o Buffer) (r bool) { }
  if len(b) == len(o) {
    for i := len(b) - 1; i > 0; i-- {   func (b Buffer) Move(i, n int) {
       if b[i] != o[i] {                  if n > len(b) - i {
         return                              n = len(b) - i
       }                                  }
    }                                     segment_to_move := b[:i].Clone()
    r = true                              copy(b, b[i:i + n])
  }                                       copy(b[n:i + n],
  return                                  segment_to_move)
}                                       }

func (b Buffer) Swap(i, j int) {
  b[i], b[j] = b[j], b[i]
}
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[0:2] = {”, b[0], “,”, b[1], “}”)
}




                                                produces:
                                                   b[0:2] = { 6, 4 }
testing
include $(GOROOT)/src/Make.inc

TARG=integer

GOFILES=integer.go

include $(GOROOT)/src/Make.pkg
package Integer                        func (b Buffer) Swap(i, j int) {
                                         b[i], b[j] = b[j], b[i]
type Int int                           }
func (i *Int) Add(x int) {
  *i += Int(x)                          func (b Buffer) Clone() Buffer {
}                                         s := make(Buffer, len(b))
                                          copy(s, b)
type Buffer []Int                         return s
func (b Buffer) Eq(o Buffer) (r bool) { }
  if len(b) == len(o) {
    for i := len(b) - 1; i > 0; i-- {   func (b Buffer) Move(i, n int) {
       if b[i] != o[i] {                  if n > len(b) - i {
         return                              n = len(b) - i
       }                                  }
    }                                     segment_to_move := b[:i].Clone()
    r = true                              copy(b, b[i:i + n])
  }                                       copy(b[n:i + n],
  return                                  segment_to_move)
}                                       }
package Integer                          func TestAdd(t *testing.T) {
import “testing”                           i := Buffer{0, 1, 2, 3, 4, 5}
                                           b := i.Clone()
func TestSwap(t *testing.T) {              b[0].Add(3)
  i := Buffer{0, 1, 2, 3, 4, 5}            if b[0] != i[0] + 3 {
  b := i.Clone()                             t.Fatalf("b[0:5] = %v", b)
  b.Swap(1, 2)                             }
  if !b[1:3].Eq(Buffer{2, 1}) {          }
    t.Fatalf("b[0: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[0:5] = %v", b)
  }
}
type embedding
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]
}
include $(GOROOT)/src/Make.inc

TARG=integer

GOFILES=
 integer.go
 vector.go

include $(GOROOT)/src/Make.pkg
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[0:5] = %v", v)
  }
}
benchmarking
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)
  }
}
$ gotest -bench="Benchmark"
rm -f _test/scripts.a
6g -o _gotest_.6 integer.go vector.go nominal_typing_test.go
embedded_typing_benchmark_test.go embedded_typing_test.go
rm -f _test/scripts.a
gopack grc _test/scripts.a _gotest_.6
PASS
integer.BenchmarkVectorSwap! 200000000!             8 ns/op
integer.BenchmarkVectorClone6! 10000000!        300 ns/op
dynamism & reflection
package adder

type Adder interface {
  Add(j int)
  Subtract(j int)
  Result() interface{}
}

type Calculator interface {
  Adder
  Reset()
}

type AddingMachine struct {
  Memory interface{}
  Adder
}
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)
}
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))
  }
}
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)
}
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().(float32) != 1.0 { t.Fatalf(error, f.Result(), 1.0) }
  f.Subtract(2)
  if i.Result().(float32) != -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().(float32) != *new(float32) {
    t.Fatalf(error, r.Result(), *new(float32))
  }
}
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) }
  }
}
package generalise
import "reflect"

func Allocate(i interface{}, limit... int) (n interface{}) {
  v := reflect.NewValue(i)
  switch v := v.(type) {
  case *reflect.SliceValue:
    l := v.Cap()
    if len(limit) > 0 { l = limit[0] }
    t := v.Type().(*reflect.SliceType)
    n = reflect.MakeSlice(t, l, l).Interface()
  case *reflect.MapValue:
    t := v.Type().(*reflect.MapType)
    n = reflect.MakeMap(t).Interface()
  }
  return
}
package generalise
import . "reflect"

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)
     Copy(temp, destination)
     Copy(destination, source)
     Copy(source, temp)
  } else {
     panic(i)
  }
}
package generalise
import . "reflect"

func Duplicate(i interface{}) (clone interface{}) {
  if clone = Allocate(i); clone != nil {
     switch clone := NewValue(clone).(type) {
     case *SliceValue:
       s := NewValue(i).(*SliceValue)
       Copy(clone, s)
     case *MapValue:
       m := NewValue(i).(*MapValue)
       for _, k := range m.Keys() {
         clone.SetElem(k, m.Elem(k))
       }
     }
  }
  return
}
package generalise

import "testing"

func throwsPanic(f func()) (b bool) {
  defer func() {
    if x := recover(); x != nil {
      b = true
    }
  }()
  f()
  return
}
func TestAllocate(t *testing.T) {
  var s2 []int

    s1 := []int{0, 1, 2}
    m := map[int] int{1: 1, 2: 2, 3: 3}
    switch {
    case throwsPanic(func() { s2 = Allocate(s1, 1).([]int) }):
      t.Fatal("Unable to allocate new slice")
    case len(s2) != 1: fallthrough
    case cap(s2) != 1:
      t.Fatal("New slice should be %v not %v", make([]int, 0, 1), s2)
    case throwsPanic(func() { Allocate(m) }):
      t.Fatal("Unable to allocate new map")
    }
}
func TestDuplicate(t *testing.T) {
  error := "Duplicating %v produced %v"
  s1 := []int{0, 1, 2}
  var s2 []int
  m1 := map[int]int{1: 1, 2: 2, 3: 3}
  var m2 map[int]int

    switch {
    case throwsPanic(func() { s2 = Duplicate(s1).([]int) }):
      t.Fatalf("Unable to duplicate slice %vn", s1)
    case len(s1) != len(s2): fallthrough
    case cap(s1) != cap(s2): fallthrough
    case s1[0] != s2[0] || s1[1] != s2[1] || s1[2] != s2[2]:
      t.Fatalf(error, s1, s2)
    case throwsPanic(func() { m2 = Duplicate(m1).(map[int]int) }):
      t.Fatalf("Unable to duplicate map %vn", m1)
    case len(m1) != len(m2): fallthrough
    case m1[1] != m2[1] || m1[2] != m2[2] || m1[3] != m2[3]:
      t.Fatalf(error, m1, m2)
    }
}
func TestSwapSlices(t *testing.T) {
  error := "%v became %v but should be %v"
  s1 := []int{0, 1, 2, 3, 4, 5}
  s2 := Duplicate(s1).([]int)
  r := []int{3, 4, 5, 0, 1, 2}
  m := map[int] int{1: 1, 2: 2}

    switch {
    case !throwsPanic(func() { SwapSlices(m, 0, 3, 3) }):
      t.Fatalf("Successfully swapped slices %vn", m)
    case throwsPanic(func() { SwapSlices(s2, 0, 3, 3) }):
      t.Fatalf("Unable to swap slices %vn", s2)
    case len(s2) != len(r):
      t.Fatalf(error, s1, s2, r)
    default:
      for i, v := range s2 {
        if r[i] != v { t.Fatalf(error, s1, s2, r) }
      }
    }
}
mutability
package raw
import . "reflect"
import "unsafe"

var _BYTE_SLICE! Type
var _STRING! ! Type
           !

func init() {
  _BYTE_SLICE = Typeof([]byte(nil))
  _STRING = Typeof("")
}

type MemoryBlock interface {
  ByteSlice() []byte
}
func SliceHeader(i interface{}) (Header *SliceHeader, Size, Align int) {
  value := NewValue(i)
  switch value := value.(type) {
  case *SliceValue:
    Header = (*SliceHeader)(unsafe.Pointer(value.UnsafeAddr()))
    t := value.Type().(*SliceType).Elem()
    Size = int(t.Size())
    Align = t.Align()
  case nil:! ! ! ! ! panic(i)
           !
  case *InterfaceValue:! Header, Size, Align = SliceHeader(value.Elem())
  case *PtrValue:! ! ! Header, Size, Align = SliceHeader(value.Elem())
  }
  return
}
func Scale(oldHeader *SliceHeader, oldESize, newESize int) (h *SliceHeader) {
! if oldHeader != nil {
! ! s := float64(oldESize) / float64(newESize)
! ! h = &SliceHeader{ Data: oldHeader.Data }
! ! h.Len = int(float64(oldHeader.Len) * s)
! ! h.Cap = int(float64(oldHeader.Cap) * s)
! }
! return
}
func ByteSlice(i interface{}) []byte {
  switch b := i.(type) {
  case []byte:! ! ! ! ! ! return b
  case MemoryBlock:! ! ! ! return b.ByteSlice()
  case nil:! ! ! ! ! ! ! return []byte{}
            !
  }
  var header *SliceHeader
  value := NewValue(i)
  switch value := value.(type) {
  case nil:! ! ! ! ! ! ! return []byte{}
            !
  case Type:! ! ! ! ! ! ! panic(i)
  case *MapValue:! ! ! ! ! panic(i)
  case *ChanValue:! ! ! ! ! panic(i)
  case *InterfaceValue:! ! ! return ByteSlice(value.Elem())
  case *PtrValue:
    if value := value.Elem(); value == nil {
       return ByteSlice(nil)
    } else {
       size := int(value.Type().Size())
       header = &SliceHeader{ value.UnsafeAddr(), size, size }
    }
case *SliceValue:
      h, s, _ := SliceHeader(i)
      header = Scale(h, s, 1)
    case *StringValue:
      s := value.Get()
      h := *(*StringHeader)(unsafe.Pointer(&s))
      header = &SliceHeader{ h.Data, h.Len, h.Len }
    default:
      size := int(value.Type().Size())
      header = &SliceHeader{ value.UnsafeAddr(), size, size }
    }
    return unsafe.Unreflect(_BYTE_SLICE, unsafe.Pointer(header)).([]byte)
}
concurrency
goroutines



concurrent threads of control

each may be a function call or method call
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...
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...
package generalise
import . "reflect"

type SignalSource func(status chan bool)

func (s SignalSource) Wait() {
  done := make(chan bool)
  defer close(done)
  go s(done)
  <-done
}

func (s SignalSource) WaitAll(count int) {
  done := make(chan bool)
  defer close(done)
  go s(done)
  for i := 0; i < count; i++ {
    <- done
  }
}
package generalise

type Iteration func(k, x interface{})

func (i Iteration) apply(k, v interface{}, c chan bool) {
  go func() {
     i(k, v)
     c <- true
  }()
}
package generalise
import . "reflect"

func (f Iteration) Each(c interface{}) {
  switch c := NewValue(c).(type) {
  case *SliceValue:! ! SignalSource(func(done chan bool) {
      !   ! ! ! ! ! for i := 0; i < c.Len(); i++ {
      !   ! ! ! ! ! ! f.apply(i, c.Elem(i).Interface(), done)
      !   ! ! ! ! ! }
    ! ! ! ! ! ! }).WaitAll(c.Len())
  case *MapValue:! ! SignalSource(func(done chan bool) {
      !   ! ! ! ! ! for _, k := range c.Keys() {
      !   ! ! ! ! ! ! f.apply(k, c.Elem(k).Interface(), done)
      !   ! ! ! ! ! }
    ! ! ! ! ! ! }).WaitAll(c.Len())
  }
}
package generalise
import . "reflect"

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() {
     Iteration(func(k, x interface{}) {
        s = f(s, x)
     }).Each(c)
     r <- s
  }()
  return
}
package generalise
import . "reflect"

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
    ! ! ! ! ! ! }).Wait()
    ! ! ! ! ! ! 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
    ! ! ! ! ! ! }).Wait()
    ! ! ! ! ! ! return n.Interface()
  }
  return Duplicate(c)
}
func (t Transformation) Map(c interface{}) interface{} {
  var i Iteration
  n := NewValue(Allocate(c))
  switch n := n.(type) {
  case *SliceValue:! ! i = Iteration(func(k, x interface{}) {
  !       ! ! ! ! ! ! ! n.Elem(k.(int)).SetValue(t.GetValue(x))
        !   ! ! ! ! ! })
  case *MapValue:! ! i = Iteration(func(k, x interface{}) {
  !       ! ! ! ! ! ! ! n.SetElem(NewValue(k), t.GetValue(x))
  !       ! ! ! ! ! ! })
  }
  if i == nil { return Duplicate(c) }
  SignalSource(func(done chan bool) {
     i.Each(c)
     done <- true
  }).Wait()
  return n.Interface()
}
package main
import “fmt”
import . “generalise”

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 := Transformation( func(x interface{}) interface{} { return x.(int) * 2 } ).Map(s)
  x := <- Combination(sum).Reduce(s, 0)
  fmt.Printf("s", s, x.(int))
  x = <- Combination(sum).Reduce(d, 0)
  fmt.Printf("d", d, x.(int))
}



produces:
   s = [0 1 2 3 4 5], sum = 15
   c = [0 2 4 6 8 10], sum = 30
integration
include $(GOROOT)/src/Make.inc

TARG=sqlite3

CGOFILES=
 sqlite3.go
 database.go

ifeq ($(GOOS),darwin)
CGO_LDFLAGS=/usr/lib/libsqlite3.0.dylib
else
CGO_LDFLAGS=-lsqlite3
endif

include $(GOROOT)/src/Make.pkg
package sqlite3
/ #include <sqlite3.h>
 /
import "C"
import "fmt"
import "os"

type Database   struct {
  handle! ! !     ! *C.sqlite3
  Filename! !    ! string
  Flags! ! !      ! C.int
}

func (db *Database) Error() os.Error {
! return Errno(C.sqlite3_errcode(db.handle))
}
const(
  OK! ! ! = Errno(iota)
  ERROR
  CANTOPEN!= Errno(14)
)

var errText = map[Errno]string {
  ERROR: ! ! "SQL error or missing database",
  CANTOPEN:! "Unable to open the database file",
}

type Errno int

func (e Errno) String() (err string) {
  if err = errText[e]; err == "" {
     err = fmt.Sprintf("errno %v", int(e))
  }
  return
}
func (db *Database) Open(flags... int) (e os.Error) {
  db.Flags = 0
  for _, v := range flags { db.Flags = db.Flags | C.int(v) }
  f := C.CString(db.Filename)
  if err := Errno(C.sqlite3_open_v2(f, &db.handle, db.Flags, nil)); err != OK {
     e = err
  } else if db.handle == nil {
     e = CANTOPEN
  }
  return
}

func (db *Database) Close() {
! C.sqlite3_close(db.handle)
! db.handle = nil
}
func Open(filename string, flags... int) (db *Database, e os.Error) {
  defer func() {
     if x := recover(); x != nil {
        db.Close()
        db = nil
        e = ERROR
     }
  }()
  db = &Database{ Filename: filename }
  if len(flags) == 0 {
     e = db.Open(
          C.SQLITE_OPEN_FULLMUTEX,
          C.SQLITE_OPEN_READWRITE,
          C.SQLITE_OPEN_CREATE)
  } else {
     e = db.Open(flags...)
  }
  return
}
func (db *Database) Prepare(sql string, values... interface{})
      (s *Statement, e os.Error) {
  s = &Statement{ db: db, timestamp: time.Nanoseconds() }
  rv := Errno(C.sqlite3_prepare_v2(db.handle, C.CString(sql), -1, &s.cptr, nil))
  switch {
  case rv != OK:!! ! return nil, rv
  case len(values) > 0:! e, _ = s.BindAll(values...)
  }
  return
}

func (db *Database) Execute(sql string, f... func(*Statement, ...interface{}))
      (c int, e os.Error) {
  var st! *Statement
  switch st, e = db.Prepare(sql); e {
  case nil:! ! c, e = st.All(f...)
           !
  case OK:! ! e = nil
  }
  return
}
software machines
synchronisation
package clock
import "syscall"

type Clock struct {
  Period! ! ! int64
  Count! ! ! chan int64
  Control!! ! chan bool
  active! ! ! bool
}
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)
          }
        }
     }()
  }
}
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")
}
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
memory
package raw
import . "reflect"

type Slice struct { *SliceValue }

func (s *Slice) Set(i int, value interface{}) {
  s.Elem(i).SetValue(NewValue(value))
}

func (s *Slice) Overwrite(offset int, source interface{}) {
  switch source := source.(type) {
  case *Slice:! s.Overwrite(offset, *source)
              !
  case Slice:!! reflect.Copy(s.SliceValue.Slice(offset, s.Len()), source.SliceValue)
  default:!! ! switch v := NewValue(source).(type) {
! ! ! ! ! case *SliceValue:! ! s.Overwrite(offset, Slice{v})
! ! ! ! ! default:! ! ! ! ! s.Set(offset, v.Interface())
! ! ! ! ! }
  }
}
package main
import . "fmt"
import . "raw"

func main() {
  report := "%v (%v) = %v of %v: %vn"
  m := make([]int, 2)
  Printf(report, "m", "cells", len(m), cap(m), m)
  b := ByteSlice(m)
  Printf(report, "b", "bytes", len(b), cap(b), b)
  Overwrite(m, []byte{0, 0, 0, 1, 0, 0, 0, 1})
  Printf(report, "m", "cells", len(m), cap(m), m)
}

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]
subtleties
von Neumann & Harvard architectures

          indirection bits

           byte-ordering
instruction set
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)) }
}
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())
}
package instructions

type Assembler struct {
  opcodes map[string] int
  names 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) Define(names... string) {
  for _, name := range names {
    a.opcodes[name] = len(a.names)
    a.names[len(a.names)] = name
  }
}
package instructions

func (a Assembler) Assemble(name string, params... int) (i Instruction) {
  i = make(Instruction, len(params) + 1)
  switch opcode, ok := a.opcodes[name]; {
  case ok:! i[0] = opcode
           !
  default:!! i[0] = INVALID_OPCODE
  }
  copy(i[1:], params)
  return
}
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
}
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])
    }
  }
}
produces:
   noop
   load! !   1
   store!1, 2
   unknown
   op = 2 result = 3
CISC
  semantically rich instructions

complex memory addressing modes

      compact binary code
RISC
separate IO and data processing

register-to-register instructions

   load/store memory access
VLIW
   multiple operations per instruction

compiler statically determines parallelism

         simplifies control logic
processor core
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"
}
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
}
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)
  top == 0 { panic(CALL_STACK_UNDERFLOW) }
  c.PC, c.CS = c.CS[top - 1], c.CS[:top]
}
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++
}
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) }
    }
  }
}
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) }
  }
}
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)
  }
}
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
accumulator machine
          1-operand instructions

data from memory combined with accumulator

        result stored in accumulator
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) }
}
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)
     }
  })
}
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
stack machine
 0-operand instructions

data popped from stack

results pushed on stack
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)!}
}
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]
}
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)
     }
  })
}
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]
register machine
      multi-operand instructions

data read from memory into registers

operator combines registers and stores
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)! }
}
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)
     }
  })
}
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]
transport triggering
       register machine architecture

   exposes internal buses and components

operations are side-effects of internal writes
vector machine
         multi-operand instructions

data vectors read from memory into registers

        operations combine registers
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)! ! }
}
package vmachine
import . "processor"

func (v *VMachine) Load(r int, m []int) {
! v.R[r] = make([]int, len(m))
! copy(v.R[r], m)
}
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)
     }
  })
}
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] [] [] [] [] [] [] []]
hypercube
   n-dimensional multi-operand instructions

data matrices read from memory into registers

        operations combine registers
superscalar
multiple execution units

   processor caching

out-of-order execution
close to the machine
      transport buses

     peripheral drivers

    hardware acceleration
finding out more
http://golang.org/

http://feyeleanor.tel/

http://golightly.games-with-brains.net/

http://github.com/feyeleanor/

twitter://#golightly

wikipedia or google

More Related Content

What's hot

Golang iran - tutorial go programming language - Preliminary
Golang iran - tutorial  go programming language - PreliminaryGolang iran - tutorial  go programming language - Preliminary
Golang iran - tutorial go programming language - Preliminarygo-lang
 
Let's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java APILet's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java APIMario Fusco
 
OOP and FP - Become a Better Programmer
OOP and FP - Become a Better ProgrammerOOP and FP - Become a Better Programmer
OOP and FP - Become a Better ProgrammerMario Fusco
 
Pydiomatic
PydiomaticPydiomatic
Pydiomaticrik0
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modelingMario Fusco
 
«iPython & Jupyter: 4 fun & profit», Лев Тонких, Rambler&Co
«iPython & Jupyter: 4 fun & profit», Лев Тонких, Rambler&Co«iPython & Jupyter: 4 fun & profit», Лев Тонких, Rambler&Co
«iPython & Jupyter: 4 fun & profit», Лев Тонких, Rambler&CoMail.ru Group
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongMario Fusco
 
Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)Scott Wlaschin
 
Use Applicative where applicable!
Use Applicative where applicable!Use Applicative where applicable!
Use Applicative where applicable!Hermann Hueck
 
Composing an App with Free Monads (using Cats)
Composing an App with Free Monads (using Cats)Composing an App with Free Monads (using Cats)
Composing an App with Free Monads (using Cats)Hermann Hueck
 
Что нам готовит грядущий C#7?
Что нам готовит грядущий C#7?Что нам готовит грядущий C#7?
Что нам готовит грядущий C#7?Andrey Akinshin
 
Kotlin as a Better Java
Kotlin as a Better JavaKotlin as a Better Java
Kotlin as a Better JavaGarth Gilmour
 
The best of AltJava is Xtend
The best of AltJava is XtendThe best of AltJava is Xtend
The best of AltJava is Xtendtakezoe
 
.NET 2015: Будущее рядом
.NET 2015: Будущее рядом.NET 2015: Будущее рядом
.NET 2015: Будущее рядомAndrey Akinshin
 
ECSE 221 - Introduction to Computer Engineering - Tutorial 1 - Muhammad Ehtas...
ECSE 221 - Introduction to Computer Engineering - Tutorial 1 - Muhammad Ehtas...ECSE 221 - Introduction to Computer Engineering - Tutorial 1 - Muhammad Ehtas...
ECSE 221 - Introduction to Computer Engineering - Tutorial 1 - Muhammad Ehtas...Muhammad Ulhaque
 
Golang concurrency design
Golang concurrency designGolang concurrency design
Golang concurrency designHyejong
 
Free Monads Getting Started
Free Monads Getting StartedFree Monads Getting Started
Free Monads Getting StartedKent Ohashi
 
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STMConcurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STMMario Fusco
 

What's hot (20)

Golang iran - tutorial go programming language - Preliminary
Golang iran - tutorial  go programming language - PreliminaryGolang iran - tutorial  go programming language - Preliminary
Golang iran - tutorial go programming language - Preliminary
 
Let's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java APILet's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java API
 
OOP and FP - Become a Better Programmer
OOP and FP - Become a Better ProgrammerOOP and FP - Become a Better Programmer
OOP and FP - Become a Better Programmer
 
Pydiomatic
PydiomaticPydiomatic
Pydiomatic
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
 
«iPython & Jupyter: 4 fun & profit», Лев Тонких, Rambler&Co
«iPython & Jupyter: 4 fun & profit», Лев Тонких, Rambler&Co«iPython & Jupyter: 4 fun & profit», Лев Тонких, Rambler&Co
«iPython & Jupyter: 4 fun & profit», Лев Тонких, Rambler&Co
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are Wrong
 
Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)
 
MP in Clojure
MP in ClojureMP in Clojure
MP in Clojure
 
Use Applicative where applicable!
Use Applicative where applicable!Use Applicative where applicable!
Use Applicative where applicable!
 
Composing an App with Free Monads (using Cats)
Composing an App with Free Monads (using Cats)Composing an App with Free Monads (using Cats)
Composing an App with Free Monads (using Cats)
 
Что нам готовит грядущий C#7?
Что нам готовит грядущий C#7?Что нам готовит грядущий C#7?
Что нам готовит грядущий C#7?
 
Kotlin as a Better Java
Kotlin as a Better JavaKotlin as a Better Java
Kotlin as a Better Java
 
The best of AltJava is Xtend
The best of AltJava is XtendThe best of AltJava is Xtend
The best of AltJava is Xtend
 
.NET 2015: Будущее рядом
.NET 2015: Будущее рядом.NET 2015: Будущее рядом
.NET 2015: Будущее рядом
 
ECSE 221 - Introduction to Computer Engineering - Tutorial 1 - Muhammad Ehtas...
ECSE 221 - Introduction to Computer Engineering - Tutorial 1 - Muhammad Ehtas...ECSE 221 - Introduction to Computer Engineering - Tutorial 1 - Muhammad Ehtas...
ECSE 221 - Introduction to Computer Engineering - Tutorial 1 - Muhammad Ehtas...
 
Golang concurrency design
Golang concurrency designGolang concurrency design
Golang concurrency design
 
Free Monads Getting Started
Free Monads Getting StartedFree Monads Getting Started
Free Monads Getting Started
 
C++ Chapter IV
C++ Chapter IVC++ Chapter IV
C++ Chapter IV
 
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STMConcurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
 

Similar to GoLightly: Building VM-Based Language Runtimes with Google Go

Go: It's Not Just For Google
Go: It's Not Just For GoogleGo: It's Not Just For Google
Go: It's Not Just For GoogleEleanor McHugh
 
Scalapeno18 - Thinking Less with Scala
Scalapeno18 - Thinking Less with ScalaScalapeno18 - Thinking Less with Scala
Scalapeno18 - Thinking Less with ScalaDaniel Sebban
 
golang_getting_started.pptx
golang_getting_started.pptxgolang_getting_started.pptx
golang_getting_started.pptxGuy Komari
 
Kotlin Austin Droids April 14 2016
Kotlin Austin Droids April 14 2016Kotlin Austin Droids April 14 2016
Kotlin Austin Droids April 14 2016DesertJames
 
Scala Functional Patterns
Scala Functional PatternsScala Functional Patterns
Scala Functional Patternsleague
 
Imugi: Compiler made with Python
Imugi: Compiler made with PythonImugi: Compiler made with Python
Imugi: Compiler made with PythonHan Lee
 
Advanced Web Technology ass.pdf
Advanced Web Technology ass.pdfAdvanced Web Technology ass.pdf
Advanced Web Technology ass.pdfsimenehanmut
 
Coding in GO - GDG SL - NSBM
Coding in GO - GDG SL - NSBMCoding in GO - GDG SL - NSBM
Coding in GO - GDG SL - NSBMRaveen Perera
 
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018John De Goes
 
The Present and The Future of Functional Programming in C++
The Present and The Future of Functional Programming in C++The Present and The Future of Functional Programming in C++
The Present and The Future of Functional Programming in C++Alexander Granin
 
Concurrency in Golang
Concurrency in GolangConcurrency in Golang
Concurrency in GolangOliver N
 
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPythonByterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPythonakaptur
 

Similar to GoLightly: Building VM-Based Language Runtimes with Google Go (20)

Go a crash course
Go   a crash courseGo   a crash course
Go a crash course
 
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
 
Go &lt;-> Ruby
Go &lt;-> RubyGo &lt;-> Ruby
Go &lt;-> Ruby
 
Scalapeno18 - Thinking Less with Scala
Scalapeno18 - Thinking Less with ScalaScalapeno18 - Thinking Less with Scala
Scalapeno18 - Thinking Less with Scala
 
golang_getting_started.pptx
golang_getting_started.pptxgolang_getting_started.pptx
golang_getting_started.pptx
 
Introduction to kotlin
Introduction to kotlinIntroduction to kotlin
Introduction to kotlin
 
Kotlin Austin Droids April 14 2016
Kotlin Austin Droids April 14 2016Kotlin Austin Droids April 14 2016
Kotlin Austin Droids April 14 2016
 
Scala Functional Patterns
Scala Functional PatternsScala Functional Patterns
Scala Functional Patterns
 
Faster Python, FOSDEM
Faster Python, FOSDEMFaster Python, FOSDEM
Faster Python, FOSDEM
 
Python idiomatico
Python idiomaticoPython idiomatico
Python idiomatico
 
Imugi: Compiler made with Python
Imugi: Compiler made with PythonImugi: Compiler made with Python
Imugi: Compiler made with Python
 
Let's Go-lang
Let's Go-langLet's Go-lang
Let's Go-lang
 
Chapter 02 functions -class xii
Chapter 02   functions -class xiiChapter 02   functions -class xii
Chapter 02 functions -class xii
 
Advanced Web Technology ass.pdf
Advanced Web Technology ass.pdfAdvanced Web Technology ass.pdf
Advanced Web Technology ass.pdf
 
Coding in GO - GDG SL - NSBM
Coding in GO - GDG SL - NSBMCoding in GO - GDG SL - NSBM
Coding in GO - GDG SL - NSBM
 
ATS Programming
ATS ProgrammingATS Programming
ATS Programming
 
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
 
The Present and The Future of Functional Programming in C++
The Present and The Future of Functional Programming in C++The Present and The Future of Functional Programming in C++
The Present and The Future of Functional Programming in C++
 
Concurrency in Golang
Concurrency in GolangConcurrency in Golang
Concurrency in Golang
 
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPythonByterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
 

More from Eleanor McHugh

[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdfEleanor McHugh
 
Generics, Reflection, and Efficient Collections
Generics, Reflection, and Efficient CollectionsGenerics, Reflection, and Efficient Collections
Generics, Reflection, and Efficient CollectionsEleanor McHugh
 
The Relevance of Liveness - Biometrics and Data Integrity
The Relevance of Liveness - Biometrics and Data IntegrityThe Relevance of Liveness - Biometrics and Data Integrity
The Relevance of Liveness - Biometrics and Data IntegrityEleanor McHugh
 
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]Eleanor McHugh
 
The Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's PerspectiveThe Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's PerspectiveEleanor McHugh
 
Go for the paranoid network programmer, 3rd edition
Go for the paranoid network programmer, 3rd editionGo for the paranoid network programmer, 3rd edition
Go for the paranoid network programmer, 3rd editionEleanor McHugh
 
An introduction to functional programming with Go [redux]
An introduction to functional programming with Go [redux]An introduction to functional programming with Go [redux]
An introduction to functional programming with Go [redux]Eleanor McHugh
 
An introduction to functional programming with go
An introduction to functional programming with goAn introduction to functional programming with go
An introduction to functional programming with goEleanor McHugh
 
Implementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxImplementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxEleanor McHugh
 
Identity & trust in Monitored Spaces
Identity & trust in Monitored SpacesIdentity & trust in Monitored Spaces
Identity & trust in Monitored SpacesEleanor McHugh
 
Don't Ask, Don't Tell - The Virtues of Privacy By Design
Don't Ask, Don't Tell - The Virtues of Privacy By DesignDon't Ask, Don't Tell - The Virtues of Privacy By Design
Don't Ask, Don't Tell - The Virtues of Privacy By DesignEleanor McHugh
 
Don't ask, don't tell the virtues of privacy by design
Don't ask, don't tell   the virtues of privacy by designDon't ask, don't tell   the virtues of privacy by design
Don't ask, don't tell the virtues of privacy by designEleanor McHugh
 
Anonymity, identity, trust
Anonymity, identity, trustAnonymity, identity, trust
Anonymity, identity, trustEleanor McHugh
 
Going Loopy - Adventures in Iteration with Google Go
Going Loopy - Adventures in Iteration with Google GoGoing Loopy - Adventures in Iteration with Google Go
Going Loopy - Adventures in Iteration with Google GoEleanor McHugh
 
Distributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at ScaleDistributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at ScaleEleanor McHugh
 
Go for the paranoid network programmer, 2nd edition
Go for the paranoid network programmer, 2nd editionGo for the paranoid network programmer, 2nd edition
Go for the paranoid network programmer, 2nd editionEleanor McHugh
 
Going Loopy: Adventures in Iteration with Go
Going Loopy: Adventures in Iteration with GoGoing Loopy: Adventures in Iteration with Go
Going Loopy: Adventures in Iteration with GoEleanor McHugh
 
Finding a useful outlet for my many Adventures in go
Finding a useful outlet for my many Adventures in goFinding a useful outlet for my many Adventures in go
Finding a useful outlet for my many Adventures in goEleanor McHugh
 
Anonymity, trust, accountability
Anonymity, trust, accountabilityAnonymity, trust, accountability
Anonymity, trust, accountabilityEleanor McHugh
 

More from 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
 

Recently uploaded

"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfSeasiaInfotech2
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 

Recently uploaded (20)

"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdf
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 

GoLightly: Building VM-Based Language Runtimes with Google Go

  • 1. GoLightly Building VM-based language runtimes in Go Eleanor McHugh http://slides.games-with-brains.net/
  • 2. portrait of an artist... physics major http:/ feyele embedded controllers / software reliability dynamic languages network scaling or.tel an questionable taste in music Elean or McHugh
  • 3. Languages Project ? fluid-dynamics simulation ? cockpit autopilot controller ? paramilitary cockpit C4I ? broadcast automation ? encrypted RDBM ? Unix kernel scripting
  • 4. Language Project ICON fluid-dynamics simulation ASM cockpit autopilot controller VB5 paramilitary cockpit C4I VB5, ASM, K&R C broadcast automation RUBY, DNS encrypted RDBM RUBY Unix kernel scripting
  • 7. wild romance golightly
  • 8. Elric sent his mind into twisting tunnels of logic, across endless plains of ideas, through mountains of symbolism and endless universes of alternate truths; he sent his mind out further and further and as it went he sent with it the words which issued from his writhing lips -- words that few of his contemporaries would understand... - Elric of Melniboné, Michael Moorcock
  • 10. go... a systems language by google productivity, performance, concurrency lighter than Java, safer than C
  • 11. ...lightly clean abstractions geared to performance non-viral open source license
  • 12. inspiration processor design sensor and control networks field-programmable gate arrays
  • 13. perspiration iterative empirical development explore -> implement -> test -> benchmark evolve towards elegance
  • 14. principles decoupling improves scalability coherence simplifies organisation optimisations are application specific
  • 15. agnostic no blessed programming languages flexible platform abstractions write once, run everywhere it matters
  • 16. heterogeneous a system comprises many components components may differ in purpose and design but they cooperate to solve problems
  • 17. virtualisation design discrete Turing machines implement these machines in software compile programs to run on them
  • 18. networks machines cooperate by sending messages machine states can be serialised as messages messages transcend process and host boundaries
  • 19. 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
  • 20. go
  • 21. an elegant language a statically-typed compiled language object-oriented static type declaration dynamic type inference garbage collection concurrency via communication (CSP)
  • 23. package main import “fmt” const( HELLO string = “hello” WORLD string = “world” ) func main() { fmt.Println(HELLO, WORLD) }
  • 25. boolean, numeric, array value structure, interface reference pointer, slice, string, map, channel function function, method, closure
  • 26. underlying method type set expressed type
  • 27. underlying method type set expressed type embedded types
  • 29. package Integer type Int int func (i *Int) Add(x int) { *i += Int(x) }
  • 30. package Integer func (b Buffer) Clone() Buffer { s := make(Buffer, len(b)) type Buffer []Int copy(s, b) return s func (b Buffer) Eq(o Buffer) (r bool) { } if len(b) == len(o) { for i := len(b) - 1; i > 0; i-- { func (b Buffer) Move(i, n int) { if b[i] != o[i] { if n > len(b) - i { return n = len(b) - i } } } segment_to_move := b[:i].Clone() r = true copy(b, b[i:i + n]) } copy(b[n:i + n], return segment_to_move) } } func (b Buffer) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
  • 31. 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[0:2] = {”, b[0], “,”, b[1], “}”) } produces: b[0:2] = { 6, 4 }
  • 34. package Integer func (b Buffer) Swap(i, j int) { b[i], b[j] = b[j], b[i] type Int int } func (i *Int) Add(x int) { *i += Int(x) func (b Buffer) Clone() Buffer { } s := make(Buffer, len(b)) copy(s, b) type Buffer []Int return s func (b Buffer) Eq(o Buffer) (r bool) { } if len(b) == len(o) { for i := len(b) - 1; i > 0; i-- { func (b Buffer) Move(i, n int) { if b[i] != o[i] { if n > len(b) - i { return n = len(b) - i } } } segment_to_move := b[:i].Clone() r = true copy(b, b[i:i + n]) } copy(b[n:i + n], return segment_to_move) } }
  • 35. package Integer func TestAdd(t *testing.T) { import “testing” i := Buffer{0, 1, 2, 3, 4, 5} b := i.Clone() func TestSwap(t *testing.T) { b[0].Add(3) i := Buffer{0, 1, 2, 3, 4, 5} if b[0] != i[0] + 3 { b := i.Clone() t.Fatalf("b[0:5] = %v", b) b.Swap(1, 2) } if !b[1:3].Eq(Buffer{2, 1}) { } t.Fatalf("b[0: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[0:5] = %v", b) } }
  • 37. 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] }
  • 38. include $(GOROOT)/src/Make.inc TARG=integer GOFILES= integer.go vector.go include $(GOROOT)/src/Make.pkg
  • 39. 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[0:5] = %v", v) } }
  • 41. 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) } }
  • 42. $ gotest -bench="Benchmark" rm -f _test/scripts.a 6g -o _gotest_.6 integer.go vector.go nominal_typing_test.go embedded_typing_benchmark_test.go embedded_typing_test.go rm -f _test/scripts.a gopack grc _test/scripts.a _gotest_.6 PASS integer.BenchmarkVectorSwap! 200000000! 8 ns/op integer.BenchmarkVectorClone6! 10000000! 300 ns/op
  • 44. package adder type Adder interface { Add(j int) Subtract(j int) Result() interface{} } type Calculator interface { Adder Reset() } type AddingMachine struct { Memory interface{} Adder }
  • 45. 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) }
  • 46. 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)) } }
  • 47. 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) }
  • 48. 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().(float32) != 1.0 { t.Fatalf(error, f.Result(), 1.0) } f.Subtract(2) if i.Result().(float32) != -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().(float32) != *new(float32) { t.Fatalf(error, r.Result(), *new(float32)) } }
  • 49. 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) } } }
  • 50. package generalise import "reflect" func Allocate(i interface{}, limit... int) (n interface{}) { v := reflect.NewValue(i) switch v := v.(type) { case *reflect.SliceValue: l := v.Cap() if len(limit) > 0 { l = limit[0] } t := v.Type().(*reflect.SliceType) n = reflect.MakeSlice(t, l, l).Interface() case *reflect.MapValue: t := v.Type().(*reflect.MapType) n = reflect.MakeMap(t).Interface() } return }
  • 51. package generalise import . "reflect" 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) Copy(temp, destination) Copy(destination, source) Copy(source, temp) } else { panic(i) } }
  • 52. package generalise import . "reflect" func Duplicate(i interface{}) (clone interface{}) { if clone = Allocate(i); clone != nil { switch clone := NewValue(clone).(type) { case *SliceValue: s := NewValue(i).(*SliceValue) Copy(clone, s) case *MapValue: m := NewValue(i).(*MapValue) for _, k := range m.Keys() { clone.SetElem(k, m.Elem(k)) } } } return }
  • 53. package generalise import "testing" func throwsPanic(f func()) (b bool) { defer func() { if x := recover(); x != nil { b = true } }() f() return }
  • 54. func TestAllocate(t *testing.T) { var s2 []int s1 := []int{0, 1, 2} m := map[int] int{1: 1, 2: 2, 3: 3} switch { case throwsPanic(func() { s2 = Allocate(s1, 1).([]int) }): t.Fatal("Unable to allocate new slice") case len(s2) != 1: fallthrough case cap(s2) != 1: t.Fatal("New slice should be %v not %v", make([]int, 0, 1), s2) case throwsPanic(func() { Allocate(m) }): t.Fatal("Unable to allocate new map") } }
  • 55. func TestDuplicate(t *testing.T) { error := "Duplicating %v produced %v" s1 := []int{0, 1, 2} var s2 []int m1 := map[int]int{1: 1, 2: 2, 3: 3} var m2 map[int]int switch { case throwsPanic(func() { s2 = Duplicate(s1).([]int) }): t.Fatalf("Unable to duplicate slice %vn", s1) case len(s1) != len(s2): fallthrough case cap(s1) != cap(s2): fallthrough case s1[0] != s2[0] || s1[1] != s2[1] || s1[2] != s2[2]: t.Fatalf(error, s1, s2) case throwsPanic(func() { m2 = Duplicate(m1).(map[int]int) }): t.Fatalf("Unable to duplicate map %vn", m1) case len(m1) != len(m2): fallthrough case m1[1] != m2[1] || m1[2] != m2[2] || m1[3] != m2[3]: t.Fatalf(error, m1, m2) } }
  • 56. func TestSwapSlices(t *testing.T) { error := "%v became %v but should be %v" s1 := []int{0, 1, 2, 3, 4, 5} s2 := Duplicate(s1).([]int) r := []int{3, 4, 5, 0, 1, 2} m := map[int] int{1: 1, 2: 2} switch { case !throwsPanic(func() { SwapSlices(m, 0, 3, 3) }): t.Fatalf("Successfully swapped slices %vn", m) case throwsPanic(func() { SwapSlices(s2, 0, 3, 3) }): t.Fatalf("Unable to swap slices %vn", s2) case len(s2) != len(r): t.Fatalf(error, s1, s2, r) default: for i, v := range s2 { if r[i] != v { t.Fatalf(error, s1, s2, r) } } } }
  • 58. package raw import . "reflect" import "unsafe" var _BYTE_SLICE! Type var _STRING! ! Type ! func init() { _BYTE_SLICE = Typeof([]byte(nil)) _STRING = Typeof("") } type MemoryBlock interface { ByteSlice() []byte }
  • 59. func SliceHeader(i interface{}) (Header *SliceHeader, Size, Align int) { value := NewValue(i) switch value := value.(type) { case *SliceValue: Header = (*SliceHeader)(unsafe.Pointer(value.UnsafeAddr())) t := value.Type().(*SliceType).Elem() Size = int(t.Size()) Align = t.Align() case nil:! ! ! ! ! panic(i) ! case *InterfaceValue:! Header, Size, Align = SliceHeader(value.Elem()) case *PtrValue:! ! ! Header, Size, Align = SliceHeader(value.Elem()) } return }
  • 60. func Scale(oldHeader *SliceHeader, oldESize, newESize int) (h *SliceHeader) { ! if oldHeader != nil { ! ! s := float64(oldESize) / float64(newESize) ! ! h = &SliceHeader{ Data: oldHeader.Data } ! ! h.Len = int(float64(oldHeader.Len) * s) ! ! h.Cap = int(float64(oldHeader.Cap) * s) ! } ! return }
  • 61. func ByteSlice(i interface{}) []byte { switch b := i.(type) { case []byte:! ! ! ! ! ! return b case MemoryBlock:! ! ! ! return b.ByteSlice() case nil:! ! ! ! ! ! ! return []byte{} ! } var header *SliceHeader value := NewValue(i) switch value := value.(type) { case nil:! ! ! ! ! ! ! return []byte{} ! case Type:! ! ! ! ! ! ! panic(i) case *MapValue:! ! ! ! ! panic(i) case *ChanValue:! ! ! ! ! panic(i) case *InterfaceValue:! ! ! return ByteSlice(value.Elem()) case *PtrValue: if value := value.Elem(); value == nil { return ByteSlice(nil) } else { size := int(value.Type().Size()) header = &SliceHeader{ value.UnsafeAddr(), size, size } }
  • 62. case *SliceValue: h, s, _ := SliceHeader(i) header = Scale(h, s, 1) case *StringValue: s := value.Get() h := *(*StringHeader)(unsafe.Pointer(&s)) header = &SliceHeader{ h.Data, h.Len, h.Len } default: size := int(value.Type().Size()) header = &SliceHeader{ value.UnsafeAddr(), size, size } } return unsafe.Unreflect(_BYTE_SLICE, unsafe.Pointer(header)).([]byte) }
  • 64. goroutines concurrent threads of control each may be a function call or method call
  • 65. 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...
  • 66. 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...
  • 67. package generalise import . "reflect" type SignalSource func(status chan bool) func (s SignalSource) Wait() { done := make(chan bool) defer close(done) go s(done) <-done } func (s SignalSource) WaitAll(count int) { done := make(chan bool) defer close(done) go s(done) for i := 0; i < count; i++ { <- done } }
  • 68. package generalise type Iteration func(k, x interface{}) func (i Iteration) apply(k, v interface{}, c chan bool) { go func() { i(k, v) c <- true }() }
  • 69. package generalise import . "reflect" func (f Iteration) Each(c interface{}) { switch c := NewValue(c).(type) { case *SliceValue:! ! SignalSource(func(done chan bool) { ! ! ! ! ! ! for i := 0; i < c.Len(); i++ { ! ! ! ! ! ! ! f.apply(i, c.Elem(i).Interface(), done) ! ! ! ! ! ! } ! ! ! ! ! ! }).WaitAll(c.Len()) case *MapValue:! ! SignalSource(func(done chan bool) { ! ! ! ! ! ! for _, k := range c.Keys() { ! ! ! ! ! ! ! f.apply(k, c.Elem(k).Interface(), done) ! ! ! ! ! ! } ! ! ! ! ! ! }).WaitAll(c.Len()) } }
  • 70. package generalise import . "reflect" 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() { Iteration(func(k, x interface{}) { s = f(s, x) }).Each(c) r <- s }() return }
  • 71. package generalise import . "reflect" type Transformation func(x interface{}) interface{} func (t Transformation) GetValue(x interface{}) Value { return NewValue(t(x)) }
  • 72. 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 ! ! ! ! ! ! }).Wait() ! ! ! ! ! ! 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 ! ! ! ! ! ! }).Wait() ! ! ! ! ! ! return n.Interface() } return Duplicate(c) }
  • 73. func (t Transformation) Map(c interface{}) interface{} { var i Iteration n := NewValue(Allocate(c)) switch n := n.(type) { case *SliceValue:! ! i = Iteration(func(k, x interface{}) { ! ! ! ! ! ! ! ! n.Elem(k.(int)).SetValue(t.GetValue(x)) ! ! ! ! ! ! }) case *MapValue:! ! i = Iteration(func(k, x interface{}) { ! ! ! ! ! ! ! ! n.SetElem(NewValue(k), t.GetValue(x)) ! ! ! ! ! ! ! }) } if i == nil { return Duplicate(c) } SignalSource(func(done chan bool) { i.Each(c) done <- true }).Wait() return n.Interface() }
  • 74. package main import “fmt” import . “generalise” 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 := Transformation( func(x interface{}) interface{} { return x.(int) * 2 } ).Map(s) x := <- Combination(sum).Reduce(s, 0) fmt.Printf("s", s, x.(int)) x = <- Combination(sum).Reduce(d, 0) fmt.Printf("d", d, x.(int)) } produces: s = [0 1 2 3 4 5], sum = 15 c = [0 2 4 6 8 10], sum = 30
  • 76. include $(GOROOT)/src/Make.inc TARG=sqlite3 CGOFILES= sqlite3.go database.go ifeq ($(GOOS),darwin) CGO_LDFLAGS=/usr/lib/libsqlite3.0.dylib else CGO_LDFLAGS=-lsqlite3 endif include $(GOROOT)/src/Make.pkg
  • 77. package sqlite3 / #include <sqlite3.h> / import "C" import "fmt" import "os" type Database struct { handle! ! ! ! *C.sqlite3 Filename! ! ! string Flags! ! ! ! C.int } func (db *Database) Error() os.Error { ! return Errno(C.sqlite3_errcode(db.handle)) }
  • 78. const( OK! ! ! = Errno(iota) ERROR CANTOPEN!= Errno(14) ) var errText = map[Errno]string { ERROR: ! ! "SQL error or missing database", CANTOPEN:! "Unable to open the database file", } type Errno int func (e Errno) String() (err string) { if err = errText[e]; err == "" { err = fmt.Sprintf("errno %v", int(e)) } return }
  • 79. func (db *Database) Open(flags... int) (e os.Error) { db.Flags = 0 for _, v := range flags { db.Flags = db.Flags | C.int(v) } f := C.CString(db.Filename) if err := Errno(C.sqlite3_open_v2(f, &db.handle, db.Flags, nil)); err != OK { e = err } else if db.handle == nil { e = CANTOPEN } return } func (db *Database) Close() { ! C.sqlite3_close(db.handle) ! db.handle = nil }
  • 80. func Open(filename string, flags... int) (db *Database, e os.Error) { defer func() { if x := recover(); x != nil { db.Close() db = nil e = ERROR } }() db = &Database{ Filename: filename } if len(flags) == 0 { e = db.Open( C.SQLITE_OPEN_FULLMUTEX, C.SQLITE_OPEN_READWRITE, C.SQLITE_OPEN_CREATE) } else { e = db.Open(flags...) } return }
  • 81. func (db *Database) Prepare(sql string, values... interface{}) (s *Statement, e os.Error) { s = &Statement{ db: db, timestamp: time.Nanoseconds() } rv := Errno(C.sqlite3_prepare_v2(db.handle, C.CString(sql), -1, &s.cptr, nil)) switch { case rv != OK:!! ! return nil, rv case len(values) > 0:! e, _ = s.BindAll(values...) } return } func (db *Database) Execute(sql string, f... func(*Statement, ...interface{})) (c int, e os.Error) { var st! *Statement switch st, e = db.Prepare(sql); e { case nil:! ! c, e = st.All(f...) ! case OK:! ! e = nil } return }
  • 84. package clock import "syscall" type Clock struct { Period! ! ! int64 Count! ! ! chan int64 Control!! ! chan bool active! ! ! bool }
  • 85. 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) } } }() } }
  • 86. 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") }
  • 87. 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
  • 89. package raw import . "reflect" type Slice struct { *SliceValue } func (s *Slice) Set(i int, value interface{}) { s.Elem(i).SetValue(NewValue(value)) } func (s *Slice) Overwrite(offset int, source interface{}) { switch source := source.(type) { case *Slice:! s.Overwrite(offset, *source) ! case Slice:!! reflect.Copy(s.SliceValue.Slice(offset, s.Len()), source.SliceValue) default:!! ! switch v := NewValue(source).(type) { ! ! ! ! ! case *SliceValue:! ! s.Overwrite(offset, Slice{v}) ! ! ! ! ! default:! ! ! ! ! s.Set(offset, v.Interface()) ! ! ! ! ! } } }
  • 90. package main import . "fmt" import . "raw" func main() { report := "%v (%v) = %v of %v: %vn" m := make([]int, 2) Printf(report, "m", "cells", len(m), cap(m), m) b := ByteSlice(m) Printf(report, "b", "bytes", len(b), cap(b), b) Overwrite(m, []byte{0, 0, 0, 1, 0, 0, 0, 1}) Printf(report, "m", "cells", len(m), cap(m), m) } 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]
  • 91. subtleties von Neumann & Harvard architectures indirection bits byte-ordering
  • 93. 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)) } }
  • 94. 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()) }
  • 95. package instructions type Assembler struct { opcodes map[string] int names 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) Define(names... string) { for _, name := range names { a.opcodes[name] = len(a.names) a.names[len(a.names)] = name } }
  • 96. package instructions func (a Assembler) Assemble(name string, params... int) (i Instruction) { i = make(Instruction, len(params) + 1) switch opcode, ok := a.opcodes[name]; { case ok:! i[0] = opcode ! default:!! i[0] = INVALID_OPCODE } copy(i[1:], params) return }
  • 97. 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 }
  • 98. 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]) } } }
  • 99. produces: noop load! ! 1 store!1, 2 unknown op = 2 result = 3
  • 100. CISC semantically rich instructions complex memory addressing modes compact binary code
  • 101. RISC separate IO and data processing register-to-register instructions load/store memory access
  • 102. VLIW multiple operations per instruction compiler statically determines parallelism simplifies control logic
  • 104. 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" }
  • 105. 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 }
  • 106. 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) top == 0 { panic(CALL_STACK_UNDERFLOW) } c.PC, c.CS = c.CS[top - 1], c.CS[:top] }
  • 107. 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++ }
  • 108. 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) } } } }
  • 109. 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) } } }
  • 110. 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) } }
  • 111. 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
  • 112. accumulator machine 1-operand instructions data from memory combined with accumulator result stored in accumulator
  • 113. 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) } }
  • 114. 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) } }) }
  • 115. 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
  • 116. stack machine 0-operand instructions data popped from stack results pushed on stack
  • 117. 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)!} }
  • 118. 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] }
  • 119. 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) } }) }
  • 120. 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]
  • 121. register machine multi-operand instructions data read from memory into registers operator combines registers and stores
  • 122. 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)! } }
  • 123. 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) } }) }
  • 124. 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]
  • 125. transport triggering register machine architecture exposes internal buses and components operations are side-effects of internal writes
  • 126. vector machine multi-operand instructions data vectors read from memory into registers operations combine registers
  • 127. 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)! ! } }
  • 128. package vmachine import . "processor" func (v *VMachine) Load(r int, m []int) { ! v.R[r] = make([]int, len(m)) ! copy(v.R[r], m) }
  • 129. 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) } }) }
  • 130. 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] [] [] [] [] [] [] []]
  • 131. hypercube n-dimensional multi-operand instructions data matrices read from memory into registers operations combine registers
  • 132. superscalar multiple execution units processor caching out-of-order execution
  • 133. close to the machine transport buses peripheral drivers hardware acceleration

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n
  62. \n
  63. \n
  64. \n
  65. \n
  66. \n
  67. \n
  68. \n
  69. \n
  70. \n
  71. \n
  72. \n
  73. \n
  74. \n
  75. \n
  76. \n
  77. \n
  78. \n
  79. \n
  80. \n
  81. \n
  82. \n
  83. \n
  84. \n
  85. \n
  86. \n
  87. \n
  88. \n
  89. \n
  90. \n
  91. \n
  92. \n
  93. \n
  94. \n
  95. \n
  96. \n
  97. \n
  98. \n
  99. \n
  100. \n
  101. \n
  102. \n
  103. \n
  104. \n
  105. \n
  106. \n
  107. \n
  108. \n
  109. \n
  110. \n
  111. \n
  112. \n
  113. \n
  114. \n
  115. \n
  116. \n
  117. \n
  118. \n
  119. \n
  120. \n
  121. \n
  122. \n
  123. \n
  124. \n
  125. \n
  126. \n
  127. \n
  128. \n
  129. \n
  130. \n
  131. \n
  132. \n
  133. \n
  134. \n