Hlavní navigace

Pohled pod kapotu JVM - předčasný výskok z metody s využitím rozhraní JVM TI

5. 3. 2013
Doba čtení: 18 minut

Sdílet

V šedesáté osmé části seriálu o jazyce Java i o vlastnostech JVM si řekneme, jakým způsobem je možné přes rozhraní JVM TI vynutit předčasné ukončení libovolné metody. Většinou se jedná o metody, na kterých je nastavený breakpoint, ovšem ve skutečnosti je možné si vynutit ukončení zcela libovolné metody.

Obsah

1. Pohled pod kapotu JVM – předčasný výskok z metody s využitím rozhraní JVM TI

2. Paměťový prostor přidělený každému vláknu: zásobník a zásobníkové rámce (stack frames)

3. Instrukce bajtkódu sloužící pro ukončení metody s předáním návratové hodnoty této metody

4. Podpora JVM TI pro výskok z metody mající návratovou hodnotu i z metody bez návratové hodnoty

5. Testovací třída použitá třicátým třetím demonstračním JVM TI agentem

6. Nastavení breakpointů pro všechny testované metody

7. Tvar callback funkce callback_on_breakpoint()

8. Tvar uživatelské funkce force_early_return()

9. Spuštění třicátého třetího demonstračního JVM TI agenta

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

11. Odkazy na Internetu

1. Pohled pod kapotu JVM – předčasný výskok z metody s využitím rozhraní JVM TI

V závěru předchozí části seriálu o programovacím jazyce Java i o vlastnostech virtuálního stroje Javy jsme si řekli, že v tomto seriálu již byla popsána většina funkcí nabízených rozhraním JVM TI. Zbývá nám tak popsat a na demonstračních příkladech ukázat pouze dvě relativně malé skupiny funkcí. Do první skupiny patří šestice funkcí začínajících prefixem ForceEarlyReturn*(). Tyto funkce slouží k tomu, aby si JVM TI agent mohl v případě potřeby vynutit opuštění nějaké javovské metody a současně vrátil z této metody specifikovanou hodnotu (vynucením se zde myslí situace, kdy agent do kódu jakoby vloží pomyslný příkaz return). Může se jednat jak o hodnotu primitivního datového typu (boolean, char, byte, short, int, long, float, double s omezeními popsanými v dalším textu), tak i o referenci, tj. odkaz na instanci nějaké třídy.

Právě popisem zmíněné šestice funkcí ForceEarlyReturn*() se budeme zabývat v následujících kapitolách. Řekneme si, jak tyto funkce ovlivní chování virtuálního stroje Javy a posléze si na třicátém třetím demonstračním JVM TI agentovi ukážeme, jak lze tyto funkce využít v praxi, konkrétně v agentovi, který si vynutí předčasné opuštění všech metod, pro něž je nastavený breakpoint.

Poznámka: aby bylo možné JVM TI funkce určené pro vynucené opuštění metod v JVM TI agentech skutečně použít, je nutné agenta nastavit takovým způsobem, aby byla podporována schopnost can_force_early_return. Jak se tato vlastnost v našem demonstračním JVM TI agentovi nastavuje, je vidět z následující ukázky:

