2012-02-10 3 views
10

J'ai utilisé Javassist pour manipuler dynamiquement des classes lorsqu'elles sont chargées. Alors que l'ajout de code à une méthode est relativement facile en utilisant Javassist, je n'ai pas été en mesure de trouver un moyen de supprimer le code.Suppression d'instructions du bytecode Java

À l'heure actuelle, je simule la suppression du code en utilisant les instructions nop pour remplacer les opcodes ciblés et tous les paramètres. Cependant, je considère cela comme la plupart du temps un hack:

  • Chaque opcode doit être traitée séparément, puisque la longueur d'octets des paramètres diffère. Dans certains cas, j'ai également besoin de choisir entre nop et pop, selon que l'opcode supprimé affecte ou non la pile. Ce type de manipulation commence à devenir fastidieux - et le code qui le fait devient alambiqué. Donc, naturellement, j'espère une solution existante. Le résultat final est rempli avec nop instructions. Alors que la JVM devrait optimiser ceux sans impact sur les performances, le bytecode résultant est encore assez inélégant et plus grand qu'il ne devrait l'être. C'est plus une question d'esthétique, mais c'est encore quelque chose à considérer.

Malheureusement, seulement le déplacement des pièces de la matrice de bytecode à combler l'écart ne suffit pas - toutes les références à l'aide du code déplacé (par exemple, des indices d'instruction de branchement) doit être mis à jour.

Est-il possible de supprimer des instructions en utilisant Javassist? Sinon, existe-t-il une bibliothèque de manipulation de bytecode qui me permettrait de le faire facilement, sans avoir à analyser essentiellement le bytecode moi-même?

+2

Je suis simplement curieux. Pourquoi veux-tu faire cela? Ne serait-il pas plus facile de décompiler les classes, de les modifier et de les compiler à nouveau? – Luixv

+0

@Luixv: Je veux que le processus de manipulation se fasse automatiquement à l'exécution - la modification manuelle du code source n'est pas une option, car les transformations ne sont pas corrigées. – thkala

+0

Si vous placez la classe dans un 'jar', le redondant' nop' sera assez bien compressé et la taille compressée ne sera pas beaucoup plus grande. –

Répondre

3

Apache BCEL vous permet de delete instructions:

Suppression d'instructions est également très simple; toutes les poignées d'instructions et les instructions contenues dans une plage donnée sont supprimées de la liste d'instructions et éliminées. La méthode delete() peut cependant lancer une exception TargetLostException quand des cibles d'instruction font toujours référence à l'une des instructions supprimées. L'utilisateur est obligé de gérer ces exceptions dans une clause try-catch et de rediriger ces références ailleurs.

Vous trouverez également un exemple dans le manuel.

+0

+1 Je n'ai pas encore regardé BCEL, mais cela semble prometteur. Je vais voir comme il serait facile d'incorporer dans mon code existant ... – thkala

0

Depuis le tutoriel javassist:

Javassist ne permet pas de supprimer une méthode ou d'un champ, mais il permet de changer le nom. Donc, si une méthode n'est plus nécessaire, elle doit être renommée et changée pour être une méthode privée en appelant setName() et setModifiers() déclaré dans CtMethod.

+0

Je ne veux pas supprimer une méthode - je veux supprimer les instructions de * dans * une méthode ... – thkala

+0

Oups, mon mauvais! Pour être complet, le tutoriel indique également: 'Pour supprimer un champ ou une méthode, appelez removeField() ou removeMethod() dans CtClass.' : S – user1205938