Как полиморфные встроенные кэши работают с изменяемыми типами?

Полиморфный встроенный кэш (PIC) работает путем кэширования фактического метода по типу объекта, чтобы избежать дорогостоящих процедур поиска (обычно это поиск в хеш-таблице).

Как справиться со сравнением типов, если объекты типов являются изменяемыми (т. Е. Метод может быть изменен во время выполнения чего-то другого)?

Одна идея, которую я придумал, - это "счетчик классов", который увеличивается каждый раз, когда метод корректируется, однако кажется, что это будет чрезвычайно дорого в среде с сильными обезьянами, так как он убьет все PIC для этот класс, даже если методы для них не были изменены.

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

2 ответа

В V8 я предполагаю, что monkeypatching изменит "скрытый класс" ("map" - это SELF-терминология) объекта. Это сработало бы у вас, обезьяна залатала сам объект.

Если вы пропатчите этот класс (вы можете сделать это как JS?), Я бы предположил, что он делает недействительными все PIC, поскольку это, вероятно, редко. В качестве альтернативы, он может перекомпилировать старый метод для отправки прямо в новый метод (я думаю, после проверки типа)

Кроме того, я не думаю, что другие "большие 3" используют PIC, на самом деле. Я полагаю, ты имеешь в виду белку-рыбу и рыбу-монстра. Первый является переводчиком, а второй фокусируется на подходе отслеживания, и я не помню, чтобы что-нибудь слышал о PIC. На самом деле, я не думаю, что tracemonkey делает что-то крутое для объектов, но я могу ошибаться.

Тип вывода используется:

SpiderMonkey в основном использует определение типа, чтобы определить, к каким свойствам обращаются; в тех случаях, когда вывод типа не находит точную форму объекта, к которому осуществляется доступ, SpiderMonkey использует PIC (полиморфные встроенные кэши) для хранения результата поиска.

Дополнительной формой обратной связи профилирования являются полиморфные встроенные кэши Baseline JIT. Полиморфные встроенные кэши - это классический метод оптимизации динамической отправки, созданный в сообществе Smalltalk.

Де-оптимизация - это имя процесса, который происходит при сбое вывода типа:

Конечно, JavaScript является динамически типизированным языком, иногда предположение о скрытом классе объекта будет неверным, и в этом случае V8 будет "де-оптимизировать" и вернется к исходной версии вызова метода, в котором объекты скрытый класс проверен.

Для этого необходимо несколько компиляторов:

Технически это означает, что компилятор на самом деле представляет собой два компилятора: базовый компилятор и "оптимизатор". (Или даже больше, если речь идет об АО и SpiderMonkey). Концепция вполне разумна и может дать невероятную производительность, но есть нюанс: оптимизированный код может быть "деоптимизирован" в разных местах, а не только в точке входа, что означает, что среда (локальные переменные, аргументы, контекст) должна быть нанесены на карту и перемещены.

Ion, будучи оптимизирующим компилятором, не поддерживает компиляцию в проверках режима отладки. Действительно, реализация такой поддержки является сомнительной полезностью, поскольку ее оптимизация сделает вызовы onStep в лучшем случае неудачными. Для поддержки режима отладки оптимизированный код в стеке деоптимизируется и выдается на базовый уровень. То есть кадр Ion в стеке перезаписывается восстановленным базовым кадром, соответствующим тому же местоположению, в котором в настоящее время выполняется код Ion.

Отладка осуществляется с помощью динамической деоптимизации:

Мы можем сделать лучше. Мечта 90-х, воплощенная в языке Self, жива в JavaScript. Мы можем адаптировать динамическую деоптимизацию Self с помощью техники замены в стеке для отладки даже оптимизированного кода. Основная идея debug mode OSR прост: когда требуется отладка, мы деоптимизируем и перекомпилируем JIT-код в стеке, исправляя адреса возврата по мере продвижения. Можно было бы сказать, что это почти элегантно, если бы не жестокое насилие, которое оно наносит на стековые фреймы.

Рассмотрим следующую функцию JavaScript:

function foo(o) { return o.f + o.g; }

В этом примере доступ к свойству может привести к чему угодно - от простой загрузки из известных мест в куче до вызовов получателей или даже сложных ловушек DOM, например, если o были объектом документа и f были имя элемента на странице. Базовый JIT первоначально выполнит эти обращения к свойствам как полностью полиморфную диспетчеризацию. Но при этом он запишет необходимые шаги и затем изменит доступ к куче на месте, чтобы он стал кэшем необходимых шагов для повторения аналогичного доступа в будущем. Например, если у объекта есть свойство f по смещению 16 от основания объекта код будет изменен, чтобы сначала быстро проверить, состоит ли входящий объект из свойства f со смещением 16 и затем выполнить нагрузку. Говорят, что эти кэши встроены, поскольку они полностью представлены в виде сгенерированного машинного кода. Говорят, что они полиморфны, потому что, если встречаются различные структуры объектов, машинный код модифицируется для включения ранее встреченных типов объектов перед выполнением полностью динамического поиска свойств. Когда DFG скомпилирует этот код, он проверит, является ли встроенный кэш мономорфным - оптимизирован ли он только для одной объектной структуры - и, если это так, он выдаст только проверку для этой объектной структуры с последующей прямой загрузкой. В этом примере, если o всегда был объектом со свойствами f а также g при инвариантных смещениях DFG должен будет выполнить только одну проверку типа для o следуют две прямые нагрузки.

Точный конвейер оптимизации компилятора потока данных (DFG JIT

Ускоренный конвейер оптимизации работы компилятора (Just-in-Time) (FTL JIT

Рекомендации