|
Spec-Zone .ru
спецификации, руководства, описания, API
|
Этот формат позволяет любому числу (от одного до сотен тысяч) классов Java быть закодированным компрессором, переданным сжато в единственном блоке байтов, и декодировал декомпрессором в эквивалентные файлы класса Java. Поскольку это может также представить ресурсы класса и другие "файлы стороны", это может служить альтернативой архиву JAR для некоторых задач развертывания, особенно загружая приложения Java.
Формат Pack200 может уменьшить размер приложения Java фактором семь - девять, по сравнению с эквивалентным JAR, содержащим несжатые хранившие файлы класса. В отличие от этого, использование 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, найденными в реальных продуктах. Попытка удалить сложность из этой спецификации вероятна также удалить в известной мере существенную эффективность сжатия.
Никакое специальное сжатие или преобразование не выполняются ни на каком файле кроме файлов класса кроме (возможно) переупорядочения их типом файла. Компрессор постпередачи, как предполагается, обеспечивает соответствующее сжатие на тех промежутках архива, которые переносят изображения файлов некласса.
Классы представляются в форме, которая подавляет их отдельные постоянные пулы, в пользу большого постоянного пула, который служит всему архиву. Таким образом, когда файл класса извлекается из архива Pack200, новый постоянный пул будет создаваться для него, и все постоянные скорректированные ссылки пула. Это не изменяет семантику класса, но это обычно изменит поразрядное изображение файла, и возможно даже его размер, поскольку неиспользованные постоянные записи пула удаляются.
Отметьте, что каждый файл класса должен быть полностью проанализирован компрессором, так, чтобы все постоянные индексы пула могли быть найдены и (позже) перенумерованы. Это требование применяется к любому классу, полю, методу, или атрибуту кода, который обращается к константе. Формат Pack200 поддерживает умеренный диапазон атрибутов. Скромное разнообразие новых разметок атрибута может быть объявлено к компрессору, и формат Pack200 обеспечивает место, чтобы передать такие разметки для использования декомпрессорами.
Логически, полоса является неявно размерным массивом 32-разрядных целых без знака. Однако, редко для полосы физически потребовать больше чем одного или двух байтов за элемент, так как кодировки элемента выбираются, чтобы передать фактические значения полосы более сжато.
У полосы нет никакого фиксированного заголовка, не даже индикации относительно его размера. Количество элементов полосы выводится декомпрессором из содержания предыдущих полос, или (в конечном счете) от заголовка архива.
У элементов любой данной полосы есть общее значение и роль. Например, имена всех переданных классов находятся в единственной полосе, в то время как все полевые количества класса находятся в различной полосе. Каждая полоса передается как непрерывный сегмент байтов в пределах архива. Эта смежность является главной причиной, что Pack200 архив, в то время как уплотнено для начала, очень сжимаем утилитами как zip.
В некоторых полосах каждый элемент помогает описать один объект. Например, каждый класс связывается с количеством полей, которое дается в архиве как соответствующее значение в полосе class_field_count. В других полосах один объект может быть описан выполнением нуля или большего количества элементов в полосе. Например, интерфейсы, реализованные классом, даются в архиве как соответствующее выполнение нуля или большего количества значений в полосе class_interface; каждое такое значение является индексом, обращающимся к единому классу.
Очень немного полос (меньше чем 10) содержат негомогенные байты, такие как изображения файлов ресурсов. Они немногих вызывают полосами байта. Многие из полос содержат ссылки в постоянный пул. Некоторые содержат флаги модификатора доступа и связанные биты. Одна полоса, названная полосой случайной работы, содержит строковые символы в особенно выбранном кодировании под названием "CHAR3" (несколько родственный UTF8, но не идентичный). Остальная часть полос передает целые числа со множеством других интерпретаций.
Одна из целочисленных полос (cp_Utf8_big_chars) переносит символы единственной строки CONSTANT_Utf8, выбранной для специального режима. Уникально, эта полоса повторяется нуль или больше раз, в зависимости от того, сколько строк выбирается для этого специального режима. (Эти особенно переданные "большие строки" объясняются позже в этом документе.)
У большинства полос есть легко понятая функция, такая как передача числа методов в классе, или имени поля, или операнда "getfield" инструкции байт-кода.
За исключением особого случая полос байта, полосу никогда не рассматривают как размерный промежуток байтов, а скорее как считаемая серия элементов, которые являются закодированными целыми числами. Так как целочисленные кодировки обычно переменного размера (когда расценено как последовательности байта), нет никакого твердого правила для того, чтобы получить размер байта полосы из его количества элемента. Действительно, обнаружение конца полосы требует, чтобы это был проанализированный байт байтом.
Как можно было бы ожидать, полосы байта (которые кодируют bytewise данные, такие как изображения файла ресурсов), кодируют их целые числа 8-разрядными байтами без знака. Это кодирование называют BYTE1 в этой спецификации. (Сравните тип "u1" в определении файла класса.)
У других полос есть значения с намного большим динамическим диапазоном, включая (в нескольких случаях) отрицательные числа, и/или значения полностью до 32-разрядного максимума без знака. Большинство этих кодировок является переменной длиной в ожидании, что типичный элемент полосы будет относительно маленьким в величине, даже при том, что некоторые элементы могут быть большими и потребовать, чтобы больше байтов представило. Некоторые полосы, которые, как ожидают, покажут сильные корреляции в их последовательностях элемента, кодируются как последовательные различия (кодирование дельты), а не абсолютные числовые значения.
Каждая полоса связывается с основным кодированием, которое компрессор и декомпрессор соглашаются использовать, передавая элементы той полосы. Кроме в полосах байта, компрессор может дополнительно определить вторичное кодирование, чтобы использовать вместо основного кодирования. В основном, значения по умолчанию кодирования полосы к основному устройству, если нет явно объявленное вторичное устройство. Это позволяет формату 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 | главным образом монотонные последовательности |
Вместо того, чтобы описывать полосы в длинной и тусклой последовательности, мы используем простую, нерекурсивную грамматику, чтобы представить их организованным способом. Эта грамматика примерно параллельна грамматике файла класса:
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 не будет присутствовать в каждом заголовке сегмента, оно должно быть вставлено прежде, чем другой сегмент добавляется, так, чтобы декомпрессор мог найти конец каждого сегмента. Формат заголовка сегмента является так, что этой корректировкой, может быть сделан легко.)
Когда объединено с транспортным уровнем потоковой передачи, сегментация обеспечивает путь к компрессору, чтобы уменьшить задержку или уменьшить требования к памяти декомпрессора по стоимости в эффективности компрессора.
Сегментация может также помочь решить масштабирующуюся проблему с очень большими архивами (многих десятков мегабайтов), в котором ширина индексов в объединенные глобальные постоянные пулы может вырасти вне преимуществ глобального постоянного совместного использования. Запуская новый сегмент, компрессор сбрасывает постоянные пулы декомпрессора, убирая бесполезные константы, за счет повторного заявления о константах, которые находятся все еще в использовании. (Компромиссы подобны в разновидности проекту копирования сборщиков "мусора".)
Только магические числа архива (первые четыре байта заголовка сегмента) фиксируются в размере. Все другие структуры архива являются переменными в размере и должны поэтому быть проанализированы последовательно. Вообще говоря, декомпрессоры должны выполнить два, передает по каждому сегменту архива, один, чтобы измерить и проанализировать полосы, и один, чтобы последовательно извлечь информацию из полос в каждый элемент 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 должен быть номером 160. Оба из последних двух значений могут быть постепенно увеличены в будущем, чтобы отразить маленькие версии в этом формате файла. Отметьте, что в предыдущей версии этого стандарта, номера вспомогательной версии и номера основной версии были 7 и 150.
Заголовок также содержит начальные количества постоянных записей пула и других "высокоуровневых" объектов. Все эти количества даются в формате 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 | (неиспользованный, должен быть нуль), | |
| 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_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 дает число файлов, которые описываются подробно архивом. Отметьте, что файл класса, который достаточно прост (столь же описанный ниже) не должен быть описан как файл, потому что это достаточно, что сам класс передается. Поэтому, #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_number_counts:
#cp_Int_count :UNSIGNED5[1]
#cp_Float_count :UNSIGNED5[1]
#cp_Long_count :UNSIGNED5[1]
#cp_Double_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.
У каждого файла класса есть заголовок, который включает магическое число и номера вспомогательной версии и номера основной версии. Магическое число (0xCAFEBABE), будучи фиксированной постоянной, не передается в архиве Pack200. Однако, номера версий, которые могут измениться несколько, должны быть записаны.
В ожидании, что определенные номера версий будут распространены, передачи заголовка архива номера основной версии по умолчанию и номера вспомогательной версии. Оба из этих чисел даются в формате UNSIGNED5.
Отдельные классы в архиве (как отмечено ниже) могут дополнительно определить свои собственные номера версий в псевдоатрибуте, который переопределяет #default_class_minver и #default_class_majver, данный в заголовке архива.
Количество #band_headers_size дает размер в байтах band_headers. Формат этих байтов, какая справка определяет спецификаторы кодирования полосы для вторичного codings, будет обсужден намного позже в разделе по метакодированию.
Заголовок архива также определяет, что число атрибута вводит (#attr_definition_count), определения классов (#class_count), вложенные объявления класса (#ic_count). Эти числа используются, чтобы измерить различные другие полосы, как отмечено в определении тех полос.
Арифметическая сумма всех 12 постоянных количеств пула должна быть меньше чем значение 536870912 (2^29). Компрессору запрещают передать архив, для которого сумма достигает или превышает этот предел. Это ограничение предназначается, чтобы позволить декомпрессорам использовать, внутренне, объединенную нумерацию констант, даже если определенные константы (такие как demangled внутренние имена классов или неявные имена SourceFile) должны быть добавлены на лету во время распаковки к постоянному пулу.
Примечание по реализации: Поскольку cp_counts передает целых 12 чисел, есть целых 26 32-разрядных целых чисел, переданных в заголовке архива. Заголовок сегмента содержит три дополнительных поддиапазона, содержа два, пять, и четыре значения. Минимальный размер segment_header - поэтому 19 байтов, и его гипотетический максимум составляет 134 байта. Кроме того декомпрессор, который хотел избежать любого побочное чтение вперед, мог считать и буферизовать начальный блок 19 байтов, которые будут уверенны, что содержали поля #archive_size. (Это предполагает, что номера версий являются небольшими, как они.) Это могло тогда сразу проанализировать достаточную информацию, чтобы определить, сколько дополнительных байтов буферного хранения будет обязано сканировать остальную часть архива, по крайней мере до изображений файла ресурсов. К тому времени, когда изображения файла ресурсов в *file_bits должны быть проанализированы, декомпрессор уже считает полосы *file_size, и будет в состоянии удалить любую неопределенность, первоначально существующую в #archive_size. (Если поля #archive_size являются нулем, декомпрессор может быть вынужден читать вслепую до конца всех данных на входном канале, чтобы проанализировать архив.)
Постоянные пулы консолидируют информацию в постоянных пулах всех входных файлов класса. Каждый постоянный пул содержит единственный тип постоянной величины. Каждый из одиннадцати постоянных типов пула, найденных в файлах класса, помещается в его собственный постоянный пул. Двенадцатый пул содержит подписи, которые в файлах класса являются строками UTF8, которые представляют метод, и типы поля, но в архивах Pack200 являются отдельно сжатым типом данных.
Следующая таблица дает двенадцать постоянных пулов в их порядке определения. Это также определяет их корреспонденцию постоянным типам, найденным в формате файла класса Java.
| Имя | элемент файла класса | тег файла класса | Цель |
|---|---|---|---|
| cp_Utf8 | ConstantPool.cpUtf8 | CONSTANT_Utf8 | основные строковые данные |
| cp_Int | ConstantPool.cpInteger | CONSTANT_Integer | международная константа |
| cp_Float | ConstantPool.cpFloat | CONSTANT_Float | константа плавающая |
| cp_Long | ConstantPool.cpLong | CONSTANT_Long | долго постоянный |
| cp_Double | ConstantPool.cpDouble | CONSTANT_Double | двойная константа |
| cp_String | ConstantPool.cpString | CONSTANT_String | Строковая константа |
| cp_Class | ConstantPool.cpClass | CONSTANT_Class | ссылка класса |
| cp_Signature | (см. ниже), | (ни один) | метод, поле, или тип переменной |
| cp_Descr | ConstantPool.cpNameAndType | CONSTANT_NameAndType | пара (имя, введите), |
| cp_Field | ConstantPool.cpFieldref | CONSTANT_Fieldref | полевая ссылка |
| cp_Method | ConstantPool.cpMethodref | CONSTANT_Methodref | вызов метода |
| cp_Imethod | ConstantPool.cpInterfaceMethodref | CONSTANT_InterfaceMethodref | интерфейсный вызов |
| (ни один) | CONSTANT_Unicode | неиспользованный тип |
Каждый постоянный пул является логически рядом символьных или числовых значений, всего одного типа. В архиве Pack200 это структурируется как последовательность таких значений, каждого с уникальным индексом в пределах последовательности. В другом месте в архиве, всякий раз, когда константа должна быть упомянута, ее индекс в пределах соответствующего постоянного пула (или в пределах подмножества пула) дается. (Подмножества пула будут описаны мимоходом наряду с полосами, которые содержат ссылки в них.)
В отличие от формата файла класса, постоянная индексация пула в формате архива Pack200 запускается в нуле. В редких местах, где нулевые ссылки ожидаются, документируется возможность, и сами нулевые ссылки кодируются нулевым индексом, в то время как все другие индексные значения постепенно увеличиваются одним. Где нулевые ссылки не ожидаются, они могут все еще быть закодированы 32-разрядным индексным значением-1.
Также в отличие от файлов класса, нет никаких "разрывов" или неиспользованных индексов, связанных с длинными или двойными значениями. Иногда, мы обратимся формально к элементу постоянного пула при использовании нотации массива. Например, первыми тремя целыми числами в cp_Int, постоянным пулом является cp_Int[0], cp_Int[1], и cp_Int[2], и последнее целое число, является cp_Int[cp_Int_count-1]. Отметьте, что обе полосы и постоянные пулы обрабатываются в этой спецификации как массивы с нулевым источником.
Это недопустимо для компрессора, чтобы передать ту же самую константу дважды. Таким образом, все постоянные записи пула должны быть уникальными.
В файле класса, за немногим исключением, постоянные ссылки пула со строгим контролем типов, в той каждой ссылке или нуль или обращается к постоянной записи пула фиксированного тега, связанного с контекстом ссылки. Исключения являются атрибутами ConstantValue и полями операнда ldc, ldc_w, и инструкций ldc2_w.
Однако, потому что постоянные пулы в архиве Pack200 отдельно индексируются, все постоянные ссылки должны быть со строгим контролем типов, так, чтобы был только один постоянный пул (или подмножество пула), в который применяется любой данный индекс. Это выполняется любой, выводя постоянный тип из контекста (в случае атрибутов ConstantValue) или добавляя дополнительную информацию к контексту ссылки. (В потоке байт-кода ldc разделяется постоянным типом в отличные инструкции aldc, 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
Как может быть замечен здесь, постоянные пулы, записи которых могут быть получены из единственного 32-разрядного целого числа или единственной ссылки, представляются как единственные полосы. Другие постоянные пулы представляются как группы полос. Каждый постоянный пул дает свое имя к соответствующему элементу грамматики. Это производство cp_bands объявляет порядок каждой полосы или группу полос, которая передает константы в eponymous постоянном пуле.
Отметьте использование UDELTA5 как основные кодировки для нескольких полос. Хотя формат файла Pack200 не требует никакого определенного упорядочивания значений в постоянных пулах, обычно выгодно упорядочить их так, чтобы закодированные значения в полосах, используя UDELTA5 монотонно увеличились. (Отрицательные дельты могут быть закодированы, хотя дорого, UDELTA5. Кроме того, вторичное кодирование со знаком может быть выбрано компрессором вместо UDELTA5.) Выбор основных кодировок в этой спецификации отражает ожидание, что высококачественные компрессоры, когда подарено выбор выходных упорядочиваний, сделают выбор, который приводит к хорошему использованию основных кодировок полосы.
Значения в 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]
Когда значения с плавающей точкой в конечном счете пишутся файлам класса, их биты должны быть точно сохранены, как будто они были обработаны java.lang.Float.floatToRawIntBits или java.lang.Double.doubleToRawLongBits. Таким образом значения "НЭН" передаются искренне без нормализации.
(Отметьте: Хотя было бы возможно расширить кодирующие полосу методы Pack200, чтобы закодировать 64-разрядные значения непосредственно, этот формат файла всегда передает 64-разрядные значения как пар 32-разрядных значений, переданных в парах полос. Это упрощает реализации, позволяя им обработать данные полосы с 32-разрядными информационными каналами.)
Каждая строка в cp_String постоянный пул представляется в его полосе ссылкой на написание строки как постоянный cp_Utf8.
Аналогично, каждый класс в cp_Class постоянный пул представляется в его полосе ссылкой на написание класса как постоянный cp_Utf8. (Как в файле класса и 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, как только встроенные ссылки класса расширяются в их написания. Константы подписи достаточно гибки, чтобы представить произвольные строки, но предназначаются для строк, которые часто содержат имена классов после эля прописной буквы 'L'. Они включают поле, метод, и типы локальных переменных, и универсальные атрибуты Signature.
Каждая строка подписи анализируется в форму и последовательность нуля или большего количества ссылок класса. Ссылки класса получаются, располагаясь в исходной строке подписи все последовательности, которые соответствуют образец "имя класса L", удаляя часть имени класса, и обрабатывая ее как ссылка в cp_Class постоянный пул. Форма определяется как остаток после того, как имена классов были удалены из исходной строки.
Форме не позволяют содержать возникновения эля буквы ('L') кроме тех, которые отмечают удаленные имена классов.
Таким образом форма будет содержать символьный 'L' везде, где исходная строка типа обращается к классу. Считая число этих символов в форме, декомпрессор может вывести число классов, к которым обращается исходная строка типа. Это число вызывают длиной класса формы.
Отметьте, что константы cp_Class не обязаны обращаться к существующим классам, и при этом они даже не требуются иметь допустимые написания имени класса. Поэтому, у компрессора есть значительная широта в выборе, какие имена классов (если кто-либо) это извлечет из строк подписи. В крайнем случае компрессор может сделать каждую форму идентичной ее соответствующей строке подписи, и просто удовлетворить ее длину класса, испуская ссылки на фиктивный класс с пустым названием. (Эта длина класса должна была бы включать любые возникновения 'L' в именах классов непосредственно.)
Отметьте также, что эти правила кодирования не требуют, чтобы имя класса сопровождалось любым определенным символом, хотя это обычно будет точка с запятой, или возможно левая угловая скобка, в случае экземпляра универсального типа в атрибуте Signature.
Правила также позволяют компрессору решать, произвольно, сколько символов (если кто-либо) после каждого эля буквы 'L' будет передан как часть имени класса. Поэтому, данная строка подписи может быть представимой несколькими формами, любая из которых декомпрессор должен быть подготовлен обработать.
Вот некоторые примеры:
| Введите Строку Подписи | Форма | Класс Лен. |
Класс... |
|---|---|---|---|
| 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 на строку подписи. Для каждой формы последовательность длиной до класса классов, требуемых воссоздавать строку подписи, передается как выполнение ссылок 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 являются упорядоченной парой класса (представленный как ссылка 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)
Файл класса, содержание которого сжимается Pack200, отмечается как "тупик" со специальным битом опции. У файла тупика класса, как должны объявлять, есть длина нуля. У этого, как могут объявлять, есть пустая строка для ее имени. Если есть недостаточно многие файлы тупика класса, переданные, чтобы соответствовать с числом переданных классов, декомпрессор должен действовать, как будто компрессор передал дополнительную серию тривиальных тупиков без имени или содержания, и время изменения и подсказка дефляции, скопированная с заголовка архива.
Каждый файл ресурсов передается в архиве Pack200 как простое изображение bytewise под относительным путем, используя наклонную черту '/' как разделитель каталога. (Это - то же самое соглашение пути, как используется в архивах ZIP.) Каждый файл (оба файла ресурсов и файлы класса) может дополнительно быть связан с подсказкой дефляции и датой модификации.
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-разрядное слово.
Байты всего некласса (то есть, ресурс) файлы сразу следуют в полосе file_bits. Каждый файл дается как соответствующее выполнение значений байта.
Дополнительная полоса file_modtime, если не пустой, предоставляет время изменения для каждого файла ресурсов (и потенциально для файлов класса, если тупики файла класса присутствуют). Каждое целочисленное значение дает различие (в секундах) от значения #archive_modtime. (Поэтому, если значение #archive_modtime является нулем, отдельные времена файла должны быть интерпретированы как абсолютные значения.) Порядок передачи file_modtime является непротиворечивым с file_name. Эта полоса пуста, если бит have_file_modtime в #archive_options является четким.
Дополнительная полоса file_options, если не пустой, предоставляет флаговые биты для каждого файла ресурсов (и потенциально для файлов класса, если тупики файла класса присутствуют). Эта полоса пуста, если бит have_file_options в #archive_options является четким. Каждое слово file_options интерпретируется порязрядно. Определенным битам дают символьные имена следующим образом, где LSB нумеруется как разрядный нуль:
| Бит | Имя | Цель |
|---|---|---|
| 0 | deflate_hint | запросите сжатый элемент файла JAR |
| 1 | is_class_stub | этот файл содержит байт-коды класса |
Если deflate_hint (LSB) устанавливается, декомпрессор требуют (но не требуется) уменьшать размер его вывода. Например, если это производит файл JAR, это может выкачать элементы JAR. Так как бит deflate_hint в слове #archive_options имеет тот же самый эффект, два бита в действительности объединяются с логическим ИЛИ для каждого файла. Если is_class_stub (второй LSB) устанавливается, это описание файла ресурсов является фактически тупиком, и содержание файла определяется как байт-коды одного из классов, определенных в архиве Pack200. Другие биты в опциях файла должны быть нулем и резервируются для будущего использования.
Если переданный файл отмечается как тупик класса, его содержание должно быть передано, как будто файл был пуст. (Таким образом, file_size_hi и file_size_lo должны и быть нулем, и в file_bits, возможно, нет никаких соответствующих байтов.) Декомпрессор обязан предоставлять содержание для файла ресурсов, воссоздавая содержание файла класса для класса, переданного в class_this и т.д. Как любой другой файл ресурсов, тупику класса позволяют иметь имя, время изменения и deflate_hint.
Тупики класса и классы соответствуют в порядке. Определите полученный параметр #class_stub_count как число файлов, отмеченных как тупики класса. (Это - также количество набора битов is_class_stub в file_options.) Затем #class_stub_count должен быть не больше чем #class_count. Тупик первого класса определяет файл, который получает байт-коды для первого класса и так далее. Хотя у тупика класса есть имя (переданный в file_name), это имя может быть пустой строкой. В этом случае декомпрессор обязан использовать стандартное имя для файла класса, который создается из имени байт-кода класса (использующий наклонную черту '/' для разделителя пакета), добавляя строку ".class". (Таким образом у classfile может быть произвольное нестандартное имя, но работы сжатия лучше всего, если его имя получается из его класса обычным способом.)
Если #class_count больше чем #class_stub_count, то декомпрессор должен вести себя, как будто достаточное число тривиальных дополнительных тупиков класса было передано после последнего явного файла. У этих тривиальных тупиков есть строка пустого названия и нулевой deflate_hint или file_modtime.
Таким образом, в простом случае, где нет никаких тупиков класса вообще (возможно, потому что have_file_options является нулем), декомпрессор должен произвести свои файлы в их порядке передачи, сопровождаемом порядком передачи классов. У каждого файла класса должно быть свое стандартное имя, и время изменения и подсказка дефляции, наследованная от #archive_modtime и бита deflate_hint в #archive_options. Но за счет дополнительного размера передачи, компрессор может направить декомпрессор, чтобы представить ресурсы и файлы класса в любом фиксированном порядке, с произвольными именами, время изменения, и подсказки дефляции для каждого выходного файла. Декомпрессор должен соблюдать это упорядочивание, если его вывод находится в форме (такой как архив JAR), где порядок является существенным.
Компрессоры свободны, если иначе не направлено, выбрать любое упорядочивание файлов. Часто выгодно поместить файлы с подобной статистикой друг рядом с другом, так, чтобы компрессор постпередачи (если кто-либо) мог обработать их содержание вместе (в том же самом окне, в случае ВЫКАЧИВАТЬ алгоритма). Вероятно, что у компрессора, который в состоянии переупорядочить его входные файлы для эффективной передачи, будет опция команды, которая вынуждает это сохранить порядок, в котором были представлены входные файлы, потому что этот порядок является существенным некоторым (но не все) приложения развертывания.
Компрессоры свободны передать файлы класса, как будто они были файлами ресурсов. Это обеспечивает способ передать файлы класса, которые должны быть сохранены поразрядно, или которые компрессоры не могут передать сжатый с достаточной точностью. Декомпрессоры обязаны принимать файлы класса, переданные "порязрядно" как файлы ресурсов.
Отметьте: полосы, управляющие файлами и их атрибутами, передаются последние в архиве, чтобы ослабить реализацию декомпрессора немного, так как последняя вещь, которую делает декомпрессор, состоит в том, чтобы собрать выходные файлы. В частности файлы ресурсов могут иметь произвольный размер, и размещение их битов в конце архива позволяет декомпрессору избегать выделять временное хранение для них.
Пять наборов полос флага переносят биты модификатора и/или приписывают биты управления. Полоса 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), или класса, поля, метода, или атрибута кода (такого как Deprecated или SourceFile), или некоторой другой необходимой управляющей информации (такой как, есть ли у файла класса номер версии не по умолчанию).
У каждого класса (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, есть специальный нуль значения. (См. обсуждение заголовков кода ниже.)
Для классов, вложенных классов, полей, и методов, присвоение позиций флагового бита к модификаторам является тем же самым как этим в формате файла класса. (Например, LSB всегда представляет ACC_PUBLIC, и в архиве Pack200 и в форматах файлов класса.) Атрибут переполнения является атрибутом, присутствие которого не обозначается непосредственно через флаговый бит, и но вместо этого обозначается возникновением его индекса в отдельной полосе. Для классов, полей, методов, и кодов, бит 16 (как установлено в маске 0x0001000) указывает на присутствие атрибутов переполнения. Для вложенных классов флаговый бит 16 указывает на присутствие явного внешнего класса и полей имени, как объяснено ниже.
| Бит | Значение |
|---|---|
| 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 | переполнение (больше данных полосы в другом месте) |
В частности младший разряд 16 битов класса, поля, и флагов метода видимы в файле класса, и могут таким образом перенести биты модификатора. Ни один из битов слова флагов кода не видим в файле класса; эти флаговые биты используются только для податрибутов кода.
В отличие от этого, младший разряд, 16 битов вложенных записей класса используются исключительно для модификаторов, начиная с вложенных записей класса, не содержит атрибуты. В остальной части этого раздела по атрибутам мы игнорируем слова флага, связанные с вложенными записями класса.
Любая из этих 63 позиций двоичного разряда в значении флагов может быть присвоена компрессором указать к декомпрессору на присутствие некоторого определенного атрибута. Компрессор может "принять" бит модификатора, присваивая это определение атрибута. (Это делается, испуская определение для атрибута, который упоминает ту позицию двоичного разряда.)
Если компрессор "вступает во владение" немного (модификатор или не), который используется по умолчанию в другой цели, бит теряет свое предыдущее значение. Однако, компрессор, возможно, не испускает явное определение для того же самого бита дважды (в том же самом контексте).
Каждый вид атрибута определяется четырьмя сведениями: объект, к которому это применяется (класс, поле, метод, или код), позиция двоичного разряда, если таковые вообще имеются, которому это присваивается, имя атрибута (как это появляется в файле класса), и расположение атрибута (который позволяет декомпрессору должным образом форматировать возникновения атрибута в файле класса). Это - ошибка для компрессора, чтобы определить то же самое имя и расположение дважды в том же самом контексте. Это не ошибка повторить имя с различным расположением, или расположением с другим именем.
Первые два элемента закодированы битом в однобайтовый "заголовок", и переданы в полосе 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 привет слова) |
У каждого атрибута класса, предопределенный ли в этой спецификации или явно определенный компрессором, есть уникальное число, названное его индексом атрибута. Если атрибут присваивается флаговый бит, то его индекс атрибута идентичен позиции флагового бита (число в [0.. 62]). (Все предопределенные атрибуты присваиваются флаговый бит по умолчанию.)
Если атрибут класса не присваивается флаговый бит, это - атрибут переполнения, и его индекс присваивается последовательно в порядке, в котором атрибуты класса определяются (то есть, передаются). Первый индекс, который будет присвоен последовательно таким образом, 32, если #have_class_flags_hi является четким, и 63, если это устанавливается. Эти индексы используются в пределах архива, чтобы объявить возникновения атрибута для отдельных классов.
Аналогично, поле, метод, и атрибуты кода присваиваются их собственные индексы атрибута, независимо от атрибутов класса и друг друга. Поэтому, атрибут (то есть, имя и пара расположения) уникально определяется в пределах архива его типом контекста и индексом атрибута. Поле и атрибуты метода могут быть присвоены флаговым битам, или иначе они - атрибуты переполнения с индексами 32 или больше. Как другие атрибуты, атрибуты кода могут быть присвоены явные числа или неявно присваивали индексы, запускающиеся с 32. (Как с атрибутами класса, если высокие полосы слова флага выбираются соответствующим битом #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 | Класс | "версия файла класса" |
| 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-разрядных флаговых значениях, сохраненных в формате файла класса. Однако, компрессоры свободны снова использовать один из младшего разряда 16 битов слова флагов, связывая их с другими атрибутами, если никакой файл фактически не устанавливает их.
Атрибут InnerClasses обрабатывается особенно, как задокументировано в другом месте, и это - ошибка для компрессора, чтобы испустить определение атрибута для этого в контексте класса. Атрибут Code также обрабатывается особенно. Это - ошибка испустить определение атрибута для этого в контексте метода.
Эта спецификация не определяет, как компрессору сообщают о существовании или формате атрибутов, которые не предопределяются. Это просто предполагает, что компрессорам сообщают о таких атрибутах, и это требует, чтобы компрессоры должным образом передали эту информацию к декомпрессорам. Как особый случай, разумно для любого компрессора передать атрибут, не содержащий байтов (то есть, нулевой длины), как будто ее расположение, как было известно, было пустой строкой.
В дальнейшем мы говорим, что некоторый данный элемент расположения атрибута управляет скалярным значением, сохраненным в атрибуте файла класса, если декомпрессор должен использовать тот элемент, чтобы воссоздать, в файл класса, представление того скалярного значения. Мы также говорим, что данный элемент расположения управляет полосой, в которой передается скалярное значение.
Расположение атрибута определяется строкой на "небольшом языке". Строка должна быть проанализирована декомпрессором в последовательность элементов расположения, каждый из которых управляет передачей и хранением значений атрибута. В частности расположение объявляет расположения всех постоянных ссылок пула, позволяя их значения быть переданным с соответствующими представлениями, или как постоянные индексы пула или иначе как некоторый другой вид числа.
Самое простое применимое расположение атрибута было бы последовательностью постоянных ссылочных объявлений пула, смешанных с однобайтовыми объявлениями, чтобы управлять всем остальным, и компрессоры свободны использовать такие разметки, чтобы описать атрибуты. Однако, более определенные разметки атрибута приводят к лучшему сжатию.
Атрибуты обычно содержат постоянные ссылки пула и маленькие целые числа. Они часто содержат целые числа, которые управляют репликацией последующих образцов. Постоянные ссылки пула со строгим контролем типов где только возможно, и условие кодирования для нулевых ссылок должно быть объявлено также. Маленькие целые числа, которые кодируют флаговые биты или индексы байт-кода, также объявляются как таковые, так, чтобы специальные методы кодирования могли использоваться на них.
Объявления расположения являются строками 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' )
schema_ref:
( 'RC' | 'RS' | 'RD' | 'RF' | 'RM' | 'RI' )
utf8_ref:
'RU'
untyped_ref:
'RQ'
numeral:
'(' ('-')? (digit)+ ')'
digit:
( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' )
Каждое возникновение атрибута в файле класса связывается (компрессором) с соответствующим определением расположения, которое описывает точно значение байтов того атрибута. Компрессор должен присвоить каждый элемент формата его собственная полоса для того, чтобы передать последовательные значения того элемента формата. В случае предопределенных атрибутов полосы, присвоенные их элементам расположения, определяются по имени в этой спецификации.
Каждое значение, которым управляет элемент расположения атрибута, преобразовывается компрессором в 32-разрядное значение и передается как элемент полосы, уникально создаваемой для, и управляло тем элементом расположения. Для элементов расположения integral преобразование просто представляет число, сохраненное в файле класса под данным типом, в то время как элементы reference преобразовывают локальную постоянную ссылку пула (локальный для файла класса, который является) в глобальную переменную, типизированную ссылку в пределах архива.
Многократные возникновения того же самого вида элемента расположения расцениваются как отличные элементы расположения. Кроме того, полосы никогда не совместно используются разметками. Поэтому, каждое новое определение расположения, переданное компрессором неявно, определяет свой собственный набор полос. Переприсвоение ранее определенного расположения атрибута к новому индексу создает новый набор полос; это не снова использует ранее определенные наборы полос.
Если компрессор определяет новые атрибуты, он должен также создать полосы, которыми они управляют. Это должно передать эти полосы, сразу после места, зарезервированного в грамматике полосы для предопределенных атрибутов (в конце class_attr_bands, field_attr_bands, method_attr_bands, или code_attr_bands). Упорядочивание этих полос должно соответствовать порядку определения элементов расположения атрибута, которые управляют ими. Таким образом декомпрессор будет в состоянии найти те значения атрибута.
Порядок определения двух элементов расположения в той же самой строке расположения атрибута соответствует их порядку возникновения в пределах той строки. Порядок определения двух элементов расположения не в той же самой строке расположения атрибута соответствует индексному порядку их определений расположения в полосе attr_definition_layout. (Таким образом, полосы для разметок с более низкими индексами предшествуют полосам для разметок того же самого типа контекста, но с более высокими индексами. Это - истина, даже если ниже индексированное расположение, оказывается, определяется позже в полосе attr_definition_layout.) Отмечают, что полосы, которыми управляют предопределенные атрибуты, кажется, следуют за таким упорядочиванием также. Однако, полосы предопределенных атрибутов класса предшествуют всем другим полосам атрибута класса, и аналогично для полей, методов, и кодируют атрибуты.
Целочисленные значения, сохраненные в атрибутах, измеряются как 1, 2, или 4 байта, в зависимости от использования символа формата 'B', 'H', или 'я', соответственно. Целочисленный тип обычно без знака, но снабжается префиксом 'S', становится со знаком. Это подписание управляет удлинением 1-байтовых и 2-байтовых типов к 32-разрядным значениям (или расширение знака или нулевое заполнение). Это также определяет основное кодирование, используемое, чтобы передать 32-разрядные значения. Поскольку все целые числа, сохраненные в файлах класса, являются "обратным порядком байтов", все интегральные элементы формата обращаются к целым числам, кодированным с битами высшего порядка в более ранних байтах.
Разметки 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 в файле класса, то номер 2 будет передан, с тех пор 6 смещение третьей инструкции.
Если префиксом расположения является 'ПО', предыдущий элемент расположения, должно быть, также был индексом байт-кода типа 'P' расположения или 'ПО'. (Там не должен вмешиваться структура, такая как скобки' [' или']'.) В этом случае значение, переданное в полосе, которой управляет элемент 'ПО', является различием между перенумерованным индексом байт-кода, которым управляет текущий элемент 'ПО', и перенумерованным индексом байт-кода, которым управляет предыдущий 'P' или элемент 'ПО'. (В случае предыдущего элемента 'P' это - фактически значение, переданное в соответствующей позиции в предыдущей полосе.)
Элементы расположения 'ПО' управляют тем же самым видом данных атрибута как элементы 'P', но они используют кодирование, которое ожидает, что коррелируются смежные индексы байт-кода. Это изменение нумерации, включая различие для предыдущего элемента, вызывают, смещение байт-кода, перенумеровывая основное кодирование для полос, содержащих смещения байт-кода, является BRANCH5. Это кодирование используется, даже если элемент расположения содержит 'S' или символ 'B'.
Смещение байт-кода объявляется с префиксом расположения 'O'. Этот элемент расположения должен сразу следовать за предыдущим индексным элементом байт-кода (с префиксным 'P' и не 'ПО'). Любое значение, которым управляет этот элемент расположения, расценивается как смещение, которое когда применено к соответствующий ранее сохраненный индекс байт-кода, производит другой индекс байт-кода. Таким образом, и предыдущее значение и сумма предыдущего значения и текущей стоимости, как ожидают, обратятся к границам инструкции. Как с расположением 'ПО', переданное значение является различием двух перенумерованных индексов байт-кода. Полосы, которыми управляют разметки 'ПО', содержат смещения байт-кода, и используют основное кодирование BRANCH5. В отличие от расположения 'ПО', хранимая сумма, которой управляет расположение 'O', является различием между двумя индексами байт-кода.
Таким образом полосы, которыми управляют и 'O' и разметками 'ПО', содержат смещения байт-кода, и используют BRANCH5, чтобы закодировать те смещения. Но значения атрибута, которыми управляют и 'P' и разметками 'ПО', хранят абсолютные индексы байт-кода; только разметки 'O' управляют сохраненными смещениями байт-кода. Сохраненные смещения обрабатываются как поля без знака в файле класса, если символ 'S' не присутствует. В отличие от этого, сохраненные индексы всегда обрабатываются как поля без знака.
Если у предыдущего атрибута в качестве примера для 20-байтового метода также есть элемент расположения 'ПО' после его элемента 'P', и номер 20 сохранен в файле класса, число, которое будет передано, находится, перенумеровывая от 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', или 'я' не занимаю байтов вообще в атрибуте файла класса. Эти элементы расположения позволяют декомпрессору использовать количества, или теги, чтобы управлять передачей, не имея их появляются непосредственно в атрибутах файла класса. Например, рассмотрите атрибут, который является массивом байтов, который не самоизмеряет, но расширяется, чтобы заполнить количество байта, упомянутое в заголовке атрибута в файле класса. У такого атрибута могла бы быть спецификация расположения 'NV [B]'. Компрессор был бы ответственен, чтобы решить который значения передать для 'V' элемент расположения. (Такие решения должны были бы использовать подробную информацию о форматах атрибута, которая не является частью этой спецификации.) Во всех случаях декомпрессор должен уважать эти значения (когда использующийся в качестве количеств или тегов), но не должен сохранить их в файле класса.
Репликация представляется префиксным 'N', который сопровождается целочисленным элементом, названным количеством репликации, и к тому времени серия элементов, названных телом репликации, включила в квадратные скобки. Данные атрибута, которыми управляет это расположение, состоят из количества репликации, сопровождаемого массивом данных, считаемых количеством репликации. Каждым элементом массива управляют разметки в теле репликации.
Элемент расположения количества репликации управляет полосой, передающей количества репликации, у которого есть основное кодирование UNSIGNED5 (или BYTE1, если расположение запускается с 'NB'). Полосы, которыми управляет соответствующее тело репликации, могут быть измерены, суммируя значения, переданные в полосе, содержащей количества.
Объединение представляется префиксным 'T', который сопровождается целочисленным элементом, названным тегом объединения, и к тому времени серией маркированных, заключенных в скобки групп элементов, названных случаями объединения. (У цифр может быть любое число цифр, но их арифметические значения являются усеченными к 32-разрядным целым числам перед стать по сравнению со значениями полосы, которые также составляют 32 бита в размере.) Каждая метка, но последнее состоит из один или более заключенный в скобки, возможно десятичные цифры со знаком, названные тегами объединения. Последняя метка (который является случаем по умолчанию) должна быть пустой парой круглых скобок. (Никакое объединение не может содержать два возникновения того же самого тега случая.) Данные атрибута, которыми управляет это расположение, состоят из интегрального значения тега, сопровождаемого данными, формат которых определяется тегом. Данными после тега управляет (уникальный) случай объединения, метка которого соответствует значение тега, или иначе случай по умолчанию. Полосы, которыми управляет каждый случай объединения, могут быть измерены, считая число значений в полосе, которой управляет расположение тега. Как с простыми интегральными полосами, основное кодирование полосы тега объединения является SIGNED5, BYTE1, или UNSIGNED5, в зависимости от того, содержит ли расположение символ 'S', 'Тбайт', или иначе.
В теге объединения две цифры, разделенные дефисом, определяют содержащий диапазон. Второе число должно быть больше чем первое. Это - сокращение для списка всех цифр сначала к второму, включительно. Расположение обрабатывается точно, как будто сокращение было заменено полным списком.
Постоянные ссылки пула в атрибуте могут быть введены строго, и переданы как индексы в один из постоянных пулов архива. Типы расположения, начинающиеся 'с КИ', 'КИЛОДЖОУЛИ', 'KF', 'KD', и 'KS', должны управлять сохраненными индексами в локальном постоянном пуле к константам целого числа типа, долго, плавания, дважды, и строки. Аналогично, типы расположения, начинающиеся 'с RC', 'РТС ', RD', 'RF', 'КОМНАТА', 'RI', и 'RU' должны управлять сохраненными индексами в локальном постоянном пуле к символам класса типа, подписи, дескриптор (пара имени и типа), полевая ссылка, ссылка метода, интерфейсная ссылка метода, и строка UTF8. Все эти ссылки передаются как 32-разрядные индексы в соответствующие глобальные постоянные пулы в полосах с основным кодированием UNSIGNED5. (Это - истина даже разметок, которые содержат 'B'.) См. таблицу ниже.
Отметьте, что ссылки подписи (расположение 'РТС) идентичны ссылкам Utf8 (расположение 'RU') в пределах файла класса, но приводят к различной тактике кодирования в архивном файле, начиная с 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 |
Если постоянная ссылка пула не может быть со строгим контролем типов, компрессор должен использовать untyped_ref ('ЗАПРОС'). Кодирование такой нетипизированной ссылки является индексом во все пулы, перенумерованные в порядке, они происходят в пределах архива Pack200. Последовательность всех констант, в этом естественном порядке возникновения, вызывают cp_All. Например, все элементы пула cp_Utf8 нумеруются то же самое в разметках 'RU' и 'ЗАПРОСЕ'. Но первый элемент (нуль элемента) пула cp_Int нумеруется, для нетипизированных ссылок, как cp_Utf8_count, и первый элемент пула cp_Float нумеруется, для нетипизированных ссылок, как cp_Utf8_count+cp_Int_count.
Если компрессор сталкивается с атрибутом, который содержит постоянный индекс пула неожиданного типа, он может или отказаться передать атрибут, или выбрать передавать атрибут в соответствии с ослабленным определением расположения, используя элементы 'RQN' вместо большего количества элементов со строгим контролем типов. Декомпрессоры обязаны соблюдать все юридические определения расположения, переданные компрессорами, даже если они могли бы произвести незаконно отформатированные файлы класса. (В крайнем случае компрессор может выбрать передавать файл класса, как будто это был файл ресурсов, не получая специфичного для класса сжатия, но сохраняя необычно отформатированные атрибуты с поразрядной точностью.)
Если тип расположения 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 |
| 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 |
Здесь, переменная X имен значение, сохраненное в атрибуте, которым управляет элемент расположения. Переменный X0 называет хранимую сумму управляемой сразу предыдущим элементом расположения, который, должно быть, начался 'с P'. Выражение renumber_bci (I) обозначает изменение нумерации индекса I байт-кода, чтобы сократить ссылки на границы инструкции, как описано выше. Выражение lcp [я] обозначаю локальную постоянную ссылку пула с индексом I, или отличным нулевым значением, если я - нуль.
Выражение indexOf (lcp [я], cp) обозначает индекс (основанный на нуле) в глобальном постоянном cp пула Pack200 постоянного lcp [я], который, как предполагается, имеет тип, соответствующий cp. У этого выражения есть значение-1, если lcp [у меня] есть отличное нулевое значение.
Отметьте, что нулевая ссылка может всегда передаваться в полосе, содержащей ссылки, передавая нуль значения (если полоса определяется, чтобы принять, обнуляет), или передавая значение-1 (иначе). Кодирование UNSIGNED5 может представить-1 в пяти байтах.
Имя cp_All обращается к объединенному создаваемому массиву (как описано выше), связывая все глобальные постоянные пулы Pack200 в их порядке передачи. Имя cp_fieldSpecific обращается к глобальному постоянному пулу, выбранному полевой подписью включения, как описано выше.
Элемент расположения вызова является заключенной в скобки десятичной цифрой со знаком N. Это обращается к Энному вызываемому в высокоуровневой структуре спецификации расположения относительно вызываемого, в котором появляется вызов. (Это недопустимо для вызовов, чтобы появиться за пределами callables.) Мы обратимся к этому вызываемому как вызываемый вызова.
(Например, элемент расположения' (2)' вызовы второе вызываемое расположение после того, в котором появляется вызов. Должен быть соответствующий вызываемый для каждого вызываемого. Вызов, записанный' (1)', не должен появиться в последнем вызываемом из расположения, и аналогично вызов, записанный' (-1)', не должен произойти в первом вызываемом. Отметьте, что самовызов, записанный' (0)', является всегда законным.)
Элемент расположения вызова косвенно управляет данными атрибута, которыми более непосредственно управляют вызываемым, которое вызывает элемент расположения. Насколько формат файла класса затрагивается, эффект является тем же самым, как будто текстом в пределах тела 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 и трех подобных полосах, которые описываются позже.
| Тип контекста | Имя | Определение расположения |
|---|---|---|
| Класс | "версия файла класса" | (пустой) * (см. примечание), |
| Класс | InnerClasses | (пустой) * (см. примечание), |
| Класс | EnclosingMethod | RCHRDNH |
| Класс | SourceFile | RUNH * (см. примечание), |
| Класс | Подпись | RSH |
| Класс | (метаданные) | (см. ниже), |
| Класс | Устаревшие | (пустой) |
| Поле | ConstantValue | KQH |
| Поле | Подпись | RSH |
| Поле | (метаданные) | (см. ниже), |
| Поле | Устаревшие | (пустой) |
| Метод | Код | (пустой) * (см. примечание), |
| Метод | Исключения | NH [RCH] |
| Метод | Подпись | RSH |
| Метод | (метаданные) | (см. ниже), |
| Метод | Устаревшие | (пустой) |
| Код | StackMapTable | (см. ниже), |
| Код | LineNumberTable | NH [PHH] |
| Код | LocalVariableTable | NH [PHOHRUHRSHH] |
| Код | LocalVariableTypeTable | NH [PHOHRUHRSHH] |
Звезда '*' в определениях расположения "версии файла класса", InnerClasses, SourceFile, и Code отражает факт, что этим атрибутам дают специальную обработку. Для класса передается "псевдоатрибут" версии файла класса, как будто используя формат VV, но декомпрессор не хранит результат в атрибуте файла класса, а скорее в заголовке файла класса. (См. обсуждение ниже.) Для класса частично передается атрибут 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]
() []
]
Следующие наблюдения могут быть выведены, сравнивая эту спецификацию расположения со спецификацией формата файла класса, которая определяет атрибут StackMapTable. Второе вызываемое описывает структуру stack_map_frame от спецификации формата файла класса. В пределах объединения во втором вызываемом случаи поддерживают следующие члены профсоюза 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 от спецификации формата файла класса.
[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 с истинной нулевой ссылкой, он должен использовать нестандартное расположение.) Вот таблица примеров имен классов и соответствующих полученных имен 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>, даже при том, что они сохранены в различном порядке в формате файла класса. Как набор, эти глобально определенные четыре кортежа вызывают ic_All. обычно нет никакого явного редактирования от отдельных классов в архиве к вложенным записям класса. Вместо этого извлекая файл класса из архива Pack200, подмножество вложенных записей класса может быть выбрано, который достаточен, чтобы описать все вложенные классы, фактически упомянутые в постоянном пуле файла извлеченного класса. Для любого файла X класса, который будет извлечен, это подмножество вызовут ic_Relevant(X), соответствующим подмножеством для X из ic_All. Алгоритм для того, чтобы выбрать соответствующее подмножество описывается позже. Дополнительно, компрессор может определить, для любого данного класса, корректировки ее соответствующего подмножества, передавая локальный атрибут InnerClasses. Это также описывается в более позднем разделе по атрибутам класса. ic_this_class и полосы ic_flags имеют оба длину #ic_count, и соответствующие элементы этих полос определяют, для каждого кортежа, вложенные идентификационные данные класса (представленный как ссылка cp_Class) и битовая маска флагов.
Вложенный флаговый бит класса в позиции 16 (как установлено в маске 0x00010000) в архивном файле, чтобы указать, есть ли соответствующие записи для кортежа в полосах ic_name и ic_outer_class. Таким образом длина обеих из этих полос является суммой всех флаговых битов в позиции 16. Как правило, только несколько процентов вложенных классов должны установить этот бит и определить внешние и поля имени явно.
Если у кортежа есть запись в ic_outer_class и полосах ic_name, они определяют его внешний класс и простое имя. (Они представляются соответственно как возможно нулевая ссылка cp_Class и возможно нулевая ссылка cp_Utf8.) Иначе, внешний класс кортежа и имя, как говорят, предсказываются. В этом случае они должны быть правильно предсказуемыми с имени вложенного класса непосредственно, анализируя его написание.
У вложенного класса есть имя байт-кода, которое называет класс в пределах файлов класса. У написания этого имени, иногда называемого "скорректированным именем", есть дополнительные знаки пунктуации и возможно цифры так же как имя содержания класса. Если имя байт-кода может быть проанализировано во внешний класс и имя класса, и этот класс и имя идентичны с истинным внешним классом и именем класса вложенного класса, то мы говорим, что внешний класс и имя класса предсказуемы.
Экстракция предсказуемого внешнего класса и имени класса должна следовать за следующей грамматикой для имен байт-кода класса, в применении к написанию вложенного имени класса. (Эта грамматика независима от грамматики, управляющей структурой полосы, или любой другой грамматикой, появляющейся в других частях этой спецификации.) Терминальный ДОЛЛАР обращается к любому символу (такому как '$' или '#'), чей код является 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)*
Эта грамматика двусмысленно делит произвольное имя класса на несколько частей, которые могут включать дополнительный префикс predictedOuter, дополнительный суффикс predictedICName, и дополнительный числовой суффикс. Любая неоднозначность должна быть разрешена, предпочитая альтернативные случаи для bcn, нетерминального в данном порядке. Например, если bcnCase1 соответствует, он используется, даже при том, что или или оба других случая может соответствовать также.
Предсказуемое вложенное имя класса является строкой, соответствующей нетерминальному predictableICName, если это было проанализировано. Иначе предсказуемое вложенное имя класса берется, чтобы быть нулем.
Если predictableOuter, внешний нетерминальный, анализируется, соответствующая строка является предсказуемым внешним именем класса. Иначе предсказуемая внешняя ссылка класса берется, чтобы быть нулем. Отметьте, что, если нетерминальный number анализируется, никакой predictableOuter не может быть проанализирован. Вот некоторые примеры прогноза, непрогноза, и misprediction:
| вложенный класс: | элемент под названием Entry java/util/Map |
|---|---|
| скорректированное имя: | java/util/Map$Entry |
| внешний, имя: | java/util/Map, Entry |
| предсказуемый? | да (так как Map.Entry является элементом Map), |
| вложенный класс: | анонимный |
| скорректированное имя: | java/util/AbstractList$1 |
| внешний, имя: | (ни один), (ни один) |
| предсказуемый? | да (так как ic_name является нулем), |
| вложенный класс: | лицо, не являющееся членом какой-либо организации, названное Local |
| скорректированное имя: | java/util/AbstractList$2$Local |
| внешний, имя: | (ни один), Local |
| предсказуемый? | да (так как ic_name является Local), |
| вложенный класс: | лицо, не являющееся членом какой-либо организации, названное Local |
| скорректированное имя: | java/util/AbstractList#2#Local |
| внешний, имя: | (ни один), Local |
| предсказуемый? | да (так как ic_name является Local), |
| вложенный класс: | элемент под названием $2$Local Foo |
| скорректированное имя: | Foo$$2$Local |
| внешний, имя: | (ни один), Local |
| предсказуемый? | нет (внешние без вести пропавшие имени, ic_name mispredicted) |
| вложенный класс: | класс под названием Red$Herring |
| скорректированное имя: | Red$Herring |
| внешний, имя: | Red, Herring |
| предсказуемый? | нет (предсказанная ic_name Сельдь) |
| вложенный класс: | элемент под названием Q X$1 |
| скорректированное имя: | X$1$Q |
| внешний, имя: | (ни один), Q |
| предсказуемый? | нет (так как Q является элементом X$1), |
| вложенный класс: | элемент под названием Z X$Y |
| скорректированное имя: | X$Y$Z |
| внешний, имя: | X$Y, Z |
| предсказуемый? | да (так как X$Y.Z является элементом X$Y), |
| вложенный класс: | элемент под названием Y$Z X |
| скорректированное имя: | X$Y$Z |
| внешний, имя: | X$Y, Z |
| предсказуемый? | нет (внешнее имя и ic_name являются mispredicted), |
Когда декомпрессор обрабатывает вложенное имя класса, отмеченное "предсказуемый", он должен проанализировать имя байт-кода вложенного класса в класс включения, дополнительное число, и дополнительное имя. (Компрессор мог бы хотеть всегда определять внешние классы и имена явно, когда декомпрессор не будет обязан анализировать вложенные имена классов вообще. Однако, декомпрессоры должны всегда готовиться выполнить этот парсинг.)
Если бы компрессор не передавал запись в cp_Utf8 или cp_Class для предсказанного имени или внешнего класса, то декомпрессор должен создать такую константу внутренне. Это будет упоминаться как cp_Utf8 или запись cp_Class, даже при том, что это не находится в постоянной последовательности передачи cp_All. Однако, если бы компрессор действительно передавал константу с тем же самым написанием как предсказанное имя или внешний класс, то декомпрессор должен использовать ту константу вместо того, чтобы создать новый. Создание таких внутренних констант в пределах декомпрессора обнаруживаемо в выходном файле, потому что они вставляются в специальный порядок в постоянном пуле выходного файла. (См. обсуждение выходных правил упорядочивания ниже.)
Пожалуйста, см. раздел Приложения для псевдокода, объясняя это понятие.
Когда декомпрессор получает ic_this_class, ic_flags, ic_name, и полосы ic_outer_class, и выполняет любой необходимый парсинг имени, это создает набор ic_All четырех кортежей. Этот набор является основным источником атрибутов InnerClasses, синтезируемых для отдельных файлов класса декомпрессором.
class_bands:
*class_this :DELTA5 [#class_count] (cp_Class)
*class_super :DELTA5 [#class_count] (cp_Class)
*class_interface_count [#class_count] :DELTA5
*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_flags_lo, как определено выше.)
Полоса class_interface содержит выполнения объявлений интерфейса класса, один выполненный для каждого элемента class_interface_count, и применения к соответствующему классу.
Каждый элемент class_this, class_super, и class_interface является ссылкой (фактически, ненулевой ссылкой) к постоянному пулу cp_Class.
В уникальном случае java/lang/Object сохраненный суперкласс должен быть нулевой ссылкой. Вместо того, чтобы нарушать передачу всех других элементов полосы class_super, мы используем соглашение, что компрессор, когда это встречается с нулевой ссылкой суперкласса, должен передать в ее месте копию ссылки текущего класса. (Так как это недопустимо для класса, чтобы наследоваться от себя, это изменение нумерации нулевых ссылок однозначно.)
Полосы field_descr содержат одно выполнение элементов для каждого элемента class_field_count, и применяются к последовательным полям в соответствующем классе. Полосы method_descr содержат одно выполнение элементов для каждого элемента class_method_count, и применяются к последовательным методам в соответствующем классе.
(В отличие от формата файла класса, поле и дескрипторы метода сохранены как единственные ссылки на "имя-и-тип" постоянный пул, а не как пары ссылок имени и вводят ссылки.)
У полосы method_descr есть основное кодирование, которое выполняет лучше всего, если ссылки метода главным образом сортируются. Компрессоры могут выбрать использовать в своих интересах этот факт, сортируя методы в каждом классе. (Отметьте: обычно приемлемо для компрессоров переупорядочить методы для лучшего сжатия, но поля не должны быть переупорядочены, так как их порядок является очевидным посредством отражения и существенным к некоторым средствам, таким как сериализация.)
Полосы атрибута помещаются в позиции, обозначенные грамматикой. Они описываются ниже. Полосы атрибута включают полосы флагов, которые переносят и модификаторы доступа и приписывают индикаторы для соответствующих классов, полей, и методов.
Pack200 архивируют концы с полосами, посвященными блокам кода метода и байт-кодам непосредственно. Если у метода есть атрибут кода, компрессор должен упомянуть это в бите флагов (6-ой LSB), которому это присваивается, или как атрибут переполнения (с индексом 6). Поля атрибута Кода передаются в полосах, организованных под нетерминальным code_bands.
Спецификация каждого атрибута Кода начинается с трех основных параметров, которые объявляют число стека и локальных слотов, и число обработчиков. #Stack является числом слотов стека, используемых кодом. #NALocal является числом локальных переменных непараметра, используемых кодом. (Фактическим числом локальных переменных, объявленных в файле класса, будет #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, или нуль, если ссылка класса обработчика является нулем.
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
Если компрессор отмечает класс (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) индексов разметок атрибута, управляющих атрибутами класса (resp. поле, метод, или код). Компрессор должен передать индекс определения расположения атрибута для каждого атрибута переполнения.
Для каждого расположения атрибута, выбранного немного в элементе class_flags или элементом class_attr_indexes, компрессор должен получить данные, которыми управляют элементы расположения от атрибута класса и элементы передачи, кодирующие эти данные в полосах, которыми управляет расположение. Подобные условия просят поле, метод, и кодируют атрибуты.
Для каждого расположения атрибута, которое передает данные и содержит обратные вызовы, компрессор должен передать число раз, каждый назад вызываемый будет предметом обратного вызова, поскольку декомпрессор прокладывает себе путь посредством разметок атрибута. Эти количества вызова передаются в class_attr_calls, field_attr_calls, method_attr_calls, и полосах code_attr_calls, согласно типу контекста разметок, которым они применяются к. Количества вызова передаются, один на вызываемый обратный, в порядке определения callables. (См. выше.) Количества вызова только передаются для обратных callables, которые происходят в пределах разметок, которые используются, по крайней мере, однажды. Количества вызова не считают записи в любого вызываемыми из-за переводить вызова, и при этом они не считают начальный вызов вызываемого, которое инициирует обработку атрибута. Количество вызова могло бы быть нулем, если обратное вызываемое происходит в расположении, которое используется, но которое, оказывается, не достигает обратного вызываемого. Эти количества вызова необходимы, чтобы повредить зацикливание, свойственное от калибровки полос для взаимно рекурсивных разметок. Они предоставляют минимальную информацию, необходимую для декомпрессора, чтобы определить местоположение всех полос в архиве, до распределения полосы оценивает различным выходным классам. Поэтому количества вызова предоставляются один на расположение, суммированное по всем возникновениям атрибута того каждого расположения.
Декомпрессор ответственен за обработку любых явных определений расположения атрибута, переданных компрессором. Это должно подготовиться получать дополнительные полосы, которыми управляют те разметки. Когда это читает индексы определения расположения, это должно подготовиться читать в корректном числе значений, переданных в каждой из тех дополнительных полос.
Грамматика полос, определенных в этой спецификации, включает полосы, которыми управляют все предопределенные разметки атрибута. Для ясности некоторые названия группы упоминают часть элемента расположения, который создал их. Отметьте, что у Осуждаемых атрибутов нет никаких полос, потому что их разметки пусты.
Атрибуты под названием "Синтетический", хотя часть формата файла стандартного класса в более ранних версиях 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,...)]
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
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 [...]
Класс обладает "псевдоатрибутом" версии файла класса, если вспомогательная или основная версия файла его класса отличается от #default_class_minver или #default_class_majver, соответственно. Этот псевдоатрибут является парой 16-разрядных целых чисел, дающих номера основной версии и номера вспомогательной версии файла класса. Эти целые числа сохранены в заголовке файла класса, а не в записи атрибута. Как соглашение с 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. (Отметьте, что формат файла класса хранит элементы этих четырех кортежей в различном порядке, (C,C2,N,F).) Для данного файла X класса последовательность локальных кортежей IC вызывают ic_Local(X).
Для каждого локального кортежа IC, передач компрессора, в минимуме, значении C и значении F. Если переданное значение флагов F не является нулем, есть также соответствующие переданные постоянные ссылки пула C2 и N. В целом переданный локальный кортеж может или, возможно, не эквивалентен глобальному кортежу от ic_All.
Как сокращение, компрессор может передать только C и значение флагов нуля, если локальный кортеж IC, который будет передан, эквивалентен элементу ic_All, и никакой другой элемент ic_All не определяет тот же самый класс C. В этом случае декомпрессор должен вести себя точно, как будто все четыре компонента кортежа были явно переданы.
(Если все четыре компонента локального кортежа передаются, и значение флагов, которое будет передано, является фактически нулем, значение, 0x00010000 должен быть передан вместо нуля для флагов.)
Часто, компрессор не должен будет передать локальные кортежи IC вообще, так как набором четырех кортежей, которые будут сохранены в атрибуте InnerClasses класса, будет точно ic_Relevant(X) без требуемой корректировки. Если посторонние четыре кортежа (вне требуемых минимизированным постоянным пулом) будут найдены во входном файле класса, то некоторые локальные кортежи IC будут необходимы (с нулевыми флагами), чтобы обеспечить локальные "корни" для дополнительных записей InnerClasses. Это может произойти, если компилятор требует записи InnerClasses для класса, упомянутого только в подписи. Компрессоры обязаны предсказывать, какие классы требуют таких дополнительных локальных корней, и передают только неожиданные четыре кортежа.
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. Класс и полевые полосы метаданных функционируют похожим способом.
Отметьте, что JSR 175 не позволяет встроенные ссылки на записи CONSTANT_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 передают подпись класса и имя элемента постоянного перечисления как ссылки в cp_Signature и cp_Utf8. Для каждого тега значения '[', полоса method_RVA_casearray_N передает длину вложенного массива значения. Для каждого тега значения, полосы method_RVA_nesttype_RS и method_RVA_nestpair_N передают класс 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_classref :UNSIGNED5 [...] (current class or cp_Class)
*bc_fieldref :DELTA5 [...] (cp_Field)
*bc_methodref :UNSIGNED5 [...] (cp_Method)
*bc_imethodref :DELTA5 [...] (cp_Imethod)
*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 [...] (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 постоянный пул. Постепенное увеличение (единицей) резервирует нуль кода, который всегда обращается к текущему классу. (Это обеспечивает компактную форму для наиболее распространенной ссылки класса, которая является самоссылкой.)
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, соответственно.
Для каждого 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 [я] | aldc | да | 18 (=ldc) |
| ldc | cp_Class [я] | cldc | да | 233 |
| ldc | cp_Int [я] | ildc | да | 234 |
| ldc | cp_Float [я] | fldc | да | 235 |
| ldc_w | cp_String [я] | aldc_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 |
| getstatic | (этот элемент класса) | getstatic_this | нет | 202 |
| putstatic | (этот элемент класса) | putstatic_this | нет | 203 |
| getfield | (этот элемент класса) | getfield_this | нет | 204 |
| putfield | (этот элемент класса) | putfield_this | нет | 205 |
| invokevirtual | (этот элемент класса) | invokevirtual_this | нет | 206 |
| invokespecial | (этот элемент класса) | invokespecial_this | нет | 207 |
| invokestatic | (этот элемент класса) | invokestatic_this | нет | 208 |
| aload_0; getstatic | (этот элемент класса) | aload_0_getstatic_this | нет | 209 |
| aload_0; putstatic | (этот элемент класса) | aload_0_putstatic_this | нет | 210 |
| aload_0; getfield | (этот элемент класса) | aload_0_getfield_this | нет | 211 |
| aload_0; putfield | (этот элемент класса) | aload_0_putfield_this | нет | 212 |
| aload_0; invokevirtual | (этот элемент класса) | aload_0_invokevirtual_this | нет | 213 |
| aload_0; invokespecial | (этот элемент класса) | aload_0_invokespecial_this | нет | 214 |
| aload_0; invokestatic | (этот элемент класса) | aload_0_invokestatic_this | нет | 215 |
| getstatic | (элемент класса высшего качества) | getstatic_super | нет | 216 |
| putstatic | (элемент класса высшего качества) | putstatic_super | нет | 217 |
| getfield | (элемент класса высшего качества) | getfield_super | нет | 218 |
| putfield | (элемент класса высшего качества) | putfield_super | нет | 219 |
| invokevirtual | (элемент класса высшего качества) | invokevirtual_super | нет | 220 |
| invokespecial | (элемент класса высшего качества) | invokespecial_super | нет | 221 |
| invokestatic | (элемент класса высшего качества) | invokestatic_super | нет | 222 |
| aload_0; getstatic | (элемент класса высшего качества) | aload_0_getstatic_super | нет | 223 |
| aload_0; putstatic | (элемент класса высшего качества) | aload_0_putstatic_super | нет | 224 |
| aload_0; getfield | (элемент класса высшего качества) | aload_0_getfield_super | нет | 225 |
| aload_0; putfield | (элемент класса высшего качества) | aload_0_putfield_super | нет | 226 |
| aload_0; invokevirtual | (элемент класса высшего качества) | aload_0_invokevirtual_super | нет | 227 |
| aload_0; invokespecial | (элемент класса высшего качества) | aload_0_invokespecial_super | нет | 228 |
| aload_0; invokestatic | (элемент класса высшего качества) | aload_0_invokestatic_super | нет | 229 |
| invokespecial | (этот класс <init>) | invokespecial_this_init | нет | 230 |
| invokespecial | (класс высшего качества <init>) | invokespecial_super_init | нет | 231 |
| invokespecial | (новый класс <init>) | invokespecial_new_init | нет | 232 |
Каждая инструкция байт-кода содержится классом, названным текущим классом. Суперкласс (если кто-либо) текущего класса является текущим классом высшего качества. Операнд дословно новой "новой" инструкции (в том же самом методе) вызывают текущим новым классом.
Если инструкция обращается к полю или методу в текущем классе, это может (в опции компрессора), переписываются для передачи как соответствующий код операции, записанный с "_this". Аналогично, инструкция, обращающаяся к полю или методу в текущем классе высшего качества, может быть переписана как соответствующий код операции, записанный с "_super". В любом случае, если сразу предыдущая инструкция является aload_0 (код операции 42), передача той инструкции может быть подавлена компрессором, и соответствующим кодом операции, записанным с "aload_0 _" выбранный вместо этого; иначе "aload_0 _" разновидность не может быть выбрана.
Если invokespecial инструкция обращается к методу, названному <init> в текущем классе, текущем классе высшего качества, или текущем новом классе, компрессор может хотеть переписывать это как invokespecial_this_init, invokespecial_super_init, или invokespecial_new_init, соответственно.
Поле (resp. метод) операнды переписанных инструкций, записанных с "_this" (но не "_init"), передается в специальной полосе bc_thisfield (resp. bc_thismethod). Нумерация этих операндов определяется, беря последовательность символов в cp_Field (resp. cp_Method) и выбор только элементы текущего класса. Получающееся подмножество, не изменяя его порядок, перенумеровывается, запускаясь с нуля. Это обеспечивает компактное отображение маленьких целых чисел к элементам текущего класса.
Аналогично, операнды переписанных инструкций, записанных с "_super" (но не "_init"), передаются в bc_superfield или полосе bc_supermethod, и перенумеровываются как подмножество cp_Field или cp_Method, выбирая только элементы текущего класса высшего качества.
Наконец, операнды переписанных инструкций, записанных с "_init", передаются в полосе bc_initref, и перенумеровываются как подмножество cp_Method, выбрали согласно соответствующему классу (ток, ток супер, или новый ток), и также выбрали, чтобы иметь имя <init>. (Переданный индекс является обычно очень маленьким; в действительности это выбирает только подпись вызванного метода, и большинство классов обладает только несколькими конструкторами.)
Вот таблица, суммирующая передачу инструкций больше чем одного байта.
| Инструкция | Операнд | Переданный Значение |
Полоса |
|---|---|---|---|
| bipush | (байт) x | x & 0xFF | bc_byte |
| sipush | (короткий) x | x & 0xFFFF | bc_short |
| ildc | cp_Int [я] | я | bc_intref |
| fldc | cp_Float [я] | я | bc_floatref |
| aldc | cp_String [я] | я | bc_stringref |
| cldc | текущий класс | 0 | bc_classref |
| cldc | cp_Class [я] | i+1 | bc_classref |
| ildc_w | cp_Int [я] | я | bc_intref |
| fldc_w | cp_Float [я] | я | bc_floatref |
| aldc_w | cp_String [я] | я | bc_stringref |
| cldc_w | текущий класс | 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 |
| новый | текущий класс | 0 | bc_classref |
| новый | cp_Class [я] | 1+i | bc_classref |
| newarray | введите код | значение | bc_byte |
| anewarray | текущий класс | 0 | bc_classref |
| anewarray | cp_Class [я] | 1+i | bc_classref |
| checkcast | текущий класс | 0 | bc_classref |
| checkcast | cp_Class [я] | 1+i | bc_classref |
| instanceof | текущий класс | 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 |
| ** _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, каждый декомпрессор обязан производить определенное мудрое байтом изображение для каждого переданного файла класса. Это требование помещается в декомпрессоры, чтобы позволить компрессорам передать информацию, такую как обзоры сообщения, который касается возможного мудрого байтом содержания переданных файлов класса. Этот раздел описывает ограничения, установленные для каждого декомпрессора, который делает мудрое байтом содержание его выходных файлов четко определенной функцией его ввода.
Вообще, порядок элементов в распакованном файле класса должен быть непротиворечивым с порядком передачи в архиве Pack200. Например, порядок полей класса, объявленных в файле класса, должен соответствовать порядку, в котором полевые дескрипторы того класса были переданы в полосе field_descr. (Это также, оказывается, соответствует порядку в полосах field_flags.) Эта таблица дает все необходимые корреспонденции порядка файла класса с порядком передачи архива:
| элемент в файл класса |
полоса, который определяет порядок |
|---|---|
| реализованные интерфейсы | class_interface |
| объявленные поля | field_descr |
| объявленные методы | method_descr |
| список обработчика кода | code_handler_start_P |
| список атрибутов класса | class_flags, class_attr_indexes |
| полевой список атрибутов | field_flags, field_attr_indexes |
| список атрибутов метода | method_flags, method_attr_indexes |
| кодируйте список атрибутов | code_attr_indexes |
| постоянные записи пула | cp_Utf8, и т.д. (см. ниже), |
Вместе, эти необходимые корреспонденции порядка определяют точное содержание распакованного файла класса. Упорядочивание интерфейсов, полей, методов, и обработчиков исключений непосредственно определяется упорядочиванием полос, которые передают их.
Если атрибут InnerClasses должен быть добавлен к классу по правилам, данным в следующем разделе, тот атрибут должен прибыть последний в список атрибутов класса.
Затем cp(X) определяется, как будто следующими шагами, которые заполняют его от глобального постоянного пула cp_All, и также потенциально производят атрибут InnerClasses для X.
В этой точке постоянный пул cp(X) чувствует себя достаточно хорошо определенный, чтобы позволить декомпрессору вычислять набор соответствующих вложенных классов, названных ic_Relevant(X).
С ic_Relevant(X) и дополнительно переданным ic_Local(X) в руке, должен затем решить декомпрессор, сохранить ли атрибут InnerClasses ic_Stored(X) для X, используя эти шаги.
С последними вкладами от вложенных записей класса декомпрессор заканчивает постоянный пул, используя эти шаги:
После этого процесса у сохраненного постоянного пула X есть ссылочная целостность, и все постоянные ссылки могут быть кодированы как индексы в cp(X), которому получили определенный порядок из cp_All. В частности если константа в cp(X) должна обратиться к другой константе, которая постоянный, должно быть, уже была вставлена в cp(X), во время шагов закрытия.
Отметьте, что упорядочивание cp(X) является непротиворечивым с тем из cp_All, за исключением того, что некоторые ссылки подписи перенаправляются к эквивалентным существующим ранее элементам cp_Utf8, и все операнды ldc байт-кодов вызываются к передней стороне постоянного пула.
Присваивая локальные индексы элементам cp(X), декомпрессор должен, конечно, уважать резервирование пустых постоянных слотов пула для индексного нуля, и для CONSTANT_Long и констант CONSTANT_Double, как требуется форматом файла класса. Вместе с этими правилами, конструкцией и упорядочиванием 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 |
| 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_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_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_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_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_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 | [...] | 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));
}
(Множитель производительности сжатия 1.002 или больше для некоторого определенного метода является существенным, потому что такие множители накапливают с готовностью в производительность то уведомление конечных пользователей. Множитель меньше чем 1.0005 является незначащим.)
Pack200, как много других алгоритмов сжатия, позволяет компрессору много степеней свободы в выборе содержания сжатого архива, но никаких степеней свободы в выборе содержания распакованного файла JAR. Учитывая сжатый архив, все совместимые декомпрессоры Pack200 должны произвести те же самые байты файла класса для каждого переданного файла класса. Эта устойчивость вывода сохраняется для файлов класса, даже если файл ресурсов (такой как декларация) изменяет свое содержание. Таким образом, для любого данного файла класса, сжатие может быть с потерями, но распаковка каждого файла класса должна быть точной полезным способом, определенным спецификацией Pack200.
Это означает, что компрессор с правильными свойствами устойчивости может использоваться, чтобы произвести упакованный JAR со знаком, используя эти шаги:
(Отметьте: Если эта спецификация позволяет двум совместимым декомпрессорам производить различные элементы архива JAR для того же самого сжатого ввода архива, это - ошибка в спецификации. Спецификация, как думают, свободна от таких ошибок, но если Вы находите один, пожалуйста, сообщите об этом.)
Спецификация Pack200 не диктует интерпретацию строк имени файла относительно любого другого инструмента или операционной системы. Однако, естественное отображение было бы настолько когерентным насколько возможно с использованиями Java.
JAR и ZIP хранят даты в локальном формате (то есть, "YYYY/MM/DD HH:MM:SS") без спецификации часового пояса. Это означает, что преобразование в и с основанных на UTC времен Java требует предположения в часовом поясе, под которым работал компрессор. (Эта проблема не уникальна для Pack200. Это - проблема со всем использованием архивов JAR и ZIP.) Во многих целях стандартное предположение - то, что декомпрессор и компрессор работали в том же самом часовом поясе и во время того же самого ежегодного режима летнего времени. Однако, чтобы обеспечить больше устойчивости во времена, переданные в архивах Pack200, ожидается, что большинство компрессоров и декомпрессоров согласятся использовать UTC в качестве часового пояса, интерпретируя местное время стиля ZIP.
Следующие соображения поддерживают этот проект:
Реализации неупаковщика строго поощряются поддерживать каждую стандартную версию формата архива, так как есть не всегда сильное выравнивание между версиями упаковщика и неупаковщика с обоих концов канала развертывания. Реализации упаковщика поощряются сохранить возможность испустить более старые форматы архива, поддержать максимальную совместимость с неупаковщиками.
Ссылочная реализация хочет поддерживать обратную совместимость, производя 1.5 формата пакета, если входной архив JAR содержит 1.5 (или ниже) classfiles. Иначе это произведет 1.6 файла пакета. Ссылочный неупаковщик реализации является совместимым со всеми предыдущими стандартными версиями.