Pohled pod kapotu JVM - instrukce invokedynamic

Pavel Tišnovský 5. 6. 2012

V dnešní části seriálu o programovacím jazyku Java i o vlastnostech virtuálního stroje tohoto jazyka se zaměříme na popis nové instrukce nazvané příhodně invokedynamic, která byla do JVM přidána v rámci JDK 7 především z důvodu lepší podpory překladačů dynamicky typovaných programovacích jazyků.

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 ja­zyků

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

6. Instrukce invokedynamic

7. Dynamic call site (DCS)

8. Novinky v bajtkódu Javy – nové typy záznamů v constant poolu

9. Odkazy na Internetu

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.tes­tMethod():

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 ja­zyků

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.reflec­t.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:

widgety

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 InterfaceMetho­dref
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 BootstrapMethod­s_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

  1. Java Virtual Machine Support for Non-Java Languages
    http://docs.o­racle.com/java­se/7/docs/techno­tes/guides/vm/mul­tiple-language-support.html
  2. New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine
    http://java.sun­.com/developer/techni­calArticles/Dyn­TypeLang/
  3. JSR 223: Scripting for the JavaTM Platform
    http://jcp.or­g/en/jsr/deta­il?id=223
  4. JSR 292: Supporting Dynamically Typed Languages on the JavaTM Platform
    http://jcp.or­g/en/jsr/deta­il?id=292
  5. Java 7: A complete invokedynamic example
    http://niklas­schlimm.blogspot­.com/2012/02/ja­va-7-complete-invokedynamic-example.html
  6. InvokeDynamic: Actually Useful?
    http://blog.he­adius.com/2007/01­/invokedynamic-actually-useful.html
  7. A First Taste of InvokeDynamic
    http://blog.he­adius.com/2008/09­/first-taste-of-invokedynamic.html
  8. Java 6 try/finally compilation without jsr/ret
    http://cliffhac­ks.blogspot.com/2008/02­/java-6-tryfinally-compilation-without.html
  9. An empirical study of Java bytecode programs
    http://www.men­deley.com/rese­arch/an-empirical-study-of-java-bytecode-programs/
  10. Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
    http://www.mo­bilefish.com/tu­torials/java/ja­va_quickguide_jvm_in­struction_set­.html
  11. The JVM Instruction Set
    http://mpdebo­er.home.xs4all­.nl/scriptie/no­de14.html
  12. Control Flow in the Java Virtual Machine
    http://www.ar­tima.com/under­thehood/flowP­.html
  13. Root.cz: Využití komprimovaných ukazatelů na objekty v JVM
    http://www.ro­ot.cz/clanky/vy­uziti-komprimovanych-ukazatelu-na-objekty-v-nbsp-jvm/
  14. Root.cz: JamVM aneb alternativa k HotSpotu nejenom pro embedded zařízení a chytré telefony
    http://www.ro­ot.cz/clanky/jam­vm-aneb-alternativa-k-hotspotu-nejenom-pro-embedded-zarizeni-tablety-a-chytre-telefony/
  15. The JavaTM Virtual Machine Specification, Second Edition
    http://java.sun­.com/docs/book­s/jvms/second_e­dition/html/VMSp­ecTOC.doc.html
  16. The class File Format
    http://java.sun­.com/docs/book­s/jvms/second_e­dition/html/Clas­sFile.doc.html
  17. javap – The Java Class File Disassembler
    http://docs.o­racle.com/java­se/1.4.2/docs/to­oldocs/window­s/javap.html
  18. javap-java-1.6.0-openjdk(1) – Linux man page
    http://linux.di­e.net/man/1/j­avap-java-1.6.0-openjdk
  19. Using javap
    http://www.ide­velopment.info/da­ta/Programmin­g/java/miscella­neous_java/Usin­g_javap.html
  20. Examine class files with the javap command
    http://www.techre­public.com/ar­ticle/examine-class-files-with-the-javap-command/5815354
  21. BCEL Home page
    http://common­s.apache.org/bcel/
  22. BCEL Manual
    http://common­s.apache.org/bcel/ma­nual.html
  23. Byte Code Engineering Library (Wikipedia)
    http://en.wiki­pedia.org/wiki/BCEL
  24. Java programming dynamics, Part 7: Bytecode engineering with BCEL
    http://www.ib­m.com/developer­works/java/li­brary/j-dyn0414/
  25. Bytecode Engineering
    http://book.chi­naunix.net/spe­cial/ebook/Co­re_Java2_Volu­me2AF/0131118269/ch13lev­1sec6.html
  26. BCEL Tutorial
    http://www.smfsup­port.com/suppor­t/java/bcel-tutorial!/
  27. ASM Home page
    http://asm.ow2­.org/
  28. Seznam nástrojů využívajících projekt ASM
    http://asm.ow2­.org/users.html
  29. ObjectWeb ASM (Wikipedia)
    http://en.wiki­pedia.org/wiki/Ob­jectWeb_ASM
  30. Java Bytecode BCEL vs ASM
    http://james.o­negoodcookie.com/2005/10­/26/java-bytecode-bcel-vs-asm/
  31. Bytecode Outline plugin for Eclipse (screenshoty + info)
    http://asm.ow2­.org/eclipse/in­dex.html
  32. aspectj (Eclipse)
    http://www.eclip­se.org/aspectj/
  33. Aspect-oriented programming (Wikipedia)
    http://en.wiki­pedia.org/wiki/As­pect_oriented_pro­gramming
  34. AspectJ (Wikipedia)
    http://en.wiki­pedia.org/wiki/As­pectJ
  35. EMMA: a free Java code coverage tool
    http://emma.sou­rceforge.net/
  36. Cobertura
    http://cobertu­ra.sourceforge­.net/
  37. FindBugs
    http://findbug­s.sourceforge­.net/
  38. GNU Classpath
    www.gnu.org/s/clas­spath/
  39. Java VMs Compared
    http://bugblog­ger.com/java-vms-compared-160/
  40. JSRs: Java Specification Requests – JSR 223: Scripting for the Java Platform
    http://www.jcp­.org/en/jsr/de­tail?id=223
  41. Scripting for the Java Platform
    http://java.sun­.com/developer/techni­calArticles/J2SE/Des­ktop/scriptin­g/
  42. Scripting for the Java Platform (Wikipedia)
    http://en.wiki­pedia.org/wiki/Scrip­ting_for_the_Ja­va_Platform
  43. Java Community Process
    http://en.wiki­pedia.org/wiki/Ja­va_Specificati­on_Request
  44. Java HotSpot VM Options
    http://www.ora­cle.com/technet­work/java/java­se/tech/vmopti­ons-jsp-140102.html
  45. Great Computer Language Shootout
    http://c2.com/cgi/wi­ki?GreatCompu­terLanguageSho­otout
  46. Java performance
    http://en.wiki­pedia.org/wiki/Ja­va_performance
  47. Trying the prototype
    http://mail.o­penjdk.java.net/pi­permail/lambda-dev/2010-August/002179.html
  48. Better closures (for Java)
    http://blogs.sun­.com/jrose/en­try/better_clo­sures
  49. Lambdas in Java: An In-Depth Analysis
    http://www.in­foq.com/articles/lam­bdas-java-analysis
  50. Class ReflectiveOpe­rationExcepti­on
    http://downlo­ad.java.net/jdk7/doc­s/api/java/lan­g/ReflectiveO­perationExcep­tion.html
  51. Proposal: Indexing access syntax for Lists and Maps
    http://mail.o­penjdk.java.net/pi­permail/coin-dev/2009-March/001108.html
  52. Proposal: Elvis and Other Null-Safe Operators
    http://mail.o­penjdk.java.net/pi­permail/coin-dev/2009-March/000047.html
  53. Java 7 : Oracle pushes a first version of closures
    http://www.bap­tiste-wicht.com/2010/05­/oracle-pushes-a-first-version-of-closures/
  54. Groovy: An agile dynamic language for the Java Platform
    http://groovy­.codehaus.org/O­perators
  55. Better Strategies for Null Handling in Java
    http://www.sli­deshare.net/Step­han.Schmidt/bet­ter-strategies-for-null-handling-in-java
  56. Control Flow in the Java Virtual Machine
    http://www.ar­tima.com/under­thehood/flowP­.html
  57. Java Virtual Machine
    http://en.wiki­pedia.org/wiki/Ja­va_virtual_machi­ne
  58. ==, .equals(), compareTo(), and compare()
    http://leepoin­t.net/notes-java/data/expres­sions/22compa­reobjects.html
  59. New JDK7 features
    http://openjdk­.java.net/pro­jects/jdk7/fe­atures/
  60. Project Coin: Bringing it to a Close(able)
    http://blogs.sun­.com/darcy/en­try/project_co­in_bring_close
  61. CloseableFinder source code
    http://blogs.sun­.com/darcy/re­source/Projec­tCoin/Closeable­Finder.java
  62. Joe Darcy blog about JDK
    http://blogs.sun­.com/darcy
  63. Java 7 – more dynamics
    http://www.bap­tiste-wicht.com/2010/04­/java-7-more-dynamics/
  64. New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine
    http://java.sun­.com/developer/techni­calArticles/Dyn­TypeLang/index­.html
Našli jste v článku chybu?
Podnikatel.cz: Chystá se smršť legislativních novinek

Chystá se smršť legislativních novinek

Vitalia.cz: Test dětských svačinek: Tyhle ne!

Test dětských svačinek: Tyhle ne!

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

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

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

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

Root.cz: Hořící telefon Samsung Note 7 zapálil auto

Hořící telefon Samsung Note 7 zapálil auto

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

Nejsilnější alergeny jsou pryč

Lupa.cz: Adblock Plus začal prodávat reklamy

Adblock Plus začal prodávat reklamy

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

Jak Ondra o astma přišel

Vitalia.cz: Voda z Vltavy před a po úpravě na pitnou

Voda z Vltavy před a po úpravě na pitnou

Podnikatel.cz: Rohlik.cz testoval roboty pro rozvážku

Rohlik.cz testoval roboty pro rozvážku

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

Nova opět stahuje „milionáře“

Podnikatel.cz: Takhle se prodávají mražené potraviny

Takhle se prodávají mražené potraviny

Lupa.cz: Jak se prodává firma za miliardu?

Jak se prodává firma za miliardu?

DigiZone.cz: Technisat připravuje trojici DAB

Technisat připravuje trojici DAB

Lupa.cz: Patička e-mailu závazná jako vlastnoruční podpis?

Patička e-mailu závazná jako vlastnoruční podpis?

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

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

Lupa.cz: Další Češi si nechali vložit do těla čip

Další Češi si nechali vložit do těla čip

Vitalia.cz: Tahák, jak vyzrát nad zápachem z úst

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

Vitalia.cz: dTest odhalil ten nejlepší kečup

dTest odhalil ten nejlepší kečup

DigiZone.cz: Regionální tele­vize CZ vysílá "Mapu úspěchu"

Regionální tele­vize CZ vysílá "Mapu úspěchu"