2013-08-05 5 views
1

실행되는 각 함수 내에 콜백 함수를 삽입하기 위해 asm을 사용하고 있습니다. 어떻게 arguents 값을 인쇄 할 수 있습니까?바이트 코드 인스턴스 작성을 위해 java asm을 사용하여 함수 인수 값을 가져옴

MethodAdapter.visitCode를 사용하여 내 기능을 각 기능에 주입했습니다.

나는 배열로 함수 인수를 삽입하고 내 callbackk 기능이 배열을 보내고 함수가 다음 코드는에 메소드 인수를 삽입 그들

를 계속 사용할 수 있도록 스택에 다시 인수를 반환 할 배열에 저장되고 콜백 함수에 Object 배열로 전송됩니다. 내가 for 루프 전에 원래의 기능

@Override public void visitCode() 
     { 

      int paramLength = paramTypes.length;    
      System.out.println(className + "." + methodName + ": paramLength = " + paramLength); 


      // Create array with length equal to number of parameters 
      mv.visitIntInsn(Opcodes.BIPUSH, paramLength); 
      mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object"); 
      mv.visitVarInsn(Opcodes.ASTORE, paramLength); 

      // Fill the created array with method parameters 
      int i = 0; 
      for (Type tp : paramTypes) 
      { 
       System.out.println("tp.getClassName() = " + tp.getClassName());    

       mv.visitVarInsn(Opcodes.ALOAD, paramLength); 
       mv.visitIntInsn(Opcodes.BIPUSH, i); 

       if (tp.equals(Type.BOOLEAN_TYPE)) 
       { 
        mv.visitVarInsn(Opcodes.ILOAD, i); 
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;"); 
       } 
       else if (tp.equals(Type.BYTE_TYPE)) 
       { 
        mv.visitVarInsn(Opcodes.ILOAD, i); 
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;"); 
       } 
       else if (tp.equals(Type.CHAR_TYPE)) 
       { 
        mv.visitVarInsn(Opcodes.ILOAD, i); 
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;"); 
       } 
       else if (tp.equals(Type.SHORT_TYPE)) 
       { 
        mv.visitVarInsn(Opcodes.ILOAD, i); 
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;"); 
       } 
       else if (tp.equals(Type.INT_TYPE)) 
       { 
        mv.visitVarInsn(Opcodes.ILOAD, i); 
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;"); 
       } 
       else if (tp.equals(Type.LONG_TYPE)) 
       { 
        mv.visitVarInsn(Opcodes.LLOAD, i); 
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;"); 
        i++; 
       } 
       else if (tp.equals(Type.FLOAT_TYPE)) 
       { 
        mv.visitVarInsn(Opcodes.FLOAD, i); 
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;"); 
       } 
       else if (tp.equals(Type.DOUBLE_TYPE)) 
       { 
        mv.visitVarInsn(Opcodes.DLOAD, i); 
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;"); 
        i++; 
       } 
       else 
        mv.visitVarInsn(Opcodes.ALOAD, i); 

       mv.visitInsn(Opcodes.AASTORE); 
       i++; 
      } 


      //System.out.println("end for"); 

      // Load class name and method name      
      this.visitLdcInsn(className); 
      this.visitLdcInsn(methodName);   
      // Load the array of parameters that we created 
      this.visitVarInsn(Opcodes.ALOAD, i);       

      this.visitMethodInsn(Opcodes.INVOKESTATIC, "callbackpackage/CallBack", "callbackfunc", "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V"); 
super.visitCode(); 
}     
+0

가에 관한 자세한 정보를 제공 할 것 당신은 논쟁하고 싶습니다. 당신은 논쟁을 인쇄 할 계획이십니까? 아니면 단순히이 인수의 값을 다른 함수로 보내겠습니까? – vijay

+0

이 값을 다른 함수, 아마도 배열로 보내려고합니다. – Shay

답변

2

의 인수를 반환하는 데 문제가 있어요, 당신은 paramLength 인덱스에있는 지역 변수 테이블 위에 배열을 생성/저장된다. 그러나 루프가 끝나면 i 번째 색인에서 액세스합니다. 그냥 안전을 위해서 : 마지막 세 번째 소스 코드 문장에서 iparamLength으로 대체하십시오. 즉, 대신 this.visitVarInsn(Opcodes.ALOAD, i)을 입력하십시오.

또한 i0으로 초기화됩니다. 예를 들어 메서드는 로컬 변수 테이블의 인수를로드하는 것을 의미합니다 (아래 일반 설명 참조). 그것이 당신이하려는 의도와 정확히 일치하는지 확인하십시오. 변수를로드하지 않으려면 (정적이 아닌) 방법으로 i에서 1으로 초기화하십시오.

일반 설명 :

당신이 MethodAdapter.visitCode를 사용 주장하는 점을 감안, 난 당신이 메소드의 호출 후 값을 메소드 인수, 에 액세스한다고 가정합니다.

메소드 인수는 메소드 호출마다 로컬 변수 테이블에 저장됩니다. 따라서 로컬 변수 테이블의 첫 번째 N 변수를 피연산자 스택에로드하기 만하면 메소드 인수의 값에 액세스 할 수 있습니다. 여기서 N은 단순히 메소드에 대한 인수의 수입니다. 지역 변수 테이블은 0으로 인덱싱된다는 점에 유의하십시오. 인덱스는 0부터 시작합니다. 또한 인스턴스 메서드의 경우 "this"도 인수로 처리됩니다. 인스턴스 메소드의 경우, 인덱스 0에있는 로컬 변수는 "variable"을 나타냅니다.

메소드에 대한 인수의 수는 다음 요지의 코드를 사용하여 메소드 설명에서 계산할 수 있습니다. https://gist.github.com/VijayKrishna/6160036. parseMethodArguments(String desc) 메서드를 사용하면 메서드에 대한 인수의 수를 쉽게 계산할 수 있습니다. 그리고 어딘가에 visitCode() 방법, 이상적으로 가능한 한 빨리, 다음을 수행하십시오 parseMethodArguments의 계산 대부분의

@Override 
public void visitCode() { 
    ... 
    char[] methodDescParsed = parseMethodArguments(methodDescription); 
    int N = methodDescParsed.length + (isMethodStatic ? 0 : 1); 
    ... 
} 

는 단순히 문자열입니다 방법 설명을 구문 분석합니다. 배열과 객체에 대한 타입 설명자를 대문자 L로 대체하고 원시 타입에 대한 타입 설명자를있는 그대로 유지합니다.배열의 각 요소가 대략 전달 된 인수의 유형을 나타내는 char[]을 반환합니다. 인자의 유형에있어서, 정보에 반영되지 않기 때문에

상기 (isMethodStatic ? 1 : 0) 삼원 식은 설명하기 위해,이 방법은 정적없는 경우, 1 인수 카운트를 증가 사용 논의.
isMethodStatic 인수가 아니므로 메서드가 인스턴스 메서드가 아닌 경우 이므로 증분 필요하지 않습니다. 메서드가 인스턴스 메서드 인 경우
isMethodStaticfalse이므로 인수가 있으므로 인수 수가 증가합니다. 당신이 인수 수를 일단 곧 메소드 호출 후 메서드의 첫 번째 N 지역 변수에 접근하기 위해 다음과 같이

, ASM을 사용하여 느슨한 자바 코드는 다음과 같습니다

for(int i = 0; i < N; i ++) { 
    int opcode = 0; 
    switch() { 
     case 'L': opcode = Opcodes.ALOAD; break; 
     case 'I': opocde = Opcodes.ILOAD; break; 
     case 'J': opcode = Opocdes.LLOAD; break; 
     case 'F': ... 
     case 'D': ... 
     // TODO: complete all the cases. 
    } 

    mv.visitVarInsn(opcode, i); 
    // ith argument is now loaded on the operand stack. 
    // add more ASM code to do what ever it is that you want to do with the argument. 
} 
+0

인수를 사용하여 메소드가 스택을 계속 사용할 수있게하려면 어떻게해야합니까? – Shay

+0

** ** 로컬 변수 테이블 ** 및 ** ** ** ** 피연산자 스택 **에서 인수 **를 가져옵니다. 메서드가 실행되는 동안 인수가 변경되지 않는 한 언제든지 로컬 변수 테이블에서 액세스 할 수 있습니다. – vijay

+0

어떻게해야합니까? 코드 예제가 있습니까? – Shay