Pohled pod kapotu JVM - sledování čtení i zápisu do vybraného atributu třídy či atributu objektu (dokončení)

Pavel Tišnovský 5. 2. 2013

V dnešní části seriálu o jazyce Java a JVM dokončíme téma, jemuž jsme se začali věnovat minule. Na příkladu demonstračního JVM TI agenta si ukážeme, jakým způsobem lze zjistit všechny důležité informace o místech, v nichž dochází ke čtení či naopak k zápisu do vybraného atributu třídy či atributu objektu.

Obsah

1. Zjištění podrobnějších informací o čteném či zapisovaném atributu i o metodě, která k tomuto atributu přistupuje

2. Popis parametrů callback funkce callback_on_field_access()

3. Popis parametrů callback funkce callback_on_field_modification()

4. Demonstrační agent číslo 29 – implementace callback funkcí callback_on_field_access() a callback_on_field_modification()

5. Zjištění jména třídy, k níž atribut náleží a jména sledovaného atributu

6. Zjištění jména třídy a metody, v níž dochází ke čtení či zápisu do sledovaného atributu

7. Přečtení čísla řádku ve volající metodě

8. Přečtení jména zdrojového souboru volající metody

9. Nastavení všech požadavků JVM TI agenta

10. Testovací příklad a výsledek běhu 29. demonstračního JVM TI agenta

11. Zdrojový kód demonstračního agenta a k němu příslušných testovacích příkladů a skriptů

12. Odkazy na Internetu

1. Zjištění podrobnějších informací o čteném či zapisovaném atributu i o metodě, která k tomuto atributu přistupuje

V dnešní části seriálu o programovacím jazyce Java i o vlastnostech virtuálního stroje Javy dokončíme téma, jemuž jsme se začali věnovat již v předchozím dílu. Na příkladu dvacátého devátého demonstračního JVM TI agenta, který bude popsán v navazujících devíti kapitolách, si ukážeme, jakým způsobem je možné zjistit všechny důležité informace o místě (myšleno je v tomto kontextu samozřejmě místo v programovém kódu, tj. třída, metoda a příslušné číslo řádku), v němž dochází ke čtení či naopak k zápisu do vybraného atributu třídy (statického atributu) či k atributu objektu (nestatického atributu).

Rozhraní JVM TI nám při sledování čtení či zápisu do vybraného atributu (či většího množství vybraných atributů) dává k dispozici dvě skupiny údajů – informace o čteném a/nebo zapisovaném atributu (jedná se o třídu, objekt a vlastní atribut, popř. i informace o nově zapisované hodnotě, včetně typu této hodnoty) a taktéž informace o místě, v němž ke čtení či k zápisu do atributu dochází. Oba typy informací tedy musíme umět přečíst a náležitě zpracovat.

2. Popis parametrů callback funkce callback_on_field_access()

Na začátku si připomeňme informaci uvedenou již v předchozí části tohoto seriálu – pro každý atribut, ať již atribut třídy (statický atribut) či atribut objektu, je možné s využitím funkce jvmti_env->SetFieldAccessWatch() zaregistrovat callback funkci volanou ve chvíli, kdy dojde ke čtení hodnoty tohoto atributu, a to nezávisle na tom, odkud je ve skutečnosti atribut čten. V případě veřejně viditelného atributu se může jednat v podstatě o zcela libovolnou část aplikace, naopak u atributů privátních se bude jednat o metody ze stejné třídy, k níž sledovaný atribut náleží. V případě, že je nastaveno sledování většího množství atributů, volá se pro ně shodná callback funkce, budou se však samozřejmě lišit parametry předávané pro každý sledovaný atribut. Volaná callback funkce má následující hlavičku:

/*
 * Callback funkce zavolana pri pristupu (cteni) vybranych atributu.
 */
static void JNICALL callback_on_field_access(
        jvmtiEnv  *jvmti_env,
        JNIEnv    *jni_env,
        jthread    thread,
        jmethodID  method,
        jlocation  location,
        jclass     class,
        jobject    object,
        jfieldID   field)
{
}

V následující tabulce jsou jednotlivé parametry této callback funkce stručně popsány:

