2011-01-19 2 views
1

Je dois instrumenter des méthodes natives pour effectuer un appel statique simple avant de l'exécuter normalement. Parce que les méthodes sont natives, je dois utiliser le "setNativePrefix" feature et envelopper les méthodes natives avec un appel intermédiaire avec la signature de la méthode d'origine. Après ce que je pensais être un simple changement de bytecode pour accomplir ceci, j'obtiens un StackOverflowError juste avant que la méthode wrapper soit exécutée même si la pile est fondamentalement vide. Voici ma classe de test:Pourquoi ce simple bytecode Java provoque-t-il une erreur StackOverflow?

public class SimpleTest { 
    public static void main(String[] args) throws IOException { 
     Perf.getPerf().highResCounter(); 
    } 
} 

Normalement, ce programme ne produira rien sur la console. Cependant, mon bytecode instrumenté exécute un println() avant d'exécuter la méthode native $ wrapper $ highResCounter(). Cela peut être vu dans la catégorie concernée après l'instrumentation bytecode Perf:

public long highResCounter() { 
    getstatic PrintStream System.out 
    ldc String Constant "this is an instrumented println" 
    invokevirtual void PrintStream.println(String) 
    aload 0 
    invokevirtual long Perf.$wrapped$highResCounter() 
    lreturn 
} 

public native long $wrapped$highResCounter(); 

Je suis un peu nouveau pour bytecode Java, donc je probablement fait une erreur. Voici la sortie du programme, ce qui montre que le println() est exécuté, mais quelque part après la première invokevirtual appel a StackOverflowError:

this is an instrumented println call 
Exception in thread "main" java.lang.StackOverflowError 
    at com.foo.SimpleTest.main(SimpleTest.java:17) 

ce qui pourrait causer ce StackOverflowError? Et comment puis-je le réparer?

+0

Avez-vous le SimpleTest.java complet pour nous? Avez-vous traversé avec un débogueur? Peut-être que vous ne courez pas ce que vous pensez que vous exécutez. (Cela me rappelle un bug il ya des années, j'ai cherché pendant des heures jusqu'à ce que je me rende compte que mon classpath pointait vers d'anciens fichiers de classe :) –

+0

C'est l'intégralité de la classe, moins la déclaration d'import et l'identifiant du paquet. Aucun initialiseur statique ou quoi que ce soit. – nahsra

+0

Cela arrive aussi sur n'importe quelle méthode native: comme StrictMath.sin(). Je ne pense pas que cela ait quelque chose à voir avec Perf. – nahsra

Répondre

1

Il n'y a pas de bugs dans le code affiché. Le problème était dû à des valeurs non valides pour les attributs de méthode MAX_STACK et MAX_LOCALS, qui sont généralement calculés par le compilateur.

La librairie de code bytecode que j'utilise, ASM, vous donne la possibilité de calculer ces valeurs automatiquement, et je n'en ai pas profité. En changeant le constructeur ASM ClassWriter à ce qui suit, je reçois un code sans erreur:

int flags = ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS; 
ClassWriter writer = new ClassWriter(flags); 

[1] http://asm.ow2.org/asm33/javadoc/user/org/objectweb/asm/ClassWriter.html#COMPUTE_FRAMES

+0

le vérificateur se plaint généralement bruyamment de tels cas – bestsss

+0

J'aurais dû y penser. Je pense que j'ai été là/fait cela. Bon travail. –

1

Votre méthode highResCounter appelle lui-même:

public long highResCounter() { 
    [...] 
    invokevirtual long Perf.$wrapped$highResCounter() 

Avez-vous plus de code que vous pouvez nous montrer pour savoir pourquoi?

+0

Ça ne s'appelle pas. Il appelle la méthode native $ wrappée $ highResCounter. La version non native est là uniquement pour que je puisse passer un coup de fil avant de transférer la responsabilité à la version native. – nahsra

+0

En quoi $ $ highResCounter est-il appelé? –

+0

@nahsra - clairement * Quelque chose * s'appelle directement ou indirectement, ou vous n'obtiendrez pas une exception de dépassement de pile. –

0

montre la fonction native, il peut aussi s'agir d'un problème de son propre chef. iirc StackOverFlowError est piégé, donc même le code JNI C peut le provoquer.

+0

J'ai lié le code cpp natif dans la réponse d'EboMike. – nahsra

+0

De plus, cela arrive avec toutes les méthodes natives que j'essaie, donc cela n'a probablement rien à voir avec le code natif. – nahsra