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_all_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_all_methods()
Úkolem uživatelské funkce print_local_variables_for_all_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:
- Konstruktor představovaný ve výsledném bajtkódu metodou <init>
- Statická metoda main()
- Nestatické metody nazvané method1() až method9()
- Statické metody nazvané static_method1() až 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:
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.org/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
- Breakpoint (Wikipedia)
http://cs.wikipedia.org/wiki/Breakpoint - JVM Tool Interface Version 1.2 Documentation
http://docs.oracle.com/javase/7/docs/platform/jvmti/jvmti.html - JVM Tool Interface Version 1.2 Documentation – SetBreakpoint
http://docs.oracle.com/javase/6/docs/platform/jvmti/jvmti.html#SetBreakpoint - JVM Tool Interface Version 1.2 Documentation – ClearBreakpoint
http://docs.oracle.com/javase/6/docs/platform/jvmti/jvmti.html#ClearBreakpoint - JVM Tool Interface Version 1.2 Documentation – Breakpoint (callback funkce)
http://docs.oracle.com/javase/6/docs/platform/jvmti/jvmti.html#Breakpoint - The JVM Tool Interface (JVM TI): How VM Agents Work
http://www.oracle.com/technetwork/articles/javase/jvm-ti-141370.html - Creating a Debugging and Profiling Agent with JVMTI
http://www.oracle.com/technetwork/articles/javase/jvmti-136367.html - JVM TI (Wikipedia)
http://en.wikipedia.org/wiki/JVM_TI - IBM JVMTI extensions
http://publib.boulder.ibm.com/infocenter/realtime/v2r0/index.jsp?topic=%2Fcom.ibm.softrt.doc%2Fdiag%2Ftools%2Fjvmti_extensions.html - An empirical study of Java bytecode programs
http://www.mendeley.com/research/an-empirical-study-of-java-bytecode-programs/ - Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
http://www.mobilefish.com/tutorials/java/java_quickguide_jvm_instruction_set.html - The JVM Instruction Set
http://mpdeboer.home.xs4all.nl/scriptie/node14.html - Control Flow in the Java Virtual Machine
http://www.artima.com/underthehood/flowP.html - The class File Format
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html - javap – The Java Class File Disassembler
http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javap.html - javap-java-1.6.0-openjdk(1) – Linux man page
http://linux.die.net/man/1/javap-java-1.6.0-openjdk - Using javap
http://www.idevelopment.info/data/Programming/java/miscellaneous_java/Using_javap.html - Examine class files with the javap command
http://www.techrepublic.com/article/examine-class-files-with-the-javap-command/5815354 - Bytecode Engineering
http://book.chinaunix.net/special/ebook/Core_Java2_Volume2AF/0131118269/ch13lev1sec6.html