# Typ parametru Název parametru Význam
1 jvmtiEnv * jvmti_env JVM TI prostředí agenta (je předáváno do většiny callback funkcí)
2 JNIEnv * jni_env JNI prostředí platné pro dané vlákno (je předáváno do některých callback funkcí)
3 jthread thread vlákno, v němž došlo ke čtení atributu
4 jmethodID method metoda, v níž došlo ke čtení atributu
5 jlocation location řádek v rámci metody, kde došlo ke čtení atributu
6 jclass class třída se sledovaným atributem
7 jobject object objekt, jehož atribut je čten (pokud se jedná o nestatický atribut)
8 jfieldID field identifikátor sledovaného atributu

3. Popis parametrů callback funkce callback_on_field_modification()

Podobná callback funkce registrovaná s využitím jvmti_env->SetFieldModificationWatch() může být zavolána i při zápisu do atributu. Zápis do atributu opět může proběhnout z jakéhokoli místa aplikace. Tato callback funkce má poněkud složitější hlavičku, protože se jí ještě předává informace o nové hodnotě zapisované do atributu, včetně typu této hodnoty:

/*
 * Callback funkce zavolana pri zapisu vybranych atributu
 */
static void JNICALL callback_on_field_modification(
        jvmtiEnv *jvmti_env,
        JNIEnv   *jni_env,
        jthread   thread,
        jmethodID method,
        jlocation location,
        jclass    class,
        jobject   object,
        jfieldID  field,
        char      signature_type,
        jvalue    new_value)
{
}

Opět si popišme význam jednotlivých parametrů této callback funkce:

# Typ parametru Název parametru Význam
1 jvmtiEnv * jvmti_env JVM TI prostředí agenta (je předáváno do většiny callback funkcí)
2 JNIEnv * jni_env JNI prostředí platné pro dané vlákno (je předáváno do některých callback funkcí)
3 jthread thread vlákno, v němž došlo k zápisu do atributu
4 jmethodID method metoda, v níž došlo k zápisu do atributu
5 jlocation location řádek v rámci metody, kde došlo k zápisu
6 jclass class třída se sledovaným atributem
7 jobject object objekt, jehož atribut je čten (pokud se jedná o nestatický atribut)
8 jfieldID field identifikátor sledovaného atributu
9 char signature_type typ zapisované hodnoty
10 jvalue new_value univerzální datová struktura (unie), která může obsahovat hodnotu libovolného typu

4. Demonstrační agent číslo 29 – implementace callback funkcí callback_on_field_access() a callback_on_field_modification()

Vraťme se ještě na chvíli k parametru signature_type předávaného do callback funkce callback_on_field_modification(). V tomto atributu je uloženo celé číslo, které určuje, jaká hodnota je do atributu předávána (zapisována). Hodnota, která může být přes tento parametr předána, je definována výčtovým typem jvmtiPrimitiveType, s nímž jsme se již v tomto seriálu jednou setkali:

typedef enum {
    JVMTI_PRIMITIVE_TYPE_BOOLEAN = 90,
    JVMTI_PRIMITIVE_TYPE_BYTE = 66,
    JVMTI_PRIMITIVE_TYPE_CHAR = 67,
    JVMTI_PRIMITIVE_TYPE_SHORT = 83,
    JVMTI_PRIMITIVE_TYPE_INT = 73,
    JVMTI_PRIMITIVE_TYPE_LONG = 74,
    JVMTI_PRIMITIVE_TYPE_FLOAT = 70,
    JVMTI_PRIMITIVE_TYPE_DOUBLE = 68
} jvmtiPrimitiveType;

Samotný typ jvalue je unií (union) definovanou v hlavičkovém souboru jni.h (nikoli jvmti.h!):

typedef union jvalue {
    jboolean z;
    jbyte    b;
    jchar    c;
    jshort   s;
    jint     i;
    jlong    j;
    jfloat   f;
    jdouble  d;
    jobject  l;
} jvalue;

Pojďme si nyní v této kapitole i v navazujících kapitolách popsat jednotlivé části, z nichž se bude skládat dvacátý devátý demonstrační JVM TI agent. Nejprve je nastaveno sledování čtení a zápisu do atributu nazvaného jednoduše i třídy MyInteger, a to naprosto stejným způsobem, jaký jsme si ukazovali již v předchozí části tohoto seriálu. Obě zaregistrované callback funkce mají velmi podobné tělo, v němž se pouze zavolá společná uživatelská funkce, která se postará a výpis všech potřebných informací:

