Java bytecode: типы локальных переменных?

В соответствии с этой статьей http://slurp.doc.ic.ac.uk/pubs/observing/linking.html#assignment:

Из-за различий в информации между Java-кодом и байт-кодом (байт-код не содержит типы локальных переменных), верификатор не нужно проверять подтипы для присвоений локальным переменным или к параметрам.

Мой вопрос: почему байт-код не содержит информацию о типе для локальных переменных, хотя он действительно содержит информацию о типе для параметров и возвращаемое значение?

Ответ 1

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

Существует верифицированный статический тип переменной, который может быть int, float, long, double, returnaddress или ссылкой на объект. Ссылки на объекты дополнительно вводятся с верхней границей, так что все ссылки являются подтипами java/lang/String, например. Поля могут дополнительно иметь один из коротких типов: байт, короткий, char или логический. Они обрабатываются одинаково с ints для целей выполнения, но имеют различное хранилище.

Наконец, существует тип среды выполнения, который совпадает с проверенным статическим типом, но в случае ссылок на объекты представляет собой фактический тип ссылки на экземпляр. Обратите внимание, что из-за верификации верификатора есть некоторые случаи, когда тип выполнения не может быть подтипом проверяемого типа. Например, переменная объявленного типа Comparable может фактически содержать любой объект в Hotspot, потому что VM не проверяет интерфейсы во время проверки.

Информация о времени компиляции не сохраняется, за исключением дополнительных атрибутов для отражения и отладки. Это потому, что нет оснований для его сохранения.

Локальные переменные не имеют информации о явном типе (кроме нового атрибута StackMapTable, но это техничность). Вместо этого, когда класс загружается, верификатор байт-кода вводит тип для каждого значения, запуская статический анализ потока данных. Цель этого заключается не в том, чтобы ловить ошибки, такие как проверка типа времени компиляции, потому что предполагается, что байт-код уже прошел такую ​​проверку во время компиляции.

Вместо этого целью проверки является обеспечение того, чтобы инструкции не были опасны для самой виртуальной машины. Например, он должен убедиться, что вы не берете целое число и не связываете его как ссылку на объект, поскольку это может привести к произвольному доступу к памяти и взлому виртуальной машины.

Таким образом, хотя значения байт-кода не имеют явной информации о типе, они имеют неявный тип, который является результатом вывода статического типа. Детали этого зависят от внутренних деталей реализации каждой виртуальной машины, хотя они должны следовать стандарту JVM. Но вам придется только беспокоиться об этом в рукописном байт-коде.

Поля имеют явный тип, так как виртуальная машина должна знать, какой тип данных хранится в ней. Параметры метода и типы возвращаемых данных кодируются в так называемом дескрипторе метода, который также используется при проверке типов. Их невозможно вывести автоматически, потому что эти значения могут исходить или уходить куда угодно, в то время как проверка типов выполняется для каждого класса.

P.S. Я пропустил несколько мелких деталей, когда говорил о типах проверки. Типы объектов дополнительно отслеживают, были ли они инициализированы или нет, и какая команда создала их, если они не инициализированы. Типы адресов отслеживают цель созданного ими jsr.

Ответ 2

Это довольно старая бумага. Текущие файлы классов включают типы для локальных и стековых переменных. Типы не сохраняются в байтовом методе метода, но сохраняются в атрибуте StackMapTable, прикрепленном к методу.

Это (и всегда было) возможно воссоздать типы всех локальных переменных и элементов стека посредством анализа потока данных без StackMapTable, но это вычислительно дорого. Код с StackMapTable можно проверить гораздо быстрее. Хотя я должен признать, что я не вижу, как проверка StackMapTable может быть быстрее, чем анализ, но тогда я почти ничего не знаю об этом.

Ответ 3

Java bytecode сохраняет информацию о типе <<21 > , method returns и parameters, но это не так,  Как вы спросили, содержат информацию о типе для local variables.

типа в файле класса Java делает задачу декомпиляции bytecode легче, чем декомпиляция machine code. Таким образом, декомпиляция байт-кода Java требует анализ большинства локальных переменных типов, выравнивание стека инструкции и структурирование loops и conditionals. Однако задача декомпиляции байт-кода сложнее компиляции. Вы бы часто видели декомпиляторы не могут полностью выполнить свою предполагаемую функцию.