- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 ASM 将 Callee::calcualte(int,int)int
的正文(其中包含 try-catch block )内联到 Caller::test
方法。生成的字节码看起来没问题,但由于异常而验证失败:
Exception in thread "main" java.lang.VerifyError: Instruction type does not match stack map
Exception Details:
Location:
CallerI.test(II)V @50: iload
Reason:
Current frame's stack size doesn't match stackmap.
Current Frame:
bci: @50
flags: { }
locals: { 'CallerI', integer, integer, integer, integer, 'code/sxu/asm/example/Callee', integer, 'java/lang/ReflectiveOperationException' }
stack: { }
Stackmap Frame:
bci: @50
flags: { }
locals: { 'CallerI', integer, integer, integer, integer, 'code/sxu/asm/example/Callee', integer, 'java/lang/Object' }
stack: { integer }
Bytecode:
0000000: 1b1c 602a b400 0e1b 1c3e 3604 3a05 0336
0000010: 06b8 002e 1230 1232 b200 3812 30b8 003e
0000020: b600 443a 07a7 000d 3a07 b200 4a12 4cb6
0000030: 0052 1506 a700 0364 3605 b200 5515 05b6
0000040: 0058 b200 5512 5ab6 0052 b1
Exception Handler Table:
bci [17, 37] => handler: 40
bci [17, 37] => handler: 40
Stackmap Table:
full_frame(@40,{Object[#2],Integer,Integer,Integer,Integer,Object[#21],Integer},{Object[#101]})
full_frame(@50,{Object[#2],Integer,Integer,Integer,Integer,Object[#21],Integer,Object[#4]},{Integer})
full_frame(@55,{Object[#2],Integer,Integer,Integer,Integer,Object[#21],Integer,Object[#4]},{Integer,Integer})
生成代码中标签14到标签52的字节码指令来自Callee::calculate主体,标签9到12的3条指令弹出两个int参数和接收者(Callee)。
//The generated bytecode method.
public void test(int, int);
flags: ACC_PUBLIC
Code:
stack=6, locals=8, args_size=3
0: iload_1
1: iload_2
2: iadd
3: aload_0
4: getfield #14 // Field _callee:Lcode/sxu/asm/example/Callee;
7: iload_1
8: iload_2
9: istore_3
10: istore 4
12: astore 5
14: iconst_0
15: istore 6
17: invokestatic #46 // Method java/lang/invoke/MethodHandles.publicLookup:()Ljava/lang/invoke/MethodHandles$Lookup;
20: ldc #48 // class java/lang/String
22: ldc #50 // String say
24: getstatic #56 // Field java/lang/Void.TYPE:Ljava/lang/Class;
27: ldc #48 // class java/lang/String
29: invokestatic #62 // Method java/lang/invoke/MethodType.methodType:(Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/invoke/MethodType;
32: invokevirtual #68 // Method java/lang/invoke/MethodHandles$Lookup.findVirtual:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;
35: astore 7
37: goto 50
40: astore 7
42: getstatic #74 // Field java/lang/System.err:Ljava/io/PrintStream;
45: ldc #76 // String I find exception in the catch
47: invokevirtual #82 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
50: iload 6
52: goto 55
55: isub
56: istore 5
58: getstatic #85 // Field java/lang/System.out:Ljava/io/PrintStream;
61: iload 5
63: invokevirtual #88 // Method java/io/PrintStream.println:(I)V
66: getstatic #85 // Field java/lang/System.out:Ljava/io/PrintStream;
69: ldc #90 // String 1..........
71: invokevirtual #82 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
74: return
Exception table:
from to target type
17 37 40 Class java/lang/NoSuchMethodException
17 37 40 Class java/lang/IllegalAccessException
LocalVariableTable:
Start Length Slot Name Signature
14 41 0 this Lcode/sxu/asm/example/Callee;
14 41 1 t I
14 41 2 p I
17 38 3 tmp I
42 8 4 e Ljava/lang/ReflectiveOperationException;
0 75 0 this LCallerI;
0 75 1 a I
0 75 2 b I
58 17 5 r I
LineNumberTable:
line 16: 0
line 18: 14
line 26: 17
line 27: 37
line 29: 42
line 31: 50
line 18: 58
line 19: 66
line 20: 74
StackMapTable: number_of_entries = 3
frame_type = 255 /* full_frame */
offset_delta = 40
locals = [ class CallerI, int, int, int, int, class code/sxu/asm/example/Callee, int ]
stack = [ class java/lang/ReflectiveOperationException ]
frame_type = 255 /* full_frame */
offset_delta = 9
locals = [ class CallerI, int, int, int, int, class code/sxu/asm/example/Callee, int, class java/lang/Object ]
stack = [ int ]
frame_type = 255 /* full_frame */
offset_delta = 4
locals = [ class CallerI, int, int, int, int, class code/sxu/asm/example/Callee, int, class java/lang/Object ]
stack = [ int, int ]
}
有人可以提供建议吗?我被这个问题困扰了三天了。这里的堆栈图处理应该有问题,但我不知道如何调整这个错误。
为了您的方便,我还发布了 Caller 和 Callee 的原始方法:
public class Callee {
public final String _a;
public final String _b;
public Callee(String a, String b){
_a = a;
_b = b;
}
....
public int calculate(int t, int p){
int tmp=0;
try {
MethodHandle handle = MethodHandles.publicLookup().findVirtual(String.class, "say", MethodType.methodType(void.class, String.class));
} catch (NoSuchMethodException | IllegalAccessException e) {
// TODO Auto-generated catch block
System.err.println("I find exception in the catch");
}
return tmp;
}
}
public class Caller {
final Callee _callee;
public Caller(Callee callee){
_callee = callee;
}
...
public void test(int a, int b){
int r = a+b-_callee.calculate(a, b);
System.out.println(r);
System.out.println("1..........");
}
}
<小时/>
更新
原始 Callee::calculate 的字节码:
public int calculate(int, int);
flags: ACC_PUBLIC
Code:
stack=5, locals=5, args_size=3
0: iconst_0
1: istore_3
2: invokestatic #26 // Method java/lang/invoke/MethodHandles.publicLookup:()Ljava/lang/invoke/MethodHandles$Lookup;
5: ldc #32 // class java/lang/String
7: ldc #34 // String say
9: getstatic #36 // Field java/lang/Void.TYPE:Ljava/lang/Class;
12: ldc #32 // class java/lang/String
14: invokestatic #42 // Method java/lang/invoke/MethodType.methodType:(Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/invoke/MethodType;
17: invokevirtual #48 // Method java/lang/invoke/MethodHandles$Lookup.findVirtual:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;
20: astore 4
22: goto 35
25: astore 4
27: getstatic #54 // Field java/lang/System.err:Ljava/io/PrintStream;
30: ldc #60 // String I find exception in the catch
32: invokevirtual #62 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
35: iload_3
36: ireturn
Exception table:
from to target type
2 22 25 Class java/lang/NoSuchMethodException
2 22 25 Class java/lang/IllegalAccessException
LineNumberTable:
line 18: 0
line 26: 2
line 27: 22
line 29: 27
line 31: 35
LocalVariableTable:
Start Length Slot Name Signature
0 37 0 this Lcode/sxu/asm/example/Callee;
0 37 1 t I
0 37 2 p I
2 35 3 tmp I
27 8 4 e Ljava/lang/ReflectiveOperationException;
StackMapTable: number_of_entries = 2
frame_type = 255 /* full_frame */
offset_delta = 25
locals = [ class code/sxu/asm/example/Callee, int, int, int ]
stack = [ class java/lang/ReflectiveOperationException ]
frame_type = 9 /* same */
我的代码也被推送到 Github Repository ,将ASM lib添加到类路径后可以直接运行类MainInliner
。
项目中的主要程序是MethodCallInliner::visitMethodInsn(..) ,其中创建了一个新的 InlinedAdapter
并用于访问 Callee::calculate()
主体。
============================================
LocalVariableTable 更新:
根据@Holger的解释和一些选项:
要禁用声明形式变量,visitLocalVariable
会被覆盖,但在 InlinedAdapter
和 MethodCallInliner
中都为空实现,LocalVariableTable
code> 在生成的代码中消失,但验证仍然失败并出现相同的错误。我也尝试过
ClassReader.accept(, ClassReader.EXPAND_FRAME|ClassReader.SKIP_DEBUG)
但结果与空覆盖相同visitLocalVariable
完整生成的字节码是:
public void test(int, int);
flags: ACC_PUBLIC
Code:
stack=6, locals=8, args_size=3
0: iload_1
1: iload_2
2: iadd
3: aload_0
4: getfield #14 // Field _callee:Lcode/sxu/asm/example/Callee;
7: iload_1
8: iload_2
9: istore_3
10: istore 4
12: astore 5
14: iconst_0
15: istore 6
17: invokestatic #46 // Method java/lang/invoke/MethodHandles.publicLookup:()Ljava/lang/invoke/MethodHandles$Lookup;
20: ldc #48 // class java/lang/String
22: ldc #50 // String say
24: getstatic #56 // Field java/lang/Void.TYPE:Ljava/lang/Class;
27: ldc #48 // class java/lang/String
29: invokestatic #62 // Method java/lang/invoke/MethodType.methodType:(Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/invoke/MethodType;
32: invokevirtual #68 // Method java/lang/invoke/MethodHandles$Lookup.findVirtual:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;
35: astore 7
37: goto 50
40: astore 7
42: getstatic #74 // Field java/lang/System.err:Ljava/io/PrintStream;
45: ldc #76 // String I find exception in the catch
47: invokevirtual #82 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
50: iload 6
52: goto 55
55: isub
56: istore_3
57: getstatic #85 // Field java/lang/System.out:Ljava/io/PrintStream;
60: iload_3
61: invokevirtual #88 // Method java/io/PrintStream.println:(I)V
64: getstatic #85 // Field java/lang/System.out:Ljava/io/PrintStream;
67: ldc #90 // String 1..........
69: invokevirtual #82 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
72: return
Exception table:
from to target type
17 37 40 Class java/lang/NoSuchMethodException
17 37 40 Class java/lang/IllegalAccessException
LocalVariableTable:
Start Length Slot Name Signature
14 41 5 this Lcode/sxu/asm/example/Callee;
14 41 4 t I
14 41 3 p I
17 38 6 tmp I
42 8 7 e Ljava/lang/ReflectiveOperationException;
0 73 0 this LCallerI;
0 73 1 a I
0 73 2 b I
57 16 3 r I
LineNumberTable:
line 20: 0
..
line 24: 72
StackMapTable: number_of_entries = 3
frame_type = 255 /* full_frame */
offset_delta = 40
locals = [ class CallerI, int, int, int, int, class code/sxu/asm/example/Callee, int ]
stack = [ class java/lang/ReflectiveOperationException ]
frame_type = 255 /* full_frame */
offset_delta = 9
locals = [ class CallerI, int, int, int, int, class code/sxu/asm/example/Callee, int, class java/lang/Object ]
stack = [ int ]
frame_type = 255 /* full_frame */
offset_delta = 4
locals = [ class CallerI, int, int, int, int, class code/sxu/asm/example/Callee, int, class java/lang/Object ]
stack = [ int, int ]
}
原来的LocalVariableTables是:
Callee: LocalVariableTable:
Start Length Slot Name Signature
0 37 0 this Lcode/sxu/asm/example/Callee;
0 37 1 t I
0 37 2 p I
2 35 3 tmp I
27 8 4 e Ljava/lang/ReflectiveOperationException;
Caller: LocalVariableTable:
Start Length Slot Name Signature
0 30 0 this Lcode/sxu/asm/example/Caller;
0 30 1 a I
0 30 2 b I
14 16 3 r I
合并看起来不错(我认为如果这些名称位于不同的区域,则没有必要避免变量名称冲突,例如,两个 this
符号位于不同的区域)。但验证在 @50::iload 处仍然失败,并显示相同的消息。
最佳答案
在调用calculate
之前,堆栈上有一个int
值,该值将在调用之后使用。正常完成的方法调用只会消耗适当的参数值,而不会影响所有其他操作数堆栈值,无论调用的方法内部发生什么。如果该方法不是void
,则返回值将被压入堆栈。
当您内联方法的代码时,情况会发生变化。然后,除了消耗参数和推送一个返回值之外,代码还可能对操作数堆栈产生影响。在您的情况下,有一个异常处理程序将恢复正常执行。但是,正如this answer中讨论的那样,异常处理程序从仅包含一个值(遇到的异常)的操作数堆栈开始。在遇到异常之前压入堆栈的所有值都将被刷新。将方法的代码内联到调用者中后,这也会影响调用者的操作数堆栈。
因此,在您的情况下,两个代码路径在内联代码的末尾附近合并,一个用于正常完成的情况,其中堆栈上的 int
值将被保留,并且异常处理程序,其中值已被删除。这种不匹配会导致 VerifyError
。
没有简单的解决方案。您不能强制异常处理程序保留该值,因此您必须重写代码以不依赖于要保留的推送值,这使得您最初通过插入指令进行内联的想法不起作用。你必须意识到,甚至相反的情况也是可能的:当一个方法遇到返回指令时,堆栈上悬挂着多少额外的未使用的值并不重要,因为当返回到调用者时,堆栈帧将被销毁。因此,天真的内联代码可能会在堆栈上留下额外的值,当您在方法上有分支或方法有多个返回指令时,这将导致错误。
关于java - 内联 tryCatchBlock 导致当前帧的堆栈大小与堆栈映射异常不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30059938/
出于好奇 - 我知道有 LAMP - Linux、Apache、MySQL 和 PHP。但是还有哪些其他 Web 堆栈替代方案的缩写呢?像 LAMR - Linux、Apache、MySQL Ruby
我有以下代码。 var stackMapIn = []; var stackMapOut = []; var stackBack = []; stackMapOut.push("m1"); $scop
我遇到了导致我的堆栈无法恢复的情况,我别无选择,只能将其删除。使用完全相同的模板,我继续创建了另一个同名的堆栈。 The following resource(s) failed to create:
这是我第一次查看 Node 堆栈,自从我学习使用 Ruby on Rails 进行 Web 开发以来,我对一些基本的东西有点困惑。我了解 Rails 目录是什么样的。 demo/ ..../app .
本文实例讲述了C语言使用深度优先搜索算法解决迷宫问题。分享给大家供大家参考,具体如下: 深度优先搜索 伪代码 (Pseudocode)如下: ?
我正在按照指南 here ,它告诉我: The stack setup will download the compiler if necessary in an isolatedlocation (
同时 trying to debug a different question ,我安装了一个似乎与我安装的其他一些软件包冲突的软件包。 我跑了 $ stack install regex-pcre-
我花了几个小时创建了一个方法,该方法将从堆栈 s1 中获取 null 元素,并将它们放入 s2 中。然后该类应该打印堆栈。方法如下 import net.datastructures.ArraySta
我有一个类Floor,它有一个Stack block ,但我不知道如何初始化它。我曾尝试过这样的: public class Floor { private Stack stack;
我知道这个问题已经问过很多次了,但搜索一个小时后我仍然遇到问题。 我想使用一个 lifo 堆栈,它可以存储最大数量的元素。达到最大数量后,首先删除该元素并将其替换为新元素,这样在第一次弹出时我可以获取
我需要编写一个方法,压缩以执行以下操作; 目标compress方法是从栈s1中移除所有null元素。剩余(非空)元素应按其初始顺序保留在 s1 上。辅助堆栈 s2 应用作s1 中元素的临时存储。在该方
我正在尝试验证以下代码发生的顺序。 function square(n) { return n * n; } setTimeout(function(){ console.log("H
我需要一个字符数组,其中包含基于特定文件夹中文件数量的动态数量的字符数组。我能够通过初始化 char (*FullPathNames)[MAX_FILENAME_AND_PATHNAME_LENGTH
我正在编写一些日志逻辑并想要进行一些缩进。了解是否存在任何函数调用或某个函数是否已完成的最简单方法是查看堆栈/帧的当前地址。让我们假设堆栈颠倒增长。然后,如果 log() 调用中的堆栈地址小于前一次调
所以内存分段在x86-64中被放弃了,但是当我们使用汇编时,我们可以在代码中指定.code和.data段/段,并且还有堆栈指针寄存器。 还有堆栈段、数据段和代码段寄存器。 代码/数据/堆栈的划分是如何
void main() { int x = 5; // stack-allocated Console.WriteLine(x); } 我知道 x 是堆栈分配的。但是关于 x 的堆栈中
这是我关于 SO 的第一个问题。这可能是一个愚蠢的问题,但到目前为止我还没弄明白。 考虑下面的程序 Reader.java: public class Reader { public
java中有没有一种快速的方法来获取嵌套/递归级别? 我正在编写一个函数来创建组及其成员的列表。成员也可以是团体。我们最终可能会得到一组循环的组/成员。 我想在某个任意级别停止。 我知道我可以将变量保
考虑以下代码: struct A{...}; A a[100]; A* pa = new A[100]; delete[] pa; a/pa 元素的销毁顺序是由标准定义的还是实现定义的(对于第二种情况
我在下面有一些代码。此代码是一个基本的压入/弹出堆栈类,我将其创建为模板以允许某人压入/弹出堆栈。我有一个家庭作业,我现在要做的是创建一个具有多个值的堆栈。 所以我希望能够创建一个基本上可以发送三个整
我是一名优秀的程序员,十分优秀!