[Java] inline methods

Sanjaz

А может ли хороший Java-компилятор(например, Sun-овский) инлайнить статические методы?

Hastya

А может ли хороший Java-компилятор(например, Sun-овский) инлайнить статические методы?
эээ... а зачем?

enochka1145

1. А может ли хороший форумчанин пользоваться Google? Ну, например, набрать там java sun inline static method. Или просто: java inline methods.
2. А может ли хороший джавер объяснить, в чём разница между подстановкой тела статического и нестатического метода?

enochka1145

Геттеры-сеттеры могут легко инлайниться.

Sanjaz

Хороший форумчанин уже пользовался Google и дажен набирал там java inline methods
Представляешь !

Sanjaz

Например, в С++ виртуальные функцмии не инлайнятся(по-моему зато обычные могут инлайниться. Думаю, что также дела должны обстоять и в Java. Только не знаю, как проверить, инлайнился метод или нет?

Sanjaz

2. А может ли хороший джавер объяснить, в чём разница между подстановкой тела статического и нестатического метода?
Разница в том, что не статический метод может быть переопределен и у компилера могут быть трудности в выборе рализации для инлайна, а статический метод не переопределяется и таких трудностей не возникает.

enochka1145

Хороший форумчанин уже пользовался Google и дажен набирал там java inline methods
Представляешь !
СлАбо. Возьми частные уроки пользования Google. Уже на первой странице можно найти ссылку (даже две) на http://blogs.sun.com/ahe, а там написано (можно Ctrl+F на "inline"):
...On the other hand, many static optimizers will automatically inline method calls. The fundamental problem with inlining method calls is that if the inlined method was never called by method into which it was inlined it will just make the resulting method bigger (and perhaps prevent it from being inlined in other methods). So although a static optimizer think it is optimizing it has no data about how the program behaves at runtime and may make mistakes.
This is a fundamental problem that will make your programs run slower on HotSpot. The name HotSpot comes from the VM's ability to recognize hotspots in the program based on statistics collected while the program is running. By using this data, HotSpot can generally make better decisions than a static optimizer.
Besides hurting HotSpots ability to inline based on live data, big methods resulting from premature inlining can have other negative effects on performance. HotSpot will compile hot methods to native machine code. This code is sensitive to CPU level optimizations such as code caches and branch prediction. I don't know if this is a real life problem...
---
Т.е. ответ на твой исходный вопрос - может.

enochka1145

статический метод не переопределяется
Даже не знаю, что тебе ответить, то ли "наглая ложь" (KOHTPA style то ли "я бы за такое сразу банил" (чья-то подпись, мне очень нравится).

psm-home

Насколько я помню, в Java компилятор очень простой (тупой а оптимизации возложены на VM. Соответственно JVM может инлайнить методы, какие сочтет подходящими. Подозреваю, что точно узнать, как VM решает, инлайнить или нет, можно только изучив исходники VM. Можешь попробовать, благо они открыты. Вот ещё кусочек текста с трепом про то, как посмотреть, инлайнился метод, или нет.

Sanjaz

to . Хочешь сказать, что в Jave статические методы переопределяются?

Sanjaz

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

psm-home

я не вижу ни одного вызова своих методов. Даже main

Печально. А откуда такой интерес именно к подстановке статических методов? Если просто надо производительность конкретного приложения улучшить, возьми хороший профайлер, JProfiler, например.

enochka1145

"С самого утра веселье, респект"
to .
Это я просёк, почти сразу после того, как прочел в заголовке поста "[re:]".
Хочешь сказать, что в Jave статические методы переопределяются?
Видишь ли, у меня никак не доходят руки до "How to Become a Bydlo-coder in 24 Hours. Advanced Techniques and Strategies" ("Thinking in C++" дочитать бы когда-нибудь сначала... поэтому я всё ещё проверяю сомнительные утверждения самостоятельно. Особенно такие, на которые требуется 1-2 минуты.

Hastya

Печально. А откуда такой интерес именно к подстановке статических методов? Если просто надо производительность конкретного приложения улучшить, возьми хороший профайлер, JProfiler, например.
Меня тоже смущает такой интерес к inline. По ходу в человеке бунтует C-шное прошлое

Sanjaz

Просто стало интересно.

Dasar

> поэтому я всё ещё проверяю сомнительные утверждения самостоятельно. Особенно такие, на которые требуется 1-2 минуты.
afaik, static-метод перекрыть(override) нельзя, можно только скрыть (hide).
hide, в отличии от override, на оптимизацию никак не влияет, т.к. еще на этапе компиляции известно какой метод будет вызываться.
ps
поправил, ранее неправильно было указано overload вместо override

enochka1145

Ну сколько можно теоретизировать? Так трудно набрать
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

class Base {
static void method {
System.out.println("From Base");
}
}

class Derived extends Base {
static void method {
System.out.println("From Derived");
}
}

public class Test {
public static void main(String[] args) throws Exception {
List list = new ArrayList;
list.add(new Base;
list.add(new Derived;

for (Iterator iter = list.iterator; iter.hasNext;) {
Base item = (Base) iter.next;
Method method = item.getClass.getDeclaredMethod("method", new Class[0]);
method.invoke(null, new Object[0]);
}
}
}

Dasar

Method method = item.getClass.getDeclaredMethod("method", new Class[0]);
method.invoke(null, new Object[0]);
1. какое это имеет отношение к обсуждаемой теме? а именно к Jit-оптимизации и inline-у?
2. почему ты это называешь перекрытием (override-ингом)?
вообще-то, это всегда называлось связыванием по имени, и к возможностям языка никакого отношения не имеет.

enochka1145

по-моему ты себя дискредитируешь:
1. какое это имеет отношение к обсуждаемой теме? а именно к Jit-оптимизации и inline-у?
Женские приёмы ведения дискуссии в разделе Programming?
2. почему ты это называешь перекрытием (override-ингом)?
Я таких умных слов-то не знаю. Был задан вопрос:
Хочешь сказать, что в Jave статические методы переопределяются?
Я дал ответ, точнее пример, без всяких так AFAIK, "according to ОБС Consulting Ltd." и т.д.
вообще-то, это всегда называлось связыванием по имени, и к возможностям языка никакого отношения не имеет.
5 раз прочитал, ничего не понял. Даже попробовал подумать. Не получается. Что сия фраза значит?.. Какое отношение имеет к вопросу переопределения статических функций.

FRider

Хочешь сказать, что в Jave статические методы переопределяются?
Это не переопределение, имхо. Обычно, когда говорят по-русски "переопределение", имеется виду именно override, по крайней мере я всегда так это понимал и меня всегда так понимали. То что ты привел в примере - это замещение.

enochka1145

А чем это отличается от переопределения? (не считая слова static)

FRider

Язык - C#
class A
{
 public virtual void Method
 {
   Console.WriteLine("A");
 }
}
class B : A
{
 public override void Method
{
   Console.WriteLine("B");
}
}
A a = new B;
При переопределении(override) метода базового класса вызов a.Method напечатает B, если вместо override написать new - это замещение и вызов a.Method - напечатает A, хотя a - инстанс класса B. Это называется полиморфизм.
Соответственно, у статических методов может быть только замещение.

enochka1145

Мы вроде [Java] обсуждаем.
у статических методов может быть только замещение
Пример мой запускал?
На всякий случай, выдаёт он следующее:
From Base
From Derived

FRider

Нет, а без рефлекшена будет работать?

enochka1145

Как именно? Можно пример?

FRider

А вот и придумай как. А то, это, имхо хак
Хотя интересная особенность явы. Ща на шарпе попробую

enochka1145

Сам придумывай . Я уже привёл один пример конкретный пример. Теперь ваша очередь. Вам правда придётся потрудней, но ничего, так всегда обстоит дело с утверждениями типа "не существует способа/алгоритма/машины Тьюринга". Но это уже ваши трудности.

FRider

А ну так тут похоже в разнице понятий все-таки дело.
Там же ты берешь getClass Вот он и возвращает КОНКРЕТНЫЙ класс. У которого вызывается конкретный метод.
Переопределение(override) - имхо термин корректен в случае инстансов классов. Так что тут уже терминологичесий спор

bastii

И к чему ты этот код запостил? Если я правильно понял, то все правильно сказал. Типа Base.method и Derived.method два разных метода, и что должно вызываться определяется однозначно на этапе компиляции.
А override это из C#, где тому, что с методами у Джава по умолчанию, в C# соответствует вариант, который явно обозначается ключевым словом override. И наоборот, семантика с методами, что по умолчанию в C#, получается в Java, когда используется final. Таким образом, final позволяет инлайнить на этапе компиляции. Хотя тут JVM по идее генерирует код в рантайме, когда известны все подклассы данного класса, для которых создавались объекты, и JVM может проверить тот факт, что виртуальный вызов не нужен.
А так поддерживаю предыдущие высказывания о том, что не стоит на эту тему особенно напрягаться. Не так это принципиально, и оптимизировать можно потом, там где это необходимо. Главное, чтобы программа позволяла относительно легко корректировать реализацию отдельных фрагментов независимо от остального кода.
Имхо лучше основное внимание по производительности уделять размещению объектов/данных в памяти, чтобы сборщик мусора не нагружать сильно. За этим лучше следить сразу, так как переход от коллекций к массивам и переход от объектов к базовым типам нельзя назвать прозрачным, и это часто приводит серьезной правке кода.

Dasar

> А override это из C#
override - это термин любого OOP-языка.
в C# - override дополнительно зафиксирован как ключевое слово
google: java override method
google: c++ override method
google: smalltalk override method
можно еще какую-нибудь wikipedia-ю почитать
http://en.wikipedia.org/wiki/Method_overriding_%28programmin...

bastii

Согласен, только в отличии от Java в C# методы можно не только переопределять, но и перекрывать — этому нужно эти понятия явно отделять. В Java имхо можно вообще другими словами обходиться, например: задать для метода m другую реализацию, которая ...

bastii

Я не совсем понял, что хотел своим фрагментом кода показать. Там не запуская ясно, какой будет вывод, и о чем это свидетельствует.

Dasar

> Я таких умных слов-то не знаю.
ты этим гордишься?
> Я дал ответ, точнее пример, без всяких так AFAIK, "according to ОБС Consulting Ltd." и т.д.
ты дал хреновый пример, который что-то выдает, при чем ты даже не можешь себе объяснить как он работает, и почему это не перекрытие методов.
я правильно понимаю, что, по-твоему вот это тоже перекрытие метода:

using System;
using System.Collections.Generic;
using System.Text;

namespace Overriding
{
class A
{
}
class B
{
}
class MyBaseClass
{
public static void Method(A a)
{
Console.WriteLine("from A");
}
}
class MySuperClass
{
public static void Method(B a)
{
Console.WriteLine("from B");
}
}

class Program
{
static void Main(string[] args)
{
object[] items = new object[] { new A new B };
foreach (object item in items)
{
foreach (Type type in typeof(Program).Assembly.GetTypes
{
foreach (System.Reflection.MethodInfo method in type.GetMethods(
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public
{
System.Reflection.ParameterInfo[] parameters = method.GetParameters;
if (parameters.Length > 0 && parameters[0].ParameterType == item.GetType
method.Invoke(null, new object[] { item });
}
}
}
}
}
}


программа на выходе выдает

from A
from B

Svyatogor

Нет, компилятор Java не может (и не должен) инлайнить static-методы.

13.4.22 Method and Constructor Body
Changes to the body of a method or constructor do not break compatibility with pre-existing binaries.
We note that a compiler cannot expand a method inline at compile time.
The keyword final on a method does not mean that the method can be safely inlined; it means only that the method cannot be overridden. It is still possible that a new version of that method will be provided at link time. Furthermore, the structure of the original program must be preserved for purposes of reflection.
In general we suggest that implementations use late-bound (run-time) code generation and optimization.
Выделение мое.
И как правильно отметил , компиляторы Java обычно досаточно просты, большая часть оптимизации отдается на откуп машине Java. Кроме того, формат байт-кода позволяет выполнять inlining не только статических, но и "виртуальных" методов (Sun HotSpot JVM так вроде бы делает). Если в рантайме не имеется наследников класса, JVM может агрессивно inlinить вызовы виртуальных методов. Когда загружается наследник этого класса JVM может выполнять обратное преобразование (т.е. заменять inlineный вызов или вызов, скомпилированный в машинный код, обратно на байт-код и интерпретировать его).

danilov

Всё-таки ты не прав
 
public class MainExc {

private static class Base{
public static void method{
System.out.println("Base");
}
}

private static class Derived extends Base{
public static void method{
System.out.println("Derived");
}
}

public static void main(String[] args) throws Exception{
Base example = new Derived;
example.method;
Derived)example).method;
}
}

И резалт:
 
Base
Derived

Значит вызываемый метод дейсвительно раранее известен.
Плюс нельзя сделать static abstract.

danilov

From Base
From Derived
Именно потому что item.getClass разные. Это ничего не доказывает.

enochka1145

У меня было 2 цели:
1. Опровергнуть, что статические методы нельзя переопределить (если к ним вообще применимо такое понятие).
2. Поприкалываться (как всегда ).
Я выдал, можно сказать, задачу-шутку (про которую, как мне сказали, я не знаю, как она работает в которой, тем не менее, статические методы ведут себя точь-в-точь, как виртуальные.
В ответ получил... э-э... целый букет ответов. Что ж, лучше узнал некоторых форумчан.

enochka1145

А ещё некоторые думают, что в Java каждый не-private не-final метод - виртуальный.

danilov

1е у тебя не получилось - ты их всё-таки не переопределил.
2е .... хз, шутки не понял.
Если ты знал, что пишешь фигю, зачем вводить людей в заблуждение?

enochka1145

1. А что это значит - "переопределить статические методы"?
2. Показать немного интересную (ну, с моей быдлокодерской точки зрения) задачу. Этот пример я придумал, когда здесь шло обсуждение т.н. виртуальных статических методов.

Dasar

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

danilov

Я думал имелось ввиду следующее
как действует obj.method - узнаём класс obj и запускаем его метод для объекта obj
Ну, то есть может и как-то по-другому, но жто было бы логично с точки зрения хранения.
Тогда точно таким же методом можно было бы вызывать статические методы. Но увы, класс там
не определяется, а юзается объявленный

enochka1145

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

enochka1145

Ну, то есть может и как-то по-другому
Да не, всё правильно. JVM-инструкция invokestatic с указанием имени класса, метода (а также аргументов и возвращаемого значения).

bastii

А ещё некоторые думают, что в Java каждый не-private не-final метод - виртуальный
А что есть не виртуальные не статические методы в Java? Как private связан с виртуальностью тоже интересно.

Dasar

вообще, есть три связывания: static, virtual и по имени.
при static-е: сразу в точке вызова запоминается адрес метода
при виртуале: запоминается адрес из vtable-а
по имени: в точке вызова запоминается в виде строки название метода
соответственно первый метод самый быстрый, т.к. сразу делается переход.
второй в два раза медленнее - т.к. делается два "перехода".
по имени - где-то на несколько порядков медленнее, т.к. делается линейный, двоичный или хэш поиск нужного метода по строке.

enochka1145

А что есть не виртуальные не статические методы в Java? Как private связан с виртуальностью тоже интересно.
Конструкторы.
private-метод не может быть виртуальным, если я ничего не путаю.

enochka1145

Ну тогда в Java все связывания по имени, если я ничего не путаю. Достаточно продизассемблировать Java-код (.class-файл, javap с какими-то ключами но у меня на домашнем компе нет Java (!).

Dasar

> Ну тогда в Java все связывания по имени, если я ничего не путаю
так вот я и говорю, что ты ни фига не понимаешь, чем, например, invokestatic A/method отличается от a.GetType.GetDeclaringMethod("method").invoke.
нет там никаких имен, есть только ссылка на "дескриптор"
In bytecode, after the invokestatic opcode is a 16-bit unsigned integer index. This is the index of an entry in the constant pool. The entry is tagged as a CONSTANT_Methodref entry. This entry has two fields. One field points to a CONSTANT_Class entry in the constant pool whose name is the classname from <method-spec>, and the other points to a CONSTANT_NameAndType entry in the constant pool whose name is the methodname from <method-spec> and whose descriptor is the type descriptor from <method-spec>.
http://www.cat.nyu.edu/~meyer/jvmref/ref--34.html

enochka1145

Да, блин... Лучше мне с тобой перестать общаться, а то у меня мир (форума Programming) рушится. Я чё-то привык воспринимать тебя всерьёз.
нет там никаких имен, есть только ссылка на "дескриптор".
In bytecode, after the invokestatic opcode is a 16-bit unsigned integer index. This is the index of an entry in the constant pool. The entry is tagged as a CONSTANT_Methodref entry. This entry has two fields. One field points to a CONSTANT_Class entry in the constant pool whose name is the classname from <method-spec>, and the other points to a CONSTANT_NameAndType entry in the constant pool whose name is the methodname from <method-spec> and whose descriptor is the type descriptor from <method-spec>.
Я не понимаю, в чём принципиальная разница между именем и дескриптором имени. Ну не писать же всё время в байт-коде java.lang.String, java.lang.String, java.lang.String, java.lang.String, ... Проще использовать номерок в пуле констант.
И хватить давить меня примерами из C#. Ну не знаю я его.

enochka1145

И ещё ты так и не пояснил фразу
вообще-то, это всегда называлось связыванием по имени, и к возможностям языка никакого отношения не имеет.

Dasar

выполни кстати следующее упражнение
создай два package-а
один

class A
{
public void Method(double a)
{
Console.WriteLine("double a");
}
}

второй

class B
{
public static void Main
{
new A.Method(1);
}
}

собери их
далее поменяй первый package на:

class A
{
public void Method(int a)
{
Console.WriteLine("int a");
}
}

пересобери только его, и подсунь под старособранный второй package.
запусти, и запости в форум результат.

bastii

Конструкторы.
private-метод не может быть виртуальным, если я ничего не путаю.
Да ну тебя.

enochka1145

?

Dasar

> И ещё ты так и не пояснил фразу
это не фича языка, потому что про такой твой вызов язык ничего не знает, соответственно не прооптимизировать, ни проверить такой вызов - язык не может.

enochka1145

выполни кстати следующее упражнение
А зачем? Может, ты сам всё сделаешь, у тебя и код готов...
И опять на C#. Нету у меня C#. Нету. И я его не знаю.
На Java, наверно, будет Error насчёт отсутствия нужного метода в .class-файле.

Dasar

> И опять на C#. Нету у меня C#. Нету. И я его не знаю.
на Java-е код один в один такой же

bastii

Про private согласен, хотя сам никогда над этим не задумывался.

public class Test1 {
private void m {
System.out.println("Test1");
}

public static class Test2 extends Test1 {
private void m {
System.out.println("Test2");
}
}

public static void main(String[] args) {
Test1 test1 = new Test2;
test1.m;
}
}

Выводит Test1.
Конструктор не хочу считать методом.

bastii

И ещё ты так и не пояснил фразу
В ответ на:
вообще-то, это всегда называлось связыванием по имени, и к возможностям языка никакого отношения не имеет.
  
Для вызова метода с именем, которое берется из строки, в языке Java нет специальной поддержки. Все делается с помощью системных классов.

Dasar

> Я не понимаю, в чём принципиальная разница между именем и дескриптором имени
при связывании по имени - можно написать, например, вот так:
псевдокод

string className="A";
string method = "method";
invokestatic className+method;

дескриптор же жестко подразумевает, что название метода фиксированное (известное на этапе компиляции).

Dasar

> На Java, наверно, будет Error насчёт отсутствия нужного метода в .class-файле.
правильно, потому что компилятор разрезолвил вызов и сформировал в точке вызова дескриптор A/method (double а VM уже работает именно с этим дескриптором, и соответственно обижается, когда по этому дескриптору не получается найти метод.
еще интереснее сначала сделать метод

int Method{return 1;}

а потом заменить на

double Method{return 1;}

то можно увидеть, что дескриптор в том числе завязывается и на возвращаемое значение, хотя, например, тот же GetDeclaringMethod возвращаемым значением не интересуется.

Dasar

и вот какой-нибудь такой изврат
было

public class A
{
public class Inner
{
public static void Method
{
Console.WriteLine("A.Inner.Method");
}
}
}
public class B:A
{
}

стало

public class A
{
}
public class B:A
{
public class Inner
{
public static void Method
{
Console.WriteLine("B.Inner.Method");
}
}
}


вызов

class Program
{
static void Main(string[] args)
{
B.Inner.Method;
}
}
Оставить комментарий
Имя или ник:
Комментарий: