Видимость и встраивание javac / JVM

1

Как влияние метода/поля влияет на метод вложения в Java?

Случай, который я имею в виду, - это нечто вроде public геттера для private поля:

private Thing blah;

public Thing getBlah() {
    return blah;
}

Здесь возникает несколько проблем.

Во-первых, делает ли сам компилятор Java какой-либо встраивание? На этот вопрос, кажется, отвечают по-разному, некоторые говорят " да", а некоторые говорят " нет". Я не знаю, было ли это потому, что он использовал, чтобы не делать какой-либо вставки, но теперь делает это, или это просто, что некоторые люди правы, а некоторые люди ошибаются...

Теперь, если это действительно делает некоторые inlining, я прав, думая, что он не может, возможно, inline getBlah() вызывает? Они были бы очевидным местом для того, чтобы вложение было полезным, потому что метод очень прост, и накладные расходы на вызов метода имеют такой же размер, как и код самого метода. Но если он был встроен компилятором, вы получите байт-код, который напрямую обратился к private полю; и, конечно же, JVM будет жаловаться? (Это применимо, даже если этот метод был static final).

Во-вторых, как насчет компилятора JIT? Насколько я вижу, эта проблема не применяется, когда дело доходит до вложения на этом уровне. После создания собственного кода JVM уже выполнил свои проверки и подтвердил, что я могу вызвать метод (потому что он public); поэтому он может затем генерировать собственный код, который встраивает вызов, без каких-либо проблем с видимостью... да?

Теги:
jvm
javac
jit
inlining

3 ответа

1
Лучший ответ

Компилятор javac (и любой действительный java-компилятор) не будет и не сможет встроить геттеры; подумайте об этом: вы можете расширить класс из этого класса и перезаписать геттер. И да, если компилятор будет чрезмерно зависеть от того, что доступ к нему не будет проходить через верификатор (ну, по крайней мере, он не должен пропускать верификатор, но они не проверяют все). В java 1.3 вы даже можете сделать main() частным, и все равно работа... аналогичным образом в javac была опция -O, которая иногда винила ваш код).

JIT - это целый другой зверь; он знает (ну, по крайней мере, в наши дни) в любое время, если есть перегрузка для метода или нет. Даже если класс загружается позже, что перезаписывает геттер, он может деоптимизировать уже JIT'd методы, чтобы отменить изменения в дереве наследования (это одна из оптимизаций компиляторов AOT не имеет информации для).

Таким образом, он может безопасно встраивать все, что захочет. Также не нужно искусственно поддерживать modfiers доступа, потому что в скомпилированном машинном коде нет такой вещи, и снова он знает, что такое трансформация кода vaild (и поскольку геттеры настолько распространены, что это также низкий уровень висящих фруктов для JIT оптимизировать).

Изменение: Чтобы сделать это абсолютно ясно, в параграфах рассматриваются потенциально виртуальные методы; особенно те, которые не являются частными, статическими или окончательными. В некоторых случаях Javac мог выполнять inlining; потому что это может доказать, что для них не существует переопределения. Было бы бессмысленным обязательством перед лицом того, что JIT также делает это, и он намного лучше работает над этим.

  • 0
    Я верю вам, что Javac не встроен. Возможно, нет никакого смысла, если JIT сможет сделать это позже. Но я не уверен, что вижу, что это невозможно сделать в принципе. Конечно, в final методе нет возможности перезаписать его в подклассе; но, что более важно, метод не обязательно должен быть всегда встроенным или никогда не встроенным. Компилятор мог видеть, что в этом конкретном контексте метод не был переопределен, и встроить его для этого вызова ... не так ли? Это не должно быть все или ничего.
  • 0
    Это не все или ничего, ваши выводы полностью технически обоснованы. Если метод явно не виртуальный (приватный, финальный или статический), он может быть встроен компилятором. Я говорю о деле Букл (ОП специально спрашивал о добытчиках и двоюродных братьях), хотя это было бы достаточно ясно из контекста. Таким образом, пока существует несколько возможностей для сферы применения Javac; большая часть все еще может быть сделана только JIT. Теперь, когда у нас уже есть JIT, который делает это, зачем дублировать эти усилия в javac?
1
  1. javac не использует встроенные методы, такие же простые, как getBlah() и setBlah()
  2. Что касается JVM HotSpot, JIT-компилятор делает встроенные все такие методы, если он не достигнет максимального уровня inline (-XX:MaxInlineLevel)
  3. JIT одинаково относится к public и private методам с точки зрения встраивания. Модификаторы доступа обычно не влияют на inlining, если не встречаются некоторые конкретные случаи.
0

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

Однако, в отличие от компилятора Java, он мог встроить только private методы и конструкторы. Все остальное является кандидатом на доступ из (непознаваемых) других классов.

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

  • 0
    Java-компилятор не может быть встроенным (getters) по определению; это будет необратимо сломаться в тот момент, когда метод будет перезаписан дочерним классом.
  • 0
    Я не понимаю, почему компилятор Java не должен выборочно включать заключительные публичные методы. Он не может пометить публичный метод как всегда встроенный, но он может встроить его в случае необходимости. И если он окончательный, то он не может быть отменен.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню