7
votes

Bug JVM? Valeur de champ d'objet mis en cache Cause arrayindexoutofboundsException

C'est une sorte d'étrange, mais le code parle plus que des mots, alors regardez le test pour voir ce que je fais. Dans ma configuration actuelle (Java 7 Mise à jour 21 sous Windows 64 bit) Ce test échoue avec ArrayIndexoutofboundSException, mais le remplacement du code de méthode de test avec le code commenté, le fonctionnement. Et je me demande s'il y a une partie de la spécification Java qui expliquerait pourquoi.

Il me semble que "Michael Nesterenko" suggère que la valeur du champ de tableau est mise en cache dans la pile, avant d'appeler la méthode, et non mis à jour le retour de l'appel. Je ne peux pas dire s'il s'agit d'un bug JVM ou d'une "optimisation" documentée. Pas de multi-filetage ou "magique" impliqué. xxx


4 commentaires

Juste une suppose, lorsque vous appelez grandir à partir de tableau, il est déjà en pile et donc le lien n'est pas mis à jour, mais si vous appelez GROGUER avant, puis utilisez l'index, lien vers le tableau est chargé après la mise à jour et cela fonctionne donc. Juste une supposition. Peut-être que regarder le code des octets pourrait aider


Je ne l'appellerais pas "mis en cache dans la pile". Je pense que c'est une question java (la langueuse). Vous référencez un nom, qui est résolu avant en utilisant / appliquant la valeur résolue associée à celle-ci. Donc, si le nom est réaffecté entre les deux, vous avez la mauvaise valeur.


Voici un cas d'essai plus simple: Classe publique TestaioOB {Objet statique [] Array; static int réassigne () {array = nouvel objet [] {nouvel objet ()}; retour 0; } Void statique public principal (chaîne [] args) {system.out.println (réaffectation (réaffectation ()]); }} . Cela jette (comme si cela devrait), et vous demandez pourquoi.


Il convient de mentionner que ce n'est pas seulement Java. La référence de tableau est évaluée avant l'appel Appel JavaScript ( exemple ), C # ( exemple ), et c ( Exemple ) également, et probablement d'autres mais je ne les essayais pas. (Vous pouvez exécuter l'un ou l'autre de ces deux derniers en ligne ici: compileonline.com )


3 Réponses :


0
votes

Comparer le code Java compilé à l'aide de Javap -C TestaioOOOOOOOOB CODE>

CODE COMMENTAIRE: P>

public void testGrow();
  Code:
   0:   aload_0
   1:   ldc     #6; //String test
   3:   invokespecial   #7; //Method grow:(Ljava/lang/String;)I
   6:   istore_1
   7:   getstatic       #8; //Field java/lang/System.out:Ljava/io/PrintStream;
   10:  aload_0
   11:  getfield        #3; //Field array:[Ljava/lang/String;
   14:  iload_1
   15:  aaload
   16:  invokevirtual   #9; //Method java/io/PrintStream.println:(Ljava/lang/Str
ing;)V
   19:  return


1 commentaires

Cela explique le comportement, mais cela n'explique pas pourquoi il a été compilé comme ça. Il doit y avoir quelque chose dans les JLS ...



6
votes

Ceci est bien défini par Spécification de la langue Java : évaluer x [y] , premier x est évalué, puis y est évalué. Dans votre cas, x évalue vers une chaîne [] avec zéro éléments. Ensuite, y modifie une variable de membre et évalue à 0 . Essayer d'accéder à l'élément du 0ème de la matrice déjà retournée échoue. Le fait que le membre modifications n'a aucune incidence sur la recherche de tableau, car nous envisageons la chaîne [] que array référencé à le temps que nous l'avons évalué.


1 commentaires

Là-bas comme la première balle sur le lien. Excellent.