stringtranslate.com

máquina de código p

En programación de computadoras , 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 de máquina de una hipotética unidad central de procesamiento (CPU)). Este término se aplica tanto genéricamente a todas estas máquinas (como la máquina virtual Java (JVM) y el código precompilado de MATLAB ) como a implementaciones específicas, siendo la más famosa la p-Machine del sistema Pascal-P , particularmente la Implementación de UCSD Pascal , entre cuyos desarrolladores, la p en p-code se interpretó como pseudo más a menudo que portable , por lo que pseudocódigo 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 de los primeros compiladores que generaron código p fueron el compilador Pascal-P en 1973, de Kesav V. Nori, Urs Ammann, Kathleen Jensen, Hans-Heinrich Nägeli y Christian Jacobi, [3] y el compilador Pascal-S en 1975, de Niklaus Wirth .

Los programas que se han traducido a código p pueden interpretarse mediante un programa de software que emule el comportamiento de la CPU hipotética o traducirse al código de máquina de la CPU en la que se ejecutará el programa y luego se ejecutará. Si hay suficiente interés comercial, se puede construir una implementación de hardware de la especificación de la CPU (por ejemplo, Pascal MicroEngine o una versión de un procesador Java ).

Beneficios y debilidades de implementar código p

En comparación con la traducción directa a código de máquina nativo , 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) ofrece varias ventajas.

Una de las desventajas importantes del código p es la velocidad de ejecución, que a veces se puede solucionar mediante la compilación justo a tiempo . El código P suele ser también más fácil de aplicar ingeniería inversa que el código nativo.

Implementaciones de código p

A principios de la década de 1980, al menos dos sistemas operativos lograron independencia de la máquina mediante el uso extensivo del código p. El Business Operating System (BOS) era un sistema operativo multiplataforma diseñado para ejecutar programas de código p exclusivamente. El UCSD p-System , desarrollado en la Universidad de California, San Diego, era un sistema operativo autocompilador y autohospedado [ se necesita aclaración ] 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 implementaciones de lenguajes como Python , Microsoft P-Code en Visual Basic y Java bytecode en Java . [4] [ verificación fallida ]

El lenguaje Go utiliza un ensamblado genérico y portátil como una forma de código p, implementado por Ken Thompson como una extensión del trabajo en Plan 9 de Bell Labs . A diferencia del código de bytes de Common Language Runtime (CLR) o del código de bytes de JVM, no existe una especificación estable y las herramientas de compilación de Go no emiten un formato de código de bytes para utilizarlo más adelante. El ensamblador de Go utiliza el lenguaje ensamblador genérico como representación intermedia , y los ejecutables de Go son archivos binarios vinculados estáticamente específicos de la máquina . [5]

Máquina p de UCSD

Arquitectura

Como muchas otras máquinas de código p, la UCSD p-Machine 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 nuevamente en la pila. Por lo tanto, la addinstrucción reemplaza los dos elementos superiores de la pila con su suma. Algunas instrucciones requieren un argumento inmediato. Al igual que Pascal, el código p está fuertemente tipado y admite tipos de datos booleano (b), carácter (c), entero (i), real (r), conjunto (s) y puntero (a) de forma nativa.

Algunas instrucciones sencillas:

Posada. Descripción de la pila de pila antes después adi i1 i2 i1+i2 sumar dos números enterosadr r1 r2 r1+r2 sumar dos realesposada i1 s1 b1 conjunto membresía; b1 = si i1 es miembro de s1ldi i1 i1 i1 carga constante enteramovimiento a1 a2 a2 movimientono b1 b1 -b1 negación booleana

Ambiente

De manera similar a una CPU de destino real, el p-System tiene solo una pila compartida por 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):

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 utilizada más baja) del montón. Cuando EP es mayor que 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 se ven así:

