Security Theater
SecTheater is an online teaching community that targets the IT department. We do our best to produce for you high quality and well-edited screen casts about web development.
Compiler
Interpreter
Compiler
Interpreter
Lexer
AST
Parsed tokens
let code = '100 - 5 * (2 - 2 / 3)'
let arithmeticToknizer = (eqn) =>
eqn
.split(/(\+|\-|\*|\/|\(|\))/)
.map((token) => {
let type
if (['-', '*', '/', '+'].includes(token)) {
type = 'BinaryExpression'
} else if (['(', ')'].includes(token)) {
type = 'GroupExpression'
} else {
type = 'NumberLiteral'
}
return {
type,
value: token,
}
})
.filter((s) => s.value !== '')
let tokens = arithmeticToknizer(code)
const esprima = require('esprima')
let code = 'const meaningOfLife = 42'
console.log(esprima.tokenize(code))
/*
output => [
{ type: 'Keyword', value: 'const' },
{ type: 'Identifier', value: 'meaningOfLife' },
{ type: 'Punctuator', value: '=' },
{ type: 'Numeric', value: '42' },
]
*/
VariableDeclaration
VariableDeclarator
id: Identifier
init: Literal
name: meaningOfLife
value: 42
const util = require('util')
const esprima = require('esprima')
console.log(
util.inspect(
esprima.parse('const meaningOfLife = 42'), false, null, true,
),
)
/*
output => [
{ type: 'Keyword', value: 'const' },
{ type: 'Identifier', value: 'meaningOfLife' },
{ type: 'Punctuator', value: '=' },
{ type: 'Numeric', value: '42' },
]
*/
Parsed tokens
[generated bytecode for function: define (0x1c8e78250519 <SharedFunctionInfo define>)]
Parameter count 1
Register count 1
Frame size 8
44 S> 0x1c8e78250f36 @ 0 : 0c 2a LdaSmi [42]
0x1c8e78250f38 @ 2 : 26 fb Star r0
0x1c8e78250f3a @ 4 : 0d LdaUndefined
47 S> 0x1c8e78250f3b @ 5 : aa Return
Constant pool (size = 0)
Handler Table (size = 0)
Source Position Table (size = 6)
0x1c8e78250f41 <ByteArray[6]>
AST + scopes
Profiler
Interpreter
Compiler
Lexer
AST
Output
Optimized code
Parsed tokens
Generated bytecode
On stack replacement
OSR is simply a technique the optimizing compilers makes to optimize the code by replacing some frames from the stack by new ones that are optimized meanwhile the execution and without losing any data from the removed stack frame
function getX(point) {
return point.x
}
un-optimized stack frame in byte code
Stack trace
[generated bytecode for function: getX (0x2665be510511 <SharedFunctionInfo getX>)]
Parameter count 2
Register count 0
Frame size 0
38 S> 0x2665be5111c6 @ 0 : 28 02 00 00 LdaNamedProperty a0, [0], [0]
39 S> 0x2665be5111ca @ 4 : aa Return
Constant pool (size = 1)
0x2665be511179: [FixedArray] in OldSpace
- map: 0x34c1936c0729 <Map>
- length: 1
0: 0x16097aa0c561 <String[#1]: x>
Handler Table (size = 0)
Source Position Table (size = 6)
0x2665be5111d1 <ByteArray[6]>
AST + Scopes
a new optimized stack frame using opt code
Stack trace
[generated bytecode for function: getX (0x2665be510511 <SharedFunctionInfo getX>)]
Parameter count 2
Register count 0
Frame size 0
38 S> 0x2665be5111c6 @ 0 : 28 02 00 00 LdaNamedProperty a0, [0], [0]
39 S> 0x2665be5111ca @ 4 : aa Return
Constant pool (size = 1)
0x2665be511179: [FixedArray] in OldSpace
- map: 0x34c1936c0729 <Map>
- length: 1
0: 0x16097aa0c561 <String[#1]: x>
Handler Table (size = 0)
Source Position Table (size = 6)
0x2665be5111d1 <ByteArray[6]>
Instructions (size = 1008)
0xbd6ab243000 0 488b59c0 REX.W movq rbx,[rcx-0x40]
0xbd6ab243004 4 f6430f01 testb [rbx+0xf],0x1
0xbd6ab243008 8 740d jz 0xbd6ab243017 <+0x17>
0xbd6ab24300a a 49ba80d93d0100000000 REX.W movq r10,0x13dd980 (CompileLazyDeoptimizedCode)
0xbd6ab243014 14 41ffe2 jmp r10
0xbd6ab243017 17 55 push rbp
0xbd6ab243018 18 4889e5 REX.W movq rbp,rsp
0xbd6ab24301b 1b 56 push rsi
0xbd6ab24301c 1c 57 push rdi
0xbd6ab24301d 1d 48ba0000000021000000 REX.W movq rdx,0x2100000000
0xbd6ab243027 27 49bac010400100000000 REX.W movq r10,0x14010c0 (Abort)
0xbd6ab243031 31 41ffd2 call r10
0xbd6ab243034 34 cc int3l
0xbd6ab243035 35 4883ec08 REX.W subq rsp,0x8
0xbd6ab243039 39 4889b568ffffff REX.W movq [rbp-0x98],rsi
0xbd6ab243040 40 488b4db8 REX.W movq rcx,[rbp-0x48]
0xbd6ab243044 44 48bf89675172ed200000 REX.W movq rdi,0x20ed72516789 ;; object: 0x20ed72516789 <JSFunction next (sfi = 0x25c7b99d7971)>
0xbd6ab24304e 4e 483bcf REX.W cmpq rcx,rdi
0xbd6ab243051 51 0f8508030000 jnz 0xbd6ab24335f <+0x35f>
0xbd6ab243057 57 488b771f REX.W mo
Optimizing compiler
Replaces the value that an expression yields to, with the actual value of expression at the run-time instead of re-evaluating the expression
import axios from 'axios'
const { data } = await axios.get(
'http://jsonplaceholder.typicode.com/todos',
)
const todos = data
.slice(0, 5)
.filter((todo) => todo.completed)
.map((todo) => todo.title)
console.log(todos)
const data = [
{
id: 1,
title: "abc",
completed: false,
user_id: 2
},
...
]
Replaces the value that an expression yields to, with the actual value of expression at the run-time instead of re-evaluating the expression
import axios from 'axios'
const { data } = await axios.get(
'http://jsonplaceholder.typicode.com/todos',
)
const data = [
{
id: 1,
title: "abc",
completed: false,
user_id: 2
},
...
]
Not compiling/interpreting the un-used parts of code in order to save time
function add(x, y) {
return x + y
}
add(5, 2)
[generated bytecode for function: add (0x0d2bff519889 <SharedFunctionInfo add>)]
Parameter count 3
Register count 0
Frame size 0
23 S> 0xd2bff519c86 @ 0 : 25 02 Ldar a1
32 E> 0xd2bff519c88 @ 2 : 34 03 00 Add a0, [0]
35 S> 0xd2bff519c8b @ 5 : aa Return
Constant pool (size = 0)
Handler Table (size = 0)
Source Position Table (size = 8)
0x0d2bff519c91 <ByteArray[8]>
Not compiling/interpreting the un-used parts of code in order to save time
function add(x, y) {
return x + y
}
// add(5, 2)
// empty file
Byte code
Optimized code
output
Ignition
TurboFan
Feedback
Callback queue
Runtime API
Event loop
Memory
Heap
Call
Stack
Byte code
Ignition
TurboFan
Output
Opt code
A call stack is an implementation of the stack data structure to keep track of function calls in your program
Me 👉👈
function one() {
console.log('I am first')
}
function two() {
console.log('I am second')
one()
}
function third() {
two()
return 'I am third'
}
function run() {
return third()
}
console.log(run())
main()
run()
third()
two()
one()
Stack trace
A memory heap is an implementation of the graph data structure for allocating memory used by your program
Me 👉👈
Memory heap
GC Algorithms
Memory allocation
let meaningOfLife = 42
const data = {
users: [
{
username: 'ahmedosama-st',
email: 'ahmedosama@sectheater.io',
articles: [
{
title: 'Optimizing recursive functions',
url: 'https://dev.to/ahmedosama_st/optimizing-recursive-functions-1lhh',
},
],
},
],
}
meaningOfLife
42
data
JSObject
reference
Stack allocation
Heap allocation
Reference count
Mark and sweep
Reference count
Mark and sweep
class Point {
constructor(x, y) {
this.x = x
this.y = y
}
}
let p1 = new Point(1, 2) // Point Ref count : 1, p1 Ref count: 1
let p2 = p1 // p1 Ref count: 2
Reference count
Mark and sweep
Free
Reference count
Mark and sweep
Free
A
Root
let A = { value: 1 }
Reference count
Mark and sweep
Free
A
Root
B
C
D
let A = { value: 1 }
let B = { value: 2 }
A.B = B
A.C = { value: 3 } // C object
B.D = { value: 4 } // D object
Mark and sweep
Free
A
Root
B
C
D
E
let A = { value: 1 }
let B = { value: 2 }
A.B = B
A.C = { value: 3 } // C object
B.D = { value: 4 } // D object
A.C.E = { value: 5 }
Mark and sweep
Free
A
Root
B
C
D
E
let A = { value: 1 }
let B = { value: 2 }
A.B = B
A.C = { value: 3 } // C object
B.D = { value: 4 } // D object
A.C.E = { value: 5 }
delete A.B
Mark and sweep
Free
A
Root
Free
C
Free
E
let A = { value: 1 }
let B = { value: 2 }
A.B = B
A.C = { value: 3 } // C object
B.D = { value: 4 } // D object
A.C.E = { value: 5 }
delete A.B
let arr = [1, 2, 3]
let user = { first_name: 'ahmed', last_name: 'osama' }
const double = (x) => x * 2
function sayWelcome(name) {
return `Hello ${name}`
}
let arr = [1, 2, 3]
let user = { first_name: 'ahmed', last_name: 'osama' }
const double = (x) => x * 2
function sayWelcome(name) {
return `Hello ${name}`
}
Stack
Heap
arr: x1ud
x1ud: [1, 2, 3]
let object = {
x: 5,
y: 6,
}
Property attributes
[[Value]]: 5
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
Property attributes
[[Value]]: 6
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
'x'
'y'
JSObject
let a = { x: 5, y: 6 }
let b = { x: 5, y: 6 }
Property attributes
[[Value]]: 5
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
Property attributes
[[Value]]: 6
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
'x'
'y'
JSObject (a)
'x'
'y'
JSObject (b)
Property attributes
[[Value]]: 5
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
Property attributes
[[Value]]: 6
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
let a = {
x: 5,
y: 6,
}
Property information
Offset: 0
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
Property attributes
Offset: 1
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
5
6
JSObject (a)
'x'
'y'
Shape
let a = { x: 5, y: 6 }
let b = { x: 7, y: 8 }
Property information
Offset: 0
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
Property attributes
Offset: 1
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
5
6
JSObject (a)
'x'
'y'
Shape
7
8
JSObject (b)
let o = {}
JSObject (o)
Shape
(empty)
let o = {}
o.x = 6
Property information
Offset: 0
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
6
JSObject (o)
'x'
Shape
(empty)
Shape
(x)
let o = {}
o.x = 6
o.y = 7
Property information
Offset: 0
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
Property attributes
Offset: 1
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
6
7
JSObject (o)
'x'
'x'
'y'
Shape
(empty)
Shape
(x)
Shape
(x, y)
let o = {}
o.x = 6
o.y = 7
Property information
Offset: 0
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
Property attributes
Offset: 1
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
6
7
JSObject (o)
'x'
'y'
Shape
(empty)
Shape
(x)
Shape
(x, y)
let a = {}
a.x = 6
Property attributes
Offset: 0
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
6
JSObject (a)
'x'
Shape
(empty)
Shape
(x)
let a = {}
a.x = 6
let b = {}
b.y = 7
Property information
Offset: 0
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
Property attributes
Offset: 0
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
6
JSObject (a)
'x'
Shape
(empty)
Shape
(x)
7
JSObject (b)
'y'
Shape
(y)
let o = {}
o.x = 6
let w = { x: 6 }
Property information
Offset: 0
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
6
JSObject (o)
'x'
Shape
(empty)
Shape
(x)
Property information
Offset: 0
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
6
JSObject (w)
'x'
Shape
(x)
let point = {}
point.x = 3
point.y = 4
point.z = 5
3
JSObject (p)
4
5
'x'
Shape
(x)
'y'
Shape
(x, y)
'z'
Shape
(x, y, z)
'x'
Shape table
'y'
'z'
function getX(o) {
return o.x
}
JSFunction 'getX'
get_by_id loc0, arg1, x
N/A
N/A
return loc0
function getX(o) {
return o.x
}
getX({ x: 'a' })
JSFunction 'getX'
get_by_id loc0, arg1, x
0
return loc0
Property information
Offset: 0
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
'x'
Shape
function getX(o) {
return o.x
}
getX({ x: 'a' })
getX({ x: 'b' })
JSFunction 'getX'
get_by_id loc0, arg1, x
0
return loc0
Property information
Offset: 0
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
'x'
Shape
let array = [
'a',
]
Property attributes
[[Value]]: 1
[[Writable]]: true
[[Enumerable]]: false
[[Configurable]]: false
Property attributes
[[Value]]: 'a'
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
'length'
'0'
Array
let array = [
'a',
'b,'
]
Property attributes
[[Value]]: 'a'
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
'length'
'0'
Array
'1'
Property attributes
[[Value]]: 2
[[Writable]]: true
[[Enumerable]]: false
[[Configurable]]: false
Property attributes
[[Value]]: 'b'
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
let usernames = [
'ahmedosama-st',
'ahmedosama_st'
]
Property information
Offset: 0
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
1
JSArray
'length'
Shape
Element information
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
'ahmedosama-st'
Elements
'ahmedosama_st'
const array = Object.defineProperty([], '0', {
value: 'ahmed',
writable: false,
enumerable: false,
configurable: false,
})
const anotherArray = []
Object.defineProperties(anotherArray, [
{
value: 'one',
writable: true,
enumerable: true,
configurable: true,
},
])
console.log(anotherArray)
let arr = Object.defineProperty([], '0', {...})
let anotherArr = Object.defineProperties([], [...])
Property information
Offset: 0
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
1
JSArray
'length'
Shape
Element information
[[Value]]: 'abc'
[[Writable]]: true
[[Enumerable]]: true
[[Configurable]]: true
0
Dictionary Elements
1
GIF from Lydia Hallie's article
Raise up your techinal skills
By Security Theater
Let's explore how JavaScript works under the hood.
SecTheater is an online teaching community that targets the IT department. We do our best to produce for you high quality and well-edited screen casts about web development.