Controlando alterações implementação do método em bytecode classe

s0larm00n:

Eu tenho algum projeto abstrato (vamos chamá-lo O Projeto) bytecode (ele é de cada classe) dentro de algum código Kotlin, e cada bytecode classe é armazenada como ByteArray; a tarefa é dizer que métodos específicos de cada classe estão sendo modificados de construção para construir do projeto. Em outras palavras, há dois bytearrays de uma mesma classe do projeto, mas eles pertencem a diferentes versões do mesmo, e eu preciso compará-los precisos. Um exemplo simples. Vamos supor que temos uma classe trivial:

class Rst {

    fun getjson(): String {
        abc("""ss""");
        return "jsonValid"
    }

    public fun abc(s: String) {
        println(s)
    }

}

É de bytecode é armazenado em oldByteCode. Agora algumas mudanças aconteceu com a classe:

class Rst {

        fun getjson(): String {
            abc("""ss""");
            return "someOtherValue"
        }

        public fun newMethod(s: String) {
            println("it's not abc anymore!")
        }

    }

É de bytecode é armazenado em newByteCode. Esse é o objetivo principal: compare oldByteCode para newByteCode.

Aqui temos as seguintes alterações:

  • método getJSON () tinha sido alterada;
  • método ABC () tinha sido removida;
  • newMethod () tinha sido criado.

Assim, um método for alterada, se é assinatura permanece o mesmo. Se não, já é algum método diferente.

Agora, de volta para o problema real. Eu tenho que saber o estado exato de cada método por ele de bytecode. O que eu tenho no momento é o analisador jacoco, que analisa classe bytecode para "pacotes". Nestes pacotes Tenho hierarquia de pacotes, classes, métodos, mas apenas com suas assinaturas, por isso não posso dizer se o corpo de um método tem quaisquer alterações. Eu só pode acompanhar diferenças de assinatura. Existem algumas ferramentas, libs para bytecode classe Split para seus métodos bytecodes? Com aqueles que eu poderia, por exemplo, hashes calcular e compará-los. Talvez biblioteca asm tem qualquer acordo com isso? Todas as idéias são bem-vindas.

Holger:

TL; DR você se aproxima de apenas comparando bytecode ou mesmo hashes não vai levar a uma solução confiável, de fato, não há uma solução com um esforço razoável para este tipo de problema.

Eu não sei, como muito do que se aplica para o compilador Kotlin, mas como elaborado em é a criação de classe Java arquivos determinista? , Compiladores de Java não são obrigados a produzir bytecode idêntica mesmo se a mesma versão é usado para compilar exatamente o mesmo código fonte. Enquanto eles podem ter uma implementação que tenta ser tão determinista quanto possível, as coisas mudam quando se olha para diferentes versões ou implementações alternativas, como explicado no Do diferente Java Compiladores (onde o fornecedor é diferente) produzem bytecode diferente .

Mesmo quando nós assumimos que o compilador Kotlin é excepcionalmente determinística, mesmo entre versões, não podemos ignorar a evolução JVM. Por exemplo, a remoção dos jsr/ retinstruções não pode ser ignorado por qualquer compilador, mesmo quando tentando ser conservador. Mas é bastante provável que ele irá incorporar outras melhorias, bem como, mesmo quando não estão sendo forced¹.

Assim, em breve, mesmo quando todo o código fonte não mudou, não é uma aposta segura para assumir que a forma compilada tem que permanecer o mesmo. Mesmo com um compilador explicitamente determinista teríamos que estar preparado para mudanças quando recompilar com as versões mais recentes.

Pior ainda, se muda um método, ele pode ter um impacto sobre a forma compilada dos outros, como instruções referem-se a itens de uma piscina constante, sempre que são necessários constantes ou informações de ligação e esses índices podem mudar, dependendo de como os outros métodos de usar o piscina constante. Há também uma forma optimizada para certas instruções ao acessar um dos primeiros 255 índices de piscina, assim que as mudanças na numeração poderá ser necessário alterar a forma da instrução. Este por sua vez pode ter um impacto sobre as outras instruções, por exemplo, instruções de comutação tem bytes de enchimento, dependendo a sua posição de código byte.

Por outro lado, uma simples mudança de um valor constante usado em apenas um método pode ter nenhum impacto no bytecode do método em tudo, se a nova constante aconteceu a acabar no mesmo lugar na piscina do que a antiga constante.

Assim, para determinar se o código de dois métodos faz realmente o mesmo, não há nenhuma maneira em torno de analisar as instruções e entender seu significado em algum grau. Comparando apenas bytes ou hashes não vai funcionar.

¹ para citar algumas mudanças não obrigatórios, a compilação de literais de classe mudou, da mesma forma concatenação mudou de usar StringBufferpara uso StringBuildere mudou novamente para usoStringConcatFactory , o uso de getClass()para intrínsecas nullcheques alterado pararequireNonNull(…) , etc. Um compilador para uma linguagem diferente não faz tem que seguir, mas ninguém quer ser deixado para trás ...

Há também erros para corrigir, como instruções obsoletas , que não compilador iria manter apenas para ficar determinista.

Acho que você gosta

Origin http://43.154.161.224:23101/article/api/json?id=231155&siteId=1
Recomendado
Clasificación