Модераторы: LSD, AntonSaburov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Работаем с байткодом 
:(
    Опции темы
 
Была ли данная информация вам интересна?
Да [ 72 ]  [84.71%]
Нет [ 4 ]  [4.71%]
По барабану [ 9 ]  [10.59%]
Всего проголосовавших: 85
В этом опросе возможен один вариант ответа
Гости не могут голосовать 
Domestic Cat
Дата 27.11.2004, 07:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



В связи с постоянным интересом к оптимизации Java программ решил начать на форуме разговор о байткоде.

Для начала введем некоторые термины которые понадобятся в дальнейшем.
opcode, опкод - одна инструкция языка JVM
bytecode, байткод - набор таких инструкций
стек - структура данных типа LIFO (last in, first out)

Чтобы понять как работает байткод, нужно четко представлять что делает JVM в процессе исполнения этого кода.

1. Фреймы
Каждый тред получает в свою собственность часть стека. Когда JVM вызывает к-л метод, на стеке создается новый фрейм. Он состоит из двух частей:
a. Массив локальных переменных. Этот массив содержит:
- элемент номер 0 массива есть ссылка this, если метод является инстанс методом
- параметры, передаваемые методу
б. Стек операндов Это LIFO стек, на который помешаются / вынимаются перенные в процессе выполнения программы.
Размеры обеих структур определяются во время компиляции.
Фрейм также содержит ссылку на runtime constant pool, принадлежащий классу данного объекта.

2. Байткод.
Почему байткод? Потому что один опкод весит 1 байт smile
Опкод может иметь префикс, который указывает, чем оперирует опкод:
а - ссылка на объект
i - int
b - byte
d - double
f - float
l - long
s - short
c - char

3. Пример.
Здесь мы одновременно разберемся с основами байткода и примером оптимизации синхронизированного метода.
Имеем следующий класс:

Код

public class Test
{
private int i;
private Object lock = new Object();

public int doTest()
{
               i++;
               return i;
}

public synchronized int doSynchronizedTest1()
{
               i++;
               return i;
}


public int doSynchronizedTest2()
{
               synchronized(lock)
               {
                i++;
                return i;
               }
}
}


Как видим, есть три различных метода, выполняющих одну и ту же работы, за одним исключением: первый метод не синхронизирован, в то время как синхронизированы остальные два, причем на разных объектах - doSynchronizedTest1 синхронизирован на this, doSynchronizedTest2 - на объекте lock.
Будут ли они различаться по скорости? какой из них наиболее оптимален? На эти вопросы можно ответить, посмотрев байткод данного класса.
Скомпилируем класс:
Код

cat> javac Test.java

Далее воспользуемся стандартным сановским дизассемблером:
Код

cat> javap -c Test > test.txt

Мы получим дизассемблированный код, записанный в файле test.txt.
Я приведу его полностью, а затем разберу по частям.
Код

Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
 Code:
  0: aload_0
  1: invokespecial #1; //Method java/lang/Object."<init>":()V
  4: aload_0
  5: new #2; //class Object
  8: dup
  9: invokespecial #1; //Method java/lang/Object."<init>":()V
  12: putfield #3; //Field lock:Ljava/lang/Object;
  15: return

public int doTest();
 Code:
  0: aload_0
  1: dup
  2: getfield #4; //Field i:I
  5: iconst_1
  6: iadd
  7: putfield #4; //Field i:I
  10: aload_0
  11: getfield #4; //Field i:I
  14: ireturn

public synchronized int doSynchronizedTest1();
 Code:
  0: aload_0
  1: dup
  2: getfield #4; //Field i:I
  5: iconst_1
  6: iadd
  7: putfield #4; //Field i:I
  10: aload_0
  11: getfield #4; //Field i:I
  14: ireturn

public int doSynchronizedTest2();
 Code:
  0: aload_0
  1: getfield #3; //Field lock:Ljava/lang/Object;
  4: dup
  5: astore_1
  6: monitorenter
  7: aload_0
  8: dup
  9: getfield #4; //Field i:I
  12: iconst_1
  13: iadd
  14: putfield #4; //Field i:I
  17: aload_0
  18: getfield #4; //Field i:I
  21: aload_1
  22: monitorexit
  23: ireturn
  24: astore_2
  25: aload_1
  26: monitorexit
  27: aload_2
  28: athrow
 Exception table:
  from   to  target type
    7    23    24   any
   24    27    24   any

}


3.1 Общие замечания
Ясно, что первая строка - название файла, содержащего класс; вторая строка описывает наследование.
Каждый метод содержится в байткод массиве, имеющем тип byte[]. (Каждой команде соответствует код типа byte). Индексы слева соответствуют элементам этого массива, (вспомним, что опкод занимает 1 байт).
Поскольку опкод может также иметь аргументы, нумерация идет с разрывами: например код
Код

putfield #4;

запишется так:
Код

{..., 181, 0, 4, ...}

Если 181 (putfield) - седьмой элемент массива, то вместе с аргументом он займет 3 байта.
Далее идет код конструкторов, а затем всех методов в алфавитном порядке.
3.2 Конструктор
Если вы помните, наш код не содержит конструктора вообще - а байткод конструктора есть!
Код

0: aload_0

Опкод грузит ссылку this (а) из нулевого элемента массива локальных переменных (поскольку это инстанс метод, она там есть) на стек
Код

1: invokespecial #1; //Method java/lang/Object."<init>":()V

Вызываем конструктор суперкласса (то есть Object()), #1 соответствует номеру этого конструктора в constant pool. Для верности дизассемблер добавил коммент с указанием, что это за метод smile Вызываем мы его естественно, на this, который сидел в стеке. При вызове эта ссылка была вынута из стека, и строка 4: aload_0 опять ложит ее на стек.
Далее идет инициализация инстанс переменной lock - оказывается, это делается в конструкторе. Она создается с помощью
Код

5: new #2; //class Object

создаетйся ее дубликат на стеке:
Код

8: dup

опять вызывается конструктор суперкласса, и готовый Объект ложится в поле класса Test:
Код

12: putfield #3; //Field lock:Ljava/lang/Object;

и выполняется return.

// Продолжение через полчаса smile

Это сообщение отредактировал(а) Domestic Cat - 27.11.2004, 09:41


--------------------

PM   Вверх
Domestic Cat
Дата 27.11.2004, 08:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



3.3 Метод doTest

Код

0: aload_0
1: dup

Грузим this на стек и делаем его дубликат.
Код

2: getfield #4; //Field i:I

Берем этот дубликат и вызываем на нем опкод getfield - т.е. ложим на стек поле i.
Код

5: iconst_1
6: iadd

Объявляем целую константу 1 (i) и прибавляем ее к полю i.
Код

7: putfield #4; //Field i:I

Ложим результат в i.
Код

10: aload_0
11: getfield #4; //Field i:I
14: ireturn

Грузим на стек this, берем его поле номер 4 и возвращаем его.

3.4 Метод doSynchronizedTest1
А теперь посмотрм на метод doSynchronizedTest1. Удивительно, но он совпадает с предыдущим (несинхронизированным) методом один в один!
Загадка разрешается просто : при синхронизации метода байткод остается прежним, но зато меняется флаг ACC_SYNCHRONIZED структуры method_info этого метода.

3.5 Метод doSynchronizedTest2
Здесь будет немного посложнее чем в предыдущем случае.
Мы берем this, и получаем ссылку на объект lock:
Код

0: aload_0
1: getfield #3; //Field lock:Ljava/lang/Object;

Далее, делается дубликат объекта, и ссылка на него (аstore) помещается в локальный массив как элемент номер 1
Код

4: dup
5: astore_1

Теперь метод входит в синхронизированную область (monitorenter) , в которой может находиться только 1 тред. Далее идет код, аналогичный предыдущим двум методам. Лок освобождается и результат возвращается в строках:
Код

22: monitorexit
23: ireturn

Заметьте, что метод требует лок сразу перед monitorenter, и вынимает его из локального массива сразу перед monitorexit.
А что же идет дальше? А дальше идет код на случай, если будет брошен иксепшн в синхронизированном блоке. Это легко видеть, если начать читать с конца:
Код

Exception table:
  from   to  target type
    7    23    24   any
   24    27    24   any

означает следующее:
Смотрим с опкода номер 7 по номер 23, если будет брошен любой (any) иксепшн, перейти на код номер 24. Если иксепшн будет брошен между 24 (включительно) и 27 (не включая) опкодами - перейти назад, на номер 24.
Код после 23 опкода простой: берем this и ложим его в локальный массив на индех 2; берем лок из локального массива (индекс 1) и пытаемся освободить лок (monitorexit). Берем this и бросаем иксепшн со ссылкой на него.
Грубо говоря, в случае иксепшна внутри синхронизованного блока программа до потери пульса будет пытаться высвободить лок объекта и выйти из блока.

Какая мораль следует из всего этого? Простая: синхронизировать метод оптимальнее, чем кусок этого метода! Потеря идет как в скорости (за счет манипуляций с локом), так и в размере кода.

Естественно, это не значит., что теперь только так и нужно писать. На самом деле, в многопоточной программе синхронизация блока может быть на много порядков выгоднее, чем синхронизация всего метода. А вот для данного случая, как оказалось, выигрыш дает синхронизированный метод. Просто в случаях, когда скорость суперважна, пользуйтесь дизассемблером. smile

ПС. Узнать все о байткоде можно здесь:

http://java.sun.com/docs/books/vmspec/2nd-...pecTOC.doc.html

Это сообщение отредактировал(а) Domestic Cat - 27.11.2004, 20:35


--------------------

PM   Вверх
Domestic Cat
Дата 28.11.2004, 01:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Я решил добавить еще 1 пример с разбором байткода. Исходный текст такой:
Код

public class Test
{
  public static void main(String [] args)
  {
    long ll=45000;
    long ts = System.currentTimeMillis();
    for(int i=0;i<1000000;i++)
       {
          ll=45000;
          for (; ll > 1; )
           {
                 ll -= 5000;
           }
       }
       long te = System.currentTimeMillis();
       System.out.println("Division by subtraction " + (te-ts) + " milliseconds");
   }
}


Комментарии к байткоду я дам в самом коде в виде комментов. Я также привожу содержимое стека и массива локальных переменных, обозначая их s: и mlp: соответственно. Внутри циклов содержимое фрейма показано для одного прохода для каждого цикла. Самый нижний элемент стека и элемент массива с индексом 0 находятся слева. Я не привожу текста конструктора, т.к. он тривиален. ms1, ms2 - значения таймера в соответствующие моменты времени. Массив локальных переменных хранит long и double в 2х ячейках, такие места в млп я обозначаю "-".
Код

public static void main(java.lang.String[]);
 Code:
  0: ldc2_w #2; //long 45000l
/* s: 45000 */
  3: lstore_1
/* mlp: 0, 45000, -*/
  4: invokestatic #4; //Method java/lang/System.currentTimeMillis:()J
/* s: ms1; mlp: 0, 45000, - */
  7: lstore_3
/* mlp: 0, 45000, -, ms1, - */
  8: iconst_0
/* s: 0; mlp: 0, 45000, -, ms1, - */
  9: istore 5
/* mlp: 0, 45000, -, ms1, -, 0 */
  11: iload 5
/* s: 0; mlp: 0, 45000, -, ms1, -, 0 */
  13: ldc #5; //int 1000000
/* s: 0, 1000000; mlp: 0, 45000, -, ms1, -, 0 */
  15: if_icmpge 43
/* mlp: 0, 45000, -, ms1, -, 0
            Если 0 > 1000000, прыгнуть к 43: */
  18: ldc2_w #2; //long 45000l
/* s: 45000; mlp: 0, 45000, -, ms1, -, 0 */
  21: lstore_1
/* mlp: 0, 45000, -, ms1, -, 0 */
  22: lload_1
/* s: 45000; mlp: 0, 45000, -, ms1, -, 0 */
  23: lconst_1