PE-> pila localSP->... lugareños ... parámetros ... dirección de remitente (PC anterior) EP anterior enlace dinámico (MP 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 sustantivo, masculino—

donde nespecifica 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 la pila anterior e inicializará el enlace EP, dinámico y estático anterior. Luego, la persona que llama calcula y envía cualquier parámetro para el procedimiento y luego emite

copa n, p

para llamar a un procedimiento de usuario ( nsiendo el número de parámetros, pla dirección del procedimiento). Esto guardará la PC en la celda de dirección del remitente y establecerá la dirección del procedimiento como la nueva PC.

Los procedimientos del usuario comienzan con las dos instrucciones.

ent 1, yo ent 2, j

El primero configura SP en MP + i, el segundo configura EP en SP + j. Básicamente i, especifica el espacio reservado para los 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.

El regreso a la persona que llama se logra mediante

retC

dando Cel tipo de retorno (i, r, c, b, a como arriba y p sin valor de retorno). El valor de retorno debe almacenarse previamente en la celda correspondiente. En todos los tipos excepto p, regresar dejará este valor en la pila.

En lugar de llamar a un procedimiento de usuario (taza), qse puede llamar a un procedimiento estándar con

cspq

Estos procedimientos estándar son procedimientos de Pascal como readln()( csp rln), sin()( csp sin), etc. Curiosamente, eof()en su lugar es una instrucción de Código p.

Máquina de ejemplo

Niklaus Wirth especificó una máquina de código p simple en el libro de 1976 Algoritmos + Estructuras de datos = Programas . La máquina tenía 3 registros: un contador de programa p , un registro base b y un registro superior de la pila t . Había 8 instrucciones:

  1. lit 0, a : carga constante a
  2. opr 0, a : ejecutar la operación a (13 operaciones: RETORNO, 5 funciones matemáticas y 7 funciones de comparación)
  3. lod l, a : cargar variable l , a
  4. sto l, a : almacenar variable l , a
  5. cal l, a : llamar al procedimiento a en el nivel l
  6. int 0, a : incrementa el registro t en un
  7. jmp 0, a : saltar a un
  8. jpc 0, a : salto condicional a [ 6]

Este es el código de la máquina, escrito en Pascal:

constante amax = 2047 ; {dirección máxima} levmax = 3 ; {profundidad máxima de anidamiento de bloques} cxmax = 200 ; {tamaño de la matriz de códigos}   escriba fct = ( lit , opr , lod , sto , cal , int , jmp , jpc ) ; instrucción = registro empaquetado f : fct ; l : 0 .. levmáx ; a : 0 .. amáx ; fin ;   código var : matriz [ 0 .. cxmax ] de instrucción ;    interpretación del procedimiento ;  tamaño de pila constante = 500 ;    var p , b , t : entero ; {registros de programa, base, topstack} i : instrucción ; {registro de instrucción} s : matriz [ 1 .. tamaño de pila ] de número entero ; {Almacén de datos}               función base ( l : entero ) : entero ; var b1 : número entero ; comenzar b1 := b ; {encontrar la base l niveles hacia abajo} mientras l > 0 comienza b1 : = s [ b1 ] ; l := l - 1 final ; base := b1 final {base} ;                               comenzar a escribir ( 'iniciar pl/0' ) ; t := 0 ; b := 1 ; pag := 0 ; s [ 1 ] := 0 ; s [ 2 ] := 0 ; s [ 3 ] := 0 ; repetir i := código [ p ] ; p := p + 1 ; con i hago el caso f de lit : comienza t := t + 1 ; s [ t ] := un final ; opr : caso a de {operador} 0 : comenzar {retorno} t := b - 1 ; p := s [ t + 3 ] ; b := s [ t + 2 ] ; fin ; 1 : s [ t ] : = -s [ t ] ; 2 : comienza t : = t - 1 ; s [ t ] := s [ t ] + s [ t + 1 ] fin ; 3 : comienza t : = t - 1 ; s [ t ] : = s [ t ] -s [ t + 1 ] fin ; 4 : comienza t : = t - 1 ; s [ t ] := s [ t ] * s [ t + 1 ] fin ;                                                                                                                         5 : comienza t : = t - 1 ; s [ t ] := s [ t ] div s [ t + 1 ] fin ; 6 : s [ t ] := ord ( impar ( s [ t ])) ; 8 : comienza t : = t - 1 ; s [ t ] := ord ( s [ t ] = s [ t + 1 ]) fin ; 9 : comienza t : = t - 1 ; s [ t ] := ord ( s [ t ] <> s [ t + 1 ]) fin ; 10 : comienza t : = t - 1 ; s [ t ] := ord ( s [ t ] < s [ t + 1 ]) fin ; 11 : comienza t : = t - 1 ; s [ t ] := ord ( s [ t ] >= s [ t + 1 ]) fin ; 12 : comienza t : = t - 1 ; s [ t ] := ord ( s [ t ] > s [ t + 1 ] ) fin ; 13 : comienza t : = t - 1 ; s [ t ] := ord ( s [ t ]                                                                                                        <= s [ t + 1 ]) fin ; fin ; lod : comenzar t := t + 1 ; s [ t ] := s [ base ( l ) + a ] final ; sto : comenzar s [ base ( l ) + a ] := s [ t ] ; writeln ( s [ t ]) ; t := t - 1 fin ; cal : comenzar {generar nueva marca de bloque} s [ t + 1 ] := base ( l ) ; s [ t + 2 ] := b ; s [ t + 3 ] := p ; segundo := t + 1 ; p := un final ; int : t := t + a ; jmp : p := a ; jpc : comienza si s [ t ] = 0 entonces p : = a ; t := t - 1 end end {con, caso} hasta p = 0 ; writeln ( 'fin pl/0' ) ; fin {interpretar} ;                                                                                            

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. [7] [ verificación fallida ]

Código P de Microsoft

P-Code es el nombre de varios de los lenguajes intermedios propietarios de Microsoft . Proporcionaron un formato binario alternativo al código de máquina . En varias ocasiones, Microsoft ha dicho que p-code es una abreviatura de código empaquetado [8] o pseudocódigo . [9]

El código p de Microsoft se utilizó en Visual C++ y Visual Basic . Al igual que otras implementaciones de código p, el código p de Microsoft permitió un ejecutable más compacto a expensas de una ejecución más lenta.

Otras implementaciones

Ver también

Referencias

  1. ^ Upton, Eben; Duntemann, Jeffrey; Roberts, Ralph; Mamtora, Tim; Everard, Ben (13 de septiembre de 2016). Aprender arquitectura de computadoras con Raspberry Pi. John Wiley e hijos. ISBN 978-1-119-18393-8.
  2. ^ Wirth, Niklaus ; Weber, Helmut (1966). "EULER: una generalización de ALGOL y su definición formal: Parte II". Comunicaciones de la ACM . 9 (2). Nueva York, EE.UU.: Asociación de Maquinaria de Computación (ACM): 89–99. doi : 10.1145/365170.365202 . S2CID  12124100.
  3. ^ 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).
  4. ^ "El sistema de código p".
  5. ^ Pike, Robert C. (2016). "El diseño del Go Assembler". YouTube (charla de conferencia). Archivado desde el original el 11 de diciembre de 2021 . Consultado el 25 de agosto de 2017 .
  6. ^ "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 . 2018-08-02.
  7. ^ Alpert, Donald (septiembre de 1979). Un intérprete de código P de Pascal para el Emmy de Stanford (PDF) (Reporte). Laboratorio de Sistemas Computacionales, Departamentos de Ingeniería Eléctrica y Ciencias de la Computación, Universidad de Stanford. Nota Técnica No. 164.
  8. ^ Padawer, Andy (abril de 1992). "Tecnología de código P de Microsoft". Red de desarrolladores de Microsoft . Archivado desde el original el 22 de febrero de 2001.
  9. ^ "Compilar su proyecto en código nativo". Documentación de Visual Studio 6.0 . 2007. Archivado desde el original el 27 de febrero de 2007.

Otras lecturas

enlaces externos