Вот обзор работы v86. Для получения более подробной информации, проверьте источник.
Основные ограничения WebAssembly (для создания эмуляторов с JIT):
структурированный поток управления (нет произвольных переходов);
нет контроля над регистрами (нельзя сохранять аппаратные регистры в локальных переменных WebAssembly между функциями);
нет mmap (необходимо полностью эмулировать подкачку страниц);
нельзя вносить изменения;
генерация модулей довольно медленная, но по крайней мере она асинхронная, поэтому другие процессы могут продолжать работу;
есть некоторые накладные расходы памяти на модуль, поэтому вы не можете создать более нескольких тысяч.
v86 имеет интерпретируемый режим, который собирает точки входа (цели вызовов функций и косвенные переходы). Он также измеряет «горячесть» каждой страницы, чтобы компиляция была сосредоточена на коде, который часто выполняется. Как только страница считается «горячей», код генерируется для всей страницы и до MAX_PAGES, которые напрямую достижимы из неё.
v86 генерирует одну функцию с большим оператором switch (brtable), чтобы гарантировать, что все функции и цели косвенных переходов доступны из других модулей. Остальной поток управления обрабатывается с помощью алгоритма «stackifier» (хорошо объяснённого в этом блоге). На данный момент нет связывания модулей WebAssembly. Текущий модуль завершается, и основной цикл определяет, можно ли ввести новый модуль.
На практике я обнаружил, что браузеры не очень хорошо справляются с этой структурой (глубокие brtables, с использованием локальных переменных по всей функции), и MAX_PAGES должен быть установлен на довольно низкое значение, иначе использование памяти резко возрастает. Вероятно, возможны улучшения (генерация меньшего количества точек входа, разделение кода на несколько функций).
Генерация кода происходит в два прохода. Первый проход находит все границы основных блоков, второй генерирует код для каждого основного блока. Декодирование инструкций генерируется набором скриптов из таблицы инструкций. Оно также используется для генерации тестов.
Для обработки подкачки страниц v86 генерирует код, подобный этому (см. gen_safe_read):
entry <- tlb[addr >> 12 << 2]
if entry & MASK == TLB_VALID && (addr & 0xFFF) <= 0xFFC - bytes: goto fast
entry <- safe_read_jit_slow(addr, instruction_pointer)
if page_fault: goto exit-with-pagefault
fast: mem[(entry & ~0xFFF) ^ addr]
Существует кэш размером 4 МБ, который действует как tlb. Он содержит физический адрес, бит только для чтения, указывает ли страница на код (чтобы сделать его недействительным при записи) и указывает ли страница на mmio. Любой из этих случаев обрабатывается в медленном пути (safe_read_jit_slow), а также при обходе таблиц страниц и возникновении ошибок страниц. Быстрый путь используется в подавляющем большинстве случаев.
Остальная генерация кода в основном представляет собой прямой перевод x86 в WebAssembly. Единственный анализ, который проводится, — это оптимизация генерации условных переходов сразу после арифметических инструкций, например:
cmp eax, 52
setb eax
становится:
... // код для cmp
eax <- eax < 52
Используется механизм ленивых флагов для ускорения арифметики (применяется как к JIT, так и к интерпретируемому режиму, см. arith.rs и misc_instr.rs). Существует WIP, который пытается исключить большинство обновлений ленивых флагов.
Инструкции FPU эмулируются с помощью softfloat (очень медленно, но, к сожалению, некоторый код полагается на 80-битные числа с плавающей запятой).
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )