问题如下;用Java代码编写的方法是:

Rule foo()
{
    return sequence(foo(), x());
}

这将引发一个解析循环,当然应该避免该循环。但是,这是合法的:
Rule foo()
{
    return sequence(x(), foo());
}

现在,在代码的其他地方,我确实可以访问RuleMethod,这是扩展MethodNode的类,因此我可以访问以下信息:
  • ruleMethod.name:foo; (在MethodNode中定义)
  • ruleMethod.desc:()Lorg/parboiled/Rule;(在MethodNode中定义)
  • ruleMethod.ownerClass:com.github.fge.grappa.experiments.SelfReferringRule.MyParser(在RuleMethod中定义

  • 上面第一个代码提取的字节码如下:
    Method 'foo':
     0    L0
     1     ALOAD 0
     2     ALOAD 0
     3     INVOKEVIRTUAL com/github/fge/grappa/experiments/SelfReferringRule$MyParser.foo ()Lorg/parboiled/Rule;
     4     ALOAD 0
     5     INVOKEVIRTUAL com/github/fge/grappa/experiments/SelfReferringRule$MyParser.x ()Lorg/parboiled/Rule;
     6     ICONST_0
     7     ANEWARRAY java/lang/Object
     8     INVOKEVIRTUAL com/github/fge/grappa/experiments/SelfReferringRule$MyParser.sequence (Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Lorg/parboiled/Rule;
     9     ARETURN
    10    L1
    

    这意味着我拥有所有可用的信息,至少可以在上面的字节码中发现,foo()sequence()调用的第一个参数,,因为构造函数接受三个参数,并且构造函数上包含三个元素堆。

    但是我当然不能在运行时“检查”。因此,我需要一种方法来执行此操作...

    看来我需要的是MethodVisitor和某种程度上的visitInsn(),然后查看存在的参数并适本地进行检测...

    但是我丝毫不知道从哪里开始。在网上搜索似乎仅给出了如何修改字节码的示例,而没有发现这种情况:/

    我从哪里开始?

    最佳答案

    使用tree api进行分析通常要容易得多,因为它使您可以轻松地回溯并提供对流分析的支持。

    如果我正确理解了您的问题,那么您需要做的所有事情(如果您希望支持的只是诸如示例之类的简单情况)就是从调用序列向后扫描。如您所知,代码编译的堆栈中的内容必须是有效的,因此只需计算三个方法调用/字段获取/等即可。

    如果要支持更复杂的方案,在这些方案中,输入是通过分支语句分配给变量的,则需要进行某种流分析。

    09-26 04:31