Obsah
1. Čtyři „klasické“ instrukce bajtkódu JVM určené pro volání metod
2. Virtuální stroj Javy a překladače staticky typovaných programovacích jazyků
3. Použití signatur metod při jejich volání
4. Důvody vedoucí k zavedení instrukce invokedynamic
5. Možná řešení problému volání metod v dynamicky typovaných programovacích jazycích
8. Novinky v bajtkódu Javy – nové typy záznamů v constant poolu
1. Čtyři „klasické“ instrukce bajtkódu JVM určené pro volání metod
V závěru předchozí části seriálu o programovacím jazyku Java i o vlastnostech virtuálního stroje tohoto jazyka jsme se zmínili o tom, že v rámci JDK 7 byl instrukční soubor JVM rozšířen o novou instrukci nazvanou příhodně invokedynamic. Zajímavé je, že se tato nová instrukce nevyužívá v samotné Javě, což znamená, že v bajtkódu získaném překladem zdrojových kódů naprogramovaných (čistě) v Javě tuto instrukci nenajdeme. Důvod je jednoduchý – programovací jazyk Java byl a stále zůstává staticky typovaným programovacím jazykem, u nějž překladač při volání jakékoli metody musí vědět, jakého typu jsou parametry této metody a jaký je její návratový typ. Nemusí sice již přesně vědět, metoda jaké třídy se má volat (to kvůli polymorfismu), protože tuto informaci je v mnoha případech možné zjistit až v čase běhu aplikace (v Javě se této vlastnosti poněkud nepřesně říká pozdní vazba – late binding).
Z důvodu podpory polymorfismu, volání statických metod, konstruktorů atd. se všechny metody v Javě volají s využitím jedné z následujících čtyř instrukcí:
# | Instrukce JVM | Opkód | Operandy instrukce | Prováděná operace |
---|---|---|---|---|
1 | invokestatic | 0×B8 | highbyte, lowbyte | zavolání statické metody s předáním parametrů této metodě |
2 | invokevirtual | 0×B6 | highbyte, lowbyte | zavolání nestatické (neprivátní) metody s předáním hodnoty this (první implicitní parametr) a všech dalších explicitně uvedených parametrů |
3 | invokespecial | 0×B7 | highbyte, lowbyte | zavolání konstruktoru, privátní nestatické metody či překryté metody |
4 | invokeinterface | 0×B9 | highbyte, lowbyte, count | zavolání metody deklarované v rozhraní, samozřejmě s předáním parametrů |
Operandy highbyte a lowbyte, které jsou použité u všech čtyř výše uvedených instrukcí, tvoří šestnáctibitový index do constant poolu. Záznam uložený na daném indexu musí být typu Method Reference (MethodRef), což je pro připomenutí záznam obsahující odkaz (index) na další záznam typu Class (jméno třídy či rozhraní, jejíž metoda se má zavolat, odkazuje se na řetězec s názvem třídy) a taktéž na záznam typu Name and Type obsahující signaturu metody. Pro připomenutí je pod tímto odstavcem vypsán obsah constant poolu pro třídu, v níž se s využitím instrukce invokespecial #2 volá metoda void OtherClass.testMethod():
Velikost const. poolu: 18 prvku 1 10 MethodRef 4 12 java/lang/Object.<init>()V * 2 * 10 MethodRef 13--. 14----. OtherClass.testMethod()V 3 7 Class 15 | | Test 4 7 Class 16 | | java/lang/Object 5 1 String | | "<init>" 6 1 String ,-> | | "()V" 7 1 String | | | "Code" 8 1 String | | | "LineNumberTable" 9 1 String | | | "callTestMethod" 10 1 String | | | "SourceFile" 11 1 String | | | "Test.java" 12 12 Name and type | 6 | 5 | ()V <init> 13 7 Class | 17 `---------------> OtherClass 14 12 Name and type `--6 18--. `------> ()V testMethod 15 1 String | "Test" 16 1 String | "java/lang/Object" 17 1 String | "OtherClass" 18 1 String `--------> "testMethod"
2. Virtuální stroj Javy a překladače staticky typovaných programovacích jazyků
Všechny čtyři výše uvedené instrukce zpracovávané virtuálním strojem Javy plně dostačují potřebám tohoto programovacího jazyka, i když se u instrukce invokeinterface používá její poslední parametr count již spíše z historických důvodů. Ovšem v posledních několika letech můžeme sledovat zvýšený zájem tvůrců dalších programovacích jazyků o vytvoření překladačů těchto jazyků do bajtkódu JVM (kromě překladačů vzniklo ještě větší množství různých interpretrů, těmi se však v tomto článku nebudeme prozatím zabývat). Pokud se jedná o staticky typovaný jazyk, neměly by při tvorbě jeho překladače nastat závažnější problémy (pokud tedy daný jazyk přímo nemanipuluje s ukazateli či neprovádí skutečně nízkoúrovňové operace, které nemají přímou podporu v instrukcích JVM) a programátoři-uživatelé tohoto překladače tak mohou s minimálním úsilím získat kvalitní platformu pro vývoj aplikací – bajtkód vytvořený překladačem totiž může být optimalizován a následně přeložen just-in-time překladačem přímo do nativního kódu, virtuální stroj Javy je vybaven několika správci paměti (garbage collector), podporuje běh programu ve více vláknech a hlavní devizou JVM je v neposlední řadě i rozsáhlá standardní knihovna s přesně definovaným rozhraním dodržovaným na všech podporovaných platformách.
Zajímavé je, že virtuální stroj Javy byl navržen takovým způsobem, že vlastně ani nepočítá s tím, že bajtkód prováděný JVM byl skutečně vytvořen překladačem programovacího jazyka Java. Ve skutečnosti je přímo ve specifikaci JVM na několika místech řečeno, že bajtkód může vzniknout v podstatě jakýmkoli způsobem (například může být syntetizován či upraven pomocí nástrojů BCEL či ASM), pouze musí splňovat všechny požadavky na něj kladené (kupodivu je bajtkód v některých ohledech více dynamický než samotná Java :-).
Dobrým příkladem dnes poměrně úspěšného programovacího jazyka těžícího z předností infrastruktury představované virtuálním strojem Javy je programovací jazyk Scala. Aplikace napsané ve Scale jsou překládány přímo do standardního bajtkódu JVM a mohou se tak velmi snadno zaintegrovat do větší javovské aplikace. Ovšem je nutné říci, že Scala je z jazyků dostupných pro JVM spíše výjimkou, protože převažují programovací jazyky dynamicky typované. Tvůrci překladačů těchto programovacích jazyků až donedávna (konkrétně až do poloviny roku 2011) stáli před problémem jak do bajtkódu vytvářeného překladačem vložit instrukce pro volání funkcí či metod. Problém s voláním metod či funkcí u těchto jazyků spočívá v tom, že instrukce invokestatic, invokevirtual, invokespecial ani invokeinterface nelze přímo použít, protože u dynamicky typovaného jazyka není obecně možné v čase překladu určit, která konkrétní metoda se má použít: JVM totiž při volání vyžaduje plnou signaturu metody, tj. její jméno, přesné typy všech parametrů i typ návratové hodnoty.
3. Použití signatur metod při jejich volání
Při použití instrukcí invokestatic, invokevirtual, invokespecial a invokeinterface je navíc nutné mít typy parametrů určené zcela přesně. Nestačí tedy například uvést, že první parametr má být typu float a ve skutečnosti předávat hodnotu typu int – prakticky všechny konverze musí být provedeny explicitně, což JVM testuje při načítání bajtkódu i při jeho vykonávání (některé konverze jsou však za určitých okolností implicitní, například převod byte či short na int, protože datové typy byte a short nejsou „uzavřeny“ vůči většině prováděných operací v JVM). Konverzní instrukce generuje samozřejmě samotný překladač, protože ten již při překladu zná (a musí znát) signatury všech volaných metod. Viz též následující příklad:
public class Test { static int add(int x, int y) { return x+y; } static float add(float x, float y) { return x+y; } static String add(String x, String y) { return x+y; } void test() { int integerValue = 10; float floatValue = 10.0f; // volání metody int add(int, int) // bez konverzí parametrů add(integerValue, integerValue); // volání metody float add(float, float) // bez konverzí parametrů add(floatValue, floatValue); // volání metody float add(float, float) // s konverzí prvního parametru add(integerValue, floatValue); // volání metody float add(float, float) // s konverzí druhého parametru add(floatValue, integerValue); // volání metody String add(String, String) // bez konverzí parametrů add("hello ", "world"); } }
Překladač vždy musí zajistit volání správné konkrétní metody a současně musí zajistit, že jsou této metodě předány parametry mající korektní typ. Proto se metoda test() přeloží následovně:
void test(); Code: 0: bipush 10 2: istore_1 3: ldc #2; //float 10.0f 5: fstore_2 6: iload_1 7: iload_1 // JVM musí znát přesnou signaturu volané metody // (II)I = metoda s dvojicí parametrů int vracející int 8: invokestatic #3; //Method add:(II)I 11: pop 12: fload_2 13: fload_2 // JVM musí znát přesnou signaturu volané metody // (FF)F = metoda s dvojicí parametrů float vracející float 14: invokestatic #4; //Method add:(FF)F 17: pop 18: iload_1 19: i2f // explicitní konverze 20: fload_2 // JVM musí znát přesnou signaturu volané metody // (FF)F = metoda s dvojicí parametrů float vracející float 21: invokestatic #4; //Method add:(FF)F 24: pop 25: fload_2 26: iload_1 27: i2f // explicitní konverze // JVM musí znát přesnou signaturu volané metody // (FF)F = metoda s dvojicí parametrů float vracející float 28: invokestatic #4; //Method add:(FF)F 31: pop 32: ldc #9; //String "hello " 34: ldc #10; //String "world" // JVM musí znát přesnou signaturu volané metody 36: invokestatic #11; //Method add:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; 39: pop 40: return }
4. Důvody vedoucí k zavedení instrukce invokedynamic
Pojďme si nyní ukázat, proč je vlastně zavedení nové instrukce invokedynamic tak důležité – dokonce tak důležité, že tuto instrukci považují někteří programátoři za největší novinku přidanou do JDK 7 (osobně si však myslím, že většina programátorů používajících Javu více ocení některá další rozšíření tohoto jazyka, která byla do JDK 7 přidána). Dejme tomu, že vývojář používající některý dynamicky typovaný programovací jazyk napíše následující funkci (konkrétní syntaxe nyní nehraje prakticky žádnou roli):
define max(x, y) if x.lessThan(y) then return y else return x end
Zápis této funkce ve skutečnosti znamená, že se v jejím těle zavolá nějaká metoda v čase kompilace ještě většinou neznámé třídy x, která je nazvaná lessThan. Této metodě je předán parametr y, jehož datový typ opět není v čase kompilace (compile time) většinou překladači známý. To znamená, že až v čase běhu aplikace (runtime) je možné na základě typů konkrétních parametrů předávaných do funkce max rozhodnout, jaká konkrétní metoda lessThan se bude ve skutečnosti volat. První problém spočívá v tom, že příkaz typu „najdi a zavolej vhodnou metodu lessThan“ není možné přímo implementovat ani jednou ze čtyř výše zmíněných instrukcí typu invoke* (neznáme totiž přesnou signaturu metody, tedy informaci o typech jejích parametrů i o její návratové hodnotě), takže se vývojáři překladačů museli poohlédnout po alternativních způsobech, jak příkaz pro nalezení a zavolání „vhodné“ metody odpovídající předávaným typům implementovat.
Naproti tomu některé další virtuální stroje (VM) již od svého začátku podporují instrukce sloužící pro nalezení vhodné metody a pro její zavolání. Pro ilustraci se podívejme, jak by byl celý problém s metodou add z předchozí kapitoly vyřešený v bajtkódu virtuálního stroje programovacího jazyka Python. Funkce add() by vypadala velmi jednoduše, protože typy obou parametrů x a y i návratový typ se vyhodnocuje až v době běhu programu:
def add(x,y): return x+y
Vzhledem k tomu, že bajtkód jazyka Python (resp. jeho virtuálního stroje) obsahuje – na rozdíl od JVM – vysokoúrovňové instrukce, vypadá přeložená funkce add() následovně:
import dis dis.dis(add) 2 0 LOAD_FAST 0 (x) 3 LOAD_FAST 1 (y) 6 BINARY_ADD 7 RETURN_VALUE
Všechny čtyři instrukce VM Pythonu jsou vlastně polymorfní a manipulují s hodnotami libovolného typu. Může se skutečně jednat o jakékoli objekty, pouze je za běhu kontrolováno, zda je na ně možné aplikovat operátor +, který ve skutečnosti odpovídá volání metody __add__, kterou je možné kdykoli předefinovat. Naopak v případě Javy by se naproti tomu existence vhodné metody __add__ musela kontrolovat již při překladu: to samozřejmě v případě, kdy by jazyk byl rozšířen o možnosti přetížení operátorů (což v podstatě neznamená až tak velký zásah do překladače, jak by se mohlo zdát; prozatím však tato možnost budí poměrně velké rozpaky).
5. Možná řešení problému volání metod v dynamicky typovaných programovacích jazycích
Jednou z možností řešení problému volání metody bez předem známé signatury spočívá v tom, že překladač vytvoří a použije novou třídu, která bude reprezentovat libovolný datový typ, což u mnoha dynamických jazyků kromě pravdivostních hodnot, čísel a řetězců většinou zahrnuje i takové datové typy, jakými jsou pole, seznamy, asociativní pole, n-tice atd.). Metoda lessThan() by v tomto případě jako svůj parametr akceptovala právě instanci této třídy (a sama by byla metodou této třídy), takže by se celý problém mohl alespoň zdánlivě vyřešit, i když by metoda lessThan() ve svém těle musela obsahovat mnoho větví řešících různé kombinace skutečně předaných parametrů (lessThan() aplikovaná na dvojici čísel se bude určitě chovat jinak, než lessThan() aplikovaná na dva řetězce, pole atd.) – obecně se vlastně jedná o obcházení možností, které nám automaticky nabízí OOP a polymorfismus v Javě. Ve skutečnosti se však o zcela obecné řešení nejedná, protože nové metody či funkce definované později uživatelem by nebylo možné volat přímo, ale musela by se použít nějaká „univerzální“ metoda pojmenovaná většinou Invoke či Apply.
Druhé řešení, ke kterému se mohou tvůrci překladačů uchýlit, spočívá ve využití reflection API, konkrétně v použití velmi užitečné třídy java.lang.reflect.Method. V této třídě se kromě dalších metod nachází i metoda nazvaná příhodně invoke. Tuto metodu pravděpodobně nebudou mít skalní zastánci striktně typovaných jazyků příliš v lásce :-) nicméně jde o metodu používanou například v testovacích nástrojích atd. Hlavička metody invoke je následující:
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
Prvním parametrem metody invoke() je instance třídy, jejíž metoda se volá, další parametry pak musí svým typem odpovídat skutečným parametrům metody. Návratovou hodnotou invoke() je samozřejmě návratová hodnota volané metody – tuto hodnotu je nutné většinou explicitně přetypovat.
Následuje velmi jednoduchá ukázka použití invoke():
import java.lang.reflect.*; public class Test { // tato metoda se bude volat přes Method.invoke() public int computeAnswer(Integer x, Integer y) { return x * y; } public static void main(String[] args) { // základem pro práci s reflection API je třída Class Class c = Test.class; try { // pokusíme se nalézt metodu s daným jménem a současně // s daným počtem a typem parametrů - zde lze tyto informace // vyhodnotit až v runtime, nikoli nutně v compile time Method m = c.getMethod("computeAnswer", Integer.class, Integer.class); // zavolání metody pomocí Method.invoke() Object answer = m.invoke(new Test(), Integer.valueOf(6), Integer.valueOf(7)); // převod z Object na Integer nemusíme provádět, je nám totiž jedno, // jak se zavolá answer.toString() System.out.println("Answer is " + answer); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }
Použití Method.invoke() je skutečně pro tvůrce překladače rozumným řešením, ovšem stále zde zůstává jeden problém: v runtime je nutné získat nejenom informace o konkrétním typu objektu (jehož metoda se má volat) i typu parametrů volané metody, ale navíc se ještě musí všechny tyto typy převést na typy (čti objekty) „kompatibilní“ s Javou. Jinými slovy musí být všechny datové typy nabízené daným programovacím jazykem převoditelné na objekty reprezentovatelné v Javě (Integer, String, List atd.). Nejedná se sice o neřešitelnou překážku, nicméně někdy to vede k nutnosti vytváření „paralelní“ hierarchie tříd nahrazujících javovské datové typy, což není optimální z hlediska výpočetního výkonu.
6. Instrukce invokedynamic
Nová instrukce invokedynamic má poměrně složité chování, které se dosti zásadním způsobem odlišuje od zbylých čtyř instrukcí invokestatic, invokevirtual, invokespecial a invokeinterface. Je tomu tak z toho důvodu, že instrukce invokedynamic má programátorům překladače zajistit možnost volby konkrétní metody, která se má spustit v čase běhu aplikace, ovšem na druhou stranu se musí jednat o řešení, které je dostatečně výkonné, aby se při každém volání nemusel stále volat složitý kód pro nalezení volané metody (není bez zajímavosti, že tato „optimalizace“ nebyla do původního návrhu pro invokedynamic zahrnuta, což by však mělo velmi negativní dopad na výkonnost přeloženého kódu).
Z tohoto důvodu pracuje instrukce invokedynamic tak, že se při jejím prvním zavolání z daného místa bajtkódu nejprve vytvoří vazba (link) mezí tímto místem a volanou metodou a při každém dalším volání invokedynamic se již přímo použije slinkovaná metoda (tj. metoda svázaná s tímto výskytem instrukce invokedynamic). Přednosti tohoto řešení jsou zřejmé, když si uvědomíme, že by se například instrukce invokedynamic použila v programové smyčce.
7. Dynamic call site (DCS)
Každá instance instrukce invokedynamic v bajtkódu se nazývá dynamic call site neboli zkráceně DCS (volně lze tento termín pravděpodobně přeložit jako „místo dynamického volání“). Ke každému DCS je přiřazen určitý stav, přičemž ve výchozím stavu není DCS slinkováno s žádnou konkrétní volanou metodou – slinkování se totiž vždy provádí až v čase běhu programu (runtime). Překladač namísto konkrétní metody, která se bude z DCS volat (tuto metodu, jak již víme, obecně nemůže v čase překladu znát) musí pro každé DCS (instanci invokedynamic v bajtkódu) specifikovat takzvanou bootstrap metodu, a to podobným způsobem, jakým se specifikují volané metody u instrukcí invokestatic, invokevirtual, invokespecial a invokeinterface. Kvůli bootstrap metodám se navíc musely specifikovat další typy záznamů ukládaných do constant poolu.
Bootstrap metoda je zavolána ve chvíli, kdy není DCS ještě s ničím slinkována, tj. v okamžiku, kdy virtuální stroj Javy ještě neví, kterou konkrétní metodu má skutečně zavolat. Namísto toho tedy zavolá bootstrap metodu (tu zná – je přímo parametrem instrukce invokedynamic), která zajistí vytvoření kýžené vazby mezi DCS a nějakou vhodnou metodou. Návratovým typem bootstrap metody je totiž objekt, který reprezentuje vazbu (link). Při každém dalším průchodu přes DCS nyní již virtuální stroj Javy nebude volat bootstrap metodu, ale metodu, na níž vede vytvořený link (jakým způsobem jsou tyto linky uloženy v paměti je již věcí vývojářů JVM, konkrétní implementace bootstrap metody naopak trápí vývojáře překladačů).
Následuje (neúplný) příklad toho, jak by mohla bootstrap metoda vypadat. Tento příklad navazuje na příklad s třídou Test a její metodou computeAnswer():
public class InvokeDynamicTest { public static int bootstrapMethod(CallSite site, Object... args) { // MethodHandles.lookup() vrati objekt typu MethodHandles.Lookup // ten nabizi vyhledavaci mechanismus pro metody pres: // MethodHandles.Lookup.findVirtual() // MethodHandles.Lookup.findStatic() // MethodHandles.Lookup.findSpecial() // MethodHandles.Lookup.findConstrutor() // atd. // vyhledavana metoda Test.computeAnswer() je NEstaticka, tudiz virtualni MethodHandle target = MethodHandles.lookup().findVirtual( // trida, ve ktere se provadi hledani metody Test.class, "computeAnswer", // ukazka zpusobu specifikace typu parametru i typu navratove hodnoty: // prvni parametr: typ navratove hodnoty // dalsi parametry: typy parametru metody MethodType.methodType(Integer.class, Integer.class, Integer.class)); // (jedna se o pretizenou metodu, existuje ve vice variantach) // vytvoreni linku site.setTarget(target); // zde se již může zavolat metoda Test.computeAnswer() return (Integer) MethodHandle.invoke(target, site, args); // pokud by metoda vyhazovala nejake vyjimky, mely by se samozrejme // odchytit - MethodHandle.invoke() obecne vyhazuje Throwable, tedy "vse" } }
Registrace bootstrap metody je možné jednoduše provést ve static bloku:
static { Linkage.registerBootstrapMethod("bootstrapMethod"); }
8. Novinky v bajtkódu Javy – nové typy záznamů v constant poolu
V předchozí kapitole jsme si řekli, že v rámci zavádění podpory pro dynamicky typované programovací jazyky došlo i k rozšíření typů záznamů ukládaných do constant poolu. Připomeňme si, že až doposud jsme se seznámili s následujícími typy záznamů používanými od JDK 1.0 až do JDK 6:
Tag | Název tagu | Parametr 1 | Parametr 2 |
---|---|---|---|
1 | Utf8 | délka řetězce v bajtech | sekvence bajtů (počet znaků je obecně menší než počet bajtů) |
3 | Integer | čtyřbajtová celočíselná konstanta | × |
4 | Float | čtyřbajtová FP konstanta | × |
5 | Long | osmibajtová celočíselná konstanta | × |
6 | Double | osmibajtová FP konstanta | × |
8 | String | 2 bajty: odkaz na vlastní řetězec (záznam typu Utf8) | × |
7 | Class | 2 bajty: odkaz na jméno třídy (záznam typu Utf8) | × |
9 | Fieldref | 2 bajty: odkaz na jméno třídy (záznam typu Utf8) | 2 bajty: odkaz na záznam typu NameAndType |
10 | Methodref | 2 bajty: odkaz na jméno třídy (záznam typu Utf8) | 2 bajty: odkaz na záznam typu NameAndType |
11 | InterfaceMethodref | 2 bajty: odkaz na jméno třídy (záznam typu Utf8) | 2 bajty: odkaz na záznam typu NameAndType |
12 | NameAndType | 2 bajty: odkaz na záznam typu Utf8 | 2 bajty: odkaz na záznam typu Utf8 |
Nově se mohou v bajtkódu objevit ještě další tři typy záznamů, které jsou vypsány v následující tabulce:
Tag | Název tagu | Parametr 1 | Parametr 2 |
---|---|---|---|
15 | MethodHandle | typ reference (1–9) | index na Fieldref, Methodref či InterfaceMethodref |
16 | MethodType | odkaz na záznam typu Utf8 obsahující deskriptor metody | × |
18 | InvokeDynamic | index ukazující na bootstrap metodu | index na záznam typu NameAndType |
U záznamu typu InvokeDynamic obsahuje první parametr index do pole vytvořeného pomocí atributu BootstrapMethods_attribute (jedná se o doplňkové informace přidané k bajtkódu). Bližší informace o všech třech nových typech záznamů i způsobu jejich použití si řekneme v některém z následujících částí tohoto seriálu.
9. Odkazy na Internetu
- Java Virtual Machine Support for Non-Java Languages
http://docs.oracle.com/javase/7/docs/technotes/guides/vm/multiple-language-support.html - New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine
http://java.sun.com/developer/technicalArticles/DynTypeLang/ - JSR 223: Scripting for the JavaTM Platform
http://jcp.org/en/jsr/detail?id=223 - JSR 292: Supporting Dynamically Typed Languages on the JavaTM Platform
http://jcp.org/en/jsr/detail?id=292 - Java 7: A complete invokedynamic example
http://niklasschlimm.blogspot.com/2012/02/java-7-complete-invokedynamic-example.html - InvokeDynamic: Actually Useful?
http://blog.headius.com/2007/01/invokedynamic-actually-useful.html - A First Taste of InvokeDynamic
http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html - Java 6 try/finally compilation without jsr/ret
http://cliffhacks.blogspot.com/2008/02/java-6-tryfinally-compilation-without.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 - Root.cz: Využití komprimovaných ukazatelů na objekty v JVM
http://www.root.cz/clanky/vyuziti-komprimovanych-ukazatelu-na-objekty-v-nbsp-jvm/ - Root.cz: JamVM aneb alternativa k HotSpotu nejenom pro embedded zařízení a chytré telefony
http://www.root.cz/clanky/jamvm-aneb-alternativa-k-hotspotu-nejenom-pro-embedded-zarizeni-tablety-a-chytre-telefony/ - The JavaTM Virtual Machine Specification, Second Edition
http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.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 - BCEL Home page
http://commons.apache.org/bcel/ - BCEL Manual
http://commons.apache.org/bcel/manual.html - Byte Code Engineering Library (Wikipedia)
http://en.wikipedia.org/wiki/BCEL - Java programming dynamics, Part 7: Bytecode engineering with BCEL
http://www.ibm.com/developerworks/java/library/j-dyn0414/ - Bytecode Engineering
http://book.chinaunix.net/special/ebook/Core_Java2_Volume2AF/0131118269/ch13lev1sec6.html - BCEL Tutorial
http://www.smfsupport.com/support/java/bcel-tutorial!/ - ASM Home page
http://asm.ow2.org/ - Seznam nástrojů využívajících projekt ASM
http://asm.ow2.org/users.html - ObjectWeb ASM (Wikipedia)
http://en.wikipedia.org/wiki/ObjectWeb_ASM - Java Bytecode BCEL vs ASM
http://james.onegoodcookie.com/2005/10/26/java-bytecode-bcel-vs-asm/ - Bytecode Outline plugin for Eclipse (screenshoty + info)
http://asm.ow2.org/eclipse/index.html - aspectj (Eclipse)
http://www.eclipse.org/aspectj/ - Aspect-oriented programming (Wikipedia)
http://en.wikipedia.org/wiki/Aspect_oriented_programming - AspectJ (Wikipedia)
http://en.wikipedia.org/wiki/AspectJ - EMMA: a free Java code coverage tool
http://emma.sourceforge.net/ - Cobertura
http://cobertura.sourceforge.net/ - FindBugs
http://findbugs.sourceforge.net/ - GNU Classpath
www.gnu.org/s/classpath/ - Java VMs Compared
http://bugblogger.com/java-vms-compared-160/ - JSRs: Java Specification Requests – JSR 223: Scripting for the Java Platform
http://www.jcp.org/en/jsr/detail?id=223 - Scripting for the Java Platform
http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/ - Scripting for the Java Platform (Wikipedia)
http://en.wikipedia.org/wiki/Scripting_for_the_Java_Platform - Java Community Process
http://en.wikipedia.org/wiki/Java_Specification_Request - Java HotSpot VM Options
http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html - Great Computer Language Shootout
http://c2.com/cgi/wiki?GreatComputerLanguageShootout - Java performance
http://en.wikipedia.org/wiki/Java_performance - Trying the prototype
http://mail.openjdk.java.net/pipermail/lambda-dev/2010-August/002179.html - Better closures (for Java)
http://blogs.sun.com/jrose/entry/better_closures - Lambdas in Java: An In-Depth Analysis
http://www.infoq.com/articles/lambdas-java-analysis - Class ReflectiveOperationException
http://download.java.net/jdk7/docs/api/java/lang/ReflectiveOperationException.html - Proposal: Indexing access syntax for Lists and Maps
http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/001108.html - Proposal: Elvis and Other Null-Safe Operators
http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/000047.html - Java 7 : Oracle pushes a first version of closures
http://www.baptiste-wicht.com/2010/05/oracle-pushes-a-first-version-of-closures/ - Groovy: An agile dynamic language for the Java Platform
http://groovy.codehaus.org/Operators - Better Strategies for Null Handling in Java
http://www.slideshare.net/Stephan.Schmidt/better-strategies-for-null-handling-in-java - Control Flow in the Java Virtual Machine
http://www.artima.com/underthehood/flowP.html - Java Virtual Machine
http://en.wikipedia.org/wiki/Java_virtual_machine - ==, .equals(), compareTo(), and compare()
http://leepoint.net/notes-java/data/expressions/22compareobjects.html - New JDK7 features
http://openjdk.java.net/projects/jdk7/features/ - Project Coin: Bringing it to a Close(able)
http://blogs.sun.com/darcy/entry/project_coin_bring_close - CloseableFinder source code
http://blogs.sun.com/darcy/resource/ProjectCoin/CloseableFinder.java - Joe Darcy blog about JDK
http://blogs.sun.com/darcy - Java 7 – more dynamics
http://www.baptiste-wicht.com/2010/04/java-7-more-dynamics/ - New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine
http://java.sun.com/developer/technicalArticles/DynTypeLang/index.html