ОПТИМИЗАЦИЯ ПРЕДСТАВЛЕНИЯ БАЙТКОДА JVM ДЛЯ ВСТРАИВАЕМЫХ СИСТЕМ Пилипенко А. В., аспирант кафедры информатики математикомеханического факультета СПбГУ, artur.pilipenko@gmail.com Аннотация В докладе описан алгоритм сжатия байт-кода JVM, основанный на генерации новых инструкций для часто встречающихся последовательностей байт-кодов исходной программы. Этот алгоритм минимизирует суммарный размер программы и интерпретатора, необходимого для её исполнения. Наилучших результатов этот подход позволяет добиться в закрытой модели, когда весь исполняемый код доступен на этапе построения, и не стоит задачи обеспечить совместимость интерпретатора со стандартным байт-кодом. Введение Для встраиваемых систем выполняемые задачи не отличаются вычислительной сложностью, но общий размер программного обеспечения является критически важным параметром. Другой особенностью встраиваемых устройств является то, что в редких случаях на таких устройствах необходимо исполнять произвольные приложения. Обычно такое устройство имеет вполне конкретное применение, и конкретное приложение для исполнения. Этот факт позволяет использовать специализированное представление для Java приложений, без необходимости поддерживать совместимость со стандартным байт-кодом. В докладе описывается алгоритм сжатия Java приложений, основанный на автоматической генерации специализированного набора инструкций на основе стандартного байт-кода JVM. [1] Специализированный набор инструкций минимизирует суммарный размер приложения и интерпретатора, необходимого для его исполнения. Он представляет собой подмножество стандартного байт-кода JVM, используемое приложением, дополненное “суперинструкциями”, кодирующими часто встречающиеся последовательности байт-кодов исходной программы. По сути, этот алгоритм является применением методов словарного сжатия к коду программ. Аналогичный подход к сжатию кода программ рассмотрен в работах [2, 3]. Генерация оптимизированного набора инструкций Построение словаря Процесс генерации специализированного набора инструкций начинается с построения словаря всех последовательностей байт-кодов исходной программы, которые могут быть использованы для создания “суперинструкций”. Это последовательности небольшой длины (обычно не более 10 инструкций) с одной точкой входа и выхода. Для каждой последовательности в словаре хранится то, сколько раз она встречается в исходной программе программы. Для хранения словаря используется префиксное дерево, в узлах которого записываются байт-коды. Каждый узел такого дерева представляет элемент словаря – последовательность инструкций исходной программы, которую можно восстановить, выписав байт-коды всех вершины от узла до корня в обратном порядке. Словарь наполняется в процессе итерации по байт-коду всех методов программы. В процессе итерации, на каждом шаге вычисляется множество последовательностей инструкций, которые оканчиваются в просматриваемой позиции. В начале просмотра каждого метода это множество содержит только пустую последовательность. На каждом последующем шаге множество состоит из пустой последовательности и всех последовательностей множества из предыдущего шага, дополненных текущим байт-кодом. В дерево добавляются последовательности, которые могут быть использованы для создания “суперинструкций”. Так как все новые последовательности получаются путем добавления одного байт-кода к существующей последовательности, операции поиска и добавления в дерево сводятся к поиску и добавлению потомка для существующей вершины. Выбор набора инструкций Задача выбора оптимального словаря для методов словарного сжатия является NP-полной [4], поэтому на практике используются различные эвристики. Достаточно простым и эффективным является частотный подход, когда в словарь включается самые часто встречающиеся подстроки исходного текста. Аналогичный подход используется и в описываемом алгоритме. В байт-коде JVM все инструкции кодируются одним байтом, следовательно, набор инструкций ограничен 256 элементами. В набор включаются все инструкции исходного байт-кода, которые использует приложение, затем набор дополняется до 256 элементов последовательностями словаря с максимальным весом, где вес последовательности считается по следующей формуле: patternCount * (patternLenght – 1) – interpreterSize, где, patternCount – сколько раз данная последовательность встречается в коде программы; patternLength – длина последовательности в байтах; interpreterSize – последовательности. размер кода интерпретатора для данной Нахождение оптимального покрытия Для заданного набора инструкций может существовать более одного представления исходной программы. Выбор оптимального представления сводится к нахождению такого покрытия кода исходной программы последовательностями из набора инструкций, при котором суммарная длина использованных последовательностей максимальна. Оптимальное покрытие вычисляется отдельно для каждого метода. Вычисление оптимального покрытия метода осуществляется последовательно для каждой позиции в теле метода. Для каждой позиции хранится сумма длин использованных последовательностей и указатель на последнюю использованную последовательность. Тогда, при известном оптимальном покрытии для всех предыдущих позиций нахождение оптимального покрытия для текущей позиции сводится к выбору последовательности, заканчивающейся в текущей позиции. Из множества последовательностей, заканчивающихся в данной позиции, выбирается такая последовательность, принадлежащая набору инструкций, для которой максимально значение length(pattern) + lengths[pos - length(pattern)], где, length(pattern) – длина последовательности; lengths[i] – сумма длин последовательностей оптимального покрытия для i-ой позиции; pos – текущая позиция. Представление метода в оптимизированном байт-коде восстанавливается с конца метода по указателям на использованные последовательности. Заключение Описанный в статье подход позволяет уменьшить размер байт-кода Java программы на 15-30% в зависимости от приложения. В отличие от многих других алгоритмов сжатия программ, описанная оптимизация не оказывает влияния на скорость исполнения программы. Данный подход может быть применен и для открытой модели, например, для уменьшения размера системных классов. Но в открытой модели совместимость со стандартным набором инструкций существенно ограничивает количество свободных байт-кодов. Литература 1. 2. 3. 4. Tim Lindholm, Frank Yellin, Gilad Bracha, Alex Buckley “The Java® Virtual Machine Specification” http://docs.oracle.com/javase/specs/jvms/se7/jvms7.pdf [дата просмотра: 21.04.2013] Lars Raeder Clausen , Ulrik Pagh Schultz, Gilles Muller, Charles Consel “Java Bytecode Compression for Low-End Embedded Systems”, ACM Transactions on Programming Languages and Systems, 2000 Dimitris Saougkos , George Manis, Konstantinos Blekas, Apostolos V. Zarras, “Revisiting Java Bytecode Compression for Embedded and Mobile Computing Environments”, IEEE Transactions on Software Engineering, 2005 Michael Garey, David Johnson, “Computers and Intractability: A Guide to the Theory of NP-Completeness”, 1990