Java bytecode
From Wikipedia, the free encyclopedia
Remove ads
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]
Remove ads
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++".[4]
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.[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
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:
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.
Remove ads
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[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]
Remove ads
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.
Remove ads
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.[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.
Remove ads
Referencias
Véxase tamén
Wikiwand - on
Seamless Wikipedia browsing. On steroids.
Remove ads