Hlavní navigace

Pohled pod kapotu JVM - práce s parametry a lokálními proměnnými metod přes rozhraní JVM TI

12. 3. 2013
Doba čtení: 33 minut

Sdílet

Dnes si společně řekneme, jakým způsobem lze přes rozhraní JVM TI získat informace o parametrech a lokálních proměnných statických i nestatických metod. Tyto informace je možné využít například ve chvíli, kdy je v nějaké metodě vstoupeno na breakpoint a je nutné prozkoumat aktuální stav procesu.

Obsah

1. Pohled pod kapotu JVM – práce s parametry a lokálními proměnnými metod přes rozhraní JVM TI

2. JVM TI funkce GetLocalVariableTable() a struktura jvmtiLocalVariableEntry

3. Nastavení požadovaných vlastností JVM TI agenta

4. Tvar callback funkce callback_on_class_prepare()

5. Uživatelská funkce print_local_variables_for_a­ll_methods()

6. Uživatelská funkce print_method_name_and_signature()

7. Uživatelská funkce print_local_variables()

8. Uživatelská funkce print_local_variable_info()

9. Uživatelská funkce print_signature_of_local_variable()

10. Testovací třída použitá společně s demonstračním JVM TI agentem

11. Spuštění 34. demonstračního JVM TI agenta

12. Porovnání výstupu JVM TI agenta s výpisem získaným přes nástroj javap

13. Zdrojové kódy 34.demonstračního agenta i k němu příslušných testovacích příkladů a skriptů

14. Literatura a odkazy na Internetu

1. Pohled pod kapotu JVM – práce s parametry a lokálními proměnnými metod přes rozhraní JVM TI

V předchozích třech částech [65] [66] a [67] seriálu o programovacím jazyku Java i o virtuálním stroji Javy jsme si řekli, jakým způsobem je možné přes rozhraní JVM TI pracovat s breakpointy. Víme již, jak se breakpointy nastavují i jak je možné v příslušné callback funkci reagovat na událost vstupu nějakého vlákna na breakpoint. Můžeme například velmi snadno získat obsah zásobníkových rámců, tj. vlastně část historie života daného vlákna. Kromě využití breakpointů je taktéž poměrně snadné sledovat čtení i zápis do vybraného atributu třídy či atributu objektu, což je problematika, které jsme se podrobně věnovali v částech 63 a 64. Prozatím nám však chybí ještě schopnost přečíst informace o typech a hodnotách parametrů metod i lokálních proměnných těchto metod.

Již v předchozí části tohoto seriálu, v níž jsme se věnovali popisu způsobu předčasného výskoku z metod, jsme si řekli, že všechny parametry metod i všechny lokální proměnné dané metody jsou uloženy v zásobníkovém rámci (stack frame) vytvořeném ve chvíli, kdy je metoda zavolána. Pokud se jedná o nestatickou metodu, je mezi parametry počítán i „neviditelný“ parametr this. K oběma typům dat, tj. jak k parametrům, tak i k lokálním proměnným, se v bajtkódu virtuálního stroje Javy přistupuje s využitím indexu: první údaj má index 0, další údaj má index 1 atd. Z toho, že se uvnitř metody vlastně nedělá žádný rozdíl mezi jejími parametry a lokálními proměnnými vyplývá, že i hodnotu parametrů lze uvnitř metody měnit, ovšem jedná se pouze o lokální změnu viditelnou uvnitř metody. Na zásobníkový rámec je uložena buď kopie hodnoty primitivního datového typu nebo kopie reference (což znamená, že v tomto případě ve skutečnosti LZE měnit stav objektu voláním jeho metod či přímým nastavováním jeho atributů – o defenzivní kopii objektu se musí v případě potřeby postarat sám programátor).

2. JVM TI funkce GetLocalVariableTable() a struktura jvmtiLocalVariableEntry

V rozhraní JVM TI lze získat informace o parametrech i o lokálních proměnných zvolené metody s využitím funkce nazvané GetLocalVariableTable(). Této funkci se musí předat jednoznačný identifikátor metody, který je nastaven ve chvíli, kdy je do virtuálního stroje Javy načítána třída, v níž je metoda deklarována. Logicky z toho vyplývá, že nejjednodušeji lze získat veškeré potřebné informace o metodě v callback funkci zavolané při načítání třídy. JVM TI funkce GetLocalVariableTable() má následující hlavičku:

jvmtiError GetLocalVariableTable(
            jvmtiEnv* env,
            jmethodID method,
            jint*     entry_count_ptr,
            jvmtiLocalVariableEntry** table_ptr)

Význam jednotlivých parametrů této funkce je vypsán v tabulce:

# Typ Jméno parametru Popis
1 jvmtiEnv* env JVM TI prostředí agenta (je předáváno do většiny funkcí nabízených rozhraním JVM TI)
2 jmethodID method identifikátor metody, pro níž se zjišťují informace
3 jint* entry_count_ptr celkový počet parametrů a lokálních proměnných
4 jvmtiLocalVariableEntry** table_ptr tabulka obsahující informace o parametrech i o lokálních proměnných

U popisované JVM TI funkce je nutné kontrolovat její návratovou hodnotu, jelikož rozhraní JVM TI dokáže získat potřebné informace o zvolené metodě pouze v tom případě, kdy se v bajtkódu nachází všechny potřebné ladicí informace. Třídu/třídy je z tohoto důvodu nutné překládat s přepínačem -g. Význam prvních dvou parametrů funkce GetLocalVariableTable() je zřejmý. Třetí parametr slouží pro zpětné předání počtu parametrů a lokálních proměnných – současně se jedná o počet záznamů v poli naplněném přes poslední (čtvrtý) parametr. Toto pole obsahuje struktury jvmtiLocalVariableEntry:

typedef struct {
    jlocation start_location;
    jint      length;
    char*     name;
    char*     signature;
    char*     generic_signature;
    jint      slot;
} jvmtiLocalVariableEntry;

Opět si popíšeme význam jednotlivých prvků této struktury:

# Typ Jméno prvku Popis
1 jlocation start_location pozice v bajtkódu (vnitřní příkazový blok), od níž je lokální proměnná platná
2 jint length velikost příkazového bloku, v němž je lokální proměnná platná
3 char* name jméno proměnné
4 char* signature úplná signatura proměnné (datový typ)
5 char* generic_signature signatura generického typu v případě, že je proměnná typu Typ1<Typ2> apod.
6 jint slot slot lokální proměnné (význam si vysvětlíme příště)

3. Nastavení požadovaných vlastností JVM TI agenta

V následujícím textu si popíšeme důležité funkce, z nichž se skládá třicátý čtvrtý demonstrační JVM TI agent. Zdrojový kód tohoto agenta je z velké části postaven na zdrojovém kódu třicátého třetího JVM TI agenta, s jehož popisem jsme se seznámili již minule. Jedna ze změn mezi oběma agenty je způsobena tím, že u nového agenta vyžadujeme jiné vlastnosti než u agenta popsaného minule. 33. agent totiž potřeboval pracovat s breakpointy a taktéž jsme vyžadovali podporu pro volání funkcí typu ForceEarlyReturn*(). Původně bylo tedy nutné si od virtuálního stroje Javy vyžádat využití hned tří speciálních funkcí JVM TI:

/*
 * Nastaveni pozadovanych schopnosti agenta.
 */
jvmtiError set_capabilities(jvmtiEnv *jvmti)
{
    jvmtiCapabilities capabilities;
    jvmtiError error_code;
 
    memset(&capabilities, 0, sizeof(jvmtiCapabilities));
 
    /* vyuzivame pouze tri specialni schopnosti agenta */
    capabilities.can_get_line_numbers = 1;
    capabilities.can_generate_breakpoint_events = 1;
    capabilities.can_force_early_return = 1;
 
    error_code = (*jvmti)->AddCapabilities(jvmti, &capabilities);
    check_jvmti_error(jvmti, error_code, "Unable to get necessary JVMTI capabilities.");
    return error_code;
}

V dnes popisovaném agentovi sice není zapotřebí nastavovat breakpointy ani využívat funkce typu ForceEarlyReturn*(), ovšem navíc je nutné přistupovat k lokálním proměnným. Z tohoto důvodu bude nová varianta uživatelské funkce set_capabilities() vypadat poněkud odlišně:

/*
 * Nastaveni pozadovanych schopnosti agenta.
 */
jvmtiError set_capabilities(jvmtiEnv *jvmti)
{
    jvmtiCapabilities capabilities;
    jvmtiError error_code;
 
    memset(&capabilities, 0, sizeof(jvmtiCapabilities));
 
    /* vyuzivame pouze dve specialni schopnosti agenta */
    capabilities.can_get_line_numbers = 1;
    capabilities.can_access_local_variables = 1;
 
    error_code = (*jvmti)->AddCapabilities(jvmti, &capabilities);
    check_jvmti_error(jvmti, error_code, "Unable to get necessary JVMTI capabilities.");
    return error_code;
}

4. Tvar callback funkce callback_on_class_prepare()

V demonstračním JVM TI agentovi je zaregistrována callback funkce nazvaná callback_on_class_prepare(), která je, podobně jako i v několika agentech předchozích, zavolána ve chvíli, kdy je do virtuálního stroje Javy načítána nějaká třída a kdy je zpracován její bajtkód. V této callback funkci nejprve kontrolujeme, zda je jméno načítané třídy totožné s řetězcem „Test34“. Pokud tomu tak skutečně je, znamená to, že se aktuálně načítá právě testovací třída Test34 a můžeme tedy vypsat informace o všech jejích metodách. Výpis se provede v uživatelské funkci print_local_variables_for_all_methods popsané v páté kapitole:

/*
 * Callback funkce zavolana ve chvili, kdy je trida ve virtualnim stroji ve stavu,
 * kdy ji lze normalne pouzivat.
 */
static void JNICALL callback_on_class_prepare(
        jvmtiEnv *jvmti_env,
        JNIEnv   *jni_env,
        jthread   thread,
        jclass    class)
{
    jvmtiError error;
    char *class_name_ptr;
    char *updated_class_name_ptr;
 
    enter_critical_section(jvmti_env);
 
    /* ziskat jmeno tridy */
    error = (*jvmti_env)->GetClassSignature(jvmti_env, class, &class_name_ptr, NULL);
    check_jvmti_error(jvmti_env, error, "get class signature");
    if (class_name_ptr == NULL)
    {
        puts("Error: class has no signature");
    }
 
    /* upravit jmeno tridy */
    updated_class_name_ptr = update_class_name(class_name_ptr, ';');
 
    /* pokud jsme nasli to pravou tridu */
    if (strcmp(updated_class_name_ptr, TEST_CLASS_NAME) == 0)
    {
        puts(AGENT_NAME " Class "TEST_CLASS_NAME" prepared, processing all methods in this class");
        print_local_variables_for_all_methods(jvmti_env, class);
    }
 
    /* dealokace pameti po GetClassSignature() */
    error = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *)class_name_ptr);
    check_jvmti_error(jvmti_env, error, "deallocate class name");
    exit_critical_section(jvmti_env);
}

5. Uživatelská funkce print_local_variables_for_a­ll_methods()

Úkolem uživatelské funkce print_local_variables_for_a­ll_methods(), která je volaná z callback funkce callback_on_class_prepare(), je vypsat jméno a signaturu každé metody deklarované v testovací třídě Test34. Posléze se pro každou metodu vypíšou informace o jejích parametrech a lokálních proměnných. V popisované funkci se nejprve s využitím JVM TI funkce GetClassMethods() získá pole všech metod třídy a posléze se tímto polem prochází podobným způsobem, jaký již známe z předchozích částí tohoto seriálu. Na konci samozřejmě nesmíme zapomenout na uvolnění pole s metodami z operační paměti, což zajistí JVM TI funkce Deallocate:

/*
 * Vypise lokalni promenne vsech metod ve vybrane tride.
 */
void print_local_variables_for_all_methods(jvmtiEnv *jvmti_env, jclass class)
{
    jvmtiError  error;
    int         method_count;
    jmethodID  *methods_array;
 
    /* precist vsechny metody tridy */
    error = (*jvmti_env)->GetClassMethods(jvmti_env, class, &method_count, &methods_array);
    check_jvmti_error(jvmti_env, error, "get class methods");
 
    /* pole metod bylo inicializovano */
    if (error == JVMTI_ERROR_NONE)
    {
        int i;
        /* projit vsemi metodami a vypsat jejich lokalni promenne */
        for (i = 0; i < method_count; i++)
        {
            jmethodID method = methods_array[i];
            print_method_name_and_signature(jvmti_env, method);
            print_local_variables(jvmti_env, method);
        }
    }
 
    /* dealokace pole ziskaneho pres GetClassFields() */
    error = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char*)methods_array);
    check_jvmti_error(jvmti_env, error, "deallocate class fields array");
}

6. Uživatelská funkce print_method_name_and_signature()

Funkce print_method_name_and_signature() je velmi jednoduchá, protože v ní pouze potřebujeme vypsat jméno a signaturu metody, jejíž identifikátor je do této funkce předán jako parametr. Žádnou novou funkcionalitu rozhraní JVM TI zde nevyužíváme. Funkcí GetMethodName() se získá jak jméno metody, tak i její signatura, z níž lze odvodit počet a typ parametrů funkce i její návratovou hodnotu. V demonstračním JVM TI agentovi se oba řetězce pouze vypíšou na standardní výstup a posléze se uvolní z operační paměti s využitím funkce Deallocate():

/*
 * Vypis jmena a signatury zvolene metody
 */
void print_method_name_and_signature(jvmtiEnv *jvmti_env, jmethodID method)
{
    jvmtiError  error;
    char *method_name;
    char *method_signature;
 
    /* precist jmeno metody */
    error = (*jvmti_env)->GetMethodName(jvmti_env, method, &method_name, &method_signature, NULL);
    check_jvmti_error(jvmti_env, error, "get method name");
 
    /* tisk jmena a signatury metody */
    printf(AGENT_NAME"\n");
    printf(AGENT_NAME"     method %s with signature %s\n", method_name, method_signature);
 
    /* dealokace retezcu ziskanych pres GetMethodName() */
    error = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char*)method_name);
    check_jvmti_error(jvmti_env, error, "deallocate method name");
 
    /* dealokace retezcu ziskanych pres GetMethodName() */
    error = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char*)method_signature);
    check_jvmti_error(jvmti_env, error, "deallocate method signature");
}

7. Uživatelská funkce print_local_variables()

Uživatelská funkce print_local_variables() se nejprve s využitím JVM TI funkce nazvané GetLocalVariableTable() pokusí získat pole obsahující informace o všech parametrech i o lokálních proměnných metody, jejíž identifikátor je do této funkce předán v parametru method. Jak jsme si již řekli v úvodu tohoto článku, je bezpodmínečně nutné otestovat návratovou hodnotu funkce GetLocalVariableTable(), protože ta může korektně pracovat jen v tom případě, že byl bajtkód zpracovávané třídy přeložen s volbou -g, protože jen v tom případě jsou do bajtkódu vloženy potřebné ladicí informace o lokálních proměnných. Volbu -g lze v případě potřeby omezit na pouhé generování určitého typu informací s použitím -g:vars, -g:lines či -g:source (popř. kombinací těchto možností). Vraťme se však k funkci print_local_variables(). Pokud se přečtení informací o lokálních proměnných zdaří, začne průchod vráceným polem, přičemž se v každé iteraci zavolá další uživatelská funkce nazvaná print_local_variable_info():

/*
 * Vypis lokalnich promennych zvolene metody
 */
void print_local_variables(jvmtiEnv *jvmti_env, jmethodID method)
{
    jvmtiError  error;
    jint   variables_count;
    jvmtiLocalVariableEntry *local_variable_table;
 
    /* nacteni tabulky lokalnich promennych */
    error = (*jvmti_env)->GetLocalVariableTable(jvmti_env, method, &variables_count, &local_variable_table);
 
    /* pokud se nacteni podarilo */
    if (error == JVMTI_ERROR_NONE)
    {
        int i;
        printf(AGENT_NAME"         number of local variables %d:\n", (int)variables_count);
        /* projit tabulkou a vypsat vsechny udaje o lokalni promenne */
        for (i = 0; i < variables_count; i++)
        {
            print_local_variable_info(i, local_variable_table[i]);
        }
    }
    else
    {
        printf(AGENT_NAME"         can not read local variable table");
    }
 
    /* dealokace tabulky lokalnich promennych */
    error = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char*)local_variable_table);
    check_jvmti_error(jvmti_env, error, "deallocate local variable table");
}

8. Uživatelská funkce print_local_variable_info()

Předposlední funkcí, jejímž podrobnějším popisem se dnes budeme zabývat, je uživatelská funkce nazvaná print_local_variable_info(). Jak již víme z předchozího textu, je tato funkce zavolána pro každou metodu a pro každý parametr/lokální proměnnou testovací třídy Test34. Do funkce print_local_variable_info() se předávají pouze dva údaje – index parametru či lokální proměnné a struktura typu jvmtiLocalVariableEntry, jejíž popis byl uveden ve druhé kapitole. U každého parametru či lokální proměnné se nejprve vypíše jeho index (což je triviální) a taktéž jméno, které je získáno z prvku var_info.name. Jméno je kódováno v UTF-8, i když ve většině rozumných javovských aplikací lze předpokládat pouze použití ASCII znaků. Ve druhé části popisované funkce se vypíše signatura parametru či lokální proměnné, z níž lze jednoznačně zjistit datový typ, a to jak v případě, že se jedná o proměnnou primitivního typu, pole či o objekt (referenci).

Posléze se vypíše i signatura generického datového typu. Tato signatura je použita v případě, že je parametr či lokální proměnná metody deklarována například jako List<String>. Tato podrobnější informace o typu není součástí signatury metody (ta obsahuje pouze plné jméno třídy/rozhraní, tedy java.util.List), ovšem lze ji získat právě z těchto doplňujících metadat:

/*
 * Vypis informaci o jedne lokalni promenne
 */
void print_local_variable_info(int i, jvmtiLocalVariableEntry var_info)
{
    /* vypis poradi lokalni promenne a jmena promenne */
    printf(AGENT_NAME"         %2d  %-20s  ", i, var_info.name);
 
    /* vypis upravene signatury promenne */
    print_signature_of_local_variable(var_info.signature);
    putchar('\t');
 
    /* vypis upravene signatury generickeho typu (pokud existuje) */
    print_signature_of_local_variable(var_info.generic_signature);
    putchar('\n');
}

9. Uživatelská funkce print_signature_of_local_variable()

Signaturu parametru/lokální proměnné i signaturu generického datového typu lze buď vypsat přímo ve formátu vráceném rozhraním JVM TI, popř. je možné provést úpravu vráceného řetězce do tvaru, který je lépe čitelný. Právě tato úprava formátu se provádí v poslední dnes popisované uživatelské funkci print_signature_of_local_variable(). Ta buď jednoduše zobrazí předaný řetězec, popř. provede jeho přeformátování (žádné nové informace se však do vypisovaného textu pochopitelně nedodají). Chování této funkce je ovlivněno symbolickou konstantou UPDATE_VAR_NAMES. Samotná konverze je vlastně velmi jednoduchá, protože primitivní datový typ je zakódován jedním znakem [BSIJCFDZ], každá dimenze pole je představována znakem „[“ a jméno třídy začíná znakem „L“. Ve jméně třídy se vyskytují lomítka namísto teček a celé jméno končí středníkem (ten je při výpisu odstraněn). Poněkud složitější je situace v případě generických typů, kde je nutné při výpisu vkládat mezi jména tříd čárky:

/*
 * Vypis upravene signatury lokalni promenne.
 */
void print_signature_of_local_variable(char *signature)
{
#if (UPDATE_VAR_NAMES==1)
    /* nastaveno, pokud je promenna instanci nejake tridy */
    /* a ne zakladni typ ci pole zakladniho typu */
    int is_a_class = 0;
 
    /* nastaveno uvnitr zavorek < a > */
    int inside_generic = 0;
 
    char *c;
    /* signatura nemusi byt vzdy znama */
    if (signature == NULL)
    {
        return;
    }
 
    /* projit celym retezcem se signaturou lokalni promenne */
    for (c = signature; *c != 0; c++)
    {
        /* za znakem 'L' se nachazi plne kvalifikovane jmeno tridy */
        if (is_a_class)
        {
            switch (*c)
            {
                case '/':
                    putchar('.');
                    break;
                case ';':
                    /* oddeleni jmen trid uvnitr sekvence < ... > */
                    if (inside_generic && *(c+1)!='>')
                    {
                        putchar(',');
                    }
                    is_a_class = 0;
                    break;
                case '<':
                    is_a_class = 0;
                    inside_generic = 1;
                    putchar(*c);
                    break;
                default:
                    putchar(*c);
                    break;
            }
        }
        else
        {
            switch (*c)
            {
                case '[': /* znak oznacujici jednu dimenzi pole */
                    printf("array of ");
                    break;
                case 'B':
                    printf("byte");
                    break;
                case 'S':
                    printf("short");
                    break;
                case 'I':
                    printf("int");
                    break;
                case 'J':
                    printf("long");
                    break;
                case 'C':
                    printf("char");
                    break;
                case 'F':
                    printf("float");
                    break;
                case 'D':
                    printf("double");
                    break;
                case 'Z':
                    printf("boolean");
                    break;
                case 'L': /* zacatek plne kvalifikovaneho jmena tridy */
                    is_a_class=1;
                    break;
                default:
                    putchar(*c);
                    break;
            }
        }
    }
    printf("  ");
#else
    printf("%-20s", signature);
#endif
}

10. Testovací třída použitá společně s demonstračním JVM TI agentem

Abychom si funkci výše popsaného demonstračního JVM TI agenta otestovali, byla vytvořena javovská třída nazvaná Test34, která obsahuje celkem dvacet metod, které lze rozdělit do čtyř skupin:

  1. Konstruktor představovaný ve výsledném bajtkódu metodou <init>
  2. Statická metoda main()
  3. Nestatické metody nazvané method1()method9()
  4. Statické metody nazvané static_method1()static_method9()

Jednotlivé metody se od sebe liší počtem svých parametrů i počtem a typem lokálních proměnných.

Následuje výpis zdrojového kódu testovací třídy Test34:

import java.awt.Color;
import java.util.*;
 
/**
  * Testovaci trida pouzita pro test tricateho
  * ctvrteho demonstracniho JVM TI agenta.
  *
  * Trida obsahuje nekolik metod s ruznym poctem
  * a typy lokalnich promennych.
  */
public class Test34 {
 
    private void method1() {
    }
 
    private void method2() {
        int x = 0;
    }
 
    private void method3() {
        int x = 1;
        int y = 2;
    }
 
    private void method4() {
        byte    byte_variable = 1;
        short   short_variable = 2;
        int     int_variable = 3;
        long    long_variable = 4;
    }
 
    private void method5() {
        char    char_variable = 'a';
        float   float_variable = 1/2f;
        double  double_variable = 1/2.0;
        boolean boolean_variable = true;
    }
 
    private void method6() {
        int[]   int_array = null;
        float[] float_array = null;
        int[][] int_matrix = null;
    }
 
    private void method7() {
        String  str = null;
        Color   color = null;
        Color[] colors = null;
    }
 
    private void method8() {
        List<String>       list = null;
        Set<Integer>       set = null;
        Map<Float, String> map = null;
        Queue<Color>       queue = null;
        Deque<String>      double_ended_queue = null;
    }
 
    private void method9(int x, float y, boolean z) {
        List<String>       list = null;
        Set<Integer>       set = null;
        Map<Float, String> map = null;
        Queue<Color>       queue = null;
        Deque<String>      double_ended_queue = null;
    }
 
    private static void static_method1() {
    }
 
    private static void static_method2() {
        int x = 0;
    }
 
    private static void static_method3() {
        int x = 1;
        int y = 2;
    }
 
    private static void static_method4() {
        byte    byte_variable = 1;
        short   short_variable = 2;
        int     int_variable = 3;
        long    long_variable = 4;
    }
 
    private static void static_method5() {
        char    char_variable = 'a';
        float   float_variable = 1/2f;
        double  double_variable = 1/2.0;
        boolean boolean_variable = true;
    }
 
    private static void static_method6() {
        int[]   int_array = null;
        float[] float_array = null;
        int[][] int_matrix = null;
    }
 
    private static void static_method7() {
        String  str = null;
        Color   color = null;
        Color[] colors = null;
    }
 
    private static void static_method8() {
        List<String>       list = null;
        Set<Integer>       set = null;
        Map<Float, String> map = null;
        Queue<Color>       queue = null;
        Deque<String>      double_ended_queue = null;
    }
 
    private static void static_method9(int x, float y, boolean z) {
        List<String>       list = null;
        Set<Integer>       set = null;
        Map<Float, String> map = null;
        Queue<Color>       queue = null;
        Deque<String>      double_ended_queue = null;
    }
 
    /**
      * Spusteni testu.
      */
    public static void main(String[] args) {
    }
 
}

Nesmíme zapomenout na to, že se tato testovací třída musí překládat s přepínačem -g, aby došlo k uložení všech důležitých ladicích informací do výsledného bajtkódu:

javac -g Test34.java

11. Spuštění 34. demonstračního JVM TI agenta

Po překladu třicátého čtvrtého demonstračního JVM TI agenta je již možné si vyzkoušet jeho spuštění. Pokud je při překladu nastavena symbolická konstanta UPDATE_VAR_NAMES na nulovou hodnotu, vypíše agent po své inicializaci a spuštění následující informace o metodách testovací třídy Test34. Za povšimnutí stojí především rozdíl mezi statickou a nestatickou variantou téže metody (method1 vs static_method1 apod.):

Agent34: Agent_OnLoad
Agent34: JVM TI version is correct
Agent34: Got VM init event
Agent34: Class Test34; prepared, processing all methods in this class
Agent34:
Agent34:     method <init> with signature ()V
Agent34:         number of local variables 1:
Agent34:          0  this                  LTest34;             (null)
Agent34:
Agent34:     method main with signature ([Ljava/lang/String;)V
Agent34:         number of local variables 1:
Agent34:          0  args                  [Ljava/lang/String;  (null)
Agent34:
Agent34:     method method1 with signature ()V
Agent34:         number of local variables 1:
Agent34:          0  this                  LTest34;             (null)
Agent34:
Agent34:     method method2 with signature ()V
Agent34:         number of local variables 2:
Agent34:          0  this                  LTest34;             (null)
Agent34:          1  x                     I                    (null)
Agent34:
Agent34:     method method3 with signature ()V
Agent34:         number of local variables 3:
Agent34:          0  this                  LTest34;             (null)
Agent34:          1  x                     I                    (null)
Agent34:          2  y                     I                    (null)
Agent34:
Agent34:     method method4 with signature ()V
Agent34:         number of local variables 5:
Agent34:          0  this                  LTest34;             (null)
Agent34:          1  byte_variable         B                    (null)
Agent34:          2  short_variable        S                    (null)
Agent34:          3  int_variable          I                    (null)
Agent34:          4  long_variable         J                    (null)
Agent34:
Agent34:     method method5 with signature ()V
Agent34:         number of local variables 5:
Agent34:          0  this                  LTest34;             (null)
Agent34:          1  char_variable         C                    (null)
Agent34:          2  float_variable        F                    (null)
Agent34:          3  double_variable       D                    (null)
Agent34:          4  boolean_variable      Z                    (null)
Agent34:
Agent34:     method method6 with signature ()V
Agent34:         number of local variables 4:
Agent34:          0  this                  LTest34;             (null)
Agent34:          1  int_array             [I                   (null)
Agent34:          2  float_array           [F                   (null)
Agent34:          3  int_matrix            [[I                  (null)
Agent34:
Agent34:     method method7 with signature ()V
Agent34:         number of local variables 4:
Agent34:          0  this                  LTest34;             (null)
Agent34:          1  str                   Ljava/lang/String;   (null)
Agent34:          2  color                 Ljava/awt/Color;     (null)
Agent34:          3  colors                [Ljava/awt/Color;    (null)
Agent34:
Agent34:     method method8 with signature ()V
Agent34:         number of local variables 6:
Agent34:          0  this                  LTest34;             (null)
Agent34:          1  list                  Ljava/util/List;     Ljava/util/List<Ljava/lang/String;>;
Agent34:          2  set                   Ljava/util/Set;      Ljava/util/Set<Ljava/lang/Integer;>;
Agent34:          3  map                   Ljava/util/Map;      Ljava/util/Map<Ljava/lang/Float;Ljava/lang/String;>;
Agent34:          4  queue                 Ljava/util/Queue;    Ljava/util/Queue<Ljava/awt/Color;>;
Agent34:          5  double_ended_queue    Ljava/util/Deque;    Ljava/util/Deque<Ljava/lang/String;>;
Agent34:
Agent34:     method method9 with signature (IFZ)V
Agent34:         number of local variables 9:
Agent34:          0  this                  LTest34;             (null)
Agent34:          1  x                     I                    (null)
Agent34:          2  y                     F                    (null)
Agent34:          3  z                     Z                    (null)
Agent34:          4  list                  Ljava/util/List;     Ljava/util/List<Ljava/lang/String;>;
Agent34:          5  set                   Ljava/util/Set;      Ljava/util/Set<Ljava/lang/Integer;>;
Agent34:          6  map                   Ljava/util/Map;      Ljava/util/Map<Ljava/lang/Float;Ljava/lang/String;>;
Agent34:          7  queue                 Ljava/util/Queue;    Ljava/util/Queue<Ljava/awt/Color;>;
Agent34:          8  double_ended_queue    Ljava/util/Deque;    Ljava/util/Deque<Ljava/lang/String;>;
Agent34:
Agent34:     method static_method1 with signature ()V
Agent34:         number of local variables 0:
Agent34:
Agent34:     method static_method2 with signature ()V
Agent34:         number of local variables 1:
Agent34:          0  x                     I                    (null)
Agent34:
Agent34:     method static_method3 with signature ()V
Agent34:         number of local variables 2:
Agent34:          0  x                     I                    (null)
Agent34:          1  y                     I                    (null)
Agent34:
Agent34:     method static_method4 with signature ()V
Agent34:         number of local variables 4:
Agent34:          0  byte_variable         B                    (null)
Agent34:          1  short_variable        S                    (null)
Agent34:          2  int_variable          I                    (null)
Agent34:          3  long_variable         J                    (null)
Agent34:
Agent34:     method static_method5 with signature ()V
Agent34:         number of local variables 4:
Agent34:          0  char_variable         C                    (null)
Agent34:          1  float_variable        F                    (null)
Agent34:          2  double_variable       D                    (null)
Agent34:          3  boolean_variable      Z                    (null)
Agent34:
Agent34:     method static_method6 with signature ()V
Agent34:         number of local variables 3:
Agent34:          0  int_array             [I                   (null)
Agent34:          1  float_array           [F                   (null)
Agent34:          2  int_matrix            [[I                  (null)
Agent34:
Agent34:     method static_method7 with signature ()V
Agent34:         number of local variables 3:
Agent34:          0  str                   Ljava/lang/String;   (null)
Agent34:          1  color                 Ljava/awt/Color;     (null)
Agent34:          2  colors                [Ljava/awt/Color;    (null)
Agent34:
Agent34:     method static_method8 with signature ()V
Agent34:         number of local variables 5:
Agent34:          0  list                  Ljava/util/List;     Ljava/util/List<Ljava/lang/String;>;
Agent34:          1  set                   Ljava/util/Set;      Ljava/util/Set<Ljava/lang/Integer;>;
Agent34:          2  map                   Ljava/util/Map;      Ljava/util/Map<Ljava/lang/Float;Ljava/lang/String;>;
Agent34:          3  queue                 Ljava/util/Queue;    Ljava/util/Queue<Ljava/awt/Color;>;
Agent34:          4  double_ended_queue    Ljava/util/Deque;    Ljava/util/Deque<Ljava/lang/String;>;
Agent34:
Agent34:     method static_method9 with signature (IFZ)V
Agent34:         number of local variables 8:
Agent34:          0  x                     I                    (null)
Agent34:          1  y                     F                    (null)
Agent34:          2  z                     Z                    (null)
Agent34:          3  list                  Ljava/util/List;     Ljava/util/List<Ljava/lang/String;>;
Agent34:          4  set                   Ljava/util/Set;      Ljava/util/Set<Ljava/lang/Integer;>;
Agent34:          5  map                   Ljava/util/Map;      Ljava/util/Map<Ljava/lang/Float;Ljava/lang/String;>;
Agent34:          6  queue                 Ljava/util/Queue;    Ljava/util/Queue<Ljava/awt/Color;>;
Agent34:          7  double_ended_queue    Ljava/util/Deque;    Ljava/util/Deque<Ljava/lang/String;>;
Agent34: Got VM Death event
Agent34: Agent_OnUnload

V případě, že naopak nastavíme symbolickou konstantu UPDATE_VAR_NAMES na hodnotu 1, dojde při výpisu parametrů metod i jejich lokálních proměnných k úpravě typu proměnné i případné úpravě generického typu, takže je výstup mnohem čitelnější:

Agent34: Agent_OnLoad
Agent34: JVM TI version is correct
Agent34: Got VM init event
Agent34: Class Test34; prepared, processing all methods in this class
Agent34:
Agent34:     method <init> with signature ()V
Agent34:         number of local variables 1:
Agent34:          0  this                  Test34
Agent34:
Agent34:     method main with signature ([Ljava/lang/String;)V
Agent34:         number of local variables 1:
Agent34:          0  args                  array of java.lang.String
Agent34:
Agent34:     method method1 with signature ()V
Agent34:         number of local variables 1:
Agent34:          0  this                  Test34
Agent34:
Agent34:     method method2 with signature ()V
Agent34:         number of local variables 2:
Agent34:          0  this                  Test34
Agent34:          1  x                     int
Agent34:
Agent34:     method method3 with signature ()V
Agent34:         number of local variables 3:
Agent34:          0  this                  Test34
Agent34:          1  x                     int
Agent34:          2  y                     int
Agent34:
Agent34:     method method4 with signature ()V
Agent34:         number of local variables 5:
Agent34:          0  this                  Test34
Agent34:          1  byte_variable         byte
Agent34:          2  short_variable        short
Agent34:          3  int_variable          int
Agent34:          4  long_variable         long
Agent34:
Agent34:     method method5 with signature ()V
Agent34:         number of local variables 5:
Agent34:          0  this                  Test34
Agent34:          1  char_variable         char
Agent34:          2  float_variable        float
Agent34:          3  double_variable       double
Agent34:          4  boolean_variable      boolean
Agent34:
Agent34:     method method6 with signature ()V
Agent34:         number of local variables 4:
Agent34:          0  this                  Test34
Agent34:          1  int_array             array of int
Agent34:          2  float_array           array of float
Agent34:          3  int_matrix            array of array of int
Agent34:
Agent34:     method method7 with signature ()V
Agent34:         number of local variables 4:
Agent34:          0  this                  Test34
Agent34:          1  str                   java.lang.String
Agent34:          2  color                 java.awt.Color
Agent34:          3  colors                array of java.awt.Color
Agent34:
Agent34:     method method8 with signature ()V
Agent34:         number of local variables 6:
Agent34:          0  this                  Test34
Agent34:          1  list                  java.util.List       java.util.List<java.lang.String>;
Agent34:          2  set                   java.util.Set        java.util.Set<java.lang.Integer>;
Agent34:          3  map                   java.util.Map        java.util.Map<java.lang.Float,java.lang.String>;
Agent34:          4  queue                 java.util.Queue      java.util.Queue<java.awt.Color>;
Agent34:          5  double_ended_queue    java.util.Deque      java.util.Deque<java.lang.String>;
Agent34:
Agent34:     method method9 with signature (IFZ)V
Agent34:         number of local variables 9:
Agent34:          0  this                  Test34
Agent34:          1  x                     int
Agent34:          2  y                     float
Agent34:          3  z                     boolean
Agent34:          4  list                  java.util.List       java.util.List<java.lang.String>;
Agent34:          5  set                   java.util.Set        java.util.Set<java.lang.Integer>;
Agent34:          6  map                   java.util.Map        java.util.Map<java.lang.Float,java.lang.String>;
Agent34:          7  queue                 java.util.Queue      java.util.Queue<java.awt.Color>;
Agent34:          8  double_ended_queue    java.util.Deque      java.util.Deque<java.lang.String>;
Agent34:
Agent34:     method static_method1 with signature ()V
Agent34:         number of local variables 0:
Agent34:
Agent34:     method static_method2 with signature ()V
Agent34:         number of local variables 1:
Agent34:          0  x                     int
Agent34:
Agent34:     method static_method3 with signature ()V
Agent34:         number of local variables 2:
Agent34:          0  x                     int
Agent34:          1  y                     int
Agent34:
Agent34:     method static_method4 with signature ()V
Agent34:         number of local variables 4:
Agent34:          0  byte_variable         byte
Agent34:          1  short_variable        short
Agent34:          2  int_variable          int
Agent34:          3  long_variable         long
Agent34:
Agent34:     method static_method5 with signature ()V
Agent34:         number of local variables 4:
Agent34:          0  char_variable         char
Agent34:          1  float_variable        float
Agent34:          2  double_variable       double
Agent34:          3  boolean_variable      boolean
Agent34:
Agent34:     method static_method6 with signature ()V
Agent34:         number of local variables 3:
Agent34:          0  int_array             array of int
Agent34:          1  float_array           array of float
Agent34:          2  int_matrix            array of array of int
Agent34:
Agent34:     method static_method7 with signature ()V
Agent34:         number of local variables 3:
Agent34:          0  str                   java.lang.String
Agent34:          1  color                 java.awt.Color
Agent34:          2  colors                array of java.awt.Color
Agent34:
Agent34:     method static_method8 with signature ()V
Agent34:         number of local variables 5:
Agent34:          0  list                  java.util.List       java.util.List<java.lang.String>;
Agent34:          1  set                   java.util.Set        java.util.Set<java.lang.Integer>;
Agent34:          2  map                   java.util.Map        java.util.Map<java.lang.Float,java.lang.String>;
Agent34:          3  queue                 java.util.Queue      java.util.Queue<java.awt.Color>;
Agent34:          4  double_ended_queue    java.util.Deque      java.util.Deque<java.lang.String>;
Agent34:
Agent34:     method static_method9 with signature (IFZ)V
Agent34:         number of local variables 8:
Agent34:          0  x                     int
Agent34:          1  y                     float
Agent34:          2  z                     boolean
Agent34:          3  list                  java.util.List       java.util.List<java.lang.String>;
Agent34:          4  set                   java.util.Set        java.util.Set<java.lang.Integer>;
Agent34:          5  map                   java.util.Map        java.util.Map<java.lang.Float,java.lang.String>;
Agent34:          6  queue                 java.util.Queue      java.util.Queue<java.awt.Color>;
Agent34:          7  double_ended_queue    java.util.Deque      java.util.Deque<java.lang.String>;
Agent34: Got VM Death event
Agent34: Agent_OnUnload

12. Porovnání výstupu JVM TI agenta s výpisem získaným přes nástroj javap

Po kontrolu korektnosti informací vypsaných demonstračním JVM TI agentem si vyzkoušejme, jaké informace se zobrazí po zadání příkazu:

root_podpora

javap -verbose -private Test34

Pokud byla testovací třída Test34 přeložena s ladicími informacemi, získáme následující výstup:

Compiled from "Test34.java"
public class Test34 extends java.lang.Object
  SourceFile: "Test34.java"
  minor version: 0
  major version: 50
  Constant pool:
const #1 = Method       #9.#89; //  java/lang/Object."<init>":()V
const #2 = long 4l;
const #4 = float        0.5f;
const #5 = double       0.5d;
const #7 = class        #46;    //  "[[I"
const #8 = class        #90;    //  Test34
const #9 = class        #91;    //  java/lang/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       LTest34;;
const #17 = Asciz       method1;
const #18 = Asciz       method2;
const #19 = Asciz       x;
const #20 = Asciz       I;
const #21 = Asciz       method3;
const #22 = Asciz       y;
const #23 = Asciz       method4;
const #24 = Asciz       byte_variable;
const #25 = Asciz       B;
const #26 = Asciz       short_variable;
const #27 = Asciz       S;
const #28 = Asciz       int_variable;
const #29 = Asciz       long_variable;
const #30 = Asciz       J;
const #31 = Asciz       method5;
const #32 = Asciz       char_variable;
const #33 = Asciz       C;
const #34 = Asciz       float_variable;
const #35 = Asciz       F;
const #36 = Asciz       double_variable;
const #37 = Asciz       D;
const #38 = Asciz       boolean_variable;
const #39 = Asciz       Z;
const #40 = Asciz       method6;
const #41 = Asciz       int_array;
const #42 = Asciz       [I;
const #43 = Asciz       float_array;
const #44 = Asciz       [F;
const #45 = Asciz       int_matrix;
const #46 = Asciz       [[I;
const #47 = Asciz       method7;
const #48 = Asciz       str;
const #49 = Asciz       Ljava/lang/String;;
const #50 = Asciz       color;
const #51 = Asciz       Ljava/awt/Color;;
const #52 = Asciz       colors;
const #53 = Asciz       [Ljava/awt/Color;;
const #54 = Asciz       method8;
const #55 = Asciz       list;
const #56 = Asciz       Ljava/util/List;;
const #57 = Asciz       set;
const #58 = Asciz       Ljava/util/Set;;
const #59 = Asciz       map;
const #60 = Asciz       Ljava/util/Map;;
const #61 = Asciz       queue;
const #62 = Asciz       Ljava/util/Queue;;
const #63 = Asciz       double_ended_queue;
const #64 = Asciz       Ljava/util/Deque;;
const #65 = Asciz       LocalVariableTypeTable;
const #66 = Asciz       Ljava/util/List<Ljava/lang/String;>;;
const #67 = Asciz       Ljava/util/Set<Ljava/lang/Integer;>;;
const #68 = Asciz       Ljava/util/Map<Ljava/lang/Float;Ljava/lang/String;>;;
const #69 = Asciz       Ljava/util/Queue<Ljava/awt/Color;>;;
const #70 = Asciz       Ljava/util/Deque<Ljava/lang/String;>;;
const #71 = Asciz       method9;
const #72 = Asciz       (IFZ)V;
const #73 = Asciz       z;
const #74 = Asciz       static_method1;
const #75 = Asciz       static_method2;
const #76 = Asciz       static_method3;
const #77 = Asciz       static_method4;
const #78 = Asciz       static_method5;
const #79 = Asciz       static_method6;
const #80 = Asciz       static_method7;
const #81 = Asciz       static_method8;
const #82 = Asciz       static_method9;
const #83 = Asciz       main;
const #84 = Asciz       ([Ljava/lang/String;)V;
const #85 = Asciz       args;
const #86 = Asciz       [Ljava/lang/String;;
const #87 = Asciz       SourceFile;
const #88 = Asciz       Test34.java;
const #89 = NameAndType #10:#11;//  "<init>":()V
const #90 = Asciz       Test34;
const #91 = Asciz       java/lang/Object;
 
{
public Test34();
  Code:
   Stack=1, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return
  LineNumberTable:
   line 11: 0
 
  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      5       0     this   LTest34;
 
 
private void method1();
  Code:
   Stack=0, Locals=1, Args_size=1
   0:   return
  LineNumberTable:
   line 14: 0
 
  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      1       0     this   LTest34;
 
 
private void method2();
  Code:
   Stack=1, Locals=2, Args_size=1
   0:   iconst_0
   1:   istore_1
   2:   return
  LineNumberTable:
   line 17: 0
   line 18: 2
 
  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      3       0     this   LTest34;
   2      1       1     x      I
 
 
private void method3();
  Code:
   Stack=1, Locals=3, Args_size=1
   0:   iconst_1
   1:   istore_1
   2:   iconst_2
   3:   istore_2
   4:   return
  LineNumberTable:
   line 21: 0
   line 22: 2
   line 23: 4
 
  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      5       0     this   LTest34;
   2      3       1     x      I
   4      1       2     y      I
 
 
private void method4();
  Code:
   Stack=2, Locals=6, Args_size=1
   0:   iconst_1
   1:   istore_1
   2:   iconst_2
   3:   istore_2
   4:   iconst_3
   5:   istore_3
   6:   ldc2_w  #2; //long 4l
   9:   lstore  4
   11:  return
  LineNumberTable:
   line 26: 0
   line 27: 2
   line 28: 4
   line 29: 6
   line 30: 11
 
  LocalVariableTable:
   Start  Length  Slot  Name           Signature
   0      12      0     this           LTest34;
   2      10      1     byte_variable  B
   4       8      2     short_variable S
   6       6      3     int_variable   I
   11      1      4     long_variable  J
 
 
private void method5();
  Code:
   Stack=2, Locals=6, Args_size=1
   0:   bipush  97
   2:   istore_1
   3:   ldc     #4; //float 0.5f
   5:   fstore_2
   6:   ldc2_w  #5; //double 0.5d
   9:   dstore_3
   10:  iconst_1
   11:  istore  5
   13:  return
  LineNumberTable:
   line 33: 0
   line 34: 3
   line 35: 6
   line 36: 10
   line 37: 13
 
  LocalVariableTable:
   Start  Length  Slot  Name             Signature
   0      14      0     this             LTest34;
   3      11      1     char_variable    C
   6       8      2     float_variable   F
   10      4      3     double_variable  D
   13      1      5     boolean_variable Z
 
 
private void method6();
  Code:
   Stack=1, Locals=4, Args_size=1
   0:   aconst_null
   1:   astore_1
   2:   aconst_null
   3:   astore_2
   4:   aconst_null
   5:   checkcast       #7; //class "[[I"
   8:   astore_3
   9:   return
  LineNumberTable:
   line 40: 0
   line 41: 2
   line 42: 4
   line 43: 9
 
  LocalVariableTable:
   Start  Length  Slot  Name         Signature
   0      10      0     this         LTest34;
   2      8       1     int_array    [I
   4      6       2     float_array  [F
   9      1       3     int_matrix   [[I
 
 
private void method7();
  Code:
   Stack=1, Locals=4, Args_size=1
   0:   aconst_null
   1:   astore_1
   2:   aconst_null
   3:   astore_2
   4:   aconst_null
   5:   astore_3
   6:   return
  LineNumberTable:
   line 46: 0
   line 47: 2
   line 48: 4
   line 49: 6
 
  LocalVariableTable:
   Start  Length  Slot  Name      Signature
   0      7       0     this      LTest34;
   2      5       1     str       Ljava/lang/String;
   4      3       2     color     Ljava/awt/Color;
   6      1       3     colors    [Ljava/awt/Color;
 
 
private void method8();
  Code:
   Stack=1, Locals=6, Args_size=1
   0:   aconst_null
   1:   astore_1
   2:   aconst_null
   3:   astore_2
   4:   aconst_null
   5:   astore_3
   6:   aconst_null
   7:   astore  4
   9:   aconst_null
   10:  astore  5
   12:  return
  LineNumberTable:
   line 52: 0
   line 53: 2
   line 54: 4
   line 55: 6
   line 56: 9
   line 57: 12
 
  LocalVariableTable:
   Start  Length  Slot  Name                Signature
   0      13      0     this                LTest34;
   2      11      1     list                Ljava/util/List;
   4       9      2     set                 Ljava/util/Set;
   6       7      3     map                 Ljava/util/Map;
   9       4      4     queue               Ljava/util/Queue;
   12      1      5     double_ended_queue  Ljava/util/Deque;
 
  LocalVariableTypeTable: length = 0x34
   00 05 00 02 00 0B 00 37 00 42 00 01 00 04 00 09
   00 39 00 43 00 02 00 06 00 07 00 3B 00 44 00 03
   00 09 00 04 00 3D 00 45 00 04 00 0C 00 01 00 3F
   00 46 00 05
 
private void method9(int, float, boolean);
  Code:
   Stack=1, Locals=9, Args_size=4
   0:   aconst_null
   1:   astore  4
   3:   aconst_null
   4:   astore  5
   6:   aconst_null
   7:   astore  6
   9:   aconst_null
   10:  astore  7
   12:  aconst_null
   13:  astore  8
   15:  return
  LineNumberTable:
   line 60: 0
   line 61: 3
   line 62: 6
   line 63: 9
   line 64: 12
   line 65: 15
 
  LocalVariableTable:
   Start  Length  Slot  Name                Signature
   0      16      0     this                LTest34;
   0      16      1     x                   I
   0      16      2     y                   F
   0      16      3     z                   Z
   3      13      4     list                Ljava/util/List;
   6      10      5     set                 Ljava/util/Set;
   9       7      6     map                 Ljava/util/Map;
   12      4      7     queue               Ljava/util/Queue;
   15      1      8     double_ended_queue  Ljava/util/Deque;
 
  LocalVariableTypeTable: length = 0x34
   00 05 00 03 00 0D 00 37 00 42 00 04 00 06 00 0A
   00 39 00 43 00 05 00 09 00 07 00 3B 00 44 00 06
   00 0C 00 04 00 3D 00 45 00 07 00 0F 00 01 00 3F
   00 46 00 08
 
private static void static_method1();
  Code:
   Stack=0, Locals=0, Args_size=0
   0:   return
  LineNumberTable:
   line 68: 0
 
 
private static void static_method2();
  Code:
   Stack=1, Locals=1, Args_size=0
   0:   iconst_0
   1:   istore_0
   2:   return
  LineNumberTable:
   line 71: 0
   line 72: 2
 
  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   2      1       0     x      I
 
 
private static void static_method3();
  Code:
   Stack=1, Locals=2, Args_size=0
   0:   iconst_1
   1:   istore_0
   2:   iconst_2
   3:   istore_1
   4:   return
  LineNumberTable:
   line 75: 0
   line 76: 2
   line 77: 4
 
  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   2      3       0     x      I
   4      1       1     y      I
 
 
private static void static_method4();
  Code:
   Stack=2, Locals=5, Args_size=0
   0:   iconst_1
   1:   istore_0
   2:   iconst_2
   3:   istore_1
   4:   iconst_3
   5:   istore_2
   6:   ldc2_w  #2; //long 4l
   9:   lstore_3
   10:  return
  LineNumberTable:
   line 80: 0
   line 81: 2
   line 82: 4
   line 83: 6
   line 84: 10
 
  LocalVariableTable:
   Start  Length  Slot  Name            Signature
   2      9       0     byte_variable   B
   4      7       1     short_variable  S
   6      5       2     int_variable    I
   10     1       3     long_variable   J
 
 
private static void static_method5();
  Code:
   Stack=2, Locals=5, Args_size=0
   0:   bipush  97
   2:   istore_0
   3:   ldc     #4; //float 0.5f
   5:   fstore_1
   6:   ldc2_w  #5; //double 0.5d
   9:   dstore_2
   10:  iconst_1
   11:  istore  4
   13:  return
  LineNumberTable:
   line 87: 0
   line 88: 3
   line 89: 6
   line 90: 10
   line 91: 13
 
  LocalVariableTable:
   Start  Length  Slot  Name              Signature
   3      11      0     char_variable     C
   6       8      1     float_variable    F
   10      4      2     double_variable   D
   13      1      4     boolean_variable  Z
 
 
private static void static_method6();
  Code:
   Stack=1, Locals=3, Args_size=0
   0:   aconst_null
   1:   astore_0
   2:   aconst_null
   3:   astore_1
   4:   aconst_null
   5:   checkcast       #7; //class "[[I"
   8:   astore_2
   9:   return
  LineNumberTable:
   line 94: 0
   line 95: 2
   line 96: 4
   line 97: 9
 
  LocalVariableTable:
   Start  Length  Slot  Name          Signature
   2      8       0     int_array     [I
   4      6       1     float_array   [F
   9      1       2     int_matrix    [[I
 
 
private static void static_method7();
  Code:
   Stack=1, Locals=3, Args_size=0
   0:   aconst_null
   1:   astore_0
   2:   aconst_null
   3:   astore_1
   4:   aconst_null
   5:   astore_2
   6:   return
  LineNumberTable:
   line 100: 0
   line 101: 2
   line 102: 4
   line 103: 6
 
  LocalVariableTable:
   Start  Length  Slot  Name      Signature
   2      5       0     str       Ljava/lang/String;
   4      3       1     color     Ljava/awt/Color;
   6      1       2     colors    [Ljava/awt/Color;
 
 
private static void static_method8();
  Code:
   Stack=1, Locals=5, Args_size=0
   0:   aconst_null
   1:   astore_0
   2:   aconst_null
   3:   astore_1
   4:   aconst_null
   5:   astore_2
   6:   aconst_null
   7:   astore_3
   8:   aconst_null
   9:   astore  4
   11:  return
  LineNumberTable:
   line 106: 0
   line 107: 2
   line 108: 4
   line 109: 6
   line 110: 8
   line 111: 11
 
  LocalVariableTable:
   Start  Length  Slot  Name                Signature
   2      10      0     list                Ljava/util/List;
   4       8      1     set                 Ljava/util/Set;
   6       6      2     map                 Ljava/util/Map;
   8       4      3     queue               Ljava/util/Queue;
   11      1      4     double_ended_queue  Ljava/util/Deque;
 
  LocalVariableTypeTable: length = 0x34
   00 05 00 02 00 0A 00 37 00 42 00 00 00 04 00 08
   00 39 00 43 00 01 00 06 00 06 00 3B 00 44 00 02
   00 08 00 04 00 3D 00 45 00 03 00 0B 00 01 00 3F
   00 46 00 04
 
private static void static_method9(int, float, boolean);
  Code:
   Stack=1, Locals=8, Args_size=3
   0:   aconst_null
   1:   astore_3
   2:   aconst_null
   3:   astore  4
   5:   aconst_null
   6:   astore  5
   8:   aconst_null
   9:   astore  6
   11:  aconst_null
   12:  astore  7
   14:  return
  LineNumberTable:
   line 114: 0
   line 115: 2
   line 116: 5
   line 117: 8
   line 118: 11
   line 119: 14
 
  LocalVariableTable:
   Start  Length  Slot  Name                Signature
   0      15      0     x                   I
   0      15      1     y                   F
   0      15      2     z                   Z
   2      13      3     list                Ljava/util/List;
   5      10      4     set                 Ljava/util/Set;
   8       7      5     map                 Ljava/util/Map;
   11      4      6     queue               Ljava/util/Queue;
   14      1      7     double_ended_queue  Ljava/util/Deque;
 
  LocalVariableTypeTable: length = 0x34
   00 05 00 02 00 0D 00 37 00 42 00 03 00 05 00 0A
   00 39 00 43 00 04 00 08 00 07 00 3B 00 44 00 05
   00 0B 00 04 00 3D 00 45 00 06 00 0E 00 01 00 3F
   00 46 00 07
 
public static void main(java.lang.String[]);
  Code:
   Stack=0, Locals=1, Args_size=1
   0:   return
  LineNumberTable:
   line 125: 0
 
  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      1       0     args   [Ljava/lang/String;
 
 
}

13. Zdrojové kódy 34.demonstračního agenta i k němu příslušných testovacích příkladů a skriptů

Zdrojový kód třicátého čtvrtého demonstračního JVM TI agenta je, společně s testovací třídou nazvanou Test34 i se skripty použitými pro překlad a spuštění agenta, uložen do Mercurial repositáře dostupného na adrese http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/. Prozatím nejnovější verze všech zmíněných zdrojových souborů můžete najít na adresách:

14. Literatura a odkazy na Internetu

  1. Breakpoint (Wikipedia)
    http://cs.wikipedia.org/wi­ki/Breakpoint
  2. JVM Tool Interface Version 1.2 Documentation
    http://docs.oracle.com/ja­vase/7/docs/platform/jvmti/jvmti­.html
  3. JVM Tool Interface Version 1.2 Documentation – SetBreakpoint
    http://docs.oracle.com/ja­vase/6/docs/platform/jvmti/jvmti­.html#SetBreakpoint
  4. JVM Tool Interface Version 1.2 Documentation – ClearBreakpoint
    http://docs.oracle.com/ja­vase/6/docs/platform/jvmti/jvmti­.html#ClearBreakpoint
  5. JVM Tool Interface Version 1.2 Documentation – Breakpoint (callback funkce)
    http://docs.oracle.com/ja­vase/6/docs/platform/jvmti/jvmti­.html#Breakpoint
  6. The JVM Tool Interface (JVM TI): How VM Agents Work
    http://www.oracle.com/technet­work/articles/javase/jvm-ti-141370.html
  7. Creating a Debugging and Profiling Agent with JVMTI
    http://www.oracle.com/technet­work/articles/javase/jvmti-136367.html
  8. JVM TI (Wikipedia)
    http://en.wikipedia.org/wiki/JVM_TI
  9. IBM JVMTI extensions
    http://publib.boulder.ibm­.com/infocenter/realtime/v2r0/in­dex.jsp?topic=%2Fcom.ibm.sof­trt.doc%2Fdiag%2Ftools%2Fjvmti_ex­tensions.html
  10. An empirical study of Java bytecode programs
    http://www.mendeley.com/research/an-empirical-study-of-java-bytecode-programs/
  11. Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
    http://www.mobilefish.com/tu­torials/java/java_quickgu­ide_jvm_instruction_set.html
  12. The JVM Instruction Set
    http://mpdeboer.home.xs4a­ll.nl/scriptie/node14.html
  13. Control Flow in the Java Virtual Machine
    http://www.artima.com/under­thehood/flowP.html
  14. The class File Format
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/Clas­sFile.doc.html
  15. javap – The Java Class File Disassembler
    http://docs.oracle.com/ja­vase/1.4.2/docs/tooldocs/win­dows/javap.html
  16. javap-java-1.6.0-openjdk(1) – Linux man page
    http://linux.die.net/man/1/javap-java-1.6.0-openjdk
  17. Using javap
    http://www.idevelopment.in­fo/data/Programming/java/mis­cellaneous_java/Using_javap­.html
  18. Examine class files with the javap command
    http://www.techrepublic.com/ar­ticle/examine-class-files-with-the-javap-command/5815354
  19. Bytecode Engineering
    http://book.chinaunix.net/spe­cial/ebook/Core_Java2_Volu­me2AF/0131118269/ch13lev1sec6­.html

Byl pro vás článek přínosný?