/*
 * Callback funkce zavolana pri pristupu (cteni) vybranych atributu
 */
static void JNICALL callback_on_field_access(
        jvmtiEnv  *jvmti_env,
        JNIEnv    *jni_env,
        jthread    thread,
        jmethodID  method,
        jlocation  location,
        jclass     class,
        jobject    object,
        jfieldID   field)
{
    print_field_info(jvmti_env, jni_env, READ, method, location, class, object, field, 0);
}

U callback funkce volané při zápisu do vybraného atributu si dovolíme malé zjednodušení – dopředu již víme, že se sleduje atribut typu integer, tudíž je možné z unie new_value přímo získat hodnotu new_value.i. Obecně to však není možné a v reálných agentech by se musel provést rozeskok na základě hodnoty uložené v parametru signature_type:

/*
 * Callback funkce zavolana pri zapisu vybranych atributu
 */
static void JNICALL callback_on_field_modification(
        jvmtiEnv *jvmti_env,
        JNIEnv   *jni_env,
        jthread   thread,
        jmethodID method,
        jlocation location,
        jclass    class,
        jobject   object,
        jfieldID  field,
        char signature_type,
        jvalue new_value)
{
    int value = (int)new_value.i;
    printf("%d\n", signature_type);
    print_field_info(jvmti_env, jni_env, WRITE, method, location, class, object, field, value);
}

Hodnoty READ a WRITE jsou konstanty definované ve výčtovém typu:

/*
 * Typ pristupu k atributu - cteni ci zapis.
 */
typedef enum
{
    READ,
    WRITE
} FieldAccessMode;

5. Zjištění jména třídy, k níž atribut náleží a jména sledovaného atributu

V předchozí kapitole jsme si řekli, že obě callback funkce volají jedinou „univerzální“ funkci print_field_info(), v níž se získají a následně vypíšou informace o sledovaném atributu i informace o kódu, z něhož je atribut čten a/nebo modifikován. První informací, kterou je nutné vypsat, je jméno třídy a jméno sledovaného atributu („sledovací“ callback funkce totiž mohou být registrovány pro větší množství atributů). Jméno třídy a jméno atributu lze zjistit velmi jednoduše, můžeme totiž použít nám již známou dvojici JVM TI funkcí jvmti->GetClassSignature() a jvmti->GetFieldName(). U obou funkcí je samozřejmě vhodné kontrolovat, zda při jejich volání nedošlo k nějaké chybě (ta je většinou způsobena tím, že nejsou správně nastaveny požadované vlastnosti agenta). Vzhledem k tomu, že obě zmíněné JVM TI funkce vrací řetězce alokované uvnitř JVM TI, je nutné oba řetězce explicitně dealokovat s použitím funkce jvmti->Deallocate():

/* lokalni retezce */
char *class_name;
char *updated_class_name;
char *field_name;
 
/* ziskat jmeno tridy */
error = (*jvmti_env)->GetClassSignature(jvmti_env, class, &class_name, NULL);
check_jvmti_error(jvmti_env, error, "GetClassSignature() failed");
 
/* ziskat jmeno atributu */
error = (*jvmti_env)->GetFieldName(jvmti_env, class, field, &field_name, NULL, NULL);
check_jvmti_error(jvmti_env, error, "GetFieldName() failed");
 
/* upravit jmeno tridy s atributem */
updated_class_name = update_class_name(class_name, '.');
 
...
...
...
 
/* dealokace retezce s nazvem tridy */
error = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char*)class_name);
check_jvmti_error(jvmti_env, error, "deallocate class name");
 
/* dealokace retezce s nazvem atributu */
error = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char*)field_name);
check_jvmti_error(jvmti_env, error, "deallocate field name");

Funkci update_class_name() používanou pro úpravu jména třídy do čitelnějšího tvaru již známe z mnoha dalších demonstračních JVM TI agentů:

/*
 * Uprava jmena tridy pro tisk.
 */
char* update_class_name(char *class_name_ptr, char replace_to)
{
    char *class_name_ptr_;
    char *c;
    if (class_name_ptr != NULL)
    {
        /* odstraneni pocatecniho L na zacatku jmena tridy */
        class_name_ptr_ = class_name_ptr;
        if (class_name_ptr_[0] == 'L')
        {
            class_name_ptr_++;
        }
        /* nahrada znaku ; za tecku ci jiny definovany znak */
        char *last_char = class_name_ptr_ + strlen(class_name_ptr_) - 1;
        if (*last_char == ';')
        {
            *last_char = replace_to;
        }
        /* nahrada vsech znaku '/' za '.' */
        c = class_name_ptr_;
        for (c = class_name_ptr_; *c != 0; c++)
        {
            if (*c == '/') *c = '.';
        }
    }
    return class_name_ptr_;
}

6. Zjištění jména třídy a metody, v níž dochází ke čtení či zápisu do sledovaného atributu

Dále by měl náš demonstrační JVM TI agent umět vypsat všechny dostupné informace o kódu, v němž je sledovaný atribut čten či kde jsou do něj zapisovány nové hodnoty. Všechny potřebné údaje o tomto kódu nám rozhraní JVM TI samozřejmě nabízí v parametrech obou callback funkcí, my pouze musíme tyto údaje vhodným způsobem využít a zpracovat. Jméno volající metody lze získat pomocí JVM TI funkce jvmti->GetMethodName() a následně můžeme s využitím funkce jvmti->GetMethodDeclaringClass() získat identifikátor představující třídu, v níž je tato metoda deklarována. Získání jména třídy je pak již jednoduché, protože postačuje zavolat funkci jvmti->GetClassSignature(). Po využití všech tří řetězců samozřejmě opět nesmíme zapomenout na jejich dealokaci pomocí funkce jvmti->Deallocate(), podobně jako tomu bylo u řetězců získaných funkcemi popsanými v předchozí kapitole:

char *method_name;
char *declaring_class_name;
char *updated_declaring_class_name;
 
/* ziskat jmeno volajici metody i jeji tridu */
error = (*jvmti_env)->GetMethodName(jvmti_env, method, &method_name, NULL, NULL);
check_jvmti_error(jvmti_env, error, "GetMethodName() failed");
 
error = (*jvmti_env)->GetMethodDeclaringClass(jvmti_env, method, &declaring_class);
check_jvmti_error(jvmti_env, error, "GetMethodDeclaringClass() failed");
 
/* tridu jiz zname, takze muzeme ziskat jeji jmeno (signaturu) */
error = (*jvmti_env)->GetClassSignature(jvmti_env, declaring_class, &declaring_class_name, NULL);
check_jvmti_error(jvmti_env, error, "GetClassSignature() failed");
 
/* upravit jmeno volajici tridy */
updated_declaring_class_name = update_class_name(declaring_class_name, '.');
 
...
...
...
 
/* dealokace retezce s nazvem tridy */
error = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char*)class_name);
check_jvmti_error(jvmti_env, error, "deallocate class name");
 
/* dealokace retezce s nazvem atributu */
error = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char*)field_name);
check_jvmti_error(jvmti_env, error, "deallocate field name");

7. Přečtení čísla řádku ve volající metodě

Zbývá nám ještě získat informaci o čísle řádku v rámci metody, v níž se provádí čtení či naopak zápis do sledovaného atributu:

/* na kterem radku je atribut menen */
line_number = get_line_number(jvmti_env, method, location);

Pro získání tabulky obsahující převodní informace mezi hodnotou location a skutečným číslem řádku použijeme JVM TI funkci jvmti->GetLineNumberTable():

jvmtiError JNICALL GetLineNumberTable (
    jvmtiEnv* env,
    jmethodID method,
    jint* entry_count_ptr,
    jvmtiLineNumberEntry** table_ptr);

Uživatelskou funkci provádějící převod hodnoty location na číslo řádku již známe, protože jsme ji použili již v několika předchozích JVM TI agentech:

/*
 * Ziskani cisla radku pro zadanou metodu a index instrukce.
 */