/*
 * 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;
}

2. Paměťový prostor přidělený každému vláknu: zásobník a zásobníkové rámce (stack frames)

Dříve než si popíšeme funkce nabízené rozhraním JVM TI, které dokážou vynutit předčasné ukončení zvolené metody, si připomeňme, jakým způsobem je vlastně organizována paměť využívaná „uvnitř“ metod. Již v úvodních částech tohoto seriálu jsme si řekli, že instance tříd, tj. vlastně hodnoty jednotlivých atributů, jsou alokovány na haldě (heapu). Tato paměťová oblast je pro nás v tomto momentě relativně nezajímavá, protože se jí předčasné ukončení metod vlastně nijak netýká. Mnohem důležitější paměťovou oblastí je pro nás zásobník (stack), který je tvořen sekvencí vzájemně pouze nepřímo propojených zásobníkových rámců (stack frame(s)). Označení „zásobník“ sice může navozovat pocit, že se jedná o kontinuální oblast paměti, ve skutečnosti však mezi jednotlivými zásobníkovými rámci neexistují žádné přímé vazby a proto se každý zásobníkový rámec může (ale nemusí) nacházet v paměti kdekoli – rámce například mohou být vytvářeny přímo na haldě (hodně zde záleží na konkrétní implementaci JVM).

Důležité je, že zásobník je virtuálním strojem Javy automaticky vytvořen pro každé vlákno, což při bližším zamyšlení dává smysl, protože jedna metoda může být v jednom okamžiku volána z většího množství vláken a je tedy nutné oddělit parametry metody i její lokální proměnné od dalších volání téže metody. Ostatně právě fakt, že zásobník je vytvořen pro každé vlákno, vede k tomu, že dále popsané JVM TI funkce ForceEarlyReturn*() vyžadují jako jeden ze svých parametrů i identifikátor vlákna, jenž je typu jthread. Zásobníkové rámce jsou tvořeny lokálními proměnnými metod a parametry metod. Jejich součástí je však taktéž zásobník operandů (operand stack) využívaný jak při všech aritmetických a logických operacích, tak i při volání jiné metody. Opět platí, že není možné získat přímou adresu lokálních proměnných, parametrů metod ani dat uložených na zásobníku operandů, proto se nemusí jednat o kontinuální oblast paměti.

V předchozím textu bylo řečeno, že v zásobníkovém rámci jsou uloženy jak parametry metod, tak i její lokální proměnné. Nejdříve jsou v zásobníkovém rámci uloženy parametry metod (včetně parametru this, ovšem logicky pouze u nestatických metod) a ihned za nimi se nachází oblast vyhrazená pro lokální proměnné. Ke všem těmto údajům, tj. jak k parametrům, tak i k lokálním proměnným, se v bajtkódu přistupuje s využitím indexu: první údaj má index 0, další 1 atd. Ukažme si to na jednoduchém příkladu třídy s dvojicí metod – jedné nestatické a druhé statické:

class Test {
    void add1(int x, int y) {
        int z = x + y;
    }
 
    static void add2(int x, int y) {
        int z = x + y;
    }
}

Obě metody sice provádí tutéž činnost – součet dvou celých čísel s uložením výsledku do lokální proměnné – ovšem způsob indexování parametrů je uvnitř JVM odlišný, protože v nestatické metodě je v první pozici zásobníkového rámce (tato pozice má index roven nule) uložen implicitní parametr this, kdežto v metodě statické se na stejné pozici zásobníkového rámce nachází již přímo první parametr:

void add1(int, int);
  Code:
   Stack=2, Locals=4, Args_size=3
                        // v prvním parametru je uložena hodnota this, tu nepotřebujeme
   0:   iload_1         // načtení druhého parametru metody s jeho uložením na zásobník operandů
   1:   iload_2         // načtení třetího parametru metody s jeho uložením na zásobník operandů
   2:   iadd            // provedení součtu
   3:   istore_3        // uložení výsledku na čtvrtou pozici v zásobníkovém rámci: první lokální proměnné
   4:   return          // návrat z metody
static void add2(int, int);
  Code:
   Stack=2, Locals=3, Args_size=2
   0:   iload_1         // načtení druhého parametru metody s jeho uložením na zásobník operandů
   1:   iload_2         // načtení třetího parametru metody s jeho uložením na zásobník operandů
   2:   iadd            // provedení součtu
   3:   istore_2        // uložení výsledku na třetí pozici v zásobníkovém rámci: první lokální proměnné
   4:   return          // návrat z metody

3. Instrukce bajtkódu sloužící pro ukončení metody s předáním návratové hodnoty této metody

V bajtkódu virtuálního stroje Javy je možné využít několik (konkrétně se jedná o šest) instrukcí sloužících pro ukončení metody, tj. pro výskok z těla metody se současným úklidem zásobníku operandů i zásobníkového rámce popsaného v předchozí kapitole. Kromě úklidu zásobníku operandů tyto instrukce taktéž zajišťují předání návratové hodnoty (pokud ovšem nějaká existuje, tj. pokud návratový typ metody není void) do volající metody (caller method). Zmíněné instrukce jsou většinou generovány překladačem Javy, a to jak na konci zdrojového kódu metody, tak i v těch místech, kde programátor do zdrojového kódu vložil příkaz return výraz. Připomeňme si, že volající metoda si může tuto návratovou hodnotu vyzvednout z vrcholu svého zásobníku operandů (to je zařízeno virtuálním strojem Javy většinou bez nutnosti přesunu těchto hodnot).

Použití dále vypsaných instrukcí typu *return je ostatně jedinou možností, jak může volaná metoda modifikovat obsah zásobníku operandů volající metody – v ostatních případech jsou totiž zásobníky operandů (taktéž i datová oblast s parametry a lokálními proměnnými) obou metod od sebe izolovány, což přispívá jak k větší bezpečnosti práce virtuálního stroje (nelze vytvořit metodu s postranním účinkem), tak i k oddělení jednotlivých částí kódu. Navíc tato vlastnost samozřejmě zjednodušuje práci just-in-time překladače při provádění optimalizací. Ukončení metody s uložením návratové hodnoty zabezpečuje šestice instrukcí *return, která je vypsaná v následující tabulce:

# Instrukce Opkód Datový typ na TOS Prováděná operace
1 ireturn 0×AC int získání návratové hodnoty typu int z TOS zásobníku operandů + návrat z metody
2 lreturn 0×AD long získání návratové hodnoty typu long z TOS zásobníku operandů + návrat z metody
3 freturn 0×AE float získání návratové hodnoty typu float z TOS zásobníku operandů + návrat z metody
4 dreturn 0×AF double získání návratové hodnoty typu double z TOS zásobníku operandů + návrat z metody
5 areturn 0×B0 reference získání návratové hodnoty typu reference na objekt z TOS zásobníku operandů + návrat z metody
6 return 0×B1 × pouze návrat z metody, žádná hodnota se nevrací

Zkratka TOS znamená Top Of Stack, v tomto případě se jedná o hodnotu uloženou na vrcholu lokálního zásobníku operandů, která je předána do volající metody. Opkód je zkrácenina sousloví „operační kód“, tedy vlastního číselného kódu instrukce v bajtkódu.

4. Podpora JVM TI pro výskok z metody mající návratovou hodnotu i z metody bez návratové hodnoty

Asi nejdůležitější informací, která byla v předchozí kapitole uvedena, je fakt, že i když v Javě existuje celkem osm primitivních datových typů (boolean, char, byte, short, int, long, float a double), je ve skutečnosti možné z metody vrátit hodnoty jen čtyř primitivních datových typů a to konkrétně int, long, float a double s využitím instrukcí ireturn, lreturn, freturn a dreturn.

Je tomu tak z toho důvodu, že celočíselné datové typy byte a short jsou ve většině instrukcí bajtkódu automaticky rozšířeny na typ int (tomu ostatně odpovídá i sémantika Javy, která pro tyto dva datové typy nemá vyhrazenu například ani operaci součtu). Podobná konverze platí i pro zbývající dva typy boolean a char. Další instrukce nazvaná pouze return je použita pro výskok z metody bez návratové hodnoty (void) a poslední, šestou instrukci areturn lze využít pro výskok z metody se současným vrácením reference na objekt (popř. hodnoty null).

Šesti zmíněným instrukcím return, ireturn, lreturn, freturn, dreturn a areturn odpovídá i šestice funkcí nabízených rozhraním JVM TI, které vlastně slouží pro „vnucení“ těchto instrukcí virtuálnímu stroji i v místě, kde bajtkód ve skutečnosti obsahuje zcela odlišnou instrukci. Následuje výpis hlaviček všech šesti JVM TI funkcí.

Vynucení výskoku z metody bez návratové hodnoty (void):

jvmtiError JNICALL ForceEarlyReturnVoid(
    jvmtiEnv* env,
    jthread   thread);

Vynucení výskoku z metody, jejíž návratová hodnota je typu boolean, char, byte, short nebo int:

jvmtiError JNICALL ForceEarlyReturnInt(
    jvmtiEnv* env,
    jthread   thread,
    jint      value);

Vynucení výskoku z metody, jejíž návratová hodnota je typu long:

jvmtiError JNICALL ForceEarlyReturnLong(
    jvmtiEnv* env,
    jthread   thread,
    jlong     value);

Vynucení výskoku z metody, jejíž návratová hodnota je typu float:

jvmtiError JNICALL ForceEarlyReturnFloat(
    jvmtiEnv* env,
    jthread   thread,
    jfloat    value);

Vynucení výskoku z metody, jejíž návratová hodnota je typu double:

jvmtiError JNICALL ForceEarlyReturnDouble(
    jvmtiEnv* env,
    jthread   thread,
    jdouble   value);

Vynucení výskoku z metody, jejíž návratová hodnota je typu reference na objekt (samotná instance třídy=objekt je samozřejmě uložený na haldě/heapu):

jvmtiError JNICALL ForceEarlyReturnObject(
    jvmtiEnv* env,
    jthread   thread,
    jobject   value);

5. Testovací třída použitá třicátým třetím demonstračním JVM TI agentem

Pojďme si nyní ukázat, jakým způsobem je možné JVM TI funkce popsané v předchozí kapitole využít. Následující javovská třída nazvaná Test33 obsahuje šest testovacích metod pojmenovaných voidMethod(), booleanMethod(), intMethod(), longMethod(), floatMethod() a doubleMethod(). Všechny tyto metody při svém zavolání vypíšou na standardní výstup dvě zprávy a pět z těchto metod navíc vrátí volající metodě konstantní návratovou hodnotu:

/**
  * Testovaci trida pouzita pro test tricateho
  * tretiho demonstracniho JVM TI agenta.
  * Agent se pokusi u kazde metody vynutit predcasny navrat.
  */
