SlideShare une entreprise Scribd logo
1  sur  31
BOOSTED JNI
Table des matières
 Présentation et/ou rappel de JNI
 Wrapper C++
 Objectif (quoi)
 Aperçu du code (comment)
 En parallèle
 TypeTrait
 Template Specialization (full, partial)
 Template meta-programming
 SFINAE
 Variadic templates
Durant la présentation…
S’il vous plait
Évitez de poser des questions
…sauf si vous en avez
JNI (Java to Native Interface)
Java
C, C++,
C#,Fortran,
Haskell
(n’importe quel
language qui
supporte la C
calling
convention)
Exemple (Java)
class JniTest
{
/**
Implemented in c++
*/
native boolean nativeMethod(String s);
/**
Called from c++
*/
void javaMethod(int i, float f) {
System.out.println("Hello from native!");
}
static void main(String args) {
new JniTest().nativeMethod("Ni!");
}
static {
System.loadLibrary("MyNativeLibrary");
}
}
Exemple (C++)
JNIEXPORT jboolean JNICALL Java_JniTest_nativeMethod
(JNIEnv* env, jobject obj, jstring s)
{
std::cout << env->GetStringUTFChars(s,0) << std::endl;
jclass clazz = env->FindClass("JniTest");
jmethodID m = env->GetMethodID(clazz, “javaMethod", "(ID)V");
std::thread([=]
{
env->CallStaticObjectMethod(clazz, m, 42, "1.0", 3.14);
}).detach();
return JNI_TRUE;
}
Voyez-vous un bug ?
Et pourtant, ce code compile sans erreur et sans warning!
Solutions existantes
 Générateurs de code
 GIWS
 JACE
 Codemesh JunC++ion
 Wrapper + générateur
 android-cpp-sdk
 Autres (appel de code natif à partir de Java)
 SWIG
 JNIWrapper
L’objectif
 Sans générateur de code
 Sans fichier de configuration
 Sans code d’initialisation
 Sans gras trans
myClass.invoke<void(jint, jfloat)>("javaMethod", 42, 1.0);
Type de la function
Sert à générer la signature JNI
ET à valider la liste des
arguments
Les arguments passés à
la fonction
Le nombre et les types sont
validés à la compilation
Le nom de la
méthode Java
Lance une exception si
elle n’existe pas
Plan de match
1. Génération de la signature JNI (“(IF)V”)
2. Interface d’invocation (invoke())
3. Invocation (env->CallStaticVoidMethod())
Génération de la signature
 Projeter (mapper) un type en string
jint -> "I"
(type) (string)
 Décomposition du function type
void(jint,jfloat) -> Ret = void
P1 = jint
P2 = jfloat
 Bâtir la signature
void(jint, jfloat) -> "(IF)V"
Projeter un type en string
 Solution: TypeTrait
template<class T>
struct JniTypeTrait;
template<> struct JniTypeTrait<jfloat>
{
static const char* signature() {return "F";}
};
template<> struct JniTypeTrait<jint>
{
static const char* signature() {return "I";}
};
// Exemple
const char* signature_int = JniTypeTrait<jint>::signature();
template<> struct JniTypeTrait<void>
{
static const char* signature() {return "V";}
};
// …ainsi de suite pour les autres types
Décomposition du fonction type
Des meta-fonctions ??? Une liste de types ???
typedef boost::mpl::at_c<ParameterTypes, 0>::type P1;
typedef boost::mpl::at_c<ParameterTypes, 1>::type P2;
typedef boost::function_types::parameter_types<F>::type ParameterTypes;
typedef boost::function_types::result_type<F>::type ReturnType;
typedef void(F)(jint, jfloat);
Template Metaprogramming
 Effectuer des calculs par à la compilation
 Les calculs se basent sur des types et des
constantes
 Le résultat est une constante ou du code
 Turing Complete!
 Possible d’effectuer n’importe quelle computation
 Pas de variable!
 Pas de loops. Seulement de la récursion.
 Familiarité avec le paradigme fonctionnel
Exemple: Suite de Fibonacci
template<int n> struct Fibo {
enum {value = Fibo<n-2>::value + Fibo<n-1>::value};
};
template<> struct Fibo<0> {
enum {value = 1};
};
template<> struct Fibo<1> {
enum {value = 1};
};
// Exemples d’utilisation
BOOST_STATIC_ASSERT(Fibo<7>::value == 21);
std::cout << Fibo<12>::value << std::endl;
int array[Fibo<5>::value];
Boost.MPL
// Example #1: vector and push_back
typedef vector<float,double,long double> floats;
typedef push_back<floats,int>::type types;
BOOST_MPL_ASSERT(( is_same< at_c<types,3>::type, int > ));
// Example #2: transform
typedef vector<char, short, int, long, float, double> types;
typedef vector<char*,short*,int*,long*,float*,double*> pointers;
typedef transform< types,boost::add_pointer<_1> >::type result;
BOOST_MPL_ASSERT(( equal<result, pointers> ));
// Example #3: find_if
typedef vector<char,int,unsigned,long,unsigned long> types;
typedef find_if<types, is_same<_1, unsigned> >::type iter;
BOOST_MPL_ASSERT(( is_same< deref<iter>::type, unsigned > ));
BOOST_MPL_ASSERT_RELATION( iter::pos::value, ==, 2 );
Function Type to JNI Signature
std::string buf;
buf += "(";
buf += ")";
buf += JniTypeTrait<ReturnType>::signature();
[&] (auto t) {
buf += JniTypeTrait<decltype(t)>::signature();
}
boost::mpl::for_each<ParameterTypes>(
);
NB: Les polymorphic lambdas (avec auto) ont été introduits dans
C++14 (qui est actuellement en cours de standardisation). Ils sont
disponibles dansVS2013 CTP, GCC 4.9 et Clang 3.4
Plan de match
2. Interface d’invocation (invoke())
Invocation (interface)
 Rappel de l’enjeux:Vérification compile-time
du nombre et du type des arguments
obj.invoke<void(jint, jfloat)>("func", 1); // Error!
obj.invoke<void(jint, jfloat)>("func", 1, 2.0, 3); // Error!
obj.invoke<void(jint, jfloat)>("func", "1", "2.0"); // Error!
obj.invoke<void(jint, jfloat)>("func", 1, 1.0); // OK
Invocation (interface)
template<class F>
typename JniMethod<F>::ReturnType invoke(
const char* methodName
{
// ...
}
template<class F>
typename JniMethod<F>::ReturnType invoke(
const char* methodName,
typename boost::mpl::at_c<typename JniMethod<F>::ParameterTypes, 0>::type p1)
{
// ...
}
template<class F>
typename JniMethod<F>::ReturnType invoke(
const char* methodName,
typename boost::mpl::at_c<typename JniMethod<F>::ParameterTypes, 0>::type p1,
typename boost::mpl::at_c<typename JniMethod<F>::ParameterTypes, 1>::type p2)
{
// ...
}
Question quiz
 Sachant que boost::mpl::at_c<Seq, n> n’est
valide que pour des valeurs de n comprise entre 0
et boost::mpl::size<Seq>::value,
 Comment se peut-il y avoir des overloads de
invoke() pour chaque nombre d’arguments sans
erreur de compilation ?
typedef boost::mpl::vector<int> TypeList;
typedef boost::mpl::at_c<TypeList, 2>::type foo; // Error!
Réponse: SFINAE
 Substitution Failure Is Not An Error
If an invalid argument or return type is formed during the instantiation
of a function template, the instantiation is removed from the overload
resolution set instead of causing a compilation error.
http://boost.org/doc/libs/1_55_0/libs/utility/enable_if.html
 Exemple:
int negate(int i) {
return -i;
}
template<class F>
typename F::result_type negate(const F& f) {
return -f();
}
SFINAE (application)
template<class T>
std::size_t size_in_bits(T t,
typename std::enable_if<std::is_arithmetic<T>>::type* dummy = 0)
{
return 8 * sizeof(T);
}
template<class T>
std::size_t size_in_bits(T t)
{
return 8 * sizeof(T);
}
size_in_bits(42); // 32. OK
size_in_bits(std::string(“yo”)); // 256. OK, mais...?!?
size_in_bits(42); // 32. OK
size_in_bits(std::string(“yo”)); // ERROR. Unable to instantiate template...
Plan de match
3. Invocation (env->CallStaticVoidMethod())
Invocation (implementation)
OK, mais ce n’est pas tout!
CallIntMethod()
Et si ReturnType vaut autre
chose que jint ??
auto r = env_->CallIntMethod(object_, method, p1);
env_.checkException();
return r;
Invocation (variations sur ReturnType)
typedef JniTypeTrait<typename JniMethod<F>::ReturnType> Trait;
((*env_).*Trait::callFunction())
// pointer-to-member-function type (to simplify callFunction() declaration)
typedef jint (JNIEnv::*CallFunctionType)(jobject, jmethodID, ...);
// return the JNIEnv member function to call to return jint
static CallFunctionType callFunction() {return &JNIEnv::CallIntMethod;}
Invocation (cas de ReturnType=void)
Il reste un problème:
auto r = env_->CallVoidMethod(object_, method, p1);
>> ERROR! auto cannot deduce type from void
Invocation (cas de ReturnType=void)
template<class ReturnType, class ParameterTypes>
struct Invoker
{
ReturnType operator()()
{
auto r = ((*env_).*CallFunc_)(object_, method_);
env_.checkException();
return r;
}
};
template<class ParameterTypes>
struct Invoker<void, ParameterTypes>
{
void operator()()
{
env_->CallVoidMethod(object_, method_);
env_.checkException();
}
}; Et les paramètres dans tout ça ?
Invocation (paramètres)
template<class... P>
P... params
params...
Variadic templates ?
Variadic templates
template<class Head, class... Tail>
void print(const Head& head, Tail... tail)
{
std::cout << head << " ";
print(tail...);
}
template<class Head>
void print(const Head& head)
{
std::cout << head << std::endl;
}
// Exemple
print(2, "abc", 3.1415);
// resultat:
// 2 abc 3.1415
Template parameter pack
expansion
Voilà!
 Autres fonctionnalités:
 Gestion des références (locales vs globales)
 Gestion des exceptions
 Scope de fonction et de thread
 Facilitateur pour les Strings
 Surveillez les commits dans Lithium
(git@git.innobec.com:innobec/lithium.git)
obj.invoke<void(jint, jfloat)>("javaMethod", 42, 1.0);
Questions?

Contenu connexe

Tendances

Chapitre5: Classes et objets
Chapitre5: Classes et objetsChapitre5: Classes et objets
Chapitre5: Classes et objetsAziz Darouichi
 
Chapitre 11: Expression Lambda et Référence de méthode en Java
Chapitre 11: Expression Lambda et Référence de méthode en JavaChapitre 11: Expression Lambda et Référence de méthode en Java
Chapitre 11: Expression Lambda et Référence de méthode en JavaAziz Darouichi
 
Chapitre6: Surcharge des opérateurs
Chapitre6:  Surcharge des opérateursChapitre6:  Surcharge des opérateurs
Chapitre6: Surcharge des opérateursAziz Darouichi
 
Les fondamentaux de langage C#
Les fondamentaux de langage C#Les fondamentaux de langage C#
Les fondamentaux de langage C#Youness Boukouchi
 
Cours langage c
Cours langage cCours langage c
Cours langage ccoursuniv
 
C# et .NET : Enigmes et puzzles
C# et .NET : Enigmes  et puzzlesC# et .NET : Enigmes  et puzzles
C# et .NET : Enigmes et puzzlesMicrosoft
 
Cours c#
Cours c#Cours c#
Cours c#zan
 
Formation C# - Cours 2 - Programmation procédurale
Formation C# - Cours 2 - Programmation procéduraleFormation C# - Cours 2 - Programmation procédurale
Formation C# - Cours 2 - Programmation procéduralekemenaran
 
Les nouveautés de C++11 : Ecrire du C++ Moderne
Les nouveautés de C++11 : Ecrire du C++ ModerneLes nouveautés de C++11 : Ecrire du C++ Moderne
Les nouveautés de C++11 : Ecrire du C++ ModerneMicrosoft
 
Développer en natif avec C++11
Développer en natif avec C++11Développer en natif avec C++11
Développer en natif avec C++11Microsoft
 
C1 - Langage C - ISIMA - Première partie
C1 - Langage C - ISIMA - Première partieC1 - Langage C - ISIMA - Première partie
C1 - Langage C - ISIMA - Première partieLoic Yon
 
C++ Metaprogramming : multidimensional typelist
C++ Metaprogramming : multidimensional typelistC++ Metaprogramming : multidimensional typelist
C++ Metaprogramming : multidimensional typelistVincent Agnus
 
Cours de programmation en c
Cours de programmation en cCours de programmation en c
Cours de programmation en cbenouini rachid
 
Corrigés exercices langage C
Corrigés exercices langage CCorrigés exercices langage C
Corrigés exercices langage Ccoursuniv
 
Eléments syntaxiques du langage java-Jihen HEDHLI
Eléments syntaxiques du langage java-Jihen HEDHLIEléments syntaxiques du langage java-Jihen HEDHLI
Eléments syntaxiques du langage java-Jihen HEDHLIJihenHedhli1
 

Tendances (20)

Chapitre5: Classes et objets
Chapitre5: Classes et objetsChapitre5: Classes et objets
Chapitre5: Classes et objets
 
Chapitre 11: Expression Lambda et Référence de méthode en Java
Chapitre 11: Expression Lambda et Référence de méthode en JavaChapitre 11: Expression Lambda et Référence de méthode en Java
Chapitre 11: Expression Lambda et Référence de méthode en Java
 
Programmation en C
Programmation en CProgrammation en C
Programmation en C
 
Chapitre6: Surcharge des opérateurs
Chapitre6:  Surcharge des opérateursChapitre6:  Surcharge des opérateurs
Chapitre6: Surcharge des opérateurs
 
Les fondamentaux de langage C#
Les fondamentaux de langage C#Les fondamentaux de langage C#
Les fondamentaux de langage C#
 
Cours langage c
Cours langage cCours langage c
Cours langage c
 
Le langage C
Le langage CLe langage C
Le langage C
 
C# et .NET : Enigmes et puzzles
C# et .NET : Enigmes  et puzzlesC# et .NET : Enigmes  et puzzles
C# et .NET : Enigmes et puzzles
 
Cours c#
Cours c#Cours c#
Cours c#
 
Formation C# - Cours 2 - Programmation procédurale
Formation C# - Cours 2 - Programmation procéduraleFormation C# - Cours 2 - Programmation procédurale
Formation C# - Cours 2 - Programmation procédurale
 
Les nouveautés de C++11 : Ecrire du C++ Moderne
Les nouveautés de C++11 : Ecrire du C++ ModerneLes nouveautés de C++11 : Ecrire du C++ Moderne
Les nouveautés de C++11 : Ecrire du C++ Moderne
 
Développer en natif avec C++11
Développer en natif avec C++11Développer en natif avec C++11
Développer en natif avec C++11
 
Le langage C
Le langage CLe langage C
Le langage C
 
C1 - Langage C - ISIMA - Première partie
C1 - Langage C - ISIMA - Première partieC1 - Langage C - ISIMA - Première partie
C1 - Langage C - ISIMA - Première partie
 
C++ Metaprogramming : multidimensional typelist
C++ Metaprogramming : multidimensional typelistC++ Metaprogramming : multidimensional typelist
C++ Metaprogramming : multidimensional typelist
 
Cours de programmation en c
Cours de programmation en cCours de programmation en c
Cours de programmation en c
 
Corrigés exercices langage C
Corrigés exercices langage CCorrigés exercices langage C
Corrigés exercices langage C
 
Chapitre2 prog dsplf3
Chapitre2 prog dsplf3Chapitre2 prog dsplf3
Chapitre2 prog dsplf3
 
Polymorphisme
PolymorphismePolymorphisme
Polymorphisme
 
Eléments syntaxiques du langage java-Jihen HEDHLI
Eléments syntaxiques du langage java-Jihen HEDHLIEléments syntaxiques du langage java-Jihen HEDHLI
Eléments syntaxiques du langage java-Jihen HEDHLI
 

Similaire à Boosted Java to Native Interface (JNI)

Lect14 dev2
Lect14 dev2Lect14 dev2
Lect14 dev2moisko
 
Cours de C++ / Tronc commun deuxième année ISIMA
Cours de C++ / Tronc commun deuxième année ISIMACours de C++ / Tronc commun deuxième année ISIMA
Cours de C++ / Tronc commun deuxième année ISIMALoic Yon
 
De java à swift en 2 temps trois mouvements
De java à swift en 2 temps trois mouvementsDe java à swift en 2 temps trois mouvements
De java à swift en 2 temps trois mouvementsDidier Plaindoux
 
Un compilateur... comment ça marche?
Un compilateur... comment ça marche?Un compilateur... comment ça marche?
Un compilateur... comment ça marche?Dinesh Bolkensteyn
 
Interception de signal avec dump de la pile d'appel
Interception de signal avec dump de la pile d'appelInterception de signal avec dump de la pile d'appel
Interception de signal avec dump de la pile d'appelThierry Gayet
 
02 Spécificité du C++ COURS SYS SYSSSSSS
02 Spécificité du C++  COURS SYS SYSSSSSS02 Spécificité du C++  COURS SYS SYSSSSSS
02 Spécificité du C++ COURS SYS SYSSSSSSAyoubElmrabet6
 
Découvrez C# 4.0 et les améliorations apportées à la BCL
Découvrez C# 4.0 et les améliorations apportées à la BCLDécouvrez C# 4.0 et les améliorations apportées à la BCL
Découvrez C# 4.0 et les améliorations apportées à la BCLDotNetHub
 
IMPLEMENTATION EN PYTHON DES CONVENTIONS ALGORITHMIQUES (2022-2023)
IMPLEMENTATION EN PYTHON DES CONVENTIONS ALGORITHMIQUES  (2022-2023)IMPLEMENTATION EN PYTHON DES CONVENTIONS ALGORITHMIQUES  (2022-2023)
IMPLEMENTATION EN PYTHON DES CONVENTIONS ALGORITHMIQUES (2022-2023)Tunisie collège
 
Chap 2--POO avec JAVA.pdf
Chap 2--POO avec JAVA.pdfChap 2--POO avec JAVA.pdf
Chap 2--POO avec JAVA.pdframadanmahdi
 
Algorithmique Amp Programmation (R Sum
Algorithmique  Amp  Programmation (R SumAlgorithmique  Amp  Programmation (R Sum
Algorithmique Amp Programmation (R SumAmy Isleb
 
Seance 3- Programmation en langage C
Seance 3- Programmation en langage C Seance 3- Programmation en langage C
Seance 3- Programmation en langage C Fahad Golra
 
Cours C Avancé chapitre 2 et chapitre.pdf
Cours C Avancé  chapitre 2 et chapitre.pdfCours C Avancé  chapitre 2 et chapitre.pdf
Cours C Avancé chapitre 2 et chapitre.pdfc79024186
 
CPP PTT DE CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CPP PTT DE CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCPP PTT DE CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CPP PTT DE CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCSiratiSoufiane
 

Similaire à Boosted Java to Native Interface (JNI) (20)

Lect14 dev2
Lect14 dev2Lect14 dev2
Lect14 dev2
 
POO-chapitre2.pptx
POO-chapitre2.pptxPOO-chapitre2.pptx
POO-chapitre2.pptx
 
C++ 11/14
C++ 11/14C++ 11/14
C++ 11/14
 
Cours de C++ / Tronc commun deuxième année ISIMA
Cours de C++ / Tronc commun deuxième année ISIMACours de C++ / Tronc commun deuxième année ISIMA
Cours de C++ / Tronc commun deuxième année ISIMA
 
De java à swift en 2 temps trois mouvements
De java à swift en 2 temps trois mouvementsDe java à swift en 2 temps trois mouvements
De java à swift en 2 temps trois mouvements
 
Un compilateur... comment ça marche?
Un compilateur... comment ça marche?Un compilateur... comment ça marche?
Un compilateur... comment ça marche?
 
Interception de signal avec dump de la pile d'appel
Interception de signal avec dump de la pile d'appelInterception de signal avec dump de la pile d'appel
Interception de signal avec dump de la pile d'appel
 
Support programmation orientée objet c# .net version f8
Support programmation orientée objet c#  .net version f8Support programmation orientée objet c#  .net version f8
Support programmation orientée objet c# .net version f8
 
Formation python
Formation pythonFormation python
Formation python
 
POO-chapitre6.pptx
POO-chapitre6.pptxPOO-chapitre6.pptx
POO-chapitre6.pptx
 
02 Spécificité du C++ COURS SYS SYSSSSSS
02 Spécificité du C++  COURS SYS SYSSSSSS02 Spécificité du C++  COURS SYS SYSSSSSS
02 Spécificité du C++ COURS SYS SYSSSSSS
 
Découvrez C# 4.0 et les améliorations apportées à la BCL
Découvrez C# 4.0 et les améliorations apportées à la BCLDécouvrez C# 4.0 et les améliorations apportées à la BCL
Découvrez C# 4.0 et les améliorations apportées à la BCL
 
IMPLEMENTATION EN PYTHON DES CONVENTIONS ALGORITHMIQUES (2022-2023)
IMPLEMENTATION EN PYTHON DES CONVENTIONS ALGORITHMIQUES  (2022-2023)IMPLEMENTATION EN PYTHON DES CONVENTIONS ALGORITHMIQUES  (2022-2023)
IMPLEMENTATION EN PYTHON DES CONVENTIONS ALGORITHMIQUES (2022-2023)
 
Chap 2--POO avec JAVA.pdf
Chap 2--POO avec JAVA.pdfChap 2--POO avec JAVA.pdf
Chap 2--POO avec JAVA.pdf
 
Algorithmique Amp Programmation (R Sum
Algorithmique  Amp  Programmation (R SumAlgorithmique  Amp  Programmation (R Sum
Algorithmique Amp Programmation (R Sum
 
Ch04
Ch04Ch04
Ch04
 
Seance 3- Programmation en langage C
Seance 3- Programmation en langage C Seance 3- Programmation en langage C
Seance 3- Programmation en langage C
 
Cours C Avancé chapitre 2 et chapitre.pdf
Cours C Avancé  chapitre 2 et chapitre.pdfCours C Avancé  chapitre 2 et chapitre.pdf
Cours C Avancé chapitre 2 et chapitre.pdf
 
CPP PTT DE CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CPP PTT DE CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCPP PTT DE CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CPP PTT DE CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
 
C++11
C++11C++11
C++11
 

Boosted Java to Native Interface (JNI)

  • 2. Table des matières  Présentation et/ou rappel de JNI  Wrapper C++  Objectif (quoi)  Aperçu du code (comment)  En parallèle  TypeTrait  Template Specialization (full, partial)  Template meta-programming  SFINAE  Variadic templates
  • 3. Durant la présentation… S’il vous plait Évitez de poser des questions …sauf si vous en avez
  • 4. JNI (Java to Native Interface) Java C, C++, C#,Fortran, Haskell (n’importe quel language qui supporte la C calling convention)
  • 5. Exemple (Java) class JniTest { /** Implemented in c++ */ native boolean nativeMethod(String s); /** Called from c++ */ void javaMethod(int i, float f) { System.out.println("Hello from native!"); } static void main(String args) { new JniTest().nativeMethod("Ni!"); } static { System.loadLibrary("MyNativeLibrary"); } }
  • 6. Exemple (C++) JNIEXPORT jboolean JNICALL Java_JniTest_nativeMethod (JNIEnv* env, jobject obj, jstring s) { std::cout << env->GetStringUTFChars(s,0) << std::endl; jclass clazz = env->FindClass("JniTest"); jmethodID m = env->GetMethodID(clazz, “javaMethod", "(ID)V"); std::thread([=] { env->CallStaticObjectMethod(clazz, m, 42, "1.0", 3.14); }).detach(); return JNI_TRUE; } Voyez-vous un bug ? Et pourtant, ce code compile sans erreur et sans warning!
  • 7. Solutions existantes  Générateurs de code  GIWS  JACE  Codemesh JunC++ion  Wrapper + générateur  android-cpp-sdk  Autres (appel de code natif à partir de Java)  SWIG  JNIWrapper
  • 8. L’objectif  Sans générateur de code  Sans fichier de configuration  Sans code d’initialisation  Sans gras trans myClass.invoke<void(jint, jfloat)>("javaMethod", 42, 1.0); Type de la function Sert à générer la signature JNI ET à valider la liste des arguments Les arguments passés à la fonction Le nombre et les types sont validés à la compilation Le nom de la méthode Java Lance une exception si elle n’existe pas
  • 9. Plan de match 1. Génération de la signature JNI (“(IF)V”) 2. Interface d’invocation (invoke()) 3. Invocation (env->CallStaticVoidMethod())
  • 10. Génération de la signature  Projeter (mapper) un type en string jint -> "I" (type) (string)  Décomposition du function type void(jint,jfloat) -> Ret = void P1 = jint P2 = jfloat  Bâtir la signature void(jint, jfloat) -> "(IF)V"
  • 11. Projeter un type en string  Solution: TypeTrait template<class T> struct JniTypeTrait; template<> struct JniTypeTrait<jfloat> { static const char* signature() {return "F";} }; template<> struct JniTypeTrait<jint> { static const char* signature() {return "I";} }; // Exemple const char* signature_int = JniTypeTrait<jint>::signature(); template<> struct JniTypeTrait<void> { static const char* signature() {return "V";} }; // …ainsi de suite pour les autres types
  • 12. Décomposition du fonction type Des meta-fonctions ??? Une liste de types ??? typedef boost::mpl::at_c<ParameterTypes, 0>::type P1; typedef boost::mpl::at_c<ParameterTypes, 1>::type P2; typedef boost::function_types::parameter_types<F>::type ParameterTypes; typedef boost::function_types::result_type<F>::type ReturnType; typedef void(F)(jint, jfloat);
  • 13. Template Metaprogramming  Effectuer des calculs par à la compilation  Les calculs se basent sur des types et des constantes  Le résultat est une constante ou du code  Turing Complete!  Possible d’effectuer n’importe quelle computation  Pas de variable!  Pas de loops. Seulement de la récursion.  Familiarité avec le paradigme fonctionnel
  • 14. Exemple: Suite de Fibonacci template<int n> struct Fibo { enum {value = Fibo<n-2>::value + Fibo<n-1>::value}; }; template<> struct Fibo<0> { enum {value = 1}; }; template<> struct Fibo<1> { enum {value = 1}; }; // Exemples d’utilisation BOOST_STATIC_ASSERT(Fibo<7>::value == 21); std::cout << Fibo<12>::value << std::endl; int array[Fibo<5>::value];
  • 15. Boost.MPL // Example #1: vector and push_back typedef vector<float,double,long double> floats; typedef push_back<floats,int>::type types; BOOST_MPL_ASSERT(( is_same< at_c<types,3>::type, int > )); // Example #2: transform typedef vector<char, short, int, long, float, double> types; typedef vector<char*,short*,int*,long*,float*,double*> pointers; typedef transform< types,boost::add_pointer<_1> >::type result; BOOST_MPL_ASSERT(( equal<result, pointers> )); // Example #3: find_if typedef vector<char,int,unsigned,long,unsigned long> types; typedef find_if<types, is_same<_1, unsigned> >::type iter; BOOST_MPL_ASSERT(( is_same< deref<iter>::type, unsigned > )); BOOST_MPL_ASSERT_RELATION( iter::pos::value, ==, 2 );
  • 16. Function Type to JNI Signature std::string buf; buf += "("; buf += ")"; buf += JniTypeTrait<ReturnType>::signature(); [&] (auto t) { buf += JniTypeTrait<decltype(t)>::signature(); } boost::mpl::for_each<ParameterTypes>( ); NB: Les polymorphic lambdas (avec auto) ont été introduits dans C++14 (qui est actuellement en cours de standardisation). Ils sont disponibles dansVS2013 CTP, GCC 4.9 et Clang 3.4
  • 17. Plan de match 2. Interface d’invocation (invoke())
  • 18. Invocation (interface)  Rappel de l’enjeux:Vérification compile-time du nombre et du type des arguments obj.invoke<void(jint, jfloat)>("func", 1); // Error! obj.invoke<void(jint, jfloat)>("func", 1, 2.0, 3); // Error! obj.invoke<void(jint, jfloat)>("func", "1", "2.0"); // Error! obj.invoke<void(jint, jfloat)>("func", 1, 1.0); // OK
  • 19. Invocation (interface) template<class F> typename JniMethod<F>::ReturnType invoke( const char* methodName { // ... } template<class F> typename JniMethod<F>::ReturnType invoke( const char* methodName, typename boost::mpl::at_c<typename JniMethod<F>::ParameterTypes, 0>::type p1) { // ... } template<class F> typename JniMethod<F>::ReturnType invoke( const char* methodName, typename boost::mpl::at_c<typename JniMethod<F>::ParameterTypes, 0>::type p1, typename boost::mpl::at_c<typename JniMethod<F>::ParameterTypes, 1>::type p2) { // ... }
  • 20. Question quiz  Sachant que boost::mpl::at_c<Seq, n> n’est valide que pour des valeurs de n comprise entre 0 et boost::mpl::size<Seq>::value,  Comment se peut-il y avoir des overloads de invoke() pour chaque nombre d’arguments sans erreur de compilation ? typedef boost::mpl::vector<int> TypeList; typedef boost::mpl::at_c<TypeList, 2>::type foo; // Error!
  • 21. Réponse: SFINAE  Substitution Failure Is Not An Error If an invalid argument or return type is formed during the instantiation of a function template, the instantiation is removed from the overload resolution set instead of causing a compilation error. http://boost.org/doc/libs/1_55_0/libs/utility/enable_if.html  Exemple: int negate(int i) { return -i; } template<class F> typename F::result_type negate(const F& f) { return -f(); }
  • 22. SFINAE (application) template<class T> std::size_t size_in_bits(T t, typename std::enable_if<std::is_arithmetic<T>>::type* dummy = 0) { return 8 * sizeof(T); } template<class T> std::size_t size_in_bits(T t) { return 8 * sizeof(T); } size_in_bits(42); // 32. OK size_in_bits(std::string(“yo”)); // 256. OK, mais...?!? size_in_bits(42); // 32. OK size_in_bits(std::string(“yo”)); // ERROR. Unable to instantiate template...
  • 23. Plan de match 3. Invocation (env->CallStaticVoidMethod())
  • 24. Invocation (implementation) OK, mais ce n’est pas tout! CallIntMethod() Et si ReturnType vaut autre chose que jint ?? auto r = env_->CallIntMethod(object_, method, p1); env_.checkException(); return r;
  • 25. Invocation (variations sur ReturnType) typedef JniTypeTrait<typename JniMethod<F>::ReturnType> Trait; ((*env_).*Trait::callFunction()) // pointer-to-member-function type (to simplify callFunction() declaration) typedef jint (JNIEnv::*CallFunctionType)(jobject, jmethodID, ...); // return the JNIEnv member function to call to return jint static CallFunctionType callFunction() {return &JNIEnv::CallIntMethod;}
  • 26. Invocation (cas de ReturnType=void) Il reste un problème: auto r = env_->CallVoidMethod(object_, method, p1); >> ERROR! auto cannot deduce type from void
  • 27. Invocation (cas de ReturnType=void) template<class ReturnType, class ParameterTypes> struct Invoker { ReturnType operator()() { auto r = ((*env_).*CallFunc_)(object_, method_); env_.checkException(); return r; } }; template<class ParameterTypes> struct Invoker<void, ParameterTypes> { void operator()() { env_->CallVoidMethod(object_, method_); env_.checkException(); } }; Et les paramètres dans tout ça ?
  • 28. Invocation (paramètres) template<class... P> P... params params... Variadic templates ?
  • 29. Variadic templates template<class Head, class... Tail> void print(const Head& head, Tail... tail) { std::cout << head << " "; print(tail...); } template<class Head> void print(const Head& head) { std::cout << head << std::endl; } // Exemple print(2, "abc", 3.1415); // resultat: // 2 abc 3.1415 Template parameter pack expansion
  • 30. Voilà!  Autres fonctionnalités:  Gestion des références (locales vs globales)  Gestion des exceptions  Scope de fonction et de thread  Facilitateur pour les Strings  Surveillez les commits dans Lithium (git@git.innobec.com:innobec/lithium.git) obj.invoke<void(jint, jfloat)>("javaMethod", 42, 1.0);

Notes de l'éditeur

  1. Récemment, j’ai eu l’occasion de travailler sur un wrapper JNI que l’on utilise dans le projet Lithium pour appeler du Java à partir du C++. Non seulement est-ce que j’ai été satisfait du résultat que ça a donné, mais j’ai eu un plaisir fou à le réaliser. Aujourd’hui, je veux partager ce thrill avec vous.
  2. Cette présentation n’est pas une présentation exhaustive du wrapper JNI. Il s’agit plutôt d’un survol partiel avec emphase sur le “comment ça marche” et un prétexte pour présenter certaines technique moderne de programmation c++ qui sont inconnue à plusieurs.
  3. SVP éviter les questions du genre “pourquoi ne pas faire ceci au lieu de cela ?”, qui pourrait faire diverger rapidement la présentation déjà chargée. Je suis disponible pour en parler par après. Tous les commentaires et questions sont d’ailleurs les bienvenus.
  4. JNI permet d’appeler du code natif à partir du Java et appeler du code Java à partir du code C++. Le premier cas d’utilisation est plus fréquent et plus simple. Il permet à des organisations de rentabiliser un code base natif et l’intégrant à une application moderne Java. Le second cas est plus rare (parce qu’en général non requis dans le premier cas d’utilisation) et aussi plus compliqué à cause de l’aspect “managed” de la JVM.
  5. La fonction “nativeMethod” est implémentée par du code natif. La fonction “javaMethod” est appelée par le code natif.
  6. La signature de la fonction est générée par l’outil “javah” qui est inclus avec le JRE. Il ne reste plus qu’à remplir le corps de la fonction et compiler. Exemples typiques: Accéder le tableau de caractères d’une string Java Charger une classe par son nom Récupérer la méthode à appeler, identifiée par son nom et par sa signature Appeler la méthode Mais il y a des bugs dans cet exemple: Leak de mémoire de la string UTF8 Erreur dans la signature Erreur dans le nombre et le type des arguments Mauvaise fonction d’appel (static + return type) Initialization de l’environnement JNI pour les threads Passage illégal de l’environnement et des références entre threads Gestion d’erreurs
  7. La majorité des solutions existantes comporte un générateur de code. C’est bien, mais c’est lourd, surtout dans un petit projet si l’on a qu’un ou deux appels à faire (on se connait: en tant que développeur, on va le faire manuellement plutôt que sortir la grosse machine.)
  8. Voici l’objectif: Syntaxe succinte, claire et simple Pur C++ Sure (vérification statique) + exception en cas d’erreur runtime Sondage: Piece of cake ? Possible, mais ne sait pas trop comment ? What? Si vous avez répondu b), cette présentation est pour vous!!
  9. Pour cette présentation, je me limite seulement à l’aspect “appel d’une méthode Java en C++”. Il y a d’autres aspects, mais il faut faire des choix.
  10. On commence en douceur…
  11. On définit une classe “JniTypeTrait” pour laquelle on fournit une spécialisation pour int, float, void, etc. La fonction membre signature() permet d’obtenir la string correspondant au type. Simple, non ?
  12. Ensuite, il faut extraire les types de la signature de la fonction Boost.FunctionTypes offre des méta-fonctions qui permettent d’extraire le ReturnType et le type des arguments sont la forme d’une liste de type. Boost.MPL permet ensuite d’extraire le type de chaque paramètre à partir de la liste avec la méta-fonction at_c<>
  13. Le TMP a été “découvert accidentellement” durant la standardisation du c++. On réalise alors que non seulement on peut faire plein de chose avec les templates, mais qu’on peut faire n’importe quel calcul! (Turing complete-ness). Comme le langage n’a pas été concu pour ça, la syntaxe est plus bizarre, mais on s’habitue. Il y a 10 ans, les compilateurs suffoquaient à compiler des meta-programme moindrement complexe. Aujourd’hui, ce n’est plus un problème et l’évolution du langage fait de plus en plus de place à la métaprogrammation.
  14. Tout le monde connait la suite de Fibonacci, alors on va l’implémenter dans un métaprogramme! Cette façon de faire dite “pattern matching” est typique des langages fonctionnels. La limitation: les arguments et le résultats sont des constantes à la compilation.
  15. Boost.MPL fournit un algorithme, for_each, qui, comme son pendant STL, invoque un functor pour chaque élément d’une séquence. À la différence que la séquence en question est, dans le cas mpl::for_each, une séquence de types. Convertir un type en string? Nous avons déjà vu ça! JniTypeTrait ! Trop facile…
  16. Troisième et dernière étape de notre périple…
  17. Voici la solution pour ReturnType=int. Rien de compliqué La fonction checkException() vérifie qui une exception Java a été lancée et convertie celle-ci en exception C++. On se rappele que JNI est une API C et donc ne supporte pas les exceptions nativement. Les exceptions Java sont donc émulées par des attributs de JNIEnv que le programmeur se doit de vérifier.
  18. On ramène la class de Trait définit plus tôt et on y ajoute une fonction qui permet d’obtenir la fonction JNI à appeler selon le type de valeur de retour. La fonction est retournée sous la forme d’un pointeur vers une fonction membre (dont un typedef est déclaré pour fin de lisibilité).
  19. Impossible, même pour auto, de déclarer une variable de type void (qui, par définition, signifie absence de type)
  20. Dans un premier temps, on refactor le corps de la fonction dans une classe “invoker” NB: cette définition est complète: il manque le constructeur ainsi que les membres Dans un 2e temps, on crée une spécialisation partielle pour ReturnType=void Pas de spécialisation partielle des function templates
  21. Ici, on peut se permettre d’accepter n’importe quoi parce que la validation a été faite au niveau de invoke() Alors, on utilise simplement un variadic template
  22. Voici un exemple type d’utilisation de variadic templates L’équivalent de la fonction print en Python. Il ne faut pas confondre les variadic templates (…) et les VARARGS (…). Les derniers ne sont pas sécuritaires et un héritage du langage C. Les variadic templates, en revanches, sont sécuritaires parce qu’ils n’existent qu’à la compilation. À noter: Le template parameter pack n’est pas un type! Il n’est pas manipulable au runtime. En fait, comme les templates, il n’existent carrément plus une fois le programme compilé… Il est possible d’inclure une expression abitrairement complexe dans l’expansion du pack.