ASM Type top (current frame, locals[3]) is not assignable [How to Solve]

Let’s start with the problems encountered. Hasor runs ASM in 1.6 and early 1.7 JDK, and the bytecode generated dynamically has no exception. Then there was a feedback that an exception similar to the following appeared in java8. At the beginning, there was no exception information in Java 8. One solution is to add a – noverify parameter to suppress the check exception

Recently, I am curious to find out why verifyerror error occurs. Here is a panorama of this error


2017-02-15 11:03:47.423 [RSF-Nio-4] INFO  - connected form 127.0.0.1:60618
2017-02-15 11:03:47.440 [RSF-Biz-1] ERROR - do request(12345) failed -> service [RSF]net.hasor.website.client.ProjectService-1.0.0, error :(net.hasor.core.utils.UnhandledException)java.lang.VerifyError - Inconsistent stackmap frames at branch target 101
Exception Details:
  Location:
    net/hasor/website/manager/UserManager$A_19.loginUpdate(Lnet/hasor/website/domain/UserDO;Ljava/lang/String;)V @101: new
  Reason:
    Type top (current frame, locals[3]) is not assignable to 'java/lang/Throwable' (stack map, locals[3])
  Current Frame:
    bci: @92
    flags: { }
    locals: { 'net/hasor/website/manager/UserManager$A_19', 'net/hasor/website/domain/UserDO', 'java/lang/String', top, top, 'java/lang/Throwable' }
    stack: { integer }
  Stackmap Frame:
    bci: @101
    flags: { }
    locals: { 'net/hasor/website/manager/UserManager$A_19', 'net/hasor/website/domain/UserDO', 'java/lang/String', 'java/lang/Throwable' }
    stack: { }
  Bytecode:
    0x0000000: 1002 bd00 0659 1000 1208 5359 1001 120a
    0x0000010: 533a 0410 02bd 000c 5910 002b 5359 1001
    0x0000020: 2c53 3a05 2ab6 0012 1213 1904 b600 173a
    0x0000030: 06bb 0019 5919 062a 1905 b700 1d3a 07bb
    0x0000040: 001f 5912 2119 0619 07b7 0024 b600 283a
    0x0000050: 0819 0857 b13a 0519 05c1 002a 9900 0919
    0x0000060: 05c0 002a bfbb 002a 5919 05b7 002d bf  
  Exception Handler Table:
    bci [0, 83] => handler: 85
  Stackmap Table:
    same_locals_1_stack_item_extended(@85,Object[#4])
    append_frame(@101,Object[#4])

net.hasor.core.utils.UnhandledException: java.lang.VerifyError - Inconsistent stackmap frames at branch target 101
Exception Details:
  Location:
    net/hasor/website/manager/UserManager$A_19.loginUpdate(Lnet/hasor/website/domain/UserDO;Ljava/lang/String;)V @101: new
  Reason:
    Type top (current frame, locals[3]) is not assignable to 'java/lang/Throwable' (stack map, locals[3])
  Current Frame:
    bci: @92
    flags: { }
    locals: { 'net/hasor/website/manager/UserManager$A_19', 'net/hasor/website/domain/UserDO', 'java/lang/String', top, top, 'java/lang/Throwable' }
    stack: { integer }
  Stackmap Frame:
    bci: @101
    flags: { }
    locals: { 'net/hasor/website/manager/UserManager$A_19', 'net/hasor/website/domain/UserDO', 'java/lang/String', 'java/lang/Throwable' }
    stack: { }
  Bytecode:
    0x0000000: 1002 bd00 0659 1000 1208 5359 1001 120a
    0x0000010: 533a 0410 02bd 000c 5910 002b 5359 1001
    0x0000020: 2c53 3a05 2ab6 0012 1213 1904 b600 173a
    0x0000030: 06bb 0019 5919 062a 1905 b700 1d3a 07bb
    0x0000040: 001f 5912 2119 0619 07b7 0024 b600 283a
    0x0000050: 0819 0857 b13a 0519 05c1 002a 9900 0919
    0x0000060: 05c0 002a bfbb 002a 5919 05b7 002d bf  
  Exception Handler Table:
    bci [0, 83] => handler: 85
  Stackmap Table:
    same_locals_1_stack_item_extended(@85,Object[#4])
    append_frame(@101,Object[#4])

	at net.hasor.core.utils.ExceptionUtils.toRuntimeException(ExceptionUtils.java:28) ~[classes/:na]
	at net.hasor.core.container.TemplateBeanBuilder.createObject(TemplateBeanBuilder.java:159) ~[classes/:na]
	at net.hasor.core.container.BeanContainer.callSuperCreateObject(BeanContainer.java:156) ~[classes/:na]
	at net.hasor.core.container.BeanContainer.access$000(BeanContainer.java:42) ~[classes/:na]
	at net.hasor.core.container.BeanContainer$1.get(BeanContainer.java:144) ~[classes/:na]
	at net.hasor.core.provider.SingleProvider.get(SingleProvider.java:35) ~[classes/:na]
	at net.hasor.core.container.BeanContainer.createObject(BeanContainer.java:142) ~[classes/:na]
	at net.hasor.core.container.TemplateBeanBuilder.getDefaultInstance(TemplateBeanBuilder.java:88) ~[classes/:na]
	at net.hasor.core.context.TemplateAppContext$1.get(TemplateAppContext.java:149) ~[classes/:na]
	at net.hasor.core.context.TemplateAppContext.getInstance(TemplateAppContext.java:98) ~[classes/:na]
	at net.hasor.core.container.TemplateBeanBuilder.injInject(TemplateBeanBuilder.java:249) ~[classes/:na]
	at net.hasor.core.container.TemplateBeanBuilder.injectObject(TemplateBeanBuilder.java:232) ~[classes/:na]
	at net.hasor.core.container.TemplateBeanBuilder.doInject(TemplateBeanBuilder.java:176) ~[classes/:na]
	at net.hasor.core.container.TemplateBeanBuilder.createObject(TemplateBeanBuilder.java:149) ~[classes/:na]
	at net.hasor.core.container.BeanContainer.callSuperCreateObject(BeanContainer.java:156) ~[classes/:na]
	at net.hasor.core.container.BeanContainer.access$000(BeanContainer.java:42) ~[classes/:na]
	at net.hasor.core.container.BeanContainer$1.get(BeanContainer.java:144) ~[classes/:na]
	at net.hasor.core.provider.SingleProvider.get(SingleProvider.java:35) ~[classes/:na]
	at net.hasor.core.container.BeanContainer.createObject(BeanContainer.java:142) ~[classes/:na]
	at net.hasor.core.container.TemplateBeanBuilder.getDefaultInstance(TemplateBeanBuilder.java:88) ~[classes/:na]
	at net.hasor.core.context.TemplateAppContext$1.get(TemplateAppContext.java:149) ~[classes/:na]
	at net.hasor.core.context.TemplateAppContext.getInstance(TemplateAppContext.java:98) ~[classes/:na]
	at net.hasor.core.container.TemplateBeanBuilder.injInject(TemplateBeanBuilder.java:249) ~[classes/:na]
	at net.hasor.core.container.TemplateBeanBuilder.injectObject(TemplateBeanBuilder.java:232) ~[classes/:na]
	at net.hasor.core.container.TemplateBeanBuilder.doInject(TemplateBeanBuilder.java:176) ~[classes/:na]
	at net.hasor.core.container.TemplateBeanBuilder.createObject(TemplateBeanBuilder.java:149) ~[classes/:na]
	at net.hasor.core.container.BeanContainer.callSuperCreateObject(BeanContainer.java:156) ~[classes/:na]
	at net.hasor.core.container.BeanContainer.createObject(BeanContainer.java:148) ~[classes/:na]
	at net.hasor.core.container.TemplateBeanBuilder.getDefaultInstance(TemplateBeanBuilder.java:88) ~[classes/:na]
	at net.hasor.core.context.TemplateAppContext$1.get(TemplateAppContext.java:149) ~[classes/:na]
	at net.hasor.core.context.TemplateAppContext.getInstance(TemplateAppContext.java:98) ~[classes/:na]
	at net.hasor.core.provider.ClassAwareProvider.get(ClassAwareProvider.java:40) ~[classes/:na]
	at net.hasor.rsf.rpc.caller.remote.RsfInvokeFilterChain.doFilter(RsfInvokeFilterChain.java:40) ~[classes/:na]
	at net.hasor.rsf.rpc.caller.RsfFilterHandler.doFilter(RsfFilterHandler.java:43) ~[classes/:na]
	at net.hasor.rsf.filters.online.OnlineRsfFilter.doFilter(OnlineRsfFilter.java:37) ~[classes/:na]
	at net.hasor.rsf.rpc.caller.RsfFilterHandler.doFilter(RsfFilterHandler.java:41) ~[classes/:na]
	at net.hasor.rsf.filters.thread.LocalWarpFilter.doFilter(LocalWarpFilter.java:32) ~[classes/:na]
	at net.hasor.rsf.rpc.caller.RsfFilterHandler.doFilter(RsfFilterHandler.java:41) ~[classes/:na]
	at net.hasor.rsf.filters.local.LocalPref.doFilter(LocalPref.java:49) ~[classes/:na]
	at net.hasor.rsf.rpc.caller.RsfFilterHandler.doFilter(RsfFilterHandler.java:41) ~[classes/:na]
	at net.hasor.rsf.filters.trace.TraceFilter.doFilter(TraceFilter.java:40) ~[classes/:na]
	at net.hasor.rsf.rpc.caller.RsfFilterHandler.doFilter(RsfFilterHandler.java:41) ~[classes/:na]
	at net.hasor.rsf.rpc.caller.remote.InvokerProcessing.run(InvokerProcessing.java:152) ~[classes/:na]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_74]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_74]
	at java.lang.Thread.run(Thread.java:745) [na:1.8.0_74]
Caused by: java.lang.VerifyError: Inconsistent stackmap frames at branch target 101
Exception Details:
  Location:
    net/hasor/website/manager/UserManager$A_19.loginUpdate(Lnet/hasor/website/domain/UserDO;Ljava/lang/String;)V @101: new
  Reason:
    Type top (current frame, locals[3]) is not assignable to 'java/lang/Throwable' (stack map, locals[3])
  Current Frame:
    bci: @92
    flags: { }
    locals: { 'net/hasor/website/manager/UserManager$A_19', 'net/hasor/website/domain/UserDO', 'java/lang/String', top, top, 'java/lang/Throwable' }
    stack: { integer }
  Stackmap Frame:
    bci: @101
    flags: { }
    locals: { 'net/hasor/website/manager/UserManager$A_19', 'net/hasor/website/domain/UserDO', 'java/lang/String', 'java/lang/Throwable' }
    stack: { }
  Bytecode:
    0x0000000: 1002 bd00 0659 1000 1208 5359 1001 120a
    0x0000010: 533a 0410 02bd 000c 5910 002b 5359 1001
    0x0000020: 2c53 3a05 2ab6 0012 1213 1904 b600 173a
    0x0000030: 06bb 0019 5919 062a 1905 b700 1d3a 07bb
    0x0000040: 001f 5912 2119 0619 07b7 0024 b600 283a
    0x0000050: 0819 0857 b13a 0519 05c1 002a 9900 0919
    0x0000060: 05c0 002a bfbb 002a 5919 05b7 002d bf  
  Exception Handler Table:
    bci [0, 83] => handler: 85
  Stackmap Table:
    same_locals_1_stack_item_extended(@85,Object[#4])
    append_frame(@101,Object[#4])

	at java.lang.Class.getDeclaredConstructors0(Native Method) ~[na:1.8.0_74]
	at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671) ~[na:1.8.0_74]
	at java.lang.Class.getConstructor0(Class.java:3075) ~[na:1.8.0_74]
	at java.lang.Class.getConstructor(Class.java:1825) ~[na:1.8.0_74]
	at net.hasor.core.container.TemplateBeanBuilder.createObject(TemplateBeanBuilder.java:142) ~[classes/:na]
	... 44 common frames omitted

Process finished with exit code 137 (interrupted by signal 9: SIGKILL)

———-

The AOP function of hasor is to dynamically proxy through ASM, and each proxy method will be generated in the following way. In general, the generated class is in memory and cannot be seen on the local disk. In order to check the framework problems, the “work” is added after hasor 3.1.0_ Set the “mode” environment variable parameter to debug

After that, all classes that are dynamically proxied by hasor will save the generated class to the temp directory under the work directory

Now let’s take a look at the overview of the dynamic proxy method of hassor AOP. This ASM generates Java decompilation of dynamic classes, and visually checks that the generated code has no exception

———-

Since the code decompiled into Java source file can not see the clue, let’s directly “javap – P – C” look at the different parts of the bytecode instructions. Javap decompiled, generated code (right) and java8 compiled code (left). After bytecode decompilation, it seems that we can see the clue. Is it because the return instruction forces postposition

———-

Since the problem code is in the catch block, simplify the generated code of exception throw. Encapsulate the above code into a tool class, and then generate a simpler throw statement, as follows:

Problem solving

———-

To sum up: Although the last cause of the exception instruction is not found, but the problem is solved. Finally, the reason lies in the generated if code. Later, I have time to go deep into the JVM source code to see what new things have been added to jdk8

———-

Last update

The problem was solved about a year ago. I can see this blog updated conveniently. The problem of that year was composed of two small problems

-The first problem is that the result of bytecode generation instruction is not rigorous enough, and the JDK version is irrelevant, so the – noverify parameter needs to be added because the lax code can run, but there is a security risk, so the parameter needs to be added to suppress it

-The second problem is that there is still a lot of knowledge in the generation of if in this paper. If alone, it is better to say that putting try caches together is easier to generate errors

At present, the bytecode enhancement part of hasor has run perfectly on each JVM platform

Pay attention to the following items when generating bytecode:

When double and long are used as input parameters, the order of the variable tables of these two types on the method input parameter is extra + 1

Don’t deliberately ignore the output “visitlocalvariable” of the method variable table. Although it can be ignored, the compiler will report an error. This error can be suppressed by – noverify, but it is not rigorous after all

Similar Posts: