I've modified the line 15 of the bytecode below and changed it form invokevirtual to invokespecial (JAVA 8). Unfortunately I get a verify error ( Bad type on operand stack)
I know that the value of the operand stack must be a subclass of the class specified in the objectref but in this case #18 is Type and not Type$ClassType like the error suggest. Or to say it differently shouldn't the stackmapframe at line 15 have Type and not Type$ClassType in stack[0]? What am I missing?
edit: stackmapframes are the same before and after the change. (in case ASM COMPUTE FRAMES which I used would changed them)
Exception Details:
Location:
com/sun/tools/javac/code/Type$ClassType.toString()Ljava/lang/String; @15: invokespecial
Reason:
Type 'com/sun/tools/javac/code/Type' (current frame, stack[0]) is not assignable to 'com/sun/tools/javac/code/Type$ClassType'
Current Frame:
bci: @15
flags: { }
locals: { 'com/sun/tools/javac/code/Type$ClassType', 'java/lang/StringBuilder' }
stack: { 'com/sun/tools/javac/code/Type', 'com/sun/tools/javac/code/TypeTag' }
...
Stackmap Table:
append_frame(@71,Object[#108])
same_frame(@85)
same_frame(@121)
Here's is the code. Type$ClassType is a direct subclass of Type and com/sun/tools/javac/code/Type$ClassType is the current class which allows us to call a superclass (like Type) with invokespecial
public class com.sun.tools.javac.code.Type$ClassType extends com.sun.tools.javac.code.Type implements
javax.lang.model.type.DeclaredType
....
public java.lang.String toString();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=4, locals=2, args_size=1
0: new #108 // class java/lang/StringBuilder
3: dup
4: invokespecial #17 // Method java/lang/StringBuilder."<init>":()V
7: astore_1
8: aload_0
9: invokevirtual #13 // Method com/sun/tools/javac/code/Type$ClassType.getEnclosingType:()Lcom/sun/tools/javac/code/Type;
12: getstatic #10 // Field com/sun/tools/javac/code/TypeTag.CLASS:Lcom/sun/tools/javac/code/TypeTag;
15: invokespecial #18 // Method com/sun/tools/javac/code/Type.hasTag:(Lcom/sun/tools/javac/code/TypeTag;)Z
18: ifeq 71
.....
StackMapTable: number_of_entries = 3
frame_type = 252 /* append */
offset_delta = 71
locals = [ class java/lang/StringBuilder ]
frame_type = 13 /* same */
frame_type = 35 /* same */
You attempt to execute invokespecial
on an instance of Type
(returned by invokevirtual
@9), while the verifier expects the reference of current class, i.e. Type$ClassType
.
See JVMS §4.10.1.9:
One can validly replace types matching the current class and the argument types given in Descriptor on the incoming operand stack with the return type given in Descriptor, yielding the outgoing type state.