SOFTWAREENGINEERVLOG Telegram 2298
Forwarded from S0ER.Code
TurboFan: анализ оптимизаций в V8 с помощью ассемблера (часть 1)

Чем глубже мы узнаем языки программирования, тем больше начинаем любить и ценить ассемблер. Сегодня покажу, как знание ассемблера помогает в изучении возможностей движка V8.

V8 — это движок для работы с языком JavaScript, он используется в NodeJS и браузере Chrome. Одна из особенностей этого движка — представление «горячего» кода в виде оптимизированных машинных инструкций. Для этого в движок интегрирован оптимизирующий JIT-компилятор TurboFan.

Основные задачи, которые решает TurboFan:

💡 Анализ и оптимизация «горячих» функций (которые вызываются часто);
💡 Специализация кода под конкретные типы данных;
💡 Удаление избыточных операций;
💡 Векторизация вычислений;
💡 Инлайнинг функций.

Для работы с машинным кодом традиционно используется ассемблер, поэтому давайте разберем небольшой пример, который позволит лучше понять, как работает TurboFan. В этой статье будет общее описание блоков кода, а в будущих статьях разберем детали каждого из них.

Основные моменты, которые нужны для старта:

1️⃣ Мы будем использовать nodejs для получения машинного кода функции, для этого нужно запомнить следующий шаблон команды:


node --print-opt-code --code-comments -allow-natives-syntax your_script.js


2️⃣Мы будем использовать специальную инструкцию %OptimizeFunctionOnNextCall, без нее ничего не получится.

Давайте сделаем простой скрипт:


// sum.js
function sum(a, b) {
return a + b;
}

// Прогреваем функцию (вызываем много раз, чтобы V8 её оптимизировал)
for (let i = 0; i < 10000; i++) {
sum(i, i + 1); // используем целые числа, чтобы TurboFan сделал оптимизацию именно под них
}

// Явно просим V8 оптимизировать функцию (требует --allow-natives-syntax) иначе в выводе не будет описане функции
%OptimizeFunctionOnNextCall(sum);
// Вызываем ещё раз (теперь с оптимизацией)
sum(1, 2);


Теперь запустим скрипт node --print-opt-code --code-comments -allow-natives-syntax sum.js, если мы сделали всё правильно, то получим огромный вывод на экран, из которого интересна вот эта часть:



--- Raw source ---
(a, b) {
return a + b;
}

--- Optimized code ---
optimization_id = 1
source_position = 22
kind = TURBOFAN
name = sum
stack_slots = 6
compiler = turbofan
address = 0x2edae09247a1

Instructions (size = 184)

; загрузка hidden класса объекта (проверка структуры)
0x1097064c0 0 488b59f8 REX.W movq rbx, [rcx-0x8]

; проверка контекста
0x1097064c4 4 f6433501 testb [rbx+0x35],0x1
0x1097064c8 8 0f85f2e03dfb jnz 0x104ae45c0 (CompileLazyDeoptimizedCode) ;; деоптимизация

; пролог
0x1097064ce e 55 push rbp
0x1097064cf f 4889e5 REX.W movq rbp, rsp
0x1097064d2 12 56 push rsi
0x1097064d3 13 57 push rdi
0x1097064d4 14 50 push rax

; выравнивание стека и проверка лимитов
0x1097064d5 15 4883ec08 REX.W subq rsp,0x8
0x1097064d9 19 488975e0 REX.W movq [rbp-0x20],rsi
0x1097064dd 1d 493b65a0 REX.W cmpq rsp, [r13-0x60] (external value (StackGuard::address_of_jslimit()))
0x1097064e1 21 0f8653000000 jna 0x10970653a <+0x7a> ; если стек переполнен, переходим

; ====== Основная функция ======

; Загрузка аргумента "a"
0x1097064e7 27 488b5518 REX.W movq rdx, [rbp+0x18]
0x1097064eb 2b f6c201 testb rdx,0x1
0x1097064ee 2e 0f8572000000 jnz 0x109706566 <+0xa6>

; Загрузка аргумента "b"
0x1097064f4 34 488b4d20 REX.W movq rcx, [rbp+0x20]
0x1097064f8 38 48c1f920 REX.W sarq rcx, 32 ; сразу распаковка SMI для "b"

; Подготовка аргументов к сложению
0x1097064fc 3c 488bfa REX.W movq rdi,rdx
0x1097064ff 3f 48c1ff20 REX.W sarq rdi, 32 ; распаковка для "a"
Please open Telegram to view this post
VIEW IN TELEGRAM
👍72👀1



tgoop.com/softwareengineervlog/2298
Create:
Last Update:

TurboFan: анализ оптимизаций в V8 с помощью ассемблера (часть 1)

Чем глубже мы узнаем языки программирования, тем больше начинаем любить и ценить ассемблер. Сегодня покажу, как знание ассемблера помогает в изучении возможностей движка V8.

V8 — это движок для работы с языком JavaScript, он используется в NodeJS и браузере Chrome. Одна из особенностей этого движка — представление «горячего» кода в виде оптимизированных машинных инструкций. Для этого в движок интегрирован оптимизирующий JIT-компилятор TurboFan.

Основные задачи, которые решает TurboFan:

💡 Анализ и оптимизация «горячих» функций (которые вызываются часто);
💡 Специализация кода под конкретные типы данных;
💡 Удаление избыточных операций;
💡 Векторизация вычислений;
💡 Инлайнинг функций.

Для работы с машинным кодом традиционно используется ассемблер, поэтому давайте разберем небольшой пример, который позволит лучше понять, как работает TurboFan. В этой статье будет общее описание блоков кода, а в будущих статьях разберем детали каждого из них.

Основные моменты, которые нужны для старта:

1️⃣ Мы будем использовать nodejs для получения машинного кода функции, для этого нужно запомнить следующий шаблон команды:


node --print-opt-code --code-comments -allow-natives-syntax your_script.js


2️⃣Мы будем использовать специальную инструкцию %OptimizeFunctionOnNextCall, без нее ничего не получится.

Давайте сделаем простой скрипт:


// sum.js
function sum(a, b) {
return a + b;
}

// Прогреваем функцию (вызываем много раз, чтобы V8 её оптимизировал)
for (let i = 0; i < 10000; i++) {
sum(i, i + 1); // используем целые числа, чтобы TurboFan сделал оптимизацию именно под них
}

// Явно просим V8 оптимизировать функцию (требует --allow-natives-syntax) иначе в выводе не будет описане функции
%OptimizeFunctionOnNextCall(sum);
// Вызываем ещё раз (теперь с оптимизацией)
sum(1, 2);


Теперь запустим скрипт node --print-opt-code --code-comments -allow-natives-syntax sum.js, если мы сделали всё правильно, то получим огромный вывод на экран, из которого интересна вот эта часть:



--- Raw source ---
(a, b) {
return a + b;
}

--- Optimized code ---
optimization_id = 1
source_position = 22
kind = TURBOFAN
name = sum
stack_slots = 6
compiler = turbofan
address = 0x2edae09247a1

Instructions (size = 184)

; загрузка hidden класса объекта (проверка структуры)
0x1097064c0 0 488b59f8 REX.W movq rbx, [rcx-0x8]

; проверка контекста
0x1097064c4 4 f6433501 testb [rbx+0x35],0x1
0x1097064c8 8 0f85f2e03dfb jnz 0x104ae45c0 (CompileLazyDeoptimizedCode) ;; деоптимизация

; пролог
0x1097064ce e 55 push rbp
0x1097064cf f 4889e5 REX.W movq rbp, rsp
0x1097064d2 12 56 push rsi
0x1097064d3 13 57 push rdi
0x1097064d4 14 50 push rax

; выравнивание стека и проверка лимитов
0x1097064d5 15 4883ec08 REX.W subq rsp,0x8
0x1097064d9 19 488975e0 REX.W movq [rbp-0x20],rsi
0x1097064dd 1d 493b65a0 REX.W cmpq rsp, [r13-0x60] (external value (StackGuard::address_of_jslimit()))
0x1097064e1 21 0f8653000000 jna 0x10970653a <+0x7a> ; если стек переполнен, переходим

; ====== Основная функция ======

; Загрузка аргумента "a"
0x1097064e7 27 488b5518 REX.W movq rdx, [rbp+0x18]
0x1097064eb 2b f6c201 testb rdx,0x1
0x1097064ee 2e 0f8572000000 jnz 0x109706566 <+0xa6>

; Загрузка аргумента "b"
0x1097064f4 34 488b4d20 REX.W movq rcx, [rbp+0x20]
0x1097064f8 38 48c1f920 REX.W sarq rcx, 32 ; сразу распаковка SMI для "b"

; Подготовка аргументов к сложению
0x1097064fc 3c 488bfa REX.W movq rdi,rdx
0x1097064ff 3f 48c1ff20 REX.W sarq rdi, 32 ; распаковка для "a"

BY S0ER


Share with your friend now:
tgoop.com/softwareengineervlog/2298

View MORE
Open in Telegram


Telegram News

Date: |

Telegram channels enable users to broadcast messages to multiple users simultaneously. Like on social media, users need to subscribe to your channel to get access to your content published by one or more administrators. Each account can create up to 10 public channels The main design elements of your Telegram channel include a name, bio (brief description), and avatar. Your bio should be: Clear A Telegram channel is used for various purposes, from sharing helpful content to implementing a business strategy. In addition, you can use your channel to build and improve your company image, boost your sales, make profits, enhance customer loyalty, and more.
from us


Telegram S0ER
FROM American