Java bytecode

Java bytecode é o conxunto de instrucións da máquina virtual de Java (JVM), a linguaxe na que se compila o código fonte de Java e outros códigos compatibles con JVM. Cada instrución é representada por un só byte, por iso o nome bytecode, o que o converte nunha forma compacta de datos.

Debido á natureza do bytecode, un programa de bytecode de Java pódese executar en calquera máquina cunha JVM compatíbel, sen o longo proceso de compilar a partir do código fonte.

Java bytecode é utilizado en tempo de compilación, xa sexa interpretado por unha JVM ou compilado a código máquina mediante compilación xusto a tempo (JIT) e executado como unha aplicación nativa.

Como Java bytecode está deseñado para a compatibilidade e seguridade entre plataformas, unha  aplicación de Java bytecode tende a executarse de forma consistente en varias configuracións de hardware e software.

 Relación con Java 
En xeral, un programador de Java non necesita comprender Java bytecode, nin sequera ser consciente del. Con todo, como se suxire na revista IBM developerWorks, "Comprender o bytecode e que bytecode é probable que xere un compilador de Java axuda ao programador de Java do mesmo xeito que o coñecemento de ensamblador axuda ao programador de C ou C++".

 Arquitectura do conxunto de instrucións 
O bytecode comprende varios tipos de instrucións, incluíndo a manipulación de datos, a transferencia de control, a creación e manipulación de obxectos e a invocación de métodoa, todos eles parte integral do modelo de programación orientada a obxectos de Java.

A JVM é tanto unha máquina de pila como unha máquina de rexistros. Cada marco para unha chamada de método ten unha "pila de operandos" e unha matriz de "variábeis locais".:2.6 A pila de operandos úsase para pasar operandos aos cálculos e para recibir o valor de retorno dun método chamado, mentres que as variables locais serven para o mesmo propósito que os rexistros e tamén se usan para pasar argumentos de métodos. O tamaño máximo da pila de operandos e da matriz de variables locais, calculada polo compilador, forma parte dos atributos de cada método. :4.7.3 Cada un pode ter un tamaño independente de 0 a 65535 valores, onde cada valor é de 32 bits. Os tipos long e double, que son de 64 bits, ocupan dúas variables locais consecutivas:2.6.1 (que non precisan estar aliñadas a 64 bits na matriz de variables locais) ou un valor na pila de operandos (pero cóntanse como dúas unidades na profundidade da pila).: 2.6.2 

 Conxunto de instrucións 
Cada bytecode está composto por un byte que representa o opcode, xunto con cero ou máis bytes para operandos.: 2.11 

Dos 256 opcodes de bytes posibles, dende 2015, 202 están en uso (~79%), 51 están reservados para uso futuro (~20%), e 3 instrucións (~1%) están reservadas permanentemente para que as usen as implementacións de JVM.: 6.2 Dúas destas (impdep1 e impdep2) serven para proporcionar trampas para software e hardware específicos da implementación, respectivamente. A terceira úsase para que os depuradores implementen puntos de interrupción (breakpoints).

As instrucións divídense en varios grupos amplos:

 Carga e almacenamento (por exemplo, aload_0, istore)
 Aritmetico-lóxicas (por exemplo, ladd, fcmpl)
 Conversión de tipo (por exemplo, i2b, d2i)
 Creación e manipulación de obxectos (new, putfield)
 Xestión da pila de operandos (por exemplo, swap, dup2)
 Transferencia de control (por exemplo, ifeq, goto)
 Invocación e retorno de métodos (por exemplo, invokespecial, areturn)

Tamén hai algunhas instrucións para unha serie de tarefas máis especializadas, como a xeración de excepcións, a sincronización, etc.

Moitas instrucións teñen prefixos e/ou sufixos que refiren aos tipos de operandos nos que operan.: 2.11.1 Son os seguintes:
Prefixo/SufixoTipo de operandoiintegerllongsshortbbyteccharacterffloatddoubleareference
Por exemplo, iadd sumará dous enteiros, mentres que dadd sumará dous doubles. As instrucións const, load e store tamén poden tomar un sufixo da forma _n, onde n é un número do 0 ao 3 para load e store. O n máximo para const varía segundo o tipo.

As instrucións const introducen un valor do tipo especificado na pila. Por exemplo, iconst_5 introduce un enteiro (valor de 32 bits) co valor 5 na pila, mentres que dconst_1 introduce un double (valor de coma flotante de 64 bits) co valor 1 na pila. Tamén hai un aconst_null, que envía unha referencia nula (null). O n para as instrucións load e store especifica o índice na matriz de variables locais desde onde cargar ou onde almacenar. A instrución aload_0 envía o obxecto da variable local 0 á pila (normalmente é o obxecto this). istore_1 almacena o número enteiro que está na parte superior da pila na variable local 1. Para as variables locais posteriores a 3, o sufixo elimínase e deben usarse operandos.

 Exemplo 
Considere o seguinte código Java:outer:
for (int i = 2; i < 1000; i++) {
    for (int j = 2; j < i; j++) {
        if (i % j == 0)
            continue outer;
    }
    System.out.println(i);
}Un compilador de Java podería traducir o código Java anterior a bytecode do seguinte xeito, supoñendo que se puxese nun método:0:   iconst_2
1:   istore_1
2:   iload_1
3:   sipush  1000
6:   if_icmpge       44
9:   iconst_2
10:  istore_2
11:  iload_2
12:  iload_1
13:  if_icmpge       31
16:  iload_1
17:  iload_2
18:  irem
19:  ifne    25
22:  goto    38
25:  iinc    2, 1
28:  goto    11
31:  getstatic       #84; // Field java/lang/System.out:Ljava/io/PrintStream;
34:  iload_1
35:  invokevirtual   #85; // Method java/io/PrintStream.println:(I)V
38:  iinc    1, 1
41:  goto    2
44:  return

 Xeración 
A linguaxe máis común á que se dirixe a máquina virtual de Java producindo Java bytecode é Java. Orixinalmente só existía un compilador, o compilador javac de Sun Microsystems, o cal compila código fonte Java a bytecode Java; pero como todas as especificacións para o bytecode Java xa están dispoñibles, outras partes forneceron compiladores que producen bytecode Java. 

Algúns exemplos doutros compiladores inclúen:

 Compilador Eclipse para Java (ECJ)
 Jikes, compila de Java a bytecode Java (desenvolvido por IBM, implementado en C++)
 Espresso, compila de Java a bytecode Java (só Java 1.0)
 GNU Compiler for Java (GCJ), compila de Java a bytecode Java; tamén pode compilar a código máquina nativo e formou parte da GNU Compiler Colección (GCC) ata a versión 6.

Algúns proxectos proporcionan ensambladores Java para permitir escribir Java bytecode a man. O código ensamblador tamén pode ser xerado por máquinas, por exemplo, por un compilador dirixido a unha máquina virtual Java. Entre os ensambladores de Java máis destacados inclúense:

 Jasmin, toma descricións de texto para as clases de Java, escritas nunha sintaxe simple similar á dun ensamblador usando o conxunto de instrucións da máquina virtual Java e xera un ficheiro de clase Java
 Jamaica, unha linguaxe de ensamblaxe de macros  para a máquina virtual Java. A sintaxe de Java úsase para a definición de clases ou de interfaces. Os corpos dos métodos especifícanse usando instrucións de bytecode.
 Krakatau Bytecode Tools, contén actualmente tres ferramentas: un descompilador e desensamblador para ficheiros de clase de Java e un ensamblador para crear ficheiros de clase.
 Lila,  un ensamblador e desensamblador para a máquina virtual Java.

Outros desenvolveron compiladores, para diferentes linguaxes de programación, dirixidos á máquina virtual Java, como:

 ColdFusion
 JRuby e Jython, dúas linguaxes de scripting baseadas en Ruby e Python
 Apache Groovy,  linguaxe de propósito xeral opcionalmente tipada e dinámica, con capacidades de tipado estático e compilación estática
 Scala, unha linguaxe de programación xeral de tipado seguro que admite programación funcional e programación orientada a obxectos
 JGNAT e AppletMagic, compilan da linguaxe Ada a Java bytecode
 Compiladores de C a bytecode Java
 Clojure, unha linguaxe de programación funcional, inmutable e de propósito xeral da familia Lisp cunha forte énfase na concorrencia
 Kawa, unha implementación da linguaxe de programación Scheme, tamén un dialecto de Lisp.
 MIDletPascal
 O código JavaFX Script compílase en bytecode Java
 Kotlin, unha linguaxe de programación de propósito xeral con tipado estático e inferencia de tipos
 O código fonte de Object Pascal compílase en bytecode Java usando o compilador Free Pascal 3.0+.

 Execución 
Hoxe en día existen varias máquinas virtuais Java dispoñibles para executar Java bytecode, tanto produtos gratuítos como comerciais. Se non é desexable executar bytecode nunha máquina virtual, un desenvolvedor tamén pode compilar código fonte ou Java bytecode directamente a código máquina nativo con ferramentas como o GNU Compiler for Java (GCJ). Algúns procesadores poden executar Java bytecode de forma nativa. Estes procesadores denomínanse procesadores de Java.

 Compatibilidade con linguaxes dinámicas 
A máquina virtual Java ofrece certa compatibilidade con  linguaxes de tipo dinámico. A maior parte do conxunto de instrucións JVM existente ten tipado estático, no sentido de que as chamadas a métodos teñen as súas sinaturas verificadas no tempo de compilación, sen un mecanismo para adiar esta decisión ao tempo de execución ou para elixir o envío do método mediante un enfoque alternativo.

JSR 292 (Compatibilidade con linguaxes de tipo dinámico na plataforma Java) engadiu unha nova instrución invokedynamic no nivel de JVM, para permitir a invocación de métodos baseándose na comprobación dinámica de tipo (en lugar da instrución invokevirtual existente con tipo verificado estaticamente). A máquina Da Vinci é unha implementación prototipo de máquina virtual que aloxa extensións de JVM destinadas a soportar linguaxes dinámicas. Todas as JVM compatibles con JSE 7 tamén inclúen o código de operación invokedynamic.

 Referencias 

 Véxase tamén 
 Ligazóns externas 

 Especificación da máquina virtual Java de Oracle
 Linguaxes de programación para a máquina virtual Java
 Visualizador de bytecode: visor e depurador de bytecode (complemento gratuíto de Eclipse)
 AdaptJ StackTrace: depuración a nivel de bytecode con control total da pila, as variables locais e o fluxo de execución
 Unpacker de clases Java: complemento para Total Commander, permite abrir ficheiros de clase como arquivos comprimidos e ver campos e métodos como ficheiros. O bytecode pódese ver como texto usando F3

Categoría:Java (linguaxe de programación)