Создание JIT-компилятора

Я написал реализацию Brainfuck (C ++), которая работает следующим образом:

  1. Прочитать входной файл brainfuck
  2. Сделайте тривиальную оптимизацию
  3. Преобразование brainfuck в машинный код для виртуальной машины
  4. Выполните этот машинный код в виртуальной машине

Это довольно быстро, но теперь узким местом является виртуальная машина. Он написан на C ++ и читает токен, выполняет действие (которого совсем немного, если вы знаете Brainfuck) и так далее.

Что я хочу сделать, так это вырезать виртуальную машину и на лету сгенерировать собственный машинный код (то есть, в основном, JIT-компилятор). Это легко может быть 20-кратное ускорение.

Это означало бы, что шаг 3 заменяется JIT-компилятором, а шаг 4 - выполнением сгенерированного машинного кода.

Я действительно не знаю, с чего начать, поэтому у меня есть несколько вопросов:

  1. Как это работает, как выполняется сгенерированный машинный код?
  2. Существуют ли библиотеки C ++ для генерации машинного кода?

person orlp    schedule 13.05.2011    source источник


Ответы (4)


  1. Сгенерированный машинный код просто jmp-ed to или call-ed как обычная функция. Иногда также требовалось отключить флаг невыполнения (бит NX) в памяти, содержащий сгенерированный код. В Linux это делается с помощью mprotect(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC.). В Windows NX называется DEP.

  2. Есть некоторые ... http://www.gnu.org/software/lightning/ - GNU Lightning (универсальный) и https://developer.mozilla.org/En/Nanojit - Nanojit, который используется в JIT-движки Firefox JavaScript. Более мощный и современный JIT - это LLVM, вам просто нужно перевести код BF в LLVM IR, и тогда LLVM сможет выполнять оптимизацию и генерацию кода для многих платформ или запускать LLVM IR на интерпретаторе (виртуальной машине) с возможностями JIT. Есть сообщение о BF и LLVM с полным компилятором LLVM JIT для BF http://www.remcobloemen.nl/2010/02/brainfuck-using-llvm/

Другой компилятор BF + LLVM находится здесь, в svn LLVM: https://llvm.org/svn/llvm-project/llvm/trunk/examples/BrainF/BrainF.cpp

person osgx    schedule 13.05.2011
comment
+1 и принято за единственную, объясняющую, как называется машинный код. - person orlp; 17.05.2011

LLVM - это полная библиотека C ++ (или набор библиотек) для генерации собственного кода из промежуточной формы, дополненная документацией и примерами. , и который использовался для создания JITters.

(У него также есть компилятор C / C ++, который использует фреймворк, однако сам фреймворк может использоваться для других языков).

person davmac    schedule 13.05.2011

GNU Lightning - это набор макросов, которые могут генерировать собственный код для нескольких различных архитектур. Вам потребуется твердое понимание ассемблерного кода, потому что ваш шаг 3 будет включать использование макросов Lightning для передачи машинного кода непосредственно в буфер, который вы позже будете выполнять.

person Ben Jackson    schedule 13.05.2011

Это может быть поздно, но ради помощи другим я публикую этот ответ.

У JIT-компилятора есть все шаги, которые есть у AOT-компилятора. Основное отличие заключается в том, что компилятор AOT выводит машинно-зависимый код в исполняемый файл, например exe и т. Д., В то время как JIT-компилятор загружает машинно-зависимый код в память во время выполнения (отсюда накладные расходы на производительность, потому что каждый раз он должен перекомпилировать и загружать).

Как JIT-компилятор загружает машинный код в память во время выполнения?

я не буду учить вас машинному коду, потому что я предполагаю, что вы уже знаете об этом,

для напр. код сборки

mov    rax,0x1

переводится на

48 c7 c0 01 00 00 00

вы динамически генерируете переведенный код и сохраняете его в таком векторе (это вектор C)

vector machineCode{
   0x48, 0xc7, 0xc0, 0x01, 0x00, 0x00, 0x00, 
}

затем вы копируете этот вектор в память, для этого вам нужно знать размер памяти, необходимый для этого кода, который вы можете получить с помощью machinecode.size (), и учитывать размер страницы.

чтобы скопировать этот вектор в память, вам нужно вызвать функцию mmap в C. Установите указатель на начало вашего кода и вызовите его. ты в порядке.

Извините, если что-то неясно, вы всегда можете проверить этот пост для простоты https://solarianprogrammer.com/2018/01/10/writing-minimal-x86-64-jit-compiler-cpp/ https://github.com/spencertipping/jit-tutorial.

person Mamoon Ahmed    schedule 14.08.2018