58 votes

Étrange entrée de table d'exceptions produite par le javac de Sun

Compte tenu de ce programme:

class Test {
    public static void main(String[] args) {
        try {
            throw new NullPointerException();
        } catch (NullPointerException npe) {
            System.out.println("In catch");
        } finally {
            System.out.println("In finally");
        }
    }
}

Du soleil, javac (v 1.6.0_24) produit la suite de bytecode:

public static void main(java.lang.String[]);

        // Instantiate / throw NPE
   0:   new     #2;         // class NullPointerException
   3:   dup
   4:   invokespecial   #3; // Method NullPointerException."<init>":()V
   7:   athrow

        // Start of catch clause
   8:   astore_1
   9:   getstatic       #4; // Field System.out
   12:  ldc     #5;         // "In catch"
   14:  invokevirtual   #6; // Method PrintStream.println
   17:  getstatic       #4; // Field System.out

        // Inlined finally block
   20:  ldc     #7;         // String In finally
   22:  invokevirtual   #6; // Method PrintStream.println
   25:  goto    39

        // Finally block
        // store "incomming" exception(?)
   28:  astore_2
   29:  getstatic       #4; // Field System.out
   32:  ldc     #7;         // "In finally"
   34:  invokevirtual   #6; // Method PrintStream.println

        // rethrow "incomming" exception
   37:  aload_2
   38:  athrow

   39:  return

Avec l'exception suivante table:

  Exception table:
   from   to  target type
     0     8     8   Class NullPointerException
     0    17    28   any
    28    29    28   any


Ma question est: Pourquoi sur la terre ne comprennent que la dernière entrée dans la table d'exception?!

Si je comprends bien, il dit en gros "si l' astore_2 lance une exception, l'attraper, et réessayer la même instruction".

Une telle entrée est produit, même avec vide try / catch / finally clauses telles que

try {} catch (NullPointerException npe) {} finally {}

Quelques observations

  • Eclipse compilateur ne génère aucune exception de ce type d'entrée de la table
  • La JVM spec ne documentent pas des exceptions d'exécution pour l' astore instruction.
  • Je sais que c'est légal pour la JVM de jeter VirtualMachineError pour les instructions. Je suppose que le propre entrée empêche toute erreur de la propagation de l'instruction.

9voto

fernacolo Points 1626

Il y a seulement deux explications sont possibles: le compilateur contient un bug ou c'est de placer une sorte de filigrane pour des raisons obscures.

Cette entrée est certainement faux, parce que toute exception levée par un bloc finally lui-même doit envoyer le flux d'exécution à l'exception du gestionnaire ou du bloc finally, mais jamais "exécuter à nouveau" le même bloc finally.

Aussi, une bonne preuve que c'est un bug/filigrane, c'est le fait qu'Eclipse (et peut-être d'autres compilateurs Java) ne sont pas générer de telles entrée, et même si Eclipse-classes générées fonctionner correctement sur Sun JVM.

Cela dit, ce post est intéressant car il semble que le fichier de classe est valide et vérifié. Si j'étais chargé de l'implémentation de la JVM, je ne serais pas entrée et de remplir un bug de Sun/Oracle!

7voto

Dan Cruz Points 7016

En regardant les OpenJDK 7 du code source, je me risquerais à deviner la raison pour cette dernière 28 29 28 any exception d'entrée de la table est parce que le code que les poignées de l' astore bytecode (voir code commençant à la ligne 1871) peut jetez un java.lang.LinkageError sauf si le sauté de la valeur de l'opérande de la pile n'est pas un returnAddress ou reference (voir le La Machine Virtuelle Java Specification for astore) et ils veulent que ce condition d'erreur s'affiche sur la trace de la pile.

Dans le cas où il y a un mauvais type d'opérande sur l'opérande de la pile, la JVM va claire l'opérande de la pile (à se débarrasser de cette mauvaise opérande), mettre un LinkageError sur l'opérande de la pile, et d'exécuter l' astore bytecode de nouveau, cette fois la réussite de l' astore bytecode à l'aide d'une JVM fournis LinkageError référence de l'objet. Voir la athrow la documentation pour plus d'informations.

Je serais très soupçonner la cause de racine de jeter un LinkageErrorau cours de astore de traitement est due à la complexité de la JSR/RET sous-routines introduire dans le bytecode de la vérification (OpenJDK changements 6878713, 6932496 et 7020373sont des données récentes de l' JSR's a continué complexité; je suis sûr que Sun/Oracle a d'autres à code source fermé les tests que nous ne voyons pas dans OpenJDK). L'OpenJDK 7020373 changer les utilisations LinkageError pour valider/invalider les résultats du test.

1voto

philwb Points 2847

D'après ce que je comprends, la deuxième entrée de la table des exceptions est la clause de capture tout implicite ajoutée par le compilateur pour couvrir les exceptions / erreurs renvoyées dans le corps ou les gestionnaires de capture, et la troisième entrée sert de garde à cette capture implicite pour forcer le flux à travers le enfin l'exécution.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X