domingo, 15 de maio de 2016

Projeto Valhalla - Um pouco sobre este grande projeto.



Project Valhalla

Para quem não conhece, o projeto Valhalla visa melhorar os genéricos da linguagem Java. Como a própria página do projeto diz, ele não irá trazer os genéricos reificados para o Java, o objetivo principal é permitir que possamos utilizar primitivos nos genéricos.

É inevitável que, com a evolução da JVM seja necessário termos uma espécie de unificação entre Referencias e Valores (primitivos) no sistema de genéricos do Java, já que, cada vez os genéricos estão mais presentes na linguagem, como por exemplo, nas classes funcionais.

Atualmente, os genéricos só aceitam Referencias, e isto faz com que, se você quiser passar os tipos primitivos, você irá informar o tipo Wrapped (Integer, Character, Short, etc), e quando passar os valores, a JVM irá fazer boxing e unboxing, e como na maioria das vezes utilizamos primitivos, a JVM terá um grande problema com o desempenho. A solução atual desenvolvida pela equipe para a área funcional, foi criar classes funcionais que aceitassem primitivos (IntUnaryOperator, DoubleUnaryOperator), porém, em uma linguagem orientada a objetos, esta não é a melhor solução, sem considerar que, o método destas classes são: applyAsInt, applyAsDouble, etc.

A proposta atual da equipe do Valhalla é: manter o type erasure para os genericos de Referencia, e criar uma nova classe em runtime para os primitivos, esta é uma boa solução, mas ainda é apenas o começo.

Até o momento, a parte mais importante já foi implementada, a geração de classe para os primitivos e a possibilidade de usa-los nos genéricos.

Para que isto pudesse ser possivel era necessário que algumas instruções fossem substituidas por outras, por exemplo, quando se trata de um objeto é utilizado 'aload', 'astore', porém, quando se trata de um primitivo, é necessário usar por exemplo, 'iload', 'dload', etc, uma para cada primitivo. A proposta do modelo 3 era criar novas instruções que pudessem chamar outras instruções baseadas no tipo armazenado no 'constant pool' (cabeçalho da classe aonde ficam muitas das informações) das classes, sendo elas 'vreturn', 'vload', 'vstore', etc... que referenciam uma posição do 'constant pool', atualmente é este que esta sendo implementado no projeto.

Veja um exemplo abaixo:

Minha classe:



A palavra 'any' será a nova palavra reservada do Java, que indica que este genérico poderá receber qualquer coisa, não só Referencias, mas também tipos primitivos. Também será inserida duas novas palavras reserdas, ref e val, ref será somente para referencias, e val para os futuros 'Value Types' e os primitivos. Quando compilada, serão geradas duas classes, a MinhaClasse e MinhaClasse$$any.

A classe MinhaClasse implementará a classe MinhaClasse$$any, a qual até o momento é só uma representação, não tem nenhum elemento dentro dela, somente algumas informações.

Agora vamos ver o que ocorre quando chamarmos esta classe com dois tipos distintos, uma int, e outra String.


Agora, quando executarmos este código, quando você instanciar a classe pedindo que o genérico seja int, a JVM irá gerar uma classe que também implementa MinhaClasse$$any que aceita int, e com um método getValue que retorna int, esta classe se chamara MinhaClasse$${I} (sendo I a representação de int). No segundo caso, a JVM continuará fazendo o mesmo que faz atualmente, inferindo os tipos, não irá gerar nenhuma classe.

A geração de classes fica a cargo de um "especializador", o mesmo faz logging dizendo que especializou a classe.



Vamos dar uma olhada no bytecode agora?


Na primeira declaração, vemos que o compilador gera uma chamada para uma classe chamada MinhaClass<I>, qual não existe em tempo de compilação, em em tempo de execução será gerada, assim permitindo que ela seja chamada ser dar erro de "ClassNotFound", também é chamado o construtor (I)V, que está presente na classe gerada, mas não na classe que escrevemos (a que escrevemos tem o constructor descrito como '(Ljava/lang/Object;)V' (MinhaClasse(Object)), qual se pode observar mais abaixo após '// String X'

O compilador gera o código desta forma pois, durante a compilação, não é possível chamar classes inexistente (o compilador oficial não permite), mas é possível sim, chamar métodos ou classes que não existem durante a compilação, contanto que elas existam durante a execução da aplicação.


Os obstaculos

 

Por mais que tenha muita coisa pronta, ainda não está completo, é necessário ainda correções no sistema de Arrays (proposta Arrays 2.0), Arrays de genéricos ainda precisam ser Object (o método toArray do List & Stream por exemplo, que aceita T[], só irá aceitar arrays de objetos, não os de int), melhorias de desempenho e refinamentos, também tem o problema com a compatibilidade, que é o maior obstáculo atual.



Fiquem ligados, mais noticias postarei no blog.


Tags: , , , ,

0 Comentarios para “Projeto Valhalla - Um pouco sobre este grande projeto.”

Postar um comentário

© SouUmByte. Todos direitos reservados.
Designed by SpicyTricks