En programación informática , una máquina de código P ( máquina de código portátil [ 1 ] ) es una máquina virtual diseñada para ejecutar código P, el lenguaje ensamblador o código máquina de una hipotética unidad central de procesamiento (CPU). El término máquina de código P se aplica genéricamente a todas estas máquinas (como la máquina virtual Java (JVM) y el código precompilado de MATLAB ), así como a implementaciones específicas que utilizan dichas máquinas. Uno de los usos más notables de las máquinas de código P es la P-Machine del sistema Pascal-P . Los desarrolladores de la implementación de Pascal de la UCSD dentro de este sistema interpretaron la P en código P como pseudo más a menudo que como portátil; adoptaron una etiqueta única para el pseudocódigo que significa instrucciones para una pseudomáquina.
Aunque el concepto se implementó por primera vez alrededor de 1966 como código O para el lenguaje de programación combinado básico ( BCPL ) y código P para el lenguaje Euler , [ 2 ] el término código P apareció por primera vez a principios de la década de 1970. Dos compiladores tempranos que generaban código P fueron el compilador Pascal-P en 1973, por Kesav V. Nori, Urs Ammann, Kathleen Jensen, Hans-Heinrich Nägeli y Christian Jacobi, [ 3 ] y el compilador Pascal-S en 1975, por Niklaus Wirth .
Los programas traducidos a código P pueden ser interpretados por un programa de software que emule el comportamiento de la CPU hipotética, o bien traducidos al código máquina de la CPU en la que se ejecutará el programa y, posteriormente, ejecutados. Si existe suficiente interés comercial, se puede construir una implementación de hardware de la especificación de la CPU (por ejemplo, el Pascal MicroEngine o una versión de un procesador Java ).
Código P frente a código máquina
Si bien un modelo de compilador típico tiene como objetivo traducir un código de programa a código máquina , la idea de una máquina de código P sigue un enfoque de dos etapas que implica la traducción a código P y la ejecución mediante interpretación o compilación justo a tiempo (JIT) a través de la máquina de código P.
Esta separación permite desvincular el desarrollo de un intérprete de código P del compilador de código máquina subyacente, que debe considerar el comportamiento dependiente de la máquina al generar su código de bytes . De esta forma, un intérprete de código P también puede implementarse más rápidamente, y la capacidad de interpretar el código en tiempo de ejecución permite realizar comprobaciones adicionales que podrían no estar disponibles en el código nativo. Además, como el código P se basa en una máquina virtual ideal, un programa en código P suele ser más pequeño que el mismo programa traducido a código máquina. Por otro lado, la interpretación en dos pasos de un programa basado en código P conlleva una velocidad de ejecución más lenta, aunque esto a veces se puede solucionar con la compilación justo a tiempo , y su estructura más simple facilita la ingeniería inversa en comparación con el código nativo.
Implementaciones del código P
A principios de la década de 1980, al menos dos sistemas operativos lograron la independencia de la máquina mediante el uso extensivo de código P. El Business Operating System (BOS) era un sistema operativo multiplataforma diseñado para ejecutar exclusivamente programas en código P. El UCSD p-System , desarrollado en la Universidad de California en San Diego, era un sistema operativo autocompilable y autoalojado basado en código P optimizado para su generación mediante el lenguaje Pascal .
En la década de 1990, la traducción a código P se convirtió en una estrategia popular para las implementaciones de lenguajes como Python , Microsoft P-Code en Visual Basic y Java bytecode en Java .
El lenguaje Go utiliza un lenguaje ensamblador genérico y portátil como forma de código P, implementado por Ken Thompson como una extensión del trabajo de Plan 9 de Bell Labs . A diferencia del código de bytes de Common Language Runtime (CLR) o del código de bytes de la JVM, no existe una especificación estable y las herramientas de compilación de Go no generan un formato de código de bytes para su uso posterior. El ensamblador de Go utiliza el lenguaje ensamblador genérico como representación intermedia y los ejecutables de Go son binarios enlazados estáticamente específicos de la máquina . [ 4 ]
Máquina P de la UCSD
Arquitectura
Al igual que muchas otras máquinas de código P, la máquina P de la UCSD es una máquina de pila , lo que significa que la mayoría de las instrucciones toman sus operandos de una pila y colocan los resultados de nuevo en ella. Por lo tanto, la addinstrucción reemplaza los dos elementos superiores de la pila con su suma. Algunas instrucciones toman un argumento inmediato. Al igual que Pascal, el código P es fuertemente tipado y admite de forma nativa los tipos de datos booleano (b), carácter (c), entero (i), real (r), conjunto (s) y puntero (a) .
Algunas instrucciones sencillas:
Descripción de la pila Insn. antes después adi i1 i2 i1+i2 suman dos números enteros adr r1 r2 r1+r2 suman dos números reales inn i1 s1 b1 conjunto de pertenencia; b1 = si i1 es miembro de s1 ldi i1 i1 i1 carga constante entera mover a1 a2 a2 mover no b1 b1 -b1 Negación booleanaAmbiente
De forma similar a una CPU real, el sistema P tiene una única pila compartida por los marcos de pila de procedimientos (que proporcionan la dirección de retorno , etc.) y los argumentos de las instrucciones locales. Tres de los registros de la máquina apuntan a la pila (que crece hacia arriba):
- SP apunta a la parte superior de la pila (el puntero de pila ).
- MP marca el inicio del marco de pila activo (el puntero de marca ).
- EP apunta a la ubicación de pila más alta utilizada en el procedimiento actual (el puntero extremo ).
También está presente un área constante y, debajo de ella, el montón que crece hacia la pila. El registro NP (el nuevo puntero ) apunta a la parte superior (la dirección más baja utilizada) del montón. Cuando EP supera a NP, la memoria de la máquina se agota.
El quinto registro, PC, apunta a la instrucción actual en el área de código.
Convenciones de llamadas
Los marcos de pila tienen este aspecto:
EP -> pila local SP -> ... lugareños ... parámetros ... Dirección de retorno (PC anterior) EP anterior Enlace dinámico (diputado anterior) Enlace estático (MP del procedimiento circundante) MP -> valor de retorno de la función
La secuencia de llamada al procedimiento funciona de la siguiente manera: La llamada se introduce con
mst n
donde nse especifica la diferencia en los niveles de anidamiento (recuerde que Pascal admite procedimientos anidados). Esta instrucción marcará la pila, es decir, reservará las primeras cinco celdas del marco de pila anterior e inicializará el enlace EP, dinámico y estático anterior. El llamador calcula y agrega los parámetros para el procedimiento y luego ejecuta
taza n, p
Para llamar a un procedimiento de usuario ( ndonde es el número de parámetros y pes la dirección del procedimiento). Esto guardará el PC en la celda de dirección de retorno y establecerá la dirección del procedimiento como el nuevo PC.
Los procedimientos de usuario comienzan con las dos instrucciones.
ent 1, i ent 2, j
El primero establece SP a MP+ i, el segundo establece EP a SP+ j. En iesencia, especifica el espacio reservado para variables locales (más el número de parámetros más 5) y jproporciona el número de entradas necesarias localmente para la pila. En este punto se comprueba el agotamiento de la memoria.
La devolución a la persona que llamó se realiza mediante
retC
especificando Cel tipo de retorno (i, r, c, b, a como se indicó anteriormente, y p para ningún valor de retorno). El valor de retorno debe almacenarse previamente en la celda correspondiente. En todos los tipos, excepto p, el retorno dejará este valor en la pila.
En lugar de llamar a un procedimiento de usuario (cup), qse puede llamar a un procedimiento estándar con
csp q
Estos procedimientos estándar son procedimientos de Pascal como readln()( csp rln), sin()( csp sin), etc. Curiosamente, eof()es una instrucción de código P en su lugar.
Máquina de ejemplo
Niklaus Wirth especificó una máquina de código p simple en el libro de 1976 Algorithms + Data Structures = Programs . La máquina tenía 3 registros: un contador de programa p , un registro base b y un registro de cima de pila t . Había 8 instrucciones:
lit 0, a: cargar constante aopr 0, a: ejecutar operación a (13 operaciones: RETORNO, 5 funciones matemáticas y 7 funciones de comparación)lodl, a: cargar variable l , astol, a: almacenar variable l , acall, a: llamar al procedimiento a en el nivel lint 0, a: incrementar el registro t en unjmp 0, a: saltar a unjpc 0, a: salto condicional a un [ 5 ]
Este es el código de la máquina, escrito en Pascal:
const amax = 2047 ; {dirección máxima} levmax = 3 ; {profundidad máxima de anidamiento de bloques} cxmax = 200 ; {tamaño del array de código}tipo fct = ( lit , opr , lod , sto , cal , int , jmp , jpc ) ; instrucción = registro empaquetado f : fct ; l : 0 .. levmax ; a : 0 .. amax ; fin ;var code : array [ 0 .. cxmax ] de instrucción ;procedimiento interpretar ;const stacksize = 500 ;var p , b , t : entero ; {registros de programa, base y pila superior} i : instrucción ; {registro de instrucción} s : matriz [ 1..tamaño de pila ] de enteros ; {almacén de datos}función base ( l : entero ) : entero ; var b1 : entero ; inicio b1 := b ; {encontrar base l niveles hacia abajo} mientras l > 0 hacer inicio b1 := s [ b1 ] ; l := l - 1 fin ; base := b1 fin {base} ;begin writeln ( ' inicio pl/0' ) ; t := 0 ; b := 1 ; p := 0 ; s [ 1 ] := 0 ; s [ 2 ] := 0 ; s [ 3 ] := 0 ; repeat i := code [ p ] ; p := p + 1 ; with i do case f of lit : begin t := t + 1 ; s [ t ] := a end ; opr : case a of {operator} 0 : begin {return} t := b - 1 ; p := s [ t + 3 ] ; b := s [ t + 2 ] ; end ; 1 : s [ t ] := - s [ t ] ; 2 : begin t := t - 1 ; s [ t ] := s [ t ] + s [ t + 1 ] end ; 3 : begin t := t - 1 ; s [ t ] := s [ t ] - s [ t + 1 ] end ; 4 : begin t := t - 1 ; s [ t ] := s [ t ] * s [ t + 1 ] end ;5 : begin t := t - 1 ; s [ t ] := s [ t ] div s [ t + 1 ] end ; 6 : s [ t ] := ord ( odd ( s [ t ])) ; 8 : begin t := t - 1 ; s [ t ] := ord ( s [ t ] = s [ t + 1 ]) end ; 9 : begin t := t - 1 ; s [ t ] := ord ( s [ t ] <> s [ t + 1 ]) end ; 10 : begin t := t - 1 ; s [ t ] := ord ( s [ t ] < s [ t + 1 ]) end ; 11 : begin t := t - 1 ; s [ t ] := ord ( s [ t ] >= s [ t + 1 ]) end ; 12 : begin t := t - 1 ; s [ t ] := ord ( s [ t ] > s [ t + 1 ]) end ; 13 : begin t := t - 1 ; s [ t ] := ord ( s [ t ]<= s [ t + 1 ]) fin ; fin ; lod : inicio t := t + 1 ; s [ t ] := s [ base ( l ) + a ] fin ; sto : inicio s [ base ( l ) + a ] := s [ t ] ; writeln ( s [ t ]) ; t := t - 1 fin ; cal : inicio {generar nueva marca de bloque} s [ t + 1 ] := base ( l ) ; s [ t + 2 ] := b ; s [ t + 3 ] := p ; b := t + 1 ; p := a fin ; int : t := t + a ; jmp : p := a ; jpc : begin if s [ t ] = 0 then p := a ; t := t - 1 end end {with, case} until p = 0 ; writeln ( ' end pl/0' ) ; end {interpret} ;Esta máquina se utilizó para ejecutar PL/0 de Wirth , un compilador de subconjunto de Pascal utilizado para enseñar el desarrollo de compiladores. [ 6 ]
Código P de Microsoft
El objetivo de la empresa era lanzar software para todas las principales plataformas y arquitecturas existentes en ese momento. Entre 1980 y 1982, Microsoft desarrolló un compilador C primitivo que generaba código P (el lenguaje C en sí no estaba estandarizado y no lo estaría hasta finales de los 80). El código P permitía ejecutar software en la mayoría de las plataformas con cambios mínimos en el código. UCSD Pascal utilizaba un enfoque similar. Esta conversión de C a código P fue un éxito, pero muy lenta. En 1983, Microsoft lanzó el compilador Microsoft C (MSC), basado en una licencia del compilador Lattice C para las versiones 1.0 y 2.0; a partir de la versión 3.0, el MSC fue completamente reescrito por Microsoft. [ 7 ]
El código P es un nombre que posteriormente utilizaron algunos de los lenguajes intermedios de Microsoft . Estos proporcionaban un formato binario alternativo al código máquina. En varias ocasiones, Microsoft ha afirmado que el código P es una abreviatura de código empaquetado [ 8 ] o pseudocódigo [ 9 ] .
Una variante del código P de Microsoft, bastante diferente de la utilizada por el compilador de C, se usaba ampliamente con Visual Basic , que contaba con un entorno de ejecución que incluía una máquina virtual o podía compilarse directamente a código nativo. Al igual que otras implementaciones de código P, el código P de Microsoft permitía un ejecutable más compacto a costa de una ejecución más lenta.
Otras implementaciones
Véase también
- Código de bytes
- Representación intermedia
- Joel McCormack , diseñador de la versión de la máquina de código P de NCR Corporation
- Sistema de tiempo de ejecución
- enhebrado de tokens
- Código mnemotécnico de City & Guilds
Referencias
- ↑ Upton, Eben; Duntemann, Jeffrey; Roberts, Ralph; Mamtora, Tim; Everard, Ben (13 de septiembre de 2016). Aprendiendo arquitectura de computadoras con Raspberry Pi . John Wiley & Sons. ISBN 978-1-119-18393-8.
- ↑ Wirth, Niklaus ; Weber, Helmut (1966). "EULER: una generalización de ALGOL y su definición formal: Parte II" . Communications of the ACM . 9 (2). Nueva York, EE. UU.: Association for Computing Machinery (ACM): 89–99 . doi : 10.1145/365170.365202 . S2CID 12124100 .
- ^ Nori, Kesav V.; Ammann, Urs; Jensen, Kathleen; Nägeli, Hans-Heinrich; Jacobi, cristiano (1975). Notas de implementación del compilador Pascal P. Zúrich, Suiza: Eidgenössische Technische Hochschule (ETH).
- ↑ Pike, Robert C. (2016). "El diseño del ensamblador de Go" . YouTube (Charla en conferencia). Archivado del original el 11 de diciembre de 2021. Recuperado el 25 de agosto de 2017 .
- ↑ "Archivos de categoría: Wirth - Euler - Diseñado por Niklaus Wirth y Helmut Weber" . Pascal para máquinas pequeñas - Lenguajes Wirth, Pascal, UCSD, Turbo, Delphi, Freepascal, Oberon . 2 de agosto de 2018.
- ↑ Alpert, Donald (septiembre de 1979). Un intérprete de código P de Pascal para el Stanford Emmy (PDF) (Informe). Laboratorio de Sistemas Informáticos, Departamentos de Ingeniería Eléctrica e Informática, Universidad de Stanford. Nota técnica n.º 164.
- ↑ "Software" . Computerworld . 19 (15). Framingham, MA: CW Communications: 71. 15 de abril de 1985. ISSN 0010-4841 .
Microsoft ha anunciado una versión mejorada de su compilador Microsoft C para la computadora personal IBM... Un portavoz del proveedor dijo que la versión 3.0 es el primer compilador C desarrollado internamente por Microsoft.
- ↑ Padawer, Andy (abril de 1992). "Tecnología de código P de Microsoft" . Microsoft Developer Network . Archivado del original el 22 de febrero de 2001.
- ↑ "Compilación de su proyecto a código nativo" . Documentación de Visual Studio 6.0 . 2007. Archivado del original el 27 de febrero de 2007.
Lecturas adicionales
- Pemberton, Steven ; Daniels, Martin. Implementación de Pascal: El compilador e intérprete P4 . John Wiley . ISBN 0-13-653031-1.
- Pemberton, Steven , ed. (2011-04-13). "Implementación de Pascal: un libro y fuentes" .(Nota: Incluye el código fuente en Pascal del compilador e intérprete P4 , así como instrucciones de uso).
- Pemberton, Steven , ed. (2011-04-13). "pcode del compilador Pascal tal como se compila a sí mismo" .(Nota: Contiene el código P del compilador P4 , generado por sí mismo).
- "Página del Museo de Computación Jefferson sobre el sistema p de la UCSD" .
- "Implementación de código abierto" ., incluyendo empaquetado y binarios precompilados; una bifurcación amigable de Klebsch. "Implementación de Klebsch" .
- Terry, Pat (2005). Compilación con C# y Java . Pearson/Addison-Wesley. pág. 624. ISBN 0-321-26360-X.
- Wirth, Niklaus (1975). Algoritmos + Estructuras de datos = Programas . Prentice-Hall. ISBN 0-13-022418-9.
- Wirth, Niklaus (1996). Construcción de compiladores . Addison-Wesley. ISBN 0-201-40353-6.
- Liffick, Blaise W., ed. (1979). The Byte Book of Pascal . BYTE Publications. ISBN 0-07-037823-1.
- Barron, David William , ed. (1981). Pascal: El lenguaje y su implementación . Wiley. ISBN 0-471-27835-1.(Nota: Consulte especialmente los artículos Notas de implementación de Pascal-P y Pascal-S: Un subconjunto y su implementación ).
Enlaces externos
- Información sobre el código P de VB por Mr Silver en Wayback Machine (archivado el 22 de diciembre de 2015)
- Máquinas virtuales basadas en pila
- Pascal (lenguaje de programación)
- Compiladores
- Implementación del lenguaje de programación