Как полиморфные встроенные кэши работают с изменяемыми типами? - PullRequest
4 голосов
/ 27 июня 2009

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

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

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

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

Ответы [ 2 ]

1 голос
/ 29 июля 2009

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

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

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

0 голосов
/ 26 мая 2017

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

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

Data Flow Just-in-Time Compiler (DFG JIT) Optimization Pipeline

Faster-Than-Light Just-in-Time Compiler (FTL JIT) Optimization Pipeline

Ссылки

...