2014-12-07 3 views
1

Я довольно новичок в управлении ASM и байт-кодами. Моя задача довольно проста: я рассказываю своему агенту, какой класс и метод посещать, и измеряет время выполнения этого метода. Измерение выполняется с помощью класса секундомера библиотеки Guava. ASM в основном окружает тело метода, запуская Секундомер в начале и останавливая его в конце тела метода и распечатывая время выполнения. Это работало над некоторыми методами, но большинство из них не удалось.Обработка байт-кода ASM: скорость выполнения метода измерения

Это часть, где ASM посещает начало целевого метода.

package com.agent.agentclasses; 


import org.objectweb.asm.MethodVisitor; 
import org.objectweb.asm.Opcodes; 
import org.objectweb.asm.commons.LocalVariablesSorter; 
import org.objectweb.asm.Type; 

public class ModifierMethodWriter extends LocalVariablesSorter /*MethodVisitor*/ { 
    private int time; 
    protected ModifierMethodWriter(int api, int access, String desc, MethodVisitor mv) { 
     super(api, access, desc, mv); 
    } 


    @Override 
    public void visitCode() { 
     System.out.println("I am @ModifierMethodWriter!"); 

     /* 
     * Guava - beginning of the method ! 
     */ 
     time = newLocal(Type.getObjectType("stopwatch")); 


     super.visitMethodInsn(Opcodes.INVOKESTATIC, "com/google/common/base/Stopwatch", "createStarted", "()Lcom/google/common/base/Stopwatch;", false); 

     super.visitVarInsn(Opcodes.ASTORE, time); 
     super.visitCode(); 




    } 

Добавление кода в конец!

package com.agent.agentclasses; 

import org.objectweb.asm.MethodVisitor; 
import org.objectweb.asm.Opcodes; 
import org.objectweb.asm.commons.AdviceAdapter; 

public class AddCodeBeforeReturn extends AdviceAdapter { 
    public AddCodeBeforeReturn(int api, MethodVisitor mv, 
      int acc, String name, String desc){ 

     super(api, mv, acc, name, desc); 

    } 
    @Override 
    protected void onMethodExit(int opcode) { 
     /* 
     * Guava - Before return ! 
     */ 
     super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 
     super.visitIntInsn(Opcodes.ALOAD, 2); 
     super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "com/google/common/base/Stopwatch", "stop", "()Lcom/google/common/base/Stopwatch;", false); 
     super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "com/google/common/base/Stopwatch", "toString", "()Ljava/lang/String;", false); 
     super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); 
    } 
} 

Это тестовый класс, где я хочу, чтобы проверить мой агент: Это HSQL дб класс и я хочу, чтобы измерить время выполнения SelectAll() метод.

package com.agent.database; 

import java.sql.Connection; 
import java.sql.DriverManager; 
import java.sql.ResultSet; 
import java.sql.Statement; 
import com.agent.testclasses.*; 
public class Database { 

    private Connection connection = null; 
    private ResultSet resultSet = null; 
    private Statement statement = null; 
    private String createtablestr = " CREATE TABLE IF NOT EXISTS Students(Id int,Name varchar(255));"; 
    private static int id = 1; 

    public String connect() { 
     System.out.println("I am in connect!"); 
     try{ 
     Class.forName("org.hsqldb.jdbcDriver"); 
     connection = DriverManager.getConnection("jdbc:hsqldb:file:C:/hsqldb/studentdb", "sa", ""); 
     if (connection == null) 
     { 

      return "Error: Connection failed."; 
     } 
      statement = connection.createStatement(); 
      statement.executeUpdate(createtablestr); 
     }catch(Throwable ex){ 
      ex.printStackTrace(); 
     } 

     return "Connection succesful!"; 
    } 

    public String insert(Student student){ 
     connect(); 
     try { 

      String insertStr = "INSERT INTO Students VALUES ('"+ id +"','"+ student.getName() + "')"; 
      statement.executeUpdate(insertStr); 
      id++; 
     }catch(Throwable ex){ex.printStackTrace(); return "Error: Data was not written!";} 

     return "Data written succesfully!"; 
    } 

    public String selectAll() { 


     connect(); 
     String outputHTML=""; 
     try{ 


      resultSet = statement.executeQuery("SELECT * FROM Students"); 


      while (resultSet.next()) 
      { 
       outputHTML+= "<tr>" + "<td>" + resultSet.getString("Id") + "</td>" + "<td>" + resultSet.getString("Name") + "</td>" + "</tr>"; 
      } 



      resultSet.close(); 
      connection.commit(); 
      connection.close(); 


     } 
     catch (Throwable e) 
     { 
      e.printStackTrace(); 
     } 

     return outputHTML; 
    } 
} 

И, наконец, исключение, Jvm thorws:

Exception in thread "main" java.lang.VerifyError: Stack map does not match the one at exception handler 85 
    Exception Details: 
     Location: 
     com/agent/database/Database.connect()Ljava/lang/String; @85: astore_2 
     Reason: 
     Type top (current frame, locals[1]) is not assignable to 'stopwatch' (stack map, locals[1]) 
     Current Frame: 
     bci: @12 
     flags: { } 
     locals: { 'com/agent/database/Database', top, 'com/google/common/base/Stopwatch' } 
     stack: { 'java/lang/Throwable' } 
     Stackmap Frame: 
     bci: @85 
     flags: { } 
     locals: { 'com/agent/database/Database', 'stopwatch' } 
     stack: { 'java/lang/Throwable' } 
     Bytecode: 
     0x0000000: b800 2a4d b200 3212 34b6 003a 123c b800 
     0x0000010: 4257 2a12 4412 4612 48b8 004e b500 182a 
     0x0000020: b400 18c7 0014 1250 b200 3219 02b6 0053 
     0x0000030: b600 56b6 003a b02a 2ab4 0018 b900 5e01 
     0x0000040: 00b5 001c 2ab4 001c 2ab4 0020 b900 6402 
     0x0000050: 0057 a700 084d 2cb6 0067 1269 b200 3219 
     0x0000060: 02b6 0053 b600 56b6 003a b0    
     Exception Handler Table: 
     bci [12, 38] => handler: 85 
     bci [55, 82] => handler: 85 
     Stackmap Table: 
     append_frame(@55,Object[#88]) 
     same_locals_1_stack_item_frame(@85,Object[#44]) 
     same_frame(@90) 

     at com.agent.testers.tester1.main(tester1.java:15) 

Мне кажется, что после ASM создает новую запись в таблице локальной переменной для Секундомера, JVM пытается переписать его с местным переменные метода, который я пытаюсь настроить (в этом случае selectAll()). Поэтому:

Тип верхней (текущий кадр, местные жители [1]) не может быть назначен на 'Секундомер' (стек карты, местные жители [1])

Я не уверен, если это актуальная проблема или нет, но мне нужно ее решить! В конце концов, мой агент должен быть подключен любым способом. Вся ваша помощь будет оценена! Спасибо.

ответ

1

Вы создаете экземпляр «StopWatch» в новой выделенной «временной» локальной переменной, а затем загружаете его экземпляр из локального слота переменной 2, и вы должны добавить свой код после «super.visitCode()».

Также см. ASM FAQ Why do I get the xxx verifier error, чтобы узнать, как использовать CheckClassAdapter для отладки преобразований байт-кода.

+0

Hello Eugene! Прежде всего, поблагодарите свой ответ! Во-вторых, я немного смущен, потому что не знаю, – pvammus

Смежные вопросы