|
Spec-Zone .ru
спецификации, руководства, описания, API
|
Этот формат позволяет любому числу (от одного до сотен тысяч) классов Java быть закодированным компрессором, переданным сжато в единственном блоке байтов, и декодировал декомпрессором в эквивалентный Java файлы class. Поскольку это может также представить ресурсы class и другие "файлы стороны", это может служить альтернативой архиву JAR для некоторых задач развертывания, особенно загружая приложения Java.
Формат Pack200 может уменьшить размер приложения Java фактором семь - девять, по сравнению с эквивалентным JAR, содержащим несжатый, хранил файлы class. В отличие от этого, использование zip ВЫКАЧИВАЕТ интеграл алгоритма к JAR, и архивы ZIP получает фактор два. Недокументированный механизм "уплотнения", используемый, чтобы развернуть загрузки SDK в прошлом, получает соответствующий фактор пять - шесть. Отметьте, что все эти числа принимают и соединяются, эффекты постпередачи с ВЫКАЧИВАЮТ или подобный стандартный алгоритм сжатия. (ВЫКАЧАЙТЕ, документируется .)
Основное побуждение для этого формата должно уменьшить диск и требования пропускной способности для упаковки приложения Java, передачи, и поставки. Более ранняя версия использовалась, чтобы упаковать загрузки для Java 2 Standard Edition выпуск 1.4.1 и 1.4.2 (кодовые названия "Загрузочный лоток" и "Богомол").
Этот формат не предназначается для быстрой загрузки в виртуальную машину, и не пытается улучшить скорость запуска или объем потребляемой памяти в запущении приложений Java. Тяжелые технические требования к непосредственно загружаемому формату файла сделали бы оптимальное сжатие невозможным. Декомпрессор настойчиво сжатого файла будет иметь сложное задание, чтобы сделать, и должен быть позволен память и процессорное время, чтобы сделать это задание. Мы предполагаем, что архивы Pack200 будут распакованы на тех же самых классах машины, которые выполняют Java SE и приложения J2EE.
Этот формат пакетно-ориентирован, оптимизируется для упаковки и передачи классов Java. Это не поддерживает произвольный доступ индивидуально сохраненных классов. Чтобы подчеркнуть последовательную природу этого формата архива, мы будем использовать передачу глагола, а не хранить, чтобы обратиться к форматированию данных, произведенных компрессором и принятый декомпрессором.
Этот формат не пытается копировать работу, выполняемую, ВЫКАЧИВАЮТ или другие байтовые алгоритмы сжатия. Как правило, инструменты используя Pack200 далее сожмут архивы, храня их в файлах ZIP или используя некоторый другой метод сжатия. Присутствие такого компрессора постпередачи является предположением, сделанным проектом Pack200.
Эта спецификация сложна, и может замеченный некоторым читателям, напрасно сложным. Проектные решения, отраженные здесь, были мотивированы обширным тестированием и экспериментированием с фактическим Java файлы class, найденные в реальных продуктах. Попытка удалить сложность из этой спецификации вероятна также удалить в известной мере существенную эффективность сжатия.
Никакое специальное сжатие или преобразование не выполняются ни на каком файле кроме файлов class кроме (возможно) переупорядочения их типом файла. Компрессор постпередачи, как предполагается, обеспечивает соответствующее сжатие на тех промежутках архива, которые переносят изображения non-class файлов.
Классы представляются в форме, которая подавляет их отдельные постоянные пулы, в пользу большого постоянного пула, который служит всему архиву. Таким образом, когда файл class извлекается из архива Pack200, новый постоянный пул будет создаваться для него, и все постоянные скорректированные ссылки пула. Это не изменяет семантику class, но это обычно изменит поразрядное изображение файла, и возможно даже его размер, поскольку неиспользованные постоянные записи пула удаляются.
Отметьте, что каждый файл class должен быть полностью проанализирован компрессором, так, чтобы весь постоянный пул индексировал, может быть найден и (позже) перенумерован. Это требование применяется к любому class, полю, методу, или атрибуту кода, который обращается к константе. Формат Pack200 поддерживает умеренный диапазон атрибутов. Скромное разнообразие новых разметок атрибута может быть объявлено к компрессору, и формат Pack200 обеспечивает место, чтобы передать такие разметки для использования декомпрессорами.
Логически, полоса является неявно размерным массивом 32-разрядных целых без знака. Однако, редко для полосы физически потребовать больше чем одного или двух байтов за элемент, так как кодировки элемента выбираются, чтобы передать фактические значения полосы более сжато.
У полосы нет никакого фиксированного заголовка, не даже индикации относительно его размера. Количество элементов полосы выводится декомпрессором из содержания предыдущих полос, или (в конечном счете) от заголовка архива.
У элементов любой данной полосы есть общее значение и роль. Например, имена всех переданных классов находятся в единственной полосе, в то время как все количества поля class находятся в различной полосе. Каждая полоса передается как непрерывный сегмент байтов в пределах архива. Эта смежность является главной причиной, что Pack200 архив, в то время как уплотнено для начала, очень сжимаем утилитами как zip.
В некоторых полосах каждый элемент помогает описать один объект. Например, каждый class связывается с количеством полей, которое дается в архиве как соответствующее значение в полосе class_field_count. В других полосах один объект может быть описан выполнением нуля или большего количества элементов в полосе. Например, интерфейсы, реализованные class, даются в архиве как соответствующее выполнение нуля или большего количества значений в полосе class_interface; каждое такое значение является индексировать обращением к единственному class.
Очень немного полос (меньше чем 10) содержат негомогенные байты, такие как изображения файлов ресурсов. Они немногих вызывают полосами байта. Многие из полос содержат ссылки в постоянный пул. Некоторые содержат флаги модификатора доступа и связанные биты. Одна полоса, названная полосой случайной работы, содержит строковые символы в особенно выбранном кодировании под названием "CHAR3" (несколько родственный UTF8, но не идентичный). Остальная часть полос передает целые числа со множеством других интерпретаций.
Одна из целочисленных полос (cp_Utf8_big_chars) переносит символы единственной строки CONSTANT_Utf8, выбранной для специального режима. Уникально, эта полоса повторяется нуль или больше раз, в зависимости от того, сколько строк выбирается для этого специального режима. (Эти особенно переданные "большие строки" объясняются позже в этом документе.)
У большинства полос есть легко понятая функция, такая как передача числа методов в class, или имени поля, или операнда "getfield" инструкции байт-кода.
За исключением особого случая полос байта, полосу никогда не рассматривают как размерный промежуток байтов, а скорее как считаемая серия элементов, которые являются закодированными целыми числами. Так как целочисленные кодировки обычно переменного размера (когда расценено как последовательности байта), нет никакого твердого правила для того, чтобы получить размер байта полосы из его количества элемента. Действительно, обнаружение конца полосы требует, чтобы это был проанализированный байт байтом.
Как можно было бы ожидать, полосы байта (которые кодируют bytewise данные, такие как изображения файла ресурсов), кодируют их целые числа как 8-разрядные байты без знака. Это кодирование называют BYTE1 в этой спецификации. (Сравните тип "u1" в определении файла class.)
У других полос есть значения с намного большим динамическим диапазоном, включая (в нескольких случаях) отрицательные числа, и/или значения полностью до 32-разрядного максимума без знака. Большинство этих кодировок является переменной длиной в ожидании, что типичный элемент полосы будет относительно маленьким в величине, даже при том, что некоторые элементы могут быть большими и потребовать, чтобы больше байтов представило. Некоторые полосы, которые, как ожидают, покажут корреляции strong в их последовательностях элемента, кодируются как последовательные различия (кодирование дельты), а не абсолютные числовые значения.
Каждая полоса связывается с основным кодированием, которое компрессор и декомпрессор соглашаются использовать, передавая элементы той полосы. Для любой полосы после конца заголовка сегмента, за исключением полос байта, компрессор может дополнительно определить вторичное кодирование, чтобы использовать вместо основного кодирования. В основном, значения по умолчанию кодирования полосы к основному устройству, если нет явно объявленное вторичное устройство. Это позволяет формату Pack200 адаптироваться более близко к фактической статистике элементов полосы.
Например, у большинства полос, таких как те, которые содержат количества и размеры, есть основное кодирование под названием UNSIGNED5. Это - кодирование без знака общего назначения, которое представляет значения в диапазоне [0.. 191] как единственный байт, и увеличивается к максимальному размеру пяти байтов для чисел, больше чем приблизительно пятьдесят миллионов. Однако, если полоса содержит только числа в диапазоне [0,255], кодирование BYTE1 более компактно, и компрессору позволяют дать декомпрессору команду использовать это вместо этого.
Когда компрессор определяет вторичное кодирование, он должен испустить дополнительный спецификатор кодирования полосы, который описывается в другом месте. Специализированный метод кодирования часто сохраняет много байтов, если он соответствует более точно фактический динамический диапазон значений элемента полосы.
Параметр B (1 <=B <=5) является максимальной длиной в байтах кодирования единственного целого числа. Менее существенные биты всегда кодируются в более ранних байтах.
Параметр H (1 <=H <=256) является основанием кодирования. это также определяет условия, при которых завершаются последовательности байта кодирования. Cо-параметр L (0 <=L <=255) определяется как (256-ой). Закодированным последовательностям байта позволяют содержать только один байт со значением меньше чем L, и тот байт должен быть последним в последовательности. Таким образом большие значения H делают для более длительных средних длин кодирования. Если H 256, и L является нулем, то метод кодирования является фиксированной длиной, потому что все кодировки должны быть точно B байтами долго.
Параметр S (0 <=S <=2) определяет, ли и как кодирование представляет числа со знаком. (Более точно, так как элементы полосы традиционно расцениваются, поскольку 32-разрядные целые числа без знака, S определяет кодирование элементов полосы, больше чем самое большое 31-разрядное число без знака, 2147483647. Но мы будем продолжать обращаться к таким числам как отрицательный, где различие не важно.) S обозначает число младших значащих битов, которые служат знаковым битом. Если S является нулем, числа без знака. Если S один, LSB числа без знака является монопольным-ored в смещенный на право остаток от числа без знака, чтобы произвести соответствующее число со знаком. Если S - больше чем один, произведенное число со знаком отрицательно, только если все младшие значащие биты S устанавливаются, и иначе эти младшие биты способствуют положительной величине целого числа. Это представление эффективно для полос, содержащих главным-образом-положительные-числа, такие как смещения ответвления байт-кода. Интерпретация знаковых битов более точно описывается в другом месте.
Параметр D (0 <=D <=1) определяет, передает ли полоса свои данные через последовательные различия (то есть, кодирование дельты). В записи этих кодировок могут быть опущены параметры S и D, если и нуль, и D может быть опущен если нуль.
Таким образом кодирование (1,256,0,0), также записанный как (1 256), представляет числа как байты без знака, в то время как (4 256) представляет числа как 32-разрядные целые числа с прямым порядком байтов без знака. Кодирование (1,256,1) карты единственные байты к числам в диапазоне [-128 127]. Кодирование (1,256,1,1) экспрессы любая последовательность чисел, последовательные различия которых находятся в диапазоне [-128 127] (и чье первое число находится в том диапазоне).
Очень общее кодирование UNSIGNED5 может представить полный диапазон без знака 32-разрядных целых чисел. Последовательность байта в этом кодировании состоит или из четырех байтов меньше чем 192 сопровождаемые произвольным байтом, или иначе от нуля до трех байтов меньше чем 192 сопровождаемые байтом, больше чем или равный 192. Значение без знака формируется, масштабируя каждый последующий байт последовательными полномочиями основания 64, и добавляя все масштабируемые значения байта вместе.
| значение | байт 0 | байт 1 | байт 2 | байт 3 | байт 4 |
|---|---|---|---|---|---|
| 1 | 1 | ||||
| 191 | 191 | ||||
| 192 | 192 | 0 | |||
| 193 | 193 | 0 | |||
| 255 | 255 | 0 | |||
| 256 | 192 | 1 | |||
| 512 | 192 | 5 | |||
| 1024 | 192 | 13 | |||
| 2048 | 192 | 29 | |||
| 12479 | 255 | 191 | |||
| 12480 | 192 | 192 | 0 | ||
| 798911 | 255 | 255 | 191 | ||
| 798912 | 192 | 192 | 192 | 0 | |
| 51130559 | 255 | 255 | 255 | 191 | |
| 51130560 | 192 | 192 | 192 | 192 | 0 |
| 0xFFFFFFFF | 255 | 252 | 252 | 252 | 252 |
Вот набор основных кодировок, используемых по крайней мере одной полосой:
| Ввести | Имя | Цель |
|---|---|---|
| (1,256) | BYTE1 | байты |
| (3,128) | CHAR3 | Символы Java |
| (5,4) | BCI5 | позиции байт-кода |
| (5,4,2) | BRANCH5 | смещения ответвления байт-кода |
| (5,64) | UNSIGNED5 | общий ints без знака |
| (5,64,1) | SIGNED5 | общий подписал ints |
| (5,64,0,1) | UDELTA5 | монотонные последовательности |
| (5,64,1,1) | DELTA5 | автокоррелированые последовательности |
| (5,64,2,1) | MDELTA5 | главным образом монотонные последовательности |
Вместо того, чтобы описывать полосы в длинной и тусклой последовательности, мы используем простую, нерекурсивную грамматику, чтобы представить их организованным способом. Эта грамматика примерно параллельна грамматике файла class:
pack200_segment:
segment_header
*band_headers :BYTE1
cp_bands
attr_definition_bands
ic_bands
class_bands
bc_bands
file_bands
Терминалы этой грамматики являются скалярами и полосами. Чтобы сделать терминалы легче распознать, скалярные имена начинаются со знака фунта "#", и названия группы начинаются со звезды "*". Скаляр является закодированным целым числом (или маленькое постоянное число их), который появляется в пределах заголовка архивного файла. Когда скаляр упоминается в грамматике, он сопровождается двоеточием и кодированием и заключенным в скобки количеством скалярного значения (й). Всякий раз, когда полоса упоминается, она сопровождается двоеточием и его основным кодированием, сопровождаемым комментарием в квадратных скобках, указывающих на его длину. Если полоса кодирует ссылки в некоторую другую структуру данных, такие как постоянный пул, та структура упоминается как комментарий в круглых скобках. Если ссылкам позволяют быть нулем, тот факт упоминается также.
Вот пример:
example_non_terminal:
other_non_terminal
#single_scalar_integer :UNSIGNED5[1]
#four_byte_scalar :BYTE1[4]
*band_of_integers :UNSIGNED5 [#integer_count]
*band_of_method_references :UNSIGNED5 [SUM(*ref_counts)] (cp_Method)
*band_of_strings_and_nulls :UNSIGNED5 [...] (null or cp_String)
Многие из длин полосы являются просто ссылками на предыдущие скаляры (такие как [#class_count]) или суммы предыдущих полос, которые передают количества (например, [SUM(*class_method_count)]). Эти заключенные в скобки длины должны быть расценены как комментарии в грамматике, так как текст спецификации определяет длины полосы устно. Количества полосы, которые не могут быть кратко получены в итоге как иногда определено в частичном выражении, которое содержит замещающий знак.
Иногда мы используем дополнительные грамматические нотации. Мы используем обычные операторы регулярного выражения средства (X | Y), достойные или X или Y, (X)* означает любое число соответствий для X, (X)+ означает одно или более соответствий для X, и (X)? означает или достойный X или ничто. В одном случае, где у полосы может быть несколько экземпляров, выражение (band1) , длина ** (band2) означает, что есть так много экземпляров band1, как есть элементы в band2. Аналогично, в трех случаях, выражение (band1) ** #scalar указывает, что есть нуль или экземпляры band1 согласно значению (нуль или один, соответственно) булева скалярного значения.
pack200_archive:
(pack200_segment)+
Отметьте, что каждый сегмент начинается снова с магического числа Pack200 и номеров версий. (С одним протестом это означает, что архивы Pack200 могут быть связаны с естественным значением объединения архивов, которые они представляют. Как будет замечен ниже, если поле #archive_size не будет присутствовать в каждом заголовке сегмента, оно должно быть вставлено прежде, чем другой сегмент добавляется, так, чтобы декомпрессор мог найти конец каждого сегмента. Формат заголовка сегмента является так, что этой корректировкой, может быть сделан легко.)
Когда объединено с транспортным уровнем потоковой передачи, сегментация обеспечивает путь к компрессору, чтобы уменьшить задержку или уменьшить требования к памяти декомпрессора по стоимости в эффективности компрессора.
Сегментация может также помочь решить масштабирующуюся проблему с очень большими архивами (многих десятков мегабайтов), в котором width индексирует в объединенные глобальные постоянные пулы, может вырасти вне преимуществ глобального постоянного совместного использования. Запуская новый сегмент, компрессор сбрасывает постоянные пулы декомпрессора, убирая бесполезные константы, за счет повторного заявления о константах, которые находятся все еще в использовании. (Компромиссы подобны в разновидности проекту копирования сборщиков "мусора".)
Только магические числа архива (первые четыре байта заголовка сегмента) фиксируются в размере. Все другие структуры архива являются переменными в размере и должны поэтому быть проанализированы последовательно. Вообще говоря, декомпрессоры должны выполнить два, передает по каждому сегменту архива, один, чтобы измерить и проанализировать полосы, и один, чтобы последовательно извлечь информацию из полос в каждый элемент JAR в выводе.
segment_header:
archive_magic archive_header
archive_magic:
#archive_magic_word :BYTE1[4]
archive_header:
#archive_minver :UNSIGNED5[1]
#archive_majver :UNSIGNED5[1]
#archive_options :UNSIGNED5[1]
(archive_file_counts) ** (#have_file_headers)
(archive_special_counts) ** (#have_special_formats)
cp_counts
class_counts
archive_file_counts:
#archive_size_hi :UNSIGNED5[1]
#archive_size_lo :UNSIGNED5[1]
#archive_next_count :UNSIGNED5[1]
#archive_modtime :UNSIGNED5[1]
#file_count :UNSIGNED5[1]
archive_magic_word состоит из четырех байтов 0xCA, 0xFE, 0xD0, 0x0D. #archive_minver должен быть номером 1. #archive_majver должен быть номером 170. Оба из последних двух значений могут быть постепенно увеличены в будущем, чтобы отразить маленькие версии в этом формате файла. Отметьте, что в предыдущих версиях этого стандарта, номера вспомогательной версии и номера основной версии были 7 и 150, или 1 и 160.
Заголовок также содержит начальные количества постоянных записей пула и других "высокоуровневых" объектов. Все эти количества даются в формате UNSIGNED5. Некоторые из этих количеств условно присутствуют, управляемые битами в слове #archive_options. Правило для недостающего значения заголовка (и для отсутствующих значений вообще если иначе не определено) состоит в том, что декомпрессор должен вести себя, как будто он получил явное нулевое значение.
| Бит | Имя | Значение если установлено в #archive_options |
|---|---|---|
| 0 | have_special_formats | archive_special_counts содержит количества |
| 1 | have_cp_numbers | cp_number_counts содержит количества |
| 2 | have_all_code_flags | code_flags_lo содержит элемент для каждого кода |
| 3 | have_cp_extra_counts | cp_extra_counts содержит количества |
| 4 | have_file_headers | archive_file_counts содержит количества |
| 5 | deflate_hint | запросите сжатый файл JAR на все элементы |
| 6 | have_file_modtime | file_modtime содержит modtimes |
| 7 | have_file_options | file_options содержит биты опции |
| 8 | have_file_size_hi | file_size_hi содержит слова размера старшего разряда |
| 9 | have_class_flags_hi | class_flags_hi содержит дополнительные флаги атрибута |
| 10 | have_field_flags_hi | field_flags_hi содержит дополнительные флаги атрибута |
| 11 | have_method_flags_hi | method_flags_hi содержит дополнительные флаги атрибута |
| 12 | have_code_flags_hi | code_flags_hi содержит дополнительные флаги атрибута |
| 13 | (неиспользованный, должен быть нуль), | |
| ... | (неиспользованный, должен быть нуль), | |
| 31 | (неиспользованный, должен быть нуль), |
Если have_special_formats (LSB) будет установлен, полоса, то у archive_special_counts будет два элемента, как определено в грамматике. Иначе у этой полосы будут нулевые элементы. Точно так же, если have_cp_numbers будет установлен, полоса, то у cp_number_counts будет четыре элемента, как определено в грамматике. Иначе у этой полосы будут нулевые элементы. Если have_all_code_flags устанавливается, полоса, code_flags должен содержать один элемент для каждого атрибута Code. Иначе у этой полосы может быть меньше элементов. (Эта опция полезна, когда атрибуты Code богаты податрибутами, возможно потому что JAR содержит большое количество отладочной информации.)
Если have_cp_extra_counts будет установлен, полоса, то cp_extra_counts будет содержать четыре элемента, как определено в грамматике. Иначе у этой полосы будут нулевые элементы. (Флаг может только быть установлен, когда #archive_majver 170 или выше. Эти дополнительные количества соответствуют дополнительным постоянным типам пула, представленным в недавних версиях формата classfile.)
Если have_file_headers будет установлен, полоса, то у archive_file_counts будет пять элементов, как определено в грамматике. Иначе у этой полосы будут нулевые элементы. Если deflate_hint устанавливается, декомпрессор требуют (но не требуется) уменьшать размер его вывода. Например, если это производит файл JAR, это может выкачать элементы JAR. Если опция have_file_modtime (или have_file_options, have_file_size_hi, have_class_flags_hi, have_field_flags_hi, have_method_flags_hi, have_code_flags_hi, соответственно) устанавливается, соответствующая полоса, file_modtime (или file_options, file_size_hi, class_flags_hi, field_flags_hi, method_flags_hi, code_flags_hi, соответственно) может быть непустым, как определено ниже. Иначе у той полосы будут нулевые элементы. Другие биты в опциях архива должны быть нулем и резервируются для будущего использования.
Сразу после того, как слово #archive_options является парой 32-разрядных чисел, которые вместе формируют 64-разрядную длину, которая помогает декомпрессорам легко буферизовать входящие данные до конца сегмента архива, не читая вне сегмента. Значение #archive_size является 64-разрядным значением без знака, составленным из 32-разрядных слов без знака #archive_size_lo и #archive_size_hi, где прежнее значение является младшим разрядом 32-разрядное слово и последнее значение, является старшим разрядом 32-разрядное слово. Значение #archive_size является или нулем или объявляет число байтов в сегменте архива, запускаясь сразу после #archive_size_lo и перед #archive_next_count и заканчиваясь последней полосой, полосой *file_bits. (Таким образом, ненулевой размер включает размер #archive_next_count, *file_bits, и всего промежуточный.) Это значение избыточно, но если ненулевой должно быть правильно предоставлено любым компрессором. Если сегмент архива передается как часть потока, и если другие данные (такие как дополнительные сегменты) следуют за архивом, значение #archive_size не должно быть нулем. Хотя это может быть полностью проигнорировано декомпрессором, это значение может помочь некоторым декомпрессорам буферизовать свои вводы более эффективно.
Сразу после того, как #archive_size является другим значением #archive_next_count, который оценивает число сегментов архива сразу после текущего. Это число не должно быть корректным, и может всегда быть нулем. Это предназначается, чтобы предоставить декомпрессорам подсказку как на сумму остающейся работы распаковки, чтобы сделать. (Такие подсказки обычно выводятся на экран в индикаторах выполнения.)
Если значение #archive_modtime является ненулевым, декомпрессор требуют (но не требуется) скорректировать специфичное для системы время изменения для его вывода. Например, если декомпрессор производит файл JAR, он может назначить дату модификации каждого элемента JAR, или файла JAR непосредственно, к той дате, в отсутствие больше определенного направляющий, такое ненулевое значение file_modtime. Значение #archive_modtime интерпретируется как число секунд начиная с эпохи, используемой System.currentTimeMillis, который является 01.01.1970, GMT 0:00:00. Однако, специальный нуль значения резервируется, чтобы указать на отсутствие любого времени изменения для архива в целом. Декомпрессор может предоставить произвольное значение вместо недостающего времени изменения архива. Если это делается, и если значения file_modtime присутствуют, те значения интерпретируются относительно времени изменения, предоставленного для #archive_modtime компрессором.
Значение #file_count дает число файлов, которые описываются подробно архивом. Отметьте, что файл class, который достаточно прост (столь же описанный ниже) не должен быть описан как файл, потому что это достаточно, что сам class передается. Поэтому, #file_count может быть меньше чем число переданных классов. (Это последнее число вызывают #class_count.) С другой стороны переданные файлы не должны содержать классы, так, чтобы #file_count мог также быть больше чем число классов.
Количество элементов каждого постоянного пула дается в формате UNSIGNED5 в элементах структуры cp_counts заголовка архива:
cp_counts:
#cp_Utf8_count :UNSIGNED5[1]
(cp_number_counts) ** (#have_cp_numbers)
#cp_String_count :UNSIGNED5[1]
#cp_Class_count :UNSIGNED5[1]
#cp_Signature_count :UNSIGNED5[1]
#cp_Descr_count :UNSIGNED5[1]
#cp_Field_count :UNSIGNED5[1]
#cp_Method_count :UNSIGNED5[1]
#cp_Imethod_count :UNSIGNED5[1]
(cp_extra_counts) ** (#have_cp_extra_counts)
cp_number_counts:
#cp_Int_count :UNSIGNED5[1]
#cp_Float_count :UNSIGNED5[1]
#cp_Long_count :UNSIGNED5[1]
#cp_Double_count :UNSIGNED5[1]
cp_extra_counts:
#cp_MethodHandle_count :UNSIGNED5[1]
#cp_MethodType_count :UNSIGNED5[1]
#cp_BootstrapMethod_count :UNSIGNED5[1]
#cp_InvokeDynamic_count :UNSIGNED5[1]
archive_special_counts:
#band_headers_size :UNSIGNED5[1]
#attr_definition_count :UNSIGNED5[1]
class_counts:
#ic_count :UNSIGNED5[1]
#default_class_minver :UNSIGNED5[1]
#default_class_majver :UNSIGNED5[1]
#class_count :UNSIGNED5[1]
Порядок, в котором происходят эти количества, параллелен порядку, в котором сами постоянные пулы передаются в архиве. Этот порядок вызывают порядком определения постоянных пулов. Четыре числовых постоянных пула измеряются cp_number_counts. Они определяют числа, используемые иногда байт-кодами ldc. Поскольку меньшинство классов фактически использует такие байт-коды, размеры являются дополнительными под управлением #have_cp_numbers.
Аналогично, последние четыре постоянных пула измеряются cp_extra_counts. Они определяют информацию о редактировании для инструкции invokedynamic, и определенные типы констант (дескрипторы метода и типы метода). Как с числовыми записями, эти размеры являются дополнительными под управлением #have_cp_extra_counts.
У каждого файла class есть заголовок, который включает магическое число и номера вспомогательной версии и номера основной версии. Магическое число (0xCAFEBABE), будучи фиксированной постоянной, не передается в архиве Pack200. Однако, номера версий, которые могут измениться несколько, должны быть записаны.
В ожидании, что определенные номера версий будут распространены, заголовок архива передает номера основной версии значения по умолчанию и номера вспомогательной версии. Оба из этих чисел даются в формате UNSIGNED5.
Отдельные классы в архиве (как отмечено ниже) могут дополнительно определить свои собственные номера версий в псевдоатрибуте, который переопределяет #default_class_minver и #default_class_majver, данный в заголовке архива.
Количество #band_headers_size дает размер в байтах band_headers. Формат этих байтов, какая справка определяет спецификаторы кодирования полосы для вторичного codings, будет обсужден намного позже в разделе по метакодированию.
Заголовок архива также определяет, что число (#attr_definition_count) типов атрибута, определения class (#class_count), вкладывало объявления class (#ic_count). Эти числа используются, чтобы измерить различные другие полосы, как отмечено в определении тех полос.
Арифметическая сумма всех чисел в cp_counts должна быть меньше чем значение 536870912 (2^29). Компрессору запрещают передать архив, для которого сумма достигает или превышает этот предел. Это ограничение предназначается, чтобы позволить декомпрессорам использовать, внутренне, объединенную нумерацию констант, даже если определенные константы (такие как demangled внутренние имена class или неявные имена SourceFile) должны быть добавлены на лету во время распаковки к постоянному пулу.
Примечание по реализации: archive_header непосредственно содержит 3 числа, в то время как cp_counts содержит по крайней мере 8 чисел, и class_counts содержит точно 4. Поэтому, минимальный размер archive_header составляет 15 байтов, и этому всегда предшествуют на 4 байта archive_magic. Декомпрессор, который хотел избежать любого побочное чтение вперед, мог считать и буферизовать начальный блок 19 байтов, которые будут уверенны, что содержали поля #archive_size. (Это предполагает, что номера версий являются небольшими, как они.) Это могло тогда сразу проанализировать достаточную информацию, чтобы определить, сколько дополнительных байтов буферного накопителя будет обязано сканировать остальную часть архива, по крайней мере до изображений файла ресурсов. К тому времени, когда изображения файла ресурсов в *file_bits должны быть проанализированы, декомпрессор уже считает полосы *file_size, и будет в состоянии удалить любую неопределенность, первоначально существующую в #archive_size. (Если поля #archive_size являются нулем, декомпрессор может быть вынужден читать вслепую до конца всех данных на входном канале, чтобы проанализировать архив.)
Постоянные пулы консолидируют информацию в постоянных пулах всего ввода файлы class. Каждый постоянный пул содержит единственный тип постоянной величины. Каждый из одиннадцати постоянных типов пула, найденных в Java 6 файлов class, помещается в его собственный постоянный пул. Двенадцатый пул содержит подписи, которые в файлах class являются строками UTF8, которые представляют метод, и типы поля, но в архивах Pack200 являются отдельно сжатым типом данных.
Еще три постоянных пула содержат константы, определенные как часть Java 7 форматов classfile (основная версия 51 или позже). Еще один постоянный пул содержит константы, которые будут собраны в атрибут BootstrapMethods, который может быть просмотрен как приложение к classfile постоянному пулу.
Следующая таблица дает шестнадцать предопределенных постоянных пулов в их порядке определения. Это также определяет их корреспонденцию постоянным типам, найденным в Java формат файла class.
| Имя | Элемент файла class | Тег файла class | Цель |
|---|---|---|---|
| cp_Utf8 | CONSTANT_Utf8_info | CONSTANT_Utf8 | основные строковые данные |
| cp_Int | CONSTANT_Integer_info | CONSTANT_Integer | международная константа |
| cp_Float | CONSTANT_Float_info | CONSTANT_Float | константа плавающая |
| cp_Long | CONSTANT_Long_info | CONSTANT_Long | долго постоянный |
| cp_Double | CONSTANT_Double_info | CONSTANT_Double | двойная константа |
| cp_String | CONSTANT_String_info | CONSTANT_String | Строковая константа |
| cp_Class | CONSTANT_Class_info | CONSTANT_Class | Ссылка class |
| cp_Signature | (см. ниже), | (ни один) | метод, поле, или тип переменной |
| cp_Descr | CONSTANT_NameAndType_info | CONSTANT_NameAndType | пара (имя, введите), |
| cp_Field | CONSTANT_Fieldref_info | CONSTANT_Fieldref | полевая ссылка |
| cp_Method | CONSTANT_Methodref_info | CONSTANT_Methodref | вызов метода |
| cp_Imethod | CONSTANT_InterfaceMethodref_info | CONSTANT_InterfaceMethodref | вызов интерфейса |
| cp_MethodHandle | CONSTANT_MethodHandle_info | CONSTANT_MethodHandle | постоянный дескриптор метода |
| cp_MethodType | CONSTANT_MethodType_info | CONSTANT_MethodType | постоянный тип метода |
| cp_BootstrapMethod | BootstrapMethods_attribute.bootstrap_methods [я] | (ни один; приставной стол к постоянному пулу) | спецификатор метода начальной загрузки |
| cp_InvokeDynamic | CONSTANT_InvokeDynamic_info | CONSTANT_InvokeDynamic | вызов invokedynamic |
(Отметьте, что порядок определения на эти постоянные пулы подобен числовому упорядочиванию соответствующего тега файла class. Например, CONSTANT_Utf8 является первым тегом, и cp_Utf8 является первым постоянным пулом в порядке определения. Однако, подробно есть различия. В частности отметьте, что cp_String прибывает прежде cp_Class, даже при том, что соответствующие теги файла class находятся в обратном порядке.)
Каждый постоянный пул является логически рядом символьных или числовых значений, всего одного типа. В архиве Pack200 это структурируется как последовательность таких значений, каждого с уникальным индексом в пределах последовательности. В другом месте в архиве, всякий раз, когда константа должна быть упомянута, индексировала в пределах соответствующего постоянного пула (или в пределах подмножества пула, или в пределах группы пулов) дается.
В отличие от формата файла class, постоянная индексация пула в формате архива Pack200 запускается в нуле. В редких местах, где нулевые ссылки ожидаются, документируется возможность, и сами нулевые ссылки кодируются нулем, индексируют, в то время как все другой индексировать значения постепенно увеличиваются одним. Где нулевые ссылки не ожидаются, они могут все еще быть закодированы 32-разрядным, индексируют значение-1.
Также в отличие от файлов class, нет никаких "разрывов", или неиспользованный индексирует связанный с длинными или двойными значениями. Иногда, мы обратимся формально к элементу постоянного пула при использовании нотации массива. Например, первыми тремя целыми числами в cp_Int, постоянным пулом является cp_Int[0], cp_Int[1], и cp_Int[2], и последнее целое число, является cp_Int[cp_Int_count-1]. Отметьте, что обе полосы и постоянные пулы обрабатываются в этой спецификации как массивы с нулевым источником.
Это недопустимо для компрессора, чтобы передать ту же самую константу дважды. Таким образом, все постоянные записи пула должны быть уникальными.
В файле class, за немногим исключением, постоянные ссылки пула со строгим контролем типов, в той каждой ссылке или нуль или обращается к постоянной записи пула фиксированного тега, связанного с контекстом ссылки. Исключения являются атрибутами ConstantValue и полями операнда ldc, ldc_w, и инструкций ldc2_w.
Однако, потому что постоянные пулы в архиве Pack200 отдельно индексируются, все постоянные ссылки должны быть со строгим контролем типов, так, чтобы был только один постоянный пул (или подмножество пула), в который любой данный индексирует, применяется. Это выполняется любой, выводя постоянный тип из контекста (в случае атрибутов ConstantValue) или добавляя дополнительную информацию к контексту ссылки. (В потоке байт-кода ldc разделяется постоянным типом в отличные инструкции sldc, ildc, и т.д.),
Расположение постоянных полос пула в архиве следует за порядком определения постоянных пулов непосредственно. Каждый постоянный пул представляется в свою очередь последовательностью одной или более полос. Последовательность постоянных полос пула поэтому структурируется следующим образом:
cp_bands:
cp_Utf8
*cp_Int :UDELTA5 [#cp_Int_count]
*cp_Float :UDELTA5 [#cp_Float_count]
cp_Long
cp_Double
*cp_String :UDELTA5 [#cp_String_count] (cp_Utf8)
*cp_Class :UDELTA5 [#cp_Class_count] (cp_Utf8)
cp_Signature
cp_Descr
cp_Field
cp_Method
cp_Imethod
cp_MethodHandle
*cp_MethodType :UDELTA5 [#cp_MethodType_count] (cp_Signature)
cp_BootstrapMethod
cp_InvokeDynamic
Как может быть замечен здесь, постоянные пулы, записи которых могут быть получены из единственного 32-разрядного целого числа или единственной ссылки, представляются как единственные полосы. Другие постоянные пулы представляются как группы полос. Каждый постоянный пул дает свое имя к соответствующему элементу грамматики. Производство cp_bands объявляет порядок каждой полосы или группу полос, которая передает константы в eponymous постоянном пуле.
Отметьте использование UDELTA5 как основные кодировки для нескольких полос. Хотя формат файла Pack200 не требует никакого определенного упорядочивания значений в постоянных пулах, обычно выгодно упорядочить их так, чтобы закодированные значения в полосах, используя UDELTA5 монотонно увеличились. (Отрицательные дельты могут быть закодированы, хотя дорого, UDELTA5. Кроме того, подписанное вторичное кодирование может быть выбрано компрессором вместо UDELTA5.) Выбор основных кодировок в этой спецификации отражает ожидание, что высококачественные компрессоры, когда подарено выбор выходных упорядочиваний, сделают выбор, который приводит к хорошему использованию основных кодировок полосы.
В нескольких случаях несколько из шестнадцати постоянных пулов объединяются в группу, так, чтобы индексировал, может быть сформирован, чтобы обратиться к элементам группы в целом. Такая группа полностью определяется ее составляющими постоянными пулами. Индексирование в постоянную группу пула всегда последовательно формируется с полным порядком составляющих постоянных пулов, так же как с внутренним порядком каждого пула. Например, если группа, cp_ABC формируется из трех пулов cp_A, cp_B, и cp_C размеров COUNT(cp_A), COUNT(cp_B), и COUNT(cp_C), соответственно, то группа индексирует, выбирает из одного из трех пулов в зависимости от того, является ли это в диапазоне 0 .. COUNT(cp_A)-1, COUNT(cp_A) .. COUNT(cp_A)+COUNT(cp_B)-1, или COUNT(cp_A)+COUNT(cp_B) .. COUNT(cp_ABC)-1, соответственно. Размер группы пула является, конечно, суммой составляющих пулов.
В некоторых других случаях подмножества постоянных пулов индексируются сокращенным способом. Индексирование в постоянное подмножество пула всегда последовательно формируется с порядком пула непосредственно. Например, индексировать 0 всегда обращается к первому элементу подмножества, индексировать 1 обращается к второму и так далее.
Вот определения групп пула, используемых в этой спецификации.
| Имя | Составляющие | Цель |
|---|---|---|
| cp_All | (все шестнадцать пулов) | универсальные ссылки |
| cp_LoadableValue | cp_Int, cp_Float, cp_Long, cp_Double, cp_String, cp_Class, cp_MethodHandle, cp_MethodType | Операнд qldc, параметр метода начальной загрузки |
| cp_AnyMember | cp_Field, cp_Method, cp_Imethod | get или операнд invoke, компонент дескриптора метода |
Значения в cp_Int постоянный пул непосредственно представляются значениями, закодированными в его полосе. Значения в cp_Float постоянный пул получаются как будто, применяя java.lang.Float.intBitsToFloat к 32-разрядным значениям, закодированным в его полосе.
64-разрядные значения полосы cp_Long получаются, примыкая, как высокие и низкие слова, соответствующие 32-разрядные значения от этих двух полос cp_Long_hi и cp_Long_lo. (Они содержат высокие и низкие слова, соответственно.) Аналогично, значения полосы cp_Double получаются первыми смежными высокими и низкими словами из двух других полос, и затем перепечатыванием получающихся 64-разрядных целых чисел как будто, применяя java.lang.Double.longBitsToDouble. Высокие и низкие слова находятся в полосах cp_Double_hi и cp_Double_lo, соответственно.
cp_Long:
*cp_Long_hi :UDELTA5 [#cp_Long_count]
*cp_Long_lo :DELTA5 [#cp_Long_count]
cp_Double:
*cp_Double_hi :UDELTA5 [#cp_Double_count]
*cp_Double_lo :DELTA5 [#cp_Double_count]
Когда значения с плавающей точкой в конечном счете пишутся файлам class, их биты должны быть точно сохранены, как будто они были обработаны java.lang.Float.floatToRawIntBits или java.lang.Double.doubleToRawLongBits. Таким образом значения "НЭН" передаются искренне без нормализации.
(Отметьте: Хотя было бы возможно расширить кодирующие полосу методы Pack200, чтобы закодировать 64-разрядные значения непосредственно, этот формат файла всегда передает 64-разрядные значения как пар 32-разрядных значений, переданных в парах полос. Это упрощает реализации, позволяя им обработать данные полосы с 32-разрядными информационными каналами.)
Каждая строка в cp_String постоянный пул представляется в его полосе ссылкой на написание строки как постоянный cp_Utf8.
Аналогично, каждый class в cp_Class постоянный пул представляется в его полосе ссылкой на написание class как постоянный cp_Utf8. (Как в файле class и VM, написание использует символ наклонной черты, чтобы разграничить компоненты префикса пакета.)
Если cp_Utf8 не пуст, его первое значение всегда является пустой строкой. Таким образом пустой строке всегда дают индексирование нуля. Никакие значения полосы не передаются, чтобы представить эту пустую строку. (Значения в полосах cp_Utf8_prefix и cp_Utf8_suffix принадлежат строкам после пустой строки в cp_Utf8.), Поскольку константы не могут быть дублированы, все другие элементы cp_Utf8 содержат по крайней мере один символ.
Каждая строка в cp_Utf8 постоянный пул представляется в архивном файле в двух частях, префиксе и суффиксе. Суффикс представляется и количеством и последовательностью символьных кодов. Префикс представляется только количеством; символы префикса дублируются от предыдущей строки. Этот метод позволяет компрессор (если это выбирает) представлять строки посредством их последовательных различий. Первое суффиксное значение и первые два префиксных значения подавляются в переданном архиве. Значения, если передано, всегда были бы нулем, так как первая строка cp_Utf8 всегда пуста, и вторая строка никогда не может совместно использовать непустой префикс с первой строкой.
Каждый суффикс передается точно одним из двух способов как маленький суффикс или большой суффикс. Маленькие суффиксы передаются рядом в одной большой полосе. Большие суффиксы редки; они предназначаются как способ сжато передать строки с необычной статистикой, такие как строки, которые являются действительно таблицами числовых данных. Каждый большой суффикс передается в его собственной полосе. Это позволяет компрессору опцию, чтобы выбрать эффективно специализированное вторичное кодирование для символов в каждой большой, необычной строке.
cp_Utf8:
*cp_Utf8_prefix :DELTA5 [MAX(0,#cp_Utf8_count-2)]
*cp_Utf8_suffix :UNSIGNED5 [MAX(0,#cp_Utf8_count-1)]
*cp_Utf8_chars :CHAR3 [SUM( *cp_Utf8_suffix )]
*cp_Utf8_big_suffix :DELTA5 [COUNT(0, *cp_Utf8_suffix )]
(*cp_Utf8_big_chars :DELTA5)
** length(cp_Utf8_big_suffix) [SUM( *cp_Utf8_big_suffix )]
(Отметьте: Это полезно, но не требуемое этой спецификацией, чтобы упорядочить строки лексикографически и найти максимальные общие префиксы между смежными строками. Допустимо проигнорировать функцию совместного использования префикса и объявить, что все префиксы нуль.) Полоса cp_Utf8_suffix содержит меньше чем элементы #cp_Utf8_count. Это определяет, в порядке, маленькой суффиксной длине каждой постоянной строки пула (кроме неявной первой строки, которая пуста). Полоса cp_Utf8_prefix содержит два меньше чем элементы #cp_Utf8_count. Это определяет, в порядке, длине префикса каждой постоянной строки пула (кроме первых двух строк, у которых всегда есть нулевые длины префикса). Длина префикса кодирует длину префиксной подстроки, совместно использованной и cp_Utf8[i-1] и cp_Utf8[i]. Если есть меньше чем три строки в cp_Utf8, то cp_Utf8_prefix пуст. Длина префикса обычно является значительной долей (иногда половина) полной длины.
Каждое значение в полосе cp_Utf8_chars является 16-разрядным числом, выражающим символ Java. Эта полоса содержит символы всех маленьких суффиксов в порядке. Для каждой последовательной строки cp_Utf8_chars содержит дополнительное выполнение значений, кодирующих символы его маленького суффикса, если любой. Поэтому, полная длина этой полосы является суммой всех значений в полосе cp_Utf8_suffix.
Всякий раз, когда маленькая суффиксная длина для постоянной записи пула является нулем, у строки нет никакого маленького суффикса, но большого суффикса вместо этого. Длина каждого большого суффикса дается элементом полосы cp_Utf8_big_suffix. (Поэтому, длина этой полосы является точно количеством нулевых значений в полосе cp_Utf8_suffix.) Каждый большой суффикс передается как отдельная полоса 16-разрядных символьных значений, один элемент полосы на символ. Есть одна такая полоса на большой суффикс. Эти полосы сразу следуют за полосой cp_Utf8_big_suffix, и все вместе вызываются полосами cp_Utf8_big_chars. Хотя обычно данные того же самого типа собираются в единственную полосу, эти строки помещаются в отдельные полосы так, чтобы они могли быть независимо закодированы. Эти строки обычно кодируют массивы двоичных данных, а не истинные символы Java.
У большого суффикса может быть длина нуля, что означает, что постоянная запись пула является непустым префиксом предыдущей строки. В таком случае соответствующая суффиксная полоса не займет места в архивном файле, так как полосы нулевой длины не занимают байтов вообще.
Пожалуйста, см. раздел Приложения для псевдокода, объясняя это понятие.
Константы подписи являются особенными в этом, они могут содержать встроенные ссылки на константы cp_Class. Постоянная подпись эквивалентна константе Utf8, как только встроенные ссылки class расширяются в их написания. Константы подписи достаточно гибки, чтобы представить произвольные строки, но предназначаются для строк, которые часто содержат имена class после эля прописной буквы 'L'. Они включают поле, метод, и типы локальных переменных, и универсальные атрибуты Signature.
Каждая строка подписи анализируется в форму и последовательность нуля или большего количества ссылок class. Ссылки class получаются, располагаясь в исходной строке подписи все последовательности, которые соответствуют образец "имя класса L", удаляя часть имени класса, и обрабатывая ее как ссылка в cp_Class постоянный пул. Форма определяется как остаток после того, как имена class были удалены из исходной строки.
Форме не позволяют содержать возникновения эля буквы ('L') кроме тех, которые отмечают удаленные имена class.
Таким образом форма будет содержать символьный 'L' везде, где исходная строка типа обращается к class. Считая число этих символов в форме, декомпрессор может вывести число классов, к которым обращается исходная строка типа. Это число вызывают длиной class формы.
Отметьте, что константы cp_Class не обязаны обращаться к существующим классам, и при этом они даже не требуются иметь допустимые написания имени class. Поэтому, у компрессора есть значительная широта в выборе, который называет class (если любой), это извлечет из строк подписи. В крайнем случае компрессор может сделать каждую форму идентичной ее соответствующей строке подписи, и просто удовлетворить ее длину class, испуская ссылки на фиктивный class с пустым названием. (Эта длина class должна была бы включать любые возникновения 'L' на имена class непосредственно.)
Отметьте также, что эти правила кодирования не требуют, чтобы имя class сопровождалось любым определенным символом, хотя это обычно будет точка с запятой, или возможно левая угловая скобка, в случае экземпляра универсального типа в атрибуте Signature.
Правила также позволяют компрессору решать, произвольно, сколько символов (если кто-либо) после каждого эля буквы 'L' будет передан как часть имени class. Поэтому, данная строка подписи может быть представимой несколькими формами, любая из которых декомпрессор должен быть подготовлен обработать.
Вот некоторые примеры:
| Введите Строку Подписи | Форма | Класс Лен. |
Класс... |
|---|---|---|---|
| F | F | 0 | |
| [Z | [Z | 0 | |
| [[[LLL; | [[[L; | 1 | LL |
| [[[LLL; | [[[LLL; | 3 | (empty), (empty), (empty) |
| ([Ljava/lang/String;)V | ([L;)V | 1 | java/lang/String |
| Ljava/util/List<Lpkg/Item;>; | L<L;>; | 2 | java/util/List, pkg/Item |
| (Ljava/lang/String;II)Lpkg/Item; | (L;II)L; | 2 | java/lang/String, pkg/Item |
| Ljava/util/List<Ljava/lang/Byte;>; | L<L;>; | 2 | java/util/List, java/lang/Byte |
| <ELEM:>(Ljava/util/List<TELEM;>;)TELEM; | <EL:>(L<TEL;>;)TEL; | 1 | EM, java/util/List, EM, EM |
| ALLOWABLE | ALLOWABLE | 3 | (empty), (empty), (empty) |
| ALLOWABLE | AL | 1 | LOWABLE |
| ALLOWABLE | ALABL | 2 | LOW, E |
Формы всех строк в cp_Signature постоянный пул даются в порядке в полосе cp_Signature_form как одна ссылка cp_Utf8 на строку подписи. Для каждой формы class последовательность длиной классов, требуемых воссоздавать строку подписи, передается как выполнение ссылок cp_Class в полосе cp_Signature_classes. Как следствие этих определений длина полосы cp_Signature_classes является общим количеством эля буквы возникновения 'L' в последовательности написаний форм, упомянутых в cp_Signature_form.
cp_Signature:
*cp_Signature_form :DELTA5 [#cp_Signature_count](cp_Utf8)
*cp_Signature_classes :UDELTA5 [COUNT('L',...)] (cp_Class)
Пожалуйста, см. раздел Приложения для псевдокода, объясняя это понятие.
Аналогично, каждый cp_Field, cp_Method, или постоянный cp_Imethod являются упорядоченной парой class (представленный как ссылка cp_Class) и дескриптор имени-и-типа (представленный как ссылка cp_Descr). Снова, эти ссылки передаются в соответствующих элементах связанных полос.
cp_Descr:
*cp_Descr_name :DELTA5 [#cp_Descr_count] (cp_Utf8)
*cp_Descr_type :UDELTA5 [#cp_Descr_count] (cp_Signature)
cp_Field:
*cp_Field_class :DELTA5 [#cp_Field_count] (cp_Class)
*cp_Field_desc :UDELTA5 [#cp_Field_count] (cp_Descr)
cp_Method:
*cp_Method_class :DELTA5 [#cp_Method_count] (cp_Class)
*cp_Method_desc :UDELTA5 [#cp_Method_count] (cp_Descr)
cp_Imethod:
*cp_Imethod_class :DELTA5 [#cp_Imethod_count] (cp_Class)
*cp_Imethod_desc :UDELTA5 [#cp_Imethod_count] (cp_Descr)
cp_MethodHandle:
*cp_MethodHandle_refkind :DELTA5 [#cp_MethodHandle_count]
*cp_MethodHandle_member :UDELTA5 [#cp_MethodHandle_count] (cp_AnyMember)
cp_BootstrapMethod:
*cp_BootstrapMethod_ref :DELTA5 [#cp_BootstrapMethod_count] (cp_MethodHandle)
*cp_BootstrapMethod_arg_count :UDELTA5 [#cp_BootstrapMethod_count]
*cp_BootstrapMethod_arg :DELTA5 [SUM(*BootstrapMethod_arg_count)] (cp_LoadableValue)
cp_InvokeDynamic:
*cp_InvokeDynamic_spec :DELTA5 [#cp_InvokeDynamic_count] (cp_BootstrapMethod)
*cp_InvokeDynamic_descr :UDELTA5 [#cp_InvokeDynamic_count] (cp_Descr)
Файл class, содержание которого сжимается Pack200, отмечается как "тупик" со специальным битом опции. У файла тупика class, как должны объявлять, есть длина нуля. У этого, как могут объявлять, есть пустая строка для ее имени. Если есть недостаточно многие файлы тупика class, переданные, чтобы соответствовать с числом переданных классов, декомпрессор должен действовать, как будто компрессор передал дополнительную серию тривиальных тупиков без имени или содержания, и время изменения и подсказка дефляции, скопированная с заголовка архива.
Каждый файл ресурсов передается в архиве Pack200 как простое изображение bytewise под относительным путем, используя наклонную черту '/' как разделитель каталога. (Это - то же самое соглашение пути, как используется в архивах ZIP.) Каждый файл (оба файла ресурсов и файлы class) может дополнительно быть связан с подсказкой дефляции и датой модификации.
file_bands:
*file_name :UNSIGNED5 [#file_count] (cp_Utf8)
*file_size_hi :UNSIGNED5 [#file_count*(#have_file_size_hi)]
*file_size_lo :UNSIGNED5 [#file_count]
*file_modtime :DELTA5 [#file_count*(#have_file_modtime)]
*file_options :UNSIGNED5 [#file_count*(#have_file_options)]
*file_bits :BYTE1 [SUM(*file_size)]
Нет никаких дополнительных атрибутов файла, таких как комментарии, дополнительные атрибуты, или значения CRC. Приложение, которое требует таких атрибутов на некоторых файлах, может закодировать те файлы в соответствующий формат архивного файла (такие как ZIP), и передать те архивы как файлы ресурсов в архиве Pack200.
Каждое имя файла передается как элемент полосы file_name, и каждая длина (в байтах) передается в соответствующих элементах полосы file_size_lo и (если есть) полосы file_size_hi. Все три полосы имеют длину #file_count, за исключением того, что у file_size_hi есть нулевые элементы, если бит have_file_size_hi в #archive_options является четким.
Длина в байтах каждого файла является соответствующим 32-разрядным значением без знака, принятым от полосы file_size_lo, если полоса file_size_hi пуста. Иначе, длина файла является 64-разрядным значением без знака, составленным из corresonding 32-разрядных элементов без знака file_size_lo и полос file_size_hi, где прежнее значение является младшим разрядом, 32-разрядное слово и последнее значение являются старшим разрядом 32-разрядное слово.
Байты всего non-class (то есть, ресурс) файлы сразу следуют в полосе file_bits. Каждый файл дается как соответствующее выполнение значений байта.
Дополнительная полоса file_modtime, если не пустой, предоставляет время изменения для каждого файла ресурсов (и потенциально для файлов class, если тупики файла class присутствуют). Каждое целочисленное значение дает различие (в секундах) от значения #archive_modtime. (Поэтому, если значение #archive_modtime является нулем, отдельные времена файла должны быть интерпретированы как абсолютные значения.) Порядок передачи file_modtime является непротиворечивым с file_name. Эта полоса пуста, если бит have_file_modtime в #archive_options является четким.
Дополнительная полоса file_options, если не пустой, предоставляет флаговые биты для каждого файла ресурсов (и потенциально для файлов class, если тупики файла class присутствуют). Эта полоса пуста, если бит have_file_options в #archive_options является четким. Каждое слово file_options интерпретируется поразрядное. Определенным битам дают символьные имена следующим образом, где LSB нумеруется как разрядный нуль:
| Бит | Имя | Цель |
|---|---|---|
| 0 | deflate_hint | запросите сжатый элемент файла JAR |
| 1 | is_class_stub | этот файл содержит байт-коды class |
Если deflate_hint (LSB) устанавливается, декомпрессор требуют (но не требуется) уменьшать размер его вывода. Например, если это производит файл JAR, это может выкачать элементы JAR. Так как бит deflate_hint в слове #archive_options имеет тот же самый эффект, два бита в действительности объединяются с логическим ИЛИ для каждого файла. Если is_class_stub (второй LSB) устанавливается, это описание файла ресурсов является фактически тупиком, и содержание файла определяется как байт-коды одного из классов, определенных в архиве Pack200. Другие биты в опциях файла должны быть нулем и резервируются для будущего использования.
Если переданный файл отмечается как тупик class, его содержание должно быть передано, как будто файл был пуст. (Таким образом, file_size_hi и file_size_lo должны и быть нулем, и в file_bits, возможно, нет никаких соответствующих байтов.) Декомпрессор обязан предоставлять содержание для файла ресурсов, воссоздавая содержание файла class для class, переданного в class_this и т.д. Как любой другой файл ресурсов, тупику class позволяют иметь имя, время изменения и deflate_hint.
Тупики class и классы соответствуют в порядке. Определите полученный параметр #class_stub_count как число файлов, отмеченных как тупики class. (Это - также количество набора битов is_class_stub в file_options.) Затем #class_stub_count должен быть не больше чем #class_count. Первый тупик class определяет файл, который получает байт-коды для первого class и так далее. Хотя у тупика class есть имя (переданный в file_name), это имя может быть пустой строкой. В этом случае декомпрессор обязан использовать стандартное имя для файла class, который создается из имени байт-кода class (использующий наклонную черту '/' для разделителя пакета), добавляя строку ".class". (Таким образом у classfile может быть произвольное нестандартное имя, но работы сжатия лучше всего, если его имя получается из его class обычным способом.)
Если #class_count больше чем #class_stub_count, то декомпрессор должен вести себя, как будто достаточное число тривиальных дополнительных тупиков class было передано после последнего явного файла. У этих тривиальных тупиков есть строка пустого названия и нулевой deflate_hint или file_modtime.
Таким образом, в простом случае, где нет никаких тупиков class вообще (возможно, потому что have_file_options является нулем), декомпрессор должен произвести свои файлы в их порядке передачи, сопровождаемом порядком передачи классов. У каждого файла class должно быть свое стандартное имя, и время изменения и подсказка дефляции, наследованная от #archive_modtime и бита deflate_hint в #archive_options. Но за счет дополнительного размера передачи, компрессор может направить декомпрессор, чтобы представить ресурсы и файлы class в любом фиксированном порядке, с произвольными именами, время изменения, и подсказки дефляции для каждого выходного файла. Декомпрессор должен соблюдать это упорядочивание, если его вывод находится в форме (такой как архив JAR), где порядок является существенным.
Компрессоры свободны, если иначе не направлено, выбрать любое упорядочивание файлов. Часто выгодно поместить файлы с подобной статистикой друг рядом с другом, так, чтобы компрессор постпередачи (если кто-либо) мог обработать их содержание вместе (в том же самом окне, в случае ВЫКАЧИВАТЬ алгоритма). Вероятно, что у компрессора, который в состоянии переупорядочить его входные файлы для эффективной передачи, будет опция команды, которая вынуждает это сохранить порядок, в котором были представлены входные файлы, потому что этот порядок является существенным некоторым (но не все) приложения развертывания.
Компрессоры свободны передать файлы class, как будто они были файлами ресурсов. Это обеспечивает способ передать файлы class, которые должны быть сохранены поразрядно, или которые компрессоры не могут передать сжатый с достаточной точностью. Декомпрессоры обязаны принимать файлы class, переданные "поразрядный" как файлы ресурсов.
Отметьте: полосы, управляющие файлами и их атрибутами, передаются последние в архиве, чтобы ослабить реализацию декомпрессора немного, так как последняя вещь, которую делает декомпрессор, состоит в том, чтобы собрать выходные файлы. В частности файлы ресурсов могут иметь произвольный размер, и размещение их битов в конце архива позволяет декомпрессору избегать выделять временное хранение для них.
Пять наборов полос флага переносят биты модификатора и/или приписывают биты управления. Полоса ic_flags переносит биты модификатора для вложенных классов. Кроме того, модификатор и биты управления атрибута переносят class_flags_lo, field_flags_lo, method_flags_lo, и code_flags_lo, и четыре соответствующих дополнительных высоких полосы слова, class_flags_hi, field_flags_hi, method_flags_hi, и code_flags_hi. (Нет никакого высокого слова для ic_flags.) Каждое значение в этих полосах интерпретируется как 32-разрядное двоичное число без знака. Каждый бит в этих полосах независимо определяет присутствие модификатора доступа Java (такого как ACC_PRIVATE), или class, поля, метода, или атрибута кода (такого как Deprecated или SourceFile), или некоторой другой необходимой управляющей информации (такой как, есть ли у файла class номер версии не по умолчанию).
У каждого class (resp. поле, метод, атрибут Code) есть соответствующее значение флагов до 63 битов, переданных в class_flags_lo (resp., field_flags_lo, method_flags_lo, code_flags_lo) и дополнительно в class_flags_hi (resp., field_flags_hi, method_flags_hi, code_flags_hi). Эти значения флагов, собранные в 64-разрядные числа, называют class_flags (resp., field_flags, method_flags, code_flags). За исключением атрибутов Code, каждый из низких шестнадцати флаговых битов может использоваться, чтобы передать флаги доступа. Высокие шестнадцать битов (или сорок семь, если дополнительное высокое слово передается) используются, чтобы указать на присутствие атрибутов, или предопределенных или определенных с помощью компрессора. Шестьдесят четвертая позиция двоичного разряда значения флагов (если передано) резервируется и должна быть нулем.
Значение флагов для атрибута Code является дополнительным и взято, чтобы быть нулем, отсутствуя. У атрибута Code есть соответствующее значение флагов, переданное, если и только если или бит have_all_code_flags в #archive_options устанавливается, или иначе у элемента code_headers, соответствующего атрибуту Code, есть специальный нуль значения. (См. обсуждение заголовков кода ниже.)
Для классов, вложенных классов, полей, и методов, присвоение позиций флагового бита к модификаторам является тем же самым как этим в формате файла class. (Например, LSB всегда представляет ACC_PUBLIC, и в архиве Pack200 и в форматах файлов class.) Атрибут переполнения является атрибутом, присутствие которого не обозначается непосредственно через флаговый бит, и но вместо этого обозначается возникновением индексировать в отдельной полосе. Для классов, полей, методов, и кодов, бит 16 (как установлено в маске 0x0001000) указывает на присутствие атрибутов переполнения. Для вложенных классов флаговый бит 16 указывает на присутствие явного внешнего class и полей имени, как объяснено ниже.
| Бит | Значение |
|---|---|
| 0 | ACC_PUBLIC |
| 1 | ACC_PRIVATE |
| 2 | ACC_PROTECTED |
| 3 | ACC_STATIC |
| 4 | ACC_FINAL |
| 5 | ACC_SYNCHRONIZED (ACC_SUPER) |
| 6 | ACC_VOLATILE (ACC_BRIDGE *) |
| 7 | ACC_TRANSIENT (ACC_VARARGS *) |
| 8 | ACC_NATIVE |
| 9 | ACC_INTERFACE |
| 10 | ACC_ABSTRACT |
| 11 | ACC_STRICT |
| 12 | ACC_SYNTHETIC* |
| 13 | ACC_ANNOTATION* |
| 14 | ACC_ENUM* |
| 16 | переполнение (больше данных полосы в другом месте) |
Модификаторы, отмеченные со звездой (*), в новинку для недавних версий Java. Они присутствуют здесь для информации только, и не являются частью спецификации Pack200.
В частности младший разряд 16 битов class, поля, и флагов метода видимы в файле class, и могут таким образом перенести биты модификатора. Ни один из битов слова флагов кода не видим в файле class; эти флаговые биты используются только для податрибутов кода.
В отличие от этого, младший разряд, 16 битов вложенных записей class используются исключительно для модификаторов, начиная с вложенных записей class, не содержит атрибуты. В остальной части этого раздела по атрибутам мы игнорируем слова флага, связанные с вложенными записями class.
Любая из этих 63 позиций двоичного разряда в значении флагов может быть присвоена компрессором указать к декомпрессору на присутствие некоторого определенного атрибута. Компрессор может "принять" бит модификатора, присваивая это определение атрибута. (Это делается, испуская определение для атрибута, который упоминает ту позицию двоичного разряда.)
Если компрессор "вступает во владение" немного (модификатор или не), который используется по умолчанию в другой цели, бит теряет свое предыдущее значение. Однако, компрессор, возможно, не испускает явное определение для того же самого бита дважды (в том же самом контексте).
Каждый вид атрибута определяется четырьмя сведениями: объект, к которому это применяется (class, поле, метод, или код), позиция двоичного разряда, если таковые вообще имеются, которому это присваивается, имя атрибута (как это появляется в файле class), и расположение атрибута (который позволяет декомпрессору должным образом форматировать возникновения атрибута в файле class). Это - ошибка для компрессора, чтобы определить то же самое имя и расположение дважды в том же самом контексте. Это не ошибка повторить имя с различным расположением, или расположением с другим именем.
Первые два элемента закодированы битом в однобайтовый "заголовок", и переданы в полосе attr_definition_headers. Последние два элемента передаются как ссылки cp_Utf8 в соответствующих элементах attr_definition_name и attr_definition_layout. Таким образом есть три полосы, которыми компрессор объявляет типы атрибута к декомпрессору, и каждая полоса имеет длину #attr_definition_count.
attr_definition_bands:
*attr_definition_headers :BYTE1 [#attr_definition_count]
*attr_definition_name :UNSIGNED5 [#attr_definition_count] (cp_Utf8)
*attr_definition_layout :UNSIGNED5 [#attr_definition_count] (cp_Utf8)
Младшие значащие два бита байта заголовка определения атрибута обрабатываются как поле без знака, и дают тип контекста атрибута, который является типом объекта, к которому применяется атрибут:
| (h & 0x03) | Тип контекста |
|---|---|
| 0 | атрибут применяется к классам |
| 1 | атрибут применяется к полям |
| 2 | атрибут применяется к методам |
| 3 | атрибут применяется к атрибутам Кода |
Старшие значащие шесть битов байта заголовка определения атрибута обрабатываются как поле без знака, и дают дополнительную позицию двоичного разряда, которой атрибут присваивается в слове флагов.
| (h >> 2) | Присвоение Флагового бита |
|---|---|
| 0 | переполните атрибута, не присвоенного любому биту |
| 1 | атрибут, присвоенный биту 0 (LSB lo слова) |
| 2 | атрибут, присвоенный биту 1 |
| 3 | атрибут, присвоенный биту 2 |
| ... | |
| 32 | атрибут, присвоенный биту 31 (MSB lo слова) |
| 33 | атрибут, присвоенный биту 32 (LSB привет слова) |
| ... | |
| 63 | атрибут, присвоенный биту 62 |
| (никакое значение) | бит 63 должен быть нулем (MSB привет слова) |
У каждого атрибута class, предопределенный ли в этой спецификации или явно определенный компрессором, есть уникальное число, названное его атрибутом, индексируют. Если атрибут присваивается флаговый бит, то его атрибут индексирует, идентично позиции флагового бита (число в [0.. 62]). (Все предопределенные атрибуты присваиваются флаговый бит по умолчанию.)
Если атрибут class не присваивается флаговый бит, это - атрибут переполнения, и индексировать присваивается последовательно в порядке, в котором атрибуты class определяются (то есть, передаются). Первые индексируют, чтобы быть присвоенными, последовательно таким образом 32, если #have_class_flags_hi является четким, и 63, если он устанавливается. Они индексируют, используются в пределах архива, чтобы объявить возникновения атрибута для отдельных классов.
Аналогично, поле, метод, и атрибуты кода присваиваются, их собственный атрибут индексирует, независимо от атрибутов class и друг друга. Поэтому, атрибут (то есть, имя и пара расположения) уникально определяется в пределах архива его типом контекста, и атрибут индексируют. Поле и атрибуты метода могут быть присвоены флаговым битам, или иначе они - атрибуты переполнения с, индексирует 32 или больше. Как другие атрибуты, атрибуты кода могут быть присвоены явные числа или неявно присвоены, индексирует запуск с 32. (Как с атрибутами class, если высокие полосы слова флага выбираются соответствующим битом #archive_options, то поле, метод, или кодируют атрибуты переполнения, имеют, индексирует 63 или больше.)
Некоторые атрибуты предопределяются, и не требуют, чтобы компрессор испустил определения для них. Они неявно определили разметки и присвоения флагового бита (то есть, индексирует).
Атрибут индексирует, меньше чем 63 применимы во всех случаях, но они могут конфликтовать с присвоенными предопределенным атрибутам, включая предопределенные определенные атрибуты (в диапазоне 16 - 62) в будущих расширениях формата Pack200. В существующей версии все предопределенные атрибуты имеют, индексирует в диапазоне [17.. 31], так, чтобы флаги модификатора не были приняты по умолчанию, и высоко отметили слова, не должны обычно использоваться.
Здесь имена и индексируют присвоения предопределенных атрибутов. (Предопределенные разметки даются ниже.)
| Индексировать | Тип контекста | Имя |
|---|---|---|
| 16 | C, F, М. | (переполните атрибутов), |
| 17 | Класс | SourceFile |
| 18 | Класс | EnclosingMethod |
| 19 | C, F, М. | Подпись |
| 20 | C, F, М. | Устаревшие |
| 21 | C, F, М. | RuntimeVisibleAnnotations |
| 22 | C, F, М. | RuntimeInvisibleAnnotations |
| 23 | Класс | InnerClasses |
| 24 | Класс | "class - версия файла" |
| 17 | Поле | ConstantValue |
| 17 | Метод | Код |
| 18 | Метод | Исключения |
| 23 | Метод | RuntimeVisibleParameterAnnotations |
| 24 | Метод | RuntimeInvisibleParameterAnnotations |
| 25 | Метод | AnnotationDefault |
| 0 | Код | StackMapTable |
| 1 | Код | LineNumberTable |
| 2 | Код | LocalVariableTable |
| 3 | Код | LocalVariableTypeTable |
| 16 | Код | (переполните атрибутов), |
Бит 16 предопределяется как индикатор присутствия атрибутов переполнения для классов, полей, методов, и кодов. Если у объекта будут атрибуты переполнения, то он будет обладать соответствующим количеством в "attr_count" полосе, и каждый атрибут переполнения будет частью выполнения значений в "attr_indexes" полосе, которая определяет разметки атрибутов переполнения. Эта обработка атрибутов переполнения описывается более полно ниже.
Они предопределяли атрибут, индексирует, определяют не только, какие позиции двоичного разряда используются, чтобы выбрать те атрибуты, но также и фиксированный порядок полосы, в котором данные атрибута передаются, как описано ниже.
Определенные биты предопределяются, чтобы поддерживать пять типов атрибутов метаданных на классах, полях, и методах, RuntimeVisibleAnnotations, RuntimeInvisibleAnnotations, RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations, и AnnotationDefault. (Последние три типа применяются только к методам.) Значение и формат этих атрибутов определяются JSR 175.
Допустимо для компрессора воздержаться от установки битов в любых словах флага за исключением бита 16, и передать все расположение атрибута индексирует явно в class_attr_indexes или подобной полосе. Декомпрессоры обязаны обрабатывать любой вид возникновения атрибута, индексируют. (Также допустимо, хотя бесполезный, для количества атрибута быть явно передано как нуль.) Компрессоры поощряются сделать умный выбор и очистить бит 16 и установить другие присвоенные флаговые биты когда возможный.
Отметьте, что ни один из предопределенных битов не вмешивается ни в какие настоящие или будущие флаговые биты в 16-разрядных флаговых значениях, сохраненных в формате файла class. Однако, компрессоры свободны снова использовать один из младшего разряда 16 битов слова флагов, связывая их с другими атрибутами, если никакой файл фактически не устанавливает их.
Атрибут InnerClasses обрабатывается особенно, как задокументировано в другом месте, и это - ошибка для компрессора, чтобы испустить определение атрибута для этого в контексте class. Атрибут Code также обрабатывается особенно. Это - ошибка испустить определение атрибута для этого в контексте метода.
Эта спецификация не определяет, как компрессору сообщают о существовании или формате атрибутов, которые не предопределяются. Это просто предполагает, что компрессорам сообщают о таких атрибутах, и это требует, чтобы компрессоры должным образом передали эту информацию к декомпрессорам. Как особый случай, разумно для любого компрессора передать атрибут, не содержащий байтов (то есть, нулевой длины), как будто ее расположение, как было известно, было пустой строкой.
В дальнейшем мы говорим, что некоторый данный элемент расположения атрибута управляет скалярным значением, сохраненным в атрибуте файла class, если декомпрессор должен использовать тот элемент, чтобы воссоздать, в файл class, представление того скалярного значения. Мы также говорим, что данный элемент расположения управляет полосой, в которой передается скалярное значение.
Расположение атрибута определяется строкой на "небольшом языке". Строка должна быть проанализирована декомпрессором в последовательность элементов расположения, каждый из которых управляет передачей и хранением значений атрибута. В частности расположение объявляет расположения всех постоянных ссылок пула, позволяя их значения быть переданным с соответствующими представлениями, или поскольку постоянный пул индексирует или иначе некоторый другой вид числа.
Самое простое применимое расположение атрибута было бы последовательностью постоянных ссылочных объявлений пула, смешанных с однобайтовыми объявлениями, чтобы управлять всем остальным, и компрессоры свободны использовать такие разметки, чтобы описать атрибуты. Однако, более определенные разметки атрибута приводят к лучшему сжатию.
Атрибуты обычно содержат постоянные ссылки пула и маленькие целые числа. Они часто содержат целые числа, которые управляют репликацией последующих образцов. Постоянные ссылки пула со строгим контролем типов где только возможно, и условие кодирования для нулевых ссылок должно быть объявлено также. Маленькие целые числа, которые кодируют флаговые биты или байт-код, индексируют, также объявляются как таковым, так, чтобы специальные методы кодирования могли использоваться на них.
Объявления расположения являются строками UTF8, сформированными согласно следующей грамматике. (Эта грамматика независима от грамматики, которая описывает структуру полосы, или любую другую грамматику, появляющуюся в других частях этой спецификации.)
attribute_layout:
( layout_element )* | ( callable )+
layout_element:
( integral | replication | union | call | reference )
callable:
'[' body ']'
body:
( layout_element )+
integral:
( unsigned_int | signed_int | bc_index | bc_offset | flag )
unsigned_int:
uint_type
signed_int:
'S' uint_type
any_int:
( unsigned_int | signed_int )
bc_index:
( 'P' uint_type | 'PO' uint_type )
bc_offset:
'O' any_int
flag:
'F' uint_type
uint_type:
( 'B' | 'H' | 'I' | 'V' )
replication:
'N' uint_type '[' body ']'
union:
'T' any_int (union_case)* '(' ')' '[' (body)? ']'
union_case:
'(' union_case_tag (',' union_case_tag)* ')' '[' (body)? ']'
union_case_tag:
( numeral | numeral '-' numeral )
call:
'(' numeral ')'
reference:
reference_type ( 'N' )? uint_type
reference_type:
( constant_ref | schema_ref | utf8_ref | untyped_ref )
constant_ref:
( 'KI' | 'KJ' | 'KF' | 'KD' | 'KS' | 'KQ' | 'KM' | 'KT' | 'KL' )
schema_ref:
( 'RC' | 'RS' | 'RD' | 'RF' | 'RM' | 'RI' | 'RY' | 'RB' | 'RN' )
utf8_ref:
'RU'
untyped_ref:
'RQ'
numeral:
'(' ('-')? (digit)+ ')'
digit:
( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' )
Каждое возникновение атрибута в файле class связывается (компрессором) с соответствующим определением расположения, которое описывает точно значение байтов того атрибута. Компрессор должен присвоить каждый элемент формата его собственная полоса для того, чтобы передать последовательные значения того элемента формата. В случае предопределенных атрибутов полосы, присвоенные их элементам расположения, определяются по имени в этой спецификации.
Каждое значение, которым управляет элемент расположения атрибута, преобразовывается компрессором в 32-разрядное значение и передается как элемент полосы, уникально создаваемой для, и управляло тем элементом расположения. Для элементов расположения integral преобразование просто представляет число, сохраненное в файле class под данным типом, в то время как элементы reference преобразовывают локальную постоянную ссылку пула (локальный для файла class, который является) в глобальную переменную, типизированную ссылку в пределах архива.
Многократные возникновения того же самого вида элемента расположения расцениваются как отличные элементы расположения. Кроме того, полосы никогда не совместно используются разметками. Поэтому, каждое новое определение расположения, переданное компрессором неявно, определяет свой собственный набор полос. Переприсвоение ранее определенного расположения атрибута к новому индексирует, создает новый набор полос; это не снова использует ранее определенные наборы полос.
Если компрессор определяет новые атрибуты, он должен также создать полосы, которыми они управляют. Это должно передать эти полосы, сразу после места, зарезервированного в грамматике полосы для предопределенных атрибутов (в конце class_attr_bands, field_attr_bands, method_attr_bands, или code_attr_bands). Упорядочивание этих полос должно соответствовать порядку определения элементов расположения атрибута, которые управляют ими. Таким образом декомпрессор будет в состоянии найти те значения атрибута.
Порядок определения двух элементов расположения в той же самой строке расположения атрибута соответствует их порядку возникновения в пределах той строки. Порядок определения двух элементов расположения не в той же самой строке расположения атрибута соответствует индексировать порядку их определений расположения в полосе attr_definition_layout. (Таким образом, полосы для разметок с ниже индексируют, предшествуют полосам для разметок того же самого типа контекста, но с выше индексирует. Это - истина, даже если ниже индексированное расположение, оказывается, определяется позже в полосе attr_definition_layout.) Отмечают, что полосы, которыми управляют предопределенные атрибуты, кажется, следуют за таким упорядочиванием также. Однако, полосы предопределенных атрибутов class предшествуют всем другим полосам атрибута class, и аналогично для полей, методов, и кодируют атрибуты.
Целочисленные значения, сохраненные в атрибутах, измеряются как 1, 2, или 4 байта, в зависимости от использования символа формата 'B', 'H', или 'я', соответственно. Целочисленный тип обычно без знака, но снабжается префиксом 'S', становится подписанным. Это подписание управляет удлинением 1-байтовых и 2-байтовых типов к 32-разрядным значениям (или расширение знака или нулевое заполнение). Это также определяет основное кодирование, используемое, чтобы передать 32-разрядные значения. Поскольку все целые числа, сохраненные в файлах class, являются "обратным порядком байтов", все интегральные элементы формата обращаются к целым числам, кодированным с битами высшего порядка в более ранних байтах.
Разметки Integral (то есть, те элементы под нетерминальным integral) управляют значениями подписанного или целого без знака. Интегральные разметки, объявления которых включают символы 'P' или 'O', используют специальные основные кодировки (BCI5 или BRANCH5) как описано ниже. Любые другие интегральные разметки, объявления которых включают символ 'S', управляют полосами с основным кодированием SIGNED5. Целое без знака и элементы расположения флага управляют полосами с основным кодированием UNSIGNED5, за исключением того, что целочисленное расположение 'B' (байт без знака) управляет полосой с основным кодированием BYTE1.
(Отметьте, что нет никакого специального кодирования для подписанных байтов. Если атрибут содержит подписанное поле байта, это может быть точно также, чтобы обработать то поле, как будто это было без знака, и дает этому простой 'Б' элемент расположения. Помимо законченности, расположение 'СУРЬМЫ' предназначается, чтобы позволить маленькой величине однобайтовые целые числа, которые будут переданы, используя алфавит байта, в котором знаковые биты редки. Это является требуемым, когда компрессор постпередачи использует Кодирование методом Хаффмана, чтобы представить байты; такие codings выполняют лучше всего, когда непротиворечивый алфавит байта представляется компрессору.)
Сохраненный байт-код индексирует, объявляется с префиксом расположения 'P'. Этот элемент расположения может только использоваться на методах или кодах. Любое число может быть сохранено в байт-коде, индексируют. Однако, прежде, чем сохраненные числа передаются как элементы полосы, они перенумеровываются в ожидании, что позиции байта не на границах инструкции будут редки.
BCI, перенумеровывающий сжато, индексирует границы инструкции, и также обеспечивает кодирование (несколько менее компактное) для всех других 32-разрядных целых чисел, таких как адреса байтов в инструкциях или вне границ байт-кодов. В частности первый байт первой инструкции нумеруется нуль, первый байт второй инструкции нумеруется один, и так далее через все инструкции. Байт располагает одно прошлое, последняя инструкция нумеруется со следующим числом (число инструкций). Второй байт первой многобайтовой инструкции нумеруется со следующим числом, которое является еще одним чем число всех инструкций. Все остающиеся непронумерованные байты присваиваются последующие числа без дальнейших беспорядков упорядочивания. Для достаточно больших положительных чисел, и для отрицательных чисел, изменение нумерации является тождественным отображением.
В целях определить местоположение границ инструкции для изменения нумерации BCI, _wide байт-код (0xc4) берется, чтобы быть частью следующих инструкций, формат которых это помогает определить. Если компрессор передает byte_escape (254) или ref_escape (253) псевдоинструкции, декомпрессор должен принять последовательности байт-кода, произведенные каждой из этих инструкций как интегральные инструкции, когда вычислительный BCI renumberings. Таким образом будет граница инструкции для каждого байта в bc_codes (кроме _wide байт-кодов) плюс дополнительная граница для каждого "aload_0_xxx" изменения (таких как "aload_0_getstatic_this"), потому что эти псевдокоды операций расширяются до пар инструкций байт-кода.
Пожалуйста, см. раздел Приложения для псевдокода, объясняя это понятие.
Если элемент расположения снабжается префиксом 'P' и не 'ПО', то перенумерованный байт-код индексирует, передается. Это изменение нумерации вызывают, байт-код индексирует изменение нумерации. Основное кодирование для полос, содержащих байт-код, индексирует, BCI5.
Вот пример того, как это работает. Вообразите метод с 20 байтами данных байт-кода и пяти инструкций в следующих позициях: { 0, 4, 6, 10, 17 }. Изменение нумерации BCI преобразовывает эти определенные числа сжато в [0..4]. Более полностью изменение нумерации BCI преобразовывает [0..20] в числа { 0, 6, 7, 8, 1, 9, 2, 10, 11, 12, 3, 13, 14, 15, 16, 17, 18, 4, 19, 20, 5 }, и что-либо вне диапазона, [0..20] остается то же самое после изменения нумерации BCI. Если атрибут этого метода будет иметь элемент расположения 'P', и сохранит номер 6 в файле class, то номер 2 будет передан, с тех пор 6 смещение третьей инструкции.
Если префиксом расположения является 'ПО', предыдущий элемент расположения, должно быть, также был байт-кодом, индексируют типа 'P' расположения или 'ПО'. (Там не должен вмешиваться структура, такая как скобки' [' или']'.) В этом случае значение, переданное в полосе, которой управляет элемент 'ПО', является различием между перенумерованным байт-кодом, индексируют управляемый текущим элементом 'ПО', и перенумерованный байт-код индексирует управляемый предыдущим 'P' или элементом 'ПО'. (В случае предыдущего элемента 'P' это - фактически значение, переданное в соответствующей позиции в предыдущей полосе.)
Элементы расположения 'ПО' управляют тем же самым видом данных атрибута как элементы 'P', но они используют кодирование, которое ожидает, что смежный байт-код индексирует, коррелируются. Это изменение нумерации, включая различие для предыдущего элемента, вызывают, смещение байт-кода, перенумеровывая основное кодирование для полос, содержащих смещения байт-кода, является BRANCH5. Это кодирование используется, даже если элемент расположения содержит 'S' или символ 'B'.
Смещение байт-кода объявляется с префиксом расположения 'O'. Этот элемент расположения должен сразу следовать, предыдущий байт-код индексируют элемент (с префиксным 'P' и не 'ПО'). Любое значение, которым управляет этот элемент расположения, расценивается как смещение, которое когда применено к индексирует соответствующий ранее сохраненный байт-код, производит другой байт-код, индексируют. Таким образом, и предыдущее значение и сумма предыдущего значения и текущей стоимости, как ожидают, обратятся к границам инструкции. Как с расположением 'ПО', переданное значение является различием двух перенумерованных байт-кодов, индексирует. Полосы, которыми управляют разметки 'ПО', содержат смещения байт-кода, и используют основное кодирование BRANCH5. В отличие от расположения 'ПО', хранимая сумма, которой управляет расположение 'O', является различием между двумя байт-кодами, индексирует.
Таким образом полосы, которыми управляют и 'O' и разметками 'ПО', содержат смещения байт-кода, и используют BRANCH5, чтобы закодировать те смещения. Но значения атрибута, которыми управляют и 'P' и абсолютным байт-кодом хранилища разметок 'ПО', индексируют; только разметки 'O' управляют сохраненными смещениями байт-кода. Сохраненные смещения обрабатываются как поля без знака в файле class, если символ 'S' не присутствует. В отличие от этого, сохраненный индексирует, всегда обрабатываются как поля без знака.
Если у предыдущего атрибута в качестве примера для 20-байтового метода также есть элемент расположения 'ПО' после его элемента 'P', и номер 20 сохранен в файле class, число, которое будет передано, находится, перенумеровывая от 20 до 5, и затем вычитая предыдущий переданный номер (5-2). Номер 3 будет поэтому передан. Если вместо этого сохраненное число будет 7 (BCI в инструкции в позиции 6), то переданное число будет (10-2) или 8. Те же самые переданные значения (3, 8), если бы управляющийся элементом расположения 'O' вместо 'ПО', соответствовали бы сохраненным значениям 14 (20-6) и 1 (7-6), вместо 20 и 7.
Элемент флага (с префиксным 'F') кодирует целочисленные значения, которые, как ожидают, закодируют короткий массив битов, а не арифметические значения. Биты не обязаны быть интерпретированными как модификаторы доступа. Основное кодирование для полос, передающих элементы расположения флага, является UNSIGNED5, за исключением того, что разметки 'FB' используют основное кодирование BYTE1.
Интегральные значения, переданные под 'V' символ формата вместо 'B', 'H', или 'я' не занимаю байтов вообще в атрибуте файла class. Эти элементы расположения позволяют декомпрессору использовать количества, или теги, чтобы управлять передачей, не имея их появляются непосредственно в атрибутах файла class. Например, рассмотрите атрибут, который является массивом байтов, который не самоизмеряет, но расширяется, чтобы заполнить количество байта, упомянутое в заголовке атрибута в файле class. У такого атрибута могла бы быть спецификация расположения 'NV [B]'. Компрессор был бы ответственен, чтобы решить который значения передать для 'V' элемент расположения. (Такие решения должны были бы использовать подробную информацию о форматах атрибута, которая не является частью этой спецификации.) Во всех случаях декомпрессор должен уважать эти значения (когда использующийся в качестве количеств или тегов), но не должен сохранить их в файле class.
Репликация представляется префиксным 'N', который сопровождается целочисленным элементом, названным количеством репликации, и к тому времени серия элементов, названных телом репликации, включила в квадратные скобки. Данные атрибута, которыми управляет это расположение, состоят из количества репликации, сопровождаемого массивом данных, считаемых количеством репликации. Каждым элементом массива управляют разметки в теле репликации.
Элемент расположения количества репликации управляет полосой, передающей количества репликации, у которого есть основное кодирование UNSIGNED5 (или BYTE1, если расположение запускается с 'NB'). Полосы, которыми управляет соответствующее тело репликации, могут быть измерены, суммируя значения, переданные в полосе, содержащей количества.
Объединение представляется префиксным 'T', который сопровождается целочисленным элементом, названным тегом объединения, и к тому времени серией маркированных, заключенных в скобки групп элементов, названных случаями объединения. (У цифр может быть любое число цифр, но их арифметические значения являются усеченными к 32-разрядным целым числам перед стать по сравнению со значениями полосы, которые также составляют 32 бита в размере.) Каждая метка, но последнее состоит из один или более заключенный в скобки, возможно подписанные десятичные цифры, названные тегами объединения. Последняя метка (который является случаем значения по умолчанию) должна быть пустой парой круглых скобок. (Никакое объединение не может содержать два возникновения того же самого тега случая.) Данные атрибута, которыми управляет это расположение, состоят из интегрального значения тега, сопровождаемого данными, формат которых определяется тегом. Данными после тега управляет (уникальный) случай объединения, метка которого соответствует значение тега, или иначе случай значения по умолчанию. Полосы, которыми управляет каждый случай объединения, могут быть измерены, считая число значений в полосе, которой управляет расположение тега. Как с простыми интегральными полосами, основное кодирование полосы тега объединения является SIGNED5, BYTE1, или UNSIGNED5, в зависимости от того, содержит ли расположение символ 'S', 'Тбайт', или иначе.
В теге объединения две цифры, разделенные дефисом, определяют содержащий диапазон. Второе число должно быть больше чем первое. Это - сокращение для списка всех цифр сначала к второму, включительно. Расположение обрабатывается точно, как будто сокращение было заменено полным списком.
Постоянные ссылки пула в атрибуте могут быть введены строго, и переданы, как индексирует в один из постоянных пулов архива. Типы расположения, начинающиеся 'с КИ', 'КИЛОДЖОУЛИ', 'KF', 'KD', и 'KS', должны управлять сохраненный, индексирует в локальном постоянном пуле к константам целого числа типа, долго, плавания, дважды, и строки. Расположение вводит beginnig 'KM', и 'KT' управляют, индексирует к константам типа MethodHandle и MethodType. Аналогично, типы расположения, начинающиеся 'с RC', 'РТС ', RD', 'RF', 'КОМНАТА', 'RI', и 'RU' должны управлять сохраненный, индексирует в локальном постоянном пуле к символам типа class, подпись, дескриптор (пара имени и вводят), полевая ссылка, ссылка метода, ссылка метода интерфейса, и строка UTF8. Тип расположения 'РАЙ' управляет, индексирует к invokedynamic дескрипторам, в то время как тип 'RB' управляет, индексирует, чтобы загрузить спецификаторы метода (которые являются элементами атрибута BootstrapMethods, не постоянного пула). Все эти ссылки передаются, поскольку 32-разрядный индексирует в соответствующие глобальные постоянные пулы, в полосах с основным кодированием UNSIGNED5. (Это - истина даже разметок, которые содержат 'B'.) См. таблицу ниже.
Отметьте, что ссылки подписи (расположение 'РТС) идентичны ссылкам Utf8 (расположение 'RU') в пределах файла class, но приводят к различной тактике кодирования в архивном файле, начиная с cp_Utf8 и cp_Signature, который постоянные пулы имеют независимый, индексирует и передаются по-другому.
Элементы расположения, начинающие 'KQ', могут только произойти в атрибутах на полях. Они обращаются к константам в постоянном пуле, идентификационные данные которого определяются подписью поля. (Этот элемент расположения, вероятно, полезен только для атрибутов ConstantValue, которые предопределяются.) Следующая таблица дает полевые подписи, законные для использования с разметками 'KQ', и соответствующих постоянных пулов, в которых должны быть найдены соответствующие сохраненные ссылки.
| Полевая Подпись | 'KQ' Постоянный Пул |
|---|---|
| B | cp_Int |
| S | cp_Int |
| C | cp_Int |
| Z | cp_Int |
| Я | cp_Int |
| J | cp_Long |
| F | cp_Float |
| D | cp_Double |
| Ljava/lang/String; | cp_String |
| Ljava/lang/Class; | cp_Class |
Три дополнительных передачи типов расположения индексируют в постоянные группы пула вместо отдельных постоянных пулов. Они могут использоваться, когда компрессор выбирает использовать расположение, у которого есть ссылки, которые не со строгим контролем типов. Объединенный тип 'KL' может использоваться для любого, индексируют, который обращается к допустимому операнду 'ldc' инструкции, и переданный индексирует, будет перенумерован относительно группы пула cp_LoadableValue. Точно так же объединенный тип расположения 'RN' может использоваться для любого, индексируют, который обращается к допустимому операнду любого того, 'чтобы получать', или 'вызовите' инструкции (кроме 'invokedynamic'), и они индексируют, будет перенумерованный относительно группы пула cp_AnyMember.
Наконец, если постоянная ссылка пула не может быть введена вообще, компрессор должен использовать untyped_ref ('ЗАПРОС'), который передает индексирование во всестороннюю постоянную группу пула cp_All. Например, все элементы пула cp_Utf8 нумеруются то же самое в разметках 'RU' и 'ЗАПРОСЕ'. Но первый элемент (нуль элемента) пула cp_Int нумеруется, для нетипизированных ссылок, как cp_Utf8_count, и первый элемент пула cp_Float нумеруется, для нетипизированных ссылок, как cp_Utf8_count+cp_Int_count.
Если компрессор сталкивается с атрибутом, который содержит постоянный пул, индексируют неожиданного типа, он может или отказаться передать атрибут, или выбрать передавать атрибут в соответствии с ослабленным определением расположения, используя 'ЗАПРОС' или элементы 'RQN' вместо большего количества элементов со строгим контролем типов. (Если неожиданный тип является загружаемой константой или задействованной ссылкой, компрессор может выбрать использовать 'RN' или элементы 'KL' вместо этого.) Декомпрессоры обязаны соблюдать все юридические определения расположения, переданные компрессорами, даже если они могли бы произвести, незаконно отформатировал файлы class. (В крайнем случае компрессор может выбрать передавать файл class, как будто это был файл ресурсов, не получая class специфичное сжатие, но сохраняя необычно отформатированные атрибуты с поразрядной точностью.)
Если тип расположения reference включает символьный 'N', все значения полосы, кодирующие постоянные записи пула, постепенно увеличиваются одним, и нулевое значение кодируется как нуль. Иначе, нулевое значение кодируется как отрицательное один (-1).
Эффект на основные кодировки полосы правил, данных выше, может быть получен в итоге как список расположенных по приоритетам правил для элементов расположения, где первое применимое правило определяет кодирование:
Вот таблица, суммирующая полосы и кодировки для различных элементов расположения. (Не все возможные комбинации типов и целочисленных размеров показывают.)
| Расположение Элемент |
Сохраненный Значение |
Переданный Значение |
Основной Кодирование |
|---|---|---|---|
| B | u1 | x | BYTE1 |
| FB | u1 | x | BYTE1 |
| СУРЬМА | u1 | (байт) x | SIGNED5 |
| H | u2 | x | UNSIGNED5 |
| FH | u2 | x | UNSIGNED5 |
| SH | u2 | (короткий) x | SIGNED5 |
| Я | u4 | x | UNSIGNED5 |
| FI | u4 | x | UNSIGNED5 |
| SI | u4 | x | SIGNED5 |
| PH ФАКТОР | u2 | renumber_bci (x) | BCI5 |
| POH | u2 | renumber_bci (x) - renumber_bci (x0) | BRANCH5 |
| OH | u2 | renumber_bci (x0+x) - renumber_bci (x0) | BRANCH5 |
| NB [...] | u1 | x (также служит количеством размера), | BYTE1 |
| NH [...] | u2 | x (также служит количеством размера), | UNSIGNED5 |
| NI [...] | u4 | x (также служит количеством размера), | UNSIGNED5 |
| ТБАЙТ... | u1 | x | BYTE1 |
| TSB... | u1 | (байт) x | SIGNED5 |
| TH... | u2 | x | UNSIGNED5 |
| TSH... | u2 | (короткий) x | SIGNED5 |
| КИБИБАЙТ | u1 | indexOf (lcp [x], cp_Int) | UNSIGNED5 |
| KIH | u2 | indexOf (lcp [x], cp_Int) | UNSIGNED5 |
| KII | u4 | indexOf (lcp [x], cp_Int) | UNSIGNED5 |
| KINH | u2 | 1+indexOf (lcp [x], cp_Int) | UNSIGNED5 |
| KJH | u2 | indexOf (lcp [x], cp_Long) | UNSIGNED5 |
| KFH | u2 | indexOf (lcp [x], cp_Float) | UNSIGNED5 |
| KDH | u2 | indexOf (lcp [x], cp_Double) | UNSIGNED5 |
| KSH | u2 | indexOf (lcp [x], cp_String) | UNSIGNED5 |
| KQH | u2 | indexOf (lcp [x], cp_FieldSpecific) | UNSIGNED5 |
| КМ/Ч | u2 | indexOf (lcp [x], cp_MethodHandle) | UNSIGNED5 |
| KTH | u2 | indexOf (lcp [x], cp_MethodType) | UNSIGNED5 |
| KLH | u2 | indexOf (lcp [x], cp_LoadableValue) | UNSIGNED5 |
| RCH | u2 | indexOf (lcp [x], cp_Class) | UNSIGNED5 |
| RSH | u2 | indexOf (lcp [x], cp_Signature) | UNSIGNED5 |
| RDH | u2 | indexOf (lcp [x], cp_Descr) | UNSIGNED5 |
| RFH | u2 | indexOf (lcp [x], cp_Field) | UNSIGNED5 |
| RMH | u2 | indexOf (lcp [x], cp_Method) | UNSIGNED5 |
| RIH | u2 | indexOf (lcp [x], cp_Imethod) | UNSIGNED5 |
| RUH | u2 | indexOf (lcp [x], cp_Utf8) | UNSIGNED5 |
| RQH | u2 | indexOf (lcp [x], cp_All) | UNSIGNED5 |
| RQNH | u2 | 1+indexOf (lcp [x], cp_All) | UNSIGNED5 |
| RQNI | u4 | 1+indexOf (lcp [x], cp_All) | UNSIGNED5 |
| RYH | u2 | indexOf (lcp [x], cp_InvokeDynamic) | UNSIGNED5 |
| RBH | u2 | indexOf (class.BootstrapMethods [x], cp_BootstrapMethod) | UNSIGNED5 |
| RNH | u2 | indexOf (lcp [x], cp_AnyMember) | UNSIGNED5 |
Здесь, переменная x называет значение сохраненным в атрибуте, которым управляет элемент расположения. Переменная x0 называет хранимую сумму управляемой сразу предыдущим элементом расположения, который, должно быть, начался 'с P'. Выражение renumber_bci (x) обозначает, что изменение нумерации байт-кода индексирует x, чтобы сократить ссылки на границы инструкции, как описано выше. Выражение lcp [x] обозначает, что локальная постоянная ссылка пула, с индексируют x, или отличное нулевое значение, если x является нулем.
Выражение class.BootstrapMethods [x] обозначает элемент атрибута BootstrapMethods текущего class. Этот атрибут содержит дополнительные сложные константы, требуемые CONSTANT_InvokeDynamic постоянные записи пула.
Выражение indexOf (lcp [x], cp) обозначает индексирование (основанного на нуле) в глобальном постоянном cp пула Pack200 постоянного lcp [x], который, как предполагается, имеет тип, соответствующий cp. У этого выражения есть значение-1, если у lcp [x] есть отличное нулевое значение.
Отметьте, что нулевая ссылка может всегда передаваться в полосе, содержащей ссылки, передавая нуль значения (если полоса определяется, чтобы принять, обнуляет), или передавая значение-1 (иначе). Кодирование UNSIGNED5 может представить-1 в пяти байтах.
Имя cp_FieldSpecific обращается к глобальному постоянному пулу, выбранному полевой подписью включения, как описано выше.
Элемент расположения вызова является заключенной в скобки подписанной десятичной цифрой N. Это обращается к Энному вызываемому в высокоуровневой структуре спецификации расположения относительно вызываемого, в котором появляется вызов. (Это недопустимо для вызовов, чтобы появиться за пределами callables.) Мы обратимся к этому вызываемому как вызываемый вызова.
(Например, элемент расположения' (2)' вызовы второе вызываемое расположение после того, в котором появляется вызов. Должен быть соответствующий вызываемый для каждого вызываемого. Вызов, записанный' (1)', не должен появиться в последнем вызываемом из расположения, и аналогично вызов, записанный' (-1)', не должен произойти в первом вызываемом. Отметьте, что самовызов, записанный' (0)', является всегда законным.)
Элемент расположения вызова косвенно управляет данными атрибута, которыми более непосредственно управляют вызываемым, которое вызывает элемент расположения. Насколько формат файла class затрагивается, эффект является тем же самым, как будто текстом в пределах тела callable заменили вместо вызова.
Однако, эта семантика замены не описывает эффект элемента расположения вызова на структуре полосы. Элемент расположения вызова непосредственно не управляет никакими полосами, а скорее определяет, что данные, которыми он косвенно управляет, должны быть переданы в полосах, которыми управляет более непосредственно вызываемый.
Если вызываемый вызова начинает дословно позже чем вызов непосредственно, вызов является переводить вызовом. Эффект переводить вызова состоит в том, чтобы просто сделать полосы вызываемого с обеспечением совместного доступа вызовом и любыми другими прямыми звонками в того же самого вызываемого. Например, у следующей спецификации расположения есть две полосы, последний которых передает данные, которыми косвенно управляет любой из случаев объединения. (Случай объединения значения по умолчанию не управляет никакими полосами, так, чтобы у байта тега кроме ASCII или 'B' не было никакого после байтов. Пробел был добавлен к расположению для простоты чтения.)
[TB
(65) [(1)]
(66) [(1)]
( ) []
]
[H]
Вызываемый вызова может также начать дословно ранее чем вызов непосредственно. Такой вызов, у которого должно быть написание формы' (0)' или' (-N)', упоминается как обратный вызов. Его вызываемый упоминается как обратное вызываемое. (Callables, которые являются целью никаких вызовов или только, переводят вызовы, не обратный callables; все другие.) Назад вызывает, и callables представляют возможность рекурсии и цикличного выполнения. Вот пример дерева Не, листы которого являются строками Utf8, которым предшествует нулевой байт, и чьи внутренние узлы считаются массивы древовидных узлов, которым предшествуют однобайтовым: В этом примере вызываемый включает вызов для прямой рекурсии. Расположение управляет тремя полосами, под элементами 'Тбайт', 'NH', и 'RUH'.
[TB
(1) [NH[ (0) ]]
(0) [RUH]
]
Калибровке полос, которыми управляют такие взаимно рекурсивные разметки, помогают явные количества обратных вызовов, переданных перед любой из полос атрибута расположения, в class_attr_calls и трех подобных полосах, которые описываются позже.
| Тип контекста | Имя | Определение расположения |
|---|---|---|
| Класс | "class - версия файла" | (пустой) * (см. примечание), |
| Класс | InnerClasses | (пустой) * (см. примечание), |
| Класс | EnclosingMethod | RCHRDNH |
| Класс | SourceFile | RUNH * (см. примечание), |
| Класс | Подпись | RSH |
| Класс | (метаданные) | (см. ниже), |
| Класс | Устаревшие | (пустой) |
| Поле | ConstantValue | KQH |
| Поле | Подпись | RSH |
| Поле | (метаданные) | (см. ниже), |
| Поле | Устаревшие | (пустой) |
| Метод | Код | (пустой) * (см. примечание), |
| Метод | Исключения | NH [RCH] |
| Метод | Подпись | RSH |
| Метод | (метаданные) | (см. ниже), |
| Метод | Устаревшие | (пустой) |
| Код | StackMapTable | (см. ниже), |
| Код | LineNumberTable | NH [PHH] |
| Код | LocalVariableTable | NH [PHOHRUHRSHH] |
| Код | LocalVariableTypeTable | NH [PHOHRUHRSHH] |
Звезда '*' в определениях расположения "class - версия файла", InnerClasses, SourceFile, и Code отражают факт, что этим атрибутам дают специальную обработку. Для class "class - передается псевдоатрибут" версии файла, как будто используя формат VV, но декомпрессор не хранит результат в атрибуте файла class, а скорее в заголовке файла class. (См. обсуждение ниже.) Для class частично передается атрибут InnerClasses, как будто используя формат NV[RCVTV[(0)[]()[RCNVRUNV]]], но декомпрессор обрабатывает полученные значения далее прежде (возможно) испустить атрибут InnerClasses. (См. обсуждение ниже.), Когда атрибут SourceFile передается, используя предопределенное расположение, специальное правило позволяет этому принимать значение по умолчанию к очевидной стандартной строке. Наконец, для метода, атрибут Code передается под code_bands.
[NH[(1)]]
[TB
(64-127) [(2)]
(247) [(1)(2)]
(248-251) [(1)]
(252) [(1)(2)]
(253) [(1)(2)(2)]
(254) [(1)(2)(2)(2)]
(255) [(1)NH[(2)]NH[(2)]]
() []
]
[H]
[TB
(7) [RCH]
(8) [PH]
() []
]
Следующие наблюдения могут быть выведены, сравнивая эту спецификацию расположения со спецификацией формата файла class, которая определяет атрибут StackMapTable. Второе вызываемое описывает структуру stack_map_frame от спецификации формата файла class. В пределах объединения во втором вызываемом случаи поддерживают следующие члены профсоюза stack_map_frame, соответственно: same_locals_1_stack_item_frame, same_locals_1_stack_item_extended, chop_frame (и также same_frame_extended), append_frame (для трех случаев объединения расположения), full_frame, и (в случае объединения расположения значения по умолчанию) same_frame. Третьи и четвертые callables описывают значение offset_delta и структуру verification_type_info от спецификации формата файла class.
[NH[(1)]]
[RSH NH[RUH(1)]]
[TB
(66,67,73,83,90) [KIH]
(68) [KDH]
(70) [KFH]
(74) [KJH]
(99) [RSH]
(101) [RSH RUH]
(115) [RUH]
(91) [NH[(0)]]
(64) [RSH [RUH(0)]]
() []
]
И видимые и невидимые аннотации используют это расположение. Второе вызываемое описывает структуру annotation от спецификации метаданных. Третье вызываемое описывает структуру member_value от спецификации метаданных. Это длится вызываемое, совершенно отдельно, используется для атрибута AnnotationDefault на методах. Аннотации параметра метода (и видимый и невидимый) также предопределяются, используя это расположение с предварительно ожидаемым вызываемым, чтобы считать число параметров: [NB[(1)]] [NH[(1)]] [RSH NH[RUH(1)]] [TB...]
Это правило соответствует историческое поведение многих компиляторов Java, и позволяет компрессору избегать выделять строки Utf8 для "очевидных" полученных имен SourceFile. (Если компрессор должен передать неправильный атрибут SourceFile с истинной нулевой ссылкой, он должен использовать нестандартное расположение.) Вот таблица примеров имен class и соответствующих полученных имен SourceFile.
| Класс | SourceFile |
|---|---|
| foo | foo.java |
| foo/bar | bar.java |
| foo/bar$baz | bar.java |
| foo/bar#baz#1 | bar.java |
| foo.bar.baz#1 | baz.java |
ic_bands:
*ic_this_class :UDELTA5 [#ic_count] (cp_Class)
*ic_flags :UNSIGNED5 [#ic_count]
*ic_outer_class :DELTA5 [COUNT(1<<16,...)] (null or cp_Class)
*ic_name :DELTA5 [LENGTH(*ic_outer_class)] (null or cp_Utf8)
Эти четыре кортежа совместно используются глобально, как постоянные записи пула. В этой спецификации они - традиционно записанный <C,F,C2,N>, даже при том, что они сохранены в различном порядке в формате файла class. Как набор, эти глобально определенные четыре кортежа вызывают ic_All. обычно нет никакого явного редактирования от отдельных классов в архиве к вложенным записям class. Вместо этого извлекая файл class из архива Pack200, подмножество вложенных записей class может быть выбрано, который достаточен, чтобы описать все вложенные классы, фактически упомянутые в постоянном пуле файла извлеченного class. Для любого файла X class, который будет извлечен, это подмножество вызовут ic_Relevant(X), соответствующим подмножеством для X из ic_All. Алгоритм для того, чтобы выбрать соответствующее подмножество описывается позже. Дополнительно, компрессор может определить, для любого данного class, корректировки ее соответствующего подмножества, передавая локальный атрибут InnerClasses. Это также описывается в более позднем разделе по атрибутам class. ic_this_class и полосы ic_flags имеют оба длину #ic_count, и соответствующие элементы этих полос определяют, для каждого кортежа, вложенные идентификационные данные class (представленный как ссылка cp_Class) и битовая маска флагов.
Вложенный флаговый бит class в позиции 16 (как установлено в маске 0x00010000) в архивном файле, чтобы указать, есть ли соответствующие записи для кортежа в полосах ic_name и ic_outer_class. Таким образом длина обеих из этих полос является суммой всех флаговых битов в позиции 16. Как правило, только несколько процентов вложенных классов должны установить этот бит и определить внешние и поля имени явно.
Если у кортежа есть запись в ic_outer_class и полосах ic_name, они определяют его внешний class и простое имя. (Они представляются соответственно как возможно нулевая ссылка cp_Class и возможно нулевая ссылка cp_Utf8.) Иначе, внешний class кортежа и имя, как говорят, предсказываются. В этом случае они должны быть правильно предсказуемыми с имени вложенного class непосредственно, анализируя его написание.
У вложенного class есть имя байт-кода, которое называет class в пределах файлов class. У написания этого имени, иногда называемого "скорректированным именем", есть дополнительные знаки пунктуации и возможно цифры так же как имя содержания class. Если имя байт-кода может быть проанализировано во внешний class и имя class, и этот class и имя идентичны с истинным внешним class и именем class вложенного class, то мы говорим, что внешний class и имя class предсказуемы.
Экстракция предсказуемого внешнего class и имени class должна следовать за следующей грамматикой для имен байт-кода class, в применении к написанию вложенного имени class. (Эта грамматика независима от грамматики, управляющей структурой полосы, или любой другой грамматикой, появляющейся в других частях этой спецификации.) Терминальный ДОЛЛАР обращается к любому символу (такому как '$' или '#'), чей код является 0x2D или ниже. НАКЛОННАЯ ЧЕРТА терминалов обращается к наклонной черте или точечным символам '/' или'.', у которых есть коды 0x2E и 0x2F. Терминальная ЦИФРА обращается к десятичной цифре ASCII, одному из десяти символьных кодов от 0x30 до 0x39 включительно. Терминальная БУКВА обращается к любому другому символу. Таким образом, это обращается к любому символу, код которого является 0x3A или выше.
bcn:
(bcnCase1 | bcnCase2 | bcnCase3 | bcnCase4)
bcnCase1:
packageQual (namePart)? DOLLAR number
bcnCase2:
packageQual (namePart)? DOLLAR number DOLLAR predictableICName
bcnCase3:
predictableOuter DOLLAR predictableICName
bcnCase4:
packageQual (namePart)?
predictableOuter:
packageQual namePart
predictableICName:
LETTER (LETTER | DIGIT)*
namePart:
(LETTER | DIGIT | DOLLAR)+
number:
(DIGIT)+
packageQual:
(namePart SLASH)*
Эта грамматика двусмысленно делит произвольное имя class на несколько частей, которые могут включать дополнительный префикс predictedOuter, дополнительный суффикс predictedICName, и дополнительный числовой суффикс. Любая неоднозначность должна быть разрешена, предпочитая альтернативные случаи для bcn, нетерминального в данном порядке. Например, если bcnCase1 соответствует, он используется, даже при том, что или или оба других случая может соответствовать также.
Предсказуемое вложенное имя class является строкой, соответствующей нетерминальному predictableICName, если это было проанализировано. Иначе предсказуемое вложенное имя class берется, чтобы быть нулем.
Если predictableOuter, внешний нетерминальный, анализируется, соответствующая строка является предсказуемым внешним именем class. Иначе предсказуемая внешняя ссылка class берется, чтобы быть нулем. Отметьте, что, если нетерминальный number анализируется, никакой predictableOuter не может быть проанализирован. Вот некоторые примеры прогноза, непрогноза, и misprediction:
| Внутренние Примеры Прогноза Класса | |
|---|---|
| вложенный class: | элемент под названием Entry java/util/Map |
| скорректированное имя: | java/util/Map$Entry |
| внешний, имя: | java/util/Map, Entry |
| предсказуемый? | да (так как Map.Entry является элементом Map), |
| вложенный class: | анонимный |
| скорректированное имя: | java/util/AbstractList$1 |
| внешний, имя: | (ни один), (ни один) |
| предсказуемый? | да (так как ic_name является нулем), |
| вложенный class: | лицо, не являющееся членом какой-либо организации, названное Local |
| скорректированное имя: | java/util/AbstractList$2$Local |
| внешний, имя: | (ни один), Local |
| предсказуемый? | да (так как ic_name является Local), |
| вложенный class: | лицо, не являющееся членом какой-либо организации, названное Local |
| скорректированное имя: | java/util/AbstractList#2#Local |
| внешний, имя: | (ни один), Local |
| предсказуемый? | да (так как ic_name является Local), |
| вложенный class: | элемент под названием $2$Local Foo |
| скорректированное имя: | Foo$$2$Local |
| внешний, имя: | (ни один), Local |
| предсказуемый? | нет (внешние без вести пропавшие имени, ic_name mispredicted) |
| вложенный class: | class по имени Red$Herring |
| скорректированное имя: | Red$Herring |
| внешний, имя: | Red, Herring |
| предсказуемый? | нет (предсказанная ic_name Сельдь) |
| вложенный class: | элемент под названием Q X$1 |
| скорректированное имя: | X$1$Q |
| внешний, имя: | (ни один), Q |
| предсказуемый? | нет (так как Q является элементом X$1), |
| вложенный class: | элемент под названием Z X$Y |
| скорректированное имя: | X$Y$Z |
| внешний, имя: | X$Y, Z |
| предсказуемый? | да (так как X$Y.Z является элементом X$Y), |
| вложенный class: | элемент под названием Y$Z X |
| скорректированное имя: | X$Y$Z |
| внешний, имя: | X$Y, Z |
| предсказуемый? | нет (внешнее имя и ic_name являются mispredicted), |
Когда декомпрессор обрабатывает вложенное имя class, отмеченное "предсказуемый", он должен проанализировать имя байт-кода вложенного class во включение class, дополнительное число, и дополнительное имя. (Компрессор мог бы хотеть всегда определять внешние классы и имена явно, когда декомпрессор не будет обязан анализировать вложенные имена class вообще. Однако, декомпрессоры должны всегда готовиться выполнить этот парсинг.)
Если бы компрессор не передавал запись в cp_Utf8 или cp_Class для предсказанного имени или внешнего class, то декомпрессор должен создать такую константу внутренне. Это будет упоминаться как cp_Utf8 или запись cp_Class, даже при том, что это не находится в постоянной последовательности передачи cp_All. Однако, если бы компрессор действительно передавал константу с тем же самым написанием как предсказанное имя или внешний class, то декомпрессор должен использовать ту константу вместо того, чтобы создать новый. Создание таких внутренних констант в пределах декомпрессора обнаруживаемо в выходном файле, потому что они вставляются в специальный порядок в постоянном пуле выходного файла. (См. обсуждение выходных правил упорядочивания ниже.)
Пожалуйста, см. раздел Приложения для псевдокода, объясняя это понятие.
Когда декомпрессор получает ic_this_class, ic_flags, ic_name, и полосы ic_outer_class, и выполняет любой необходимый парсинг имени, это создает набор ic_All четырех кортежей. Этот набор является основным источником атрибутов InnerClasses, синтезируемых для отдельных файлов class декомпрессором.
class_bands:
*class_this :DELTA5 [#class_count] (cp_Class)
*class_super :DELTA5 [#class_count] (cp_Class)
*class_interface_count :DELTA5 [#class_count]
*class_interface :DELTA5 [SUM(*class_interface_count)] (cp_Class)
*class_field_count :DELTA5 [#class_count]
*class_method_count :DELTA5 [#class_count]
*field_descr :DELTA5 [SUM(*class_field_count)] (cp_Descr)
field_attr_bands
*method_descr :MDELTA5 [SUM(*class_method_count)] (cp_Descr)
method_attr_bands
class_attr_bands
code_bands
class_this, class_super, class_flags_lo, class_flags_hi (если есть), class_interface_count, class_field_count, и полосы class_method_count являются всей длиной #class_count, и соответствующие элементы этих полос передача поочередно имя каждого class и super-class, и число реализованных интерфейсов, объявленных полями, и объявленными методами. (Биты модификатора доступа в слове флагов каждого class смешиваются с индикаторами атрибута, и передаются в class_flags_lo, как определено выше.)
Полоса class_interface содержит выполнения объявлений интерфейса class, один выполненный для каждого элемента class_interface_count, и применения к соответствующему class.
Каждый элемент class_this, class_super, и class_interface является ссылкой (фактически, ненулевой ссылкой) к постоянному пулу cp_Class.
В уникальном случае java/lang/Object сохраненный super-class должен быть нулевой ссылкой. Вместо того, чтобы нарушать передачу всех других элементов полосы class_super, мы используем соглашение, что компрессор, когда это встречается с нулем super-class ссылка, должен передать в ее месте копию ссылки текущего class. (Так как это недопустимо для class, чтобы наследоваться от себя, это изменение нумерации нулевых ссылок однозначно.)
Полосы field_descr содержат одно выполнение элементов для каждого элемента class_field_count, и применяются к последовательным полям в соответствующем class. Полосы method_descr содержат одно выполнение элементов для каждого элемента class_method_count, и применяются к последовательным методам в соответствующем class.
(В отличие от формата файла class, поле и дескрипторы метода сохранены как единственные ссылки на "имя-и-тип" постоянный пул, а не как пары ссылок имени и вводят ссылки.)
У полосы method_descr есть основное кодирование, которое выполняет лучше всего, если ссылки метода главным образом сортируются. Компрессоры могут выбрать использовать в своих интересах этот факт, сортируя методы в каждом class. (Отметьте: обычно приемлемо для компрессоров переупорядочить методы для лучшего сжатия, но поля не должны быть переупорядочены, так как их порядок является очевидным посредством отражения и существенным к некоторым средствам, таким как сериализация.)
Полосы атрибута помещаются в позиции, обозначенные грамматикой. Они описываются ниже. Полосы атрибута включают полосы флагов, которые переносят и модификаторы доступа и приписывают индикаторы для соответствующих классов, полей, и методов.
Pack200 архивируют концы с полосами, посвященными блокам кода метода и байт-кодам непосредственно. Если у метода есть атрибут кода, компрессор должен упомянуть это в бите флагов (6-ой LSB), которому это присваивается, или как атрибут переполнения (с индексированием 6). Поля атрибута Кода передаются в полосах, организованных под нетерминальным code_bands.
Спецификация каждого атрибута Кода начинается с трех основных параметров, которые объявляют число стека и локальных слотов, и число обработчиков. #Stack является числом слотов стека, используемых кодом. #NALocal является числом локальных переменных непараметра, используемых кодом. (Фактическим числом локальных переменных, объявленных в файле class, будет #NALocal плюс число локальных переменных, требуемых параметрами метода, как определено подписью метода.) #Handler является числом обработчиков исключений.
Полоса code_headers содержит серию байтов, каждый из которых кратко кодирует первые три основных параметра атрибута кода: Каждое из 255 ненулевых значений байта кодирует уникальный тройной из #NALocal, #Stack, и #Handler. Есть (конечно), один заголовок кода для каждого переданного атрибута Кода.
Специальный нуль (0x00) байта заголовка кода указывает, что атрибут кода три параметра должен быть найден, вместо этого, в code_max_stack, code_max_na_locals, и полосах code_handler_count. Если байт заголовка кода является ненулевым, эти три полосы не передают записи для соответствующего атрибута Кода.
Полоса code_flags_lo передает запись для соответствующего атрибута Code, если и только если один или оба из следующего истина: байт заголовка кода атрибута Кода является нулем, или бит have_all_code_flags устанавливается в слове #archive_options. Если у атрибута Code нет переданного значения code_flags_lo, его слово флагов берется, чтобы быть нулем, и у этого нет никаких податрибутов. Полоса code_flags_hi передает соответствующую запись, если и только если значение code_flags_lo было передано как только описано, и также #have_code_flags_hi устанавливается.
Ненулевые байты заголовка кода обозначают параметры атрибута кода согласно следующей схеме:
| Диапазон заголовка | #Stack | #NALocal | #Handler |
|---|---|---|---|
| 1 <= x <= 144 | (x-1) % 12 | (x-1) / 12 | 0 |
| 145 <= x <= 208 | (x-145) % 8 | (x-145) / 8 | 1 |
| 209 <= x <= 255 | (x-209) % 7 | (x-209) / 7 | 2 |
| x = 0 | code_max_stack | code_max_na_locals | code_handler_count |
Независимо от того, кодируется ли количество обработчика исключений в однобайтовом заголовке кода, или является ли это явным элементом code_handler_count, для каждого атрибута кода есть выполнение значений в code_handler_start_P, code_handler_end_PO, code_handler_catch_PO, и code_handler_class_RCN, один для каждого обработчика, как будто теми полосами управляло расположение атрибута 'NV[PHPOHPOHRCNH]' (нет никакой полосы, которой управляет элемент расположения 'NV' непосредственно; это - количество обработчика).
Таким образом, каждый триплет Handler.start, Handler.end, и значений Handler.catch передается как перенумеровано (renumber_bci). Кроме того, Handler.end передается как различие его изменения нумерации с тем из Handler.start в том же самом триплете, и Handler.catch передается как различие его изменения нумерации с тем из Handler.end в том же самом триплете. Наконец, code_handler_class_RCN передается как постепенно увеличенная ссылка в cp_Class, или нуль, если обработчик ссылка class является нулем.
code_bands:
*code_headers :BYTE1 [COUNT(Code,...)]
*code_max_stack :UNSIGNED5 [COUNT(0,*code_headers)]
*code_max_na_locals :UNSIGNED5 [COUNT(0,*code_headers)]
*code_handler_count :UNSIGNED5 [COUNT(0,*code_headers)]
*code_handler_start_P :BCI5 [SUM(*code_handler_count)]
*code_handler_end_PO :BRANCH5 [SUM(*code_handler_count)]
*code_handler_catch_PO :BRANCH5 [SUM(*code_handler_count)]
*code_handler_class_RCN :UNSIGNED5 [SUM(*code_handler_count)] (null or cp_Class)
code_attr_bands
Если компрессор отмечает class (resp. поле, метод, или код) как имеющий атрибуты переполнения, это должно передать соответствующий элемент в полосе class_attr_count (resp. field_attr_count, method_attr_count, или полоса code_attr_count). Это количество, поочередно, определяет размер выполнения в class_attr_indexes (resp. field_attr_indexes, method_attr_indexes, или code_attr_indexes) индексирует разметок атрибута, управляющих атрибутами class (resp. поле, метод, или код). Компрессор должен передать определение расположения атрибута, индексируют для каждого атрибута переполнения.
Для каждого расположения атрибута, выбранного немного в элементе class_flags или элементом class_attr_indexes, компрессор должен получить данные, которыми управляют элементы расположения от атрибута class и элементы передачи, кодирующие эти данные в полосах, которыми управляет расположение. Подобные условия просят поле, метод, и кодируют атрибуты.
Для каждого расположения атрибута, которое передает данные и содержит обратные вызовы, компрессор должен передать число раз, каждый назад вызываемый будет предметом обратного вызова, поскольку декомпрессор прокладывает себе путь посредством разметок атрибута. Эти количества вызова передаются в class_attr_calls, field_attr_calls, method_attr_calls, и полосах code_attr_calls, согласно типу контекста разметок, которым они применяются к. Количества вызова передаются, один на вызываемый обратный, в порядке определения callables. (См. выше.) Количества вызова только передаются для обратных callables, которые происходят в пределах разметок, которые используются, по крайней мере, однажды. Количества вызова не считают записи в любого вызываемыми из-за переводить вызова, и при этом они не считают начальный вызов вызываемого, которое инициирует обработку атрибута. Количество вызова могло бы быть нулем, если обратное вызываемое происходит в расположении, которое используется, но которое, оказывается, не достигает обратного вызываемого. Эти количества вызова необходимы, чтобы повредить зацикливание, свойственное от калибровки полос для взаимно рекурсивных разметок. Они предоставляют минимальную информацию, необходимую для декомпрессора, чтобы определить местоположение всех полос в архиве, до распределения полосы оценивает различным выходным классам. Поэтому количества вызова предоставляются один на расположение, суммированное по всем возникновениям атрибута того каждого расположения.
Декомпрессор ответственен за обработку любых явных определений расположения атрибута, переданных компрессором. Это должно подготовиться получать дополнительные полосы, которыми управляют те разметки. Когда это читает, определение расположения индексирует, это должно подготовиться читать в корректном числе значений, переданных в каждой из тех дополнительных полос.
Грамматика полос, определенных в этой спецификации, включает полосы, которыми управляют все предопределенные разметки атрибута. Для ясности некоторые названия группы упоминают часть элемента расположения, который создал их. Отметьте, что у Осуждаемых атрибутов нет никаких полос, потому что их разметки пусты.
Атрибуты под названием "Синтетический", хотя часть стандартного формата файла class в более ранних версиях Java, непосредственно не поддерживаются в этой спецификации, потому что тот атрибут был заменен новым флаговым битом (ACC_SYNTHETIC, 0x1000) в более свежих версиях Java. Однако, компрессоры поощряются обработать Синтетические атрибуты, и любые другие атрибуты нулевые длиной, не предопределенные здесь, присваивая их неиспользованные флаговые биты, и испуская явные определения расположения нулевые длиной для декомпрессоров, чтобы следовать.
Если компрессор выбирает определять новые разметки, полосы, которыми управляют те разметки, сразу добавляются после полос для предопределенных разметок. (Порядок и структура предопределенных полос атрибута отражают предопределенные определения расположения регулярным способом, как будто компрессор фактически определил их явно.)
class_attr_bands:
*class_flags_hi :UNSIGNED5 [#class_count*#have_class_flags_hi]
*class_flags_lo :UNSIGNED5 [#class_count]
*class_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
*class_attr_indexes :UNSIGNED5 [SUM(*class_attr_count)]
*class_attr_calls :UNSIGNED5 [...]
*class_SourceFile_RUN :UNSIGNED5 [COUNT(SourceFile,...)] (null or cp_Utf8)
*class_EnclosingMethod_RC :UNSIGNED5 [COUNT(EnclosingMethod,...)] (cp_Class)
*class_EnclosingMethod_RDN :UNSIGNED5 [COUNT(EnclosingMethod,...)] (null or cp_Descr)
*class_Signature_RS :UNSIGNED5 [COUNT(Signature,..)] (cp_Signature)
class_metadata_bands
ic_local_bands
*class_file_version_minor_H :UNSIGNED5 [COUNT(version,...)]
*class_file_version_major_H :UNSIGNED5 [COUNT(version,...)]
{class_attr_element_bands...}
field_attr_bands:
*field_flags_hi :UNSIGNED5 [SUM(*class_field_count)*#have_field_flags_hi]
*field_flags_lo :UNSIGNED5 [SUM(*class_field_count)]
*field_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
*field_attr_indexes :UNSIGNED5 [SUM(*field_attr_count)]
*field_attr_calls :UNSIGNED5 [...]
*field_ConstantValue_KQ :UNSIGNED5 [COUNT(ConstantValue,...)] (cp_Int, etc.; see note)
*field_Signature_RS :UNSIGNED5 [COUNT(Signature,...)] (cp_Signature)
field_metadata_bands
method_attr_bands:
*method_flags_hi :UNSIGNED5 [SUM(*class_method_count)*#have_method_flags_hi]
*method_flags_lo :UNSIGNED5 [SUM(*class_method_count)]
*method_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
*method_attr_indexes :UNSIGNED5 [SUM(*method_attr_count)]
*method_attr_calls :UNSIGNED5 [...]
*method_Exceptions_N :UNSIGNED5 [COUNT(Exceptions,...)]
*method_Exceptions_RC :UNSIGNED5 [SUM(*method_Exceptions_N)] (cp_Class)
*method_Signature_RS :UNSIGNED5 [COUNT(Signature,...)] (cp_Signature)
method_metadata_bands
{method_attr_element_bands...}
code_attr_bands:
*code_flags_hi :UNSIGNED5 [...*#have_code_flags_hi]
*code_flags_lo :UNSIGNED5 [...]
*code_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
*code_attr_indexes :UNSIGNED5 [SUM(*code_attr_count)]
*code_attr_calls :UNSIGNED5 [...]
*code_StackMapTable_N :UNSIGNED5 [COUNT(StackMapTable,...)]
*code_StackMapTable_frame_T :BYTE1 [SUM(*code_StackMapTable_N)]
*code_StackMapTable_local_N :UNSIGNED5 [COUNT(255,*code_StackMapTable_frame_T)]
*code_StackMapTable_stack_N :UNSIGNED5 [COUNT(255,*code_StackMapTable_frame_T)]
*code_StackMapTable_offset :UNSIGNED5 [...]
*code_StackMapTable_T :BYTE1 [...]
*code_StackMapTable_RC :UNSIGNED5 [COUNT(7,*code_StackMapTable_T)]
*code_StackMapTable_P :BCI5 [COUNT(8,*code_StackMapTable_T)]
*code_LineNumberTable_N :UNSIGNED5 [...]
*code_LineNumberTable_bci_P :BCI5 [...]
*code_LineNumberTable_line :UNSIGNED5 [...]
*code_LocalVariableTable_N :UNSIGNED5 [...]
*code_LocalVariableTable_bci_P :BCI5 [...]
*code_LocalVariableTable_span_O :BRANCH5 [...]
*code_LocalVariableTable_name_RU :UNSIGNED5 [...] (cp_Utf8)
*code_LocalVariableTable_type_RS :UNSIGNED5 [...] (cp_Signature)
*code_LocalVariableTable_slot :UNSIGNED5 [...]
*code_LocalVariableTypeTable_N :UNSIGNED5 [...]
*code_LocalVariableTypeTable_bci_P :BCI5 [...]
*code_LocalVariableTypeTable_span_O :BRANCH5 [...]
*code_LocalVariableTypeTable_name_RU :UNSIGNED5 [...] (cp_Utf8)
*code_LocalVariableTypeTable_type_RS :UNSIGNED5 [...] (cp_Signature)
*code_LocalVariableTypeTable_slot :UNSIGNED5 [...]
{code_attr_element_bands...}
class обладает "class - псевдоатрибут" версии файла, если вспомогательная или основная версия файла его class отличается от #default_class_minver или #default_class_majver, соответственно. Этот псевдоатрибут является парой 16-разрядных целых чисел, дающих номера основной версии и номера вспомогательной версии файла class. Эти целые числа сохранены в заголовке файла class, а не в записи атрибута. Как соглашение с classfiles, номер вспомогательной версии на первом месте. Таким образом номера вспомогательной версии передаются в полосе class_file_version_minor_H, и номера основной версии в class_file_version_major_H. Декомпрессоры не обязаны обрабатывать архивы с большими номерами вспомогательной версии или номерами основной версии чем таковые из спецификации, которую они были спроектированы, чтобы обработать. Декомпрессоры обязаны обрабатывать архивы с теми же самыми главными и меньшими или равными номерами вспомогательной версии.
Четыре кортежа всех локальных атрибутов InnerClasses передаются в пяти полосах:
ic_local_bands:
*class_InnerClasses_N :UNSIGNED5 [COUNT(InnerClasses,...)]
*class_InnerClasses_RC :UNSIGNED5 [SUM(*class_InnerClasses_N)] (cp_Class)
*class_InnerClasses_F :UNSIGNED5 [SUM(*class_InnerClasses_N)]
*class_InnerClasses_outer_RCN :UNSIGNED5 [COUNT(!=0,*class_InnerClasses_F)] (null or cp_Class)
*class_InnerClasses_name_RUN :UNSIGNED5 [COUNT(!=0,*class_InnerClasses_F)] (null or cp_Utf8)
Каждый <C,F,C2,N> с четырьмя кортежами, переданный в этих полосах атрибута, вызывают локальным кортежем IC. (Отметьте, что формат файла class хранит элементы этих четырех кортежей в различном порядке, (C,C2,N,F).) Для данного файла X class последовательность локальных кортежей IC вызывают ic_Local(X).
Для каждого локального кортежа IC, передач компрессора, в минимуме, значении C и значении F. Если переданное значение флагов F не является нулем, есть также соответствующие переданные постоянные ссылки пула C2 и N. В целом переданный локальный кортеж может или, возможно, не эквивалентен глобальному кортежу от ic_All.
Как сокращение, компрессор может передать только C и значение флагов нуля, если локальный кортеж IC, который будет передан, эквивалентен элементу ic_All, и никакой другой элемент ic_All не определяет тот же самый class C. В этом случае декомпрессор должен вести себя точно, как будто все четыре компонента кортежа были явно переданы.
(Если все четыре компонента локального кортежа передаются, и значение флагов, которое будет передано, является фактически нулем, значение, 0x00010000 должен быть передан вместо нуля для флагов.)
Часто, компрессор не должен будет передать локальные кортежи IC вообще, так как набором четырех кортежей, которые будут сохранены в атрибуте InnerClasses class, будет точно ic_Relevant(X) без требуемой корректировки. Если посторонние четыре кортежа (вне требуемых минимизированным постоянным пулом) будут сочтены во вводе файлом class, то некоторые локальные кортежи IC будут необходимы (с нулевыми флагами), чтобы обеспечить локальные "корни" для дополнительных записей InnerClasses. Это может произойти, если компилятор требует записи InnerClasses для class, упомянутого только в подписи. Компрессоры обязаны предсказывать, какие классы требуют таких дополнительных локальных корней, и передают только неожиданные четыре кортежа.
class_metadata_bands:
class_RVA_bands
class_RIA_bands
field_metadata_bands:
field_RVA_bands
field_RIA_bands
method_metadata_bands:
method_RVA_bands
method_RIA_bands
method_RVPA_bands
method_RIPA_bands
method_AD_bands
class_RVA_bands:
*class_RVA_anno_N :UNSIGNED5 [...]
*class_RVA_type_RS :UNSIGNED5 [...] (cp_Signature)
*class_RVA_pair_N :UNSIGNED5 [...]
*class_RVA_name_RU :UNSIGNED5 [...] (cp_Utf8)
*class_RVA_T :BYTE1 [...]
*class_RVA_caseI_KI :UNSIGNED5 [...] (cp_Int)
*class_RVA_caseD_KD :UNSIGNED5 [...] (cp_Double)
*class_RVA_caseF_KF :UNSIGNED5 [...] (cp_Float)
*class_RVA_caseJ_KJ :UNSIGNED5 [...] (cp_Long)
*class_RVA_casec_RS :UNSIGNED5 [...] (cp_Signature)
*class_RVA_caseet_RS :UNSIGNED5 [...] (cp_Signature)
*class_RVA_caseec_RU :UNSIGNED5 [...] (cp_Utf8)
*class_RVA_cases_RU :UNSIGNED5 [...] (cp_Utf8)
*class_RVA_casearray_N :UNSIGNED5 [...]
*class_RVA_nesttype_RS :UNSIGNED5 [...] (cp_Signature)
*class_RVA_nestpair_N :UNSIGNED5 [...]
*class_RVA_nestname_RU :UNSIGNED5 [...] (cp_Utf8)
class_RIA_bands:
*class_RIA_anno_N :UNSIGNED5 [...]
(analogous to class_RVA_bands)
field_RVA_bands:
*field_RVA_anno_N :UNSIGNED5 [...]
(analogous to class_RVA_bands)
field_RIA_bands:
*field_RIA_anno_N :UNSIGNED5 [...]
(analogous to field_RVA_bands)
method_RVA_bands:
*method_RVA_anno_N :UNSIGNED5 [...]
(analogous to class_RVA_bands)
method_RIA_bands:
*method_RIA_anno_N :UNSIGNED5 [...]
(analogous to method_RIA_bands)
method_RVPA_bands:
*method_RVPA_param_NB :BYTE1 [...]
*method_RVPA_anno_N :UNSIGNED5 [...]
(analogous to method_RVA_bands)
method_RIPA_bands:
*method_RIPA_param_NB :BYTE1 [...]
*method_RIPA_anno_N :UNSIGNED5 [...]
(analogous to method_RVPA_bands)
method_AD_bands
*method_AD_T :BYTE1 [...]
*method_AD_caseI_KI :UNSIGNED5 [...] (cp_Int)
*method_AD_caseD_KD :UNSIGNED5 [...] (cp_Double)
*method_AD_caseF_KF :UNSIGNED5 [...] (cp_Float)
*method_AD_caseJ_KJ :UNSIGNED5 [...] (cp_Long)
*method_AD_casec_RS :UNSIGNED5 [...] (cp_Signature)
*method_AD_caseet_RS :UNSIGNED5 [...] (cp_Signature)
*method_AD_caseec_RU :UNSIGNED5 [...] (cp_Utf8)
*method_AD_cases_RU :UNSIGNED5 [...] (cp_Utf8)
*method_AD_casearray_N :UNSIGNED5 [...]
*method_AD_nesttype_RS :UNSIGNED5 [...] (cp_Signature)
*method_AD_nestpair_N :UNSIGNED5 [...]
*method_AD_nestname_RU :UNSIGNED5 [...] (cp_Utf8)
Как средство пониманию расположения метаданных, вот краткое описание каждой из полос метаданных метода, как использующийся classfiles, которые выполняют JSR 175. class и полевые полосы метаданных функционируют похожим способом.
Отметьте, что JSR 175 не позволяет встроенные ссылки на записи CONSTANT_Class, даже там, где ссылка на class требуется. Вместо этого JSR 175 требует, чтобы ссылки на классы были закодированы как полевые подписи. (Их имена заключаются в скобки 'L' и';'.) Архив Pack200 передает все такие значения как ссылки в cp_Signature, не cp_Class.
Для каждого использования атрибута аннотации параметра, полосы method_RVPA_param_NB или полосы method_RIPA_param_NB (для невидимых аннотаций) передает байт без знака, указывающий на количество параметра. Для каждого использования атрибута аннотации непараметра, полосы method_RVA_anno_N или полосы method_RIA_anno_N (для невидимых аннотаций) передает количество аннотации. Аналогично, для каждого аннотируемого параметра, полосы method_RVPA_anno_N или полосы method_RIPA_anno_N (для невидимых аннотаций) передает количество аннотации.
Для каждой видимой аннотации непараметра полоса method_RVA_type_RS передает тип аннотации, и полоса method_RVA_pair_N передает число который пары задействованного значения аннотации. Аналогичные значения для невидимых аннотаций и аннотаций параметра передаются в полосах method_RIA_type_RS, method_RIA_pair_N, method_RVPA_type_RS, method_RVPA_pair_N, method_RIPA_type_RS, и method_RIPA_pair_N. Для каждой пары задействованного значения, переданной как прямая часть видимой аннотации непараметра, полоса method_RVA_name_RU передает имя элемента. Аналогичные значения для невидимых аннотаций и аннотаций параметра передаются в полосах method_RIA_name_RU, method_RVPA_name_RU, и method_RIPA_name_RU.
Для каждого значения, переданного с видимой аннотацией непараметра, передает ли непосредственно, или косвенно через вложенное значение или аннотацию, полоса method_RVA_T байт, который выбирает формат значения аннотации, и аналогичных значений, передаются в полосах method_RIA_T, method_RVPA_T, method_RIPA_T, и (для значений по умолчанию аннотации) method_AD_T, Прямое использование этих полос тега значения считается, суммируя значения соответствующей предыдущей полосы парного количества (method_RVA_pair_N, и т.д.). Это количество также включает сумму соответствующей следующей вложенной полосы парного количества (method_RVA_nestpair_N, и т.д.) и вложенных полос длины массива (method_RVA_casearray_N, и т.д.).
Начиная с тех последних сумм, прибывших от обратных вызовов в расположение атрибута, они не могут быть непосредственно вычислены декомпрессором, но об их сумме сообщает компрессор как элемент method_attr_calls. (Отметьте, что последней вызываемой в каждом расположении метаданных является цель двух обратных вызовов изнутри себя.), Что полоса содержит, они назад вызывают счета для method_RVA_T, method_RIA_T method_RVPA_T, method_RIPA_T method_AD_T, в том порядке. Если нет никаких возникновений атрибута метаданных метода, то соответствующий обратный вызов опускается. (Таким образом есть до пяти обратных количеств вызова, переданных для метаданных метода.), Если там определяются с помощью компрессора рекурсивные разметки, используемые в архиве, их обратные количества вызова следуют за счетами для метаданных в method_attr_calls.
Для каждого тега значения 'B', 'C', 'я', 'S', или 'Z', есть соответствующий элемент, переданный в method_RVA_caseI_KI, который предоставляет значение как cp_Int ссылку. Аналогичные целочисленные ссылки в пределах невидимого и аннотаций параметра и значений по умолчанию аннотации передаются в полосах method_RIA_caseI_KI, method_RVPA_caseI_KI, method_RIPA_caseI_KI, и method_AD_caseI_KI. Для каждого тега значения 'e' полосы method_RVA_caseet_RS и method_RVA_caseec_RU передают подпись class и имя элемента постоянного перечисления как ссылки в cp_Signature и cp_Utf8. Для каждого тега значения '[', полоса method_RVA_casearray_N передает длину вложенного массива значения. Для каждого тега значения, полосы method_RVA_nesttype_RS и method_RVA_nestpair_N передают class signtaure вложенной аннотации и числа ее пар. Для каждой пары в такой вложенной аннотации полоса method_RVA_nestname_RU передает имя пары.
Полосы в следующей таблице передают ссылки пула соответственно-типизированной-константы для каждого происшествия определенных символов тега.
| Тег (и) | Полоса | Ссылка |
|---|---|---|
| 'B','C','I','S','Z' | method_RVA_caseI_KI | cp_Int |
| 'D' | method_RVA_caseD_KD | cp_Double |
| 'F' | method_RVA_caseF_KF | cp_Float |
| 'J' | method_RVA_caseJ_KJ | cp_Long |
| 'c' | method_RVA_casec_RS | cp_Signature |
| 'e' |
method_RVA_caseet_RS method_RVA_caseec_RU |
cp_Signature cp_Utf8 |
| 's' | method_RVA_cases_RU | cp_Utf8 |
Аналогичные группы полос передают значения в пределах других четырех типов аннотации метода, и в пределах видимых и невидимых аннотаций классов и полей.
Вот полосы, которые передают инструкции байт-кода:
bc_bands:
*bc_codes :BYTE1 [...]
*bc_case_count :UNSIGNED5 [COUNT(switch,*bc_codes)]
*bc_case_value :DELTA5 [...]
*bc_byte :BYTE1 [...]
*bc_short :DELTA5 [...]
*bc_local :UNSIGNED5 [...]
*bc_label :BRANCH5 [...]
*bc_intref :DELTA5 [...] (cp_Int)
*bc_floatref :DELTA5 [...] (cp_Float)
*bc_longref :DELTA5 [...] (cp_Long)
*bc_doubleref :DELTA5 [...] (cp_Double)
*bc_stringref :DELTA5 [...] (cp_String)
*bc_loadablevalueref :DELTA5 [...] (cp_LoadableValue)
*bc_classref :UNSIGNED5 [...] (current class or cp_Class)
*bc_fieldref :DELTA5 [...] (cp_Field)
*bc_methodref :UNSIGNED5 [...] (cp_Method)
*bc_imethodref :DELTA5 [...] (cp_Imethod)
*bc_indyref :DELTA5 [...] (cp_InvokeDynamic)
*bc_thisfield :UNSIGNED5 [...] (cp_Field, only for current class)
*bc_superfield :UNSIGNED5 [...] (cp_Field, only for current super)
*bc_thismethod :UNSIGNED5 [...] (cp_Method, only for current class)
*bc_supermethod :UNSIGNED5 [...] (cp_Method, only for current super)
*bc_initref :UNSIGNED5 [...] (cp_Field, only for most recent new)
*bc_escref :UNSIGNED5 [COUNT(ref_escape,*bc_codes)] (cp_All)
*bc_escrefsize :UNSIGNED5 [...]
*bc_escsize :UNSIGNED5 [...]
*bc_escbyte :BYTE1 [...]
Чтобы передать инструкции байт-кода более эффективно, некоторые инструкции могут быть переписаны в форму передачи. ldc, ldc_w, и ldc2_w байт-коды должен быть переписан компрессором в операции со строгим контролем типов; см. ниже. Некоторый getstatic, putstatic, getfield, putfield, invokevirtual, invokespecial, и invokestatic байт-коды могут (в опции компрессора) быть переписанными в более специализированные и компактные формы, которые, потому что они контекстно-зависимы, выбирают их операнды из меньшего набора возможностей.
Во всех случаях первый байт каждой инструкции (возможно, переписанный) определяется байтом, переданным в bc_codes. Все байты операнда декодируются в операнды и передаются в отдельных полосах согласно типу закодированного операнда. Дополнительные байты инструкций переключателя и последние два байта invokeinterface инструкций отбрасываются, потому что они могут быть восстановлены декомпрессором.
"Широкий" префиксный байт-код передается в bc_codes. Инструкция после префикса декодируется в его широком формате, но (кроме в случае iinc) это передается таким же образом, и использование тех же самых полос, как нормальный (неширокий) формат. Широкий формат iinc инструкции использует bc_short вместо bc_byte, чтобы передать его второй операнд.
Каждая команда перехода передает свою цель (или цели, в случае переключателей) в полосе bc_label, закодированной как различие между перенумерованным BCI цели ответвления и перенумерованным BCI ответвления непосредственно. (Изменение нумерации, столь же описанное выше, нумерует первую инструкцию как нуль, второе как один, и т.д.) Различия между перенумерованными BCI очень компактны; основное кодирование BRANCH5 также использует в своих интересах факт, что большинство таких различий положительно, потому что большинство ответвлений является прямыми ответвлениями.
Постепенно увеличенные переносы полосы bc_classref индексируют в cp_Class постоянный пул. Постепенное увеличение (единицей) резервирует нуль кода, который всегда обращается к текущему class. (Это обеспечивает компактную форму для наиболее распространенной ссылки class, которая является самоссылкой.)
bc_byte и фиксированный перенос полос bc_short - измеренные операнды. Эти операнды не передаются как общие 32-разрядные целые числа, потому что их инструкции, как первоначально определено, уже служат особенно сжатыми форматами передачи. Целочисленные значения этих полос обрабатываются как без знака, даже когда они семантически подписываются как операнды. Полоса bc_byte используется для последних операндов multianewarray и нешироких iinc инструкций, и для операндов bipush и newarray инструкций. Полоса bc_short используется для последних операндов широких iinc инструкций, и для операндов sipush инструкций.
Полосы bc_intref, bc_floatref, bc_longref, bc_doubleref, bc_stringref, bc_fieldref, bc_methodref, и bc_imethodref передают показатели преломления обыкновенной волны в постоянные пулы cp_Int, cp_Float, cp_Long, cp_Double, cp_String, cp_Field, cp_Method, и cp_Imethod, соответственно.
Полоса передачи bc_indyref индексирует в cp_InvokeDynamic для инструкций invokedynamic.
Полоса передачи bc_loadablevalueref индексируют в постоянную группу пула cp_LoadableValue, так, что нуль, обращается к первой константе CONSTANT_Integer и так далее. Это сразу передается после bc_stringref. (Как правило, эта полоса используется для констант cp_MethodHandle.)
(Инструкции invokedynamic могут только появиться, когда #archive_majver 170 или выше. Они и их связанные постоянные типы пула были представлены в недавних версиях формата classfile.)
Для каждого lookupswitch или tableswitch инструкции, число случаев передается в bc_case_count, и метка значения по умолчанию передается в bc_label. Каждое значение случая и цель случая lookupswitch передаются в bc_case_value и bc_label, соответственно. Начальное значение случая tableswitch передается в bc_case_value, и каждая из его целей случая передается в bc_label.
Если у первого байта инструкции есть код в диапазоне [202.. 255], или если операнды инструкции не могут быть проанализированы согласно требованиям этой спецификации, это - нестандартная инструкция. Каждый байт нестандартной инструкции должен быть передан в специальном конверте, чтобы попросить декомпрессор принять это буквально. Конверт состоит из серии "byte_escape" и "ref_escape" кодов операций в полосе bc_code, соответствующих размеров в bc_escsize и bc_escrefsize, байтах в bc_escbyte, и постоянных ссылках пула в bc_escref. Каждой постоянной ссылки пула в нестандартной инструкции нужно оставить и передана в полосе bc_escref. Каждый ref_escape обертывает одну такую постоянную ссылку пула размера до четырех байтов. Переданная ссылка является индексированием в cp_All, так, что обнулите, обращается к первой константе CONSTANT_Utf8, и так далее.
| Escape Код операции |
Размер Операнд |
Операнд Размер |
Размер Полоса |
Данные Полоса |
Код операции Значение |
|---|---|---|---|---|---|
| byte_escape | N <=255 | N байты | bc_escsize | bc_escbyte | 254 |
| ref_escape | N <=2 | N байты | bc_escrefsize | bc_escref | 253 |
Нет никакой потребности в специальной передаче никакого другого типа операнда в пределах нестандартных инструкций, потому что формат Pack200 точно сохраняет все байты инструкции за исключением постоянных ссылок пула. Эта спецификация не адресует средства, которыми компрессоры адаптируются к присутствию и формату нестандартных инструкций. Это просто требует, чтобы декомпрессоры декодировали их правильно.
Вот таблица особенно переписанных форм передачи для инструкций:
я| Исходный Инструкция |
Операнд | Передача Инструкция |
Перезапись Необходимый? |
Код операции |
|---|---|---|---|---|
| ldc | cp_String [я] | sldc | да | 18 (=ldc) |
| ldc | cp_Class [я] | cldc | да | 233 |
| ldc | cp_Int [я] | ildc | да | 234 |
| ldc | cp_Float [я] | fldc | да | 235 |
| ldc_w | cp_String [я] | sldc_w | да | 19 (=ldc_w) |
| ldc_w | cp_Class [я] | cldc_w | да | 236 |
| ldc_w | cp_Int [я] | ildc_w | да | 237 |
| ldc_w | cp_Float [я] | fldc_w | да | 238 |
| ldc2_w | cp_Long [я] | lldc2_w | да | 20 (=ldc2_w) |
| ldc2_w | cp_Double [я] | dldc2_w | да | 239 |
| ldc | cp_LoadableValue [я] | qldc | да | 240 |
| ldc_w | cp_LoadableValue [я] | qldc_w | да | 241 |
| getstatic | (этот элемент class) | getstatic_this | нет | 202 |
| putstatic | (этот элемент class) | putstatic_this | нет | 203 |
| getfield | (этот элемент class) | getfield_this | нет | 204 |
| putfield | (этот элемент class) | putfield_this | нет | 205 |
| invokevirtual | (этот элемент class) | invokevirtual_this | нет | 206 |
| invokespecial | (этот элемент class) | invokespecial_this | нет | 207 |
| invokestatic | (этот элемент class) | invokestatic_this | нет | 208 |
| aload_0; getstatic | (этот элемент class) | aload_0_getstatic_this | нет | 209 |
| aload_0; putstatic | (этот элемент class) | aload_0_putstatic_this | нет | 210 |
| aload_0; getfield | (этот элемент class) | aload_0_getfield_this | нет | 211 |
| aload_0; putfield | (этот элемент class) | aload_0_putfield_this | нет | 212 |
| aload_0; invokevirtual | (этот элемент class) | aload_0_invokevirtual_this | нет | 213 |
| aload_0; invokespecial | (этот элемент class) | aload_0_invokespecial_this | нет | 214 |
| aload_0; invokestatic | (этот элемент class) | aload_0_invokestatic_this | нет | 215 |
| getstatic | (элемент class высшего качества) | getstatic_super | нет | 216 |
| putstatic | (элемент class высшего качества) | putstatic_super | нет | 217 |
| getfield | (элемент class высшего качества) | getfield_super | нет | 218 |
| putfield | (элемент class высшего качества) | putfield_super | нет | 219 |
| invokevirtual | (элемент class высшего качества) | invokevirtual_super | нет | 220 |
| invokespecial | (элемент class высшего качества) | invokespecial_super | нет | 221 |
| invokestatic | (элемент class высшего качества) | invokestatic_super | нет | 222 |
| aload_0; getstatic | (элемент class высшего качества) | aload_0_getstatic_super | нет | 223 |
| aload_0; putstatic | (элемент class высшего качества) | aload_0_putstatic_super | нет | 224 |
| aload_0; getfield | (элемент class высшего качества) | aload_0_getfield_super | нет | 225 |
| aload_0; putfield | (элемент class высшего качества) | aload_0_putfield_super | нет | 226 |
| aload_0; invokevirtual | (элемент class высшего качества) | aload_0_invokevirtual_super | нет | 227 |
| aload_0; invokespecial | (элемент class высшего качества) | aload_0_invokespecial_super | нет | 228 |
| aload_0; invokestatic | (элемент class высшего качества) | aload_0_invokestatic_super | нет | 229 |
| invokespecial | (этот class <init>) | invokespecial_this_init | нет | 230 |
| invokespecial | (class высшего качества <init>) | invokespecial_super_init | нет | 231 |
| invokespecial | (новый class <init>) | invokespecial_new_init | нет | 232 |
Использование инструкций qldc И qldc_w индексирует в постоянную группу пула cp_LoadableValue, чтобы выбрать произвольные загружаемые константы. (Эти инструкции могут только появиться, когда #archive_majver 170 или выше. Ранние версии формата classfile не требуют их.) Декомпрессоры обязаны принимать любую постоянную ссылку как операнд к одной из этих инструкций, но компрессоры поощряются передать только константы, которые не могут быть закодированы другими разновидностями ldc, определенно элементы cp_MethodHandle и cp_MethodType.
(Отметьте: предыдущая версия этой спецификации, упомянутой переносящие строку разновидности ldc, sldc и sldc_w, как aldc и aldc_w. Несмотря на новые имена, кодовые точки и их интерпретация не изменились. Старые названия осуждаются.)
Каждая инструкция байт-кода содержится class, названным текущим class. Суперклассом (если кто-либо) текущего class является текущий class высшего качества. Операнд дословно новой "новой" инструкции (в том же самом методе) вызывают текущим новым class.
Если инструкция обращается к полю или методу в текущем class, это может (в опции компрессора), переписываются для передачи как соответствующий код операции, записанный с "_this". Аналогично, инструкция, обращающаяся к полю или методу в текущем class высшего качества, может быть переписана как соответствующий код операции, записанный с "_super". В любом случае, если сразу предыдущая инструкция является aload_0 (код операции 42), передача той инструкции может быть подавлена компрессором, и соответствующим кодом операции, записанным с "aload_0 _" выбранный вместо этого; иначе "aload_0 _" разновидность не может быть выбрана.
Если invokespecial инструкция обращается к методу, названному <init> в текущем class, текущем class высшего качества, или текущем новом class, компрессор может хотеть переписывать это как invokespecial_this_init, invokespecial_super_init, или invokespecial_new_init, соответственно.
Поле (resp. метод) операнды переписанных инструкций, записанных с "_this" (но не "_init"), передается в специальной полосе bc_thisfield (resp. bc_thismethod). Нумерация этих операндов определяется, беря последовательность символов в cp_Field (resp. cp_Method) и выбор только элементы текущего class. Получающееся подмножество, не изменяя его порядок, перенумеровывается, запускаясь с нуля. Это обеспечивает компактное отображение маленьких целых чисел к элементам текущего class.
Аналогично, операнды переписанных инструкций, записанных с "_super" (но не "_init"), передаются в bc_superfield или полосе bc_supermethod, и перенумеровываются как подмножество cp_Field или cp_Method, выбирая только элементы текущего class высшего качества.
Наконец, операнды переписанных инструкций, записанных с "_init", передаются в полосе bc_initref, и перенумеровываются как подмножество cp_Method, выбрали согласно соответствующему class (ток, ток супер, или новый ток), и также выбрали, чтобы иметь имя <init>. (Индексирование переданного является обычно очень маленьким; в действительности это выбирает только подпись вызванного метода, и большинство классов обладает только несколькими конструкторами.)
Вот таблица, суммирующая передачу инструкций больше чем одного байта.
| Инструкция | Операнд | Переданный Значение |
Полоса |
|---|---|---|---|
| bipush | (байт) x | x & 0xFF | bc_byte |
| sipush | (короткий) x | x & 0xFFFF | bc_short |
| ildc | cp_Int [я] | я | bc_intref |
| fldc | cp_Float [я] | я | bc_floatref |
| sldc | cp_String [я] | я | bc_stringref |
| qldc | cp_LoadableValue [я] | я | bc_loadablevalueref |
| cldc | текущий class | 0 | bc_classref |
| cldc | cp_Class [я] | i+1 | bc_classref |
| ildc_w | cp_Int [я] | я | bc_intref |
| fldc_w | cp_Float [я] | я | bc_floatref |
| sldc_w | cp_String [я] | я | bc_stringref |
| qldc_w | cp_LoadableValue [я] | я | bc_loadablevalueref |
| cldc_w | текущий class | 0 | bc_classref |
| cldc_w | cp_Class [я] | i+1 | bc_classref |
| lldc2_w | cp_Long [я] | я | bc_long |
| dldc2_w | cp_Double [я] | я | bc_double |
| *load | локальные переменные [я] | я | bc_local |
| *store | локальные переменные [я] | я | bc_local |
| мочить | локальные переменные [я] | я | bc_local |
| iinc | локальные переменные [я] | я | bc_local |
| iinc (не широкий) | (байт) x | x & 0xFF | bc_byte |
| (широкий) iinc | (короткий) x | x & 0xFFFF | bc_short |
| если ** | pc | (дельта/перенумеровывать) | bc_label |
| if_ ** | pc | (дельта/перенумеровывать) | bc_label |
| goto | pc | (дельта/перенумеровывать) | bc_label |
| jsr | pc | (дельта/перенумеровывать) | bc_label |
| goto_w | pc | (дельта/перенумеровывать) | bc_label |
| jsr_w | pc | (дельта/перенумеровывать) | bc_label |
| tableswitch | количество случая | количество | bc_case_count |
| tableswitch | pc значения по умолчанию | (дельта/перенумеровывать) | bc_label |
| tableswitch | первое значение случая | значение | bc_case_value |
| tableswitch | каждый pc случая | (дельта/перенумеровывать) | bc_label |
| lookupswitch | количество случая | количество | bc_case_count |
| lookupswitch | pc значения по умолчанию | (дельта/перенумеровывать) | bc_label |
| lookupswitch | каждое значение случая | значение | bc_case_value |
| lookupswitch | каждый pc случая | (дельта/перенумеровывать) | bc_label |
| новый | текущий class | 0 | bc_classref |
| новый | cp_Class [я] | 1+i | bc_classref |
| newarray | введите код | значение | bc_byte |
| anewarray | текущий class | 0 | bc_classref |
| anewarray | cp_Class [я] | 1+i | bc_classref |
| checkcast | текущий class | 0 | bc_classref |
| checkcast | cp_Class [я] | 1+i | bc_classref |
| instanceof | текущий class | 0 | bc_classref |
| instanceof | cp_Class [я] | 1+i | bc_classref |
| multianewarray | cp_Class [я] | 1+i | bc_classref |
| multianewarray | разряд | разряд & 0xFF | bc_byte |
| getstatic | cp_Field [я] | я | bc_fieldref |
| putstatic | cp_Field [я] | я | bc_fieldref |
| getfield | cp_Field [я] | я | bc_fieldref |
| putfield | cp_Field [я] | я | bc_fieldref |
| invokevirtual | cp_Method [я] | я | bc_methodref |
| invokespecial | cp_Method [я] | я | bc_methodref |
| invokestatic | cp_Method [я] | я | bc_methodref |
| invokeinterface | cp_Imethod [я] | я | bc_imethodref |
| invokedynamic | cp_InvokeDynamic [я] | я | bc_indyref |
| ** _this | this_fields [я] | я | bc_thisfield |
| ** _this | this_methods [я] | я | bc_thismethod |
| ** _super | super_fields [я] | я | bc_superfield |
| ** _super | super_methods [я] | я | bc_supermethod |
| invokespecial_this_init | this_constructors [я] | я | bc_initref |
| invokespecial_super_init | super_constructors [я] | я | bc_initref |
| invokespecial_new_init | new_constructors [я] | я | bc_initref |
Каждое целое число кодируется для передачи как последовательность байта, использующая между одним и пятью байтами, согласно ранее решительному кодированию. Май кодирования основным кодированием для текущей полосы столь же определенной как часть этой спецификации формата архива Pack200, или кодирование может зависеть от информации, переданной перед возникновением закодированного целого числа.
(Отметьте: В этой учетной записи кодировок байты являются неделимыми октетами, которые выражают значения без знака в [0,255].)
| Имя | Диапазон | Значение |
|---|---|---|
| B | [1..5] | максимальная длина байта |
| H | [1..256] | число высоких значений байта |
| L | [0..255] | число значений младшего байта, определенных как (256-ой) |
Учитывая любые два значения B и H, есть кодирование (B, H), который устанавливает взаимно-однозначное соответствие между начальной последовательностью неотрицательных целых чисел, и "кодирование устанавливает" коротких последовательностей байтов.
Кроме того никакая последовательность байта в наборе кодирования не является надлежащим префиксом другой последовательности байта в том же самом наборе. префикс. Это означает, неофициально, что кодировки самоизмеряют, или "parseable".
Кроме того, набор кодирования настолько полон насколько возможно, так, чтобы каждый достаточно долго последовательность байтов началась с уникального префикса байтов, оттянутых из набора кодирования. В частности у каждой последовательности байтов B есть (уникальный) префикс в наборе кодирования для (B, H) кодирование.
Данный (B, H) кодирование, последовательность байтов находится в ее наборе кодирования, если и только если все следующее является истиной:
Как следствие этого определения, набор кодирования быть расцененным как удовлетворяющий это регулярное выражение, с точки зрения высоких и младших байтов:
encoding_set = (high* low) | (high)^B
(Отметьте: В этой спецификации знак-каре '^' обозначает возведение в степень, или регулярных выражений как выше, или чисел.)
Если n является меньше чем B тогда число (B, H), кодировками длины точно n является (H^(n-1) * L). Числом (B, H) кодировки длины точно B является (H^(B-1) * (L+H)). Сумма этих значений для всего n в [1..B] является полным размером набора кодирования для (B, H) кодирование. Это вызывают Картой (B, H) и поэтому определяется как:
Card(B,H) = (L * (1-H^B)/(1-H)) + H^B
if H>1, or else
Card(B,1) = B*255+1
Если H 256, нет никаких младших байтов, и набор кодирования состоит из всех возможных последовательностей точно B байты, и Картой (B, H) является 256^B.
Иначе, набор кодирования состоит из последовательностей различных длин, от 1 до B включительно. В частности есть однобайтовые последовательности L. Мы будем использовать их в другом месте, чтобы закодировать "привилегированные" целые числа самой высокой частоты. Отметьте, что правила кодирования, определенные в другом месте в этом документе, разрабатываются, чтобы производить меньшие целые числа более часто чем большие.
Отметьте, что L может быть просмотрен как параметр "резкости", выражая резкость распределения о нуле математических ожиданий, которые будут закодированы. Чем больший L, тем больше кодирование одобряет дистрибутивы значений, которые являются близко к нулю, и редко отнюдь нет. Больший H оценивает пользу "более плоские" дистрибутивы, до H=256, L=0, который благоприятно кодирует абсолютно случайные данные в пределах диапазона кодирования.
Учитывая последовательность байта N оценивает b [0].. b [N-1], основанное на сортировке определение, данное выше, подразумевает, что декодируемое целочисленное значение этой последовательности байта является основой-H с прямым порядком байтов масштабируемая сумма байтов, и вызывается, Декодируют (B, H; b):
Decode(B,H; b[*]) = Sum[0<=i<N]( b[i] * H^i )
Как следствие этого определения каждая последовательность байта в наборе кодирования соответствует уникально арифметическому целочисленному значению в том диапазоне. Эта корреспонденция может наблюдаться, упорядочивая последовательности байта сначала длиной, и вторая согласно их антилексикографическому порядку (с прямым порядком байтов). Каждый элемент в получающейся последовательности декодирует в ее собственное основанное на нуле, индексируют в пределах последовательности.
Отметьте, что нуль числа всегда кодируется последовательностью нулевых байтов B (если H 256), или иначе единственным нулевым байтом.
Самое большое закодированное арифметическое значение всегда кодируется последовательностью байтов B 255 имеющие значение.
Отметьте, что (B, H) кодировки (1 256), (2 256), и (4 256) идентичны со стандартными представлениями с прямым порядком байтов байтов без знака, 16-разрядных целых чисел без знака, и 32-разрядных целых чисел без знака.
Отметьте, что некоторые могут представить арифметические значения, больше чем 2^31-1 или даже 2^32-1. Это - функция (B, H) кодирование схемы. (Но иногда промежуточные 64-разрядные значения требуются, когда многократные знаковые биты используются, как описано ниже. Правила, данные ниже для подписанных значений, требуют, чтобы компрессор испустил самое простое кодирование, которое будет достаточно, чтобы передать необходимое 32-разрядное целое число, даже если более сложные последовательности произвели бы то же самое 32-разрядное значение после усечения.)
Отметьте, что реализации не всегда свободны усечь промежуточные значения, вычисляя (B, H) кодирующие значения. Однако, финал декодируемые значения (после восстановления знаков) будет всегда помещаться в 32 бита, как описано в следующем разделе.
| Имя | Диапазон | Значение |
|---|---|---|
| B | [1..5] | максимальная длина байта |
| H | [1..256] | число высоких значений байта |
| L | [0..255] | число значений младшего байта, определенных как (256-ой) |
| S | [0..2] | число знаковых битов |
Целое число U полученный из (B, H) кодирование преобразовывается в подписанное 32-разрядное значение X способом, который зависит от параметра S. Этот процесс вызывают преобразованием знака.
Неофициально, преобразование знака выполняется 32-разрядным усечением если S=0. Иначе, биты младшего разряда U все вместе обрабатываются как знаковый бит, так, чтобы X было отрицательно, только если все знаковые биты устанавливаются. Эти два преобразования от U до положительного X и U к отрицательному X являются независимо плотными и монотонными в противоположных направлениях, как определено ниже.
В отличие от этого (B, H) кодирование, (B, H, S) кодирование представляет только числа в определенно определенном диапазоне, который никогда не больше чем [-2^31..2^31-1].
В дальнейшем, для каждого (B, H, S) кодирование, мы определяем Диапазон (B, H, S), и метод, используемый, чтобы представить 32-разрядные подписанные значения с тем кодированием.
(B, H) кодирование последовательности байта не является юридическим вводом к соответствию (B, H, S) кодирование, если это представляет целое число U, который не преобразовывает в диапазон (B, H, S) кодирование. Кроме того, если есть двухбайтовые последовательности, кодирующие значения U1 и U2, который обе карты в ту же самую точку X в подписанном диапазоне, только последовательность байта для меньшего из U1 и U2 является законной.
Таким образом, (B, H, S) у кодирования может быть меньшее количество элементов чем соответствие (B, H) кодирование, из-за недопустимых последовательностей байта кодирования.
Диапазон (B, H, S) кодирование содержит все 32-разрядные целые числа со знаком [-2^31..2^31-1], если Картой (B, H) является 2^32 или больше. (Отрицательные величины представляются 31-разрядным переполнением без знака.), Если кодирование кодирует меньше значений без знака, вершина его диапазона отсекается к 2^31-1, и нижняя часть его диапазона отсекается к -2^31.
Более точно, диапазон (B, H, S) кодирование вызывают Диапазоном (B, H, S) и определяется (частично для S=0) как:
Range(B,H,S) = [-2^31..2^31-1]
if S=0, Card(B,H) >= 2^32, or
Range(B,H,S) = [0..2^31-1]
if S=0, 2^31 < Card(B,H) < 2^32, or else
Range(B,H,S) = [0..Card(B,H)-1]
if S=0, Card(B,H) <= 2^31
Компрессору не позволяют испустить последовательность байта, которая, когда интерпретирующийся согласно текущему кодированию, декодирует к значению за пределами диапазона того кодирования. (Отметьте, что декомпрессоры могут произвести произвольные ответы для codings из диапазона, так как компрессорам не позволяют испустить их. Это позволяет декомпрессорам использовать 32-разрядную арифметику для большинства вычислений, игнорируя возможность нежелательного wraparond.)
Если S> 0, декодирование последовательности байта выполняется сначала, декодируя это как (B, H) кодирование, и затем преобразовывая декодируемое целое число в подписанное 32-разрядное число. Это преобразование знака зависит только от арифметического значения U полученный из (B, H) кодирование, и на значении S. Арифметическое значение должно быть сохранено вне 32 битов точности, если преобразование знака произведет значение в пределах диапазона кодирования. Если количество элементов (B, H) кодированием является 2^32 или больше, (B, H, S), кодирование производит все возможные подписанные 32-разрядные отрицательные величины 32-разрядным усечением промежуточного целого числа без знака. Промежуточная арифметика без знака может быть выполнена (с некоторой заботой) использование 32-разрядных чисел без знака, или это может быть выполнено на 64-разрядных подписанных или числах без знака.
Более точно, работа преобразования знака SignConvert (S; U) определяется как:
SignConvert(S; U) = Cast32(U)
if S==0; or
SignConvert(S; U) = U - Floor(U / 2^S)
if S>0, (U % 2^S) < 2^S-1, Card(B,H) < 2^32
SignConvert(S; U) = Cast32(U - Floor(U / 2^S))
if S>0, (U % 2^S) < 2^S-1, Card(B,H) >= 2^32
SignConvert(S; U) = -Floor(U / 2^S)-1
if S>0, (U % 2^S) == 2^S-1
Преобразование из большого числа без знака отрицательного 32-разрядного числа через перенос является просто знакомым удрученным к подписанному 32-разрядному интервалу. Это может быть определено математически как: Cast32(U) = ((U + 2^31) mod 2^32) - 2^31
Как следствие определения SignConvert(S;U) биты младшего разряда S U функционируют как знаковый бит. В действительности U делится в поле U0 знака (состоящий из битов младшего разряда S) и мантисса U1 (состоящий из всех других битов U).
В этом альтернативном представлении определения SignConvert, если все биты S U0 устанавливаются, то декодируемое подписанное значение - те дополнение U1. (Так как это включает неопределенное число нулевых битов старшего разряда U, получающееся значение арифметически отрицательно.)
Иначе, если некоторые из битов S U0 являются четкими, то мантисса U1 масштабируется числом возможных значений U0 (то есть, (2^2)-1, если S 2), и U0 включается назад.
Это обеспечивает взаимно-однозначное соответствие между некоторой частью арифметического интервала [0..Card(B,H)-1] и Range(B,H,S).
Целые числа, "одобренные" этим кодированием, являются таковыми из маленькой величины, но у них может быть любой знак. Если S один, у кодирования есть сбалансированное число положительных и отрицательных привилегированных значений. Если S два (или больше), кодирование скашивается к положительным числам, но также и одобряет несколько отрицательных чисел. Мы используем такой codings в другом месте, чтобы закодировать значения, такие как смещения ответвления или дельты сортированных главным образом данных, которые обычно положительны, но иногда отрицательны.
Отметьте это, если S=1, это определение преобразования знака эквивалентно сдвигу вправо без знака, сопровождаемому монопольным - или знакового бита со всеми остающимися битами:
SignConvert(1; U) = (U >>> 1) ^ -(U & 1)
Для S> 0, Диапазон (B, H, S) просто определяется как пересечение 32-разрядного подписанного диапазона [-2^31..2^31-1] с набором SignConvert(S; [0..Card(B,H)-1]), полученный поэлементным приложением преобразования знака в каждое арифметически представимое значение (B, H). Поэтому, мы можем завершить определение Диапазона следующим образом:
Range(B,H,S) = [-2^31..2^31-1]
if Card(B,H) >= 2^32, or
Range(B,H,S) = [0..2^31-1]
if S=0, 2^31 < Card(B,H) < 2^32, or else
Range(B,H,S) = [0..Card(B,H)-1]
if S=0, Card(B,H) <= 2^31
Range(B,H,S) = [max( -2^31, min SignConvert(S; Range(B,H,0)) )
.. min( 2^31-1, max SignConvert(S; Range(B,H,0)) )]
(Отметьте: вычисляя границы подписанного кодирования (B, H, S), полезно запустить с самого большого значения без знака М. (B, H, 0) и выполнить преобразование знака на М., M-1, M-2, и т.д., отмечая первое положительное и первую отрицательную величину, с которой встретятся. Они будут содержащими границами диапазона подписанного кодирования.)
Card(B,H) = (L * (1-H^B)/(1-H)) + H^B
Количество элементов (B, H, S) кодирование определяется тем из его диапазона:
Card(B,H,S) = Card Range(B,H,S) <= Card(B,H)
Как определено, диапазон любого кодирования (B, H, S) плотен о нуле и может поэтому быть выражен как закрытый интервал:
Range(B,H,S) = [Min(B,H,S)..Max(B,H,S)] -2^31 <= Min(B,H,S) <= 0 0 < Max(B,H,S) <= 2^31-1
Определенные дополнительные атрибуты могут быть утверждены codings. Кодирование может или быть подписано или нет, и это может быть полнофункциональное кодирование, или кодирование поддиапазона (или ни один).
(B, H, S) кодирование подписывается, если оно может закодировать по крайней мере одну отрицательную величину. Это - истина, если и только если S является ненулевым, или S является нулем, и Карта (B, H) 2^32 или больше.
(B, H, S) кодирование является полным диапазоном, если Диапазоном (B, H, S) является [-2^31..2^31-1].
Кодирование поддиапазона поставляет меньше чем 2^31 отличные значения. Более точно кодирование (B, H, S) является поддиапазоном если Карта (B, H, S) <= 2^31-1. (Некоторые codings не являются ни полным диапазоном, ни поддиапазоном codings.)
Как следствие этих определений, любой кодирующий, для которого B <=3 является кодированием поддиапазона. Дольше codings может также быть поддиапазонами, если они достаточно "резки". Некоторые примеры (4,192,0), (5,32,0), и (5,32,1).
Кроме того, кодирование без знака (4,256,0) является полным диапазоном, как подписанная версия (4,256,1), но не вдвойне подписанная версия (4,256,2).
Кодирование (4,255,0) не является ни поддиапазоном, ни полнофункциональным кодированием, так как его количество элементов 2^31. Это представляет только неотрицательные 32-разрядные целые числа, но его количество элементов не может быть столь представлено.
| Имя | Диапазон | Значение |
|---|---|---|
| B | [1..5] | максимальная длина байта |
| H | [1..256] | число высоких значений байта |
| L | [0..255] | число значений младшего байта, определенных как (256-ой) |
| S | [0..2] | число знаковых битов |
| D | [0..1] | порядок кодирования дельты |
Если D является нулем, никакой differencing не выполняется, и (B, H, S, 0), кодирование во всех отношениях идентично соответствию (B, H, S) кодирование. Если D один, значения кодируются с точки зрения их последовательных различий.
(Отметьте: Последовательности, которые главным образом монотонно возрастают, будут часто благоприятно кодироваться, используя дельту без знака codings формы (5, H, 0,1).)
Предположите последовательность значений X [мне] дают для некоторого диапазона меня в [0.. N-1]. Эта последовательность будет представимой (B, H, S, 1) кодирование, только если (B, H, S) кодирование является поддиапазоном или полнофункциональным кодированием. (Если это ни один не, там является не законным (B, H, S, 1) кодирование.)
Последовательность X [я] буду представимым, только если есть серия "значений дельты" D [я], частичные суммы которого Sum[j<=i](D[j]) может представить значения X [я].
Каждый (B, H, S, 1) у кодирования есть диапазон, в котором весь X [я] оцениваю, должен лечь. Этот диапазон определяется как Range(B,H,S,1) = Range(B,H,0). Диапазон кодирования дельты (B, H, S, 1) содержит отрицательные числа, только если это основано на полнофункциональном кодировании (B, H, S). Иначе, кодирование дельты может только представить неотрицательные числа. Практически, это не серьезное ограничение, так как практически очень немного элементов полосы отрицательны.
Частичной Сумме сумм [j <=i] (D [j]) позволяют оставить диапазон, но финал X [я] оцениваю, всегда возвращаются в диапазон, добавляя или вычитая кратное число Диапазона Карты (B, H, 0).
Более точно:
X[i] = Sum[j<=i](D[j]) mod Card(B,H,0)
if (B,H,S) is sub-range
X[i] = (int32) Sum[j<=i](D[j])
if (B,H,S) is full-range
(Здесь, бросок к int32 обозначает усечение к 32 битам.) Отметьте, что реализации могут просто проигнорировать 32-разрядный перенос, вычисляя частичные суммы, если кодирование является полным диапазоном. Иначе, больше заботы должно быть проявлено, чтобы возвратить частичные суммы в диапазон, вычитая или добавляя сеть магазинов количества элементов диапазона. Кроме того, 32-разрядный перенос может быть опасностью для диапазонов размера 2^30 или больше. Возможно реализовать это использование только 32-разрядная подписанная арифметика.
Компрессор может выбрать использовать основанное на совокупности преобразование кодирования в таких случаях. Это преобразование берет последовательность S арифметики N, оценивает и преобразовывает это в три последовательности значения:
Каждая из этих последовательностей (F, T, и U) поочередно обрабатывается как поддиапазон, и передается с независимым кодированием. Каждое ненулевое значение в T индексирует значение от F, в то время как каждое нулевое значение в T выбирает (чтобы) значение из U:
S[i] = F[T[i]-1]
if T[i] != 0
U = { S[i] such that T[i] == 0 }
"Центральное значение" X из F определяется как тот элемент F, который является арифметически самым близким к нулю. Если F содержит и положительное X и отрицательный-X минимального абсолютного значения, то-X определяется как центральное значение. (То есть, знак минус является схемой разрешения конфликтов. Центральное значение выбирается, чтобы иметь благоприятное кодирование.)
(Отметьте, что реализации могут сравнить значения для центрированности при использовании 32-разрядного подписанного международного выражения (X>>31)^(X<<1) как ключ сравнения без знака.)
Допустимое значение сигнальной метки является или центральным значением F, или последним значением F. Таким образом, анализируя F, декомпрессор должен искать повторение или центрального значения (до сих пор) или сразу предыдущего значения.
Позвольте K быть числом значений в F, игнорируя повторение значения сигнальной метки. В следующей полосе значения в [1..K] отнесутся (поскольку 1 источник индексирует) к соответствующим элементам F.
Каждый элемент T является маркером или для привилегированного или для непривилегированного значения, закодированного в арифметическом диапазоне [0..K]. Каждое ненулевое значение соответствует, чтобы к элементу F, и производит то привилегированное значение. Каждое нулевое значение в T является заполнителем для "непривилегированного" значения, которое все еще неизвестно.
Как упомянуто выше, каждый элемент F должен быть упомянут по крайней мере одним элементом T. Таким образом, следующие два набора должны быть тем же самым:
{ F[T[i]-1] such that T[i] != 0 }
{ F[j] }
Статистические данные последовательности T довольно благоприятны для компактного кодирования в подходящем (B, H) схема, предполагая что кодер сделанный хороший выбор для содержания F. Вообще говоря, обычно происходящим входным значениям нужно дать ранние позиции в F.
Жадный алгоритм мог сортировать входные значения числом возникновений и поместить наиболее распространенные значения впереди F. Это, вероятно, произвело бы улучшенное кодирование для ввода. Такие методы ни не передаются под мандат, ни обескураживаются этой спецификацией.
Взятый вместе, элементы F и U, выбранного элементами T, должны быть идентичными в значении и упорядочить к вводу преобразования совокупности.
Декомпрессор может тогда считать F в память, считать T в память, и затем сделать вторую передачу по T, преобразовывая символические стоимости, или обращаясь к F или читая из U по мере необходимости.
Адаптивный метод кодирования обрабатывает эту ситуацию, позволяя последовательности значения быть разделенным (эффективно в поддиапазоны) с независимым кодированием, используемым локально в каждой части.
Адаптивный метод кодирования определяется количеством K, метод A кодирования, который будет использоваться, чтобы закодировать коэффициенты теплопроводности, и другой метод B кодирования, который обработает остальную часть значений.
Так как полосы измеряются контекстом, когда адаптивный метод кодирования будет применен к байтам закодированной полосы, метод будет обеспечен заранее с количеством N значений, чтобы декодировать. Таким образом, после того, как метод A декодировал коэффициенты теплопроводности, метод B будет использоваться, чтобы декодировать остальную часть (N-K) значения в полосе.
Любой компрессор может выбрать не обеспечивать спецификатор кодирования полосы, когда основное кодирование полосы управляет передачей элементов. Если кодирование первого элемента полосы при основном кодировании случайно, кажется, спецификатор кодирования полосы, компрессор обязывается передать явный спецификатор кодирования полосы, который вновь подтверждает основное кодирование полосы. Это редко, потому что (столь же отмеченный ниже) полоса, кодирующая спецификаторы, представляет себя как отрицательные числа в основном кодировании, и отрицательные числа редки в большинстве полос.
BandCodingSpecifier:
(Default | BHSDCode | RunCode | PopCode)
BHSDCode:
CanonicalBHSDCode | ArbitraryBHSDCode
CanonicalBHSDCode:
( '(1,256,0)' | '(1,256,1)' | ... )
ArbitraryBHSDCode:
'arb' ( B H S D )
B, H, S, D:
Integer
RunCode:
'run' K ACode BCode
K:
Integer
ACode:
(Default | BHSDCode | PopCode)
BCode:
(Default | BHSDCode | RunCode | PopCode)
PopCode:
'pop' ( FCode TCode UCode )
FCode:
(Default | BHSDCode | RunCode)
TCode:
(Default | BHSDCode | RunCode)
UCode:
(Default | BHSDCode | RunCode)
Integer:
( '0' | '1' | ... )
Default:
'default'
Отметьте, что адаптивные методы кодирования (нетерминалы "RunCode") могут быть объединены в цепочку через нетерминальное "BCode", но не могут быть вложены непосредственно через нетерминальное "ACode". (Поскольку грамматика показывает, они могут быть вложены косвенно через нетерминальное "PopCode".) Кроме того, методы кодирования совокупности могут содержать адаптивные методы кодирования, и наоборот. Однако, хотя грамматика не показывает этот факт, методы кодирования совокупности не должны быть вложены, даже косвенно.
Не все возможные целочисленные значения K и L являются одинаково хорошо выразимыми. Намеченные значения K соразмерны с окнами компрессора, и намеченные значения L являются параметрами резкости для кодировок BHS.
Мы обозначаем приложение S в контексте N и D как "S (N, D)". Это приложение декодирует до элементов N переданных данных полосы.
Непосредственно перед тем, как полоса получается, декомпрессор знает ожидаемую длину полосы N и метод D кодирования значения по умолчанию, определенный статически как основное кодирование полосы. Декомпрессор тогда читает нуль или больше байтов, которые составляют спецификатор кодирования полосы, и декодирует элементы N данных полосы, основанных на спецификаторе кодирования полосы.
Когда спецификатор кодирования является 'значением по умолчанию', N значения декодируются, используя значение по умолчанию, кодирующее D, который является основным кодированием полосы. (Это правило необходимо, если первый элемент полосы, кажется, представляет непустой спецификатор кодирования. Такой спецификатор кодирования значения по умолчанию является единственным видом, который компрессор обязывается испустить; остальные являются все дополнительными.)
Когда спецификатор кодирования является другим BHSDCode, N значения декодируются, используя то кодирование. Окружающее значение по умолчанию D игнорируется.
Когда спецификатор кодирования является 'выполнением' K, ACode, BCode, два шага делаются. Во-первых, спецификатор ACode является данным контролем, как ACode (K, D). Таким образом, N временно устанавливается в K. Во-вторых, спецификатор BCode является данным контролем как BCode (N-K, D). (Отметьте: Если N будет бесконечностью, то N-K также будет бесконечностью.) В обоих шагах D остается неизменным, так, чтобы возникновения 'значения по умолчанию' для ACode или BCode заставили D использоваться.
Это недопустимо для спецификатора кодирования 'выполнения', чтобы определить K нуля, или для этого, чтобы использоваться, чтобы декодировать выполнение K или меньшего количества значений.
Когда спецификатор кодирования является 'выталкиванием' FCode, TCode, UCode, три шага делаются. Во-первых, FCode применяется как FCode (бесконечность, D). Декодирование F оценивает остановки, когда с первым двойным значением встречаются. (Как определено в разделе выше по кодированию совокупности, то двойное значение действия как сигнальная метка, и должно сразу быть или самое "центральное" чтение значения, или иначе значение до значения сигнальной метки.) Позволяют K быть числом уникальных декодируемых значений.
Во время декодирования значений F FCode каждый спецификатор 'выполнения' в FCode должен исчерпать свое количество 'K', не декодируя значение сигнальной метки. Таким образом, сигнальная метка должна декодироваться последним простым BHSD, кодирующим в FCode.
Во втором шаге различное кодирование используется TCode, так как значения T, как ожидают, будут плотным кодированием. TCode применяется как TCode (N, D), и маркеры читаются, которые определяют значения полосы, которые будут поставлены. (Отметьте, что 'выталкивать' метод кодирования может только быть применен, если предоставленное значение N конечно. Это будет истиной, так как единственные полосы, которые читаются с бесконечным N, являются полосами байта, такими как bc_codes.) Позволяют Z быть числом, обнуляет декодируемое использование TCode.
Третий шаг должен использовать UCode, чтобы декодировать значения Z, используя исходную кодировку по умолчанию D. UCode применяется как U (Z, D). Получающаяся полоса производится из последовательности T, как задокументировано выше, заменой обнуляет в последовательности T последовательными значениями U, и замене других элементов последовательности T индексированными в последовательности F.
Это недопустимо для 'выталкивать' спецификатора кодирования, который будет использоваться, чтобы декодировать выполнение никаких значений, или бесконечного числа значений. Если Z (число непривилегированных значений) является нулем, это недопустимо для UCode, чтобы быть чем-либо кроме 'значения по умолчанию'.
Общий спецификатор кодирования полосы 'значения по умолчанию' кодируется в пути, который часто не требует никаких дополнительных байтов. Если у полосы нет никаких элементов, никакой парсинг вообще не делается. Иначе, если кодировка по умолчанию полосы имеет переменную длину, декомпрессор обязывается декодировать одно значение X от начальных байтов полосы, используя значение по умолчанию полосы, кодирующее D. Если возможный, значение X преобразовывается в XB значения байта без знака, который берется, чтобы быть первым байтом спецификатора кодирования полосы, и X будет отброшен. Иначе, спецификатор кодирования полосы берется, чтобы быть 'значением по умолчанию', и таким образом, D применяется ко всей полосе, включая байты, которые произвели начальное значение X.
D должен иметь форму (B, H, S) или (B, H, S, D), где B> 1 и H <256. Значение является D, не важно декодированию первого значения, и декодирование X делается, используя (B, H, S, 0). Если S не является нулем, и если значение X находится в диапазоне [-256..-1], байт спецификатора кодирования, XB определяется, поскольку XB = (-1-X), и X отбрасывается. Иначе, если S является нулем, и если значение X находится в диапазоне [(256-ое).. (511-ый)], байт спецификатора кодирования XB определяется, поскольку XB = (X-(256-H)), и X отбрасывается. Иначе, нет байта спецификатора кодирования, XB, и X является первым значением полосы, как описано выше.
Значение XB, если произведено, принимается, чтобы быть начальным байтом спецификатора кодирования, предшествующего фактическим данным полосы. Этот спецификатор анализируется, запускаясь с XB, и продолжаясь (в случае необходимости) с байтами байтов, взятыми от band_headers. Проанализированный спецификатор тогда используется, чтобы управлять декодированием, запускающимся в следующем байте, всех элементов полосы.
Если полоса действительно запускает с элемента X1 в диапазоне ([-256..-1] или [L,L+255]), который требует производства полосы specififer байт, XB, но компрессор хочет использовать кодировку по умолчанию, компрессор обязан определять заголовок полосы, чтобы X1 не вводят в заблуждение декомпрессор. Если компрессор хочет сохранить кодирование значения по умолчанию, он должен в таких случаях определять явный спецификатор кодирования 'значения по умолчанию', используя значение XB нуля (как определено ниже). Этот нулевой XB передается, в зависимости от кодировки по умолчанию как X значений-1 (обычно байт 1) или L (обычно байты 192,0).
(Непосредственное следствие этого проекта - то, что у полос байта никогда не может быть кодировок не по умолчанию, но все другие полосы могут, так как у всех других полос есть значение по умолчанию encodigns, которые являются переменной длиной и имеют большой динамический диапазон. Значения "escape", выбранные для X, редки практически, таким образом, они обычно не путаются с реальными данными полосы. Добавление дополнительного нулевого значения, чтобы вновь подтвердить значение по умолчанию будет всегда стоить одного дополнительного байта перед фактическими данными полосы, и никакими дополнительными байтами в полосе band_headers. Вообще, кодирование явных, X значений будут всегда требовать двух байтов, если S будет нулем, и самое большее два байта, если S не является нулем.)
band_headers полосы передает неначальные байты заголовка полосы (если любой) каждой полосы, у которой есть заголовок полосы. Порядок передачи является непротиворечивым с полным порядком всех полос в архиве, как дано в грамматике полосы существующей спецификации. Длина band_headers независимо определяется (как #band_headers_size) в заголовке архива. (Это должно быть четким, что декомпрессор должен найти конец band_headers прежде, чем это сможет считать дальнейшие полосы.)
Таким образом кодирование спецификатора кодирования состоит из последовательности байтов: начальный байт XB, и нуль или больше неначальных байтов, взятых от band_headers. Кодировки небольшого языка, определенного в предыдущем разделе, следующие. Кодирование 'значение по умолчанию' является нулевым байтом. Из всех возможных кодировок BHSDCode последовательность 115 канонических кодировок (определенный ниже) выбирается, чтобы покрыть ожидаемый диапазон использования. BHSDCode представляется как единственный байт, значение которого является индексированием (на основе 1) из выбранного канонического кодирования.
Enc{default} = (0)
Enc{CanonicalBHSDCode} = value in [1..115]
Специальное значение 116 представляет произвольное, возможно неканонический код BHSD, описанный в следующем байте.
Enc{ arb ( B H S D ) } =
116
& (D:[0..1] + 2*S[0..2] + 8*(B:[1..5]-1))
& (H[1..256]-1):
Значение B должно быть в диапазоне [1.. 5]. Значение S должно быть в диапазоне [0.. 2]. Значение H должно быть в диапазоне [1.. 256]. Значение D должно быть в диапазоне [0.. 1]. (Эти диапазоны являются содержащими.), Кроме того, если B 1, H должен быть 256, и если H 256, B не должен быть 5. Кодировки конструкции 'выполнения' начинаются с байта в [117.. 140], и может сопровождаться дополнительным Кбайтом байта и затем одним или двумя спецификаторами кодирования ACode и BCode. Смещение от 117 представляет поразрядный следующие данные:
Enc{ run ( K ACode BCode ) } =
(117 + (KX:[0..3]) + 4*(KBFlag:[0..1]) + 8*(ABDef:[0..2]))
& KB: one of [0..255] if KBFlag=1
& Enc{ ACode } if ADef=0 (ABDef != 1)
& Enc{ BCode } if BDef=0 (ABDef != 2)
После того, как ведущий байт анализируется, Кбайт байта ожидается, если KBFlag будет установлен, иначе Кбайту неявно дают значение 3.
Коэффициент теплопроводности для конструкции 'выполнения' может взять диапазон значений, и определяется следующим образом:
K = (KB+1) * 16^KX
Кодирование ACode, как понимают, является 'значением по умолчанию', если бит ADef устанавливается. Иначе, представление ACode анализируется затем. Наконец, кодирование BCode, как понимают, является 'значением по умолчанию', если бит BDef устанавливается. Иначе, представление BCode анализируется последнее. И ADef и BDef могут быть четкими, но оба не могут быть установлены.
'Выталкивать' кодировки конструкции начинаются с байта в [141.. 188], и может сопровождаться один, два, или три спецификатора кодирования, FCode, UCode, и TCode. Смещение от 141 поразрядный кодирует следующие данные:
Enc{ pop ( FCode TCode UCode ) }
= (141 + (FDef:[0..1]) + 2*UDef:[0..1] + 4*(TDefL:[0..11]))
& Enc{ FCode } if FDef=0
& Enc{ TCode } if TDef=0 (TDefL==0)
& Enc{ UCode } if UDef=0
Если TDef является нулем, явный спецификатор кодирования определяет TCode, и параметр L не присутствует. Если TDef один, параметр L присутствует и получается из TDefL согласно следующей таблице:
| TDefL | L |
|---|---|
| 1 | 4 |
| 2 | 8 |
| 3 | 16 |
| 4 | 32 |
| 5 | 64 |
| 6 | 128 |
| 7 | 192 |
| 8 | 224 |
| 9 | 240 |
| 10 | 248 |
| 11 | 252 |
Если параметр L присутствует, TCode получается из значений K и L. Если K <256, то TCode является BYTE1 (1,255,0), и L, игнорируется. Иначе, TCode (B, H, S) кодирование, где S=0, H = (256-L), и B является самым маленьким значением так, что [0.. K] содержится в Диапазоне (B, H, S). (Это недопустимо, чтобы определить L, настолько большой, что Диапазон (5,256-L, 0) не содержит K.),
Кодирование FCode, как понимают, является 'значением по умолчанию', если бит FDef устанавливается. Иначе, представление FCode сразу анализируется после начального байта. Кодирование TCode, как понимают, получается из K и L, если бит TDef устанавливается. Иначе, представление TCode анализируется затем. Наконец, кодирование UCode, как понимают, является 'значением по умолчанию', если бит UDef устанавливается. Иначе, представление UCode анализируется последнее.
| индексировать | Кодирование BHSD |
|---|---|
| 1 | (1,256,0) |
| 2 | (1,256,1) |
| 3 | (1,256,0,1) |
| 4 | (1,256,1,1) |
| 5 | (2,256,0) |
| 6 | (2,256,1) |
| 7 | (2,256,0,1) |
| 8 | (2,256,1,1) |
| 9 | (3,256,0) |
| 10 | (3,256,1) |
| 11 | (3,256,0,1) |
| 12 | (3,256,1,1) |
| 13 | (4,256,0) |
| 14 | (4,256,1) |
| 15 | (4,256,0,1) |
| 16 | (4,256,1,1) |
| 17 | (5, 4,0) |
| 18 | (5, 4,1) |
| 19 | (5, 4,2) |
| 20 | (5, 16,0) |
| 21 | (5, 16,1) |
| 22 | (5, 16,2) |
| 23 | (5, 32,0) |
| 24 | (5, 32,1) |
| 25 | (5, 32,2) |
| 26 | (5, 64,0) |
| 27 | (5, 64,1) |
| 28 | (5, 64,2) |
| 29 | (5,128,0) |
| 30 | (5,128,1) |
| 31 | (5,128,2) |
| 32 | (5, 4,0,1) |
| 33 | (5, 4,1,1) |
| 34 | (5, 4,2,1) |
| 35 | (5, 16,0,1) |
| 36 | (5, 16,1,1) |
| 37 | (5, 16,2,1) |
| 38 | (5, 32,0,1) |
| 39 | (5, 32,1,1) |
| 40 | (5, 32,2,1) |
| 41 | (5, 64,0,1) |
| 42 | (5, 64,1,1) |
| 43 | (5, 64,2,1) |
| 44 | (5,128,0,1) |
| 45 | (5,128,1,1) |
| 46 | (5,128,2,1) |
| 47 | (2,192,0) |
| 48 | (2,224,0) |
| 49 | (2,240,0) |
| 50 | (2,248,0) |
| 51 | (2,252,0) |
| 52 | (2, 8,0,1) |
| 53 | (2, 8,1,1) |
| 54 | (2, 16,0,1) |
| 55 | (2, 16,1,1) |
| 56 | (2, 32,0,1) |
| 57 | (2, 32,1,1) |
| 58 | (2, 64,0,1) |
| 59 | (2, 64,1,1) |
| 60 | (2,128,0,1) |
| 61 | (2,128,1,1) |
| 62 | (2,192,0,1) |
| 63 | (2,192,1,1) |
| 64 | (2,224,0,1) |
| 65 | (2,224,1,1) |
| 66 | (2,240,0,1) |
| 67 | (2,240,1,1) |
| 68 | (2,248,0,1) |
| 69 | (2,248,1,1) |
| 70 | (3,192,0) |
| 71 | (3,224,0) |
| 72 | (3,240,0) |
| 73 | (3,248,0) |
| 74 | (3,252,0) |
| 75 | (3, 8,0,1) |
| 76 | (3, 8,1,1) |
| 77 | (3, 16,0,1) |
| 78 | (3, 16,1,1) |
| 79 | (3, 32,0,1) |
| 80 | (3, 32,1,1) |
| 81 | (3, 64,0,1) |
| 82 | (3, 64,1,1) |
| 83 | (3,128,0,1) |
| 84 | (3,128,1,1) |
| 85 | (3,192,0,1) |
| 86 | (3,192,1,1) |
| 87 | (3,224,0,1) |
| 88 | (3,224,1,1) |
| 89 | (3,240,0,1) |
| 90 | (3,240,1,1) |
| 91 | (3,248,0,1) |
| 92 | (3,248,1,1) |
| 93 | (4,192,0) |
| 94 | (4,224,0) |
| 95 | (4,240,0) |
| 96 | (4,248,0) |
| 97 | (4,252,0) |
| 98 | (4, 8,0,1) |
| 99 | (4, 8,1,1) |
| 100 | (4, 16,0,1) |
| 101 | (4, 16,1,1) |
| 102 | (4, 32,0,1) |
| 103 | (4, 32,1,1) |
| 104 | (4, 64,0,1) |
| 105 | (4, 64,1,1) |
| 106 | (4,128,0,1) |
| 107 | (4,128,1,1) |
| 108 | (4,192,0,1) |
| 109 | (4,192,1,1) |
| 110 | (4,224,0,1) |
| 111 | (4,224,1,1) |
| 112 | (4,240,0,1) |
| 113 | (4,240,1,1) |
| 114 | (4,248,0,1) |
| 115 | (4,248,1,1) |
Однако, для любого данного архив Pack200, каждый декомпрессор обязан производить определенное мудрое байтом изображение для каждого переданного файла class. Это требование помещается в декомпрессоры, чтобы позволить компрессорам передать информацию, такую как обзоры сообщения, который касается возможного мудрого байтом содержания переданных файлов class. Этот раздел описывает ограничения, установленные для каждого декомпрессора, который делает мудрое байтом содержание его выходных файлов четко определенной функцией его ввода.
Вообще, порядок элементов в распакованном файле class должен быть непротиворечивым с порядком передачи в архиве Pack200. Например, порядок полей class, объявленных в файле class, должен соответствовать порядку, в, котором что полевые дескрипторы class были переданы в полосе field_descr. (Это также, оказывается, соответствует порядку в полосах field_flags.) Эта таблица дает все необходимые корреспонденции порядка файла class с порядком передачи архива:
| элемент в Файл class |
полоса, который определяет порядок |
|---|---|
| реализованные интерфейсы | class _interface |
| объявленные поля | field_descr |
| объявленные методы | method_descr |
| список обработчика кода | code_handler_start_P |
| Список атрибутов class | class _flags, class _attr_indexes |
| полевой список атрибутов | field_flags, field_attr_indexes |
| список атрибутов метода | method_flags, method_attr_indexes |
| кодируйте список атрибутов | code_attr_indexes |
| постоянные записи пула | cp_Utf8, и т.д. (см. ниже), |
Вместе, эти необходимые корреспонденции порядка определяют точное содержание распакованного файла class. Упорядочивание интерфейсов, полей, методов, и обработчиков исключений непосредственно определяется упорядочиванием полос, которые передают их.
Если InnerClasses или атрибут BootstrapMethods должны быть добавлены к class по правилам, данным в следующем разделе, те атрибуты должны прибыть последние в список атрибутов class. Если больше чем один такой атрибут добавляется, относительным упорядочиванием является BootstrapMethods, то InnerClasses.
Затем cp(X) определяется, как будто следующими шагами, которые заполняют его от глобального постоянного пула cp_All, и также потенциально производят атрибут InnerClasses для X.
В этой точке постоянный пул cp(X) чувствует себя достаточно хорошо определенный, чтобы позволить декомпрессору вычислять набор соответствующих вложенных классов, названных ic_Relevant(X).
С ic_Relevant(X) и дополнительно переданным ic_Local(X) в руке, должен затем решить декомпрессор, сохранить ли атрибут InnerClasses ic_Stored(X) для X, используя эти шаги.
С последними вкладами от вложенных записей class декомпрессор заканчивает постоянный пул, используя эти шаги:
После этого процесса у сохраненного постоянного пула X есть ссылочная целостность, и все постоянные ссылки могут быть кодированы, как индексирует в cp(X), которому получили определенный порядок из cp_All. В частности если константа в cp(X) должна обратиться к другой константе, которая постоянный, должно быть, уже была вставлена в cp(X), во время шагов закрытия.
Отметьте, что упорядочивание cp(X) является непротиворечивым с тем из cp_All, за исключением того, что некоторые ссылки подписи перенаправляются к эквивалентным существующим ранее элементам cp_Utf8, и все операнды ldc байт-кодов вызываются к передней стороне постоянного пула.
Когда присвоение локального индексирует к элементам cp(X), декомпрессор должен, конечно, уважать резервирование пустых постоянных слотов пула для, индексируют нуль, и для CONSTANT_Long и констант CONSTANT_Double, как требуется форматом файла class. Вместе с этими правилами, конструкцией и упорядочиванием cp(X) полностью решает, что присвоение бетона индексирует к постоянным ссылкам в пределах X.
| Полоса | Значение по умолчанию кодирование |
Длина | Постоянный пул упомянутый |
|
|---|---|---|---|---|
| archive_magic | BYTE1 | [4] | ||
| archive_header | UNSIGNED5 | [26] | ||
| band_headers | BYTE1 | [...] | ||
| cp_Utf8_prefix | DELTA5 | [MAX(0,#cp_Utf8_count-2)] | ||
| cp_Utf8_suffix | UNSIGNED5 | [MAX(0,#cp_Utf8_count-1)] | ||
| cp_Utf8_chars | CHAR3 | [SUM(*cp_Utf8_suffix)] | ||
| cp_Utf8_big_suffix | DELTA5 | [COUNT(0,*cp_Utf8_suffix)] | ||
| {cp_Utf8_big_chars...} | DELTA5 | [*cp_Utf8_big_suffix[i]] | ||
| cp_Int | UDELTA5 | [#cp_Int_count] | ||
| cp_Float | UDELTA5 | [#cp_Float_count] | ||
| cp_Long_hi | UDELTA5 | [#cp_Long_count] | ||
| cp_Long_lo | DELTA5 | [#cp_Long_count] | ||
| cp_Double_hi | UDELTA5 | [#cp_Double_count] | ||
| cp_Double_lo | DELTA5 | [#cp_Double_count] | ||
| cp_String | UDELTA5 | [#cp_String_count] | cp_Utf8 | |
| cp_Class | UDELTA5 | [#cp_Class_count] | cp_Utf8 | |
| cp_Signature_form | DELTA5 | [#cp_Signature_count] | cp_Utf8 | |
| cp_Signature_classes | UDELTA5 | [COUNT('L',...)] | cp_Class | |
| cp_Descr_name | DELTA5 | [#cp_Descr_count] | cp_Utf8 | |
| cp_Descr_type | UDELTA5 | [#cp_Descr_count] | cp_Signature | |
| cp_Field_class | DELTA5 | [#cp_Field_count] | cp_Class | |
| cp_Field_desc | UDELTA5 | [#cp_Field_count] | cp_Descr | |
| cp_Method_class | DELTA5 | [#cp_Method_count] | cp_Class | |
| cp_Method_desc | UDELTA5 | [#cp_Method_count] | cp_Descr | |
| cp_Imethod_class | DELTA5 | [#cp_Imethod_count] | cp_Class | |
| cp_Imethod_desc | UDELTA5 | [#cp_Imethod_count] | cp_Descr | |
| cp_MethodHandle_refkind | DELTA5 | [#cp_MethodHandle_count] | ||
| cp_MethodHandle_member | UDELTA5 | [#cp_MethodHandle_count] | cp_All | |
| cp_MethodType | UDELTA5 | [#cp_MethodType_count] | cp_Signature | |
| cp_BootstrapMethod_ref | DELTA5 | [#cp_BootstrapMethod_count] | cp_MethodHandle | |
| cp_BootstrapMethod_arg_count | UDELTA5 | [#cp_BootstrapMethod_count]arg_tt> | ||
| cp_BootstrapMethod_arg | DELTA5 | [SUM(*class_interface_count)] | cp_All | |
| cp_InvokeDynamic_spec | DELTA5 | [#cp_InvokeDynamic_count] | cp_BootstrapMethod | |
| cp_InvokeDynamic_descr | UDELTA5 | [#cp_InvokeDynamic_count] | cp_Descr | |
| attr_definition_headers | BYTE1 | [#attr_definition_count] | ||
| attr_definition_name | UNSIGNED5 | [#attr_definition_count] | cp_Utf8 | |
| attr_definition_layout | UNSIGNED5 | [#attr_definition_count] | cp_Utf8 | |
| ic_this_class | UDELTA5 | [#ic_count] | cp_Class | |
| ic_flags | UNSIGNED5 | [#ic_count] | ||
| ic_outer_class | DELTA5 | [COUNT(1<<16,...)] | cp_Class | |
| ic_name | DELTA5 | [COUNT(1<<16,...)] | cp_Utf8 | |
| class_this | DELTA5 | [#class_count] | cp_Class | |
| class_super | DELTA5 | [#class_count] | cp_Class | |
| class_interface_count | DELTA5 | [#class_count] | ||
| class_interface | DELTA5 | [SUM(*class_interface_count)] | cp_Class | |
| class_field_count | DELTA5 | [#class_count] | ||
| class_method_count | DELTA5 | [#class_count] | ||
| field_descr | DELTA5 | [SUM(*class_field_count)] | cp_Descr | |
| field_flags_hi | UNSIGNED5 | [SUM(*class_field_count)*#have_field_flags_hi] | ||
| field_flags_lo | UNSIGNED5 | [SUM(*class_field_count)] | ||
| field_attr_count | UNSIGNED5 | [COUNT(1<<16,...)] | ||
| field_attr_indexes | UNSIGNED5 | [SUM(*field_attr_count)] | ||
| field_attr_calls | UNSIGNED5 | [...] | ||
| field_ConstantValue_KQ | UNSIGNED5 | [COUNT(ConstantValue,...)] | cp_Int, cp_Float, etc. | |
| field_Signature_RS | UNSIGNED5 | [COUNT(Signature,...)] | cp_Signature | |
| field_RVA_anno_N | UNSIGNED5 | [...] | ||
| field_RVA_type_RS | UNSIGNED5 | [...] | cp_Signature | |
| field_RVA_pair_N | UNSIGNED5 | [...] | ||
| field_RVA_name_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| field_RVA_T | BYTE1 | [...] | ||
| field_RVA_caseI_KI | UNSIGNED5 | [...] | cp_Int | |
| field_RVA_caseD_KD | UNSIGNED5 | [...] | cp_Double | |
| field_RVA_caseF_KF | UNSIGNED5 | [...] | cp_Float | |
| field_RVA_caseJ_KJ | UNSIGNED5 | [...] | cp_Long | |
| field_RVA_casec_RS | UNSIGNED5 | [...] | cp_Signature | |
| field_RVA_caseet_RS | UNSIGNED5 | [...] | cp_Signature | |
| field_RVA_caseec_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| field_RVA_cases_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| field_RVA_casearray_N | UNSIGNED5 | [...] | ||
| field_RVA_nesttype_RS | UNSIGNED5 | [...] | cp_Signature | |
| field_RVA_nestpair_N | UNSIGNED5 | [...] | ||
| field_RVA_nestname_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| field_RIA_anno_N | UNSIGNED5 | [...] | ||
| {field_RIA_...} | ||||
| field_RIA_nestname_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| {field_attr_element_bands...} | (различный) | [...] | (various) | |
| method_descr | MDELTA5 | [SUM(*class_method_count)] | cp_Descr | |
| method_flags_hi | UNSIGNED5 | [SUM(*class_method_count)*#have_method_flags_hi] | ||
| method_flags_lo | UNSIGNED5 | [SUM(*class_method_count)] | ||
| method_attr_count | UNSIGNED5 | [COUNT(1<<16,...)] | ||
| method_attr_indexes | UNSIGNED5 | [SUM(*method_attr_count)] | ||
| method_attr_calls | UNSIGNED5 | [...] | ||
| method_Exceptions_N | UNSIGNED5 | [COUNT(Exceptions,...)] | ||
| method_Exceptions_RC | UNSIGNED5 | [SUM(*method_Exceptions_N)] | cp_Class | |
| method_Signature_RS | UNSIGNED5 | [COUNT(Signature,...)] | cp_Signature | |
| method_RVA_anno_N | UNSIGNED5 | [...] | ||
| method_RVA_type_RS | UNSIGNED5 | [...] | cp_Signature | |
| method_RVA_pair_N | UNSIGNED5 | [...] | ||
| method_RVA_name_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| method_RVA_T | BYTE1 | [...] | ||
| method_RVA_caseI_KI | UNSIGNED5 | [...] | cp_Int | |
| method_RVA_caseD_KD | UNSIGNED5 | [...] | cp_Double | |
| method_RVA_caseF_KF | UNSIGNED5 | [...] | cp_Float | |
| method_RVA_caseJ_KJ | UNSIGNED5 | [...] | cp_Long | |
| method_RVA_casec_RS | UNSIGNED5 | [...] | cp_Signature | |
| method_RVA_caseet_RS | UNSIGNED5 | [...] | cp_Signature | |
| method_RVA_caseec_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| method_RVA_cases_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| method_RVA_casearray_N | UNSIGNED5 | [...] | ||
| method_RVA_nesttype_RS | UNSIGNED5 | [...] | cp_Signature | |
| method_RVA_nestpair_N | UNSIGNED5 | [...] | ||
| method_RVA_nestname_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| method_RIA_anno_N | UNSIGNED5 | [...] | ||
| {method_RIA_...} | ||||
| method_RIA_nestname_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| method_RVPA_param_NB | BYTE1 | [...] | ||
| method_RVPA_anno_N | UNSIGNED5 | [...] | ||
| {method_RVPA_...} | ||||
| method_RVPA_nestname_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| method_RIPA_param_NB | BYTE1 | [...] | ||
| method_RIPA_anno_N | UNSIGNED5 | [...] | ||
| {method_RIPA_...} | ||||
| method_RIPA_nestname_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| method_AD_T | BYTE1 | [...] | ||
| method_AD_caseI_KI | UNSIGNED5 | [...] | cp_Int | |
| method_AD_caseD_KD | UNSIGNED5 | [...] | cp_Double | |
| method_AD_caseF_KF | UNSIGNED5 | [...] | cp_Float | |
| method_AD_caseJ_KJ | UNSIGNED5 | [...] | cp_Long | |
| method_AD_casec_RS | UNSIGNED5 | [...] | cp_Signature | |
| method_AD_caseet_RS | UNSIGNED5 | [...] | cp_Signature | |
| method_AD_caseec_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| method_AD_cases_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| method_AD_casearray_N | UNSIGNED5 | [...] | ||
| method_AD_nesttype_RS | UNSIGNED5 | [...] | cp_Signature | |
| method_AD_nestpair_N | UNSIGNED5 | [...] | ||
| method_AD_nestname_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| {method_attr_element_bands...} | (различный) | [...] | (various) | |
| class_flags_hi | UNSIGNED5 | [#class_count*#have_class_flags_hi] | ||
| class_flags_lo | UNSIGNED5 | [#class_count] | ||
| class_attr_count | UNSIGNED5 | [COUNT(1<<16,...)] | ||
| class_attr_indexes | UNSIGNED5 | [SUM(*class_attr_count)] | ||
| class_attr_calls | UNSIGNED5 | [...] | ||
| class_SourceFile_RUN | UNSIGNED5 | [COUNT(SourceFile,...)] | null|cp_Utf8 | |
| class_EnclosingMethod_RC | UNSIGNED5 | [COUNT(EnclosingMethod,...)] | cp_Class | |
| class_EnclosingMethod_RDN | UNSIGNED5 | [COUNT(EnclosingMethod,...)] | null|cp_Descr | |
| class_Signature_RS | UNSIGNED5 | [COUNT(Signature,...)] | cp_Signature | |
| class_RVA_anno_N | UNSIGNED5 | [...] | ||
| class_RVA_type_RS | UNSIGNED5 | [...] | cp_Signature | |
| class_RVA_pair_N | UNSIGNED5 | [...] | ||
| class_RVA_name_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| class_RVA_T | BYTE1 | [...] | ||
| class_RVA_caseI_KI | UNSIGNED5 | [...] | cp_Int | |
| class_RVA_caseD_KD | UNSIGNED5 | [...] | cp_Double | |
| class_RVA_caseF_KF | UNSIGNED5 | [...] | cp_Float | |
| class_RVA_caseJ_KJ | UNSIGNED5 | [...] | cp_Long | |
| class_RVA_casec_RS | UNSIGNED5 | [...] | cp_Signature | |
| class_RVA_caseet_RS | UNSIGNED5 | [...] | cp_Signature | |
| class_RVA_caseec_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| class_RVA_cases_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| class_RVA_casearray_N | UNSIGNED5 | [...] | ||
| class_RVA_nesttype_RS | UNSIGNED5 | [...] | cp_Signature | |
| class_RVA_nestpair_N | UNSIGNED5 | [...] | ||
| class_RVA_nestname_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| class_RIA_anno_N | UNSIGNED5 | [...] | ||
| {class_RIA_...} | ||||
| class_RIA_nestname_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| class_InnerClasses_N | UNSIGNED5 | [COUNT(InnerClasses,...)] | ||
| class_InnerClasses_RC | UNSIGNED5 | [SUM(*class_InnerClasses_N)] | cp_Class | |
| class_InnerClasses_F | UNSIGNED5 | [SUM(*class_InnerClasses_N)] | ||
| class_InnerClasses_outer_RCN | UNSIGNED5 | [COUNT(!=0,*class_InnerClasses_F)] | null|cp_Class | |
| class_InnerClasses_name_RUN | UNSIGNED5 | [COUNT(!=0,*class_InnerClasses_F)] | null|cp_Utf8 | |
| class_file_version_minor_H | UNSIGNED5 | [COUNT(version,...)] | ||
| class_file_version_major_H | UNSIGNED5 | [COUNT(version,...)] | ||
| {class_attr_element_bands...} | (различный) | [...] | (various) | |
| code_headers | BYTE1 | [COUNT(Code,...)] | ||
| code_max_stack | UNSIGNED5 | [COUNT(0,*code_headers)] | ||
| code_max_na_locals | UNSIGNED5 | [COUNT(0,*code_headers)] | ||
| code_handler_count | UNSIGNED5 | [COUNT(0,*code_headers)] | ||
| code_handler_start_P | BCI5 | [SUM(*code_header_count)] | ||
| code_handler_end_PO | BRANCH5 | [SUM(*code_header_count)] | ||
| code_handler_catch_PO | BRANCH5 | [SUM(*code_header_count)] | ||
| code_handler_class_RCN | UNSIGNED5 | [SUM(*code_header_count)] | null|cp_Class | |
| code_flags_hi | UNSIGNED5 | [...*#have_code_flags_hi] | ||
| code_flags_lo | UNSIGNED5 | [...] | ||
| code_attr_count | UNSIGNED5 | [COUNT(1<<16,...)] | ||
| code_attr_indexes | UNSIGNED5 | [SUM(*code_attr_count)] | ||
| code_attr_calls | UNSIGNED5 | [...] | ||
| code_StackMapTable_N | UNSIGNED5 | [COUNT(StackMapTable,...)] | ||
| code_StackMapTable_frame_T | BYTE1 | [SUM(*code_StackMapTable_N)] | ||
| code_StackMapTable_local_N | UNSIGNED5 | [COUNT(255,*code_StackMapTable_frame_T)] | ||
| code_StackMapTable_stack_N | UNSIGNED5 | [COUNT(255,*code_StackMapTable_frame_T)] | ||
| code_StackMapTable_offset | UNSIGNED5 | [...] | ||
| code_StackMapTable_T | BYTE1 | [...] | ||
| code_StackMapTable_RC | UNSIGNED5 | [COUNT(7,*code_StackMapTable_T)] | ||
| code_StackMapTable_P | BCI5 | [COUNT(8,*code_StackMapTable_T)] | ||
| code_LineNumberTable_N | UNSIGNED5 | [...] | ||
| code_LineNumberTable_bci_P | BCI5 | [...] | ||
| code_LineNumberTable_line | UNSIGNED5 | [...] | ||
| code_LocalVariableTable_N | UNSIGNED5 | [...] | ||
| code_LocalVariableTable_bci_P | BCI5 | [...] | ||
| code_LocalVariableTable_span_O | BRANCH5 | [...] | ||
| code_LocalVariableTable_name_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| code_LocalVariableTable_type_RS | UNSIGNED5 | [...] | cp_Signature | |
| code_LocalVariableTable_slot | UNSIGNED5 | [...] | ||
| code_LocalVariableTypeTable_N | UNSIGNED5 | [...] | ||
| code_LocalVariableTypeTable_bci_P | BCI5 | [...] | ||
| code_LocalVariableTypeTable_span_O | BRANCH5 | [...] | ||
| code_LocalVariableTypeTable_name_RU | UNSIGNED5 | [...] | cp_Utf8 | |
| code_LocalVariableTypeTable_type_RS | UNSIGNED5 | [...] | cp_Signature | |
| code_LocalVariableTypeTable_slot | UNSIGNED5 | [...] | ||
| {code_attr_element_bands...} | (различный) | [...] | (various) | |
| bc_codes | BYTE1 | [...] | ||
| bc_case_count | UNSIGNED5 | [COUNT(switch,*bc_codes)] | ||
| bc_case_value | DELTA5 | [...] | ||
| bc_byte | BYTE1 | [...] | ||
| bc_short | DELTA5 | [...] | ||
| bc_local | UNSIGNED5 | [...] | ||
| bc_label | BRANCH5 | [...] | ||
| bc_intref | DELTA5 | [...] | cp_Int | |
| bc_floatref | DELTA5 | [...] | cp_Float | |
| bc_longref | DELTA5 | [...] | cp_Long | |
| bc_doubleref | DELTA5 | [...] | cp_Double | |
| bc_stringref | DELTA5 | [...] | cp_String | |
| bc_loadablevalueref | DELTA5 | [COUNT({qldc,qldc_w},*bc_codes)] | cp_All | |
| bc_classref | UNSIGNED5 | [...] | cp_Class | |
| bc_fieldref | DELTA5 | [...] | cp_Field | |
| bc_methodref | UNSIGNED5 | [...] | cp_Method | |
| bc_imethodref | DELTA5 | [...] | cp_Imethod | |
| bc_thisfield | UNSIGNED5 | [...] | cp_Field subsequence | |
| bc_superfield | UNSIGNED5 | [...] | cp_Field subsequence | |
| bc_thismethod | UNSIGNED5 | [...] | cp_Method subsequence | |
| bc_supermethod | UNSIGNED5 | [...] | cp_Method subsequence | |
| bc_initref | UNSIGNED5 | [...] | cp_Method subsequence | |
| bc_escref | UNSIGNED5 | [COUNT(ref_escape,*bc_codes)] | cp_All | |
| bc_escrefsize | UNSIGNED5 | [...] | ||
| bc_escsize | UNSIGNED5 | [...] | ||
| bc_escbyte | BYTE1 | [...] | ||
| file_name | UNSIGNED5 | [#file_count] | cp_Utf8 | |
| file_size_hi | UNSIGNED5 | [#file_count*(#have_file_size_hi)] | ||
| file_size_lo | UNSIGNED5 | [#file_count] | ||
| file_modtime | DELTA5 | [#file_count*(#have_file_modtime)] | ||
| file_options | UNSIGNED5 | [#file_count*(#have_file_options)] | ||
| file_bits | BYTE1 | [SUM(*file_size)] |
assert(cp_Utf8[0].equals(""));
int cursor = 0;
int big_cursor = 0;
for (int i = 1; i < cp_Utf8_count; i++) {
String thisString = cp_Utf8[i];
int prefix = (i == 1)? 0: cp_Utf8_prefix[i-2];
int suffix = thisString.length() - prefix;
String prevString = cp_Utf8[i-1];
String prevPrefix = prevString.substring(0, prefix);
String thisPrefix = thisString.substring(0, prefix);
assert(prevPrefix.equals(thisPrefix));
int small_suffix = cp_Utf8_suffix[i-1];
char[] suffix_chars;
int offset;
if (small_suffix != 0) {
assert(suffix == small_suffix);
suffix_chars = cp_Utf8_chars;
offset = cursor;
cursor += suffix;
} else {
assert(suffix == cp_Utf8_big_suffix[big_cursor]);
suffix_chars = cp_Utf8_big_chars[big_cursor];
offset = 0;
assert(suffix == suffix_chars.length);
big_cursor += 1;
}
String thisSuffix = thisString.substring(prefix);
String theseChars = new String(suffix_chars, offset, suffix);
assert(thisSuffix.equals(theseChars));
}
assert(cp_Utf8_prefix.length == Math.max(0, cp_Utf8_count-2));
assert(cp_Utf8_suffix.length == Math.max(0, cp_Utf8_count-1));
assert(cp_Utf8_chars.length == cursor);
assert(cp_Utf8_big_suffix.length == big_cursor);
assert(cp_Utf8_big_chars.length == big_cursor);
int cursor = 0;
for (int i = 0; i < cp_Signature_count; i++) {
String sign = cp_Signature[i];
String form = cp_Signature_form[i];
int form_ptr = 0;
int sign_ptr = 0;
for (; form_ptr < form.length(); form_ptr++) {
assert(form.charAt(form_ptr) == sign.charAt(sign_ptr));
sign_ptr += 1;
if (form.charAt(form_ptr) == 'L') {
String cls = cp_Class[cursor];
assert(sign.startsWith(cls, sign_ptr));
cursor += 1;
sign_ptr += cls.length();
}
}
assert(sign_ptr == sign.length());
}
assert(cp_Signature_form.length == cp_Signature_count);
assert(cp_Signature_classes.length == cursor);
// ins_pos is a display of all instruction boundaries
int[] ins_pos;
...
Arrays.sort(ins_pos);
assert(ins_pos[0] == 0);
assert(ins_pos[ins_pos.length-1] == bytecodes.length);
int regulars = ins_pos.length; // # instruction boundaries
...
int renumber_bci(int bci) {
int i = Arrays.binarySearch(ins_pos, bci);
return (i >= 0) ? i : (i == -1) ? bci : ins_pos.length + bci - (-i-1);
}
...
for (int bci = -100; bci <= bytecodes.length+100; bci++) {
int bci_numbering_for_band = renumber_bci(bci);
int i = Arrays.binarySearch(ins_pos, bci);
if (i >= 0) {
assert(ins_pos[i] == bci);
assert(bci_numbering_for_band < regulars);
assert(bci_numbering_for_band == i);
} else if (0 < bci && bci < bytecodes.length) {
int nexti = (-i-1); // index of next instruction
assert(ins_pos[nexti-1] < bci && bci < ins_pos[nexti]);
int prevRegulars = nexti;
int prevAll = bci;
int prevIrregulars = prevAll - prevRegulars;
assert(bci_numbering_for_band >= regulars);
assert(bci_numbering_for_band == regulars + prevIrregulars);
} else {
// other (random) numbers are unchanged by renumbering
assert(bci_numbering_for_band >= bytecodes.length ||
bci_numbering_for_band < 0);
assert(bci_numbering_for_band == bci);
}
}
String bcn, predictableOuter, predictableICName;
...
String name = bcn.substring(bcn.lastIndexOf('/')+1);
int dollar2 = name.lastIndexOf('$');
assert(predictableICName == null ||
(predictableICName.charAt(0) > '9' &&
predictableICName.indexOf('$') < 0));
if (predictableICName == null) {
// bcnCase1 or bcnCase4
assert(predictableOuter == null);
assert(dollar2 == -1 ||
dollar2+1 == name.length() ||
isDigit(name.charAt(dollar2+1)));
} else if (predictableOuter == null) {
// bcnCase2
assert(name.endsWith("$"+predictableICName));
int dollar1 = name.substring(0, dollar2).lastIndexOf('$');
assert(dollar1 >= 0 && dollar1+1 < dollar2);
assert(isDigitString(name.substring(dollar1+1, dollar2)));
} else {
// bcnCase3
assert(bcn.equals(predictableOuter+"$"+predictableICName));
}
Почему бы не использовать существующий универсальный механизм сжатия, такой как .jar, .zip, или файлы .tar.gz? Во-первых, лучше знать структуру сжатой вещи. Во-вторых, архив zip или фляги сжимается поэлементно не глобально. Это означает, что любой символ, совместно использованный несколькими классами, должен быть упомянут независимо однажды в каждом файле class. В-третьих, структура отдельного файла class является действительно чередованием многих различный вид данных, каждого с их собственной статистикой, которая ограничивает эффективность компрессора единого потока, такого как gzip. Определенное преимущество переупорядочения данных в полосы о факторе два, независимо от качества стандартного компрессора, используемого в качестве постпередачи. От различных специфичных для типа методов перекодирования есть также существенные предельные выгоды. Конечный результат состоит в том, чтобы улучшить фактор сжатия от 2-4X до 7-9X.
Почему эта спецификация настолько сложна? Методы, описанные здесь, являются результатом большого экспериментирования более чем несколько лет. Каждая функция этой спецификации, как думают, способствует в известной мере полному коэффициенту сжатия, достигнутому этой технологией. Авторы были бы счастливы быть показанными сравнительными тестами, что некоторая данная функция может быть опущена без существенной потери производительности сжатия.
(Множитель производительности сжатия 1.002 или больше для некоторого определенного метода является существенным, потому что такие множители накапливают с готовностью в производительность то уведомление конечных пользователей. Множитель меньше чем 1.0005 является незначащим.)
Формат передачи Pack200 близко связывается к текущему формату файла class. Разве это не будет выходить из моды, как только формат файла class развивается далее? Дальнейшее развитие, вероятно, примет форму новых атрибутов или возможно новых байт-кодов. Язык расположения, определенный Pack200, поддерживает очень широкий диапазон форматов атрибута, включая произвольные смеси байтов и постоянных ссылок пула. Аналогично, представление байт-кода включает операторы escape, которые могут представить произвольные смеси данных и постоянных ссылок пула. Хотя такие конструкции не будут сжиматься так оптимально как функции, для которых непосредственно разрабатывается эта спецификация, кажется, что разумные будущие расширения будут продолжать быть transmittable, не нарушая сжатие текущих функций, и не требуя, чтобы декомпрессоры были обновлены.
Так как Pack200 является алгоритмом сжатия с потерями, он не будет повреждать подписанные файлы JAR? Подписанные файлы JAR содержат безопасный, долго обсуждает bytewise содержание отдельных файлов class. Любое изменение к битам файла class изменит свой хэш-код, производя безвредные изменения Pack200, неотличимых от атак на код программы.
Pack200, как много других алгоритмов сжатия, позволяет компрессору много степеней свободы в выборе содержания сжатого архива, но никаких степеней свободы в выборе содержания распакованного файла JAR. Учитывая сжатый архив, все совместимые декомпрессоры Pack200 должны произвести те же самые байты файла class, поскольку каждый передал файл class. Эта устойчивость вывода сохраняется для файлов class, даже если файл ресурсов (такой как декларация) изменяет свое содержание. Таким образом, для любого данного файла class, сжатие может быть с потерями, но распаковка каждого файла class должна быть точной полезным способом, определенным спецификацией Pack200.
Это означает, что компрессор с правильными свойствами устойчивости может использоваться, чтобы произвести подписанный, упакованный JAR, используя эти шаги:
(Отметьте: Если эта спецификация позволяет двум совместимым декомпрессорам производить различные элементы архива JAR для того же самого сжатого ввода архива, это - ошибка в спецификации. Спецификация, как думают, свободна от таких ошибок, но если Вы находите один, пожалуйста, сообщите об этом.)
Каково отношение между именами файлов в архивах Pack200 и именами файлов в JAR (или ZIP) дисковые файлы или архивы? Pack200 определяет, что имена файлов передаются как строки Utf8. Так как эти строки предназначаются, чтобы функционировать как имена элементов JAR в функционирующих приложениях Java, строки должны также соответствовать использованию Java, которое также представляет пути, поскольку Utf8 представляет в виде строки в файлах JAR и 16-разрядном Unicode в памяти. Кроме того, в файлах JAR компоненты пути разделяются символом наклонной черты вправо (' / '), а не любым специфичным для системы символом. Это позволяет загрузчикам class легко преобразовывать внутреннее представление имен class (например, "java/lang/Object") к путям (например, "java/lang/Object. class").
Спецификация Pack200 не диктует интерпретацию строк имени файла относительно любого другого инструмента или операционной системы. Однако, естественное отображение было бы настолько когерентным насколько возможно с использованиями Java.
Каково отношение между датами файла в JAR (или ZIP) дисковые файлы или архивы? Pack200 определяет, что даты файла передаются как 32-разрядные количества секунд относительно основы времени Java (то есть, System.currentTimeMillis, разделенный на одна тысяча). Это обеспечивает абсолютные времена относительно UTC при односекундной гранулярности. Если операционная система обеспечивает более точные времена файла, они должны быть скорректированы к соседней целой секунде перед передачей в архиве Pack200.
JAR и ZIP хранят даты в локальном формате (то есть, "YYYY/MM/DD HH:MM:SS") без спецификации часового пояса. Это означает, что преобразование в и с основанных на UTC времен Java требует предположения в часовом поясе, под которым работал компрессор. (Эта проблема не уникальна для Pack200. Это - проблема со всем использованием архивов JAR и ZIP.) Во многих целях стандартное предположение - то, что декомпрессор и компрессор работали в том же самом часовом поясе и во время того же самого ежегодного режима летнего времени. Однако, чтобы обеспечить больше устойчивости во времена, переданные в архивах Pack200, ожидается, что большинство компрессоров и декомпрессоров согласятся использовать UTC в качестве часового пояса, интерпретируя местное время стиля ZIP.
Не формат файла JEFFtm также oprovide class специфичный алгоритм сжатия? Да, Рабочая группа ДЖЕФФА определила стандартный формат файла (ISO/IEC 20970), который позволяет файлам class быть сжатыми приблизительно 50 % и также загруженными непосредственно в память для интерпретирующего выполнения. Как производительность сжатия, это сопоставимо с ВЫКАЧИВАТЬ алгоритмом, используемым в пределах архивов JAR. Pack200 обеспечивает намного большее сжатие. Однако, архивы Pack200 не разрабатываются для прямого выполнения никакой виртуальной машиной. Больший уровень сжатия Pack200 выигрывается по стоимости сложности в неупаковщике, сложность, несовместимая с любым требованием прямой загрузки или выполнения.
Почему не делает Кодирования методом Хаффмана использования Pack200? (Тот же самый вопрос для LZW, или BWT, или перемещение к передней стороне, или любой другой стандартный метод сжатия.) Как простоту и подразделение рабочей силы, Pack200 преднамеренно сосредотачивается на том, чтобы находить и удалять крупномасштабную избыточность, определенную для файлов class. Pack200 производит байтовый вывод, мы надеемся, с четкими образцами и простую статистику алфавита. Это полагается на компрессор постпередачи, чтобы закодировать эти байты в некотором более эффективном совместном использовании строки, нарезанном битом представлении.
Следующие соображения поддерживают этот проект:
Как эта спецификация справляется с изменениями формата архива? Номера основной версии и номера вспомогательной версии архива Pack200 дают объявление, какая версия этого стандарта была сгенерирована упаковщиком. Из-за гибкости разметок атрибута упаковщики могут иногда представлять новые форматы classfile в старых форматах архива, но более новые форматы архива могут требоваться по причинам функциональности или производительности.
Реализации неупаковщика строго поощряются поддерживать каждую стандартную версию формата архива, так как есть не всегда выравнивание strong между версиями упаковщика и неупаковщика с обоих концов канала развертывания. Реализации упаковщика поощряются сохранить возможность испустить более старые форматы архива, поддержать максимальную совместимость с неупаковщиками.
Ссылочная реализация хочет поддерживать обратную совместимость, производя 1.5 формата пакета, если входной архив JAR содержит № 1.6 (или более новый) classfiles. Вообще, это произведет самую старую версию архива, совместимую со всем вводом classfiles. Пустой архив примет значение по умолчанию к самой старой версии архива, которая является 1.5.