Java 如何使用ASM仅从交换机中删除中断语句?

Java 如何使用ASM仅从交换机中删除中断语句?,java,java-bytecode-asm,bytecode-manipulation,Java,Java Bytecode Asm,Bytecode Manipulation,我正在使用ASM框架操作一些java字节码。我只需要从开关指令中删除中断语句。我的尝试删除了字节码中的goto指令,但不仅仅是这些与开关相连的指令(例如,所有来自类…) 您对此有何看法?Java源代码中的BREAK语句与Java字节码中的任何内容之间没有明确的联系。有些带有BREAK语句的语言结构可能被编译成GOTO操作码,但我怀疑您能否在它们之间建立可靠的链接 您唯一能做的就是在Java源代码中捕获BREAK语句的行号(假设这些行没有任何其他语句),然后使用用行号信息编译的字节码,您可以找到操

我正在使用ASM框架操作一些java字节码。我只需要从开关指令中删除中断语句。我的尝试删除了字节码中的goto指令,但不仅仅是这些与开关相连的指令(例如,所有来自类…)


您对此有何看法?

Java源代码中的BREAK语句与Java字节码中的任何内容之间没有明确的联系。有些带有BREAK语句的语言结构可能被编译成GOTO操作码,但我怀疑您能否在它们之间建立可靠的链接


您唯一能做的就是在Java源代码中捕获BREAK语句的行号(假设这些行没有任何其他语句),然后使用用行号信息编译的字节码,您可以找到操作码对于这些行。

如果出现在两个开关字节码指令之一的上下文中,则
goto
指令属于
switch
语句。棘手的部分是决定它们是否代表一个
中断
lookupswitch
tableswitch
都有分支目标列表,如果分支目标前面的指令是
goto
指令,则可能表示
中断
。这可以通过检查所有或至少大多数此类
goto
指令是否具有与
switch
语句之后的下一条指令相同的目标来验证。如果您已经识别了指令的字节码位置,在<代码>开关语句之后,您可以将所有<代码> Goto < /Cord> s定位到该位置为“代码>中断”;代码>

但这种启发式方法可能会严重失败。考虑下面的代码:

outer: for( … ) {
  …
  inner: for(…) {
    switch(…) {
      case 1: …
        continue inner; // jumps to the next iteration of inner
      case 2: …
        continue outer; // jumps to the next iteration of outer
      case 3: …
       // a break: formally jumps to the end of the switch but since
       // there is no follow-up statement, most compilers will optimize
       // this to a jump to the next inner iteration just like <continue>
        break;
      case 4:
       …
       // no break but nonetheless will be followed by a <goto>
    }
  }
}
outer:for(…){
…
内部:用于(…){
开关(…){
案例1:…
continue inner;//跳到inner的下一个迭代
案例2:…
continue outer;//跳到outer的下一个迭代
案例3:…
//中断:正式跳到切换的末尾,但从
//没有后续语句,大多数编译器都会进行优化
//这将跳转到下一个内部迭代,就像
打破
案例4:
…
//没有休息,但之后会有
}
}
}

一般来说,Java代码中所有非异常、无条件的分支都被编译成
goto
(或
goto\u w
)。这包括
break
语句、
continue
语句、无条件循环和任意数量的控制流模式。您将无法导出Java代码中的
break
语句到
goto
操作码之间的任何简单映射。您可以通过进行一些控制流分析来确定哪些跳转的行为类似于开关
中断
,但这并不完美


一个很好的学习经验可能是从Java反编译器中分离出源代码,因为反编译器必须重构
switch
语句,并找出如何将跳跃表示为
break
continue
,等等。Procyon和Krakatau都是开源的。我写了前者,但代码库庞大且令人望而生畏,因此它可能不是最佳选择。

我认为这可能无法实现您认为它可以实现的任何功能,而不必考虑识别那些GOTO的问题。你到底想解决什么?这是一个需要测试的案例。没别的了。我设法从包含开关的方法中删除了中断。但这并不是一个解决方案,因为在很多地方都会发生断裂。不仅在开关中。我在考虑用字节码连接goto和switch指令,但没有任何结果。。。