Pohled pod kapotu JVM – přednosti a zápory využití JNI při optimalizacích (2)

Pavel Tišnovský 12. 11. 2013

V dnešní části seriálu o programovacím jazyce Java i o virtuálním stroji Javy budeme pokračovat v popisu rozhraní JNI. Řekneme si, jakým způsobem mohou nativní (céčkové) funkce pracovat s poli vytvořenými v javovské části aplikace a jaké problémy mohou při práci s poli v nativních funkcích nastat.

Obsah

1. Pohled pod kapotu JVM – přednosti a zápory využití JNI při optimalizacích (2)

2. Instrukce bajtkódu JVM určené pro práci s poli

3. Základní JNI funkce pro práci s poli primitivních datových typů

4. První demonstrační příklad: předání pole nativní funkci a zjištění délky pole

5. Překlad a spuštění prvního demonstračního příkladu

6. Získání ukazatele na prvky pole vytvořeného v javovské části aplikace

7. Druhý demonstrační příklad: získání ukazatele na prvky pole a výpočet průměrné hodnoty

8. Problematika práce s poli v nativních funkcích s ohledem na automatickou správu paměti

9. JNI funkce GetPrimitiveArrayCritical()ReleasePrimitiveArrayCritical()

10. Obsah následující části seriálu

11. Repositář se zdrojovými soubory i se skripty pro překlad a spuštění

12. Odkazy na Internetu

1. Pohled pod kapotu JVM – přednosti a zápory využití JNI při optimalizacích (2)

V předchozí části seriálu o jazyce Java i o virtuálním stroji Javy jsme si ukázali základní způsob využití rozhraní JNI (Java Native Interface), díky jehož existenci je možné přímo z Javy relativně jednoduše volat nativní funkce a metody, tj. programový kód, který byl ještě před spuštěním JVM přeložen přímo do strojového kódu cílového mikroprocesoru. Víme již, že volání nativních funkcí z virtuálního stroje Javy je časově poměrně náročné, což znamená, že v mnoha případech ani nemá smysl se snažit o reimplementaci některých částí algoritmů v jazyce C či C++, protože dokonce může nastat situace, kdy bude volání nativního kódu pomalejší než ekvivalentní část algoritmu naprogramovaná přímo v Javě a přeložená JIT překladačem (ať již typu client či častěji typu server). Ovšem samotná zvýšená režie volání nativních funkcí není jediný problém, s nímž se můžeme při použití JNI v praxi setkat.

Další problémy nastávají zejména při předávání parametrů nativním funkcím a metodám. Je totiž nutné zajistit buď kopii těchto parametrů, nebo je nutné příslušné Javovské objekty označit takovým způsobem, aby s nimi nebylo v průběhu spuštění nativní funkce manipulováno například při správě paměti. Tento problém se stává palčivým především ve chvíli, kdy nativní funkce musí manipulovat s polem vytvořeným v Javě. I přes podobnou syntaxi, která je při práci s poli použita v Javě na jedné straně a v jazycích C/C++ na straně druhé, je práce s poli v těchto jazycích odlišná, což si ostatně ukážeme na demonstračních příkladech. V Javě se k prvkům polí nepřistupuje přes ukazatel, dokonce se ani v bajtkódu nemusí složitě počítat adresy jednotlivých prvků. Namísto toho bajtkód JVM obsahuje několik instrukcí, které práci s poli zjednodušují (což je mimochodem jeden z důvodů, proč je práce s poli v mnoha případech velmi efektivní).

2. Instrukce bajtkódu JVM určené pro práci s poli

Pro zajímavost si ukažme, jaké instrukce v bajtkódu JVM jsou určeny pro práci s poli. U instrukcí bez operandů je důležité si uvědomit, že příslušná data (hodnoty, indexy) musí být před zavoláním těchto instrukcí uloženy na zásobníku operandů:

# Instrukce Opkód Operandy Prováděná operace
1 newarray 0×BC arraytype vytvoří nové pole s prvky primitivního datového typu
2 anewarray 0×BD highbyte, lowbyte vytvoří nové pole objektů
3 multianewarray 0×C5 highbyte, lowbyte, dimensions vytvoří vícedimenzionální pole o dimensions dimenzích
         
4 iaload 0×2E × přečtení prvku z pole typu int[]
5 laload 0×2F × přečtení prvku z pole typu long[]
6 faload 0×30 × přečtení prvku z pole typu float[]
7 daload 0×31 × přečtení prvku z pole typu double[]
8 aaload 0×32 × přečtení prvku z pole typu reference[]
9 baload 0×33 × přečtení prvku z pole typu byte[] nebo boolean[]
10 caload 0×34 × přečtení prvku z pole typu char[]
11 saload 0×35 × přečtení prvku z pole typu short[]
         
12 iastore 0×4F × zápis nové hodnoty prvku do pole typu int[]
13 lastore 0×50 × zápis nové hodnoty prvku do pole typu long[]
14 fastore 0×51 × zápis nové hodnoty prvku do pole typu float[]
15 dastore 0×52 × zápis nové hodnoty prvku do pole typu double[]
16 aastore 0×53 × zápis nové hodnoty prvku do pole typu reference[]
17 bastore 0×54 × zápis nové hodnoty prvku do pole typu byte[] nebo boolean[]
18 castore 0×55 × zápis nové hodnoty prvku do pole typu char[]
19 sastore 0×56 × zápis nové hodnoty prvku do pole typu short[]

3. Základní JNI funkce pro práci s poli primitivních datových typů

Rozhraní JNI obsahuje několik funkcí určených pro práci s poli primitivních datových typů, které byly vytvořeny (zkonstruovány) v javovské části aplikace. Před popisem těchto funkcí si však musíme říci, jak se mapují javovské primitivní datové typy (ty jsou nezávislé na platformě) s datovými typy deklarovanými v jni.h. I tyto typy jsou nezávislé na platformě, na rozdíl od základních céčkových datových typů (int, short int, long int…):

# Typ v Javě Typ v JNI Velikost a formát
1 boolean jboolean unsigned 8 bits
2 byte jbyte signed 8 bits
3 char jchar unsigned 16 bits
4 short jshort signed 16 bits
5 int jint signed 32 bits
6 long jlong signed 64 bits
7 float jfloat 32 bits
8 double jdouble 64 bits

Pole jsou do nativních funkcí předávány ve formě speciálního referenčního typu odvozeného od obecného typu pole jarray:

# Typ v Javě Typ v JNI
1 boolean[] jbooleanArray
2 byte[] jbyteArray
3 char[] jcharArray
4 short[] jshortArray
5 int[] jintArray
6 long[] jlongArray
7 float[] jfloatArray
8 double[] jdoubleArray
9 Object[] jobjectArray

Nyní již následuje slíbený seznam základních funkcí použitých v rozhraní JNI pro práci s poli:

# Funkce Význam
1 jsize GetArrayLength(JNIEnv *env, jarray array) vrátí délku pole
     
2 jobjectArray NewObjectArray(JNIEnv *env, jsize len, jclass clazz, jobject init) vytvoří nové pole libovolných objektů
3 jbooleanArray NewBooleanArray(JNIEnv *env, jsize len) vytvoří nové pole s prvky typu boolean
4 jbyteArray NewByteArray(JNIEnv *env, jsize len) vytvoří nové pole s prvky typu byte
5 jcharArray NewCharArray(JNIEnv *env, jsize len) vytvoří nové pole s prvky typu char
6 jshortArray NewShortArray(JNIEnv *env, jsize len) vytvoří nové pole s prvky typu short
7 jintArray NewIntArray(JNIEnv *env, jsize len) vytvoří nové pole s prvky typu int
8 jlongArray NewLongArray(JNIEnv *env, jsize len) vytvoří nové pole s prvky typu long
9 jfloatArray NewFloatArray(JNIEnv *env, jsize len) vytvoří nové pole s prvky typu float
10 jdoubleArray NewDoubleArray(JNIEnv *env, jsize len) vytvoří nové pole s prvky typu double
     
11 jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index) přečtení objektu z pole
12 void SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject val) zápis do pole objektů

Další důležité funkce (pracující s poli prvků primitivních datových typů) si popíšeme v navazujících kapitolách.

4. První demonstrační příklad: předání pole nativní funkci a zjištění délky pole

V dnešním prvním demonstračním příkladu si ukážeme, jakým způsobem je možné do nativní funkce předat javovské pole a jak lze využít JNI pro získání počtu prvků v tomto poli. Příklad je skutečně velmi jednoduchý, protože (prozatím) nepotřebujeme číst ani zapisovat jednotlivé prvky uložené v poli.

JNITest4.java:

/**
 * Jednoduchy test na predavani poli do nativni funkce/metody.
 */
public class JNITest4 {
    // hlavicka ntivni funkce
    native public static int arrayLength(int[] array);

    public static void main(String[] args) {
        // nacist sdilenou knihovnu s nativni funkci arrayLength
        System.loadLibrary("JNITest4");
 
        int[] array = new int[10];
 
        // zavolat nativni funkci
        int length = arrayLength(array);
        System.out.println("Array length = " + length);
    }
}

JNITest4.h (generovaný přes nástroj javah):

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JNITest4 */
 
#ifndef _Included_JNITest4
#define _Included_JNITest4
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     JNITest4
 * Method:    arrayLength
 * Signature: ([I)I
 */
JNIEXPORT jint JNICALL Java_JNITest4_arrayLength
  (JNIEnv *, jclass, jintArray);

#ifdef __cplusplus
}
#endif
#endif

JNITest4.c:

#include "JNITest4.h"
 
JNIEXPORT jint JNICALL Java_JNITest4_arrayLength(JNIEnv *jni_env, jclass klass, jintArray array)
{
    /* ziskat delku pole */
    jint length = (*jni_env)->GetArrayLength(jni_env, (jarray)array);
    return length;
}

Povšimněte si, že všechny JNI funkce je nutné volat přes ukazatel typu JNIEnv*.

5. Překlad a spuštění prvního demonstračního příkladu

Zdrojový kód dnešního prvního demonstračního příkladu se, jak je to běžné, přeloží překladačem javac:

javac JNITest4.java

Následně je nutné vygenerovat hlavičkový soubor JNITest4.h:

javah JNITest4

Následuje překlad souboru JNITest4.c uvedeného v předchozí kapitole, což může v případě Linuxu vypadat následovně (cestu k jni.h a dalším potřebným souborům bude samozřejmě nutné upravit na základě konfigurace konkrétní distribuce Linuxu):

gcc -shared -I/usr/lib/jvm/java-1.7.0-openjdk/include/ -o libJNITest4.so JNITest4.c

Popř. na platformách vyžadujících PIC (position independent code) v knihovnách:

gcc -shared -fPIC -I/usr/lib/jvm/java-1.7.0-openjdk/include/ \
                  -I/usr/lib/jvm/java-1.7.0-openjdk/include/linux \
                  -o libJNITest4.so JNITest4.c

Na systému Windows s nainstalovanou JDK 7 by mohl překlad s využitím mingw vypadat následovně:

gcc -shared -I"c:\Program Files\Java\jdk1.7.0_25\include" -o JNITest4.dll JNITest4.c

V obou případech by měla vzniknout sdílená dynamicky linkovaná knihovna pojmenovaná v závislosti na použitém operačním systému buď libJNITest4.so či JNITest4.dll. Tyto názvy je zapotřebí zkontrolovat a dodržet, protože v případě jejich změny by došlo k chybě při volání System.loadLibrary(„JNITest4“)!

Spuštění testu na Linuxu je snadné:

export LD_LIBRARY_PATH=.
java JNITest4

Na Windows taktéž:

java JNITest4

Pokud překlad i spuštění proběhlo v pořádku, měl by se na standardní výstup vypsat následující řádek:

Array length = 10

6. Získání ukazatele na prvky pole vytvořeného v javovské části aplikace

Když se podíváme na hlavičku nativní funkce JNITest4.arrayLength(), uvidíme, že se pole celých čísel do této funkce předává ve formě parametru typu jintArray:

JNIEXPORT jint JNICALL Java_JNITest4_arrayLength(JNIEnv *jni_env, jclass klass, jintArray array)

My ovšem v programovacím jazyku C či C++ potřebujeme k prvkům pole přistupovat jako k nativním polím, tj. přes ukazatel na první prvek pole. K tomuto účelu lze v rozhraní JNI použít následující osmici funkcí, které kýžený ukazatel vrátí:

# Návratový typ Funkce Popis
1 jboolean * GetBooleanArrayElements(JNIEnv *env, jbooleanArray array, jboolean *isCopy) vrátí ukazatel na první prvek v poli typu boolean[]
2 jbyte * GetByteArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) vrátí ukazatel na první prvek v poli typu byte[]
3 jchar * GetCharArrayElements(JNIEnv *env, jcharArray array, jboolean *isCopy) vrátí ukazatel na první prvek v poli typu char[]
4 jshort * GetShortArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) vrátí ukazatel na první prvek v poli typu short[]
5 jint * GetIntArrayElements(JNIEnv *env, jintArray array, jboolean *isCopy) vrátí ukazatel na první prvek v poli typu int[]
6 jlong * GetLongArrayElements(JNIEnv *env, jlongArray array, jboolean *isCopy) vrátí ukazatel na první prvek v poli typu long[]
7 jfloat * GetFloatArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) vrátí ukazatel na první prvek v poli typu float[]
8 jdouble * GetDoubleArrayElements(JNIEnv *env, jdoubleArray array, jboolean *isCopy) vrátí ukazatel na první prvek v poli typu double[]

Zajímavý je poslední parametr těchto funkcí, jenž je typu jboolean *. Přes tento parametr se budeme moci dozvědět, zda se provedla kopie celého pole či nikoli. O této velmi důležité problematice se ještě zmíním v navazujících kapitolách. V případě, že nás informace o provedené či neprovedené kopii nezajímá, lze do posledního parametru předat hodnotu NULL (potom informaci o kopii nezískáme, což však někdy nemusí vadit).

Důležité je nezapomenout získané pole uvolnit, a to opět s využitím jedné z osmi funkcí deklarovaných v rozhraní JNI. Pokud se totiž při volání Get*ArrayElements celé pole zkopíruje, je nutné je ručně z paměti uvolnit, jinak by došlo k memory leaku (ten většina JVM nedokáže správně detekovat):

# Návratový typ Funkce Popis
1 void ReleaseBooleanArrayElements(JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode) uvolnění pole získaného funkcí GetBooleanArrayElements
2 void ReleaseByteArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) uvolnění pole získaného funkcí GetByteArrayElements
3 void ReleaseCharArrayElements(JNIEnv *env, jcharArray array, jchar *elems, jint mode) uvolnění pole získaného funkcí GetCharArrayElements
4 void ReleaseShortArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) uvolnění pole získaného funkcí GetShortArrayElements
5 void ReleaseIntArrayElements(JNIEnv *env, jintArray array, jint *elems, jint mode) uvolnění pole získaného funkcí GetIntArrayElements
6 void ReleaseLongArrayElements(JNIEnv *env, jlongArray array, jlong *elems, jint mode) uvolnění pole získaného funkcí GetLongArrayElements
7 void ReleaseFloatArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) uvolnění pole získaného funkcí GetFloatArrayElements
8 void ReleaseDoubleArrayElements(JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode) uvolnění pole získaného funkcí GetDoubleArrayElements

V posledním parametru těchto funkcí lze určit, zda se má provést zpětná kopie změněných prvků céčkového (nativního) pole do pole viditelného v javovské části aplikace. Pokud se žádný prvek nezměnil (pole se jen četlo), lze právě tímto parametrem provést optimalizaci a nezatěžovat mikroprocesor zbytečným přesunem dat.

7. Druhý demonstrační příklad: získání ukazatele na prvky pole a výpočet průměrné hodnoty

