implementing virtual machines in ruby & c

65
implementing virtual machines in Ruby & C Eleanor McHugh @feyeleanor http://github.com/feyeleanor

Upload: eleanor-mchugh

Post on 19-Jan-2017

492 views

Category:

Software


3 download

TRANSCRIPT

  • implementing virtual machines

    in Ruby & C

    Eleanor McHugh

    @feyeleanor

    http://github.com/feyeleanor

    http://github.com/feyeleanor

  • I made my own machine Yes, we're building steam I hate the same routine

    Building Steam, Abney Park

  • software is where machine meets thought

  • and as programmers we think a lot about thinking

  • whilst thinking very little about machines

  • we style ourselves philosophers & wizards

  • when machines need us to be engineers & analysts

  • so this is a talk about machine philosophy

  • framed in a language we humans can understand

  • so let's learn to love our Turing machines

  • by building other Turing machines' in their image

  • system virtualisation

  • hardware emulation

  • program execution

  • timely

    stateful

    conversational

    discrete

  • despatch loops

    fetch instruction

    decode

    execute

  • c: switch

    bytes or tokens

    portable

    #include #include #include "stack.h"

    #define READ_OPCODE *PC++

    typedef enum {PUSH = 0,ADD,PRINT,EXIT

    } opcodes;

    int program [] = {(int)PUSH, 13,(int)PUSH, 28,(int)ADD,PRINT,EXIT,

    };

    STACK *S;

    void interpret(int *PC) {int l, r;while (1) {

    switch(READ_OPCODE) {case PUSH:

    S = push(S, READ_OPCODE);break;

    case ADD:S = pop(S, &l);S = pop(S, &r);S = push(S, l + r);break;

    case PRINT:printf(%d + %d = %d\n, l, r, S->data);break;

    case EXIT:return;

    }}

    }

    int main() {interpret(program);

    }

  • ruby: switch

    symbols

    class VMdef initialize(*program)@program = program@s = []@pc = 0

    end

    def interpretloop do

    case read_programwhen :[email protected](read_program)

    when :add@s[1] += @s[0]@s = @s.drop(1)

    when :printputs "#{@s[0]}"

    when :exitreturn

    elseputs "#{op.class}"

    endend

    end

    private def read_programr = @program[@pc]

    @pc += 1r

    endend

    vm = VM.new(:push, 13,:push, 28,:add,:print,:exit,

    )vm.interpret

  • c: direct call

    pointer to function

    multi-byte

    portable

    #include #include #include "stack.h"

    #define READ_OPCODE *PC++typedef void (*opcode)();

    STACK *S;opcode *PC;

    void op_add_and_print() {int l, r;S = pop(S, &l);S = pop(S, &r);S = push(S, l + r);printf("%d + %d = %d\n", l, r, S->data);

    }

    void op_exit() {exit(0);

    }

    opcode program [] = {op_push, (opcode)(long)13,op_push, (opcode)(long)28,op_add_and_print,op_exit

    };

    int main() {PC = program;while (1) {

    (READ_OPCODE)();}

    }

  • ruby: direct call

    method names

    invoke via send

    class VMdef initialize *program

    @s = []@pc = 0@program = program.collect do |v|

    self.respond_to?(v) ? self.method(v) : vend

    end

    def interpretcatch :program_complete do

    loop doread_program.call

    endend

    end

    def [email protected](read_program)

    end

    def exitthrow :program_complete

    end

    def add_and_print@s[1] += @s[0]@s = @s.drop(1)puts "#{@s[0]}"

    end

    private def read_programr = @program[@pc]@pc += 1r

    end

    def dangerous_methodraise "!!! I'M NOT A VALID OP_CODE !!!"

    endend

    VM.new(:push, 13,:push, 28,:dangerous_method,:add_and_print,:exit

    ).interpret

  • ruby: direct call

    jit compilation

    sandboxing

    class VMBLACKLIST = [:load, :compile, :interpret] + Object.methods

    def initialize *program@s = []load(program)

    end

    def load program@program = compile(program)self

    end

    def compile programprogram.collect do |v|

    casewhen v.is_a?(Method)

    raise "method injection of #{v.inspect} is not supported" if BLACKLIST.include?(v.name)raise "unknown method #{v.inspect}" unless methods.include?(v.name)v = v.unbindv.bind(self)

    when methods.include?(v)raise "direct execution of #{v} is forbidden" if BLACKLIST.include?(v)self.method(v)

    elsev

    endend

    end

  • ruby: direct call

    jit compilation

    sandboxing

    def interpretcatch :program_complete do

    @pc = 0loop do

    read_program.callend

    endend

    end

    beginVM.new(:dangerous_method)

    rescue Exception => eputs "program compilation failed: #{e}"

    end

    vm = VM.newp = vm.compile([

    :push, 13,:push, 28,:add_and_print,:exit

    ])

    beginVM.new(*p)

    rescue Exception => eputs "program compilation failed: #{e}"

    end

    vm.load(p).interpretVM.new(*p).interpret

  • c: indirect thread

    local jumps

    gcc/clang specific

    indirect loading

    #include #include #include "stack.h"

    typedef enum {PUSH = 0, ADD, PRINT, EXIT

    } opcodes;

    void interpret(int *program) {static void *opcodes [] = {

    &&op_push,&&op_add,&&op_print,&&op_exit

    };

    int l, r;STACK *S;int *PC = program;goto *opcodes[*PC++];

    op_push:S = push(S, *PC++);goto *opcodes[*PC++];

    op_add:S = pop(S, &l);S = pop(S, &r);S = push(S, l + r);goto *opcodes[*PC++];

    op_print:printf("%d + %d = %d\n", l, r, S->data);goto *opcodes[*PC++];

    op_exit:return;

    }

    int main() {int program [] = {

    PUSH, 13,PUSH, 28,ADD,PRINT,EXIT

    };interpret(program);

    }

  • c: direct thread

    jit local jumps

    gcc/clang specific

    direct loading

    void interpret(int *PC, int words) {static void *dispatch_table[] = {

    &&op_push,&&op_add,&&op_print,&&op_exit

    };

    STACK *S;int l, r;void **program = compile(PC, words, dispatch_table);if (program == NULL)

    exit(1);goto **program++;

    op_push:S = push(S, (int)(long)*program++);goto **program++;

    op_add:S = pop(S, &l);S = pop(S, &r);S = push(S, l + r);goto **program++;

    op_print:printf("%d + %d = %d\n", l, r, S->data);goto **program++;

    op_exit:return;

    }

    int main() {int program[] = {

    PUSH, 13,PUSH, 28,ADD,PRINT,EXIT

    };interpret(program, 7);

    }

  • c: direct thread

    #define INTERPRETER(body, ...) \DISPATCHER(__VA_ARGS__); \void **p = compile(PC, d); \if (p == NULL) \

    exit(1); \EXECUTE_OPCODE \body

    #define DISPATCHER(...) \static void *d[] = { __VA_ARGS__ }

    #define READ_OPCODE \*p++

    #define EXECUTE_OPCODE \goto *READ_OPCODE;

    #define PRIMITIVE(name, body) \name: body; \EXECUTE_OPCODE

    void interpret(int *PC) {STACK *S;int l, r;INTERPRETER(

    PRIMITIVE(push,S = push(S, (int)(long)READ_OPCODE)

    )PRIMITIVE(add,

    S = pop(S, &l);S = pop(S, &r);S = push(S, l + r)

    )PRIMITIVE(print,

    printf("%d + %d = %d\n", l, r, S->data))PRIMITIVE(exit,

    return),&&push, &&add, &&print, &&exit)

    }

  • c: direct thread

    jit local jumps

    gcc/clang specific

    direct loading

    void **compile(int *PC, int words, void *dispatch_table[]) {static void *compiler [] = {

    &&comp_push,&&comp_add,&&comp_print,&&comp_exit

    };

    if (words < 1)return NULL;

    void **program = malloc(sizeof(void *) * words);void **cp = program;goto *compiler[*PC++];

    comp_push:*cp++ = dispatch_table[PUSH];*cp++ = (void *)(long)*PC++;words -= 2;if (words == 0)

    return program;goto *compiler[*PC++];

    comp_add:*cp++ = dispatch_table[ADD];words--;if (words == 0)

    return program;goto *compiler[*PC++];

    comp_print:*cp++ = dispatch_table[PRINT];words--;if (words == 0)

    return program;goto *compiler[*PC++];

    comp_exit:*cp++ = dispatch_table[EXIT];words--;if (words == 0)

    return program;goto *compiler[*PC++];

    }

  • ruby: direct thread

    meta-magic

    bind methods

    stack explosion

    probably not a good idea

  • registers

    operands

    local caching

  • vm harness

    dispatch

    program

    program counter

    class VMBL = [:load, :compile, :interpret] + Object.methods

    def initialize *programload(program)

    end

    def load program@program = compile(program)self

    end

    def interpretcatch :program_complete do

    @pc = 0loop do

    read_program.callend

    endend

    def read_programr = @program[@pc]@pc += 1r

    end

    def compile programprogram.collect do |v|

    casewhen v.is_a?(Method)

    if BL.include?(v.name)raise "forbidden method: #{v.name}"

    endunless methods.include?(v.name)

    raise "unknown method: #{v.name}"endv = v.unbindv.bind(self)

    when methods.include?(v)if BL.include?(v)

    raise "forbidden method: #{v}"endself.method(v)

    elsev

    endend

    endend

  • stack machine

    zero operands

    class Adder < VMdef interpret

    @s = []super

    end

    def print_stateputs "#{@pc}: @s => #{@s}"

    end

    def [email protected](read_program)read_program.call

    end

    def add@s[1] += @s[0]@s = @s.drop(1)read_program.call

    end

    def exitthrow :program_complete

    end

    def jump_if_not_zeroif @s[0] == 0

    @pc += 1else

    @pc = @program[@pc]endread_program.call

    endend

    Adder.new(:push, 13,:push, -1,:add,:print_state,:read_program,:print_state,:jump_if_not_zero, 2,:exit

    ).interpret

  • accumulator machine

    single register

    single operand

    class Adder < VMdef interpret

    @s = []@a = 0super

    end

    def print_stateputs "#{@pc}: @a = #{@a}, @s => #{@s}"

    end

    def clear@a = 0read_program.call

    end

    def [email protected](read_program)read_program.call

    end

    def [email protected](@accum)read_program.call

    end

    def add@a += @s.popread_program.call

    end

    def jump_if_not_zeroif @a == 0

    @pc += 1else

    @pc = @program[@pc]endread_program.call

    end

    def exitthrow :program_complete

    endend

    Adder.new(:clear,:push_value, 13,:print_state,:add,:print_state,:push_value, -1,:print_state,:add,:print_state,:read_program,:print_state,:jump_if_not_zero, 6,:exit

    ).interpret

  • register machine

    multi-register

    multi-operand

    class Adder < VMdef interpret

    @r = Array.new(2, 0)super

    end

    def load_value@r[read_program] = read_programread_program.call

    end

    def add@r[read_program] += @r[read_program]read_program.call

    end

    def jump_if_not_zeroif @r[read_program] == 0

    @pc += 1else

    @pc = @program[@pc]endread_program.call

    end

    def exitthrow :program_complete

    end

    def print_stateputs "#{@pc}: @r => #{@r}"

    endend

    Adder.new(:load_value, 0, 13,:load_value, 1, -1,:print_state,:add, 0, 1,:print_state,:jump_if_not_zero, 0, 7,:read_program,:print_state,:exit

    ).interpret

  • vector machine

    matrix machine

    hypercube

    graph processor

    any datatype can be a register

  • memory model

    instructions

    computation

    state

  • memory model

    opcodes

    stack

    heap

  • heaps

    word-aligned

    contiguous

    byte-addressable

  • ruby: array heap

    core class

    s = []s.push(1)s.push(3)

    puts "depth = #{s.length}"l = s.popr = s.popputs "#{l} + #{r} = #{l + r}"puts "depth = #{s.length}"

  • ruby: c heap

    require "fiddle"

    class Fiddle::PointerNIL = Pointer.new(0)SIZE = Fixnum::SIZE

    PACKING_PATTERN = case SIZEwhen 2 then "S"when 4 then "L"when 8 then "Q"end + "!"

    def write(value)str = Fiddle::format(value)pad = Fiddle::padding(str)l = pad + str.lengthraise BufferOverflow.new(self, l) if l > sizeself[0, l] = str + 0.chr * padself + l

    end

    def to_bin[self].pack(PACKING_PATTERN)

    endend

  • Home (./index.html) Classes(./index.html#classes) Methods(./index.html#methods)

    In Files

    fiddle/closure.c

    fiddle/fiddle.c

    fiddle/lib/fiddle.rb

    fiddle/lib/fiddle/closure.rb

    fiddle/lib/fiddle/cparser.rb

    fiddle/lib/fiddle/function.rb

    fiddle/lib/fiddle/import.rb

    fiddle/lib/fiddle/pack.rb

    fiddle/lib/fiddle/struct.rb

    fiddle/lib/fiddle/types.rb

    fiddle/lib/fiddle/value.rb

    Namespace

    MODULE Fiddle::BasicTypes (Fiddle/BasicTypes.html)MODULE Fiddle::CParser (Fiddle/CParser.html)MODULE Fiddle::CStructBuilder (Fiddle/CStructBuilder.html)MODULE Fiddle::Importer (Fiddle/Importer.html)MODULE Fiddle::Win32Types (Fiddle/Win32Types.html)CLASS Fiddle::CStruct (Fiddle/CStruct.html)CLASS Fiddle::CStructEntity (Fiddle/CStructEntity.html)CLASS Fiddle::CUnion (Fiddle/CUnion.html)CLASS Fiddle::CUnionEntity (Fiddle/CUnionEntity.html)CLASS Fiddle::Closure (Fiddle/Closure.html)CLASS Fiddle::CompositeHandler (Fiddle/CompositeHandler.html)CLASS Fiddle::DLError (Fiddle/DLError.html)CLASS Fiddle::Function (Fiddle/Function.html)CLASS Fiddle::Handle (Fiddle/Handle.html)CLASS Fiddle::Pointer (Fiddle/Pointer.html)

    Methods

    ::dlopen (#method-c-dlopen)::dlunwrap (#method-c-dlunwrap)::dlwrap (#method-c-dlwrap)::free (#method-c-free)::last_error (#method-c-last_error)::last_error= (#method-c-last_error-3D)::malloc (#method-c-malloc)::realloc (#method-c-realloc)::win32_last_error (#method-c-win32_last_error)::win32_last_error= (#method-c-win32_last_error-3D)

    Fiddle (./Fiddle.html)Fiddle::BasicTypes (./Fiddle/BasicTypes.html)Fiddle::CParser (./Fiddle/CParser.html)Fiddle::CStruct (./Fiddle/CStruct.html)Fiddle::CStructBuilder (./Fiddle/CStructBuilder.html)Fiddle::CStructEntity (./Fiddle/CStructEntity.html)Fiddle::CUnion (./Fiddle/CUnion.html)Fiddle::CUnionEntity (./Fiddle/CUnionEntity.html)Fiddle::Closure (./Fiddle/Closure.html)Fiddle::Closure::BlockCaller (./Fiddle/Closure/BlockCaller.html)Fiddle::CompositeHandler (./Fiddle/CompositeHandler.html)Fiddle::DLError (./Fiddle/DLError.html)Fiddle::Function (./Fiddle/Function.html)Fiddle::Handle (./Fiddle/Handle.html)Fiddle::Importer (./Fiddle/Importer.html)Fiddle::Pointer (./Fiddle/Pointer.html)Fiddle::Win32Types (./Fiddle/Win32Types.html)

    (http://yoururlhere.com//srv.carbonads.net/ads/click/x/GTND423UFTSIP27JCWA4YKQWCAADEKQICKBI4Z3JCESIE53UC6BDK27KC6BD553UCWSIKK3EHJNCLSIZ?

    segment=placement:rubydocorg;)

    Top software engineersare using IndeedPrime to land theirdream job.(http://yoururlhere.com//srv.carbonads.net/ads/click/x/GTND423UFTSIP27JCWA4YKQWCAADEKQICKBI4Z3JCESIE53UC6BDK27KC6BD553UCWSIKK3EHJNCLSIZ?

    segment=placement:rubydocorg;)

    ads via Carbon(http://carbonads.net/)

    Home (http://yoururlhere.com/) Core (http://yoururlhere.com/core) Std-lib (http://yoururlhere.com/stdlib) Downloads (http://yoururlhere.com/downloads)

    Search

    FiddleA libffi wrapper for Ruby.

    Description (#module-Fiddle-label-Description) (#top)

    Fiddle (Fiddle.html) is an extension to translate a foreign function interface (FFI) withruby.

    It wraps libffi (http://sourceware.org/libffi/), a popular C library which provides a portableinterface that allows code written in one language to call code written in anotherlanguage.

    Example (#module-Fiddle-label-Example) (#top)

    Here we will use Fiddle::Function (Fiddle/Function.html) to wrap floor(3) from libm(http://linux.die.net/man/3/floor)

    require 'fiddle'

    libm = Fiddle.dlopen('/lib/libm.so.6')

    floor = Fiddle::Function.new(

    libm['floor'],

    [Fiddle::TYPE_DOUBLE],

    Fiddle::TYPE_DOUBLE

    )

    puts floor.call(3.14159) #=> 3.0

    frozen_string_literal: false

    frozen_string_literal: false

    frozen_string_literal: false

    frozen_string_literal: false

    Constants

    ALIGN_CHARALIGN_CHARALIGN_CHAR (Fiddle.html#ALIGN_CHAR)

    The alignment size of a char

    ALIGN_DOUBLEALIGN_DOUBLEALIGN_DOUBLE (Fiddle.html#ALIGN_DOUBLE)

    The alignment size of a double

    ALIGN_FLOATALIGN_FLOATALIGN_FLOAT (Fiddle.html#ALIGN_FLOAT)

    The alignment size of a float

    ALIGN_INTALIGN_INTALIGN_INT (Fiddle.html#ALIGN_INT)

    The alignment size of an int

    ALIGN_INTPTR_TALIGN_INTPTR_TALIGN_INTPTR_T (Fiddle.html#ALIGN_INTPTR_T)

    The alignment size of a intptr_t

    ALIGN_LONGALIGN_LONGALIGN_LONG (Fiddle.html#ALIGN_LONG)

    The alignment size of a long

    Class/Module Index

    access DLLs

    call C functions

  • Home (../index.html) Classes(../index.html#classes) Methods(../index.html#methods)

    In Files

    fiddle/closure.c

    Parent

    Object

    Methods

    ::[] (#method-c-5B-5D)::malloc (#method-c-malloc)::new (#method-c-new)::to_ptr (#method-c-to_ptr)#+ (#method-i-2B)#+@ (#method-i-2B-40)#- (#method-i-2D)#-@ (#method-i-2D-40)# (#method-i-3C-3D-3E)#== (#method-i-3D-3D)#[] (#method-i-5B-5D)#[]= (#method-i-5B-5D-3D)#eql? (#method-i-eql-3F)#free (#method-i-free)#free= (#method-i-free-3D)#inspect (#method-i-inspect)#null? (#method-i-null-3F)#ptr (#method-i-ptr)#ref (#method-i-ref)#size (#method-i-size)#size= (#method-i-size-3D)#to_i (#method-i-to_i)#to_int (#method-i-to_int)#to_s (#method-i-to_s)#to_str (#method-i-to_str)#to_value (#method-i-to_value)

    Fiddle (../Fiddle.html)Fiddle::BasicTypes (../Fiddle/BasicTypes.html)Fiddle::CParser (../Fiddle/CParser.html)Fiddle::CStruct (../Fiddle/CStruct.html)Fiddle::CStructBuilder (../Fiddle/CStructBuilder.html)Fiddle::CStructEntity (../Fiddle/CStructEntity.html)Fiddle::CUnion (../Fiddle/CUnion.html)Fiddle::CUnionEntity (../Fiddle/CUnionEntity.html)Fiddle::Closure (../Fiddle/Closure.html)Fiddle::Closure::BlockCaller (../Fiddle/Closure/BlockCaller.html)Fiddle::CompositeHandler (../Fiddle/CompositeHandler.html)Fiddle::DLError (../Fiddle/DLError.html)Fiddle::Function (../Fiddle/Function.html)Fiddle::Handle (../Fiddle/Handle.html)Fiddle::Importer (../Fiddle/Importer.html)Fiddle::Pointer (../Fiddle/Pointer.html)Fiddle::Win32Types (../Fiddle/Win32Types.html)

    (http://yoururlhere.com//srv.carbonads.net/ads/click/x/GTND423UFTSI52JECWB4YKQWCAADEK3JCAADCZ3JCESIE53MFT7IK2QKC6BD553UCABIKK3EHJNCLSIZ?

    segment=placement:rubydocorg;)

    Top software engineersare using IndeedPrime to land theirdream job.(http://yoururlhere.com//srv.carbonads.net/ads/click/x/GTND423UFTSI52JECWB4YKQWCAADEK3JCAADCZ3JCESIE53MFT7IK2QKC6BD553UCABIKK3EHJNCLSIZ?

    segment=placement:rubydocorg;)

    ads via Carbon(http://carbonads.net/)

    (http://yoururlhere.com//srv.carbonads.net/ads/click/x/GTND423UFTSI52JECWB4YKQWCAADEK3JCAADCZ3JCESIE53MFT7IK2QKC6BD553UCABIKK3EHJNCLSIZ?

    segment=placement:rubydocorg;)

    Top software engineersare using IndeedPrime to land theirdream job.(http://yoururlhere.com//srv.carbonads.net/ads/click/x/GTND423UFTSI52JECWB4YKQWCAADEK3JCAADCZ3JCESIE53MFT7IK2QKC6BD553UCABIKK3EHJNCLSIZ?

    segment=placement:rubydocorg;)

    ads via Carbon(http://carbonads.net/)

    Home (http://yoururlhere.com/) Core (http://yoururlhere.com/core) Std-lib (http://yoururlhere.com/stdlib) Downloads (http://yoururlhere.com/downloads)

    Search

    Fiddle::PointerFiddle::Pointer (Pointer.html) is a class to handle C pointers

    Public Class Methods

    Get the underlying pointer for ruby object val and return it as a Fiddle::Pointer (Pointer.html) object.

    Allocate size bytes of memory and associate it with an optional freefunc that will be called when thepointer is garbage collected.

    freefunc must be an address pointing to a function or an instance of Fiddle::Function (Function.html)

    Create a new pointer to address with an optional size and freefunc.

    freefunc will be called when the instance is garbage collected.

    Get the underlying pointer for ruby object val and return it as a Fiddle::Pointer (Pointer.html) object.

    Public Instance Methods

    Returns a new pointer instance that has been advanced n bytes.

    Returns a new Fiddle::Pointer (Pointer.html) instance that is a dereferenced pointer for this pointer.

    Analogous to the star operator in C.

    Returns a new pointer instance that has been moved back n bytes.

    Returns a new Fiddle::Pointer (Pointer.html) instance that is a reference pointer for this pointer.

    Analogous to the ampersand operator in C.

    Returns -1 if less than, 0 if equal to, 1 if greater than other.

    Returns nil if ptr cannot be compared to other.

    Returns true if other wraps the same pointer, otherwise returns false.

    Returns integer stored at index.

    Class/Module Index

    Fiddle::Pointer[val] => cptrto_ptr(val) => cptr

    Fiddle::Pointer.malloc(size, freefunc = nil) => fiddle pointer instance

    Fiddle::Pointer.new(address) => fiddle_cptrnew(address, size) => fiddle_cptrnew(address, size, freefunc) => fiddle_cptr

    to_ptr(val) => cptr

    ptr + n => new cptr

    ptr

    ptr - n => new cptr

    ref

    ptr other => -1, 0, 1, or nil

    ptr == other => true or false

    ptr[index] an_integerptr[start, length] a_string

    MRI stdlib

    C pointers

    malloc

    not portable

  • ruby: c heap

    def Fiddle::Pointer.format(value)value.respond_to?(:to_bin) ? value.to_bin : Marshal.dump(value)

    end

  • ruby: c heap

    require "fiddle"

    class Fiddle::PointerNIL = Pointer.new(0)SIZE = Fixnum::SIZE

    PACKING_PATTERN = case SIZEwhen 2 then "S"when 4 then "L"when 8 then "Q"end + "!"

    def write(value)str = Fiddle::format(value)pad = Fiddle::padding(str)l = pad + str.lengthraise BufferOverflow.new(self, l) if l > sizeself[0, l] = str + 0.chr * padself + l

    end

    def to_bin[self].pack(PACKING_PATTERN)

    endend

  • ruby: c heap

    class FixnumSIZE = 1.size

    PACKING_PATTERN = case SIZEwhen 2 then "s"when 4 then "l"when 8 then "q"end + "!"

    def to_bin[self].pack(PACKING_PATTERN)

    end

    def self.read_bin(pointer)pointer[0, SIZE].unpack(PACKING_PATTERN).first

    endend

  • ruby: c heap

    m = Fiddle::Pointer.malloc 64begin m.write(0.chr * 59)

    m.write(0.chr * 60)m.write(0.chr * 61)

    rescue Fiddle::BufferOverflow => ep e.message

    end

    "Buffer overflow: 72 bytes at #"

  • ruby: c heap

    s = "Hello, Terrible Memory Bank!"i = 4193f = 17.00091

    m.write(i)puts m.readq = m.write(-i)puts m.read

    q.write(s)puts q.read(String)

    r = q.write(s[0, s.length - 1])puts q.read(String)

    t = r.write(f)puts r.read(Float)

    t.write(-f)puts t.read(Float)

    => 4193

    => -4193

    => Hello, Terrible Memory Bank!

    => Hello, Terrible Memory Bank

    => 17.00091

    => -17.00091

  • stacks

    sequential

    bounded depth

    push & pop

  • sequential

    push data on

    pop data off

  • contiguous

    bounded depth

  • c: array stack

    fixed size

    malloc to create

    realloc to resize

    #include #define STACK_MAX 100

    typedef enum {STACK_OK = 0,STACK_OVERFLOW,STACK_UNDERFLOW

    } STACK_STATUS;

    typedef struct stack STACK;struct stack {

    int data[STACK_MAX];int size;

    };

    STACK *NewStack() {STACK *s;s = malloc(sizeof(STACK));s->size = 0;return s;

    }

    int depth(STACK *s) {return s->size;

    }

    STACK_STATUS push(STACK *s, int data) {if (s->size < STACK_MAX) {

    s->data[s->size++] = data;return STACK_OK;

    }return STACK_OVERFLOW;

    }

    STACK_STATUS pop(STACK *s, int *r) {if (s->size > 0) {

    *r = s->data[s->size - 1];s->size--;return STACK_OK;

    }return STACK_UNDERFLOW;

    }

  • ruby: array stack

    core class

    stack semantics

    s = []s.push(1)s.push(3)

    puts "depth = #{s.length}"l = s.popr = s.popputs "#{l} + #{r} = #{l + r}"puts "depth = #{s.length}"

  • singly linked list

    functional

    shared elements

    immutability

  • c: cactus stack

    nil is empty

    grows on push

    manual GC

    #include

    typedef struct stack STACK;struct stack {

    int data;STACK *next;

    };

    STACK *push(STACK *s, int data) {STACK *r = malloc(sizeof(STACK));r->data = data;r->next = s;return r;

    }

    STACK *pop(STACK *s, int *r) {if (s == NULL)

    exit(1);*r = s->data;return s->next;

    }

    int depth(STACK *s) {int r = 0;for (STACK *t = s; t != NULL; t = t->next) {

    r++;}return r;

    }

    void gc(STACK **old, int items) {STACK *t;for (; items > 0 && *old != NULL; items--) {

    t = *old;*old = (*old)->next;free(t);

    }}

  • c: cactus stack

    nil is empty

    grows on push

    manual GC

    #include #include

    int sum(STACK *tos) {int a = 0;for (int p = 0; tos != NULL;) {

    tos = pop(tos, &p);a += p;

    }return a;

    }

    void print_sum(STACK *s) {printf("%d items: sum = %d\n", depth(s), sum(s));

    }

    int main() {STACK *s1 = push(NULL, 7);STACK *s2 = push(push(s1, 7), 11);s1 = push(push(push(s1, 2), 9), 4);

    STACK *s3 = push(s1, 17);s1 = push(s1, 3);print_sum(s1);print_sum(s2);print_sum(s3);

    }

  • ruby: cactus stack

    nil is empty

    grows on push

    automatic GC

    class Stackinclude Enumerableattr_reader :head, :tail

    def initialize data, tail = nil@head = data@tail = tail || EmptyStack.new

    end

    def push itemStack.new item, self

    end

    def pop[head, tail]

    end

    def eacht = selfuntil t.is_a?(EmptyStack)

    yield t.headt = t.tail

    endend

    end

    class EmptyStackinclude Enumerable

    def push itemStack.new item

    end

    def pop[nil, self]

    end

    def each; endend

  • caches

    word-aligned

    discontiguous

    label-addressable

  • c: hash map

    array

    associative arrays

    search

    #include

    struct map {int size;assoc_array_t **chains;

    };typedef struct map map_t;

    map_t *map_new(int size) {map_t *m = malloc(sizeof(map_t));m->chains = malloc(sizeof(assoc_array_t*) * size);for (int i = 0; i < size; i++) {

    m->chains[i] = NULL;}m->size = size;return m;

    }

    int map_chain(map_t *m, char *k) {unsigned long int b;for (int i = strlen(k) - 1; b < ULONG_MAX && i > 0; i--) {

    b = b size;

    }

    char *map_get(map_t *m, char *k) {search_t *s = search_find(m->chains[map_chain(m, k)], k);if (s != NULL) {

    return s->value;}return NULL;

    }

    void map_set(map_t *m, char *k, char *v) {int b = map_chain(m, k);assoc_array_t *a = m->chains[b];search_t *s = search_find(a, k);if (s->value != NULL) {

    s->cursor->value = strdup(v);} else {

    assoc_array_t *n = assoc_array_new(k, v);if (s->cursor == a) {

    n->next = s->cursor;m->chains[b] = n;

    } else if (s->cursor == NULL) {s->memo->next = n;

    } else {n->next = s->cursor;s->memo->next = n;

    }}free(s);

    }

  • c: hash map

    array

    associative arrays

    search

    #include #include

    struct assoc_array {char *key;void *value;struct assoc_array *next;

    };typedef struct assoc_array assoc_array_t;

    assoc_array_t *assoc_array_new(char *k, char *v) {assoc_array_t *a = malloc(sizeof(assoc_array_t));a->key = strdup(k);a->value = strdup(v);a->next = NULL;return a;

    }

    char *assoc_array_get_if(assoc_array_t *a, char *k) {char *r = NULL;if (a != NULL && strcmp(a->key, k) == 0) {

    r = strdup(a->value);}return r;

    }

  • c: hash map

    array

    associative arrays

    search

    struct search {char *term, *value;assoc_array_t *cursor, *memo;

    };typedef struct search search_t;

    search_t *search_new(assoc_array_t *a, char *k) {search_t *s = malloc(sizeof(search_t));s->term = k;s->value = NULL;s->cursor = a;s->memo = NULL;return s;

    }

    void search_step(search_t *s) {s->value = assoc_array_get_if(s->cursor, s->term);

    }

    int searching(search_t *s) {return s->value == NULL && s->cursor != NULL;

    }

    search_t *search_find(assoc_array_t *a, char *k) {search_t *s = search_new(a, k);for (search_step(s); searching(s); search_step(s)) {

    s->memo = s->cursor;s->cursor = s->cursor->next;

    }return s;

    }

  • c: hash map

    array

    associative arrays

    search

    #include #include map.h

    int main( int argc, char **argv ) {map_t *m = map_new(1024);map_set(m, "apple", "rosy");printf("%s\n", map_get(m, "apple"));map_set(m, "blueberry", "sweet");printf("%s\n", map_get(m, "blueberry"));map_set(m, "cherry", "pie");printf("%s\n", map_get(m, "cherry"));map_set(m, "cherry", "tart");printf("%s\n", map_get(m, "cherry"));printf("%s\n", map_get(m, tart"));

    }

    rosy

    sweet

    pie

    tart(null)

  • ruby: hash map

    core class

    m = {"apple": "rosy"}puts(m["apple"])

    m["blueberry"] = "sweet"puts m["blueberry"]

    m["cherry"] = "pie"puts m["cherry"]

    m["cherry"] = "tart"puts m["cherry"]

    puts m["tart"]

    rosy

    sweet

    pie

    tart

  • This repository Pull requests Issues Gist

    No description or website provided.

    demo + Switched to install for Makefile. 11 years ago

    lib Added note about using absolute paths to rootdir rdoc 8 months ago

    test Added assertion to quell minitest saying I'm not testing something 3 years ago

    tutorial - Fixed examples for 1.9 compatibility. 5 years ago

    History.txt prepped for release 2 years ago

    Manifest.txt Removed inline_package in favor of hoe's packaging. 9 years ago

    README.txt - Fixed code/home urls in readme/gem. 4 years ago

    Rakefile isolated and cleaned dependencies 5 years ago

    example.rb - Clean up example.rb and force removal of ~/.ruby_inline 7 years ago

    example2.rb - Fixed examples for 1.9 compatibility. 5 years ago

    Search

    seattlerb / rubyinline

    Code Issues 0 Pull requests 0 Projects 0 Wiki Pulse Graphs

    176 commits 1 branch 0 releases 3 contributors

    Clone or downloadClone or download Create new file Upload files Find file master Branch: New pull request

    Latest commit 112e6ad on 31 Mar zenspider Added note about using absolute paths to rootdir rdoc

    README.txt

    = Ruby Inline

    rdoc :: http://docs.seattlerb.org/RubyInline/home :: http://www.zenspider.com/ZSS/Products/RubyInline/code :: https://github.com/seattlerb/rubyinline

    == DESCRIPTION:

    Inline allows you to write foreign code within your ruby code. Itautomatically determines if the code in question has changed andbuilds it only when necessary. The extensions are then automaticallyloaded into the class/module that defines it.

    You can even write extra builders that will allow you to write inlinedcode in any language. Use Inline::C as a template and look atModule#inline for the required API.

    == PACKAGING:

    To package your binaries into a gem, use hoe's INLINE andFORCE_PLATFORM env vars.

    Example:

    rake package INLINE=1

    or:

    rake package INLINE=1 FORCE_PLATFORM=mswin32

    See hoe for more details.

    == FEATURES/PROBLEMS:

    * Quick and easy inlining of your C or C++ code embedded in your ruby script.

    191 3115 Watch Star Fork

    rubyinline

    inline c

  • This repository Pull requests Issues Gist

    No description or website provided.

    lib prepped for release a year ago

    test + Switched to minitest 8 years ago

    History.txt prepped for release a year ago

    Manifest.txt prepped for release 8 years ago

    README.txt Updated with better examples 8 years ago

    Rakefile Skip all 2.x 2 years ago

    bench.rb + Improved benchmark code 8 years ago

    example.rb - Fixed defasm to work much better. 8 years ago

    Search

    seattlerb / wilson

    Code Issues 1 Pull requests 0 Projects 0 Wiki Pulse Graphs

    27 commits 1 branch 0 releases 2 contributors

    Clone or downloadClone or download Create new file Upload files Find file master Branch: New pull request

    Latest commit 82d990f on 26 Oct 2015 zenspider prepped for release

    README.txt

    = wilson

    * http://rubyforge.org/projects/seattlerb

    == DESCRIPTION:

    Wilson is a pure ruby x86 assembler. No, really. Worst Idea Evar.

    Why "wilson"? I wanted to name it "metal", but there is an existingproject with that name... So I'm naming it after Wilson Bilkovich, whois about as metal as you can get (and it is easier to spell than"bilkovich", even tho that sounds more metal).

    == FEATURES/PROBLEMS:

    * Generates x86 machine code directly. No dependencies. No system calls.* Registers ruby methods with #defasm, or run inline assembly with #asm.* Terrible, yet, awesome.

    == SYNOPSIS:

    class X defasm :superfast_meaning_of_life do eax.mov 42 to_ruby eax # ruby fixnums = (n

  • This repository Pull requests Issues Gist

    NeverSayDie will let you rescue from SEGV's and is evil

    ext/neversaydie Changed Config:: for RbConfig 2 years ago

    lib making class declarations line up 7 years ago

    test updating rdoc, removing binfile 7 years ago

    .autotest adding extconf stuff 7 years ago

    .gitignore adding pkg to git ignore 7 years ago

    CHANGELOG.ja.rdoc translating stuff 7 years ago

    CHANGELOG.rdoc adding extconf stuff 7 years ago

    Manifest.txt updating manifest 7 years ago

    README.ja.rdoc Natural Japanese 7 years ago

    README.rdoc Added documentation for debian 2 years ago

    Rakefile Rakefile + gemspec fixes 2 years ago

    neversaydie.gemspec Rakefile + gemspec fixes 2 years ago

    Search

    tenderlove / neversaydie

    Code Issues 1 Pull requests 1 Projects 0 Wiki Pulse Graphs

    18 commits 1 branch 0 releases 3 contributors

    Clone or downloadClone or download Create new file Upload files Find file master Branch: New pull request

    Latest commit 1766194 on 12 Jun 2015 tenderlove Merge pull request #3 from cortexmedia/master

    README.rdoc

    NeverSayDieseattlerb.rubyforge.org

    github.com/tenderlove/neversaydie

    DESCRIPTION:

    NEVER SAY DIE lets you rescue from segmentation faults. Got a SEGV, don't worry about it anymore! Just rescue an

    exception and get on with life. Who cares about getting a SEGV anyway? It's just memory. I mean, when I was in school, I

    didn't need 100% to pass the class. Why should your memory need to be 100% correct to get the job done? A little memory

    corruption here and there doesn't hurt anyone.

    So go for it! Kick back, grab a beer, require the NEVER SAY DIE gem and let your problems go away sometimes!

    FEATURES/PROBLEMS:

    Oh so many problems

    Portability

    Not solving the root cause..

    It might not work.

    35 82 Watch Unstar Fork

    never day die

    libsigsegfault

  • SIMD

    branch prediction

    cache misses

    memory latency