Saltar ao contido

Java bytecode

Na Galipedia, a Wikipedia en galego.

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.[1] Cada instrución é representada por un só byte, por iso o nome bytecode, o que o converte nunha forma compacta de datos.[2]

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.[3]

Relación con Java

[editar | editar a fonte]

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++".[4]

Arquitectura do conxunto de instrucións

[editar | editar a fonte]

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.[1]

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".[5]:2.6[2] 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. [5]: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[5]: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).[5]: 2.6.2

Conxunto de instrucións

[editar | editar a fonte]

Cada bytecode está composto por un byte que representa o opcode, xunto con cero ou máis bytes para operandos.[5]: 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.[5]: 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.[5]: 2.11.1 Son os seguintes:

Prefixo/Sufixo Tipo de operando
i integer
l long
s short
b byte
c character
f float
d double
a reference

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.

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

[editar | editar a fonte]

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[6]
  • 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.[7]
  • 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.[8]
  • Lila, un ensamblador e desensamblador para a máquina virtual Java.[9]

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+.[10][11]

Execución

[editar | editar a fonte]

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

[editar | editar a fonte]

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.[12]

JSR 292 (Compatibilidade con linguaxes de tipo dinámico na plataforma Java)[13] 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

[editar | editar a fonte]
  1. 1,0 1,1 "Java Virtual Machine Specification". 
  2. 2,0 2,1 The Java Virtual Machine Specification. 2015. ISBN 978-0133905908. 
  3. Arnold, Ken (1996). "The Java Programming Language". Sun Microsystems 1: 30–40. 
  4. "IBM Developer". developer.ibm.com. Consultado o 20 de febreiro de 2006. 
  5. 5,0 5,1 5,2 5,3 5,4 5,5 5,6 Lindholm, Tim; Yellin, Frank; Bracha, Gilad; Buckley, Alex (13 de febreiro de 2015). The Java Virtual Machine Specification. 
  6. "JASMIN HOME PAGE". jasmin.sourceforge.net. 
  7. Huang, James Jianbo. "Learn to speak Jamaican". InfoWorld (en inglés). Consultado o 2 de xuño de 2024. 
  8. "Storyyeller/Krakatau". GitHub. Consultado o 2 de xuño de 2024. 
  9. "Lilac - a Java assembler". lilac.sourceforge.net. Consultado o 2 de xuño de 2024. 
  10. "FPC New Features 3.0.0 - Free Pascal wiki". wiki.freepascal.org. 
  11. "FPC JVM - Free Pascal wiki". wiki.freepascal.org. 
  12. "InvokeDynamic: Actually Useful?". 
  13. "The Java Community Process(SM) Program - JSRs: Java Specification Requests - detail JSR# 292". www.jcp.org. 

Véxase tamén

[editar | editar a fonte]

Ligazóns externas

[editar | editar a fonte]