V dnešním druhém demonstračním příkladu si ukážeme, jak je možné s využitím JNI funkcí popsaných v předchozí kapitole přistupovat k prvkům javovských polí. Úkolem nativní funkce bude vypočítat průměrnou hodnotu všech prvků pole typu float[].

JNITest5.java:

Javovská část aplikace je jednoduchá – pouze vytvoří pole, předá ho do nativní funkce a vytiskne výsledek výpočtu:

/**
 * Test s nativni metodou, ktera vrati prumer hodnot ulozenych
 * v poli.
 */
public class JNITest5 {
    // hlavicka ntivni funkce
    native public static float average(float[] array);
 
    public static void main(String[] args) {
        // nacist sdilenou knihovnu s nativni funkci average()
        System.loadLibrary("JNITest5");
 
        float[] array = {1f, 2f, 3f, 4f, 5f};
 
        // zavolat nativni funkci
        float average = average(array);
        System.out.println("Average = " + average);
    }
}

JNITest5.h (generovaný přes nástroj javah):

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JNITest5 */
 
#ifndef _Included_JNITest5
#define _Included_JNITest5
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     JNITest5
 * Method:    average
 * Signature: ([F)F
 */
JNIEXPORT jfloat JNICALL Java_JNITest5_average
  (JNIEnv *, jclass, jfloatArray);
 
#ifdef __cplusplus
}
#endif
#endif

JNITest5.c:

V nativní části aplikace je nutné nejprve přečíst délku pole, následně získat ukazatel na první prvek, provést výpočet a posléze celé pole uvolnit, aby nedošlo k memory leaku:

#include "JNITest5.h"
 
JNIEXPORT jfloat JNICALL Java_JNITest5_average(JNIEnv *jni_env, jclass klass, jfloatArray array)
{
    jint release_mode = 0; /* JNI_ABORT */
    jboolean is_copy;
    jfloat average = 0;
 
    /* ziskat delku pole */
    jint length = (*jni_env)->GetArrayLength(jni_env, (jarray)array);
 
    /* prevod na "ceckove" pole prvku typu float */
    jfloat *f = (*jni_env)->GetFloatArrayElements(jni_env, array, &is_copy);
 
    /* vypsat informaci o tom, zda muselo byt pole zkopirovano */
    puts(is_copy ? "copy array" : "no copy");
 
    /* pruchod polem a vypocet sumy prvku */
    jfloat *item = f;
    int i;
    for (i=0; i<length; i++, item++)
    {
        average += *item;
    }
 
    /* uvolnit ceckove pole s pripadnou zpetnou kopii prvku */
    (*jni_env)->ReleaseFloatArrayElements(jni_env, array, f, release_mode);
 
    /* vypocet prumeru */
    return average/length;
}

8. Problematika práce s poli v nativních funkcích s ohledem na automatickou správu paměti

Pokud předchozí demonstrační příklad vypsal na standardní výstup následující text:

Average = 3.0
copy array

znamená to, že se při volání JNI funkce GetFloatArrayElements() provedla kopie prvků pole do nově naalokované paměti. Mnoho JVM tuto kopii provádí, a to z toho důvodu, aby se při automatické správě paměti (GC) nemuselo čekat na dokončení nativní funkce. Připomeňme si, že javovské programy nemohou získat ukazatel na žádný objekt, tj. ani na pole, takže si případného přesunu celého pole na jiné místo na haldě „nevšimnou“, což však v žádném případě neplatí pro céčkový program, který již získal ukazatel na pole. Při volání funkce ReleaseFloatArrayElements() se naopak může (ale nemusí) provést zpětná kopie prvků z céčkového pole do pole javovského – vše záleží na posledním parametru této funkce, kde se většinou ponechává nula (provést zpětnou kopii) či konstanta JNI_ABORT (neprovádět kopii).

Poznámka: to, že se provádí kopie prvků pole znamená, že obsah pole viditelného z Javy a z nativní funkce se může lišit a navíc může při uvolňování pole dojít k přepisu pole viditelného z Javy. To se sice může zdát poněkud problematické, ve skutečnosti je však toto chování zcela korektní a případné kolize je nutné ošetřit například synchronizačními mechanismy.

9. JNI funkce GetPrimitiveArrayCritical()ReleasePrimitiveArrayCritical()

Vzhledem k tomu, že se kopie a zpětné kopie pole mohou stát kritickým místem aplikací, v nichž bude docházet k velkému zpomalení, byly do rozhraní JNI přidány další dvě funkce, které mohou (ale nutně nemusí!!!) tento problém řešit. Tyto dvě funkce se jmenují GetPrimitiveArrayCritical()ReleasePrimitiveArrayCritical(), viz též následující tabulku:

# Návratový typ Funkce
1 void * GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy)
2 void ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array, void *carray, jint mode)

Základní sémantika těchto funkcí je shodná se skupinou Get*ArrayElements()Release*ArrayElements(), ovšem s tím rozdílem, že se předpokládá, že kód mezi voláním obou funkcí bude velmi krátký a nebudou se zde volat další JNI funkce, které by například mohly způsobit výjimku atd. Pokud virtuální stroj Javy předpokládá jen (relativně) krátkou dobu běhu nativního kódu mezi GetPrimitiveArrayCritical()ReleasePrimitiveArrayCritical(), může upustit od provedení kopie prvků pole (a popř. navíc pozdržet běh GC). Toto chování ovšem není zaručeno pro všechny implementace JVM, takže je nutné otestovat hodnotu vrácenou přes poslední parametr isCopy, zda ke kopii prvků dochází či nikoli.

Poznámka: povšimněte si, původních funkcí pro získání pole je celkem osm (pro každý primitivní datový typ jedna funkce), zatímco funkce GetPrimitiveArrayCritical() je pouze jediná. To je dosti nesystematické řešení, které pravděpodobně vychází z toho, že funkce GetPrimitiveArrayCritical()ReleasePrimitiveArrayCritical() byly do rozhraní JNI přidány až později.

10. Obsah následující části seriálu

V následující části tohoto seriálu si na benchmarku vyzkoušíme, jak se v praxi bude odlišovat chování nativních funkcí v případě využití dvojice Get*ArrayElements()+Relea­se*ArrayElements() v porovnání s funkcemi GetPrimitiveArrayCritical()+Re­leasePrimitiveArrayCritical(). Taktéž si, podobně jako tomu bylo i v předchozí části tohoto seriálu, porovnáme rychlost nativních funkcí volaných přes JNI s obdobnou metodou implementovanou v Javě. Výsledky budou velmi zajímavé (a nutno říci, že pro nativní funkce nepříliš povzbudivé :-).

widgety

Taktéž nezapomeneme ani na problematiku předávání řetězců do nativních funkcí přes rozhraní JNI, protože i zde může docházet k procesům, které mohou celé využití JNI do značné míry zpomalit. Navíc je nutné si dát pozor na způsob kódování znaků v řetězci i na případné memory leaky, které mohou při použití JNI nastat (tyto memory leaky jsou o to zákeřnější, že řetězce jsou většinou krátké, takže se na případný problém přijde například až poté, co aplikace běží několik týdnů zdánlivě bez chyby).

11. Repositář se zdrojovými soubory i se skripty pro překlad a spuštění

Následuje – v tomto seriálu již tradiční – kapitola s odkazy na zdrojové kódy uložené do Mercurial repositáře. V následující tabulce najdete odkazy na prozatím nejnovější verzi dnes použitých demonstračních příkladů:

# Zdrojový soubor/skript Umístění souboru v repositáři
1 JNITest4.c http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/c78270233554/jit/JNI­Test4/JNITest4.c
2 JNITest4.h http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/c78270233554/jit/JNI­Test4/JNITest4.h
3 JNITest4.java http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/c78270233554/jit/JNI­Test4/JNITest4.java
4 compileJNITest4.sh http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/c78270233554/jit/JNI­Test4/compileJNITest4.sh
5 compileJNITest4.bat http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/c78270233554/jit/JNI­Test4/compileJNITest4.bat
6 runJNITest4.sh http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/c78270233554/jit/JNI­Test4/runJNITest4.sh
7 runJNITest4.bat http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/c78270233554/jit/JNI­Test4/runJNITest4.bat
     
8 JNITest5.c http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/c78270233554/jit/JNI­Test5/JNITest5.c
9 JNITest5.h http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/c78270233554/jit/JNI­Test5/JNITest5.h
10 JNITest5.java http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/c78270233554/jit/JNI­Test5/JNITest5.java
11 compileJNITest5.sh http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/c78270233554/jit/JNI­Test5/compileJNITest5.sh
12 compileJNITest5.bat http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/c78270233554/jit/JNI­Test5/compileJNITest5.bat
13 runJNITest5.sh http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/c78270233554/jit/JNI­Test5/runJNITest5.sh
14 runJNITest5.bat http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/c78270233554/jit/JNI­Test5/runJNITest5.bat

12. Odkazy na Internetu

  1. Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
    http://www.mobilefish.com/tu­torials/java/java_quickgu­ide_jvm_instruction_set.html
  2. The JVM Instruction Set
    http://mpdeboer.home.xs4a­ll.nl/scriptie/node14.html
  3. MultiMedia eXtensions
    http://softpixel.com/~cwrig­ht/programming/simd/mmx.phpi
  4. SSE (Streaming SIMD Extentions)
    http://www.songho.ca/misc/sse/sse­.html
  5. Timothy A. Chagnon: SSE and SSE2
    http://www.cs.drexel.edu/~tc365/mpi-wht/sse.pdf
  6. Intel corporation: Extending the Worldr's Most Popular Processor Architecture
    http://download.intel.com/techno­logy/architecture/new-instructions-paper.pdf
  7. SIMD architectures:
    http://arstechnica.com/ol­d/content/2000/03/simd.ar­s/
  8. GC safe-point (or safepoint) and safe-region
    http://xiao-feng.blogspot.cz/2008/01/gc-safe-point-and-safe-region.html
  9. Safepoints in HotSpot JVM
    http://blog.ragozin.info/2012/10/sa­fepoints-in-hotspot-jvm.html
  10. Java theory and practice: Synchronization optimizations in Mustang
    http://www.ibm.com/develo­perworks/java/library/j-jtp10185/
  11. How to build hsdis
    http://hg.openjdk.java.net/jdk7/hot­spot/hotspot/file/tip/src/sha­re/tools/hsdis/README
  12. Java SE 6 Performance White Paper
    http://www.oracle.com/technet­work/java/6-performance-137236.html
  13. Lukas Stadler's Blog
    http://classparser.blogspot­.cz/2010/03/hsdis-i386dll.html
  14. How to build hsdis-amd64.dll and hsdis-i386.dll on Windows
    http://dropzone.nfshost.com/hsdis.htm
  15. PrintAssembly
    https://wikis.oracle.com/dis­play/HotSpotInternals/Prin­tAssembly
  16. The Java Virtual Machine Specification: 3.14. Synchronization
    http://docs.oracle.com/ja­vase/specs/jvms/se7/html/jvms-3.html#jvms-3.14
  17. The Java Virtual Machine Specification: 8.3.1.4. volatile Fields
    http://docs.oracle.com/ja­vase/specs/jls/se7/html/jls-8.html#jls-8.3.1.4
  18. The Java Virtual Machine Specification: 17.4. Memory Model
    http://docs.oracle.com/ja­vase/specs/jls/se7/html/jls-17.html#jls-17.4
  19. The Java Virtual Machine Specification: 17.7. Non-atomic Treatment of double and long
    http://docs.oracle.com/ja­vase/specs/jls/se7/html/jls-17.html#jls-17.7
  20. Open Source ByteCode Libraries in Java
    http://java-source.net/open-source/bytecode-libraries
  21. ASM Home page
    http://asm.ow2.org/
  22. Seznam nástrojů využívajících projekt ASM
    http://asm.ow2.org/users.html
  23. ObjectWeb ASM (Wikipedia)
    http://en.wikipedia.org/wi­ki/ObjectWeb_ASM
  24. Java Bytecode BCEL vs ASM
    http://james.onegoodcooki­e.com/2005/10/26/java-bytecode-bcel-vs-asm/
  25. BCEL Home page
    http://commons.apache.org/bcel/
  26. Byte Code Engineering Library (před verzí 5.0)
    http://bcel.sourceforge.net/
  27. Byte Code Engineering Library (verze >= 5.0)
    http://commons.apache.org/pro­per/commons-bcel/
  28. BCEL Manual
    http://commons.apache.org/bcel/ma­nual.html
  29. Byte Code Engineering Library (Wikipedia)
    http://en.wikipedia.org/wiki/BCEL
  30. BCEL Tutorial
    http://www.smfsupport.com/sup­port/java/bcel-tutorial!/
  31. Bytecode Engineering
    http://book.chinaunix.net/spe­cial/ebook/Core_Java2_Volu­me2AF/0131118269/ch13lev1sec6­.html
  32. Bytecode Outline plugin for Eclipse (screenshoty + info)
    http://asm.ow2.org/eclipse/index.html
  33. Javassist
    http://www.jboss.org/javassist/
  34. Byteman
    http://www.jboss.org/byteman
  35. Java programming dynamics, Part 7: Bytecode engineering with BCEL
    http://www.ibm.com/develo­perworks/java/library/j-dyn0414/
  36. The JavaTM Virtual Machine Specification, Second Edition
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/VMSpec­TOC.doc.html
  37. The class File Format
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/Clas­sFile.doc.html
  38. javap – The Java Class File Disassembler
    http://docs.oracle.com/ja­vase/1.4.2/docs/tooldocs/win­dows/javap.html
  39. javap-java-1.6.0-openjdk(1) – Linux man page
    http://linux.die.net/man/1/javap-java-1.6.0-openjdk
  40. Using javap
    http://www.idevelopment.in­fo/data/Programming/java/mis­cellaneous_java/Using_javap­.html
  41. Examine class files with the javap command
    http://www.techrepublic.com/ar­ticle/examine-class-files-with-the-javap-command/5815354
  42. aspectj (Eclipse)
    http://www.eclipse.org/aspectj/
  43. Aspect-oriented programming (Wikipedia)
    http://en.wikipedia.org/wi­ki/Aspect_oriented_program­ming
  44. AspectJ (Wikipedia)
    http://en.wikipedia.org/wiki/AspectJ
  45. EMMA: a free Java code coverage tool
    http://emma.sourceforge.net/
  46. Cobertura
    http://cobertura.sourceforge.net/
  47. jclasslib bytecode viewer
    http://www.ej-technologies.com/products/jclas­slib/overview.html
