热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

错误的堆栈大小由ASM库计算

如何解决《错误的堆栈大小由ASM库计算》经验,为你挑选了1个好方法。

我使用ASM库生成字节码,并且方法的"最大堆栈大小"将自动计算.在运行期间,我发现此值(最大堆栈大小)不正确.

我的源代码是:

    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
     ....
    MethodType initType = MethodType.methodType(void.class, clsList);
    mv = cw.visitMethod(ACC_PUBLIC, "", initType.toMethodDescriptorString(), null, null);
    mv.visitCode();
    mv.visitVarInsn(ALOAD, 0);
    mv.visitMethodInsn(INVOKESPECIAL, "java/lang/invoke/BaseTemplate", "", "()V", false);
    for(int i=0; i expClass =defineClass(..);

上面的代码将生成字节码:

    Classfile /C:/temp/TGWD.class
  Last modified Mar 11, 2015; size 403 bytes
  MD5 checksum f58b96ad4cb0bc9e62f2ae5e11e63e90
public class TGWD extends java.lang.invoke.BaseTemplate
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER

Constant pool:
   #1 = Utf8               TGWD
   #2 = Class              #1             //  TGWD
   #3 = Utf8               java/lang/invoke/BaseTemplate
   #4 = Class              #3             //  java/lang/invoke/BaseTemplate
   #5 = Utf8               guard
   #6 = Utf8               Ljava/lang/invoke/MethodHandle;
   #7 = Utf8               trueTarget
   #8 = Utf8               falseTarget
   #9 = Utf8               
  #10 = Utf8               (Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V
  #11 = Utf8               ()V
  #12 = NameAndType        #9:#11         //  "":()V
  #13 = Methodref          #4.#12         //  java/lang/invoke/BaseTemplate."":()V
  #14 = NameAndType        #5:#6          //  guard:Ljava/lang/invoke/MethodHandle;
  #15 = Fieldref           #2.#14         //  TGWD.guard:Ljava/lang/invoke/MethodHandle;
  #16 = NameAndType        #7:#6          //  trueTarget:Ljava/lang/invoke/MethodHandle;
  #17 = Fieldref           #2.#16         //  TGWD.trueTarget:Ljava/lang/invoke/MethodHandle;
  #18 = NameAndType        #8:#6          //  falseTarget:Ljava/lang/invoke/MethodHandle;
  #19 = Fieldref           #2.#18         //  TGWD.falseTarget:Ljava/lang/invoke/MethodHandle;
  #20 = Utf8               eval
  #21 = Utf8               Code
{
  final java.lang.invoke.MethodHandle guard;
    flags: ACC_FINAL


  final java.lang.invoke.MethodHandle trueTarget;
    flags: ACC_FINAL


  final java.lang.invoke.MethodHandle falseTarget;
    flags: ACC_FINAL


  public TGWD(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
    flags: ACC_PUBLIC

    Code:
      stack=0, locals=4, args_size=4
         0: aload_0       
         1: invokespecial #13                 // Method java/lang/invoke/BaseTemplate."":()V
         4: aload_0       
         5: aload_1       
         6: putfield      #15                 // Field guard:Ljava/lang/invoke/MethodHandle;
         9: aload_0       
        10: aload_2       
        11: putfield      #17                 // Field trueTarget:Ljava/lang/invoke/MethodHandle;
        14: aload_0       
        15: aload_3       
        16: putfield      #19                 // Field falseTarget:Ljava/lang/invoke/MethodHandle;
        19: return        

  public void eval();
    flags: ACC_PUBLIC

    Code:
      stack=0, locals=1, args_size=1
         0: return        
}

字节码报告错误:

org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 0: Insufficient maximum stack size.
    at org.objectweb.asm.tree.analysis.Analyzer.analyze(Unknown Source)
    at org.objectweb.asm.util.CheckClassAdapter.verify(Unknown Source)
    at org.objectweb.asm.util.CheckClassAdapter.verify(Unknown Source)

因为构造方法:stack = 0,locals = 4,args_size = 4

正确的堆栈大小为2.

即使设置了ClassWriter(COMPUTE_MAX + COMPUTE_STACK),还有另一个线程ASM(来自ObjectWeb)没有正确计算MaxStack,表明如果其他地方的字节码无效,则可能错误地计算最大堆栈大小.

所以对我来说,问题是:

生成的文件中的无效字节码在哪里?

我仍然希望避免调用visitMax().因为有许多生成的字节码方法,并且这些值的手动计算并不是一件容易的事.

Holger.. 9

你不能省略对它的调用visitMax.来自以下文件ClassWriter.COMPUTE_MAXS:

如果该标志被设置,则自变量visitMaxs所述的方法MethodVisitor中由返回visitMethod方法将被忽略,并且从签名和每个方法的字节码自动计算.

换句话说,当您指定标志时,您可以传入任何您想要的内容,例如调用visitMax(-1,-1)以强调您没有提供实际值,但您仍然必须调用该方法来触发正确值的计算.

顺便说一句,既然你创建了一个版本的类文件,51你应该指定COMPUTE_FRAMES我怀疑你想要StackMapTable手动创建属性.注意这COMPUTE_FRAMES意味着COMPUTE_MAXS行为.



1> Holger..:

你不能省略对它的调用visitMax.来自以下文件ClassWriter.COMPUTE_MAXS:

如果该标志被设置,则自变量visitMaxs所述的方法MethodVisitor中由返回visitMethod方法将被忽略,并且从签名和每个方法的字节码自动计算.

换句话说,当您指定标志时,您可以传入任何您想要的内容,例如调用visitMax(-1,-1)以强调您没有提供实际值,但您仍然必须调用该方法来触发正确值的计算.

顺便说一句,既然你创建了一个版本的类文件,51你应该指定COMPUTE_FRAMES我怀疑你想要StackMapTable手动创建属性.注意这COMPUTE_FRAMES意味着COMPUTE_MAXS行为.


推荐阅读
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 本文介绍了三种方法来实现在Win7系统中显示桌面的快捷方式,包括使用任务栏快速启动栏、运行命令和自己创建快捷方式的方法。具体操作步骤详细说明,并提供了保存图标的路径,方便以后使用。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • 本文介绍了如何清除Eclipse中SVN用户的设置。首先需要查看使用的SVN接口,然后根据接口类型找到相应的目录并删除相关文件。最后使用SVN更新或提交来应用更改。 ... [详细]
author-avatar
昧凉生丶楚_139
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有