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.[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.
Exemplo
[editar | editar a fonte]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,0 1,1 "Java Virtual Machine Specification".
- ↑ 2,0 2,1 The Java Virtual Machine Specification. 2015. ISBN 978-0133905908.
- ↑ Arnold, Ken (1996). "The Java Programming Language". Sun Microsystems 1: 30–40.
- ↑ "IBM Developer". developer.ibm.com. Consultado o 20 de febreiro de 2006.
- ↑ 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.
- ↑ "JASMIN HOME PAGE". jasmin.sourceforge.net.
- ↑ Huang, James Jianbo. "Learn to speak Jamaican". InfoWorld (en inglés). Consultado o 2 de xuño de 2024.
- ↑ "Storyyeller/Krakatau". GitHub. Consultado o 2 de xuño de 2024.
- ↑ "Lilac - a Java assembler". lilac.sourceforge.net. Consultado o 2 de xuño de 2024.
- ↑ "FPC New Features 3.0.0 - Free Pascal wiki". wiki.freepascal.org.
- ↑ "FPC JVM - Free Pascal wiki". wiki.freepascal.org.
- ↑ "InvokeDynamic: Actually Useful?".
- ↑ "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]- 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