ich stehe gerade auf dem Schlauch und hoffe, ihr könnt mir helfen. Meine Methode “main” sieht so aus:
/* local_1 = new long[64]; */
0: ldc #8; //int 64
2: newarray long
4: astore_1
/* local_2 = 0; */
5: iconst_0
6: istore_2
/* invoke: System.in.read()I */
7: getstatic #14; //Field java/lang/System.in:Ljava/io/InputStream;
10: invokevirtual #20; //Method java/io/InputStream.read:()I
/* return-Wert in long umwandeln */
13: i2l
/* Duplizieren */
14: dup
/* Mit 0L vergleichen */
15: lconst_0
16: lcmp
/* Zu 22 gehen, wenn eingabe >= 0 ist */
17: ifge 22
/* Wert durch 0 ersetzen */
20: pop2
21: lconst_0
/* local_1[local_2] = ergebnis */
22: aload_1
23: dup_x2
24: pop
25: iload_2
26: dup_x2
27: pop
28: lastore
29: return
Allerdings mag das die JVM nicht: Exception in thread "main" java.lang.VerifyError: (class: test, method: main signature: ([Ljava/lang/String;)V) Attempt to split long or double on the stack
Der Code wurde ursprünglich für ints (32 bit) kompiliert, jetzt habe ich einen Teil umgeschrieben, um longs (64 bit) zu nutzen. Ich habe einige Probleme, die dabei auftauchten, gelöst, aber jetzt weiß ich nicht mehr weiter.
Ich würde mich wirklich freuen, wenn sich jemand die Mühe machen würde, mir zu helfen!
Liebe Grüße!
long und double benötigen zwei Plätze auf dem Stack (und auch zwei aufeinander folgende lokale Variablen). Es wird immer sicher gestellt, dass die beiden “Hälften” eines long oder double nicht getrennt voneinander genutzt werden. Liegt beispielsweise ein long auf dem Stack, sollte ein anschließendes iadd mit dem angegebenen Fehler quittiert werden; es müssen zwei ints auf dem Stack sein.
Hoffe, das hilft. Den genauen Fehler such ich nicht, das ist mir jetzt doch zu aufwendig.
Ich verstehe nicht so ganz, worauf Du hinaus willst. long und double sind jeweils 64 bit groß, der Stack der JVM aber nur 32 bit breit.
Natürlich steht es jedem Implementierer frei, das anders zu handhaben, aber für den Index von lokalen Variablen und eben für den Stack ist es relevant.
Sicherlich, wenn es die denn gäbe In meinem Fall gibt es die Möglichkeit leider nicht. Außerdem möchte ich gern verstehen, wo das Problem liegt.
Danke für die schnelle Antwort! Das Problem mit den Größen kenne ich und die Fehlermeldung verstehe ich auch. Aber ich kann nicht nachvollziehen, wo der Fehler auftritt. Kann die JVM anzeigen, bei welcher Bytecode-Anweisung die Verifizierung fehlschlägt? Ich habe versucht, den Code so anzupassen, dass er mit den doppelt so großen Werten umgehen kann (z.B. wird IFGE zu LCONST_0, LCMP, IFGE).
Für den zweiten Punkt habe ich es noch nicht genau genug gelesen, aber für den ersten: Lass die .class durch einen Decompiler laufen und ändere das ganze…
Es geht nicht um diese Methode, die kann jeder Java-Anfänger neu schreiben. Mein Compiler soll den Code erzeugen.
Die main-Methode oben ist ein ganz einfaches Beispiel. Ich brauche Hilfe beim Bytecode
Du könntest noch probieren, die bearbeitete Klasse mit einer Bibliothek für Bytecode-Manipulation zu laden (z.B. javassist oder ASM). Vielleicht haben die bessere Fehlermeldungen.
Ich verwende ASM, um den Code zu erzeugen, ich nehme an, das hätte mir schon beim Generieren der class-Datei einen Fehler geworfen. javassist habe ich noch nicht probiert, das werde ich (sobald möglich) nachholen.
Fühlt sich jemand in der Lage, mal kurz über den Bytecode rüberzugucken? Ich habe ein paar Kommentare reingeschrieben, und so lang ist er ja nicht. Der einzige komplizierte Teil ist am Ende, weil ich dort die Werte auf dem Stack sortieren muss.
Ich bemühe mich schon seit Tagen daran, aber ich finde den Fehler einfach nicht. Stack size müsste auch stimmen.
Es würde mich wirklich freuen, wenn mir jemand helfen kann!
Gerade getestet, die Datei wird von javassist auch problemlos gelesen. Allerdings glaube ich nicht, dass ASM / javassist die Instruktionen wirklich (wie die JVM) verifizieren.
[QUOTE=Unregistered]Ich verwende ASM, um den Code zu erzeugen, ich nehme an, das hätte mir schon beim Generieren der class-Datei einen Fehler geworfen. javassist habe ich noch nicht probiert, das werde ich (sobald möglich) nachholen.
Fühlt sich jemand in der Lage, mal kurz über den Bytecode rüberzugucken? Ich habe ein paar Kommentare reingeschrieben, und so lang ist er ja nicht. Der einzige komplizierte Teil ist am Ende, weil ich dort die Werte auf dem Stack sortieren muss.
Ich bemühe mich schon seit Tagen daran, aber ich finde den Fehler einfach nicht. Stack size müsste auch stimmen.
Es würde mich wirklich freuen, wenn mir jemand helfen kann! :)[/QUOTE]
An der Position 14 brauchst du ein dup2 statt dup. ASM hat auch ganz ein schönes Tools um solche Fehler besser analysieren zu können. Immer wenn eine erzeugt Klasse einen VerifyError beim laden wirft lohnt es sich den erzeugten ByteCode nochmal durch den CheckClassAdapter von ASM zu jagen und die Ausgaben mitzuloggen.
Um besser zu lernen wie der ByteCode richtig aussehen muß ist es empfehlenswert das ganze als einfache Java Klasse von Hand zu schreiben, zu kompilieren und dann durch den ASMifier zu jagen. Da kriegst du dann genau den Code raus der nötig gewesen wäre um exakt diese Klasse mit ASM zur Laufzeit generieren zu können. Ich habe irgendwo auch schonmal ein Eclipse Plugin gesehen das den ASMifier in die IDE einbindet.
Mein Gott, danke! So was banales. Vielen Dank! Ich habe es noch nicht probiert, aber jetzt wo du es sagst…
Den CheckClassAdapter sehe ich mir mal an, danke. Den anderen Weg - Klasse kompilieren und als ASM-Code ausgeben lassen - habe ich auch an verschiedenen Stellen verwendet, aber das JDK weigert sich, den Code so zu kompilieren, wie ich ihn will. Kein Wunder, schließlich sind die ganzen Swap-Varianten ziemlich umständlich. Aber der Aufbau meines Compilers passt einfach besser zu dieser Form. Außerdem wüsste ich jetzt nicht, wie ich den return-Wert von System.in.read() in Java mit 0 vergleiche, ändere und in ein Array schreibe, ohne eine weitere lokale Variable zu verwenden. Klar, das wäre möglich, aber ich dachte mir, das muss auch so gehen.