2012-12-17 20 views
8

में जावा विधि पैरामीटर मान मैं जावा प्रोग्राम के विधि के मानकों के मान प्राप्त करने का प्रयास कर रहा हूं। मैं बाइटकोड को मापने और इन मानों को प्राप्त करने के लिए एएसएम का उपयोग कर रहा हूं। हालांकि, मैं कुछ परेशानियों में भाग रहा हूं।एएसएम

यहां विज़िट कोड() विधि कोड का उपयोग करने के लिए उपयोग की जाती है। क्या यह कर रहा है:

  1. एकत्र मापदंडों स्टोर करने के लिए एक खाली सरणी बनाएँ।
  2. प्रत्येक पैरामीटर के लिए, सरणी में अपना मान लोड करें।
  3. इस सरणी को मेरे एजेंट की OnMethodEntry विधि (जहां मूल्यों का उपयोग किया जाएगा) को भेजें।

@Override 
public void visitCode() { 
    int paramLength = paramTypes.length; 

    // 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) { 
     mv.visitVarInsn(Opcodes.ALOAD, paramLength); 
     mv.visitIntInsn(Opcodes.BIPUSH, i); 

     if (tp.equals(Type.BOOLEAN_TYPE) || tp.equals(Type.BYTE_TYPE) || tp.equals(Type.CHAR_TYPE) || tp.equals(Type.SHORT_TYPE) || tp.equals(Type.INT_TYPE)) 
      mv.visitVarInsn(Opcodes.ILOAD, i); 
     else if (tp.equals(Type.LONG_TYPE)) { 
      mv.visitVarInsn(Opcodes.LLOAD, i); 
      i++; 
     } 
     else if (tp.equals(Type.FLOAT_TYPE)) 
      mv.visitVarInsn(Opcodes.FLOAD, i); 
     else if (tp.equals(Type.DOUBLE_TYPE)) { 
      mv.visitVarInsn(Opcodes.DLOAD, i); 
      i++; 
     } 
     else 
      mv.visitVarInsn(Opcodes.ALOAD, i); 

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

    // Load id, class name and method name 
    this.visitLdcInsn(new Integer(this.methodID)); 
    this.visitLdcInsn(this.className); 
    this.visitLdcInsn(this.methodName); 

    // Load the array of parameters that we created 
    this.visitVarInsn(Opcodes.ALOAD, paramLength); 

    mv.visitMethodInsn(Opcodes.INVOKESTATIC, 
      "jalen/MethodStats", 
      "onMethodEntry", 
      "(ILjava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V"); 
    super.visitCode(); 
} 

हालांकि, यह तब काम नहीं कर रहा है जब स्पष्ट रूप से विधि में एक से अधिक पैरामीटर हैं।

इस तरह

वर्ग फ़ाइल प्राप्त शो बातें:

static void moveDisk(char arg0, char arg1, PrintStream arg2) { 
Object[] arrayOfObject = new Object[3]; arrayOfObject[0] = ???; arrayOfObject[1] = ???; 
Object localObject; 
arrayOfObject[2] = localObject; MethodStats.onMethodEntry(5, "hanoi/TowersOfHanoi", "moveDisk", arrayOfObject); 

कहाँ 2 स्थानीय वस्तुओं के बजाय मानकों को लोड करने की बनाई गई हैं।

बाईटकोड कुछ भी अजीब नहीं दिखाता है:

static void moveDisk(char, char, java.io.PrintStream); 
Code: 
    0: bipush  3 
    2: anewarray  #4     // class java/lang/Object 
    5: astore_3  
    6: aload_3  
    7: bipush  0 
    9: iload_0  
    10: aastore  
    11: aload_3  
    12: bipush  1 
    14: iload_1  
    15: aastore  
    16: aload_3  
    17: bipush  2 
    19: aload_2  
    20: aastore  
    21: ldc   #118    // int 5 
    23: ldc   #12     // String hanoi/TowersOfHanoi 
    25: ldc   #119    // String moveDisk 
    27: aload_3  
    28: invokestatic #19     // Method jalen/MethodStats.onMethodEntry:(ILjava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V 

और अंत में, त्रुटि (जब -noverify का उपयोग कर) से पता चला:

param: [Ljava.lang.String;@420e54f3 
Exception in thread "Jalen Agent" java.lang.NullPointerException 
at hanoi.TowersOfHanoi.solveHanoi(TowersOfHanoi.java) 
at hanoi.TowersOfHanoi.main(TowersOfHanoi.java:29) 

अन्यथा, यह है:

Exception in thread "Jalen Agent" java.lang.VerifyError: (class: hanoi/TowersOfHanoi, method: moveDisk signature: (CCLjava/io/PrintStream;)V) Expecting to find object/array on stack 
    at java.lang.Class.getDeclaredMethods0(Native Method) 
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2442) 
    at java.lang.Class.getMethod0(Class.java:2685) 
    at java.lang.Class.getMethod(Class.java:1620) 
    at sun.launcher.LauncherHelper.getMainMethod(LauncherHelper.java:492) 
    at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:484) 

आम तौर पर, यह काम करना चाहिए क्योंकि मैं केवल स्टैक फ्रेम से जानकारी लोड कर रहा हूं। मैंने स्थैतिक & गैर स्थैतिक तरीकों की जांच करने की कोशिश की (जैसा कि यहां समझाया गया ढेर है: http://www.artima.com/insidejvm/ed2/jvm8.html), लेकिन अभी भी कोई सफलता नहीं है।

यह क्यों हो रहा है, या संभवतः समाधान का कोई विचार है?

धन्यवाद :)

संपादित करें:

अब यह काम कर रहा है जब तक (नीचे int3 :) द्वारा सुझाव के लिए धन्यवाद) आदिम प्रकार मुक्केबाजी।

@Override 
public void visitCode() { 
    int paramLength = paramTypes.length; 

    // 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) { 
     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++; 
    } 

    // Load id, class name and method name 
    this.visitLdcInsn(new Integer(this.methodID)); 
    this.visitLdcInsn(this.className); 
    this.visitLdcInsn(this.methodName); 

    // Load the array of parameters that we created 
    this.visitVarInsn(Opcodes.ALOAD, paramLength); 

    mv.visitMethodInsn(Opcodes.INVOKESTATIC, 
      "jalen/MethodStats", 
      "onMethodEntry", 
      "(ILjava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V"); 
    super.visitCode(); 
} 
+0

मैं तर्क को वापस स्टैक पर कैसे वापस कर सकता हूं ताकि फ़ंक्शन उनका उपयोग जारी रख सके? – Shay

उत्तर

6

आप aastore उपयोग कर रहे हैं एक वस्तु सरणी है, जो एक प्रकार की त्रुटि है में एक char स्टोर करने के लिए: यहाँ visitCode() विधि का काम कर कोड है। aastore केवल वस्तुओं और सरणी को संग्रहीत करने के लिए उपयोग किया जाना चाहिए, शायद यही कारण है कि त्रुटि 'अनुमानित वस्तु/सरणी पर सरणी' कहती है। अक्षरों को castore का उपयोग कर चार सरणी में संग्रहीत किया जाना चाहिए। हालांकि, चूंकि आप इसे मनमाने ढंग से हस्ताक्षर के लिए काम करना चाहते हैं, तो आप शायद आदिम प्रकारों को उन वस्तुओं में बॉक्स करना चाहते हैं जिन्हें आप aastore पर उपयोग कर सकते हैं - उदा। char को java.lang.Character ऑब्जेक्ट में बॉक्स किया जाना चाहिए।