SlideShare a Scribd company logo
VIRTUAL MACHINES
HOW DO THEY WORK? DO THEY WORK? LET’S FIND OUT!
INTRODUCTION
Bartosz Sypytkowski
▪ @Horusiath
▪ b.sypytkowski@gmail.com
▪ bartoszsypytkowski.com
 What virtual machines are all about.
 Stack vs Register based VMs
 Bytecode and interpreters
 Demo
AGENDA
MOTIVATION
VIRTUAL
MACHINE
SYSTEM VIRTUAL
MACHINE
PROCESS VIRTUAL
MACHINE
STACK
VS.
REGISTER
STACK
const.i32 3
const.i32 2
add.i32
Stack
STACK
const.i32 3
const.i32 2
add.i32
Stack
3
STACK
const.i32 3
const.i32 2
add.i32
Stack
2
3
STACK
const.i32 3
const.i32 2
add.i32
Stack
3
2
5
ACTIVATION
FRAMES arity
return address
function arg0
Activation
frame fib(5)
arity
return address
function arg0
Activation
frame fib(4)
Frame
pointer
BYTECODE
20 00 42 00 51 04 7e
42 01 05 20 00 20 00
42 01 7d 10 00 7e 0b
TEXT FORMAT BINARY FORMAT
get_local 0
i64.const 0
i64.eq
if i64
i64.const 1
else
get_local 0
get_local 0
i64.const 1
i64.sub
call 0
i64.mul
end
WHY NOT AST?
Intermediate representations
1. .NET CIL
2. JVM bytecode
3. WASM
4. LLVM IR
5. MemSQL bytecode
BYTECODE
INTERPRETER
VS.
COMPILER
ASSEMBLY NOT LOW-LEVEL LANGUAGE ANYMORE
BUT SERIOUSLY…
WHO USES BYTECODE INTERPRETER ON PROD?
COMPAR
ING
VECTOR
CLOCKS
CASE
STUDIES
• pre 1.9 – AST interpreter
• v1.9 (25 Dec 207) – YARV: bytecode interpreter
• v2.6 (25 Dec 2018) – JIT (experimental)
RUBY MRI
CPYTHON
• ATM still bytecode interpreted
• Bytecode generated and cached in .pyc files
MULTI TIER
CODE
EXECUTION
TIME
Query
parsing
interpreter
compiler
execution
execution
Switch
point
compilation
DEMO
A MINIMAL
VIRTUAL
MACHINE
1. Program to execute
2. Instruction counter / program counter
3. Virtual stack (LIFO)
4. Stack pointer
5. Frame pointer
REMARKS 1. Not optimal
2. No debugger
3. No error handling
4. No local/global variables
5. Only one primitive supporter (Int32)
SSVM
Bytecode
1. Constant
2. Add
3. Sub
4. Mul
5. JumpIfTrue
6. JumpIfFalse
7. Equal
8. LessThan
9. GreaterThan
10. Call
11. LoadArgument
12. Return
13. Halt
14. Print
SAMPLE
PROGRAM
// int fib(n) {
// if(n == 0) return 0;
LoadArgument 0 // 0 - load last function argument N
Constant 0 // 2 - put 0
Equals // 4 - check equality: N == 0
JumpIfFalse 10 // 5 - if they are NOT equal, goto 10
Constant 0 // 7 - otherwise put 0
Return // 9 - and return it
// if(n < 3) return 1;
LoadArgument 0 // 10 - load last function argument N
Constant 3 // 12 - put 3
LessThan // 14 - check if 3 is less than N
JumpIfFalse 20 // 15 - if 3 is NOT less than N, goto 20
Constant 1 // 17 - otherwise put 1
Return // 19 - and return it
// else return fib(n-1) + fib(n-2);
LoadArgument 0 // 20 - load last function argument N
Constant 1 // 22 - put 1
Sub // 24 - calculate: N-1, result is on the stack
Call fib 1 // 25 - call fib function with 1 arg. from the stack
LoadArgument 0 // 28 - load N again
Constant 2 // 30 - put 2
Sub // 32 - calculate: N-2, result is on the stack
Call fib 1 // 33 - call fib function with 1 arg. from the stack
Add // 36 - since 2 fibs pushed their ret values on the stack, just add them
Return // 37 - return from procedure
// entrypoint - main function
Constant 6 // 38 - put 6
Call fib 1 // 40 - call function: fib(arg) where arg = 6;
Print // 43 - print result
Halt // 44 - stop program
Virtual Machine
typedef struct {
int* code; // program opcodes
int* stack; // virtual stack
int pc; // program counter
int sp; // stack pointer
int fp; // frame pointer
} VM;
// push value on top of the stack
#define PUSH(vm, v) vm->stack[++vm->sp] = v
// pop value from top of the stack
#define POP(vm) vm->stack[vm->sp--]
// get next bytecode
#define NEXT(vm) vm->code[vm->pc++]
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
Interpreter Loop
void (*op_handles[])(VM*) = {
// opcode function pointers
};
void vm_run(VM* vm) {
do {
int opcode = NEXT(vm);
if (opcode == Halt) {
return;
}
op_handles[opcode](vm);
} while(1);
}
Constant X
void op_constant(VM* vm) {
int x = NEXT(vm);
PUSH(vm, x);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
Constant X
void op_constant(VM* vm) {
int x = NEXT(vm);
PUSH(vm, x);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
x
Constant X
void op_constant(VM* vm) {
int x = NEXT(vm);
PUSH(vm, x);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
x
Print
void op_print(VM* vm) {
int x = POP(vm);
printf(“%dn”, x);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
x
Print
void op_print(VM* vm) {
int x = POP(vm);
printf(“%dn”, x);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
x
Print
void op_print(VM* vm) {
int x = POP(vm);
printf(“%dn”, x);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
x
STDOUT
Add / Sub / Mul / Div
void op_add(VM* vm) {
int b = POP(vm);
int a = POP(vm);
//TODO: check overflow
PUSH(vm, a + b);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
a
b
Add / Sub / Mul / Div
void op_add(VM* vm) {
int b = POP(vm);
int a = POP(vm);
//TODO: check overflow
PUSH(vm, a + b);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
a
b
Add / Sub / Mul / Div
void op_add(VM* vm) {
int b = POP(vm);
int a = POP(vm);
//TODO: check overflow
PUSH(vm, a + b);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
a
b
Add / Sub / Mul / Div
void op_add(VM* vm) {
int b = POP(vm);
int a = POP(vm);
//TODO: check overflow
PUSH(vm, a + b);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
a + b
Equal / Less / etc.
void op_eq(VM* vm) {
int b = POP(vm);
int a = POP(vm);
PUSH(vm, a == b ? 1 : 0);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
a
b
Equal / Less / etc.
void op_eq(VM* vm) {
int b = POP(vm);
int a = POP(vm);
PUSH(vm, a == b ? 1 : 0);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
a
b
Equal / Less / etc.
void op_eq(VM* vm) {
int b = POP(vm);
int a = POP(vm);
PUSH(vm, a == b ? 1 : 0);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
a
b
Equal / Less / etc.
void op_eq(VM* vm) {
int b = POP(vm);
int a = POP(vm);
PUSH(vm, a == b ? 1 : 0);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
1
Conditional
Branches
void op_jmp_eq(VM* vm) {
int address = NEXT(vm);
if (POP(vm)) {
vm->pc = address;
}
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
1
Conditional
Branches
void op_jmp_eq(VM* vm) {
int address = NEXT(vm);
if (POP(vm)) {
vm->pc = address;
}
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
1
addr
Conditional
Branches
void op_jmp_eq(VM* vm) {
int address = NEXT(vm);
if (POP(vm)) {
vm->pc = address;
}
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
1
addr
Conditional
Branches
void op_jmp_eq(VM* vm) {
int address = NEXT(vm);
if (POP(vm)) {
vm->pc = address;
}
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
addr
Call
void op_call(VM* vm) {
int addr = NEXT(vm);
int argc = NEXT(vm);
PUSH(vm, argc);
PUSH(vm, vm->fp);
PUSH(vm, vm->pc);
vm->fp = vm->sp;
vm->pc = addr;
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
Call
void op_call(VM* vm) {
int addr = NEXT(vm);
int argc = NEXT(vm);
PUSH(vm, argc);
PUSH(vm, vm->fp);
PUSH(vm, vm->pc);
vm->fp = vm->sp;
vm->pc = addr;
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
addr
Call
void op_call(VM* vm) {
int addr = NEXT(vm);
int argc = NEXT(vm);
PUSH(vm, argc);
PUSH(vm, vm->fp);
PUSH(vm, vm->pc);
vm->fp = vm->sp;
vm->pc = addr;
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
addr
argc
Call
void op_call(VM* vm) {
int addr = NEXT(vm);
int argc = NEXT(vm);
PUSH(vm, argc);
PUSH(vm, vm->fp);
PUSH(vm, vm->pc);
vm->fp = vm->sp;
vm->pc = addr;
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
addr
argc
Call
void op_call(VM* vm) {
int addr = NEXT(vm);
int argc = NEXT(vm);
PUSH(vm, argc);
PUSH(vm, vm->fp);
PUSH(vm, vm->pc);
vm->fp = vm->sp;
vm->pc = addr;
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
addr
argc
fp
Call
void op_call(VM* vm) {
int addr = NEXT(vm);
int argc = NEXT(vm);
PUSH(vm, argc);
PUSH(vm, vm->fp);
PUSH(vm, vm->pc);
vm->fp = vm->sp;
vm->pc = addr;
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
addr
argc
fp
pc
Call
void op_call(VM* vm) {
int addr = NEXT(vm);
int argc = NEXT(vm);
PUSH(vm, argc);
PUSH(vm, vm->fp);
PUSH(vm, vm->pc);
vm->fp = vm->sp;
vm->pc = addr;
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
addr
argc
fp
pc
activation
frame
Call
void op_call(VM* vm) {
int addr = NEXT(vm);
int argc = NEXT(vm);
PUSH(vm, argc);
PUSH(vm, vm->fp);
PUSH(vm, vm->pc);
vm->fp = vm->sp;
vm->pc = addr;
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
addr
argc
fp
pc
LoadArgument
void op_lda(VM* vm) {
int argx = NEXT(vm);
int v = vm->stack[vm->fp-argx-3];
PUSH(vm, v);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
arg0
argc
fp
pc
LoadArgument
void op_lda(VM* vm) {
int argx = NEXT(vm);
int v = vm->stack[vm->fp-argx-3];
PUSH(vm, v);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
arg0
argc
fp
pc
argx
LoadArgument
void op_lda(VM* vm) {
int argx = NEXT(vm);
int v = vm->stack[vm->fp-argx-3];
PUSH(vm, v);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
arg0
argc
fp
pc
v
frame pointer – 3 - argx
LoadArgument
void op_lda(VM* vm) {
int argx = NEXT(vm);
int v = vm->stack[vm->fp-argx-3];
PUSH(vm, v);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
arg0
argc
fp
pc
v
Return
void op_ret(VM* vm) {
int result = POP(vm);
vm->pc = POP(vm);
vm->fp = POP(vm);
int argc = POP(vm);
vm->sp -= argc;
PUSH(vm, result);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
arg0
argc
fp
pc
result
Return
void op_ret(VM* vm) {
int result = POP(vm);
vm->pc = POP(vm);
vm->fp = POP(vm);
int argc = POP(vm);
vm->sp -= argc;
PUSH(vm, result);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
arg0
argc
fp
pc
result
Return
void op_ret(VM* vm) {
int result = POP(vm);
vm->pc = POP(vm);
vm->fp = POP(vm);
int argc = POP(vm);
vm->sp -= argc;
PUSH(vm, result);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
arg0
argc
fp
pc
result
Return
void op_ret(VM* vm) {
int result = POP(vm);
vm->pc = POP(vm);
vm->fp = POP(vm);
int argc = POP(vm);
vm->sp -= argc;
PUSH(vm, result);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
arg0
argc
fp
result
Return
void op_ret(VM* vm) {
int result = POP(vm);
vm->pc = POP(vm);
vm->fp = POP(vm);
int argc = POP(vm);
vm->sp -= argc;
PUSH(vm, result);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
arg0
argc
result
Return
void op_ret(VM* vm) {
int result = POP(vm);
vm->pc = POP(vm);
vm->fp = POP(vm);
int argc = POP(vm);
vm->sp -= argc;
PUSH(vm, result);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
arg0
result
Return
void op_ret(VM* vm) {
int result = POP(vm);
vm->pc = POP(vm);
vm->fp = POP(vm);
int argc = POP(vm);
vm->sp -= argc;
PUSH(vm, result);
}
stack
20 00 42
00 51 04
7e 42 01
05 20 00
20 00 42
01 7d 10
00 7e 0b
code
stack pointer
program pointer
frame pointer
result
SUMMARY
 Crafting interpreters: https://craftinginterpreters.com/contents.html#a-bytecode-virtual-machine
 Register-based VM: https://github.com/skx/simple.vm
 Konrad Kokosa: “Pro .NET Memory Management”
 Database query compilation: https://www.youtube.com/watch?v=baOAbOdcnxs
 Adding new CIL instruction to .NET: https://mattwarren.org/2017/05/19/Adding-a-new-Bytecode-
Instruction-to-the-CLR/
 and many many more…
REFERENCES
THANK YOU

More Related Content

PDF
TVM VTA (TSIM)
DOC
All VLSI programs
PDF
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
PDF
Data Structure - 2nd Study
PPT
3D-DRESD Lorenzo Pavesi
PPTX
Understand more about C
DOC
Macroprocessor
PDF
A real-world example of Functional Programming with fp-ts - no experience req...
TVM VTA (TSIM)
All VLSI programs
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
Data Structure - 2nd Study
3D-DRESD Lorenzo Pavesi
Understand more about C
Macroprocessor
A real-world example of Functional Programming with fp-ts - no experience req...

What's hot (19)

PDF
C++ Programming - 11th Study
PDF
Nefrock勉強会 in大岡山「FPGAでゲーム機を作ろう!の会」Day4
PPT
Lecture05
DOC
Infix to-postfix examples
PPTX
Cse presentation ratul
DOC
VLSI experiments II
PDF
C++ Programming - 4th Study
PPT
Buffer OverFlow
DOCX
PDF
C++ Programming - 2nd Study
DOCX
verilog code
PPT
Unit2 C
PDF
Diving into HHVM Extensions (Brno PHP Conference 2015)
DOC
Network lab manual
PDF
C++ Programming - 1st Study
PPT
Swift: Apple's New Programming Language for iOS and OS X
DOCX
Network lap pgms 7th semester
PPTX
Introduction to Javascript
C++ Programming - 11th Study
Nefrock勉強会 in大岡山「FPGAでゲーム機を作ろう!の会」Day4
Lecture05
Infix to-postfix examples
Cse presentation ratul
VLSI experiments II
C++ Programming - 4th Study
Buffer OverFlow
C++ Programming - 2nd Study
verilog code
Unit2 C
Diving into HHVM Extensions (Brno PHP Conference 2015)
Network lab manual
C++ Programming - 1st Study
Swift: Apple's New Programming Language for iOS and OS X
Network lap pgms 7th semester
Introduction to Javascript
Ad

Similar to Virtual machines - how they work (20)

PDF
Bytes in the Machine: Inside the CPython interpreter
PDF
Checking Oracle VM VirtualBox. Part 1
DOCX
Wap to implement bitwise operators
PPT
Paradigmas de Linguagens de Programacao - Aula #4
PDF
COMP360 Assembler Write an assembler that reads the source code of an.pdf
PPTX
EcmaScript unchained
PPTX
How to add an optimization for C# to RyuJIT
PDF
Implementing Software Machines in Go and C
PDF
node-rpi-ws281x
PDF
Spectre(v1%2 fv2%2fv4) v.s. meltdown(v3)
PDF
Ethereum virtual machine for Developers Part 1
PPT
OpenMP
PDF
ITGM #9 - Коварный CodeType, или от segfault'а к работающему коду
PPT
Application of Stacks
DOCX
2.1 ### uVision Project, (C) Keil Software .docx
PDF
Vectorization on x86: all you need to know
PDF
Reverse Engineering Dojo: Enhancing Assembly Reading Skills
PDF
Roberto Gallea: Workshop Arduino, giorno #2 Arduino + Processing
PDF
Arduino for Beginners
PDF
When RV Meets CEP (RV 2016 Tutorial)
Bytes in the Machine: Inside the CPython interpreter
Checking Oracle VM VirtualBox. Part 1
Wap to implement bitwise operators
Paradigmas de Linguagens de Programacao - Aula #4
COMP360 Assembler Write an assembler that reads the source code of an.pdf
EcmaScript unchained
How to add an optimization for C# to RyuJIT
Implementing Software Machines in Go and C
node-rpi-ws281x
Spectre(v1%2 fv2%2fv4) v.s. meltdown(v3)
Ethereum virtual machine for Developers Part 1
OpenMP
ITGM #9 - Коварный CodeType, или от segfault'а к работающему коду
Application of Stacks
2.1 ### uVision Project, (C) Keil Software .docx
Vectorization on x86: all you need to know
Reverse Engineering Dojo: Enhancing Assembly Reading Skills
Roberto Gallea: Workshop Arduino, giorno #2 Arduino + Processing
Arduino for Beginners
When RV Meets CEP (RV 2016 Tutorial)
Ad

More from Bartosz Sypytkowski (17)

PPTX
Full text search, vector search or both?
PPTX
Service-less communication: is it possible?
PPTX
Serviceless or how to build software without servers
PPTX
Postgres indexes: how to make them work for your application
PPTX
How do databases perform live backups and point-in-time recovery
PPTX
Scaling connections in peer-to-peer applications
PPTX
Rich collaborative data structures for everyone
PPTX
Postgres indexes
PPTX
Behind modern concurrency primitives
PPTX
Collaborative eventsourcing
PPTX
Behind modern concurrency primitives
PPTX
Living in eventually consistent reality
PPTX
Short story of time
PPTX
Akka.NET streams and reactive streams
PPTX
Collaborative text editing
PPTX
The last mile from db to disk
PPTX
GraphQL - an elegant weapon... for more civilized age
Full text search, vector search or both?
Service-less communication: is it possible?
Serviceless or how to build software without servers
Postgres indexes: how to make them work for your application
How do databases perform live backups and point-in-time recovery
Scaling connections in peer-to-peer applications
Rich collaborative data structures for everyone
Postgres indexes
Behind modern concurrency primitives
Collaborative eventsourcing
Behind modern concurrency primitives
Living in eventually consistent reality
Short story of time
Akka.NET streams and reactive streams
Collaborative text editing
The last mile from db to disk
GraphQL - an elegant weapon... for more civilized age

Recently uploaded (20)

PPTX
Custom Software Development Services.pptx.pptx
PPTX
Why Generative AI is the Future of Content, Code & Creativity?
PPTX
assetexplorer- product-overview - presentation
PDF
Time Tracking Features That Teams and Organizations Actually Need
PDF
Complete Guide to Website Development in Malaysia for SMEs
PDF
AI-Powered Threat Modeling: The Future of Cybersecurity by Arun Kumar Elengov...
PDF
Types of Token_ From Utility to Security.pdf
PPTX
WiFi Honeypot Detecscfddssdffsedfseztor.pptx
PDF
Top 10 Software Development Trends to Watch in 2025 🚀.pdf
PPTX
AMADEUS TRAVEL AGENT SOFTWARE | AMADEUS TICKETING SYSTEM
PPTX
Weekly report ppt - harsh dattuprasad patel.pptx
PPTX
Monitoring Stack: Grafana, Loki & Promtail
PDF
wealthsignaloriginal-com-DS-text-... (1).pdf
PDF
How AI/LLM recommend to you ? GDG meetup 16 Aug by Fariman Guliev
PDF
iTop VPN Crack Latest Version Full Key 2025
PDF
How to Make Money in the Metaverse_ Top Strategies for Beginners.pdf
PPTX
Computer Software and OS of computer science of grade 11.pptx
DOCX
How to Use SharePoint as an ISO-Compliant Document Management System
PDF
Product Update: Alluxio AI 3.7 Now with Sub-Millisecond Latency
PPTX
GSA Content Generator Crack (2025 Latest)
Custom Software Development Services.pptx.pptx
Why Generative AI is the Future of Content, Code & Creativity?
assetexplorer- product-overview - presentation
Time Tracking Features That Teams and Organizations Actually Need
Complete Guide to Website Development in Malaysia for SMEs
AI-Powered Threat Modeling: The Future of Cybersecurity by Arun Kumar Elengov...
Types of Token_ From Utility to Security.pdf
WiFi Honeypot Detecscfddssdffsedfseztor.pptx
Top 10 Software Development Trends to Watch in 2025 🚀.pdf
AMADEUS TRAVEL AGENT SOFTWARE | AMADEUS TICKETING SYSTEM
Weekly report ppt - harsh dattuprasad patel.pptx
Monitoring Stack: Grafana, Loki & Promtail
wealthsignaloriginal-com-DS-text-... (1).pdf
How AI/LLM recommend to you ? GDG meetup 16 Aug by Fariman Guliev
iTop VPN Crack Latest Version Full Key 2025
How to Make Money in the Metaverse_ Top Strategies for Beginners.pdf
Computer Software and OS of computer science of grade 11.pptx
How to Use SharePoint as an ISO-Compliant Document Management System
Product Update: Alluxio AI 3.7 Now with Sub-Millisecond Latency
GSA Content Generator Crack (2025 Latest)

Virtual machines - how they work

  • 1. VIRTUAL MACHINES HOW DO THEY WORK? DO THEY WORK? LET’S FIND OUT!
  • 2. INTRODUCTION Bartosz Sypytkowski ▪ @Horusiath ▪ b.sypytkowski@gmail.com ▪ bartoszsypytkowski.com
  • 3.  What virtual machines are all about.  Stack vs Register based VMs  Bytecode and interpreters  Demo AGENDA
  • 12. ACTIVATION FRAMES arity return address function arg0 Activation frame fib(5) arity return address function arg0 Activation frame fib(4) Frame pointer
  • 14. 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b TEXT FORMAT BINARY FORMAT get_local 0 i64.const 0 i64.eq if i64 i64.const 1 else get_local 0 get_local 0 i64.const 1 i64.sub call 0 i64.mul end
  • 16. Intermediate representations 1. .NET CIL 2. JVM bytecode 3. WASM 4. LLVM IR 5. MemSQL bytecode BYTECODE
  • 18. ASSEMBLY NOT LOW-LEVEL LANGUAGE ANYMORE
  • 19. BUT SERIOUSLY… WHO USES BYTECODE INTERPRETER ON PROD?
  • 20. COMPAR ING VECTOR CLOCKS CASE STUDIES • pre 1.9 – AST interpreter • v1.9 (25 Dec 207) – YARV: bytecode interpreter • v2.6 (25 Dec 2018) – JIT (experimental) RUBY MRI CPYTHON • ATM still bytecode interpreted • Bytecode generated and cached in .pyc files
  • 22. DEMO
  • 23. A MINIMAL VIRTUAL MACHINE 1. Program to execute 2. Instruction counter / program counter 3. Virtual stack (LIFO) 4. Stack pointer 5. Frame pointer
  • 24. REMARKS 1. Not optimal 2. No debugger 3. No error handling 4. No local/global variables 5. Only one primitive supporter (Int32)
  • 25. SSVM Bytecode 1. Constant 2. Add 3. Sub 4. Mul 5. JumpIfTrue 6. JumpIfFalse 7. Equal 8. LessThan 9. GreaterThan 10. Call 11. LoadArgument 12. Return 13. Halt 14. Print
  • 26. SAMPLE PROGRAM // int fib(n) { // if(n == 0) return 0; LoadArgument 0 // 0 - load last function argument N Constant 0 // 2 - put 0 Equals // 4 - check equality: N == 0 JumpIfFalse 10 // 5 - if they are NOT equal, goto 10 Constant 0 // 7 - otherwise put 0 Return // 9 - and return it // if(n < 3) return 1; LoadArgument 0 // 10 - load last function argument N Constant 3 // 12 - put 3 LessThan // 14 - check if 3 is less than N JumpIfFalse 20 // 15 - if 3 is NOT less than N, goto 20 Constant 1 // 17 - otherwise put 1 Return // 19 - and return it // else return fib(n-1) + fib(n-2); LoadArgument 0 // 20 - load last function argument N Constant 1 // 22 - put 1 Sub // 24 - calculate: N-1, result is on the stack Call fib 1 // 25 - call fib function with 1 arg. from the stack LoadArgument 0 // 28 - load N again Constant 2 // 30 - put 2 Sub // 32 - calculate: N-2, result is on the stack Call fib 1 // 33 - call fib function with 1 arg. from the stack Add // 36 - since 2 fibs pushed their ret values on the stack, just add them Return // 37 - return from procedure // entrypoint - main function Constant 6 // 38 - put 6 Call fib 1 // 40 - call function: fib(arg) where arg = 6; Print // 43 - print result Halt // 44 - stop program
  • 27. Virtual Machine typedef struct { int* code; // program opcodes int* stack; // virtual stack int pc; // program counter int sp; // stack pointer int fp; // frame pointer } VM; // push value on top of the stack #define PUSH(vm, v) vm->stack[++vm->sp] = v // pop value from top of the stack #define POP(vm) vm->stack[vm->sp--] // get next bytecode #define NEXT(vm) vm->code[vm->pc++] stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer
  • 28. Interpreter Loop void (*op_handles[])(VM*) = { // opcode function pointers }; void vm_run(VM* vm) { do { int opcode = NEXT(vm); if (opcode == Halt) { return; } op_handles[opcode](vm); } while(1); }
  • 29. Constant X void op_constant(VM* vm) { int x = NEXT(vm); PUSH(vm, x); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer
  • 30. Constant X void op_constant(VM* vm) { int x = NEXT(vm); PUSH(vm, x); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer x
  • 31. Constant X void op_constant(VM* vm) { int x = NEXT(vm); PUSH(vm, x); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer x
  • 32. Print void op_print(VM* vm) { int x = POP(vm); printf(“%dn”, x); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer x
  • 33. Print void op_print(VM* vm) { int x = POP(vm); printf(“%dn”, x); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer x
  • 34. Print void op_print(VM* vm) { int x = POP(vm); printf(“%dn”, x); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer x STDOUT
  • 35. Add / Sub / Mul / Div void op_add(VM* vm) { int b = POP(vm); int a = POP(vm); //TODO: check overflow PUSH(vm, a + b); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer a b
  • 36. Add / Sub / Mul / Div void op_add(VM* vm) { int b = POP(vm); int a = POP(vm); //TODO: check overflow PUSH(vm, a + b); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer a b
  • 37. Add / Sub / Mul / Div void op_add(VM* vm) { int b = POP(vm); int a = POP(vm); //TODO: check overflow PUSH(vm, a + b); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer a b
  • 38. Add / Sub / Mul / Div void op_add(VM* vm) { int b = POP(vm); int a = POP(vm); //TODO: check overflow PUSH(vm, a + b); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer a + b
  • 39. Equal / Less / etc. void op_eq(VM* vm) { int b = POP(vm); int a = POP(vm); PUSH(vm, a == b ? 1 : 0); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer a b
  • 40. Equal / Less / etc. void op_eq(VM* vm) { int b = POP(vm); int a = POP(vm); PUSH(vm, a == b ? 1 : 0); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer a b
  • 41. Equal / Less / etc. void op_eq(VM* vm) { int b = POP(vm); int a = POP(vm); PUSH(vm, a == b ? 1 : 0); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer a b
  • 42. Equal / Less / etc. void op_eq(VM* vm) { int b = POP(vm); int a = POP(vm); PUSH(vm, a == b ? 1 : 0); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer 1
  • 43. Conditional Branches void op_jmp_eq(VM* vm) { int address = NEXT(vm); if (POP(vm)) { vm->pc = address; } } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer 1
  • 44. Conditional Branches void op_jmp_eq(VM* vm) { int address = NEXT(vm); if (POP(vm)) { vm->pc = address; } } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer 1 addr
  • 45. Conditional Branches void op_jmp_eq(VM* vm) { int address = NEXT(vm); if (POP(vm)) { vm->pc = address; } } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer 1 addr
  • 46. Conditional Branches void op_jmp_eq(VM* vm) { int address = NEXT(vm); if (POP(vm)) { vm->pc = address; } } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer addr
  • 47. Call void op_call(VM* vm) { int addr = NEXT(vm); int argc = NEXT(vm); PUSH(vm, argc); PUSH(vm, vm->fp); PUSH(vm, vm->pc); vm->fp = vm->sp; vm->pc = addr; } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer
  • 48. Call void op_call(VM* vm) { int addr = NEXT(vm); int argc = NEXT(vm); PUSH(vm, argc); PUSH(vm, vm->fp); PUSH(vm, vm->pc); vm->fp = vm->sp; vm->pc = addr; } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer addr
  • 49. Call void op_call(VM* vm) { int addr = NEXT(vm); int argc = NEXT(vm); PUSH(vm, argc); PUSH(vm, vm->fp); PUSH(vm, vm->pc); vm->fp = vm->sp; vm->pc = addr; } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer addr argc
  • 50. Call void op_call(VM* vm) { int addr = NEXT(vm); int argc = NEXT(vm); PUSH(vm, argc); PUSH(vm, vm->fp); PUSH(vm, vm->pc); vm->fp = vm->sp; vm->pc = addr; } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer addr argc
  • 51. Call void op_call(VM* vm) { int addr = NEXT(vm); int argc = NEXT(vm); PUSH(vm, argc); PUSH(vm, vm->fp); PUSH(vm, vm->pc); vm->fp = vm->sp; vm->pc = addr; } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer addr argc fp
  • 52. Call void op_call(VM* vm) { int addr = NEXT(vm); int argc = NEXT(vm); PUSH(vm, argc); PUSH(vm, vm->fp); PUSH(vm, vm->pc); vm->fp = vm->sp; vm->pc = addr; } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer addr argc fp pc
  • 53. Call void op_call(VM* vm) { int addr = NEXT(vm); int argc = NEXT(vm); PUSH(vm, argc); PUSH(vm, vm->fp); PUSH(vm, vm->pc); vm->fp = vm->sp; vm->pc = addr; } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer addr argc fp pc activation frame
  • 54. Call void op_call(VM* vm) { int addr = NEXT(vm); int argc = NEXT(vm); PUSH(vm, argc); PUSH(vm, vm->fp); PUSH(vm, vm->pc); vm->fp = vm->sp; vm->pc = addr; } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer addr argc fp pc
  • 55. LoadArgument void op_lda(VM* vm) { int argx = NEXT(vm); int v = vm->stack[vm->fp-argx-3]; PUSH(vm, v); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer arg0 argc fp pc
  • 56. LoadArgument void op_lda(VM* vm) { int argx = NEXT(vm); int v = vm->stack[vm->fp-argx-3]; PUSH(vm, v); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer arg0 argc fp pc argx
  • 57. LoadArgument void op_lda(VM* vm) { int argx = NEXT(vm); int v = vm->stack[vm->fp-argx-3]; PUSH(vm, v); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer arg0 argc fp pc v frame pointer – 3 - argx
  • 58. LoadArgument void op_lda(VM* vm) { int argx = NEXT(vm); int v = vm->stack[vm->fp-argx-3]; PUSH(vm, v); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer arg0 argc fp pc v
  • 59. Return void op_ret(VM* vm) { int result = POP(vm); vm->pc = POP(vm); vm->fp = POP(vm); int argc = POP(vm); vm->sp -= argc; PUSH(vm, result); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer arg0 argc fp pc result
  • 60. Return void op_ret(VM* vm) { int result = POP(vm); vm->pc = POP(vm); vm->fp = POP(vm); int argc = POP(vm); vm->sp -= argc; PUSH(vm, result); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer arg0 argc fp pc result
  • 61. Return void op_ret(VM* vm) { int result = POP(vm); vm->pc = POP(vm); vm->fp = POP(vm); int argc = POP(vm); vm->sp -= argc; PUSH(vm, result); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer arg0 argc fp pc result
  • 62. Return void op_ret(VM* vm) { int result = POP(vm); vm->pc = POP(vm); vm->fp = POP(vm); int argc = POP(vm); vm->sp -= argc; PUSH(vm, result); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer arg0 argc fp result
  • 63. Return void op_ret(VM* vm) { int result = POP(vm); vm->pc = POP(vm); vm->fp = POP(vm); int argc = POP(vm); vm->sp -= argc; PUSH(vm, result); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer arg0 argc result
  • 64. Return void op_ret(VM* vm) { int result = POP(vm); vm->pc = POP(vm); vm->fp = POP(vm); int argc = POP(vm); vm->sp -= argc; PUSH(vm, result); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer arg0 result
  • 65. Return void op_ret(VM* vm) { int result = POP(vm); vm->pc = POP(vm); vm->fp = POP(vm); int argc = POP(vm); vm->sp -= argc; PUSH(vm, result); } stack 20 00 42 00 51 04 7e 42 01 05 20 00 20 00 42 01 7d 10 00 7e 0b code stack pointer program pointer frame pointer result
  • 67.  Crafting interpreters: https://craftinginterpreters.com/contents.html#a-bytecode-virtual-machine  Register-based VM: https://github.com/skx/simple.vm  Konrad Kokosa: “Pro .NET Memory Management”  Database query compilation: https://www.youtube.com/watch?v=baOAbOdcnxs  Adding new CIL instruction to .NET: https://mattwarren.org/2017/05/19/Adding-a-new-Bytecode- Instruction-to-the-CLR/  and many many more… REFERENCES