int get_line_number(jvmtiEnv *jvmti_env, jmethodID method, jlocation location)
{
    int count;
    int line_number = 0;
    int i;
    jvmtiLineNumberEntry *location_table;
    jvmtiError error_code;
 
    if (method == NULL)
    {
        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 nepodari */
    if (error_code != JVMTI_ERROR_NONE)
    {
        return -1;
    }
 
    /* projit celou tabulkou */
    for (i = 0; i < count - 1; i++)
    {
        jvmtiLineNumberEntry entry1 = location_table[i];
        jvmtiLineNumberEntry entry2 = location_table[i+1];
        /* pokud se lokace nachazi mezi entry1 (vcetne) a entry2 (krome)
         * nasli jsme spravny radek */
        if (location >= entry1.start_location && location < entry2.start_location)
        {
            line_number = entry1.line_number;
            break;
        }
    }
    /* take se muze jednat o uplne posledni instrukci v metode */
    if (location >= location_table[count-1].start_location)
    {
        line_number = location_table[count-1].line_number;
    }
 
    /* dealokace tabulky */
    (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *)location_table);
    return line_number;
}

8. Přečtení jména zdrojového souboru volající metody

Dostáváme se k problematice, kterou jsme se prozatím v tomto seriálu nezabývali. Jedná se o zjištění jména zdrojového kódu, z něhož byla nějaká zvolená třída přeložena. Tato informace je většinou součástí bajtkódu přeložené třídy a lze ji zjistit například s využitím nástroje javap. Podívejme se, jaká informace o zdrojovém kódu se vypíše pro testovací třídy Test29 a MyInteger, které později využijeme současně s dvacátým devátým demonstračním JVM TI agentem. Zajímat nás bude především řádek začínající slovy „Compiled from“:

javac Test29.java
 
javap Test29
 
Compiled from "Test29.java"
public class Test29 extends java.lang.Object{
    public Test29();
    public int foo(int);
    public int bar(int, int);
    public void run(MyInteger);
    public static void main(java.lang.String[]);
}
 
javap MyInteger
 
Compiled from "Test29.java"
class MyInteger extends java.lang.Object{
    public int i;
    public void setValue(int);
    public int getValue();
    public MyInteger(int);
}

Při běhu JVM TI agenta je možné zjistit jméno zdrojového kódu pro danou třídu (reprezentovanou hodnotou typu jclass) s využitím JVM TI funkce jvmti->GetSourceFileName(), jejíž hlavička je velmi jednoduchá:

jvmtiError JNICALL GetSourceFileName (
    jvmtiEnv* env,
    jclass klass,
    char** source_name_ptr);

Využití této funkce je velmi jednoduché – po jejím zavolání by měl být naplněn řetězec, který je do funkce předán přes adresu (řetězec je interně naalokován a je vrácen ukazatel na jeho začátek). Posléze je samozřejmě nutné tento řetězec dealokovat s využitím nám již známé funkce jvmti->Deallocate():

/* ziskat jmeno zdrojoveho souboru volajici metody */
error = (*jvmti_env)->GetSourceFileName(jvmti_env, declaring_class, &source_file_name);
check_jvmti_error(jvmti_env, error, "GetSourceFileName() failed");
 
...
...
...
 
/* dealokace retezce s nazvem atributu */
error = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char*)source_file_name
check_jvmti_error(jvmti_env, error, "deallocate source file name");

9. Nastavení všech požadavků JVM TI agenta

Vzhledem k tomu, že náš demonstrační JVM TI agent potřebuje využít poměrně velké množství vlastností poskytovaných virtuálním strojem Javy, musíme si podporu pro poskytnutí těchto vlastností explicitně vyžádat. Postup je již známý – veškeré nastavení se provede ve funkci set_capabilities(), kde se vyžádají čtyři speciální schopnosti – schopnost zachytit okamžik čtení hodnoty atributu (can_generate_field_access_events), schopnost zachytit okamžik zápisu nové hodnoty do atributu (can_generate_field_modifi­cation_events), získání čísla řádku, resp. převedení hodnoty jlocation na číslo řádku (can_get_line_numbers) a konečně potřebujeme mít možnost získat pro libovolnou třídu jméno zdrojového souboru (can_get_source_file_name):

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

10. Testovací příklad a výsledek běhu 29. demonstračního JVM TI agenta

Všechny důležité součásti dvacátého devátého demonstračního JVM TI agenta, jehož úplný zdrojový kód je uložen do Mercurial repositáře (viz následující kapitolu), jsme si již popsali. Tohoto agenta otestujeme na dvojici javovských tříd MyInteger a Test29. Ve třídě MyInteger je definován veřejný nestatický atribut nazvaný jednoduše i, který je čten i zapisován jak v konstruktoru a metodách vlastní třídy MyInteger, tak i z metod ve třídě Test29:

/**
  * Testovaci tridy pouzite pro test dvacateho
  * devateho demonstracniho JVM TI agenta.
  */
 
class MyInteger {
    public int i;
 
    public void setValue(int i) {
        this.i = i;
    }
 
    public int getValue() {
        return this.i;
    }
 
    public MyInteger(int i) {
        this.i = i;
    }
}
 
public class Test29 {
    public int foo(int x) {
        return x * x;
    }
 
    public int bar(int x, int y) {
        return (x+1) / y;
    }
 
    public void run(MyInteger in) {
        in.i = 10;
        in.i = in.i+1;
        in.i = foo(in.i);
        in.i--;
        in.i = bar(in.i, in.i);
        in.i *= 2;
        in.setValue(6502);
        ++in.i;
        int x = in.getValue();
    }
 
    /**
      * Spusteni testu.
      */
    public static void main(String[] args) {
        new Test29().run(new MyInteger(42));
    }
}

Agent se přeloží podobným způsobem, jako tomu bylo i u všech předchozích demonstračních JVM TI agentů:

gcc -Wall -ansi -I/usr/lib/jvm/java-1.6.0-openjdk/include/ -shared -o libagent29.so agent29.c

Po překladu agenta i obou testovacích tříd je již možné provést spuštění virtuálního stroje Javy a JVM TI agenta k němu připojit:

widgety

java -agentpath:./libagent29.so Test29 2> /dev/null

Agent po svém spuštění vypíše na standardní výstup následující údaje, z nichž lze velmi snadno vyčíst, ve kterém místě je provedeno čtení obsahu atributu MyInteger.i i to, kde a jaká hodnota je do tohoto atributu zapisována. Povšimněte si, že informaci o místě čtení/zápisu do atributu získáme velmi přesně, až na úroveň řádku ve zdrojovém kódu, kde se nachází příslušný příkaz:

Agent29: Agent_OnLoad
Agent29: JVM TI version is correct
Agent29: Got VM init event
Class MyInteger; prepared, setting field monitor
Setting monitors for field #34
Writting     42 value into attribute MyInteger.i.  This operation is called from MyInteger.<init>(Test29.java:18)
Writting     10 value into attribute MyInteger.i.  This operation is called from Test29.run(Test29.java:32)
Reading integer value from attribute MyInteger.i.  This operation is called from Test29.run(Test29.java:33)
Writting     11 value into attribute MyInteger.i.  This operation is called from Test29.run(Test29.java:33)
Reading integer value from attribute MyInteger.i.  This operation is called from Test29.run(Test29.java:34)
Writting    121 value into attribute MyInteger.i.  This operation is called from Test29.run(Test29.java:34)
Reading integer value from attribute MyInteger.i.  This operation is called from Test29.run(Test29.java:35)
Writting    120 value into attribute MyInteger.i.  This operation is called from Test29.run(Test29.java:35)
Reading integer value from attribute MyInteger.i.  This operation is called from Test29.run(Test29.java:36)
Reading integer value from attribute MyInteger.i.  This operation is called from Test29.run(Test29.java:36)
Writting      1 value into attribute MyInteger.i.  This operation is called from Test29.run(Test29.java:36)
Reading integer value from attribute MyInteger.i.  This operation is called from Test29.run(Test29.java:37)
Writting      2 value into attribute MyInteger.i.  This operation is called from Test29.run(Test29.java:37)
Writting   6502 value into attribute MyInteger.i.  This operation is called from MyInteger.setValue(Test29.java:10)
Reading integer value from attribute MyInteger.i.  This operation is called from Test29.run(Test29.java:39)
Writting   6503 value into attribute MyInteger.i.  This operation is called from Test29.run(Test29.java:39)
Reading integer value from attribute MyInteger.i.  This operation is called from MyInteger.getValue(Test29.java:14)
Agent29: Got VM Death event
Agent29: Agent_OnUnload

11. Zdrojový kód demonstračního agenta a k němu příslušných testovacích příkladů a skriptů

Zdrojové kódy dvacátého devátého demonstračního JVM TI agenta jsou společně s dvojicí testovacích javovských tříd i se všemi podpůrnými skripty uloženy do Mercurial repositáře, který je dostupný na adrese http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/. Prozatím nejnovější verze všech dnes použitých souborů můžete nalézt na následujících adresách:

12. Odkazy na Internetu

  1. The JVM Tool Interface (JVM TI): How VM Agents Work
    http://www.oracle.com/technet­work/articles/javase/jvm-ti-141370.html
  2. JVM Tool Interface Version 1.2
    http://docs.oracle.com/ja­vase/7/docs/platform/jvmti/jvmti­.html
  3. Creating a Debugging and Profiling Agent with JVMTI
    http://www.oracle.com/technet­work/articles/javase/jvmti-136367.html
  4. JVM TI (Wikipedia)
    http://en.wikipedia.org/wiki/JVM_TI
  5. 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
  6. An empirical study of Java bytecode programs
    http://www.mendeley.com/research/an-empirical-study-of-java-bytecode-programs/
  7. 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
  8. The JVM Instruction Set
    http://mpdeboer.home.xs4a­ll.nl/scriptie/node14.html
  9. Control Flow in the Java Virtual Machine
    http://www.artima.com/under­thehood/flowP.html
  10. The class File Format
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/Clas­sFile.doc.html
  11. javap – The Java Class File Disassembler
    http://docs.oracle.com/ja­vase/1.4.2/docs/tooldocs/win­dows/javap.html
  12. javap-java-1.6.0-openjdk(1) – Linux man page
    http://linux.die.net/man/1/javap-java-1.6.0-openjdk
  13. Using javap
    http://www.idevelopment.in­fo/data/Programming/java/mis­cellaneous_java/Using_javap­.html
  14. Examine class files with the javap command
    http://www.techrepublic.com/ar­ticle/examine-class-files-with-the-javap-command/5815354
  15. Bytecode Engineering
    http://book.chinaunix.net/spe­cial/ebook/Core_Java2_Volu­me2AF/0131118269/ch13lev1sec6­.html
Našli jste v článku chybu?
Vitalia.cz: Tahák, jak vyzrát nad zápachem z úst

Tahák, jak vyzrát nad zápachem z úst

Podnikatel.cz: Byla finanční manažerka, teď cvičí jógu

Byla finanční manažerka, teď cvičí jógu

DigiZone.cz: Rapl: seriál, který vás smíří s ČT

Rapl: seriál, který vás smíří s ČT

Lupa.cz: Blíží se konec Wi-Fi sítí bez hesla?

Blíží se konec Wi-Fi sítí bez hesla?

Vitalia.cz: Antibakteriální mýdla nepomáhají, spíš škodí

Antibakteriální mýdla nepomáhají, spíš škodí

DigiZone.cz: Světový pohár v přímém přenosu na ČT

Světový pohár v přímém přenosu na ČT

Podnikatel.cz: Letáky? Lidi zuří, ale ony stále fungují

Letáky? Lidi zuří, ale ony stále fungují

Lupa.cz: Cimrman má hry na YouTube i vlastní doodle

Cimrman má hry na YouTube i vlastní doodle

Podnikatel.cz: Nemá dluhy? Zjistíte to na poště

Nemá dluhy? Zjistíte to na poště

DigiZone.cz: DVB-T2 ověřeno: seznam TV zveřejněn

DVB-T2 ověřeno: seznam TV zveřejněn

Vitalia.cz: Tesco nabízí desítky tun jídla zdarma

Tesco nabízí desítky tun jídla zdarma

Vitalia.cz: Jak Ondra o astma přišel

Jak Ondra o astma přišel

DigiZone.cz: Numan Two: rozhlasový přijímač s CD

Numan Two: rozhlasový přijímač s CD

Měšec.cz: TEST: Vyzkoušeli jsme pražské taxikáře

TEST: Vyzkoušeli jsme pražské taxikáře

120na80.cz: Nejsilnější alergeny jsou pryč

Nejsilnější alergeny jsou pryč

Lupa.cz: Proč jsou firemní počítače pomalé?

Proč jsou firemní počítače pomalé?

DigiZone.cz: Nova opět stahuje „milionáře“

Nova opět stahuje „milionáře“

Podnikatel.cz: Tyto pojmy k #EET byste měli znát

Tyto pojmy k #EET byste měli znát

Vitalia.cz: Tradiční čínská medicína a rakovina

Tradiční čínská medicína a rakovina

Vitalia.cz: Muž, který miluje příliš. Ženám neimponuje

Muž, který miluje příliš. Ženám neimponuje