public class Test33 {
 
    private void voidMethod() {
        System.out.println("voidMethod1");
        System.out.println("voidMethod2");
    }
 
    private boolean booleanMethod() {
        System.out.println("booleanMethod1");
        System.out.println("booleanMethod2");
        return false;
    }
 
    private int intMethod() {
        System.out.println("intMethod1");
        System.out.println("intMethod2");
        return 0;
    }
 
    private long longMethod() {
        System.out.println("longMethod1");
        System.out.println("longMethod2");
        return 0;
    }
 
    private float floatMethod() {
        System.out.println("floatMethod1");
        System.out.println("floatMethod2");
        return 0.0f;
    }
 
    private double doubleMethod() {
        System.out.println("doubleMethod1");
        System.out.println("doubleMethod2");
        return 0.0;
    }
 
    public void run() {
        voidMethod();
        System.out.println(booleanMethod());
        System.out.println(intMethod());
        System.out.println(longMethod());
        System.out.println(floatMethod());
        System.out.println(doubleMethod());
    }
 
    /**
      * Spusteni testu.
      */
    public static void main(String[] args) {
        new Test33().run();
    }
}

6. Nastavení breakpointů pro všechny testované metody

Úkolem dnešního demonstračního JVM TI agenta bude vynutit si předčasné ukončení všech šesti testovacích metod voidMethod(), booleanMethod(), intMethod(), longMethod(), floatMethod() a doubleMethod() s tím, že se z těchto metod vrátí odlišná návratová hodnota, než jaká je zadána ve výrazu umístěného za příkazem return. Pro implementaci dnešního agenta využijeme zdrojový kód agenta popsaného minule, dojde však k několika úpravám. Nejprve musíme nastavit breakpointy do všech šesti zmíněných metod. Přesné umístění jednotlivých breakpointů je uloženo v poli breakpoints, podobně jako tomu bylo i minule:

/*
 * Breakpointy se budou nastavovat celkem pro sest metod.
 */
t_breakpoint breakpoints[] = {
    {"voidMethod",        10},
    {"booleanMethod",     15},
    {"intMethod",         21},
    {"longMethod",        27},
    {"floatMethod",       33},
    {"doubleMethod",      39},
    {NULL,  0}    /* zarazka - je pouzita pri prochazeni timto polem! */
};

Pokud si čísla řádků zapsaná do pole breakpoints porovnáme se zdrojovým kódem testovací třídy Test33, uvidíme, že breakpointy jsou nastaveny vždy na druhý příkaz System.out.println();. Tento příkaz se již ve skutečnosti neprovede, protože dojde k násilnému ukončení metod.

O nastavení breakpointů se postará uživatelská funkce nazvaná set_breakpoint_for_selected_method():

/*
 * 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. Tvar callback funkce callback_on_breakpoint()

Ve chvíli, kdy je všech šest breakpointů zaregistrováno, je možné spustit statickou metodu main demonstrační třídy Test33. Při každém přístupu do jedné ze šesti testovacích metod dojde k zavolání callback funkce nazvané callback_on_breakpoint, v níž se nejprve zjistí jméno a signatura metody s breakpointem a posléze se ze signatury metody zjistí, jaká je její návratová hodnota. Využíváme zde přitom faktu, že všech šest testovacích metod vrací buď hodnotu primitivního datového typu nebo se jedná o metodu typu void. Ve všech těchto případech lze typ návratové hodnoty jednoduše zjistit z posledního znaku signatury. Poněkud složitější je to v případě, že metoda bude vracet referenci (tj. odkaz na instanci nějaké třídy), tuto situaci však prozatím nemusíme řešit:

/*
 * 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       return_type;
    jvmtiError error;
 
    /* veskere operace se budou provadet v kriticke sekci */
    enter_critical_section(jvmti_env);
 
    /* ziskat jmeno metody */
    (*jvmti_env)->GetMethodName(jvmti_env, method, &method_name_ptr, &method_signature_ptr, NULL);
 
    /* ze signatury lze ziskat jmeno navratoveho typu (nepouzivame prozatim objektove typy) */
    return_type = method_signature_ptr[strlen(method_signature_ptr)-1];
 
    /* vypis vsech informaci o vyjimce */
    printf(AGENT_NAME " *** visited breakpoint in method %s with signature %s and return type %c ***\n",
            method_name_ptr,
            method_signature_ptr,
            return_type);
 
    /* vynutime si predcasne ukonceni metod */
    force_early_return(jvmti_env, thread, return_type);
 
    /* dealokace vsech ziskanych pametovych struktur */
    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 method signature");
 
    /* a vystup z kriticke sekce */
    exit_critical_section(jvmti_env);
}

8. Tvar uživatelské funkce force_early_return()

V callback funkci callback_on_breakpoint() popsané v předchozí kapitole se volá uživatelská funkce nazvaná příznačně force_early_return(). Této funkci se předává reference na prostředí JVM TI (to potřebujeme ve všech případech), dále pak identifikátor vlákna, v němž došlo k průchodu breakpointem a konečně se ve třetím parametru předává znak určující návratový typ metody. Právě na základě tohoto znaku se provede rozeskok, který zajistí, že se zavolá korektní varianta JVM TI funkce ForceEarlyReturn*(). Pokud by se totiž například použila funkce ForceEarlyReturnVoid() u metody s návratovým typem int, byla by tato akce zamítnuta jako chyba (kontrolu samozřejmě provádí přímo virtuální stroj Javy):

/*
 * Funkce, ktera zajisti predcasny vyskok z metody
 */
void force_early_return(jvmtiEnv *jvmti_env, jthread thread, char return_type)
{
    jvmtiError error;
    switch (return_type)
    {
        case 'V':
            error = (*jvmti_env)->ForceEarlyReturnVoid(jvmti_env, thread);
            check_jvmti_error(jvmti_env, error, "ForceEarlyReturnVoid");
            break;
        case 'Z':
            error = (*jvmti_env)->ForceEarlyReturnInt(jvmti_env, thread, 1);
            check_jvmti_error(jvmti_env, error, "ForceEarlyReturnInt");
            break;
        case 'I':
            error = (*jvmti_env)->ForceEarlyReturnInt(jvmti_env, thread, 42);
            check_jvmti_error(jvmti_env, error, "ForceEarlyReturnInt");
            break;
        case 'J':
            error = (*jvmti_env)->ForceEarlyReturnLong(jvmti_env, thread, 0x7fffffffffffffffLL);
            check_jvmti_error(jvmti_env, error, "ForceEarlyReturnLong");
            break;
        case 'F':
            error = (*jvmti_env)->ForceEarlyReturnFloat(jvmti_env, thread, 0.5f);
            check_jvmti_error(jvmti_env, error, "ForceEarlyReturnFloat");
            break;
        case 'D':
            error = (*jvmti_env)->ForceEarlyReturnDouble(jvmti_env, thread, 3.1415927);
            check_jvmti_error(jvmti_env, error, "ForceEarlyReturnDouble");
            break;
        default:
            break;
    }
}

9. Spuštění třicátého třetího demonstračního JVM TI agenta

Nyní si již můžeme třicátého třetího demonstračního JVM TI agenta otestovat. Pokud pouze spustíme testovací třídu Test33 bez použití agenta, budou zprávy vypisované na standardní výstup vypadat následovně:

voidMethod1
voidMethod2
 
booleanMethod1
booleanMethod2
false
 
intMethod1
intMethod2
0
 
longMethod1
longMethod2
0
 
floatMethod1
floatMethod2
0.0
 
doubleMethod1
doubleMethod2
0.0

Vidíme, že se v každé metodě skutečně zavolaly oba příkazy System.out.println(); a provedl se i příkaz return (návratová hodnota). Ovšem v případě, že spustíme virtuální stroj Javy i s agentem, bude výstup vypadat značně odlišně:

voidMethod1
 
booleanMethod1
true
 
intMethod1
42
 
longMethod1
9223372036854775807
 
floatMethod1
0.5
 
doubleMethod1
3.1415927

V každé testovací metodě se v tomto případě zavolal pouze první příkaz System.out.println(); a ihned poté došlo v JVM TI agentovi k zavolání callback funkce callback_on_breakpoint(), kde se provedl předčasný výskok z metody.

CS24_early

Pro úplnost si ještě uveďme zprávy vypisované samotným agentem při běhu virtuálního stroje Javy:

Agent33: Agent_OnLoad
Agent33: JVM TI version is correct
Agent33: Got VM init event
Agent33: Class Test33; prepared, setting breakpoints for its methods
Agent33: Found method(): <init> with signature ()V
Agent33: Found method(): main with signature ([Ljava/lang/String;)V
Agent33: Found method(): run with signature ()V
Agent33: Found method(): voidMethod with signature ()V
Agent33: ...going to set breakpoint for this method
Agent33: Found method(): booleanMethod with signature ()Z
Agent33: ...going to set breakpoint for this method
Agent33: Found method(): intMethod with signature ()I
Agent33: ...going to set breakpoint for this method
Agent33: Found method(): longMethod with signature ()J
Agent33: ...going to set breakpoint for this method
Agent33: Found method(): floatMethod with signature ()F
Agent33: ...going to set breakpoint for this method
Agent33: Found method(): doubleMethod with signature ()D
Agent33: ...going to set breakpoint for this method
Agent33: *** visited breakpoint in method voidMethod with signature ()V and return type V ***
Agent33: *** visited breakpoint in method booleanMethod with signature ()Z and return type Z ***
Agent33: *** visited breakpoint in method intMethod with signature ()I and return type I ***
Agent33: *** visited breakpoint in method longMethod with signature ()J and return type J ***
Agent33: *** visited breakpoint in method floatMethod with signature ()F and return type F ***
Agent33: *** visited breakpoint in method doubleMethod with signature ()D and return type D ***
Agent33: ERROR: JVMTI: 34(JVMTI_ERROR_TYPE_MISMATCH): ForceEarlyReturnDouble
Agent33: Got VM Death event
Agent33: Agent_OnUnload

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

V tomto seriálu se již stalo zvykem ukládat všechny zdrojové soubory i pomocné skripty do Mercurial repositáře dostupného na adrese http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/. Výjimku samozřejmě neuděláme ani dnes:

11. 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.