Našli jste v článku chybu?
DigiZone.cz: Numan Two: rozhlasový přijímač s CD

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

Podnikatel.cz: Jak otestovat e-shop. Víte?

Jak otestovat e-shop. Víte?

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

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

Vitalia.cz: Vím, co se učíš, ale netuším, co piješ

Vím, co se učíš, ale netuším, co piješ

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

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

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

Adblock Plus začal prodávat reklamy

DigiZone.cz: Wimbledon na Nova Sport až do 2019

Wimbledon na Nova Sport až do 2019

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

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

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

Jak se prodává firma za miliardu?

Podnikatel.cz: Udělali jsme velkou chybu, napsal Čupr

Udělali jsme velkou chybu, napsal Čupr

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

dTest odhalil ten nejlepší kečup

Podnikatel.cz: ČSSZ posílá přehled o důchodovém kontě

ČSSZ posílá přehled o důchodovém kontě

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

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

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

Nova opět stahuje „milionáře“

Lupa.cz: Jak levné procesory změnily svět?

Jak levné procesory změnily svět?

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

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

DigiZone.cz: Funbox 4K v DVB-T2 má ostrý provoz

Funbox 4K v DVB-T2 má ostrý provoz

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

Takhle se prodávají mražené potraviny

DigiZone.cz: Parlamentní listy: kde končí PR...

Parlamentní listy: kde končí PR...

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

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