2

다른 사람들이 만든 바이트 코드를 수정하려면 ASM library을 사용하고 있습니다. 임의의 클래스에있는 임의의 메소드의 경우 스택에 현재 클래스를 추가하는 LdcInsnNode을 생성하고 싶습니다.스택에 현재 클래스를 정적으로 추가하는 ASM LdcInsnNode를 만드는 방법은 무엇입니까?

예를 들어, com.example.ExampleClass이라는 클래스를 변환한다고 가정 해 봅시다. 나는 System.out.println(ExampleClass.class.getName());과 동등한 바이트 코드를 만들고 싶습니다.

이것은 비교적 간단한 작업처럼 보입니다. 나는 이클립스 바이트 코드 개요 플러그인을 사용하는 경우, 다음 바이트 코드가 같다고 말한다 : 그래서 name,

private InsnList printClass() { 
    InsnList result = new InsnList(); 
    result.add(new FieldInsnNode(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;")); 
    result.add(new LdcInsnNode("L" + name + ";.class")); 
    result.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;", false)); 
    result.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false)); 
    return result; 
} 

ClassNode의 확장에서 실행되고 :

GETSTATIC java/lang/System.out : Ljava/io/PrintStream; 
LDC Lcom/example/ExampleClass;.class 
INVOKEVIRTUAL java/lang/Class.getName()Ljava/lang/String; 
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V 

나는 다음 코드를 시도 ClassNode.name 필드를 나타냅니다. 이 메서드에서 반환 된 InsnListAbstractInsnNode 앞에 삽입되어 InsnList.insertBefore(AbstractInsnNode, printClass())을 사용합니다. 이 점은 바이트 코드에 도달하면, 나는 다음과 같은 이유로 오류가 다음 LDC 명령이 실제 클래스 Lcom/example/ExampleClass;.class 대신 문자열 "Lcom/example/ExampleClass;.class"를 추가하기 때문에

Type 'java/lang/String' (current frame, stack[1]) is not assignable to 'java/lang/Class' 

이 명확하다.

해결 방법이 있습니까? 클래스가 아직 존재하지 않기 때문에 LdcInsnNodeClass 개체를 직접 추가하는 것은 불가능합니다. 그러나 Class 객체를로드하는 명령어를 추가하는 방법이 있습니까?

내 경우에는 Object.getClass() 메서드를 호출하는 것이 정적 컨텍스트에서 작동해야하기 때문에 옵션이 아닙니다.

답변

2

Class 개체는 참조 할 필요가 없으며 사실 직접 지원되지도 않습니다. Class을 ASM을 통해 피연산자 스택에 푸시하려는 경우 Type 인스턴스로 참조해야합니다.

예.

new LdcInsnNode(Type.getObjectType(name)) 

, 예를 내부 이름 형태를 나타내는 name를 기대 Type.getObjectType(…) 공장 메소드를 사용하여 com/example/ExampleClass 주위에 L … ;이 없습니다. 배열이 아닌 유형의 경우 Type.getType('L'+name+';')과 같습니다. Type 객체가 기본 유형 또는 메소드 유형을 나타낼 수 있기 때문에 팩토리 메소드의 선택이 중요합니다. ldcType.getObjectType 모두 참조 유형 만 지원하므로 자연스러운 조합입니다.

단지 숫자 유형을 언급하고 String이 (ldcClass 지원 자바 5부터 존재하지만 문서가 1.4.2에 대한 링크를 포함)로 LdcInsnNode constructor documentation가 조금 오래된 것 같다. 대신 바이트 코드를 생성 할 때 객체가 전달되는 MethodVisitor.visitLdcInsn(…)을 참조 할 수 있습니다.