Mais justement, une bonne VM analyse le code, fait des
suppositions, et...
De même, s'ils l'ont fait bien, la VM doit
pouvoir « découvrir » que tous les objets qui sont mis dans le
Object[] (qui se trouve à la base de l'implémentation de la
collection) sont en fait des MaClasse, et remplacer le
transtypage dynamique à MaClasse en sortie par un transtypage
statique.
Ben non, toujours pas. D'ailleurs soit dit en passant les tableaux ne
fonctionnent pas avec les génériques.
Sauf qu'une bonne VM va plus loin ici. [...]
[...]Bref les génériques en java c'est plus de l'ordre du sucre
syntaxique qu'autre chose et on est bien loin de C++
Certes, mais pour d'autres raisons -- je ne crois pas qu'il y a
des paramètres non-type, ni des spécialisations explicites, par
exemple.
Mais justement, une bonne VM analyse le code, fait des
suppositions, et...
De même, s'ils l'ont fait bien, la VM doit
pouvoir « découvrir » que tous les objets qui sont mis dans le
Object[] (qui se trouve à la base de l'implémentation de la
collection) sont en fait des MaClasse, et remplacer le
transtypage dynamique à MaClasse en sortie par un transtypage
statique.
Ben non, toujours pas. D'ailleurs soit dit en passant les tableaux ne
fonctionnent pas avec les génériques.
Sauf qu'une bonne VM va plus loin ici. [...]
[...]
Bref les génériques en java c'est plus de l'ordre du sucre
syntaxique qu'autre chose et on est bien loin de C++
Certes, mais pour d'autres raisons -- je ne crois pas qu'il y a
des paramètres non-type, ni des spécialisations explicites, par
exemple.
Mais justement, une bonne VM analyse le code, fait des
suppositions, et...
De même, s'ils l'ont fait bien, la VM doit
pouvoir « découvrir » que tous les objets qui sont mis dans le
Object[] (qui se trouve à la base de l'implémentation de la
collection) sont en fait des MaClasse, et remplacer le
transtypage dynamique à MaClasse en sortie par un transtypage
statique.
Ben non, toujours pas. D'ailleurs soit dit en passant les tableaux ne
fonctionnent pas avec les génériques.
Sauf qu'une bonne VM va plus loin ici. [...]
[...]Bref les génériques en java c'est plus de l'ordre du sucre
syntaxique qu'autre chose et on est bien loin de C++
Certes, mais pour d'autres raisons -- je ne crois pas qu'il y a
des paramètres non-type, ni des spécialisations explicites, par
exemple.
Mais justement, une bonne VM analyse le code, fait des
suppositions, et...
Franchement je ne sais pas d'où tu sort ça. Si tu as des infos
ça m'intéresse d'ailleurs.
A moins que tu ne parle du JIT ?
Voici le byte code pour la fin du code ci-dessus:
63: new #2; //class java/util/Vector
66: dup
67: invokespecial #3; //Method java/util/Vector."<init>":()V
70: astore 5
72: aload 5
74: new #17; //class testgeneric/Generic
Donc, type connu...
En effet77: dup
78: iload_1
79: invokespecial #18; //Method "<init>":(I)V
82: invokevirtual #5; //Method
java/util/Vector.add:(Ljava/lang/Object;)Z
Sauf qu'une bonne VM va plus loin ici. Elle entre dans la
fonction, voit ce qu'elle fait, etc. Et note quelque part,
optimistiquement, que le tableut que contient l'objet ne
contient en fait que des type #17. Chaque fois qu'elle
compile un bout de code, elle vérifie (ou essaie) que cette
post-condition tient avec le bout du code qu'elle a
compilée.
"Qu'elle compile un bout de code" dit tu, donc tu me parle
bien du JIT là, si je te suis bien. Parce que au niveau du
compilateur proprement dit, je n'en ai jamais vu un qui fait
ça.
85: pop
86: aload 5
88: iconst_0
89: invokevirtual #6; //Method
java/util/Vector.get:(I)Ljava/lang/Object;
92: checkcast #17; //class testgeneric/Generic
95: astore 6
97: return
Et quand elle compile ce bout du code, elle entre dans
Vector.get assez pour voir que la valeur de retour vient
bien d'un tableau d'objet, et si le type est effectivement
noté pour ce tableau, et c'est #17, elle remplace le
checkcast par l'équivalent d'un static_cast (en fait, un
no-op si #17 est une classe, et non une interface). Et
évidemment, elle génère une pré-condition pour ce bout du
code qui assure que le type dans le tableau n'a pas changé.
Quand bien même ce que tu me dis serait vrai, (ce n'est pas la
question, je veux bien te croire), tu avoueras que c'est assez
laid tout ça non ?
Selon certains experts avec qui j'ai parlé, c'est en
principe plus facile d'optimiser lors de l'exécution dans un
VM que dans un compilateur classique. Parce que dans la VM,
tu as accès réel du profiling du programme en cours,
Je ne suis toujours pas sûr d'avoir bien compris si tu me
parles de la VM proprement dite ou du JIT.
Je sais que Hot Spot fait des optimisations en fonctions des
bouts de code les plus utilisés. Je veux dire que seulement
des bouts pertinents de byte-code sont compilés en des
routines assembleurs et que Hot Spot s'arrange pour éviter de
tout compiler ce qui prendrait trop de temps souvent pour un
gain assez faible.
Mais ce que tu me dis semble se passer au niveau de la VM (tu
dis toujours VM) et là franchement je ne sais pas. Moi je
croyais même qu'il y avait toujours transtypages dynamique
même après intervention de Hot Spot, en tous cas au moins
jusqu'à la version Hot Spot 1.4. Peut être qu'avec la 1.5
c'est différent. Si tu as des infos là-dessus, un bon lien, je
suis preneur, parce que tu piques ma curiosité au vif là :-)
Comme tu vois c'est un Object qui est mis dans le tableau et
un Object qui en sort.
Mais la VM peut voir plus loins.
Tu sembles en être tellement convaincu que je vais finir par
douter.
Mais justement, une bonne VM analyse le code, fait des
suppositions, et...
Franchement je ne sais pas d'où tu sort ça. Si tu as des infos
ça m'intéresse d'ailleurs.
A moins que tu ne parle du JIT ?
Voici le byte code pour la fin du code ci-dessus:
63: new #2; //class java/util/Vector
66: dup
67: invokespecial #3; //Method java/util/Vector."<init>":()V
70: astore 5
72: aload 5
74: new #17; //class testgeneric/Generic
Donc, type connu...
En effet
77: dup
78: iload_1
79: invokespecial #18; //Method "<init>":(I)V
82: invokevirtual #5; //Method
java/util/Vector.add:(Ljava/lang/Object;)Z
Sauf qu'une bonne VM va plus loin ici. Elle entre dans la
fonction, voit ce qu'elle fait, etc. Et note quelque part,
optimistiquement, que le tableut que contient l'objet ne
contient en fait que des type #17. Chaque fois qu'elle
compile un bout de code, elle vérifie (ou essaie) que cette
post-condition tient avec le bout du code qu'elle a
compilée.
"Qu'elle compile un bout de code" dit tu, donc tu me parle
bien du JIT là, si je te suis bien. Parce que au niveau du
compilateur proprement dit, je n'en ai jamais vu un qui fait
ça.
85: pop
86: aload 5
88: iconst_0
89: invokevirtual #6; //Method
java/util/Vector.get:(I)Ljava/lang/Object;
92: checkcast #17; //class testgeneric/Generic
95: astore 6
97: return
Et quand elle compile ce bout du code, elle entre dans
Vector.get assez pour voir que la valeur de retour vient
bien d'un tableau d'objet, et si le type est effectivement
noté pour ce tableau, et c'est #17, elle remplace le
checkcast par l'équivalent d'un static_cast (en fait, un
no-op si #17 est une classe, et non une interface). Et
évidemment, elle génère une pré-condition pour ce bout du
code qui assure que le type dans le tableau n'a pas changé.
Quand bien même ce que tu me dis serait vrai, (ce n'est pas la
question, je veux bien te croire), tu avoueras que c'est assez
laid tout ça non ?
Selon certains experts avec qui j'ai parlé, c'est en
principe plus facile d'optimiser lors de l'exécution dans un
VM que dans un compilateur classique. Parce que dans la VM,
tu as accès réel du profiling du programme en cours,
Je ne suis toujours pas sûr d'avoir bien compris si tu me
parles de la VM proprement dite ou du JIT.
Je sais que Hot Spot fait des optimisations en fonctions des
bouts de code les plus utilisés. Je veux dire que seulement
des bouts pertinents de byte-code sont compilés en des
routines assembleurs et que Hot Spot s'arrange pour éviter de
tout compiler ce qui prendrait trop de temps souvent pour un
gain assez faible.
Mais ce que tu me dis semble se passer au niveau de la VM (tu
dis toujours VM) et là franchement je ne sais pas. Moi je
croyais même qu'il y avait toujours transtypages dynamique
même après intervention de Hot Spot, en tous cas au moins
jusqu'à la version Hot Spot 1.4. Peut être qu'avec la 1.5
c'est différent. Si tu as des infos là-dessus, un bon lien, je
suis preneur, parce que tu piques ma curiosité au vif là :-)
Comme tu vois c'est un Object qui est mis dans le tableau et
un Object qui en sort.
Mais la VM peut voir plus loins.
Tu sembles en être tellement convaincu que je vais finir par
douter.
Mais justement, une bonne VM analyse le code, fait des
suppositions, et...
Franchement je ne sais pas d'où tu sort ça. Si tu as des infos
ça m'intéresse d'ailleurs.
A moins que tu ne parle du JIT ?
Voici le byte code pour la fin du code ci-dessus:
63: new #2; //class java/util/Vector
66: dup
67: invokespecial #3; //Method java/util/Vector."<init>":()V
70: astore 5
72: aload 5
74: new #17; //class testgeneric/Generic
Donc, type connu...
En effet77: dup
78: iload_1
79: invokespecial #18; //Method "<init>":(I)V
82: invokevirtual #5; //Method
java/util/Vector.add:(Ljava/lang/Object;)Z
Sauf qu'une bonne VM va plus loin ici. Elle entre dans la
fonction, voit ce qu'elle fait, etc. Et note quelque part,
optimistiquement, que le tableut que contient l'objet ne
contient en fait que des type #17. Chaque fois qu'elle
compile un bout de code, elle vérifie (ou essaie) que cette
post-condition tient avec le bout du code qu'elle a
compilée.
"Qu'elle compile un bout de code" dit tu, donc tu me parle
bien du JIT là, si je te suis bien. Parce que au niveau du
compilateur proprement dit, je n'en ai jamais vu un qui fait
ça.
85: pop
86: aload 5
88: iconst_0
89: invokevirtual #6; //Method
java/util/Vector.get:(I)Ljava/lang/Object;
92: checkcast #17; //class testgeneric/Generic
95: astore 6
97: return
Et quand elle compile ce bout du code, elle entre dans
Vector.get assez pour voir que la valeur de retour vient
bien d'un tableau d'objet, et si le type est effectivement
noté pour ce tableau, et c'est #17, elle remplace le
checkcast par l'équivalent d'un static_cast (en fait, un
no-op si #17 est une classe, et non une interface). Et
évidemment, elle génère une pré-condition pour ce bout du
code qui assure que le type dans le tableau n'a pas changé.
Quand bien même ce que tu me dis serait vrai, (ce n'est pas la
question, je veux bien te croire), tu avoueras que c'est assez
laid tout ça non ?
Selon certains experts avec qui j'ai parlé, c'est en
principe plus facile d'optimiser lors de l'exécution dans un
VM que dans un compilateur classique. Parce que dans la VM,
tu as accès réel du profiling du programme en cours,
Je ne suis toujours pas sûr d'avoir bien compris si tu me
parles de la VM proprement dite ou du JIT.
Je sais que Hot Spot fait des optimisations en fonctions des
bouts de code les plus utilisés. Je veux dire que seulement
des bouts pertinents de byte-code sont compilés en des
routines assembleurs et que Hot Spot s'arrange pour éviter de
tout compiler ce qui prendrait trop de temps souvent pour un
gain assez faible.
Mais ce que tu me dis semble se passer au niveau de la VM (tu
dis toujours VM) et là franchement je ne sais pas. Moi je
croyais même qu'il y avait toujours transtypages dynamique
même après intervention de Hot Spot, en tous cas au moins
jusqu'à la version Hot Spot 1.4. Peut être qu'avec la 1.5
c'est différent. Si tu as des infos là-dessus, un bon lien, je
suis preneur, parce que tu piques ma curiosité au vif là :-)
Comme tu vois c'est un Object qui est mis dans le tableau et
un Object qui en sort.
Mais la VM peut voir plus loins.
Tu sembles en être tellement convaincu que je vais finir par
douter.
(comme indiqué par Alain) tu parles partout ici de compilateur JIT pas
de la VM. une VM se caractérise ""seulement"" par sa pile et son byte-code.
cette distinction faite, en effet, il y a de grosses différences d'un
JIT à un autre, d'un système hôte à un autre.
non génériquement, tu peux écrire:
Vector<Integer> numbers = new Vector<Integer>(10, 10);
Object object = new String("toto");
numbers.add((Integer) object);
qui levera un CastClassException à l'exécution, parce qu'il y a bien
vérification dynamique.
(comme indiqué par Alain) tu parles partout ici de compilateur JIT pas
de la VM. une VM se caractérise ""seulement"" par sa pile et son byte-code.
cette distinction faite, en effet, il y a de grosses différences d'un
JIT à un autre, d'un système hôte à un autre.
non génériquement, tu peux écrire:
Vector<Integer> numbers = new Vector<Integer>(10, 10);
Object object = new String("toto");
numbers.add((Integer) object);
qui levera un CastClassException à l'exécution, parce qu'il y a bien
vérification dynamique.
(comme indiqué par Alain) tu parles partout ici de compilateur JIT pas
de la VM. une VM se caractérise ""seulement"" par sa pile et son byte-code.
cette distinction faite, en effet, il y a de grosses différences d'un
JIT à un autre, d'un système hôte à un autre.
non génériquement, tu peux écrire:
Vector<Integer> numbers = new Vector<Integer>(10, 10);
Object object = new String("toto");
numbers.add((Integer) object);
qui levera un CastClassException à l'exécution, parce qu'il y a bien
vérification dynamique.
C'est surtout des discussions personnelles avec des gens qui
travaillent sur des compilateurs.A moins que tu ne parle du JIT ?
Je parle des VM concrètes, non la machine abstraite. C-à-d un
programme qui, donné une suite de byte codes, s'arrange pour
effectuer leur sémantique. Le JIT et HotSpot en font partie.
"Qu'elle compile un bout de code" dit tu, donc tu me parle
bien du JIT là, si je te suis bien. Parce que au niveau du
compilateur proprement dit, je n'en ai jamais vu un qui fait
ça.
Je ne sais pas.
Il y a des parties de la VM de JDK qui sont
assez intelligentes.
Et d'autres, dont il vaut mieux ne pas en
parler.
Le problème ici, c'est ce qui pourrait éventuellement se passer
ailleurs. Je sais que la JIT d'il y a cinq ans faisait des
suppositions optimistes, et générer du code en tête du bloc qui
les vérifier, et déclencher le compilateur de nouveau si elles
s'avérait fausses.
Ce que je ne sais pas, c'est d'une part, est-ce qu'ils ont pensé
à tracer les informations de type comme faisant partie de la
valeur, pour qu'elle se propage comme les autres constantes,
Dans le temps, James Gosling avait une page sur les
modifications nécessaires pour que Java puisse servir au calcul
numérique. Son but, c'était de définir un nombre minimum de
modifications pour que le compilateur pourrait, par exemple,
convertir un tableau de Complex (ou Complex était un type défini
par l'utilisateur, qui comportait deux double) en ce qui
reviendrait à un tableau de struct en C -- le tableau physique
ne contiendrait pas des pointeurs à des objets, chacun alloué
dynamiquement, mais bien les objets.
Depuis, je n'arrive plus à
la trouver --
sans doute, une déclaration que Java pourrait
être amélioré, et qu'elle n'était pas parfait déjà, n'a pas plus
à son employeur (sûrtout en venant d'une telle source).
Mais je
ne peux pas croire que ses observations était sans effet,
En soi, non. Au contraire, c'est ce qu'on démande. En C++ aussi,
tu préfèrerais un compilateur capable d'extraire l'appel de
vector<>::end() de la boucle, non ?
Idéalement, l'optimisation
doit être le rôle du compilateur, non du programmeur.
Le JIT fait partie de la VM du Sun.
Au minimum absolu, la VM va découper le code en blocs de flux,
c-à-d en blocs avec une seule entrée, en tête, et une seule
sortie, à la fin. (La première représentation d'un programme
dans un optimisateur, c'est un graphe orienté des tels blocs.)
Et générer l'assembleur pour chaque bloc. En l'occurance, et le
JIT, et Hot Spot vont bien plus loin, mais d'une façon
différente -- le Hot Spot est optimisé pour le type de code
qu'on trouve dans un serveur (des EJB, etc.),
Je sais aussi qu'il y a des compilateurs C++ qui en font plus ou
moins autant, à partir des informations du profiling. Que dans
un bout du code dans une boucle serrée, où on fait p->f(), et
que p a le type B*, si le profiling indique que 99% des fois, on
exécute en fait D1::f(), le compilateur génère un bout du code
avant la boucle qui teste rapidement si la résolution de f()
pour p serait D1::f() (deux ou trois instructions machine
suffissent), pour choisir entre deux implémentations de la
boucle, et dans celle où on sait qu'on a D1::f(), il le génère
inline.
Je suis 100% convaincu que c'est possible. Je sais en plus que
James Gosling y a reflechi. Je sais en revanche que ce n'est pas
forcement très simple, et je ne sais pas du tout si le JVM de
JDK ou de Jikes va aussi loin.
C'est surtout des discussions personnelles avec des gens qui
travaillent sur des compilateurs.
A moins que tu ne parle du JIT ?
Je parle des VM concrètes, non la machine abstraite. C-à-d un
programme qui, donné une suite de byte codes, s'arrange pour
effectuer leur sémantique. Le JIT et HotSpot en font partie.
"Qu'elle compile un bout de code" dit tu, donc tu me parle
bien du JIT là, si je te suis bien. Parce que au niveau du
compilateur proprement dit, je n'en ai jamais vu un qui fait
ça.
Je ne sais pas.
Il y a des parties de la VM de JDK qui sont
assez intelligentes.
Et d'autres, dont il vaut mieux ne pas en
parler.
Le problème ici, c'est ce qui pourrait éventuellement se passer
ailleurs. Je sais que la JIT d'il y a cinq ans faisait des
suppositions optimistes, et générer du code en tête du bloc qui
les vérifier, et déclencher le compilateur de nouveau si elles
s'avérait fausses.
Ce que je ne sais pas, c'est d'une part, est-ce qu'ils ont pensé
à tracer les informations de type comme faisant partie de la
valeur, pour qu'elle se propage comme les autres constantes,
Dans le temps, James Gosling avait une page sur les
modifications nécessaires pour que Java puisse servir au calcul
numérique. Son but, c'était de définir un nombre minimum de
modifications pour que le compilateur pourrait, par exemple,
convertir un tableau de Complex (ou Complex était un type défini
par l'utilisateur, qui comportait deux double) en ce qui
reviendrait à un tableau de struct en C -- le tableau physique
ne contiendrait pas des pointeurs à des objets, chacun alloué
dynamiquement, mais bien les objets.
Depuis, je n'arrive plus à
la trouver --
sans doute, une déclaration que Java pourrait
être amélioré, et qu'elle n'était pas parfait déjà, n'a pas plus
à son employeur (sûrtout en venant d'une telle source).
Mais je
ne peux pas croire que ses observations était sans effet,
En soi, non. Au contraire, c'est ce qu'on démande. En C++ aussi,
tu préfèrerais un compilateur capable d'extraire l'appel de
vector<>::end() de la boucle, non ?
Idéalement, l'optimisation
doit être le rôle du compilateur, non du programmeur.
Le JIT fait partie de la VM du Sun.
Au minimum absolu, la VM va découper le code en blocs de flux,
c-à-d en blocs avec une seule entrée, en tête, et une seule
sortie, à la fin. (La première représentation d'un programme
dans un optimisateur, c'est un graphe orienté des tels blocs.)
Et générer l'assembleur pour chaque bloc. En l'occurance, et le
JIT, et Hot Spot vont bien plus loin, mais d'une façon
différente -- le Hot Spot est optimisé pour le type de code
qu'on trouve dans un serveur (des EJB, etc.),
Je sais aussi qu'il y a des compilateurs C++ qui en font plus ou
moins autant, à partir des informations du profiling. Que dans
un bout du code dans une boucle serrée, où on fait p->f(), et
que p a le type B*, si le profiling indique que 99% des fois, on
exécute en fait D1::f(), le compilateur génère un bout du code
avant la boucle qui teste rapidement si la résolution de f()
pour p serait D1::f() (deux ou trois instructions machine
suffissent), pour choisir entre deux implémentations de la
boucle, et dans celle où on sait qu'on a D1::f(), il le génère
inline.
Je suis 100% convaincu que c'est possible. Je sais en plus que
James Gosling y a reflechi. Je sais en revanche que ce n'est pas
forcement très simple, et je ne sais pas du tout si le JVM de
JDK ou de Jikes va aussi loin.
C'est surtout des discussions personnelles avec des gens qui
travaillent sur des compilateurs.A moins que tu ne parle du JIT ?
Je parle des VM concrètes, non la machine abstraite. C-à-d un
programme qui, donné une suite de byte codes, s'arrange pour
effectuer leur sémantique. Le JIT et HotSpot en font partie.
"Qu'elle compile un bout de code" dit tu, donc tu me parle
bien du JIT là, si je te suis bien. Parce que au niveau du
compilateur proprement dit, je n'en ai jamais vu un qui fait
ça.
Je ne sais pas.
Il y a des parties de la VM de JDK qui sont
assez intelligentes.
Et d'autres, dont il vaut mieux ne pas en
parler.
Le problème ici, c'est ce qui pourrait éventuellement se passer
ailleurs. Je sais que la JIT d'il y a cinq ans faisait des
suppositions optimistes, et générer du code en tête du bloc qui
les vérifier, et déclencher le compilateur de nouveau si elles
s'avérait fausses.
Ce que je ne sais pas, c'est d'une part, est-ce qu'ils ont pensé
à tracer les informations de type comme faisant partie de la
valeur, pour qu'elle se propage comme les autres constantes,
Dans le temps, James Gosling avait une page sur les
modifications nécessaires pour que Java puisse servir au calcul
numérique. Son but, c'était de définir un nombre minimum de
modifications pour que le compilateur pourrait, par exemple,
convertir un tableau de Complex (ou Complex était un type défini
par l'utilisateur, qui comportait deux double) en ce qui
reviendrait à un tableau de struct en C -- le tableau physique
ne contiendrait pas des pointeurs à des objets, chacun alloué
dynamiquement, mais bien les objets.
Depuis, je n'arrive plus à
la trouver --
sans doute, une déclaration que Java pourrait
être amélioré, et qu'elle n'était pas parfait déjà, n'a pas plus
à son employeur (sûrtout en venant d'une telle source).
Mais je
ne peux pas croire que ses observations était sans effet,
En soi, non. Au contraire, c'est ce qu'on démande. En C++ aussi,
tu préfèrerais un compilateur capable d'extraire l'appel de
vector<>::end() de la boucle, non ?
Idéalement, l'optimisation
doit être le rôle du compilateur, non du programmeur.
Le JIT fait partie de la VM du Sun.
Au minimum absolu, la VM va découper le code en blocs de flux,
c-à-d en blocs avec une seule entrée, en tête, et une seule
sortie, à la fin. (La première représentation d'un programme
dans un optimisateur, c'est un graphe orienté des tels blocs.)
Et générer l'assembleur pour chaque bloc. En l'occurance, et le
JIT, et Hot Spot vont bien plus loin, mais d'une façon
différente -- le Hot Spot est optimisé pour le type de code
qu'on trouve dans un serveur (des EJB, etc.),
Je sais aussi qu'il y a des compilateurs C++ qui en font plus ou
moins autant, à partir des informations du profiling. Que dans
un bout du code dans une boucle serrée, où on fait p->f(), et
que p a le type B*, si le profiling indique que 99% des fois, on
exécute en fait D1::f(), le compilateur génère un bout du code
avant la boucle qui teste rapidement si la résolution de f()
pour p serait D1::f() (deux ou trois instructions machine
suffissent), pour choisir entre deux implémentations de la
boucle, et dans celle où on sait qu'on a D1::f(), il le génère
inline.
Je suis 100% convaincu que c'est possible. Je sais en plus que
James Gosling y a reflechi. Je sais en revanche que ce n'est pas
forcement très simple, et je ne sais pas du tout si le JVM de
JDK ou de Jikes va aussi loin.
On relance le débat ? ;-)
"Non du programmeur", jusqu'à un certain point seulement. Tiens question
fatale, j'itère dans un vector et dans l'itèration j'ajoute un élément
au vector. Si le compilo a sorti end() sans me le dire, mon code ne
marche plus.
Donc l'optimisation c'est aussi un peu le rôle du programmeur, dans le
sens où il doit au moins être conscient de ce qu'il code et de ce que le
compilo peut faire de son code.
Ou bien c'est au compilo de détecter que dans ce cas il ne faut pas
optimiser. Mais je vois mal comment cela pourrait être possible.
Dernière possibilité, on écartèle en place de Grèves le type qui modifie
un vector pendant l'itération, ça simplifie tout ;-)
On relance le débat ? ;-)
"Non du programmeur", jusqu'à un certain point seulement. Tiens question
fatale, j'itère dans un vector et dans l'itèration j'ajoute un élément
au vector. Si le compilo a sorti end() sans me le dire, mon code ne
marche plus.
Donc l'optimisation c'est aussi un peu le rôle du programmeur, dans le
sens où il doit au moins être conscient de ce qu'il code et de ce que le
compilo peut faire de son code.
Ou bien c'est au compilo de détecter que dans ce cas il ne faut pas
optimiser. Mais je vois mal comment cela pourrait être possible.
Dernière possibilité, on écartèle en place de Grèves le type qui modifie
un vector pendant l'itération, ça simplifie tout ;-)
On relance le débat ? ;-)
"Non du programmeur", jusqu'à un certain point seulement. Tiens question
fatale, j'itère dans un vector et dans l'itèration j'ajoute un élément
au vector. Si le compilo a sorti end() sans me le dire, mon code ne
marche plus.
Donc l'optimisation c'est aussi un peu le rôle du programmeur, dans le
sens où il doit au moins être conscient de ce qu'il code et de ce que le
compilo peut faire de son code.
Ou bien c'est au compilo de détecter que dans ce cas il ne faut pas
optimiser. Mais je vois mal comment cela pourrait être possible.
Dernière possibilité, on écartèle en place de Grèves le type qui modifie
un vector pendant l'itération, ça simplifie tout ;-)
Donc l'optimisation c'est aussi un peu le rôle du programmeur, dans le
sens où il doit au moins être conscient de ce qu'il code et de ce que
le compilo peut faire de son code.
Ou bien c'est au compilo de détecter que dans ce cas il ne faut pas
optimiser. Mais je vois mal comment cela pourrait être possible.
C'est pourtant la noble tâche d'un compilateur.
Donc l'optimisation c'est aussi un peu le rôle du programmeur, dans le
sens où il doit au moins être conscient de ce qu'il code et de ce que
le compilo peut faire de son code.
Ou bien c'est au compilo de détecter que dans ce cas il ne faut pas
optimiser. Mais je vois mal comment cela pourrait être possible.
C'est pourtant la noble tâche d'un compilateur.
Donc l'optimisation c'est aussi un peu le rôle du programmeur, dans le
sens où il doit au moins être conscient de ce qu'il code et de ce que
le compilo peut faire de son code.
Ou bien c'est au compilo de détecter que dans ce cas il ne faut pas
optimiser. Mais je vois mal comment cela pourrait être possible.
C'est pourtant la noble tâche d'un compilateur.
Donc l'optimisation c'est aussi un peu le rôle du programmeur, dans le
sens où il doit au moins être conscient de ce qu'il code et de ce que le
compilo peut faire de son code.
Ou bien c'est au compilo de détecter que dans ce cas il ne faut pas
optimiser. Mais je vois mal comment cela pourrait être possible.
C'est pourtant la noble tâche d'un compilateur.
Nous sommes nous compris ? "dans ce cas", je voulais dire dans le cas du
end() sorti de la boucle.
Tu penses qu'un compilateur peut voir qu'un itérateur de conteneur risque
d'être invalidé ?
Donc l'optimisation c'est aussi un peu le rôle du programmeur, dans le
sens où il doit au moins être conscient de ce qu'il code et de ce que le
compilo peut faire de son code.
Ou bien c'est au compilo de détecter que dans ce cas il ne faut pas
optimiser. Mais je vois mal comment cela pourrait être possible.
C'est pourtant la noble tâche d'un compilateur.
Nous sommes nous compris ? "dans ce cas", je voulais dire dans le cas du
end() sorti de la boucle.
Tu penses qu'un compilateur peut voir qu'un itérateur de conteneur risque
d'être invalidé ?
Donc l'optimisation c'est aussi un peu le rôle du programmeur, dans le
sens où il doit au moins être conscient de ce qu'il code et de ce que le
compilo peut faire de son code.
Ou bien c'est au compilo de détecter que dans ce cas il ne faut pas
optimiser. Mais je vois mal comment cela pourrait être possible.
C'est pourtant la noble tâche d'un compilateur.
Nous sommes nous compris ? "dans ce cas", je voulais dire dans le cas du
end() sorti de la boucle.
Tu penses qu'un compilateur peut voir qu'un itérateur de conteneur risque
d'être invalidé ?
kanze wrote on 26/09/2006 17:03:Mais justement, une bonne VM analyse le code, fait des
suppositions, et...
(comme indiqué par Alain) tu parles partout ici de compilateur
JIT pas de la VM. une VM se caractérise ""seulement"" par sa
pile et son byte-code.
cette distinction faite, en effet, il y a de grosses
différences d'un JIT à un autre, d'un système hôte à un autre.De même, s'ils l'ont fait bien, la VM doit
pouvoir « découvrir » que tous les objets qui sont mis dans le
Object[] (qui se trouve à la base de l'implémentation de la
collection) sont en fait des MaClasse, et remplacer le
transtypage dynamique à MaClasse en sortie par un transtypage
statique.
non génériquement, tu peux écrire:
Vector<Integer> numbers = new Vector<Integer>(10, 10);
Object object = new String("toto");
numbers.add((Integer) object);
qui levera un CastClassException à l'exécution, parce qu'il y
a bien vérification dynamique.
[...]Bref les génériques en java c'est plus de l'ordre du sucre
syntaxique qu'autre chose et on est bien loin de C++
Certes, mais pour d'autres raisons -- je ne crois pas qu'il
y a des paramètres non-type, ni des spécialisations
explicites, par exemple.
"spécialisation explicite" est un concept, paradigme, ..., C++
donc en effet on le rencontre en C++
un 'template' C++ est principalement une définition
paramétrée, il n'existe vraiment qu'au travers son
instantiation pour un (des) type(s) paramètre(s) donné(s) - le
code concret n'existe pas indépendamment de ce(s)
paramètre(s).
une "classe paramétrée" Java existe bien indépendamment de
toute instantiation, une fois déclarée (et visible dans le
contexte), elle ne peut bien sur pas être redéfinie, donc une
"spécialisation à la C++" résulterait forcément en une
redéfinition invalide.
le paradigme est donc différent pour autant le même objectif
peut être réalisé, mais à la Java, en spécialisant par
surcharge ce qui doit être spécialisé, par exemple (ici je
joue sur la valeur retournée, on ferait de même pour un
traitement spécifique à la classe de l'argument):
Vector<Integer> numbers = new Vector<Integer>(10, 10);
numbers.add(1);
numbers.add(3);
numbers.add(5);
for (Integer nb: numbers)
System.out.println(nb);
out: 1 3 5
[btw, exemple on-topic et sans interrogation métaphysique sur le end()]
Vector<Integer> squares = new Vector<Integer>(10, 10){
public synchronized Integer get(int index) {
int value = super.get(index).intValue();
return new Integer(value * value);
}
};
squares.add(1);
squares.add(3);
squares.add(5);
for (Integer nb: squares)
System.out.println(nb);
out: 1 9 25
je considère même que cette forme de spécialisation est plus
avantageuse du fait même qu'elle tire parti de l'héritage.
kanze wrote on 26/09/2006 17:03:
Mais justement, une bonne VM analyse le code, fait des
suppositions, et...
(comme indiqué par Alain) tu parles partout ici de compilateur
JIT pas de la VM. une VM se caractérise ""seulement"" par sa
pile et son byte-code.
cette distinction faite, en effet, il y a de grosses
différences d'un JIT à un autre, d'un système hôte à un autre.
De même, s'ils l'ont fait bien, la VM doit
pouvoir « découvrir » que tous les objets qui sont mis dans le
Object[] (qui se trouve à la base de l'implémentation de la
collection) sont en fait des MaClasse, et remplacer le
transtypage dynamique à MaClasse en sortie par un transtypage
statique.
non génériquement, tu peux écrire:
Vector<Integer> numbers = new Vector<Integer>(10, 10);
Object object = new String("toto");
numbers.add((Integer) object);
qui levera un CastClassException à l'exécution, parce qu'il y
a bien vérification dynamique.
[...]
Bref les génériques en java c'est plus de l'ordre du sucre
syntaxique qu'autre chose et on est bien loin de C++
Certes, mais pour d'autres raisons -- je ne crois pas qu'il
y a des paramètres non-type, ni des spécialisations
explicites, par exemple.
"spécialisation explicite" est un concept, paradigme, ..., C++
donc en effet on le rencontre en C++
un 'template' C++ est principalement une définition
paramétrée, il n'existe vraiment qu'au travers son
instantiation pour un (des) type(s) paramètre(s) donné(s) - le
code concret n'existe pas indépendamment de ce(s)
paramètre(s).
une "classe paramétrée" Java existe bien indépendamment de
toute instantiation, une fois déclarée (et visible dans le
contexte), elle ne peut bien sur pas être redéfinie, donc une
"spécialisation à la C++" résulterait forcément en une
redéfinition invalide.
le paradigme est donc différent pour autant le même objectif
peut être réalisé, mais à la Java, en spécialisant par
surcharge ce qui doit être spécialisé, par exemple (ici je
joue sur la valeur retournée, on ferait de même pour un
traitement spécifique à la classe de l'argument):
Vector<Integer> numbers = new Vector<Integer>(10, 10);
numbers.add(1);
numbers.add(3);
numbers.add(5);
for (Integer nb: numbers)
System.out.println(nb);
out: 1 3 5
[btw, exemple on-topic et sans interrogation métaphysique sur le end()]
Vector<Integer> squares = new Vector<Integer>(10, 10){
public synchronized Integer get(int index) {
int value = super.get(index).intValue();
return new Integer(value * value);
}
};
squares.add(1);
squares.add(3);
squares.add(5);
for (Integer nb: squares)
System.out.println(nb);
out: 1 9 25
je considère même que cette forme de spécialisation est plus
avantageuse du fait même qu'elle tire parti de l'héritage.
kanze wrote on 26/09/2006 17:03:Mais justement, une bonne VM analyse le code, fait des
suppositions, et...
(comme indiqué par Alain) tu parles partout ici de compilateur
JIT pas de la VM. une VM se caractérise ""seulement"" par sa
pile et son byte-code.
cette distinction faite, en effet, il y a de grosses
différences d'un JIT à un autre, d'un système hôte à un autre.De même, s'ils l'ont fait bien, la VM doit
pouvoir « découvrir » que tous les objets qui sont mis dans le
Object[] (qui se trouve à la base de l'implémentation de la
collection) sont en fait des MaClasse, et remplacer le
transtypage dynamique à MaClasse en sortie par un transtypage
statique.
non génériquement, tu peux écrire:
Vector<Integer> numbers = new Vector<Integer>(10, 10);
Object object = new String("toto");
numbers.add((Integer) object);
qui levera un CastClassException à l'exécution, parce qu'il y
a bien vérification dynamique.
[...]Bref les génériques en java c'est plus de l'ordre du sucre
syntaxique qu'autre chose et on est bien loin de C++
Certes, mais pour d'autres raisons -- je ne crois pas qu'il
y a des paramètres non-type, ni des spécialisations
explicites, par exemple.
"spécialisation explicite" est un concept, paradigme, ..., C++
donc en effet on le rencontre en C++
un 'template' C++ est principalement une définition
paramétrée, il n'existe vraiment qu'au travers son
instantiation pour un (des) type(s) paramètre(s) donné(s) - le
code concret n'existe pas indépendamment de ce(s)
paramètre(s).
une "classe paramétrée" Java existe bien indépendamment de
toute instantiation, une fois déclarée (et visible dans le
contexte), elle ne peut bien sur pas être redéfinie, donc une
"spécialisation à la C++" résulterait forcément en une
redéfinition invalide.
le paradigme est donc différent pour autant le même objectif
peut être réalisé, mais à la Java, en spécialisant par
surcharge ce qui doit être spécialisé, par exemple (ici je
joue sur la valeur retournée, on ferait de même pour un
traitement spécifique à la classe de l'argument):
Vector<Integer> numbers = new Vector<Integer>(10, 10);
numbers.add(1);
numbers.add(3);
numbers.add(5);
for (Integer nb: numbers)
System.out.println(nb);
out: 1 3 5
[btw, exemple on-topic et sans interrogation métaphysique sur le end()]
Vector<Integer> squares = new Vector<Integer>(10, 10){
public synchronized Integer get(int index) {
int value = super.get(index).intValue();
return new Integer(value * value);
}
};
squares.add(1);
squares.add(3);
squares.add(5);
for (Integer nb: squares)
System.out.println(nb);
out: 1 9 25
je considère même que cette forme de spécialisation est plus
avantageuse du fait même qu'elle tire parti de l'héritage.
(comme indiqué par Alain) tu parles partout ici de
compilateur JIT pas de la VM. une VM se caractérise
""seulement"" par sa pile et son byte-code.
En effet la JVM pour ce que j'en connais, c'est ça. Mais James
a l'air tellement sûr de lui.
(comme indiqué par Alain) tu parles partout ici de
compilateur JIT pas de la VM. une VM se caractérise
""seulement"" par sa pile et son byte-code.
En effet la JVM pour ce que j'en connais, c'est ça. Mais James
a l'air tellement sûr de lui.
(comme indiqué par Alain) tu parles partout ici de
compilateur JIT pas de la VM. une VM se caractérise
""seulement"" par sa pile et son byte-code.
En effet la JVM pour ce que j'en connais, c'est ça. Mais James
a l'air tellement sûr de lui.
Je me base sur la signification de l'expression « virtual
machine » en anglais, et son utilisation avant Java. La
spécification de la machine virtuelle ne concerne pas son
implémentation, mais son « contrat ». Les byte-code définit la
sémantique, mais comment la VM même y arrive, c'est son affaire.
Ce n'est pas tout à fait pareil, mais on pourrait imaginer la
spécification de la machine virtuelle comme la spécification de
la machine abstraite de C++ dans la norme C++. La spécification
définit un comportement visible (ou un ensemble de comportements
visibles possibles, dans le cas de C++) pour un programme donné.
Ensuite, c'est la responsibilité de l'interpréteur ou du
compilateur pour traduire le programme en code machine
exécutable, soit en interprétant chaque instructions ou chaque
action dans la machine abstraite une par une, soit en faisant
quelque chose de plus astucieux.
Il faut dire que le concept d'une VM n'est pas quelque chose de
nouveau avec Java. Il existait bien avant : le Pascal de UCSD
s'en servait, par exemple, de même que certaines implémentations
de Lisp. C'est un concept assez connu.
Je me base sur la signification de l'expression « virtual
machine » en anglais, et son utilisation avant Java. La
spécification de la machine virtuelle ne concerne pas son
implémentation, mais son « contrat ». Les byte-code définit la
sémantique, mais comment la VM même y arrive, c'est son affaire.
Ce n'est pas tout à fait pareil, mais on pourrait imaginer la
spécification de la machine virtuelle comme la spécification de
la machine abstraite de C++ dans la norme C++. La spécification
définit un comportement visible (ou un ensemble de comportements
visibles possibles, dans le cas de C++) pour un programme donné.
Ensuite, c'est la responsibilité de l'interpréteur ou du
compilateur pour traduire le programme en code machine
exécutable, soit en interprétant chaque instructions ou chaque
action dans la machine abstraite une par une, soit en faisant
quelque chose de plus astucieux.
Il faut dire que le concept d'une VM n'est pas quelque chose de
nouveau avec Java. Il existait bien avant : le Pascal de UCSD
s'en servait, par exemple, de même que certaines implémentations
de Lisp. C'est un concept assez connu.
Je me base sur la signification de l'expression « virtual
machine » en anglais, et son utilisation avant Java. La
spécification de la machine virtuelle ne concerne pas son
implémentation, mais son « contrat ». Les byte-code définit la
sémantique, mais comment la VM même y arrive, c'est son affaire.
Ce n'est pas tout à fait pareil, mais on pourrait imaginer la
spécification de la machine virtuelle comme la spécification de
la machine abstraite de C++ dans la norme C++. La spécification
définit un comportement visible (ou un ensemble de comportements
visibles possibles, dans le cas de C++) pour un programme donné.
Ensuite, c'est la responsibilité de l'interpréteur ou du
compilateur pour traduire le programme en code machine
exécutable, soit en interprétant chaque instructions ou chaque
action dans la machine abstraite une par une, soit en faisant
quelque chose de plus astucieux.
Il faut dire que le concept d'une VM n'est pas quelque chose de
nouveau avec Java. Il existait bien avant : le Pascal de UCSD
s'en servait, par exemple, de même que certaines implémentations
de Lisp. C'est un concept assez connu.