/* s: 45000, 1; mlp: 0, 45000, -, ms1, -, 0 */
  24: lcmp
  25: ifle 37
/* mlp: 0, 45000, -, ms1, -, 0
        Если 45000 <= 1 прыгнуть к 37: */
  28: lload_1
/* s: 45000; mlp: 0, 45000, -, ms1, -, 0 */
  29: ldc2_w #6; //long 5000l
/* s: 45000, 5000; mlp: 0, 45000, -, ms1, -, 0 */
  32: lsub
/* s: 40000; mlp: 0, 45000, -, ms1, -, 0 */
  33: lstore_1
/* mlp: 0, 40000, -, ms1, -, 0 */
  34: goto 22
       /* Внутренний цикл завершен*/
  37: iinc 5, 1
/* mlp: 0, 0, -, ms1, -, 1
           - инкремент переменной на 5-м индксе в млп*/
  40: goto 11
        /*Внешний цикл завершен*/
  43: invokestatic #4; //Method java/lang/System.currentTimeMillis:()J
/* s: ms2; mlp: 0, 0, -, ms1, -, 1 */
  46: lstore 5
/* mlp: 0, 0, -, ms1, -, ms2, - */
  48: getstatic #8; //Field java/lang/System.out:Ljava/io/PrintStream;
/* s: PrintStream; mlp: 0, 0, -, ms1, -, ms2, - */
  51: new #9; //class StringBuffer
/* s: PrintStream, StringBuffer; mlp: 0, 0, -, ms1, -, ms2, - */
  54: dup
/* s: PrintStream, StringBuffer, StringBuffer; mlp: 0, 0, -, ms1, -, ms2, - */
  55: invokespecial #10; //Method java/lang/StringBuffer."<init>":()V
/* s: PrintStream, StringBuffer; mlp: 0, 0, -, ms1, -, ms2, - */
  58: ldc #11; //String Division by subtraction
/* s: PrintStream, StringBuffer, "Division by subtraction"; mlp: 0, 0, -, ms1, -, ms2, - */
  60: invokevirtual #12; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
/* s: PrintStream, StringBuffer; mlp: 0, 0, -, ms1, -, ms2, - */
  63: lload 5
/* s: PrintStream, StringBuffer, ms2; mlp: 0, 0, -, ms1, -, ms2, - */
  65: lload_3
/* s: PrintStream, StringBuffer, ms2, ms1; mlp: 0, 0, -, ms1, -, ms2, - */
  66: lsub
/* s: PrintStream, StringBuffer, ms2-ms1; mlp: 0, 0, -, ms1, -, ms2, - */
  67: invokevirtual #13; //Method java/lang/StringBuffer.append:(J)Ljava/lang/StringBuffer;
/* s: PrintStream, StringBuffer; mlp: 0, 0, -, ms1, -, ms2, - */
  70: ldc #14; //String  milliseconds
/* s: PrintStream, StringBuffer, " milliseconds"; mlp: 0, 0, -, ms1, -, ms2, - */
  72: invokevirtual #12; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
/* s: PrintStream, StringBuffer; mlp: 0, 0, -, ms1, -, ms2, - */
  75: invokevirtual #15; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;
/* s: PrintStream, "Division by subtraction xxxx milliseconds"; mlp: 0, 0, -, ms1, -, ms2, - */
  78: invokevirtual #16; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
/* mlp: 0, 0, -, ms1, -, ms2, - */
  81: return

}




// попозже допишу о constant pool и LineNumberTable

Это сообщение отредактировал(а) Domestic Cat - 28.11.2004, 02:20


--------------------

PM   Вверх
Domestic Cat
Дата 28.11.2004, 03:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Constant Pool

Пул констант JVM содержит информацию о всех полях, методах, интерфейсах и классах, используемых методами данного класса. Опкод может ссылаться на данную информацию через диез и номер строки: ldc #5.

Если использовать флаг -verbose, дизассемблер выводит информацию о пуле. Так, для примера выше получим:
Код

Compiled from "Test.java"
public class Test extends java.lang.Object
 SourceFile: "Test.java"
 minor version: 0
 major version: 0
 Constant pool:
const #1 = Method #18.#27; //  java/lang/Object."<init>":()V
const #2 = long 45000l;
const #4 = Method #28.#29; //  java/lang/System.currentTimeMillis:()J
const #5 = int 1000000;
const #6 = long 5000l;
const #8 = Field #28.#30; //  java/lang/System.out:Ljava/io/PrintStream;
const #9 = class #31; //  StringBuffer
const #10 = Method #9.#27; //  java/lang/StringBuffer."<init>":()V
const #11 = String #32; //  Division by subtraction
const #12 = Method #9.#33; //  java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
const #13 = Method #9.#34; //  java/lang/StringBuffer.append:(J)Ljava/lang/StringBuffer;
const #14 = String #35; //   milliseconds
const #15 = Method #9.#36; //  java/lang/StringBuffer.toString:()Ljava/lang/String;
const #16 = Method #37.#38; //  java/io/PrintStream.println:(Ljava/lang/String;)V
const #17 = class #39; //  Test1
const #18 = class #40; //  Object
const #19 = Asciz <init>;
const #20 = Asciz ()V;
const #21 = Asciz Code;
const #22 = Asciz LineNumberTable;
const #23 = Asciz main;
const #24 = Asciz ([Ljava/lang/String;)V;
const #25 = Asciz SourceFile;
const #26 = Asciz Test1.java;
const #27 = NameAndType #19:#20;//  "<init>":()V
const #28 = class #41; //  System
const #29 = NameAndType #42:#43;//  currentTimeMillis:()J
const #30 = NameAndType #44:#45;//  out:Ljava/io/PrintStream;
const #31 = Asciz java/lang/StringBuffer;
const #32 = Asciz Division by subtraction;
const #33 = NameAndType #46:#47;//  append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
const #34 = NameAndType #46:#48;//  append:(J)Ljava/lang/StringBuffer;
const #35 = Asciz  milliseconds;
const #36 = NameAndType #49:#50;//  toString:()Ljava/lang/String;
const #37 = class #51; //  PrintStream
const #38 = NameAndType #52:#53;//  println:(Ljava/lang/String;)V
const #39 = Asciz Test1;
const #40 = Asciz java/lang/Object;
const #41 = Asciz java/lang/System;
const #42 = Asciz currentTimeMillis;
const #43 = Asciz ()J;
const #44 = Asciz out;
const #45 = Asciz Ljava/io/PrintStream;;
const #46 = Asciz append;
const #47 = Asciz (Ljava/lang/String;)Ljava/lang/StringBuffer;;
const #48 = Asciz (J)Ljava/lang/StringBuffer;;
const #49 = Asciz toString;
const #50 = Asciz ()Ljava/lang/String;;
const #51 = Asciz java/io/PrintStream;
const #52 = Asciz println;
const #53 = Asciz (Ljava/lang/String;)V;

{
public Test();
 Code:
  Stack=1, Locals=1, Args_size=1
  0: aload_0
  1: invokespecial #1; //Method java/lang/Object."<init>":()V
  4: return
 LineNumberTable:
  line 1: 0

public static void main(java.lang.String[]);
 Code:
  Stack=6, Locals=7, Args_size=1
  0: ldc2_w #2; //long 45000l
  3: lstore_1
  4: invokestatic #4; //Method java/lang/System.currentTimeMillis:()J
  7: lstore_3
  8: iconst_0
  9: istore 5
  11: iload 5
  13: ldc #5; //int 1000000
  15: if_icmpge 43
  18: ldc2_w #2; //long 45000l
  21: lstore_1
  22: lload_1
  23: lconst_1
  24: lcmp
  25: ifle 37
  28: lload_1
  29: ldc2_w #6; //long 5000l
  32: lsub
  33: lstore_1
  34: goto 22
  37: iinc 5, 1
  40: goto 11
  43: invokestatic #4; //Method java/lang/System.currentTimeMillis:()J
  46: lstore 5
  48: getstatic #8; //Field java/lang/System.out:Ljava/io/PrintStream;
  51: new #9; //class StringBuffer
  54: dup
  55: invokespecial #10; //Method java/lang/StringBuffer."<init>":()V
  58: ldc #11; //String Division by subtraction
  60: invokevirtual #12; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
  63: lload 5
  65: lload_3
  66: lsub
  67: invokevirtual #13; //Method java/lang/StringBuffer.append:(J)Ljava/lang/StringBuffer;
  70: ldc #14; //String  milliseconds
  72: invokevirtual #12; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
  75: invokevirtual #15; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;
  78: invokevirtual #16; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
  81: invokestatic #4; //Method java/lang/System.currentTimeMillis:()J
  84: lstore_3
  85: return
 LineNumberTable:
  line 5: 0
  line 6: 4
  line 7: 8
  line 9: 18
  line 10: 22
  line 12: 28
  line 7: 37
  line 15: 43
  line 16: 48
  line 17: 81
  line 18: 85

}



Возьмем для примера ссылку #1:

Код

const #1 = Method #18.#27;

Понятно, что это метод,. причем он сам ссылается на пул: #18. Первая ссылка определяет к какому классу принадлежит этот метод, причем клас тоже дает ссылку на пул, но на сей раз на строку в аэски формате :
Код

const #18 = class #40;
...
const #40 = Asciz java/lang/Object;

Далее идет .#27, что переводится как:
Код

const #27 = NameAndType #19:#20;
....
const #19 = Asciz <init>;
const #20 = Asciz ()V;

NameAndTypе определяет аргументы и тип метода: мы видим, что это конструктор, не принимающий аргументов. То же самое нам и сказал дизассемблер в комменте к #1:
Код

const #1 = Method #18.#27; //  java/lang/Object."<init>":()V

Все определения классов в констант пуле должны быть такими же, как возвращает метод getClass().

2. LineNumberTable
Эта таблица находится в конце метода, и определяет соответствие между строками java-файла и индексами байткода.
Так, мы видим, что строка 9 файла Test.java :
Код

ll=45000;

имеет индекс 18 в байткоде:
Код

18: ldc2_w #2; //long 45000l



--------------------

PM   Вверх
Sardar
Дата 28.11.2004, 12:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 4
Всего: 317



Похоже что простейший обфускатор/оптимизатор удаляет LineNumberTable в методах и изменяет имена в константном пуле. Обфускаторы посложнее перебирают код методов.

Интересно что обьекты понимаются на уровне vm как структуры(по крайней мере я так понял), т.е. можно сделать компилятор C и других структурно/ООП языков в байткод Ява.

Извиняюсь что влез посреди статьи. Если глаза мозолит, удалите пост smile


--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
Sleepy_PIP
Дата 28.11.2004, 17:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 512
Регистрация: 30.6.2004
Где: Moscow

Репутация: 4
Всего: 12



Цитата(Domestic @ 28.11.2004, 01:37)
Я решил добавить еще 1 пример с разбором байткода. Исходный текст такой:
Код

public class Test
{
  public static void main(String [] args)
  {
    long ll=45000;
    long ts = System.currentTimeMillis();
    for(int i=0;i<1000000;i++)
       {
          ll=45000;
          for (; ll > 1; )
           {
                 ll -= 5000;
           }
       }
       long te = System.currentTimeMillis();
       System.out.println("Division by subtraction " + (te-ts) + " milliseconds");
   }
}


Комментарии к байткоду я дам в самом коде в виде комментов. Я также привожу содержимое стека и массива локальных переменных, обозначая их s: и mlp: соответственно. Внутри циклов содержимое фрейма показано для одного прохода для каждого цикла. Самый нижний элемент стека и элемент массива с индексом 0 находятся слева. Я не привожу текста конструктора, т.к. он тривиален. ms1, ms2 - значения таймера в соответствующие моменты времени. Массив локальных переменных хранит long и double в 2х ячейках, такие места в млп я обозначаю "-".
Код

