Virtual Machines
The MITScript Project
Parser (Formal Grammars and Parsing Theory, Phase 1)
Interpreter (Program Semantics, Phase 2)
Virtual Machine
Code Generation and Optimization (Efficiency, Phase 5)
Virtual Machine
Language
High-Level
VM
Machine Code
Low-Level
VM
What?
f = fun(y) {
x = y + 2;
};
f(1);
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]
}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
Livecode – show pycache
Recursive Interpreter
class Binop : public Expr {
enum BINOP { PLUS, SUB, MUL, DIV};
BINOP op;
Expr *left, *right;
};
int eval_expr(Frame* f, Expr *e) { ... }
int eval_binop(Frame *f, Binop *e) {
switch(e->op) {
case PLUS: return eval_plus(e);
case SUB : return eval_sub(e);
case MUL : return eval_mul(e);
case DIV : return eval_div(e);
}
}
int eval_plus(Frame *f, Binop *e) {
int n_1 = eval_expr(f, e->left);
int n_2 = eval_expr(f, e->right);
return n_1 + n_2;
}
Why?
Why?
In C:
//assuming y is in register r1
//puts the result in x in register r2.
mov $r2, 2
add $r2 $r1 //y + 2
In a dynamic language:
Check what type of value y is.
Get the integer value from the value object of y
Allocate a value object for 2.
Check the type of the value object for 2
Get the integer value from the value object of 2
Allocate a new integer value to compute y + 2
Make x point to that integer value.
x = y + 2
Translation
fun(y) {
x = y + 2;
};
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
function __function_1 (y) : {
%x = alloca int64_t
%0 = %y
%1 = 2
%2 = add %0 %1
store %x %2
%3 = 0
return %3
}
__function_1 :
sub 8 %rsp
mov %rsp %rbp
mov (%rbp, 2, 8) %rax
mov 2 %rcx
add %rcx %rax
mov %rax (%rbp)
mov 0 %rax
ret
High-Level
VM
Low-Level
VM
Machine Code
Language
Virtual Machine: Why?
MITScript Virtual Machine
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
f = fun(y) {
x = y + 2;
};
f(1);
Organization (Code, Stack, and Heaps)
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
f = fun(y) {
x = y + 2;
};
f(1);
Organization (Code, Stack, and Heaps)
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
Python VM (Illustrative)
Op Stack |
|
|
|
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
|
Heap
Globals |
f |
Locals |
Stack
Frame
Python VM (Illustrative)
Op Stack |
|
|
|
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
0 |
Globals |
f |
Locals |
0
Stack
Frame
Heap
Python VM (Illustrative)
Op Stack |
|
|
|
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
1 |
Globals |
f |
Locals |
Stack
Frame
Heap
0
Python VM (Illustrative)
Op Stack |
|
|
|
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
2 |
Globals |
f |
Locals |
Stack
Frame
Heap
0
Python VM (Illustrative)
Op Stack |
|
|
|
Locals |
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
3 |
Closure { f : }
Globals |
f |
Stack
Frame
Heap
0
Python VM (Illustrative)
Globals |
f |
Op Stack |
|
|
|
Locals |
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
4 |
Stack
Frame
Heap
Closure { f : }
0
Python VM (Illustrative)
Globals |
f |
Op Stack |
|
|
|
Locals |
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
5 |
Stack
Frame
Heap
Closure { f : }
0
Python VM (Illustrative)
Globals |
f |
Op Stack |
|
|
|
Locals |
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
6 |
Stack
Frame
Heap
0
Closure { f : }
1
Python VM (Illustrative)
Globals |
f |
Locals |
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
7 |
Op Stack |
|
|
Locals |
y : |
x : Uninit |
IP |
0 |
Op Stack |
|
|
|
Stack
Frame
Heap
0
Closure { f : }
Stack
Frame
1
Python VM (Illustrative)
Globals |
f |
Locals |
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
7 |
Op Stack |
|
|
Locals |
y : |
x : Uninit |
IP |
1 |
Op Stack |
|
|
|
Stack
Frame
Heap
0
Closure { f : }
Stack
Frame
1
Python VM (Illustrative)
Globals |
f |
Locals |
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
7 |
Op Stack |
|
|
Locals |
y : |
x : Uninit |
IP |
2 |
Stack
Frame
Op Stack |
|
|
|
Stack
Frame
Heap
0
Closure { f : }
1
2
Python VM (Illustrative)
Globals |
f |
Locals |
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
7 |
Op Stack |
|
|
Locals |
y : |
x : Uninit |
IP |
3 |
Op Stack |
|
|
|
Stack
Frame
Stack
Frame
Heap
0
Closure { f : }
1
2
3
Python VM (Illustrative)
Globals |
f |
Locals |
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
7 |
Op Stack |
|
|
Locals |
y : |
x : |
IP |
4 |
Op Stack |
|
|
|
1
2
3
Stack
Frame
Stack
Frame
Heap
0
Closure { f : }
Python VM (Illustrative)
Globals |
f |
Locals |
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
7 |
Op Stack |
|
|
Locals |
y : |
x : |
IP |
5 |
Op Stack |
|
|
|
None
Stack
Frame
Stack
Frame
Heap
0
Closure { f : }
1
2
3
Python VM (Illustrative)
Globals |
f |
Op Stack |
|
|
|
Locals |
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
7 |
Stack
Frame
Heap
0
Closure { f : }
1
2
3
None
Python VM (Illustrative)
Globals |
f |
Op Stack |
|
|
|
Locals |
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
8 |
Stack
Frame
Heap
0
Closure { f : }
1
2
3
Python VM (Illustrative)
Globals |
f |
Op Stack |
|
|
|
Locals |
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
9 |
Stack
Frame
Heap
0
Closure { f : }
None
1
2
3
General Characteristics
Virtual Machine
// Description: push a constant onto the operand stack
// Operand 0: index of constant in enclosing function's list of constants
// Mnemonic: load_const i
// Stack: S => S :: f.constants()[i]
LoadConst,
// Description: push a function onto the operand stack
// Operand 0: index of function in enclosing function's list of functions
// Mnemonic: load_func i
// Stack: S => S :: f.functions()[i]
LoadFunc,
// Description: load value of local variable and push onto operand stack
// Operand 0: index of local variable to read
// Mnemonic: load_local i
// S => S :: value_of(f.local_vars[i])
LoadLocal,
Virtual Machine
// Description: store top of operand stack into local variable
// Operand 0: index of local variable to store into
// Operand 1: value to store
// Mnemonic: store_local i
// Stack: S :: operand 1 ==> S
StoreLocal,
// Description: implements binary operation (as given in the semantics of Assignment #2)
// Operand 0: N/A
// Operand 1: right value
// Operand 2: left value
// Result: value of the operation as specified by the semantics of Assignment #2 // Mnemonic: sub/mul/div
// Stack: S:: operand 2 :: operand 1 => S :: op(operand 2, operand 1)
Add,
Virtual Machine: Why?
Language Implementations
Interpreted
Interpreted
Swift
LLVM
EVM
Java
Python VM
Ethereum
Java VM
x86
ARM
SPARC
PowerPC
Language
High-Level
VM
Machine Code
C/C++ (Clang)
Low-Level
VM
JavaScript
C/C++ (gcc)
GIMPLE (HL)
GIMPLE (LL, SSA)
MIPS
LLVM (MC)
Direct
Translation
Python
SIL
LLVM (MC)
LLVM
“Java is an attractive solution for set top boxes. Java byte code can run on any microprocessor. Intel x86 processors dominate desktop computers, but embedded systems like set top boxes may use any number of different processors. Choice of processor in embedded systems is dependent on factors such as cost, performance and footprint. For these reasons, platform neutrality is crucial to success.”
Language Implementations
Interpreted
Interpreted
Swift
LLVM
EVM
Java
Python VM
Ethereum
Java VM
x86
ARM
SPARC
PowerPC
Language
High-Level
VM
Machine Code
C/C++ (Clang)
Low-Level
VM
JavaScript
C/C++ (gcc)
GIMPLE (HL)
GIMPLE (LL, SSA)
MIPS
LLVM (MC)
Direct
Translation
Python
SIL
LLVM (MC)
LLVM