如何重用asm中methodNode的原始框架信息来创建org.objectweb.asm.tree.analysis.Frame [英] How to reuse original frame information from a methodNode in asm to create `org.objectweb.asm.tree.analysis.Frame`

查看:97
本文介绍了如何重用asm中methodNode的原始框架信息来创建org.objectweb.asm.tree.analysis.Frame的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何仅使用 FrameNodes org.objectweb.asm.tree.analysis.Frame c $ c>和 LocalVariableNodes 来自 MethodNode

How can I construct a org.objectweb.asm.tree.analysis.Frame for each instruction in a method using only FrameNodes and LocalVariableNodes from the MethodNode?

上下文

在检测一些代码时,我需要所有本地变量和堆栈类型来使用某些原始指令。

While instrumenting some code I need all the locals and stack types for some of the original instructions.

当前,我通过执行以下操作得到此信息:

Currently I get this by doing:

Analyzer analyzer = new Analyzer(new MyBasicInterpreter());
Frame[] frames = analyzer.analyze(ownerClass, methodNode);

这给了我每条指令 Frame methodNode 中。

This gives me a Frame for each instruction in the methodNode.

但是,拥有确切的类型意味着正确实现 BasicInterpreter。 merge ,这需要为任意类型解析公共超类。这迅速升级为必须了解一类超级类和接口(即必须从类加载器中读取更多信息)。

However, to have the exact types means properly implementing BasicInterpreter.merge and that requires resolving the common super class for arbitrary types. This escalates quickly to having to know super classes and interfaces for a bunch of classes (i.e. having to read more information from the classloader).

所以我想知道是否可以避免使用 Analyzer ,而仅使用原始帧信息来重建我需要的数据。

So I am wondering if I can avoid using an Analyzer and just use the original frame information to reconstruct the data I need.

原始类是始终是jdk 1.8.0类并具有框架信息。
我真的需要知道堆栈中的类型。

The original classes are always jdk 1.8.0 classes and have frame information. And I really need to know the types in the stack.

推荐答案

您不能完全避免像这样进行分析 StackMapTable 仅包含有关分支目标和合并点的信息。但是,对于线性流, BasicInterpreter 已经包含必要的操作,并且如果从<$ c中提取结果信息,则确实不需要实现合并操作。 $ c> StackMapTable 。

You can’t avoid the analyzation entirely as the StackMapTable contains only information about branch targets and merge points. However, for the linear flow, the BasicInterpreter already contains the necessary operations and you indeed don’t need to implement a merge operation if you extract the resulting information from the StackMapTable.

唯一的缺点是您必须重新实现方法条目的初始框架的构造,因为该操作是埋在 Analyzer 内,ASM似乎没有为在方法开始时正式存在的隐式堆栈映射框架提供节点。

The only drawback is that you have to re-implement the construction of the method entry’s initial frame as that operation is buried inside the Analyzer and ASM doesn’t seem to provide a node for the implicit stack map frame that formally exists at the beginning of a method.

这里是完整代码:

static List<Frame<BasicValue>> analyze(
    String ownerClass, MethodNode methodNode) throws AnalyzerException {

  final BasicValue ownerType=toBasicValue(null, ownerClass);
  BasicInterpreter interpreter = new BasicInterpreter() {
    @Override
    public BasicValue newValue(Type type) {
      return type==null || isPrimitive(type.getSort())? super.newValue(type):
             type.equals(ownerType.getType())? ownerType: new BasicValue(type);
    }
    private boolean isPrimitive(int sort) {
      return sort!=Type.OBJECT&&sort!=Type.ARRAY;
    }
  };
  List<Frame<BasicValue>> frames=new ArrayList<>();

  Frame<BasicValue> current = methodEntryFrame(methodNode, ownerType, interpreter);

  for(int ix=0, num=methodNode.instructions.size(); ix<num; ix++) {

    AbstractInsnNode i=methodNode.instructions.get(ix);

    if(i.getType() == AbstractInsnNode.FRAME) {
      current = extractFrame(methodNode, ownerType, (FrameNode)i);
      continue;
    } else if(i.getOpcode()<0) continue;//pseudo instruction node
    frames.add(new Frame<>(current));
    current.execute(i, interpreter);
  }

  return frames;
}

private static Frame<BasicValue> extractFrame(
    MethodNode methodNode, BasicValue ownerType, FrameNode fn) {

  Frame<BasicValue> current = new Frame<>(methodNode.maxLocals, methodNode.maxStack);
  int locals = fn.local!=null? fn.local.size(): 0;
  for(int lIx=0, lCount=locals; lIx<lCount; lIx++)
    current.setLocal(lIx, toBasicValue(ownerType, fn.local.get(lIx)));
  for(int lIx=locals; lIx<methodNode.maxLocals; lIx++)
    current.setLocal(lIx, BasicValue.UNINITIALIZED_VALUE);
  if(fn.stack!=null)
    for(Object obj: fn.stack) current.push(toBasicValue(ownerType, obj));
  return current;
}

private static Frame<BasicValue> methodEntryFrame(
    MethodNode methodNode, BasicValue ownerType, BasicInterpreter interpreter) {

  Frame<BasicValue> current = new Frame<>(methodNode.maxLocals, methodNode.maxStack);
  current.setReturn(interpreter.newValue(Type.getReturnType(methodNode.desc)));
  Type[] args = Type.getArgumentTypes(methodNode.desc);
  int local = 0;
  if((methodNode.access & Opcodes.ACC_STATIC) == 0)
    current.setLocal(local++, ownerType);
  for(int ix = 0; ix < args.length; ix++) {
    Type type = args[ix];
    current.setLocal(local++, interpreter.newValue(type));
    if(type.getSize() == 2)
      current.setLocal(local++, BasicValue.UNINITIALIZED_VALUE);
  }
  while(local < methodNode.maxLocals)
    current.setLocal(local++, BasicValue.UNINITIALIZED_VALUE);
  return current;
}

private static BasicValue toBasicValue(BasicValue owner, Object object) {
  if(object instanceof String) return refType(owner,(String)object);
  if(object instanceof Integer)
    switch((Integer)object) {
      case 0: return BasicValue.UNINITIALIZED_VALUE;
      case 1: return BasicValue.INT_VALUE;
      case 2: return BasicValue.FLOAT_VALUE;
      case 3: return BasicValue.DOUBLE_VALUE;
      case 4: return BasicValue.LONG_VALUE;
      case 5: return BasicValue.REFERENCE_VALUE;// null
      case 6: return owner;// uninitialized_this
      default: throw new IllegalStateException();
  }
  // uninitialized object, object is a LabelNode pointing to the ANEW instruction
  return BasicValue.REFERENCE_VALUE;
}

static final BasicValue OBJECT = new BasicValue(Type.getObjectType("java/lang/Object"));

private static BasicValue refType(BasicValue owner, String name) {
  if(name.equals("java/lang/Object")) return OBJECT;
  if(owner!=null && owner.getType().getInternalName().equals(name))
    return owner;
  return new BasicValue(Type.getObjectType(name));
}

这篇关于如何重用asm中methodNode的原始框架信息来创建org.objectweb.asm.tree.analysis.Frame的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