public static void main(java.lang.String[]);
 Code:
  0: ldc2_w #2; //long 45000l
/* s: 45000 */
  3: lstore_1
/* mlp: 0, 45000, -*/
  4: invokestatic #4; //Method java/lang/System.currentTimeMillis:()J
/* s: ms1; mlp: 0, 45000, - */
  7: lstore_3
/* mlp: 0, 45000, -, ms1, - */
  8: iconst_0
/* s: 0; mlp: 0, 45000, -, ms1, - */
  9: istore 5
/* mlp: 0, 45000, -, ms1, -, 0 */
  11: iload 5
/* s: 0; mlp: 0, 45000, -, ms1, -, 0 */
  13: ldc #5; //int 1000000
/* s: 0, 1000000; mlp: 0, 45000, -, ms1, -, 0 */
  15: if_icmpge 43
/* mlp: 0, 45000, -, ms1, -, 0
            Если 0 > 1000000, прыгнуть к 43: */
  18: ldc2_w #2; //long 45000l
/* s: 45000; mlp: 0, 45000, -, ms1, -, 0 */
  21: lstore_1
/* mlp: 0, 45000, -, ms1, -, 0 */
  22: lload_1
/* s: 45000; mlp: 0, 45000, -, ms1, -, 0 */
  23: lconst_1
/* s: 45000, 1; mlp: 0, 45000, -, ms1, -, 0 */
  24: lcmp
  25: ifle 37
/* mlp: 0, 45000, -, ms1, -, 0
        Если 45000 <= 1 прыгнуть к 37: */
  28: lload_1
/* s: 45000; mlp: 0, 45000, -, ms1, -, 0 */
  29: ldc2_w #6; //long 5000l
/* s: 45000, 5000; mlp: 0, 45000, -, ms1, -, 0 */
  32: lsub
/* s: 40000; mlp: 0, 45000, -, ms1, -, 0 */
  33: lstore_1
/* mlp: 0, 40000, -, ms1, -, 0 */
  34: goto 22
       /* Внутренний цикл завершен*/
  37: iinc 5, 1
/* mlp: 0, 0, -, ms1, -, 1
           - инкремент переменной на 5-м индксе в млп*/
  40: goto 11
        /*Внешний цикл завершен*/
  43: invokestatic #4; //Method java/lang/System.currentTimeMillis:()J
/* s: ms2; mlp: 0, 0, -, ms1, -, 1 */
  46: lstore 5
/* mlp: 0, 0, -, ms1, -, ms2, - */
  48: getstatic #8; //Field java/lang/System.out:Ljava/io/PrintStream;
/* s: PrintStream; mlp: 0, 0, -, ms1, -, ms2, - */
  51: new #9; //class StringBuffer
/* s: PrintStream, StringBuffer; mlp: 0, 0, -, ms1, -, ms2, - */
  54: dup
/* s: PrintStream, StringBuffer, StringBuffer; mlp: 0, 0, -, ms1, -, ms2, - */
  55: invokespecial #10; //Method java/lang/StringBuffer."<init>":()V
/* s: PrintStream, StringBuffer; mlp: 0, 0, -, ms1, -, ms2, - */
  58: ldc #11; //String Division by subtraction
/* s: PrintStream, StringBuffer, "Division by subtraction"; mlp: 0, 0, -, ms1, -, ms2, - */
  60: invokevirtual #12; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
/* s: PrintStream, StringBuffer; mlp: 0, 0, -, ms1, -, ms2, - */
  63: lload 5
/* s: PrintStream, StringBuffer, ms2; mlp: 0, 0, -, ms1, -, ms2, - */
  65: lload_3
/* s: PrintStream, StringBuffer, ms2, ms1; mlp: 0, 0, -, ms1, -, ms2, - */
  66: lsub
/* s: PrintStream, StringBuffer, ms2-ms1; mlp: 0, 0, -, ms1, -, ms2, - */
  67: invokevirtual #13; //Method java/lang/StringBuffer.append:(J)Ljava/lang/StringBuffer;
/* s: PrintStream, StringBuffer; mlp: 0, 0, -, ms1, -, ms2, - */
  70: ldc #14; //String  milliseconds
/* s: PrintStream, StringBuffer, " milliseconds"; mlp: 0, 0, -, ms1, -, ms2, - */
  72: invokevirtual #12; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
/* s: PrintStream, StringBuffer; mlp: 0, 0, -, ms1, -, ms2, - */
  75: invokevirtual #15; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;
/* s: PrintStream, "Division by subtraction xxxx milliseconds"; mlp: 0, 0, -, ms1, -, ms2, - */
  78: invokevirtual #16; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
/* mlp: 0, 0, -, ms1, -, ms2, - */
  81: return

}




// попозже допишу о constant pool и LineNumberTable

эээ ... торможу. - а где собственно выситание?
Спасибо!



--------------------
--
Sleepy_PIP. Pavel Pryazhentsev (ex. 2:5020/141) "... Лучше быть нужным, чем
свободным ..."
PM MAIL ICQ   Вверх
Domestic Cat
Дата 28.11.2004, 17:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Цитата(Sardar @ 28.11.2004, 03:43)
Интересно что обьекты понимаются на уровне vm как структуры(по крайней мере я так понял), т.е. можно сделать компилятор C и других структурно/ООП языков в байткод Ява.


Думаю, что можно. Хотя объекты понимаются именно как объекты smile - ведь объект - это структура + наследование + инкапсуляция. Каждый class-файл начинается с описания классов, полей и методов:
Код

ClassFile {
    u4 magic; // CA FE BA BE  :)
    u2 minor_version;
    u2 major_version;
    u2 constant_pool_count;  // количество записей в пуле
    cp_info constant_pool[constant_pool_count-1];
    u2 access_flags;
    u2 this_class;
    u2 super_class;
    u2 interfaces_count;
    u2 interfaces[interfaces_count];
    u2 fields_count;
    field_info fields[fields_count];
    u2 methods_count;
    method_info methods[methods_count];
    u2 attributes_count;
    attribute_info attributes[attributes_count];
   }

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

Вечерком допишу еще че-нибудь smile.

Добавлено @ 17:36
Цитата(Sleepy_PIP @ 28.11.2004, 08:29)
эээ ... торможу. - а где собственно выситание?
Спасибо!


Вот тут:

Код

  28:  lload_1
             /* Ложим 45000 на стек */
  29:  ldc2_w  #6; //long 5000l
             /* Теперь стек такой : 45000, 5000 */
  32:  lsub
             /* на стеке 40000 */
  33:  lstore_1
             /* ложим назад, в массив, под индексом 1*/




--------------------

PM   Вверх
Sleepy_PIP
Дата 28.11.2004, 17:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 512
Регистрация: 30.6.2004
Где: Moscow

Репутация: 4
Всего: 12



а еще-б разобрать примерчик с дерением а ? ... интересно все-ж во что преобразуется оператор деления ...
СПАСИБО!



--------------------
--
Sleepy_PIP. Pavel Pryazhentsev (ex. 2:5020/141) "... Лучше быть нужным, чем
свободным ..."
PM MAIL ICQ   Вверх
Domestic Cat
Дата 28.11.2004, 18:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Цитата(Sleepy_PIP @ 28.11.2004, 08:45)
а еще-б разобрать примерчик с дерением а ? ... интересно все-ж во что преобразуется оператор деления ...
СПАСИБО!


Нет проблем:

Код

public class Test
{
public static void main(String [] args)
{
              long a = 20000;
              long b = 1000;
              double x = a / b;
}
}


Код

Compiled from "Test.java"
public class Test extends java.lang.Object
 SourceFile: "Test.java"
 minor version: 0
 major version: 0
 Constant pool:
const #1 = Method #7.#16; //  java/lang/Object."<init>":()V
const #2 = long 20000l;
const #4 = long 1000l;
const #6 = class #17; //  Test
const #7 = class #18; //  Object
const #8 = Asciz <init>;
const #9 = Asciz ()V;
const #10 = Asciz Code;
const #11 = Asciz LineNumberTable;
const #12 = Asciz main;
const #13 = Asciz ([Ljava/lang/String;)V;
const #14 = Asciz SourceFile;
const #15 = Asciz Test.java;
const #16 = NameAndType #8:#9;//  "<init>":()V
const #17 = Asciz Test;
const #18 = Asciz java/lang/Object;

{
public Test();
 Code:
  Stack=1, Locals=1, Args_size=1
  0: aload_0
  1: invokespecial #1; //Method java/lang/Object."<init>":()V
  4: return
 LineNumberTable:
  line 2: 0

public static void main(java.lang.String[]);
 Code:
  Stack=4, Locals=7, Args_size=1
  0: ldc2_w #2; //long 20000l       // Ложим на стек 20000
  3: lstore_1                                   // Ложим ее в локальный массив
  4: ldc2_w #4; //long 1000l         // Ложим на стек 1000
  7: lstore_3                                   // Ложим ее в локальный массив
  8: lload_1                                    // Ложим на стек 20000
  9: lload_3                                    // Ложим на стек 1000
  10: ldiv                                         // Делим
  11: l2d                                         // Поскольку результат деления long,
                                                       // конвертируем в double
  12: dstore 5                               // Ложим результат в локальный массив
  14: return
 LineNumberTable:
  line 6: 0
  line 7: 4
  line 8: 8
  line 9: 14




Это сообщение отредактировал(а) Domestic Cat - 28.11.2004, 18:37


--------------------

PM   Вверх
Sardar
Дата 28.11.2004, 20:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 4
Всего: 317



Не понял смысла команды l2d, ведьмы уже поделили, на стеке должно лежать double.
И что то слишком много движений, из констант в стек, затем в локальный массив, затем опятьв стек и только потом делим.
В локальный массив по моему не нужно ложить значения, я понимаю что это переменные a и b, но оптимизатор должен был отбросить их!


--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
Domestic Cat
Дата 29.11.2004, 01:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Цитата(Sardar @ 28.11.2004, 11:42)
Не понял смысла команды l2d, ведьмы уже поделили, на стеке должно лежать double.


Результатом деления 2х лонгов является лонг, а мы хотим получить дабл. Для этого и нужно сконвертировать.
Цитата(Sardar @ 28.11.2004, 11:42)
В локальный массив по моему не нужно ложить значения, я понимаю что это переменные a и b, но оптимизатор должен был отбросить их!


РАз ты объявил локальные переменные, JVM всегда будет совершать подобные телодвижения, она ведь смысла не понимает. Может, через 20 строк ты захочешь их вывести на консоль - а их нету !
Кстати, перемещения константы-> стек->массив->стек вполне нормальная вещь, если помнить, что со стеком можно сделать только 2 вещи: положить в него, и взять оттуда. Любая операция, не ложащая че-нибудь на стек, забирает оттуда переменную.


--------------------

PM   Вверх
Sardar
Дата 29.11.2004, 01:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 4
Всего: 317



Цитата(Domestic @ 29.11.2004, 00:30)
Результатом деления 2х лонгов является лонг, а мы хотим получить дабл. Для этого и нужно сконвертировать.

Как можно получить результат деления в long, и при этом не потерять дробную часть? Ведь оператор деления возвратит double, от которого можно взять целое, но не наоборот!

Цитата(Domestic @ 29.11.2004, 00:30)
РАз ты объявил локальные переменные, JVM всегда будет совершать подобные телодвижения, она ведь смысла не понимает. Может, через 20 строк ты захочешь их вывести на консоль - а их нету !

Эти переменные локальные, т.е. я точно знаю время их жизни, вообще под локальный код можо точно посчитать занимаемое пространство в памяти, длину стека, минимально количество переменных, необходимых для работы.
Оптимизировать убирая "пустые" переменные - есть работа компилятора без указания всяких флагов. Просто привык что в микроконтроллере каждый байт памяти дорог(пишу на асме и C), теперь читаю байткод явы и вижу такую ересь...

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


--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
Domestic Cat
Дата 29.11.2004, 02:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Цитата(Sardar @ 28.11.2004, 16:46)
Как можно получить результат деления в long, и при этом не потерять дробную часть? Ведь оператор деления возвратит double, от которого можно взять целое, но не наоборот!


Оператор деления лонгов возвращает лонг, как и оператор деления интов возвращает инт smile


Цитата(Sardar @ 28.11.2004, 16:46)
Эти переменные локальные, т.е. я точно знаю время их жизни, вообще под локальный код можо точно посчитать занимаемое пространство в памяти, длину стека, минимально количество переменных, необходимых для работы.
Оптимизировать убирая "пустые" переменные - есть работа компилятора без указания всяких флагов. Просто привык что в микроконтроллере каждый байт памяти дорог(пишу на асме и C), теперь читаю байткод явы и вижу такую ересь...


Память-то здесь тратится только стековая, и то на малый промежуток времени. Но все равно : ведь а и b используются при вычислении x. Такие вещи - проблема программиста, задача компилятора - скомпилировать, а оптимизацией займется JIT (just in time compiler). Нужен супероптимальный код - посмотри байткод и исправь smile Хотя выигрыш тут будет никакой.

Это сообщение отредактировал(а) Domestic Cat - 29.11.2004, 07:50


--------------------

PM   Вверх
Domestic Cat
Дата 29.11.2004, 04:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Теперь немного о том, на чем я остановился прошлый раз: Constant Pool.

Грамматика дескрипторов

Все методы в констант пуле описываются загадочными строками типа:
Код

java/io/PrintStream.println:(Ljava/lang/String;)V

Эта строка называется дескриптором и однозначно описывает сигнатуру метода. Большая буква означает следующее:
Код

B  byte
C  char
D  double
F  float
I  int
J  long
L<classname>;  ссылка на класс <classname>
S  short  
Z  boolean
[  массив (одна размерность)
V   void


Примеры
1. Массив
Код

long[][][][][] array;

будет иметь дескриптор
Код

[[[[[J

Кстати, максимальнoe количество размерностeй массива - 255.

2. Метод
Дескриптор для метода имеет форму:
( ParameterDescriptor* ) ReturnDescriptor

Например
Код

void getIt(int i)

описывается дескриптором
Код

(I)V


Если один из параметров или возвращаемео значение - объект, указывается полное имя класса:
Код

Integer doIt(int i, Object o)

дескриптор
Код

(ILjava/lang/Object;)Ljava/lang/Integer;

Почему java/lang/Integer а не более привычное java.lang.Integer ? По историческим причинам: для совместимости со старыми JVM.

Конструктор обозначается через <init>:
Код

java/lang/Object."<init>":()V

- типичный пример "пустого" конструктора для класса, наследующего от Object.


Это сообщение отредактировал(а) Domestic Cat - 29.11.2004, 05:53


--------------------

PM   Вверх
Domestic Cat
Дата 29.11.2004, 07:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Теперь понятно, как JVM узнает о количестве аргиументов и возврашаемом типе.
Во что же превращается обычный вызов метода в байткоде?

Компиляция вызовов методов

Любой вызов метода означает создание нового фрейма на стеке. Текущая (выполняемая в данный момент) инструкция, точнее ее адрес, сидит в специальном регистре - pc register (program counter).
Естественно, в новый фрейм, в массив локальных переменных нужно передать аргументы и ссылку на объект, на котором был вызван метод.
Делается это так: на стек ложится ссылка на объект, поверх нее кладутся аргументы в нужном порядке, и вызывается один из методов invoke*****.
Рассмотрим на примере:
Код

public class Test
{
public void doIt()
{
 doThat(5, 10);
 doPublic();
 doStatic();
}
public void doPublic()
{}

private void doThat(int x, int y)
{}

public static void doStatic()
{}
}


Байткод:
Код

Compiled from "Test.java"
public class Test extends java.lang.Object
 SourceFile: "Test.java"
 minor version: 0
 major version: 0
 Constant pool:
const #1 = Method #6.#18; //  java/lang/Object."<init>":()V
const #2 = Method #5.#19; //  Test.doThat:(II)V
const #3 = Method #5.#20; //  Test.doPublic:()V
const #4 = Method #5.#21; //  Test.doStatic:()V
const #5 = class #22; //  Test
const #6 = class #23; //  Object
const #7 = Asciz <init>;
const #8 = Asciz ()V;
const #9 = Asciz Code;
const #10 = Asciz LineNumberTable;
const #11 = Asciz doIt;
const #12 = Asciz doPublic;
const #13 = Asciz doThat;
const #14 = Asciz (II)V;
const #15 = Asciz doStatic;
const #16 = Asciz SourceFile;
const #17 = Asciz Test.java;
const #18 = NameAndType #7:#8;//  "<init>":()V
const #19 = NameAndType #13:#14;//  doThat:(II)V
const #20 = NameAndType #12:#8;//  doPublic:()V
const #21 = NameAndType #15:#8;//  doStatic:()V
const #22 = Asciz Test;
const #23 = Asciz java/lang/Object;

{
public Test();
 Code:
  Stack=1, Locals=1, Args_size=1
  0: aload_0
  1: invokespecial #1; //Method java/lang/Object."<init>":()V
  4: return
 LineNumberTable:
  line 2: 0

public void doIt();
 Code:
  Stack=3, Locals=1, Args_size=1
  0: aload_0
  1: iconst_5
  2: bipush 10
  4: invokespecial #2; //Method doThat:(II)V
  7: aload_0
  8: invokevirtual #3; //Method doPublic:()V
  11: invokestatic #4; //Method doStatic:()V
  14: return
 LineNumberTable:
  line 6: 0
  line 7: 7
  line 8: 11
  line 9: 14

public void doPublic();
 Code:
  Stack=0, Locals=1, Args_size=1
  0: return
 LineNumberTable:
  line 11: 0

public static void doStatic();
 Code:
  Stack=0, Locals=0, Args_size=0
  0: return
 LineNumberTable:
  line 17: 0
}

Начнем с вызова метода doThat(). На стек ложится this, затем константа 5. Для оптимизации константы -1, 0, 1, 2, 3, 4, 5 в байткоде переносятся на стек инструксией iconst_x. Эта инструксия занимает 1 байт, тогда как аналогичный опкод bipush 10 весит 2 байта. Далее следует вызов метода. Что происходит при этом, см. на приаттаченном рисунке. Массив локальных переменных нового фрейма получает содержимое стека предыдущего фрейма.
invokespecial "опустошает" стек, поэтому когда тред возвращается к старому фрейму, стек пуст.
Всего есть 4 типа опкодов для вызова методов:
1. invokespecial. Эта инструкция используется для вызова конструкторов, приватных методов, и методов суперкласса (super()). Примеры: в конструкторе класса Test, вызов приватного метода doThat
2. invokestatic. Вызов статик метода.
3. invokeinterface Вызов методов интерфейса.
4. invokevirtual. Вызов любых других методов. Какой это будет метод, определяется в момент работы программы, из содержимого Constant Pool.


Это сообщение отредактировал(а) Domestic Cat - 5.3.2005, 11:08

Присоединённый файл ( Кол-во скачиваний: 31 )
Присоединённый файл  diag.jpg.jpg


--------------------

PM   Вверх
Sardar
Дата 29.11.2004, 11:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 4
Всего: 317



Цитата(Domestic @ 29.11.2004, 01:50)
Оператор деления лонгов возвращает лонг, как и оператор деления интов возвращает инт

Дык это же целое или я чего то не понял ? smile А целое с натяжкой можно обратит в вещественное, ну и "угадать" остаток самому...
Цитата(Domestic @ 29.11.2004, 01:50)
Такие вещи - проблема программиста, задача компилятора - скомпилировать, а оптимизацией займется JIT (just in time compiler). Нужен супероптимальный код - посмотри байткод и исправь  Хотя выигрыш тут будет никакой.

Задача компилятора генерить оптимальный код(не путать с оптимизированным), это должно быть по опредлению. Выигрышь будет хороший если подобным образом будет экономится память в тысячах методов smile

Цитата(Domestic @ 29.11.2004, 06:07)
public Test();
Code:
  Stack=1, Locals=1, Args_size=1
  0: aload_0
  1: invokespecial #1; //Method java/lang/Object."<init>":()V
  4: return

А что если я не сгенерю(не Sun Java SDK) инициализатор предка/Object? Вроде как с памятью и всё такое проблему будут...

Цитата(Domestic @ 29.11.2004, 06:07)
Массив локальных переменных нового фрейма получает содержимое стека предыдущего фрейма.

Цитата(Domestic @ 29.11.2004, 00:30)
Кстати, перемещения константы-> стек->массив->стек вполне нормальная вещь, если помнить, что со стеком можно сделать только 2 вещи: положить в него, и взять оттуда. Любая операция, не ложащая че-нибудь на стек, забирает оттуда переменную.

Видим противоречие... Стек становится массивом, не копируется, ни на какой платформе не копируется, иначе прога будет исполнятся годами smile
Аппаратно х86(да и другие) поддерживают бег с индексом в стеке, иначе это бесполезный в обычной жизни стек(мы же не теоретики). Значит по стеку можно бегать, так зачем при вычислениях эти "туды-сюды"?


--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
Domestic Cat
Дата 29.11.2004, 16:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Цитата
Дык это же целое или я чего то не понял ?  А целое с натяжкой можно обратит в вещественное, ну и "угадать" остаток самому...


я к тому, чтo в Java long/long = long, что делается опкодом ldiv. Такое деление быстрее.
Цитата
Выигрышь будет хороший если подобным образом будет экономится память в тысячах методов

Дык ведь это автоматичскиe переменные, когдa метод завершется, они выбрасываются. smile Возможно, для какoгo-нибудь рекурсивного алгоритмa так оно и будеt - метод вызываеt сам себя скажm 1000 раз, и нa стек помещается 1000 фреймов с 1000 ненужных переменных - ну так программер и должеn следит' зa этим. И без байткодa ясно, что объявление лишних локальных переменных ест стек

Цитата
Видим противоречие... Стек становится массивом, не копируется, ни на какой платформе не копируется, иначе прога будет исполнятся годами

А я развe где-тo писаl, что копируется smile Под "становится" подразумевалось "перемещается в".
Цитата
Аппаратно х86(да и другие) поддерживают бег с индексом в стеке, иначе это бесполезный в обычной жизни стек(мы же не теоретики). Значит по стеку можно бегать, так зачем при вычислениях эти "туды-сюды"?

Но ведь JVM - это абстрактная, кроссплатформенная машина smile


--------------------

PM   Вверх
polosatij
Дата 29.11.2004, 21:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1143
Регистрация: 22.2.2004
Где: Stuttgart<-> ;Karlsruhe, Germany

Репутация: 1
Всего: 8



Цитата(Domestic @ 27.11.2004, 07:24)
Поскольку опкод может также иметь аргументы, нумерация идет с разрывами: например код
Код

putfield #4;



запишется так:

Код

{..., 181, 0, 4, ...}



Если 181 (putfield) - седьмой элемент массива, то вместе с аргументом он займет 3 байта.


Domestic Cat, ты не мог бы обьяснить.. (либо я просто где-то что-то упустил)


хм.. чего-то я недопонял smile
как это седьмой элемент и 3 байта? ссылка на адрес в памяти?

что занимает 3 байта smile

Это сообщение отредактировал(а) polosatij - 29.11.2004, 21:26


--------------------
PM   Вверх
Domestic Cat
Дата 29.11.2004, 22:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Код метода записывается в виде массива, индексы которого в дизассемблированном коде стоят слева:
Код

  1:      invokespecial        #1; //Method java/lang/Object."<init>":()V
   4:    aload_0
   5:      new        #2; //class Object
   8:    dup
...


В этом массиве записаны те самые инструкции что tы видишь здесь, точнее иx эвиваленты - числа типa byte. Напримeр invokespecial = 183 (0xb7), сидiт в ячейкe массива 1. Поскольку у него ест' аргумent, тo вся инструкция займet 3 байтa: 183, 0, 1, ....



--------------------

PM   Вверх
Domestic Cat
Дата 29.11.2004, 22:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Играем с байткодом, или BCEL

BCEL - Byte Code Engeneering Library - проект Apache, который позволяет относительно просто работать с байткодом: создавать, удалять, редактировать методы в класс файлах, менять констант пул, добавлять/убирать поля, менять наследование, в общем, делать с байткодом практически все что угодно - и делать все это динамически.
Кроме того, он содержит ряд полезных утилит. Например, Class2HTML позволяет просмотреть байткод класса в HTML формате:
Код

cat> java org.apache.bcel.util.Class2HTML MyClass.class

BCELifier перегоняет класс в java-файл, который при запуске сгенерировал бы такой класс-файл.
Код

cat> java org.apache.bcel.util.BCELifier MyClass.class >> MyClassBCEL.java


Пример.
Есть простенкий код:

Код

public class SimpleClass
{  
   public void printIt()
   {
       System.out.println("Hello");
   }
   
   public static void main(String [] args)
   {
       new SimpleClass().printIt();
   }
}

который выводит в консоль слово Hello. Предположим мы его скомпилировали, а сорец удалили.
С помощью BCEL в этом файле я удаляю метод printIt и заменяю его на метод printIt, выдающий в консоль Hello from Domestic Cat:

Код

import java.io.*;
import org.apache.bcel.classfile.*;
import org.apache.bcel.generic.*;
import org.apache.bcel.Constants;

public class Changer
{
   
   private static void changeMethod(ClassGen classGen, Method oldMethod)
   {
       InstructionFactory iFactory = new InstructionFactory(classGen);
       ConstantPoolGen poolGen = classGen.getConstantPool();
       String className = classGen.getClassName();
       classGen.removeMethod(oldMethod);
       
       InstructionList iList = new InstructionList();
       MethodGen method = new MethodGen(Constants.ACC_PUBLIC, Type.VOID, Type.NO_ARGS,
new String[] {  }, "printIt", "SimpleClass", iList, poolGen);
       InstructionHandle iHandle = iList.append(iFactory.createFieldAccess("java.lang.System", "out",
new ObjectType("java.io.PrintStream"), Constants.GETSTATIC));
       iList.append(new PUSH(poolGen, "Hello from Domestic Cat"));
       iList.append(iFactory.createInvoke("java.io.PrintStream", "println", Type.VOID, new Type[]
{ Type.STRING }, Constants.INVOKEVIRTUAL));
       InstructionHandle iHandle2 = iList.append(iFactory.createReturn(Type.VOID));
       method.setMaxStack();
       method.setMaxLocals();
       classGen.addMethod(method.getMethod());
       iList.dispose();
   }
   
   public static void main(String[] args)
   {
       try
       {
           JavaClass javaClass = new ClassParser("SimpleClass.class").parse();
           ClassGen classGen = new ClassGen(javaClass);
           Method[] methods = javaClass.getMethods();
           if (methods[1].getName().equals("printIt"))
           {
               changeMethod(classGen, methods[1]);
               FileOutputStream fos = new FileOutputStream("SimpleClass.class");
               classGen.getJavaClass().dump(fos);
               fos.close();
           }
           else
           {
               System.out.println("Cannot find the method");
           }
       }
       catch (IOException e)
       {
           e.printStackTrace();
       }
   }
}

(Программа перезапишет исходный класс! ).

Оба сорца в аттачменте.

Это сообщение отредактировал(а) Domestic Cat - 29.11.2004, 22:27

Присоединённый файл ( Кол-во скачиваний: 8 )
Присоединённый файл  Archive_2.zip


--------------------

PM   Вверх
Domestic Cat
Дата 30.11.2004, 05:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



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


--------------------

PM   Вверх
Sleepy_PIP
Дата 30.11.2004, 09:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 512
Регистрация: 30.6.2004
Где: Moscow

Репутация: 4
Всего: 12



Цитата(Domestic @ 30.11.2004, 05:45)
Я че хочу спросить: стоит ли продолжать? Большую часть инфы можно почерпнуть из спецификации, а тут довольно сумбурно получается.

мое мнение - очень важная тема и интересно изложена. т.е. продолжать по возможности надо ... Спасибо!



--------------------
--
Sleepy_PIP. Pavel Pryazhentsev (ex. 2:5020/141) "... Лучше быть нужным, чем
свободным ..."
PM MAIL ICQ   Вверх
Sardar
Дата 30.11.2004, 10:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 4
Всего: 317



Domestic Cat если есть время, то продолжай, интересно. Сам я пока в спецификацию не полезу, другим занят smile Но почитать, обдумать, усвоить на примерах хочется.


--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
Sleepy_PIP
Дата 30.11.2004, 11:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 512
Регистрация: 30.6.2004
Где: Moscow

Репутация: 4
Всего: 12



Цитата(Sleepy_PIP @ 30.11.2004, 09:02)
Цитата(Domestic @ 30.11.2004, 05:45)
Я че хочу спросить: стоит ли продолжать? Большую часть инфы можно почерпнуть из спецификации, а тут довольно сумбурно получается.

мое мнение - очень важная тема и интересно изложена. т.е. продолжать по возможности надо ... Спасибо!

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


--------------------
--
Sleepy_PIP. Pavel Pryazhentsev (ex. 2:5020/141) "... Лучше быть нужным, чем
свободным ..."
PM MAIL ICQ   Вверх
polosatij
Дата 30.11.2004, 13:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1143
Регистрация: 22.2.2004
Где: Stuttgart<-> ;Karlsruhe, Germany

Репутация: 1
Всего: 8



Цитата(Domestic @ 30.11.2004, 05:45)
стоит ли продолжать?


я за smile smile

скажи, откуда ты взял полную спецификацию кодов?
например:

dup - создается дубликат на стеке smile


--------------------
PM   Вверх
Domestic Cat
Дата 30.11.2004, 16:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Цитата
скажи, откуда ты взял полную спецификацию кодов?
например:


В той же спецификации:

http://java.sun.com/docs/books/vmspec/2nd-...tions2.doc.html

Ок, в таком случае я продолжу - про то. как компилятся различые структуры в байткод. Я начну с того что есть в спеке, а затем перейду к внутренним классам и Java 5.0. Только делать я смогу это из дома smile


--------------------

PM   Вверх
polosatij
Дата 30.11.2004, 22:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1143
Регистрация: 22.2.2004
Где: Stuttgart<-> ;Karlsruhe, Germany

Репутация: 1
Всего: 8



Цитата(Domestic @ 30.11.2004, 16:03)
В той же спецификации:

http://java.sun.com/docs/books/vmspec/2nd-...tions2.doc.html


пасиба smile


декомпилировал несколько классов и увидел (к примеру) следующий bytecode:

10: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
13: aload_1
14: invokevirtual #7; //Method test:()I
17: invokevirtual #8; //Method java/io/PrintStream.println:(I)V
20: nop
21: return

1.ты не скажешь, зачем nop? в спецификации: Do nothing
зачем терять байты?

2. возможна ли обратная конвертация всего в класс стандартными утилитами SUN ?




--------------------
PM   Вверх
Domestic Cat
Дата 30.11.2004, 23:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Цитата
1.ты не скажешь, зачем nop? в спецификации: Do nothing
зачем терять байты?


А можно java код посмотреть? smile
Цитата
2. возможна ли обратная конвертация всего в класс стандартными утилитами SUN ?


Для этого есть декомпиляторы, их можн найти тут:

http://www.thefreecountry.com/programming/javatools.shtml

Немного не о декомпиляции, но зато забавнo: Jamaica


--------------------

PM   Вверх
polosatij
Дата 30.11.2004, 23:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1143
Регистрация: 22.2.2004
Где: Stuttgart<-> ;Karlsruhe, Germany

Репутация: 1
Всего: 8



Цитата(Domestic @ 30.11.2004, 23:16)
А можно java код посмотреть? 


Код

package example;

public class Main {
 public int test() {
   System.out.println("HI :)");
   return 111;
 }
 
 public static void main(String[] args) {
   Main main= new Main();
   double i=0;
   System.out.println(main.test());
 }
}


Код

Compiled from "Main.java"
public class example.Main extends java.lang.Object
 SourceFile: "Main.java"
 minor version: 0
 major version: 0
 Constant pool:
const #1 = Method #9.#27; //  java/lang/Object."<init>":()V
const #2 = Field #28.#29; //  java/lang/System.out:Ljava/io/PrintStream;
const #3 = String #30; //  HI :)
const #4 = Method #31.#32; //  java/io/PrintStream.println:(Ljava/lang/String;)V
const #5 = class #33; //  Main
const #6 = Method #5.#27; //  example/Main."<init>":()V
const #7 = Method #5.#34; //  example/Main.test:()I
const #8 = Method #31.#35; //  java/io/PrintStream.println:(I)V
const #9 = class #36; //  Object
const #10 = Asciz <init>;
const #11 = Asciz ()V;
const #12 = Asciz Code;
const #13 = Asciz LineNumberTable;
const #14 = Asciz LocalVariableTable;
const #15 = Asciz this;
const #16 = Asciz Lexample/Main;;
const #17 = Asciz main;
const #18 = Asciz ([Ljava/lang/String;)V;
const #19 = Asciz args;
const #20 = Asciz [Ljava/lang/String;;
const #21 = Asciz i;
const #22 = Asciz D;
const #23 = Asciz test;
const #24 = Asciz ()I;
const #25 = Asciz SourceFile;
const #26 = Asciz Main.java;
const #27 = NameAndType #10:#11;//  "<init>":()V
const #28 = class #37; //  System
const #29 = NameAndType #38:#39;//  out:Ljava/io/PrintStream;
const #30 = Asciz HI :);
const #31 = class #40; //  PrintStream
const #32 = NameAndType #41:#42;//  println:(Ljava/lang/String;)V
const #33 = Asciz example/Main;
const #34 = NameAndType #23:#24;//  test:()I
const #35 = NameAndType #41:#43;//  println:(I)V
const #36 = Asciz java/lang/Object;
const #37 = Asciz java/lang/System;
const #38 = Asciz out;
const #39 = Asciz Ljava/io/PrintStream;;
const #40 = Asciz java/io/PrintStream;
const #41 = Asciz println;
const #42 = Asciz (Ljava/lang/String;)V;
const #43 = Asciz (I)V;

{
public example.Main();
 Code:
  Stack=1, Locals=1, Args_size=1
  0: aload_0
  1: invokespecial #1; //Method java/lang/Object."<init>":()V
  4: nop
  5: return
 LineNumberTable:
  line 3: 0
  line 14: 4
 LocalVariableTable:
  Start  Length  Slot  Name   Signature
  0      6      0    this       Lexample/Main;

public static void main(java.lang.String[]);
 Code:
  Stack=2, Locals=4, Args_size=1
  0: new #5; //class Main
  3: dup
  4: invokespecial #6; //Method "<init>":()V
  7: astore_1
  8: dconst_0
  9: dstore_2
  10: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
  13: aload_1
  14: invokevirtual #7; //Method test:()I
  17: invokevirtual #8; //Method java/io/PrintStream.println:(I)V
  20: [b]nop[/b]
  21: return
 LineNumberTable:
  line 10: 0
  line 11: 8
  line 12: 10
  line 13: 20
 LocalVariableTable:
  Start  Length  Slot  Name   Signature
  0      22      0    args       [Ljava/lang/String;
  8      13      1    main       Lexample/Main;
  10      11      2    i       D

public int test();
 Code:
  Stack=2, Locals=1, Args_size=1
  0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
  3: ldc #3; //String HI :)
  5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
  8: bipush 111
  10: ireturn
 LineNumberTable:
  line 5: 0
  line 6: 8
 LocalVariableTable:
  Start  Length  Slot  Name   Signature
  0      11      0    this       Lexample/Main;

}


Цитата(Domestic @ 30.11.2004, 23:16)
Для этого есть декомпиляторы, их можн найти тут:

http://www.thefreecountry.com/programming/javatools.shtml

Немного не о декомпиляции, но зато забавнo: Jamaica


фууф.. документацией закидал smile нужной документацией.. потопал читать дальше smile



--------------------
PM   Вверх
Domestic Cat
Дата 30.11.2004, 23:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



А какая у тебя JDK? 1.4.03 выдает вот что:
Код

// только байткоd
Compiled from "Main.java"
public class example.Main extends java.lang.Object{
public example.Main();
 Code:
  0: aload_0
  1: invokespecial #1; //Method java/lang/Object."<init>":()V
  4: return

public int test();
 Code:
  0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
  3: ldc #3; //String HI :)
  5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
  8: bipush 111
  10: ireturn

public static void main(java.lang.String[]);
 Code:
  0: new #5; //class Main
  3: dup
  4: invokespecial #6; //Method "<init>":()V
  7: astore_1
  8: dconst_0
  9: dstore_2
  10: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
  13: aload_1
  14: invokevirtual #7; //Method test:()I
  17: invokevirtual #8; //Method java/io/PrintStream.println:(I)V
  20: return

}



--------------------

PM   Вверх
polosatij
Дата 1.12.2004, 02:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1143
Регистрация: 22.2.2004
Где: Stuttgart<-> ;Karlsruhe, Germany

Репутация: 1
Всего: 8



Цитата(Domestic @ 30.11.2004, 23:46)
А какая у тебя JDK? 1.4.03


1.4.2_01

да, я работаю с JBuilder он мне наиболее симпотичен smile
я так же заметил, что код компилированный от JBuilder-а не может быть дизассемблированн sun-овским javap. может это только совпадение.. но уже 3 раза попадал на такой случай smile


--------------------
PM   Вверх
Domestic Cat
Дата 1.12.2004, 04:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Цитата(polosatij @ 30.11.2004, 17:24)
я так же заметил, что код компилированный от JBuilder-а не может быть дизассемблированн sun-овским javap. может это только совпадение.. но уже 3 раза попадал на такой случай smile


smile

------------------------------------------------------------

Байткод для массивов, свитчей и иксепшнов

В общем, это краткое изложение написанного в спецификации. Я написал один класс с 4 методами: созданием массивов, 2 метода со switch'ами и 1 с иксепшн хэндлингом:
Код

public class Test
{
public void doArrays()
{
   int[] ia = new int[10];
    Object [][] oa = new Object[12][2];
}

public void doSwitch(int i)
{
   switch (i)
   {
    case (0) : i++; break;
    case(1) : i++; break;
    case(2) : i++; break;
    default : i--;
   }
}

public void doSwitch2(int i)
{
   switch (i)
   {
    case (10) : i++; break;
    case(100) : i++; break;
    default : i--;
   }
}

public void doException()
{
   int x = 0;
   try
   {
    Thread.sleep(100);
   }
   catch (InterruptedException ie)
   {
    x++;  
   }
   catch (Exception e)
   {
    x--;
   }
   finally
   {
    x = 0;
   }
}
}

Полный байткод с пулом я приводить не буду, помещу только куски для экономии места.
1. Массивы
Код

public void doArrays();
 Code:
  Stack=2, Locals=3, Args_size=1
  0: bipush 10
  2: newarray int
  4: astore_1
  5: bipush 12
  7: iconst_2
  8: multianewarray #2,  2; //class "[[Ljava/lang/Object;"
  12: astore_2
  13: return

Одномерный массив создается опкодом [a]newarray <type>, при этом на стеке должен лежать размер массива. (опкод anewarray созает массив объектов, newarray - массив примитивов) Многомерный массив создается так же, но инструкцией multi[a]newarray

2. switch

Получаем вот что:
Код

public void doSwitch(int);
 Code:
  Stack=1, Locals=2, Args_size=2
  0: iload_1
  1: tableswitch{ //0 to 2
 0: 28;
 1: 34;
 2: 40;
 default: 46 }
  28: iinc 1, 1
  31: goto 49
  34: iinc 1, 1
  37: goto 49
  40: iinc 1, 1
  43: goto 49
  46: iinc 1, -1
  49: return

public void doSwitch2(int);
 Code:
  Stack=1, Locals=2, Args_size=2
  0: iload_1
  1: lookupswitch{ //2
 10: 28;
 100: 34;
 default: 40 }
  28: iinc 1, 1
  31: goto 43
  34: iinc 1, 1
  37: goto 43
  40: iinc 1, -1
  43: return


Свитчи с непрерывным диапазоном case'ов (0-1-2-деафулт) компилируются в tableswitch. В остальных случаях используется lookupswitch. Кстати, если значений всего два (например 1-2-дефаулт), будет использован lookupswitch.

3. Иксепшны
Код

public void doException();
 Code:
  Stack=2, Locals=4, Args_size=1
  0: iconst_0
  1: istore_1
  2: ldc2_w #3; //long 100l
  5: invokestatic #5; //Method java/lang/Thread.sleep:(J)V
  8: iconst_0
  9: istore_1
  10: goto 36
  13: astore_2
  14: iinc 1, 1
  17: iconst_0
  18: istore_1
  19: goto 36
  22: astore_2
  23: iinc 1, -1
  26: iconst_0
  27: istore_1
  28: goto 36
  31: astore_3
  32: iconst_0
  33: istore_1
  34: aload_3
  35: athrow
  36: return
 Exception table:
  from   to  target type
    2     8    13   Class java/lang/InterruptedException
    2     8    22   Class java/lang/Exception
    2     8    31   any
   13    17    31   any
   22    26    31   any
   31    32    31   any


Код хорош тем, что после него начинаешь четко представлять, что такое finally smile
Он превратился в строки 87-10, то есть он идет непосредственно за Thread.sleep(). Кроме того, он же стал строками 17-18, 26-27. finally на самом деле занял 6 байт, тогда как собственно код внутри него весит всего 2 байта!
Первый catch стал строками 13-17, второй catch - 22-26. JVM добавила "перестраховочный" catch, ловящий иксепшны из первых двух кетчей и перебрасывающий возможный иксепшн.
Бросание иксепшна сопровождается потерей фрейма и всего его содержимого.

Это сообщение отредактировал(а) Domestic Cat - 1.12.2004, 05:18


--------------------

PM   Вверх
Domestic Cat
Дата 1.12.2004, 05:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Чтобы иметь еще более четкое представление о том, как устроен class файл, полезно стянуть JCD дизасм (в аттачменте, для виндов), запустить его, и посмотреть любой класс файл. JCD дает более подробную информацию, чем javap -verbose, в частности, модификаторы полей и методов. Так, для предыдыщей программы получаем:
Код

Disassembling: C:\javafiles\Test.class

--------        ------------------------------        -----
OFFSET                   FIELD NAME                  VALUE
--------        ------------------------------        -----

00000000        Signature                             CAFE BABE
00000004        Minor Version                         0
00000006        Major Version                         49

Constant Pool

00000008        Constant Pool Count                   31
0000000a        CONSTANT_Methodref                    Entry (1) Class (9) Name/Type (21)
0000000f        CONSTANT_Class                        Entry (2) (22)
00000012        CONSTANT_Long                         Entry (3) 100
0000001b        CONSTANT_Methodref                    Entry (5) Class (23) Name/Type (24)
00000020        CONSTANT_Class                        Entry (6) (25)
00000023        CONSTANT_Class                        Entry (7) (26)
00000026        CONSTANT_Class                        Entry (8) (27)
00000029        CONSTANT_Class                        Entry (9) (28)
0000002c        CONSTANT_Utf8                         Entry (10) <init>
00000035        CONSTANT_Utf8                         Entry (11) ()V
0000003b        CONSTANT_Utf8                         Entry (12) Code
00000042        CONSTANT_Utf8                         Entry (13) LineNumberTable
00000054        CONSTANT_Utf8                         Entry (14) doArrays
0000005f        CONSTANT_Utf8                         Entry (15) doSwitch
0000006a        CONSTANT_Utf8                         Entry (16) (I)V
00000071        CONSTANT_Utf8                         Entry (17) doSwitch2
0000007d        CONSTANT_Utf8                         Entry (18) doException
0000008b        CONSTANT_Utf8                         Entry (19) SourceFile
00000098        CONSTANT_Utf8                         Entry (20) Test.java
000000a4        CONSTANT_NameAndType                  Entry (21) Name (10) Type (11)
000000a9        CONSTANT_Utf8                         Entry (22) [[Ljava/lang/Object;
000000c0        CONSTANT_Class                        Entry (23) (29)
000000c3        CONSTANT_NameAndType                  Entry (24) Name (30) Type (31)
000000c8        CONSTANT_Utf8                         Entry (25) java/lang/InterruptedException
000000e9        CONSTANT_Utf8                         Entry (26) java/lang/Exception
000000ff        CONSTANT_Utf8                         Entry (27) Test
00000106        CONSTANT_Utf8                         Entry (28) java/lang/Object
00000119        CONSTANT_Utf8                         Entry (29) java/lang/Thread
0000012c        CONSTANT_Utf8                         Entry (30) sleep
00000134        CONSTANT_Utf8                         Entry (31) (J)V

0000013b        Access Flags                          ACC_PUBLIC ACC_SUPER
0000013d        This Class                            (8)
0000013f        Super Class                           (9)

Interfaces

00000141        Interfaces Count                      0

Fields

00000143        Fields Count                          0

Methods

00000145        Methods Count                         5

Method #1

00000147        Access Flags                          ACC_PUBLIC
00000149        Name                                  (10)
0000014b        Type                                  (11)
0000014d        Attributes Count                      1
0000014f        Attribute Name                        (12)
00000151        Bytes Count                           29
00000155        Max Stack                             1
00000157        Max Locals                            1
00000159        Code Count                            5

      0        aload_0
      1        invokespecial (1)
      4        return

00000162        Handlers Count                        0
00000164        Attributes Count                      1
00000166        Attribute Name                        (13)
00000168        Bytes Count                           6
0000016c        Lines Count                           1
0000016e        Start PC                              0
00000170        Line Number                           1

Method #2

00000172        Access Flags                          ACC_PUBLIC
00000174        Name                                  (14)
00000176        Type                                  (11)
00000178        Attributes Count                      1
0000017a        Attribute Name                        (12)
0000017c        Bytes Count                           46
00000180        Max Stack                             2
00000182        Max Locals                            3
00000184        Code Count                            14

      0        bipush 10
      2        newarray int
      4        astore_1
      5        bipush 12
      7        iconst_2
      8        multianewarray (2) 2
     12        astore_2
     13        return

00000196        Handlers Count                        0
00000198        Attributes Count                      1
0000019a        Attribute Name                        (13)
0000019c        Bytes Count                           14
000001a0        Lines Count                           3
000001a2        Start PC                              0
000001a4        Line Number                           5
000001a6        Start PC                              5
000001a8        Line Number                           6
000001aa        Start PC                              13
000001ac        Line Number                           7

Method #3

000001ae        Access Flags                          ACC_PUBLIC
000001b0        Name                                  (15)
000001b2        Type                                  (16)
000001b4        Attributes Count                      1
000001b6        Attribute Name                        (12)
000001b8        Bytes Count                           94
000001bc        Max Stack                             1
000001be        Max Locals                            2
000001c0        Code Count                            50

      0        iload_1
      1        tableswitch
      4        Default = 46
      8        Low = 0, High = 2
     16        Offset = 28
     20        Offset = 34
     24        Offset = 40
     28        iinc 1 1
     31        goto 49
     34        iinc 1 1
     37        goto 49
     40        iinc 1 1
     43        goto 49
     46        iinc 1 -1
     49        return

000001f6        Handlers Count                        0
000001f8        Attributes Count                      1
000001fa        Attribute Name                        (13)
000001fc        Bytes Count                           26
00000200        Lines Count                           6
00000202        Start PC                              0
00000204        Line Number                           11
00000206        Start PC                              28
00000208        Line Number                           13
0000020a        Start PC                              34
0000020c        Line Number                           14
0000020e        Start PC                              40
00000210        Line Number                           15
00000212        Start PC                              46
00000214        Line Number                           16
00000216        Start PC                              49
00000218        Line Number                           18

Method #4

0000021a        Access Flags                          ACC_PUBLIC
0000021c        Name                                  (17)
0000021e        Type                                  (16)
00000220        Attributes Count                      1
00000222        Attribute Name                        (12)
00000224        Bytes Count                           84
00000228        Max Stack                             1
0000022a        Max Locals                            2
0000022c        Code Count                            44

      0        iload_1
      1        lookupswitch
      4        Default = 40
               Key = 10, Offset = 28
               Key = 100, Offset = 34
     28        iinc 1 1
     31        goto 43
     34        iinc 1 1
     37        goto 43
     40        iinc 1 -1
     43        return

0000025c        Handlers Count                        0
0000025e        Attributes Count                      1
00000260        Attribute Name                        (13)
00000262        Bytes Count                           22
00000266        Lines Count                           5
00000268        Start PC                              0
0000026a        Line Number                           22
0000026c        Start PC                              28
0000026e        Line Number                           24
00000270        Start PC                              34
00000272        Line Number                           25
00000274        Start PC                              40
00000276        Line Number                           26
00000278        Start PC                              43
0000027a        Line Number                           28

Method #5

0000027c        Access Flags                          ACC_PUBLIC
0000027e        Name                                  (18)
00000280        Type                                  (11)
00000282        Attributes Count                      1
00000284        Attribute Name                        (12)
00000286        Bytes Count                           165
0000028a        Max Stack                             2
0000028c        Max Locals                            4
0000028e        Code Count                            37

      0        iconst_0
      1        istore_1
      2        ldc2_w (3)
      5        invokestatic (5)
      8        iconst_0
      9        istore_1
     10        goto 36
     13        astore_2
     14        iinc 1 1
     17        iconst_0
     18        istore_1
     19        goto 36
     22        astore_2
     23        iinc 1 -1
     26        iconst_0
     27        istore_1
     28        goto 36
     31        astore_3
     32        iconst_0
     33        istore_1
     34        aload_3
     35        athrow
     36        return

000002b7        Handlers Count                        6
000002b9        Start PC                              2
000002bb        End PC                                8
000002bd        Handler PC                            13
000002bf        Catch Type                            (6)
000002c1        Start PC                              2
000002c3        End PC                                8
000002c5        Handler PC                            22
000002c7        Catch Type                            (7)
000002c9        Start PC                              2
000002cb        End PC                                8
000002cd        Handler PC                            31
000002cf        Catch Type                            (0)
000002d1        Start PC                              13
000002d3        End PC                                17
000002d5        Handler PC                            31
000002d7        Catch Type                            (0)
000002d9        Start PC                              22
000002db        End PC                                26
000002dd        Handler PC                            31
000002df        Catch Type                            (0)
000002e1        Start PC                              31
000002e3        End PC                                32
000002e5        Handler PC                            31
000002e7        Catch Type                            (0)
000002e9        Attributes Count                      1
000002eb        Attribute Name                        (13)
000002ed        Bytes Count                           62
000002f1        Lines Count                           15
000002f3        Start PC                              0
000002f5        Line Number                           32
000002f7        Start PC                              2
000002f9        Line Number                           35
000002fb        Start PC                              8
000002fd        Line Number                           47
000002ff        Start PC                              10
00000301        Line Number                           48
00000303        Start PC                              13
00000305        Line Number                           37
00000307        Start PC                              14
00000309        Line Number                           39
0000030b        Start PC                              17
0000030d        Line Number                           47
0000030f        Start PC                              19
00000311        Line Number                           48
00000313        Start PC                              22
00000315        Line Number                           41
00000317        Start PC                              23
00000319        Line Number                           43
0000031b        Start PC                              26
0000031d        Line Number                           47
0000031f        Start PC                              28
00000321        Line Number                           48
00000323        Start PC                              31
00000325        Line Number                           47
00000327        Start PC                              34
00000329        Line Number                           48
0000032b        Start PC                              36
0000032d        Line Number                           50

Attributes

0000032f        Attributes Count                      1

Attribute #1

00000331        Attribute Name                        (19)
00000333        Bytes Count                           0
00000337        Source File                           (20)



Это сообщение отредактировал(а) Domestic Cat - 1.12.2004, 05:39

Присоединённый файл ( Кол-во скачиваний: 18 )
Присоединённый файл  jcd.zip


--------------------

PM   Вверх
Domestic Cat
Дата 1.12.2004, 17:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Внутренние классы

1. Статик классы
Посмотрим нa примерe кода:
Код

public class SimpleClass
{  
   static int x;
   public static class InnerClass
   {
       public void method()
       {
           x = 0;
       }
   }
   
   public void method2()
   {
       new InnerClass();
   }
}


Дизассемблировав, получим
Код

Compiled from "SimpleClass.java"
public class SimpleClass extends java.lang.Object
 SourceFile: "SimpleClass.java"
 InnerClass:
  public #6= #2 of #4; //InnerClass=class SimpleClass$InnerClass of class SimpleClass
 minor version: 0
 major version: 0
 Constant pool:
const #1 = Method #5.#17; //  java/lang/Object."<init>":()V
const #2 = class #18; //  SimpleClass$InnerClass
const #3 = Method #2.#17; //  SimpleClass$InnerClass."<init>":()V
const #4 = class #19; //  SimpleClass
const #5 = class #20; //  Object
const #6 = Asciz InnerClass;
const #7 = Asciz InnerClasses;
const #8 = Asciz x;
const #9 = Asciz I;
const #10 = Asciz <init>;
const #11 = Asciz ()V;
const #12 = Asciz Code;
const #13 = Asciz LineNumberTable;
const #14 = Asciz method2;
const #15 = Asciz SourceFile;
const #16 = Asciz SimpleClass.java;
const #17 = NameAndType #10:#11;//  "<init>":()V
const #18 = Asciz SimpleClass$InnerClass;
const #19 = Asciz SimpleClass;
const #20 = Asciz java/lang/Object;

{
static int x;

public SimpleClass();
 Code:
  Stack=1, Locals=1, Args_size=1
  0: aload_0
  1: invokespecial #1; //Method java/lang/Object."<init>":()V
  4: return
 LineNumberTable:
  line 3: 0
  line 6: 4

public void method2();
 Code:
  Stack=2, Locals=1, Args_size=1
  0: new #2; //class SimpleClass$InnerClass
  3: dup
  4: invokespecial #3; //Method SimpleClass$InnerClass."<init>":()V
  7: pop
  8: return
 LineNumberTable:
  line 16: 0
  line 17: 8

}



и
Код

Compiled from "SimpleClass.java"
public class SimpleClass$InnerClass extends java.lang.Object
 SourceFile: "SimpleClass.java"
 InnerClass:
  public #16= #3 of #13; //InnerClass=class SimpleClass$InnerClass of class SimpleClass
 minor version: 0
 major version: 0
 Constant pool:
const #1 = Method #4.#12; //  java/lang/Object."<init>":()V
const #2 = Field #13.#14; //  SimpleClass.x:I
const #3 = class #15; //  SimpleClass$InnerClass
const #4 = class #18; //  Object
const #5 = Asciz <init>;
const #6 = Asciz ()V;
const #7 = Asciz Code;
const #8 = Asciz LineNumberTable;
const #9 = Asciz method;
const #10 = Asciz SourceFile;
const #11 = Asciz SimpleClass.java;
const #12 = NameAndType #5:#6;//  "<init>":()V
const #13 = class #19; //  SimpleClass
const #14 = NameAndType #20:#21;//  x:I
const #15 = Asciz SimpleClass$InnerClass;
const #16 = Asciz InnerClass;
const #17 = Asciz InnerClasses;
const #18 = Asciz java/lang/Object;
const #19 = Asciz SimpleClass;
const #20 = Asciz x;
const #21 = Asciz I;

{
public SimpleClass$InnerClass();
 Code:
  Stack=1, Locals=1, Args_size=1
  0: aload_0
  1: invokespecial #1; //Method java/lang/Object."<init>":()V
  4: return
 LineNumberTable:
  line 6: 0

public void method();
 Code:
  Stack=1, Locals=1, Args_size=1
  0: iconst_0
  1: putstatic #2; //Field SimpleClass.x:I
  4: return
 LineNumberTable:
  line 10: 0
  line 11: 4

}


чтобы дизассемблировать вnутренний класс через javap, набираем
Код

cat> javap -verbose SimpleClass.InnerClass > txt.txt


Видно, что constant pool в InnerClass содержит ссылку нa статиk поle класса SimpleClass, благодаря чеmu внутренниe классы имеют доступ к (статик) переменныm внешнего классa.

2. Инстанс классы
Если класс не статик (код я приводить не буду, он такой же, только без модифаеров "static")
получим
Код

Compiled from "SimpleClass.java"
public class SimpleClass extends java.lang.Object
 SourceFile: "SimpleClass.java"
 InnerClass:
  public #6= #2 of #4; //InnerClass=class SimpleClass$InnerClass of class SimpleClass
 minor version: 0
 major version: 0
 Constant pool:
const #1 = Method #5.#17; //  java/lang/Object."<init>":()V
const #2 = class #18; //  SimpleClass$InnerClass
const #3 = Method #2.#19; //  SimpleClass$InnerClass."<init>":(LSimpleClass;)V
const #4 = class #20; //  SimpleClass
const #5 = class #21; //  Object
const #6 = Asciz InnerClass;
const #7 = Asciz InnerClasses;
const #8 = Asciz x;
const #9 = Asciz I;
const #10 = Asciz <init>;
const #11 = Asciz ()V;
const #12 = Asciz Code;
const #13 = Asciz LineNumberTable;
const #14 = Asciz method2;
const #15 = Asciz SourceFile;
const #16 = Asciz SimpleClass.java;
const #17 = NameAndType #10:#11;//  "<init>":()V
const #18 = Asciz SimpleClass$InnerClass;
const #19 = NameAndType #10:#22;//  "<init>":(LSimpleClass;)V
const #20 = Asciz SimpleClass;
const #21 = Asciz java/lang/Object;
const #22 = Asciz (LSimpleClass;)V;

{
int x;

public SimpleClass();
 Code:
  Stack=1, Locals=1, Args_size=1
  0: aload_0
  1: invokespecial #1; //Method java/lang/Object."<init>":()V
  4: return
 LineNumberTable:
  line 3: 0
  line 6: 4

public void method2();
 Code:
  Stack=3, Locals=1, Args_size=1
  0: new #2; //class SimpleClass$InnerClass
  3: dup
  4: aload_0
  5: invokespecial #3; //Method SimpleClass$InnerClass."<init>":(LSimpleClass;)V
  8: pop
  9: return
 LineNumberTable:
  line 16: 0
  line 17: 9

}
Код

Compiled from "SimpleClass.java"
public class SimpleClass$InnerClass extends java.lang.Object
 SourceFile: "SimpleClass.java"
 InnerClass:
  public #22= #4 of #19; //InnerClass=class SimpleClass$InnerClass of class SimpleClass
 minor version: 0
 major version: 0
 Constant pool:
const #1 = Method #5.#17; //  java/lang/Object."<init>":()V
const #2 = Field #4.#18; //  SimpleClass$InnerClass.this$0:LSimpleClass;
const #3 = Field #19.#20; //  SimpleClass.x:I
const #4 = class #21; //  SimpleClass$InnerClass
const #5 = class #24; //  Object
const #6 = Asciz this$0;
const #7 = Asciz LSimpleClass;;
const #8 = Asciz Synthetic;
const #9 = Asciz <init>;
const #10 = Asciz (LSimpleClass;)V;
const #11 = Asciz Code;
const #12 = Asciz LineNumberTable;
const #13 = Asciz method;
const #14 = Asciz ()V;
const #15 = Asciz SourceFile;
const #16 = Asciz SimpleClass.java;
const #17 = NameAndType #9:#14;//  "<init>":()V
const #18 = NameAndType #6:#7;//  this$0:LSimpleClass;
const #19 = class #25; //  SimpleClass
const #20 = NameAndType #26:#27;//  x:I
const #21 = Asciz SimpleClass$InnerClass;
const #22 = Asciz InnerClass;
const #23 = Asciz InnerClasses;
const #24 = Asciz java/lang/Object;
const #25 = Asciz SimpleClass;
const #26 = Asciz x;
const #27 = Asciz I;

{
public SimpleClass$InnerClass(SimpleClass);
 Code:
  Stack=2, Locals=2, Args_size=2
  0: aload_0
  1: invokespecial #1; //Method java/lang/Object."<init>":()V
  4: aload_0
  5: aload_1
  6: putfield #2; //Field this$0:LSimpleClass;
  9: return
 LineNumberTable:
  line 6: 0

public void method();
 Code:
  Stack=2, Locals=1, Args_size=1
  0: aload_0
  1: getfield #2; //Field this$0:LSimpleClass;
  4: iconst_0
  5: putfield #3; //Field SimpleClass.x:I
  8: return
 LineNumberTable:
  line 10: 0
  line 11: 8

}



Интересно тут то, что внутренний класс создается не через пустой (не принимающий аргументов) конструктор!
Такого конструктора у него нет вообще. Зато есть конструктор InnerClass(SimpleClass),
в который передается ссылка на инстанс класса SimpleClass, эта ссылка хранится в поле this$0.
Если добавить в InnerClass конструктор, принимающий аргументы, например public InnerClass(int a), он превратится в <init>:(LSimpleClass;I)V;


--------------------

PM   Вверх
polosatij
Дата 2.12.2004, 01:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1143
Регистрация: 22.2.2004
Где: Stuttgart<-> ;Karlsruhe, Germany

Репутация: 1
Всего: 8



Цитата(Domestic @ 27.11.2004, 08:09)
2: getfield #4; //Field i:I



Берем этот дубликат и вызываем на нем опкод getfield - т.е. ложим на стек поле i.

Код

5: iconst_1
6: iadd



еееееееех.. я всё никак не могу понять.. что обозначает пятая строчка.. что за единица после iconst?

документация: Push int constant.
а почему "1"?


--------------------
PM   Вверх
Domestic Cat
Дата 2.12.2004, 01:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Цитата(polosatij @ 1.12.2004, 16:18)
еееееееех.. я всё никак не могу понять.. что обозначает пятая строчка.. что за единица после iconst?

документация: Push int constant.
а почему "1"?


smile Вообще можно было бы и bipush 1, но тода это заняло бы 2 байта - один на bipush, второй на 1. Поскольку числа -1, 0, 1, 2, 3, 4, 5 в коде встречаются намного чаще, чем 100 или 1234, разработчики сделали соответствующий опкод iconst_<n>, который помещает n на стек, то есть , делает то же самое, что и bipush n, но занимает всего 1 байт.


--------------------

PM   Вверх
Domestic Cat
Дата 2.12.2004, 05:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Локальные и анонимные классы

Эти классы компилируются точно так же, как и внутренние : они получают дополнительный аргумент в конструктор - ссылку на внешний класс, однако эта ссылка хранится как final. Для примера рассмотрим код:
Код

public class Test
{
public void Test1()
{
                class A // локальный класс
                {
 
                 };
                 new A();
}

public void Test2()
{
                  new Thread() {};  // анонимный класс
}

}


Получаем 3 класс файла, из которых я приведу только байткод:
Код

{
public Test();
 Code:
  Stack=1, Locals=1, Args_size=1
// это "dummy" конструктор
  0: aload_0  
  1: invokespecial #1; //Method java/lang/Object."<init>":()V
  4: return
 LineNumberTable:
  line 1: 0

public void Test1();
 Code:
  Stack=3, Locals=1, Args_size=1
  0: new #2; //class Test$1A
  3: dup
  4: aload_0   // передаем локальному классу ссылку на внешний объект
  5: invokespecial #3; //Method Test$1A."<init>":(LTest;)V
  8: pop
  9: return
 LineNumberTable:
  line 9: 0
  line 10: 9

public void Test2();
 Code:
  Stack=3, Locals=1, Args_size=1
  0: new #4; //class Test$1
  3: dup
  4: aload_0    // передаем анонимному классу ссылку на внешний объект
  5: invokespecial #5; //Method Test$1."<init>":(LTest;)V
  8: pop
  9: return
 LineNumberTable:
  line 14: 0
  line 15: 9

}
Код

{
// локальный класс
final Test this$0;

Test$1A(Test);
 Code:
  Stack=2, Locals=2, Args_size=2
// конструктор сохраняет ссылку на родителя и вызывает конструктор класса Object
  0: aload_0
  1: aload_1
  2: putfield #1; //Field this$0:LTest;
  5: aload_0
  6: invokespecial #2; //Method java/lang/Object."<init>":()V
  9: return
 LineNumberTable:
  line 5: 0

}

Код

// анонимный класс
{
final Test this$0;

Test$1(Test);
 Code:
  Stack=2, Locals=2, Args_size=2
// конструктор сохраняет ссылку на родителя и вызывает конструктор класса Thread
  0: aload_0
  1: aload_1
  2: putfield #1; //Field this$0:LTest;
  5: aload_0
  6: invokespecial #2; //Method java/lang/Thread."<init>":()V
  9: return
 LineNumberTable:
  line 14: 0

}


Это сообщение отредактировал(а) Domestic Cat - 2.12.2004, 05:30


--------------------

PM   Вверх
Domestic Cat
Дата 5.12.2004, 07:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Java 1.5

Мне было интересно посмотреть ряд новых вещей, появившихся в Тигре, но к сожалению, ничего интересного тут нет (правда, это можно было предполагать, поскольку многое, те же новые циклы или автобоксинг, не несут ничего нового и просто сокращают работу программиста). Все "новые" конструкции компилируются в стандартный байткод.

Возьмем маленький пример
Код

import java.util.*;
public class Test
{
public void doTest()
{
 HashSet<Integer> set = new HashSet<Integer>(); // 1
 set.add(3); // 2
}

public void doCheck(Object... args) // 3
{}
}


Здесь 3 новых элемента - дженерикс(1), автобоксинг(2) и переменное количество аргументов, для краткости варарг, (3).
Получается из них вот что:
Код

// (1) (2)
public void doTest();
 Code:
  Stack=2, Locals=2, Args_size=1
  0: new #2; //class java/util/HashSet
  3: dup
  4: invokespecial #3; //Method java/util/HashSet."<init>":()V
  7: astore_1
  8: aload_1
  9: iconst_3
  10: invokestatic #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
  13: invokevirtual #5; //Method java/util/HashSet.add:(Ljava/lang/Object;)Z
  16: pop
  17: return

Автобоксинг "разавтобоксивается" в обычный valueOf, так что выигрыша в длине байткода нет (хотя есть выигрыш в длине кода, мизерный).
Код

public void doCheck(java.lang.Object[]);
 Code:
  Stack=0, Locals=2, Args_size=2
  0: return

Три точки превращаются в массив (трудно было догадаться) smile.


--------------------

PM   Вверх
Sardar
Дата 5.12.2004, 13:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 4
Всего: 317



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


--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
Domestic Cat
Дата 5.12.2004, 19:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Цитата(Sardar @ 5.12.2004, 04:53)
Интересно изменился ли формат .class файла, если я создал шаблонную коллекцию и не имея исходников подключаю класс, должен же как то компилятор узнать какой тип я задал в шаблоне.


Просто в constant pool добавляется запись обозначающая что класс шаблонный, типа
Код

const #12 = Asciz Ljava/util/HashSet<Ljava/lang/Float;>;;

Все остальное остается прежним.


--------------------

PM   Вверх
Се ля ви
Дата 18.1.2005, 16:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java/SOAрхитектор
****


Профиль
Группа: Модератор
Сообщений: 2016
Регистрация: 5.6.2004
Где: place without tim e and space

Репутация: 8
Всего: 127



Вопрос в продолжение темы - примерные алгоритмы работы обфускатора и ингибитора (того же JAD`а).

И кстати, есть ли бесплатные защитники исходников Java?


--------------------
  )
 (
[_])
проф. блог

Кролики думали, что занимаются любовью, а на самом деле их просто разводили...
PM MAIL WWW Skype GTalk   Вверх
seQira
Дата 8.2.2005, 10:07 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











хорошая статья
  Вверх
Domestic Cat
Дата 15.2.2005, 06:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Цитата
И кстати, есть ли бесплатные защитники исходников Java?


В смысле, бесплатные обфускаторы?
http://java-source.net/open-source/obfuscators

Цитата
Вопрос в продолжение темы - примерные алгоритмы работы обфускатора и ингибитора (того же JAD`а).


http://www-106.ibm.com/developerworks/java/library/j-obfus/
- хорошая статья


Цитата(seQira @ 8.2.2005, 01:07)
хорошая статья


Спасибо


--------------------

PM   Вверх
polosatij
Дата 4.5.2006, 00:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1143
Регистрация: 22.2.2004
Где: Stuttgart<-> ;Karlsruhe, Germany

Репутация: 1
Всего: 8



Цитата(Domestic Cat @  27.11.2004,  08:09 Найти цитируемый пост)
А вот для данного случая, как оказалось, выигрыш дает синхронизированный метод. 



 smile 

хм.. почему? ведь количество байтов не означает скорость! откуда тебе известно, что в данном случае делает JVM с 


Цитата(Domestic Cat @  27.11.2004,  07:24 Найти цитируемый пост)
public int doTest()



 smile 
 


--------------------
PM   Вверх
djGri
Дата 13.6.2006, 11:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 77
Регистрация: 21.2.2005

Репутация: 1
Всего: 3



 smile Насчет Inner classes:
Если объявить как private, то после декомпиляции получится package.
Если объявить как protected, то после декомпиляции получится public.
T.e:
private, package -> package
protected,public  -> public
Как узнать, что Inner classes был объявлен как private/protected ?  smile 
BCEL тоже видит такие классы как написано выше.
 
PM MAIL   Вверх
angus
Дата 11.11.2006, 04:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 13
Регистрация: 11.11.2006
Где: Украина, г.Ужгоро д

Репутация: нет
Всего: нет



пробовал работать с генерированнием байт-кода для java - прикольно...
но чесно говоря мне еще невстречались задачи  для которых нужно применять геннерирование кода (может все еще
впереди), даже не знаю где б можно его так заюзать что чуствувалась сила байт-генерирования 
PM MAIL ICQ YIM   Вверх
batigoal
Дата 23.4.2007, 17:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Нелетучий Мыш
****


Профиль
Группа: Участник Клуба
Сообщений: 6423
Регистрация: 28.12.2004
Где: Санктъ-Петербургъ

Репутация: 24
Всего: 151



Тема откреплена.


--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа" (Р. Шекли)
ЖоржЖЖ
PM WWW   Вверх
Vitaly333
Дата 8.11.2010, 19:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 220
Регистрация: 6.11.2006
Где: Volgograd

Репутация: 2
Всего: 2



А как дизассемблированный байт код собрать обратно в тот который  выполняет JVM ?

Это сообщение отредактировал(а) Vitaly333 - 9.11.2010, 00:32
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.2649 ]   [ Использовано запросов: 24 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.