Hlavní navigace

Pohled pod kapotu JVM - nastavení breakpointů s využitím rozhraní JVM TI (dokončení)

26. 2. 2013
Doba čtení: 18 minut

Sdílet

V dnešní části seriálu o programovacím jazyce Java i o vlastnostech JVM dokončíme popis způsobu nastavení breakpointů přes rozhraní JVM TI. Ukážeme si kompletní demonstrační program, na němž bude shrnuta většina postupů, s nimiž jsme se seznámili v předchozích čtrnácti částech tohoto seriálu.

Obsah

1. Pohled pod kapotu JVM – nastavení breakpointů s využitím rozhraní JVM TI (dokončení)

2. Testovací třída použitá pro třicátého druhého demonstračního JVM TI agenta

3. Pole obsahující jména metod a čísla řádků, pro něž se mají nastavit breakpointy

4. Nastavení vlastností JVM TI agenta (funkce set_capabilities)

5. Průchod načítanými třídami s vyhledáním třídy, pro niž se breakpoint nastaví (funkce prepare_breakpoints)

6. Příprava a registrace breakpointů pro vybrané metody (funkce set_breakpoint_for_selected_method)

7. Vlastní nastavení breakpointu (funkce set_breakpoint)

8. Výpis veškerých informací o navštíveném breakpointu (funkce callback_on_breakpoint)

9. Výpis obsahu zásobníkových rámců při navštívení breakpointu (funkce print_stack_trace)

10. Zdrojové kódy třicátého druhého demonstračního agenta i k němu příslušných testovacích příkladů a skriptů

11. Zbylá funkcionalita rozhraní JVM TI aneb co si popíšeme v navazujících článcích

12. Odkazy na Internetu

1. Pohled pod kapotu JVM – nastavení breakpointů s využitím rozhraní JVM TI (dokončení)

V dnešní části seriálu o programovacím jazyce Java i o vlastnostech virtuálního stroje Javy se již popatnácté budeme věnovat popisu rozhraní JVM TI. Ve skutečnosti jsme si již stačili popsat většinu funkcí, které toto rozhraní programátorům nabízí, proto nastal čas pro malou rekapitulaci. V třicátém druhém demonstračním JVM TI agentovi, jehož zdrojové kódy naleznete pod odkazy uvedenými v desáté kapitole, použijeme poměrně velké množství již popsaných funkcí nabízených přes JVM TI i uživatelských funkcí použitých v předchozích agentech. Tento demonstrační agent nejprve zaregistruje tři breakpointy pro tři různé javovské metody a ve chvíli, kdy nějaké vlákno dojde k nastavenému breakpointu, zavolá se v JVM TI agentovi vytvořená callback funkce, která vypíše podrobnější informace o vláknu, které do breakpointu vstoupilo. Vedle přesné lokalizace breakpointu se totiž vypíše i stack trace, přesněji řečeno obsah zásobníkového rámce vlákna (historie volání metod).

Po spuštění testovací třídy Test32 se v případě, že je při spuštění virtuálního stroje Javy zaregistrován JVM TI agent, vypíšou na standardní výstup následující hlášení, z nichž je patrné, že se nejdříve nastaví breakpoint pro metody Test32.run(), Test32.foo() a Test32.bar() a posléze se při vstupu na zaregistrované breakpointy vypíše obsah zásobníkového rámce, tj. seznam volaných metod. Styl výpisu zásobníkových rámců byl zvolen takovým způsobem, aby se co nejvíce podobal výpisu, který získáme při vzniku výjimky zavoláním metody Throwable.printStackTrace():

Test32.run()
Test32.foo()
Test32.bar() line 12
Test32.bar() line 13
Test32.bar() line 14
Test32.bar() line 15
Agent32: Agent_OnLoad
Agent32: JVM TI version is correct
Agent32: Got VM init event
Agent32: Class Test32; prepared, setting breakpoints for its methods
Agent32: Found method(): <init> with signature ()V
Agent32: Found method(): main with signature ([Ljava/lang/String;)V
Agent32: Found method(): run with signature ()V
Agent32: ...going to set breakpoint for this method
Agent32: Found method(): x with signature ()I
Agent32: Found method(): x with signature (I)I
Agent32: Found method(): x with signature (IZ)I
Agent32: Found method(): x with signature ([I[[D)[I
Agent32: Found method(): foo with signature ()V
Agent32: ...going to set breakpoint for this method
Agent32: Found method(): bar with signature ()V
Agent32: ...going to set breakpoint for this method
 
Agent32: *** visited breakpoint in method Test32.run(Test32.java:19) ***
Agent32: Stack Trace (depth = 2)
Agent32:    at Test32.run(Test32.java:19)
Agent32:    at Test32.main(Test32.java:32)
 
Agent32: *** visited breakpoint in method Test32.foo(Test32.java:7) ***
Agent32: Stack Trace (depth = 3)
Agent32:    at Test32.foo(Test32.java:7)
Agent32:    at Test32.run(Test32.java:20)
Agent32:    at Test32.main(Test32.java:32)
 
Agent32: *** visited breakpoint in method Test32.bar(Test32.java:14) ***
Agent32: Stack Trace (depth = 4)
Agent32:    at Test32.bar(Test32.java:14)
Agent32:    at Test32.foo(Test32.java:8)
Agent32:    at Test32.run(Test32.java:20)
Agent32:    at Test32.main(Test32.java:32)
 
Agent32: Got VM Death event
Agent32: Agent_OnUnload

2. Testovací třída použitá pro třicátého druhého demonstračního JVM TI agenta

Testovací javovská třída, která je použita společně s třicátým druhým demonstračním JVM TI agentem, vypadá následovně:

/**
  * Testovaci trida pouzite pro test tricateho
  * druheho demonstracniho JVM TI agenta.
  */
public class Test32 {
    public void foo() {
        System.out.println("Test32.foo()");
        bar();
    }
 
    public void bar() {
        System.out.println("Test32.bar() line 12");
        System.out.println("Test32.bar() line 13");
        System.out.println("Test32.bar() line 14");
        System.out.println("Test32.bar() line 15");
    }
 
    public void run() {
        System.out.println("Test32.run()");
        foo();
    }
 
    public int x() {return 0;}
    public int x(int y) {return 0;}
    public int x(int y, boolean z) {return 0;}
    public int[] x(int[] y, double[][] z) {return null;}
 
    /**
      * Spusteni testu.
      */
    public static void main(String[] args) {
        new Test32().run();
    }
}

Důležité je, aby se do třídy Test32 nepřidával ani neubíral žádný programový kód včetně prázdných řádků, protože breakpointy jsou v JVM TI agentovi nastavovány na konkrétní metodu a na konkrétní číslo řádku. Pokud by například došlo k přidání prázdného řádku či jednořádkové poznámky na začátek deklarace třídy Test32, mohlo by to vést k tomu, že by došlo k chybě při registraci breakpointu, popř. by byl breakpoint „pouze“ nastaven na špatnou pozici.

3. Pole obsahující jména metod a čísla řádků, pro něž se mají nastavit breakpointy

Dnes popisovaný demonstrační JVM TI agent je založený na zdrojovém souboru třicátého prvního agenta popsaného v předchozí části tohoto seriálu. Tento agent ovšem pouze dokázal zaregistrovat breakpoint pro jednu metodu a navíc jen stručně vypsal, že došlo k projití breakpointem. Dnes popisovaný agent musí být schopen zaregistrovat větší množství breakpointů a z tohoto důvodu v něm bude muset dojít k několika změnám. Informace o nastavovaném breakpointu budou ukládány do struktury nazvané t_breakpoint. Tato struktura bude obsahovat jméno metody, pro níž se má breakpoint nastavit a taktéž číslo řádky (počítané od začátku souboru, nikoli od začátku třídy):

/*
 * Struktura obsahujici jmeno metody a cislo
  *radku na nemz se ma nastavit breakpoint.
 */
typedef struct {
    char *method_name;
    int   line_number;
} t_breakpoint;

Na dalším úryvku kódu je ukázáno, jak se jednoduše vytvoří pole obsahující informace o třech breakpointech, které se mají v JVM TI agentovi nastavit (pro jednoduchost se jedná o globální proměnnou). Povšimněte si posledního (čtvrtého) záznamu, který namísto jména metody obsahuje pouze konstantu/makro NULL. Jde o zarážku, která bude použita v agentovi pro detekci konce pole s breakpointy:

/*
 * Breakpointy se budou nastavovat celkem pro tri metody.
 */
t_breakpoint breakpoints[] = {
    {"foo", 7},
    {"bar", 14},
    {"run", 19},
    {NULL,  0}    /* zarazka - je pouzita pri prochazeni timto polem! */
};

4. Nastavení vlastností JVM TI agenta (funkce set_capabilities)

Podobně jako tomu bylo v předchozích dvou částech tohoto seriálu, i dnes si postupně popíšeme některé důležité funkce, které jsou implementovány v demonstračním JVM TI agentovi. První uživatelskou funkci již známe – jde o funkci nazvanou set_capabilities(), která slouží k tomu, aby JVM TI agent informoval virtuální stroj Javy o tom, které technologie nabízené JVM TI rozhraním budou využity. V našem případě vyžadujeme, aby agent mohl využívat tři technologie: získání tabulky obsahující přepočet mezi čísly řádků a hodnotou jlocation (bude využito při výpisu obsahu zásobníkových rámců), získání jména zdrojového souboru pro danou třídu (taktéž bude využito při výpisu obsahu zásobníkových rámců) a konečně potřebujeme, aby virtuální stroj Javy zavolal předem zaregistrovanou callback funkci ve chvíli, kdy nějaké vlákno dojde k breakpointu. Funkce set_capabilities() tedy bude vypadat následovně:

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

Podobně jako v mnoha předchozích demonstračních JVM TI agentech, i zde je uživatelská funkce set_capabilities() zavolána z funkce Agent_OnLoad(), která je automaticky spuštěna virtuálním strojem Javy:

/*
 * Funkce zavolana ve chvili nacitani agenta do JVM.
 */
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved)
{
   ...
   ...
   ...
}

5. Průchod načítanými třídami s vyhledáním třídy, pro niž se breakpoint nastaví (funkce prepare_breakpoints)

Funkci nazvanou prepare_breakpoint() už sice máme připravenou od minulého týdne, ovšem kvůli tomu, že dnešní demonstrační agent podporuje nastavení většího množství breakpointů, došlo při úpravách této funkce k menšímu refaktoringu a část její funkcionality byla převedena do nové funkce set_breakpoint_for_selected_method() popsané dále. Připomeňme si, že se funkce prepare_breakpoint() volá z callback funkce nazvané callback_on_class_prepare(), jež je automaticky zavolána ve chvíli, kdy dojde k načtení nějaké třídy do virtuálního stroje Javy. Funkci prepare_breakpoint() se z callback_on_class_prepare() předá identifikátor třídy (typu jclass) a následně se přečtou všechny metody, které jsou ve třídě deklarovány. Pro každou metodu je zavolána nová uživatelská funkce nazvaná set_breakpoint_for_selected_method(), která bude popsána v následující kapitole:

/*
 * Registrace breakpointu pro zvolene metody.
 */
void prepare_breakpoints(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 nastavit breakpoint pro zvolenou metodu */
        for (i = 0; i < method_count; i++)
        {
            jmethodID method = methods_array[i];
            set_breakpoint_for_selected_method(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. Příprava a registrace breakpointů pro vybrané metody (funkce set_breakpoint_for_selected_method)

Nově přidaná funkce pojmenovaná set_breakpoint_for_selected_method() je zavolána pro každou metodu třídy, jejíž jméno je (pro jednoduchost) uloženo v symbolické konstantě nazvané TEST_CLASS_NAME. Uvnitř této funkce je implementována programová smyčka, která projde globálním polem breakpoints obsahujícím struktury typu t_breakpoint (viz též podrobnější popis ve třetí kapitole). V případě, že je nalezena metoda se jménem uvedeným v poli breakpoints, je z příslušné datové struktury získáno číslo řádku, na němž má být breakpoint nastaven. Následně se zavolá další uživatelská funkce set_breakpoint(), které se předá jak identifikátor metody (ten je typu jmethodID), tak i číslo řádku s nastavovaným breakpointem (celé kladné číslo):

/*
 * Pokud se metoda nachazi v poli breakpoints, nastavi se pro ni breakpoint.
 */
void set_breakpoint_for_selected_method(jvmtiEnv *jvmti_env, jmethodID method)
{
    jvmtiError  error;
    char *method_name;
    char *method_signature;
 
    error = (*jvmti_env)->GetMethodName(jvmti_env, method, &method_name, &method_signature, NULL);
    /* podarilo se ziskat jmeno metody, otestujme tedy, zda pro ni mame nastavit breakpoint */
    if (error == JVMTI_ERROR_NONE)
    {
        int j;
        printf(AGENT_NAME " Found method(): %s with signature %s\n", method_name, method_signature);
 
        for (j=0; breakpoints[j].method_name != NULL; j++)
        {
            if (strcmp(method_name, breakpoints[j].method_name) == 0)
            {
                puts(AGENT_NAME " ...going to set breakpoint for this method");
                set_breakpoint(jvmti_env, method, breakpoints[j].line_number);
            }
        }
 
        (*jvmti_env)->Deallocate(jvmti_env, (unsigned char*)method_name);
        (*jvmti_env)->Deallocate(jvmti_env, (unsigned char*)method_signature);
    }
}

7. Vlastní nastavení breakpointu (funkce set_breakpoint)

Funkce set_breakpoint() zavolaná z výše popsané funkce set_breakpoint_for_selected_method(), je, podobně jako u předchozího JVM TI agenta, velmi jednoduchá – nejprve zjistí hodnotu jlocation a posléze pouze zavolá JVM TI funkci SetBreakpoint() se všemi vyžadovanými parametry:

/*
 * Nastaveni breakpointu pro zvolenou metodu na danem radku.
 */
void set_breakpoint(jvmtiEnv *jvmti_env, jmethodID method, int line)
{
    jvmtiError  error;
    jlocation   location = get_location_for_line(jvmti_env, method, line);
 
    error = (*jvmti_env)->SetBreakpoint(jvmti_env, method, location);
    check_jvmti_error(jvmti_env, error, "set breakpoint");
}

Pro převod mezi číslem řádku (kladné celé číslo) a hodnotou typu jlocation se použije uživatelská funkce get_location_for_line():

/*
 * Ziskani indexu instrukce pro dane cislo radku.
 */
jlocation get_location_for_line(jvmtiEnv *jvmti_env, jmethodID method, int line)
{
    int count;
    int i;
    jvmtiLineNumberEntry *location_table;
    jvmtiError error_code;
    /* pokud se cislo radku nenalezne nebo zde není zadny kod, vrati se chybova hodnota -1 */
    jlocation  location = -1;
 
    /* pokud nebyla predana zadna metoda */
    if (method == NULL)
    {
        return -1;
    }
 
    /* test na korektne zadane cislo radky */
    if (line <= 0)
    {
        return -1;
    }
 
    /* nacteni tabulky s cisly radku a indexy instrukci */
    error_code = (*jvmti_env)->GetLineNumberTable(jvmti_env, method, &count, &location_table);
    /* v nekterych pripadech se nacist tabulku nemusi podarit */
    if (error_code != JVMTI_ERROR_NONE)
    {
        return -1;
    }
 
    /* projit celou tabulkou */
    for (i = 0; i < count; i++)
    {
        jvmtiLineNumberEntry entry = location_table[i];
        if (entry.line_number == line)
        {
            location = entry.start_location;
            break;
        }
    }
 
    /* nesmíme zapomenout na dealokaci tabulky (pole) s dvojicemi cislo radku:location */
    (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *)location_table);
    return location;
}

8. Výpis veškerých informací o navštíveném breakpointu (funkce callback_on_breakpoint)

V demonstračním JVM TI agentovi popsaném minule byla callback funkce zavolaná při přístupu na nastavený breakpoint velmi jednoduchá, protože pouze vypisovala zprávu „*** visited breakpoint!!! ***“:

/*
 * Callback funkce zavolana pri zapisu vybranych atributu
 */
static void JNICALL callback_on_breakpoint(
        jvmtiEnv *jvmti_env,
        JNIEnv*   jni_env,
        jthread   thread,
        jmethodID method,
        jlocation location)
{
    printf("*** visited breakpoint!!! ***\n");
}

My však po dnes popisovaném JVM TI agentovi budeme vyžadovat mnohem větší funkcionalitu, už jen z toho důvodu, že callback funkce callback_on_breakpoint() může být volána pro tři breakpointy nastavené pro tři různé metody. Do zprávy vypisované touto funkcí tedy doplníme informace o třídě a metodě, v níž byl breakpoint navštíven a tuto informaci ještě doplníme jménem příslušného zdrojového souboru třídy a číslem řádku (můžeme totiž samozřejmě mít hned několik breakpointů registrovaných pro stejnou metodu). Zpráva produkovaná novou variantou callback funkce callback_on_breakpoint() by měla vypadat následovně:

Agent32: *** visited breakpoint in method Test32.run(Test32.java:19) ***

Implementace této funkce není ve skutečnosti nijak složitá, protože využijeme již známé JVM TI funkce GetMethodName(), GetMethodDeclaringClass() (chybí nám totiž informace o třídě, v níž je metoda deklarována), GetClassSignature() a GetSourceFileName(). Veškeré řetězce naplněné přímo rozhraním JVM TI se samozřejmě musí uvolnit pomocí funkce Deallocate():

/*
 * Callback funkce zavolana pri zapisu vybranych atributu
 */
static void JNICALL callback_on_breakpoint(
        jvmtiEnv *jvmti_env,
        JNIEnv   *jni_env,
        jthread   thread,
        jmethodID method,
        jlocation location)
{
    char      *method_name_ptr;
    char      *method_signature_ptr;
    char      *class_name_ptr;
    char      *updated_class_name_ptr;
    char      *source_file_name;
    jclass     method_class;
    jvmtiError error;
    int        line_number;
 
    /* veskere operace se budou provadet v kriticke sekci */
    enter_critical_section(jvmti_env);
 
    /* ziskat jmeno a signaturu metody a signaturu tridy */
    (*jvmti_env)->GetMethodName(jvmti_env, method, &method_name_ptr, &method_signature_ptr, NULL);
    (*jvmti_env)->GetMethodDeclaringClass(jvmti_env, method, &method_class);
    (*jvmti_env)->GetClassSignature(jvmti_env, method_class, &class_name_ptr, NULL);
 
    /* upravit jmeno tridy */
    updated_class_name_ptr = update_class_name(class_name_ptr, '.');
 
    /* ziskat jmeno zdrojoveho souboru volajici metody */
    error = (*jvmti_env)->GetSourceFileName(jvmti_env, method_class, &source_file_name);
    check_jvmti_error(jvmti_env, error, "GetSourceFileName() failed");
 
    /* ziskat cislo radku */
    line_number = get_line_number(jvmti_env, method, location);
 
    /* vypis vsech informaci o vyjimce */
    printf(AGENT_NAME " *** visited breakpoint in method %s%s(%s:%d) ***\n",
            updated_class_name_ptr,
            method_name_ptr,
            source_file_name,
            line_number);
    print_stack_trace(jvmti_env, thread);
 
    /* dealokace vsech ziskanych pametovych struktur */
    error = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *)source_file_name);
    check_jvmti_error(jvmti_env, error, "deallocate source file name");
    error = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *)method_name_ptr);
    check_jvmti_error(jvmti_env, error, "deallocate method name");
    error = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *)method_signature_ptr);
    check_jvmti_error(jvmti_env, error, "deallocate signature");
    error = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *)class_name_ptr);
    check_jvmti_error(jvmti_env, error, "deallocate class name");
 
    /* a vystup z kriticke sekce */
    exit_critical_section(jvmti_env);
}

9. Výpis obsahu zásobníkových rámců při navštívení breakpointu (funkce print_stack_trace)

Při přístupu na breakpoint náš demonstrační JVM TI agent taktéž vypíše obsah zásobníkových rámců, přesněji řečeno ne hodnoty všech předávaných parametrů, ale „pouze“ jména volaných metod. Tato funkcionalita není implementována přímo v callback funkci callback_on_breakpoint(), ale v samostatné funkci nazvané jednoduše print_stack_trace(). V této funkci je alokováno pole obsahující prvky typu jvmtiFrameInfo. Následně je toto pole naplněno s využitím JVM TI funkce nazvané GetStackTrace(), přičemž je s využitím symbolické konstanty MAX_STACK_TRACE_DEPTH přečtena historie maximálně deseti volaných metod (hodnotu této konstanty lze samozřejmě zvýšit, v případě naší testovací Javovské třídy je to však zbytečné). Následně se v programové smyčce prochází všemi naplněnými prvky typu jvmtiFrameInfo a pro každý prvek se zjistí jméno metody (přes jvmtiFrameInfo.method i číslo řádku, na němž k volání došlo (přes jvmtiFrameInfo.location):

/*
 * Vypis obsahu zasobniku.
 */
void print_stack_trace(
            jvmtiEnv *jvmti_env,
            jthread   thread)
{
#define MAX_STACK_TRACE_DEPTH 10
    jvmtiFrameInfo stack_frames[MAX_STACK_TRACE_DEPTH];
    jclass     declaring_class;
    int        count;
    char      *method_name_ptr;
    char      *method_signature_ptr;
    char      *class_name_ptr;
    char      *updated_class_name_ptr;
    char      *source_file_name;
    int        line_number;
    int i;
 
    /* Ziskat trasovaci inforamce */
    (*jvmti_env)->GetStackTrace(jvmti_env, thread, 0, MAX_STACK_TRACE_DEPTH, stack_frames, &count);
    if (count == 1)
    {
        printf(AGENT_NAME " No stack trace!\n");
    }
    printf(AGENT_NAME " Stack Trace (depth = %d)\n", count);
    /* Vypis zasobnikovych ramcu */
    for (i = 0; i < count; i++) {
        jvmtiFrameInfo stack_frame = stack_frames[i];
 
        /* ziskat jmeno metody i jeji tridu */
        (*jvmti_env)->GetMethodName(jvmti_env, stack_frame.method, &method_name_ptr, &method_signature_ptr, NULL);
        (*jvmti_env)->GetMethodDeclaringClass(jvmti_env, stack_frame.method, &declaring_class);
        (*jvmti_env)->GetClassSignature(jvmti_env, declaring_class, &class_name_ptr, NULL);
 
        /* upravit jmeno tridy */
        updated_class_name_ptr = update_class_name(class_name_ptr, '.');
 
        /* ziskat jmeno zdrojoveho souboru volajici metody */
        (*jvmti_env)->GetSourceFileName(jvmti_env, declaring_class, &source_file_name);
 
        /* ziskat cislo radku */
        line_number = get_line_number(jvmti_env, stack_frame.method, stack_frame.location);
 
        /* provest vlastni vypis */
        printf(AGENT_NAME "\tat %s%s(%s:%d)\n", updated_class_name_ptr, method_name_ptr, source_file_name, line_number);
 
        /* dealokace vsech ziskanych pametovych struktur */
        (*jvmti_env)->Deallocate(jvmti_env, (unsigned char*)method_name_ptr);
        (*jvmti_env)->Deallocate(jvmti_env, (unsigned char*)method_signature_ptr);
        (*jvmti_env)->Deallocate(jvmti_env, (unsigned char*)class_name_ptr);
    }
}

10. Zdrojové kódy třicátého druhého 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 druhého demonstračního JVM TI agenta je, společně s testovací třídou Test32 i 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ů jsou dostupné na adresách:

CS24_early

11. Zbylá funkcionalita rozhraní JVM TI aneb co si popíšeme v navazujících článcích

Jak jsme si již řekli v úvodní kapitole, byla v předchozích čtrnácti částech tohoto seriálu popsána většina funkcí nabízených rozhraním JVM TI. Zbývá nám popsat a na demonstračních příkladech ukázat pouze dvě relativně malé skupiny funkcí. Do první skupiny patří funkce začínající prefixem ForceEarlyReturn*. Tyto funkce slouží k tomu, aby si JVM TI agent vynutil opuštění nějaké metody a současně vrátil zadanou hodnotu. Může se jednat jak o hodnotu primitivního datového typu (boolean, char, byte, short, int, long, float, double) či o referenci (tj. odkaz na instanci nějaké třídy).

Do druhé skupiny prozatím nepopsaných funkcí patří funkce začínající prefixem GetLocal*. Tyto funkce slouží k získání hodnot lokálních proměnných a lze je využít například při práci s breakpointy, v callback funkci zavolané při vstupu do metody, v callback funkci zavolané při vstupu do výjimky atd. Podrobnější informace o těchto dvou skupinách funkcí si řekneme příště.

12. 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ý?

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.