Bytecode (también llamado código portátil o código p [ cita requerida ] ) es una forma de conjunto de instrucciones diseñada para una ejecución eficiente por parte de un intérprete de software . A diferencia del código fuente [1] legible por humanos , los códigos de bytes son códigos numéricos compactos, constantes y referencias (normalmente direcciones numéricas) que codifican el resultado del análisis del compilador y la realización de análisis semánticos de elementos como el tipo, el alcance y la profundidad de anidamiento de los objetos del programa.
El nombre código de bytes proviene de conjuntos de instrucciones que tienen códigos de operación de un byte seguidos de parámetros opcionales. Las representaciones intermedias , como el código de bytes, pueden generarse mediante implementaciones de lenguajes de programación para facilitar la interpretación , o pueden usarse para reducir la dependencia del hardware y del sistema operativo al permitir que el mismo código se ejecute en varias plataformas , en diferentes dispositivos. El código de bytes a menudo puede ejecutarse directamente en una máquina virtual (una máquina de código p , es decir, un intérprete) o puede compilarse posteriormente en código de máquina para un mejor rendimiento.
Dado que las instrucciones de código de bytes son procesadas por software, pueden ser arbitrariamente complejas, pero a menudo son similares a las instrucciones de hardware tradicionales: las máquinas de pila virtuales son las más comunes, pero también se han construido máquinas de registro virtuales. [2] [3] Las diferentes partes a menudo se pueden almacenar en archivos separados, similares a los módulos de objetos , pero se cargan dinámicamente durante la ejecución.
Un programa de código de bytes se puede ejecutar analizando y ejecutando directamente las instrucciones, una a la vez. Este tipo de intérprete de código de bytes es muy portátil. Algunos sistemas, llamados traductores dinámicos o compiladores justo a tiempo (JIT), traducen código de bytes a código de máquina según sea necesario en tiempo de ejecución . Esto hace que la máquina virtual sea específica del hardware pero no pierde la portabilidad del código de bytes. Por ejemplo, el código Java y Smalltalk generalmente se almacena en formato de código de bytes, que luego generalmente se compila JIT para traducir el código de bytes a código de máquina antes de la ejecución. Esto introduce un retraso antes de que se ejecute un programa, cuando el código de bytes se compila en código de máquina nativo, pero mejora considerablemente la velocidad de ejecución en comparación con la interpretación directa del código fuente, normalmente en alrededor de un orden de magnitud (10x). [4]
Debido a su ventaja de rendimiento, hoy en día muchas implementaciones de lenguajes ejecutan un programa en dos fases: primero compilan el código fuente en código de bytes y luego pasan el código de bytes a la máquina virtual. Hay máquinas virtuales de este tipo basadas en códigos de bytes para Java , Raku , Python , PHP , [a] Tcl , mawk y Forth (sin embargo, Forth rara vez se compila mediante códigos de bytes de esta manera, y su máquina virtual es más genérica). En cambio, la implementación de Perl y Ruby 1.8 funciona recorriendo una representación de árbol de sintaxis abstracta derivada del código fuente.
Más recientemente, los autores de V8 [1] y Dart [7] han cuestionado la noción de que se necesita un código de bytes intermedio para una implementación rápida y eficiente de VM. Actualmente, ambas implementaciones de lenguaje realizan compilación JIT directa desde el código fuente al código de máquina sin intermediarios de código de bytes. [8]
disassemble
función [10] que imprime en la salida estándar el código subyacente de una función específica. El resultado depende de la implementación y puede o no resolverse en código de bytes. Su inspección se puede utilizar con fines de depuración y optimización. [11] Steel Bank Common Lisp , por ejemplo, produce:( desmontar ' ( lambda ( x ) ( print x ))) ; desmontaje para (LAMBDA (X)) ; 2436F6DF: 850500000F22 PRUEBA EAX, [#x220F0000]; punto de entrada sin análisis de argumentos ; E5: 8BD6 MOVEDX, ESI ; E7: 8B05A8F63624 MOV EAX, [#x2436F6A8]; #<objeto FDEFINICIÓN para IMPRIMIR> ; Edición: B904000000 MOV ECX, 4 ; F2: FF7504 PUSH DWORD PTR [EBP+4] ; F5: FF6005 JMP DWORD PTR [EAX+5] ; F8: CC0A ROTURA 10; trampa de errores ; FA: 02 BYTE #X02 ; FB: 18 BYTES #X18; ERROR-CONTADOR-ARG-INVÁLIDO ; FC: 4F BYTE #X4F; ECX
>>> import dis # "dis" - Desensamblador de código de bytes de Python en mnemónicos. >>> des . dis ( 'print("¡Hola, mundo!")' ) 1 0 LOAD_NAME 0 (imprimir) 2 LOAD_CONST 0 ('¡Hola, mundo!') 4 CALL_FUNCTION 1 6 RETURN_VALUE
{{cite web}}
: CS1 maint: bot: original URL status unknown (link)[…] De hecho, el formato es básicamente el mismo en
MS-DOS
3.3 - 8.0,
PC DOS
3.3 - 2000, incluidas las versiones rusa, lituana, china y japonesa, así como en Windows NT, 2000 y XP […] .
Existen pequeñas diferencias e incompatibilidades, pero el formato general no ha cambiado a lo largo de los años.
[…] Algunas de las entradas de datos contienen tablas normales […] Sin embargo, la mayoría de las entradas contienen
código ejecutable
interpretado por algún tipo de
intérprete de código p
en *
tiempo de ejecución
*, incluidas ramas condicionales y similares.
Esta es la razón por la que el controlador
KEYB
ocupa una cantidad de memoria tan grande en comparación con los controladores de teclado controlados por tabla, que se pueden realizar en 3 a 4 Kb y obtener el mismo nivel de función excepto el intérprete.
[…]
[…] Matthias [R.] Paul […] advierte que la versión
IBM PC DOS
del controlador de teclado utiliza algunos procedimientos internos que no son reconocidos por el controlador
de Microsoft
, por lo que, si es posible, se deben utilizar las versiones
IBM
de ambos
KEYB .
.COM
y
KEYBOARD.SYS
en lugar de mezclar versiones de Microsoft e IBM […](NB. Lo que se entiende por "procedimientos" aquí son algunos códigos de bytes adicionales en el archivo IBM KEYBOARD.SYS que no son compatibles con la versión de Microsoft del controlador KEYB).
Multiplan
no se compiló en
código de máquina
, sino en una especie de código de bytes ejecutado por un
intérprete
, para que Multiplan fuera portátil en el hardware tan variado de la época.
Este código de bytes distinguía entre el formato de punto flotante
específico de la máquina
para calcular y un formato externo (estándar), que era
decimal codificado en binario
(BCD).
Las instrucciones PACK y UNPACK se convierten entre las dos.