Как определить размер массива в байт-коде Java (FindBugs)
-
13-09-2019 - |
Вопрос
Я хотел бы узнать о размере выделяемого массива, просмотрев байт-код, если эта информация, конечно, известна во время компиляции.
Фон:Я хочу написать детектор FindBugs (который просматривает скомпилированный байт-код) и сообщать об определенных случаях выделения массива.Чтобы отфильтровать ложные срабатывания, меня интересуют не «маленькие» массивы, а только те, размер которых недоступен во время компиляции или превышает настраиваемый порог.
Поскольку исходный код FindBugs не слишком подробно документирован, я ищу несколько советов о том, как начать работу — возможно, уже существует детектор, делающий что-то подобное, и я мог бы посмотреть на него.
Решение
Это может оказаться довольно сложно.Мои знания неполны, но вам следует обратить внимание как минимум на три типа инструкций (NEWARRAY, ANEWARRAY и MULTIANEWARRAY).Глядя на предыдущую инструкцию (или в случае MULTIANEWARRAY, н предыдущие инструкции) получает размер, который, даже если бы он был константой, мог бы быть загружен с помощью BIPUSH, SIPUSH или LDC (что-нибудь еще?) в зависимости от размера.Как вы заметили, если класс является результатом вычислений, вы можете бесконечно отслеживать инструкции.
Если я правильно помню, FindBugs использует BCEL внутри себя, но я никогда не копался там, чтобы увидеть, насколько они умны.Если у любой из этих команд есть соответствующие списки рассылки, они могут оказаться лучшим местом для вопросов - они, вероятно, по крайней мере будут знать, шел ли кто-то по этому пути раньше.
Другие советы
Что ж, если они выделяются на основе константы, вы можете проверить константу, которая была добавлена непосредственно перед выделением.Например:
class ArraySize {
private static final int smallsize = 10;
private static final int largesize = 1000;
public static void main(String[] args) {
int[] small = new int[smallsize];
int[] big = new int[largesize];
}
}
дает байт-код:
Compiled from "ArraySize.java"
class ArraySize extends java.lang.Object{
ArraySize();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: bipush 10
2: newarray int
4: astore_1
5: sipush 1000
8: newarray int
10: astore_2
11: return
}