SlideShare una empresa de Scribd logo
1 de 65
Descargar para leer sin conexión
implementing
virtual machines
in
Ruby & C
Eleanor McHugh
@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 <stdio.h>
#include <stdlib.h>
#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 = %dn, l, r, S->data);
break;
case EXIT:
return;
}
}
}
int main() {
interpret(program);
}
ruby: switch
symbols
class VM
def initialize(*program)
@program = program
@s = []
@pc = 0
end
def interpret
loop do
case read_program
when :push
@s.push(read_program)
when :add
@s[1] += @s[0]
@s = @s.drop(1)
when :print
puts "#{@s[0]}"
when :exit
return
else
puts "#{op.class}"
end
end
end
private def read_program
r = @program[@pc]
@pc += 1
r
end
end
vm = VM.new(
:push, 13,
:push, 28,
:add,
:print,
:exit,
)
vm.interpret
c: direct call
pointer to function
multi-byte
portable
#include <stdio.h>
#include <stdlib.h>
#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 = %dn", 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 VM
def initialize *program
@s = []
@pc = 0
@program = program.collect do |v|
self.respond_to?(v) ? self.method(v) : v
end
end
def interpret
catch :program_complete do
loop do
read_program.call
end
end
end
def push
@s.push(read_program)
end
def exit
throw :program_complete
end
def add_and_print
@s[1] += @s[0]
@s = @s.drop(1)
puts "#{@s[0]}"
end
private def read_program
r = @program[@pc]
@pc += 1
r
end
def dangerous_method
raise "!!! I'M NOT A VALID OP_CODE !!!"
end
end
VM.new(
:push, 13,
:push, 28,
:dangerous_method,
:add_and_print,
:exit
).interpret
ruby: direct call
jit compilation
sandboxing
class VM
BLACKLIST = [:load, :compile, :interpret] + Object.methods
def initialize *program
@s = []
load(program)
end
def load program
@program = compile(program)
self
end
def compile program
program.collect do |v|
case
when 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.unbind
v.bind(self)
when methods.include?(v)
raise "direct execution of #{v} is forbidden" if BLACKLIST.include?(v)
self.method(v)
else
v
end
end
end
ruby: direct call
jit compilation
sandboxing
def interpret
catch :program_complete do
@pc = 0
loop do
read_program.call
end
end
end
end
begin
VM.new(:dangerous_method)
rescue Exception => e
puts "program compilation failed: #{e}"
end
vm = VM.new
p = vm.compile([
:push, 13,
:push, 28,
:add_and_print,
:exit
])
begin
VM.new(*p)
rescue Exception => e
puts "program compilation failed: #{e}"
end
vm.load(p).interpret
VM.new(*p).interpret
c: indirect thread
local jumps
gcc/clang specific
indirect loading
#include <stdio.h>
#include <stdlib.h>
#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 = %dn", 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 = %dn", 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 = %dn", 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 VM
BL = [:load, :compile, :interpret] + Object.methods
def initialize *program
load(program)
end
def load program
@program = compile(program)
self
end
def interpret
catch :program_complete do
@pc = 0
loop do
read_program.call
end
end
end
def read_program
r = @program[@pc]
@pc += 1
r
end
def compile program
program.collect do |v|
case
when v.is_a?(Method)
if BL.include?(v.name)
raise "forbidden method: #{v.name}"
end
unless methods.include?(v.name)
raise "unknown method: #{v.name}"
end
v = v.unbind
v.bind(self)
when methods.include?(v)
if BL.include?(v)
raise "forbidden method: #{v}"
end
self.method(v)
else
v
end
end
end
end
stack machine
zero operands
class Adder < VM
def interpret
@s = []
super
end
def print_state
puts "#{@pc}: @s => #{@s}"
end
def push
@s.push(read_program)
read_program.call
end
def add
@s[1] += @s[0]
@s = @s.drop(1)
read_program.call
end
def exit
throw :program_complete
end
def jump_if_not_zero
if @s[0] == 0
@pc += 1
else
@pc = @program[@pc]
end
read_program.call
end
end
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 < VM
def interpret
@s = []
@a = 0
super
end
def print_state
puts "#{@pc}: @a = #{@a}, @s => #{@s}"
end
def clear
@a = 0
read_program.call
end
def push_value
@s.push(read_program)
read_program.call
end
def push
@s.push(@accum)
read_program.call
end
def add
@a += @s.pop
read_program.call
end
def jump_if_not_zero
if @a == 0
@pc += 1
else
@pc = @program[@pc]
end
read_program.call
end
def exit
throw :program_complete
end
end
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 < VM
def interpret
@r = Array.new(2, 0)
super
end
def load_value
@r[read_program] = read_program
read_program.call
end
def add
@r[read_program] += @r[read_program]
read_program.call
end
def jump_if_not_zero
if @r[read_program] == 0
@pc += 1
else
@pc = @program[@pc]
end
read_program.call
end
def exit
throw :program_complete
end
def print_state
puts "#{@pc}: @r => #{@r}"
end
end
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.pop
r = s.pop
puts "#{l} + #{r} = #{l + r}"
puts "depth = #{s.length}"
ruby: c heap
require "fiddle"
class Fiddle::Pointer
NIL = Pointer.new(0)
SIZE = Fixnum::SIZE
PACKING_PATTERN = case SIZE
when 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.length
raise BufferOverflow.new(self, l) if l > size
self[0, l] = str + 0.chr * pad
self + l
end
def to_bin
[self].pack(PACKING_PATTERN)
end
end
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)
Fiddle
A libffi wrapper for Ruby.
Description¶ (#module-Fiddle-label-Description) ↑ (#top)
Fiddle (Fiddle.html) is an extension to translate a foreign function interface (FFI) with
ruby.
It wraps libffi (http://sourceware.org/libffi/), a popular C library which provides a portable
interface that allows code written in one language to call code written in another
language.
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
)
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)
Fiddle::Pointer
Fiddle::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 the
pointer 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.
Fiddle::Pointer[val] => cptr
to_ptr(val) => cptr
Fiddle::Pointer.malloc(size, freefunc = nil) => fiddle pointer instance
Fiddle::Pointer.new(address) => fiddle_cptr
new(address, size) => fiddle_cptr
new(address, size, freefunc) => fiddle_cptr
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::Pointer
NIL = Pointer.new(0)
SIZE = Fixnum::SIZE
PACKING_PATTERN = case SIZE
when 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.length
raise BufferOverflow.new(self, l) if l > size
self[0, l] = str + 0.chr * pad
self + l
end
def to_bin
[self].pack(PACKING_PATTERN)
end
end
ruby: c heap
class Fixnum
SIZE = 1.size
PACKING_PATTERN = case SIZE
when 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
end
end
ruby: c heap
m = Fiddle::Pointer.malloc 64
begin
m.write(0.chr * 59)
m.write(0.chr * 60)
m.write(0.chr * 61)
rescue Fiddle::BufferOverflow => e
p e.message
end
"Buffer overflow: 72 bytes at #<Fiddle::Pointer:0x007f8849052160
ptr=0x007f8849051da0 size=64 free=0x00000000000000>"
ruby: c heap
s = "Hello, Terrible Memory Bank!"
i = 4193
f = 17.00091
m.write(i)
puts m.read
q = 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 <stdlib.h>
#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.pop
r = s.pop
puts "#{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 <stdlib.h>
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 <stdio.h>
#include <cactus_stack.h>
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 = %dn", 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 Stack
include Enumerable
attr_reader :head, :tail
def initialize data, tail = nil
@head = data
@tail = tail || EmptyStack.new
end
def push item
Stack.new item, self
end
def pop
[head, tail]
end
def each
t = self
until t.is_a?(EmptyStack)
yield t.head
t = t.tail
end
end
end
class EmptyStack
include Enumerable
def push item
Stack.new item
end
def pop
[nil, self]
end
def each; end
end
caches
word-aligned
discontiguous
label-addressable
c: hash map
array
associative arrays
search
#include <limits.h>
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 << 8;
b += k[i];
}
return b % m->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 <stdlib.h>
#include <string.h>
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 <stdio.h>
#include “map.h
int main( int argc, char **argv ) {
map_t *m = map_new(1024);
map_set(m, "apple", "rosy");
printf("%sn", map_get(m, "apple"));
map_set(m, "blueberry", "sweet");
printf("%sn", map_get(m, "blueberry"));
map_set(m, "cherry", "pie");
printf("%sn", map_get(m, "cherry"));
map_set(m, "cherry", "tart");
printf("%sn", map_get(m, "cherry"));
printf("%sn", 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 Issu
No description or website provided.
demo + Switched to install for Makefile.
lib Added note about using absolute paths to rootdir rdoc
test Added assertion to quell minitest saying I'm not testing s
Search
seattlerb / rubyinline
Code Issues 0 Pull requests 0 Projects 0 Wiki
176 commits 1 branch
masterBranch: New pull request
zenspider Added note about using absolute paths to rootdir rdoc …
rubyinline
inline c
This repository Pull requests Issu
No description or website provided.
lib prepped for release
test + Switched to minitest
History.txt prepped for release
Search
seattlerb / wilson
Code Issues 1 Pull requests 0 Projects 0 Wiki
27 commits 1 branch
masterBranch: New pull request
zenspider prepped for release …
wilson
x86_64 asm
This repository Pull requests Issu
NeverSayDie will let you rescue from SEGV's and is evil
ext/neversaydie Changed Config:: for RbCo
lib making class declarations l
test updating rdoc, removing bi
Search
tenderlove / neversaydie
Code Issues 1 Pull requests 1 Projects 0 Wiki
18 commits 1 branch
masterBranch: New pull request
tenderlove Merge pull request #3 from cortexmedia/master …
never day die
libsigsegfault
SIMD
branch prediction
cache misses
memory latency
Implementing Virtual Machines in Ruby & C

Más contenido relacionado

La actualidad más candente

La actualidad más candente (20)

C++ Programming - 1st Study
C++ Programming - 1st StudyC++ Programming - 1st Study
C++ Programming - 1st Study
 
Data structures
Data structuresData structures
Data structures
 
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
 
Pratt Parser in Python
Pratt Parser in PythonPratt Parser in Python
Pratt Parser in Python
 
Single linked list
Single linked listSingle linked list
Single linked list
 
C Programming Language Part 7
C Programming Language Part 7C Programming Language Part 7
C Programming Language Part 7
 
1 introducing c language
1  introducing c language1  introducing c language
1 introducing c language
 
C++ Programming - 2nd Study
C++ Programming - 2nd StudyC++ Programming - 2nd Study
C++ Programming - 2nd Study
 
Pattern printing-in-c(Jaydip Kikani)
Pattern printing-in-c(Jaydip Kikani)Pattern printing-in-c(Jaydip Kikani)
Pattern printing-in-c(Jaydip Kikani)
 
Circular linked list
Circular linked listCircular linked list
Circular linked list
 
week-15x
week-15xweek-15x
week-15x
 
4 operators, expressions &amp; statements
4  operators, expressions &amp; statements4  operators, expressions &amp; statements
4 operators, expressions &amp; statements
 
Functuon
FunctuonFunctuon
Functuon
 
7 functions
7  functions7  functions
7 functions
 
Applications of list
Applications of listApplications of list
Applications of list
 
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
 
Free Monads Getting Started
Free Monads Getting StartedFree Monads Getting Started
Free Monads Getting Started
 
8 arrays and pointers
8  arrays and pointers8  arrays and pointers
8 arrays and pointers
 
C Programming Language Part 6
C Programming Language Part 6C Programming Language Part 6
C Programming Language Part 6
 
Building resilient services in go
Building resilient services in goBuilding resilient services in go
Building resilient services in go
 

Destacado

Ruby without rails
Ruby without railsRuby without rails
Ruby without rails
Eddie Kao
 
Choosing A Proxy Server - Apachecon 2014
Choosing A Proxy Server - Apachecon 2014Choosing A Proxy Server - Apachecon 2014
Choosing A Proxy Server - Apachecon 2014
bryan_call
 
Aljoscha Krettek - Apache Flink for IoT: How Event-Time Processing Enables Ea...
Aljoscha Krettek - Apache Flink for IoT: How Event-Time Processing Enables Ea...Aljoscha Krettek - Apache Flink for IoT: How Event-Time Processing Enables Ea...
Aljoscha Krettek - Apache Flink for IoT: How Event-Time Processing Enables Ea...
Ververica
 

Destacado (10)

Ruby without rails
Ruby without railsRuby without rails
Ruby without rails
 
Invited cloud-e-Genome project talk at 2015 NGS Data Congress
Invited cloud-e-Genome project talk at 2015 NGS Data CongressInvited cloud-e-Genome project talk at 2015 NGS Data Congress
Invited cloud-e-Genome project talk at 2015 NGS Data Congress
 
Ruby Internals
Ruby InternalsRuby Internals
Ruby Internals
 
Hourglass: a Library for Incremental Processing on Hadoop
Hourglass: a Library for Incremental Processing on HadoopHourglass: a Library for Incremental Processing on Hadoop
Hourglass: a Library for Incremental Processing on Hadoop
 
ORTC Library - Introduction
ORTC Library - IntroductionORTC Library - Introduction
ORTC Library - Introduction
 
Performance Implications of Mobile Design
Performance Implications of Mobile DesignPerformance Implications of Mobile Design
Performance Implications of Mobile Design
 
Effective IoT System on Openstack
Effective IoT System on OpenstackEffective IoT System on Openstack
Effective IoT System on Openstack
 
Choosing A Proxy Server - Apachecon 2014
Choosing A Proxy Server - Apachecon 2014Choosing A Proxy Server - Apachecon 2014
Choosing A Proxy Server - Apachecon 2014
 
Aljoscha Krettek - Apache Flink for IoT: How Event-Time Processing Enables Ea...
Aljoscha Krettek - Apache Flink for IoT: How Event-Time Processing Enables Ea...Aljoscha Krettek - Apache Flink for IoT: How Event-Time Processing Enables Ea...
Aljoscha Krettek - Apache Flink for IoT: How Event-Time Processing Enables Ea...
 
Sparkler - Spark Crawler
Sparkler - Spark Crawler Sparkler - Spark Crawler
Sparkler - Spark Crawler
 

Similar a Implementing Virtual Machines in Ruby & C

Beware: Sharp Tools
Beware: Sharp ToolsBeware: Sharp Tools
Beware: Sharp Tools
chrismdp
 
Dti2143 lab sheet 9
Dti2143 lab sheet 9Dti2143 lab sheet 9
Dti2143 lab sheet 9
alish sha
 
Bti1022 lab sheet 9 10
Bti1022 lab sheet 9 10Bti1022 lab sheet 9 10
Bti1022 lab sheet 9 10
alish sha
 
How I Built a Power Debugger Out of the Standard Library and Things I Found o...
How I Built a Power Debugger Out of the Standard Library and Things I Found o...How I Built a Power Debugger Out of the Standard Library and Things I Found o...
How I Built a Power Debugger Out of the Standard Library and Things I Found o...
doughellmann
 
Building Interpreters with PyPy
Building Interpreters with PyPyBuilding Interpreters with PyPy
Building Interpreters with PyPy
Daniel Neuhäuser
 
(ThoughtWorks Away Day 2009) one or two things you may not know about typesys...
(ThoughtWorks Away Day 2009) one or two things you may not know about typesys...(ThoughtWorks Away Day 2009) one or two things you may not know about typesys...
(ThoughtWorks Away Day 2009) one or two things you may not know about typesys...
Phil Calçado
 

Similar a Implementing Virtual Machines in Ruby & C (20)

golang_getting_started.pptx
golang_getting_started.pptxgolang_getting_started.pptx
golang_getting_started.pptx
 
Lua by Ong Hean Kuan
Lua by Ong Hean KuanLua by Ong Hean Kuan
Lua by Ong Hean Kuan
 
Programming Fundamentals lecture 5
Programming Fundamentals lecture 5Programming Fundamentals lecture 5
Programming Fundamentals lecture 5
 
Design problem
Design problemDesign problem
Design problem
 
Beware: Sharp Tools
Beware: Sharp ToolsBeware: Sharp Tools
Beware: Sharp Tools
 
Dti2143 lab sheet 9
Dti2143 lab sheet 9Dti2143 lab sheet 9
Dti2143 lab sheet 9
 
Bti1022 lab sheet 9 10
Bti1022 lab sheet 9 10Bti1022 lab sheet 9 10
Bti1022 lab sheet 9 10
 
03 Geographic scripting in uDig - halfway between user and developer
03 Geographic scripting in uDig - halfway between user and developer03 Geographic scripting in uDig - halfway between user and developer
03 Geographic scripting in uDig - halfway between user and developer
 
Os lab final
Os lab finalOs lab final
Os lab final
 
Tres Gemas De Ruby
Tres Gemas De RubyTres Gemas De Ruby
Tres Gemas De Ruby
 
How I Built a Power Debugger Out of the Standard Library and Things I Found o...
How I Built a Power Debugger Out of the Standard Library and Things I Found o...How I Built a Power Debugger Out of the Standard Library and Things I Found o...
How I Built a Power Debugger Out of the Standard Library and Things I Found o...
 
Beware sharp tools
Beware sharp toolsBeware sharp tools
Beware sharp tools
 
Building Interpreters with PyPy
Building Interpreters with PyPyBuilding Interpreters with PyPy
Building Interpreters with PyPy
 
2Bytesprog2 course_2014_c8_units
2Bytesprog2 course_2014_c8_units2Bytesprog2 course_2014_c8_units
2Bytesprog2 course_2014_c8_units
 
python codes
python codespython codes
python codes
 
Container (Docker) Orchestration Tools
Container (Docker) Orchestration ToolsContainer (Docker) Orchestration Tools
Container (Docker) Orchestration Tools
 
Programming ppt files (final)
Programming ppt files (final)Programming ppt files (final)
Programming ppt files (final)
 
Hello. I was wondering if I could get some help on this C programmin.pdf
Hello. I was wondering if I could get some help on this C programmin.pdfHello. I was wondering if I could get some help on this C programmin.pdf
Hello. I was wondering if I could get some help on this C programmin.pdf
 
The basics of c programming
The basics of c programmingThe basics of c programming
The basics of c programming
 
(ThoughtWorks Away Day 2009) one or two things you may not know about typesys...
(ThoughtWorks Away Day 2009) one or two things you may not know about typesys...(ThoughtWorks Away Day 2009) one or two things you may not know about typesys...
(ThoughtWorks Away Day 2009) one or two things you may not know about typesys...
 

Más de Eleanor McHugh

Más 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
 
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
 
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
 
Encrypt all transports
Encrypt all transportsEncrypt all transports
Encrypt all transports
 
Whispered secrets
Whispered secretsWhispered secrets
Whispered secrets
 

Último

CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
anilsa9823
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 

Último (20)

Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 

Implementing Virtual Machines in Ruby & C

  • 1. implementing virtual machines in Ruby & C Eleanor McHugh @feyeleanor http://github.com/feyeleanor
  • 2. I made my own machine Yes, we're building steam I hate the same routine — Building Steam, Abney Park
  • 4. and as programmers we think a lot about thinking
  • 5. whilst thinking very little about machines
  • 7. when machines need us to be engineers & analysts
  • 8. so this is a talk about machine philosophy
  • 9. framed in a language we humans can understand
  • 10. so let's learn to love our Turing machines
  • 11. by building other Turing machines' in their image
  • 17. c: switch bytes or tokens portable #include <stdio.h> #include <stdlib.h> #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 = %dn, l, r, S->data); break; case EXIT: return; } } } int main() { interpret(program); }
  • 18. ruby: switch symbols class VM def initialize(*program) @program = program @s = [] @pc = 0 end def interpret loop do case read_program when :push @s.push(read_program) when :add @s[1] += @s[0] @s = @s.drop(1) when :print puts "#{@s[0]}" when :exit return else puts "#{op.class}" end end end private def read_program r = @program[@pc] @pc += 1 r end end vm = VM.new( :push, 13, :push, 28, :add, :print, :exit, ) vm.interpret
  • 19. c: direct call pointer to function multi-byte portable #include <stdio.h> #include <stdlib.h> #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 = %dn", 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)(); } }
  • 20. ruby: direct call method names invoke via send class VM def initialize *program @s = [] @pc = 0 @program = program.collect do |v| self.respond_to?(v) ? self.method(v) : v end end def interpret catch :program_complete do loop do read_program.call end end end def push @s.push(read_program) end def exit throw :program_complete end def add_and_print @s[1] += @s[0] @s = @s.drop(1) puts "#{@s[0]}" end private def read_program r = @program[@pc] @pc += 1 r end def dangerous_method raise "!!! I'M NOT A VALID OP_CODE !!!" end end VM.new( :push, 13, :push, 28, :dangerous_method, :add_and_print, :exit ).interpret
  • 21. ruby: direct call jit compilation sandboxing class VM BLACKLIST = [:load, :compile, :interpret] + Object.methods def initialize *program @s = [] load(program) end def load program @program = compile(program) self end def compile program program.collect do |v| case when 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.unbind v.bind(self) when methods.include?(v) raise "direct execution of #{v} is forbidden" if BLACKLIST.include?(v) self.method(v) else v end end end
  • 22. ruby: direct call jit compilation sandboxing def interpret catch :program_complete do @pc = 0 loop do read_program.call end end end end begin VM.new(:dangerous_method) rescue Exception => e puts "program compilation failed: #{e}" end vm = VM.new p = vm.compile([ :push, 13, :push, 28, :add_and_print, :exit ]) begin VM.new(*p) rescue Exception => e puts "program compilation failed: #{e}" end vm.load(p).interpret VM.new(*p).interpret
  • 23. c: indirect thread local jumps gcc/clang specific indirect loading #include <stdio.h> #include <stdlib.h> #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 = %dn", l, r, S->data); goto *opcodes[*PC++]; op_exit: return; } int main() { int program [] = { PUSH, 13, PUSH, 28, ADD, PRINT, EXIT }; interpret(program); }
  • 24. 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 = %dn", l, r, S->data); goto **program++; op_exit: return; } int main() { int program[] = { PUSH, 13, PUSH, 28, ADD, PRINT, EXIT }; interpret(program, 7); }
  • 25. 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 = %dn", l, r, S->data) ) PRIMITIVE(exit, return ), &&push, &&add, &&print, &&exit ) }
  • 26. 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++]; }
  • 27. ruby: direct thread meta-magic bind methods stack explosion probably not a good idea
  • 29. vm harness dispatch program program counter class VM BL = [:load, :compile, :interpret] + Object.methods def initialize *program load(program) end def load program @program = compile(program) self end def interpret catch :program_complete do @pc = 0 loop do read_program.call end end end def read_program r = @program[@pc] @pc += 1 r end def compile program program.collect do |v| case when v.is_a?(Method) if BL.include?(v.name) raise "forbidden method: #{v.name}" end unless methods.include?(v.name) raise "unknown method: #{v.name}" end v = v.unbind v.bind(self) when methods.include?(v) if BL.include?(v) raise "forbidden method: #{v}" end self.method(v) else v end end end end
  • 30. stack machine zero operands class Adder < VM def interpret @s = [] super end def print_state puts "#{@pc}: @s => #{@s}" end def push @s.push(read_program) read_program.call end def add @s[1] += @s[0] @s = @s.drop(1) read_program.call end def exit throw :program_complete end def jump_if_not_zero if @s[0] == 0 @pc += 1 else @pc = @program[@pc] end read_program.call end end Adder.new( :push, 13, :push, -1, :add, :print_state, :read_program, :print_state, :jump_if_not_zero, 2, :exit ).interpret
  • 31. accumulator machine single register single operand class Adder < VM def interpret @s = [] @a = 0 super end def print_state puts "#{@pc}: @a = #{@a}, @s => #{@s}" end def clear @a = 0 read_program.call end def push_value @s.push(read_program) read_program.call end def push @s.push(@accum) read_program.call end def add @a += @s.pop read_program.call end def jump_if_not_zero if @a == 0 @pc += 1 else @pc = @program[@pc] end read_program.call end def exit throw :program_complete end end 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
  • 32. register machine multi-register multi-operand class Adder < VM def interpret @r = Array.new(2, 0) super end def load_value @r[read_program] = read_program read_program.call end def add @r[read_program] += @r[read_program] read_program.call end def jump_if_not_zero if @r[read_program] == 0 @pc += 1 else @pc = @program[@pc] end read_program.call end def exit throw :program_complete end def print_state puts "#{@pc}: @r => #{@r}" end end 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
  • 33. vector machine matrix machine hypercube graph processor any datatype can be a register
  • 37. ruby: array heap core class s = [] s.push(1) s.push(3) puts "depth = #{s.length}" l = s.pop r = s.pop puts "#{l} + #{r} = #{l + r}" puts "depth = #{s.length}"
  • 38. ruby: c heap require "fiddle" class Fiddle::Pointer NIL = Pointer.new(0) SIZE = Fixnum::SIZE PACKING_PATTERN = case SIZE when 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.length raise BufferOverflow.new(self, l) if l > size self[0, l] = str + 0.chr * pad self + l end def to_bin [self].pack(PACKING_PATTERN) end end
  • 39. 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) Fiddle A libffi wrapper for Ruby. Description¶ (#module-Fiddle-label-Description) ↑ (#top) Fiddle (Fiddle.html) is an extension to translate a foreign function interface (FFI) with ruby. It wraps libffi (http://sourceware.org/libffi/), a popular C library which provides a portable interface that allows code written in one language to call code written in another language. 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 ) access DLLs call C functions
  • 40. 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) Fiddle::Pointer Fiddle::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 the pointer 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. Fiddle::Pointer[val] => cptr to_ptr(val) => cptr Fiddle::Pointer.malloc(size, freefunc = nil) => fiddle pointer instance Fiddle::Pointer.new(address) => fiddle_cptr new(address, size) => fiddle_cptr new(address, size, freefunc) => fiddle_cptr MRI stdlib C pointers malloc not portable
  • 41. ruby: c heap def Fiddle::Pointer.format(value) value.respond_to?(:to_bin) ? value.to_bin : Marshal.dump(value) end
  • 42. ruby: c heap require "fiddle" class Fiddle::Pointer NIL = Pointer.new(0) SIZE = Fixnum::SIZE PACKING_PATTERN = case SIZE when 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.length raise BufferOverflow.new(self, l) if l > size self[0, l] = str + 0.chr * pad self + l end def to_bin [self].pack(PACKING_PATTERN) end end
  • 43. ruby: c heap class Fixnum SIZE = 1.size PACKING_PATTERN = case SIZE when 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 end end
  • 44. ruby: c heap m = Fiddle::Pointer.malloc 64 begin m.write(0.chr * 59) m.write(0.chr * 60) m.write(0.chr * 61) rescue Fiddle::BufferOverflow => e p e.message end "Buffer overflow: 72 bytes at #<Fiddle::Pointer:0x007f8849052160 ptr=0x007f8849051da0 size=64 free=0x00000000000000>"
  • 45. ruby: c heap s = "Hello, Terrible Memory Bank!" i = 4193 f = 17.00091 m.write(i) puts m.read q = 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
  • 49. c: array stack fixed size malloc to create realloc to resize #include <stdlib.h> #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; }
  • 50. ruby: array stack core class stack semantics s = [] s.push(1) s.push(3) puts "depth = #{s.length}" l = s.pop r = s.pop puts "#{l} + #{r} = #{l + r}" puts "depth = #{s.length}"
  • 51. singly linked list functional shared elements immutability
  • 52. c: cactus stack nil is empty grows on push manual GC #include <stdlib.h> 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); } }
  • 53. c: cactus stack nil is empty grows on push manual GC #include <stdio.h> #include <cactus_stack.h> 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 = %dn", 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); }
  • 54. ruby: cactus stack nil is empty grows on push automatic GC class Stack include Enumerable attr_reader :head, :tail def initialize data, tail = nil @head = data @tail = tail || EmptyStack.new end def push item Stack.new item, self end def pop [head, tail] end def each t = self until t.is_a?(EmptyStack) yield t.head t = t.tail end end end class EmptyStack include Enumerable def push item Stack.new item end def pop [nil, self] end def each; end end
  • 56. c: hash map array associative arrays search #include <limits.h> 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 << 8; b += k[i]; } return b % m->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); }
  • 57. c: hash map array associative arrays search #include <stdlib.h> #include <string.h> 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; }
  • 58. 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; }
  • 59. c: hash map array associative arrays search #include <stdio.h> #include “map.h int main( int argc, char **argv ) { map_t *m = map_new(1024); map_set(m, "apple", "rosy"); printf("%sn", map_get(m, "apple")); map_set(m, "blueberry", "sweet"); printf("%sn", map_get(m, "blueberry")); map_set(m, "cherry", "pie"); printf("%sn", map_get(m, "cherry")); map_set(m, "cherry", "tart"); printf("%sn", map_get(m, "cherry")); printf("%sn", map_get(m, “tart")); } rosy sweet pie tart (null)
  • 60. 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
  • 61. This repository Pull requests Issu No description or website provided. demo + Switched to install for Makefile. lib Added note about using absolute paths to rootdir rdoc test Added assertion to quell minitest saying I'm not testing s Search seattlerb / rubyinline Code Issues 0 Pull requests 0 Projects 0 Wiki 176 commits 1 branch masterBranch: New pull request zenspider Added note about using absolute paths to rootdir rdoc … rubyinline inline c
  • 62. This repository Pull requests Issu No description or website provided. lib prepped for release test + Switched to minitest History.txt prepped for release Search seattlerb / wilson Code Issues 1 Pull requests 0 Projects 0 Wiki 27 commits 1 branch masterBranch: New pull request zenspider prepped for release … wilson x86_64 asm
  • 63. This repository Pull requests Issu NeverSayDie will let you rescue from SEGV's and is evil ext/neversaydie Changed Config:: for RbCo lib making class declarations l test updating rdoc, removing bi Search tenderlove / neversaydie Code Issues 1 Pull requests 1 Projects 0 Wiki 18 commits 1 branch masterBranch: New pull request tenderlove Merge pull request #3 from cortexmedia/master … never day die libsigsegfault