SlideShare une entreprise Scribd logo
1  sur  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

Contenu connexe

Tendances

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
Mario Fusco
 
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
Mario Fusco
 

Tendances (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
 

Similaire à GoLightly: Building VM-Based Language Runtimes with Google Go

Similaire à 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
 

Plus de Eleanor McHugh

Plus de Eleanor McHugh (20)

[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf
 
Generics, Reflection, and Efficient Collections
Generics, Reflection, and Efficient CollectionsGenerics, Reflection, and Efficient Collections
Generics, Reflection, and Efficient Collections
 
The Relevance of Liveness - Biometrics and Data Integrity
The Relevance of Liveness - Biometrics and Data IntegrityThe Relevance of Liveness - Biometrics and Data Integrity
The Relevance of Liveness - Biometrics and Data Integrity
 
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
 
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
 

Dernier

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Dernier (20)

How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 

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

Notes de l'éditeur

  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