stringtranslate.com

машина p-кода

В компьютерном программировании машина p-кода ( переносимая кодовая машина [1] ) — это виртуальная машина , предназначенная для выполнения p-кода ( языка ассемблера или машинного кода гипотетического центрального процессора (ЦП)). Этот термин применяется как в общем смысле ко всем таким машинам (таким как виртуальная машина Java (JVM) и предварительно скомпилированный код MATLAB ), так и к конкретным реализациям, наиболее известной из которых является p-машина системы Pascal-P , в частности реализация UCSD Pascal , среди разработчиков которой p в p-коде чаще трактовалось как псевдо, чем переносимый , таким образом, псевдокод означает инструкции для псевдомашины.

Хотя эта концепция была впервые реализована около 1966 года как O-код для Basic Combined Programming Language ( BCPL ) и P-код для языка Euler , [2] термин p -код впервые появился в начале 1970-х годов. Двумя ранними компиляторами, генерирующими p-код, были компилятор Pascal-P в 1973 году, созданный Кесавом В. Нори, Урсом Амманном, Кэтлин Йенсен, Хансом-Генрихом Нэгели и Кристианом Якоби, [3] и компилятор Pascal-S в 1975 году, созданный Никлаусом Виртом .

Программы, которые были переведены в p-код, могут быть либо интерпретированы программой, которая эмулирует поведение гипотетического ЦП, либо переведены в машинный код ЦП, на котором программа должна работать, а затем выполнены. Если есть достаточный коммерческий интерес, может быть построена аппаратная реализация спецификации ЦП (например, Pascal MicroEngine или версия процессора Java ).

Преимущества и недостатки внедрения p-кода

По сравнению с прямой трансляцией в машинный код , двухэтапный подход, включающий трансляцию в p-код и выполнение путем интерпретации или оперативной компиляции (JIT), дает несколько преимуществ.

Одним из существенных недостатков p-кода является скорость выполнения, которую иногда можно исправить с помощью Just-in-time компиляции . P-код часто также проще поддается обратному проектированию, чем нативный код.

Реализации p-кода

В начале 1980-х годов по крайней мере две операционные системы достигли машинной независимости посредством широкого использования p-кода. Business Operating System (BOS) была кроссплатформенной операционной системой, разработанной для запуска программ исключительно на p-коде. UCSD p-System , разработанная в Калифорнийском университете в Сан-Диего, была самокомпилирующейся и саморазмещающейся [ требуется разъяснение ] операционной системой на основе p-кода, оптимизированного для генерации языком Pascal .

В 1990-х годах перевод в p-код стал популярной стратегией для реализаций таких языков, как Python , Microsoft P-Code в Visual Basic и байт-код Java в Java .

Язык Go использует универсальную, переносимую сборку как форму p-кода, реализованную Кеном Томпсоном как расширение работы над Plan 9 из Bell Labs . В отличие от байт-кода Common Language Runtime (CLR) или байт-кода JVM, здесь нет стабильной спецификации, а инструменты сборки Go не выдают формат байт-кода для использования в более позднее время. Ассемблер Go использует универсальную сборку как промежуточное представление , а исполняемые файлы Go являются машинно-специфичными статически связанными двоичными файлами. [4]

UCSD p-машина

Архитектура

Как и многие другие машины p-кода, UCSD p-Machine является стековой машиной , что означает, что большинство инструкций берут свои операнды из стека и помещают результаты обратно в стек. Таким образом, addинструкция заменяет два верхних элемента стека их суммой. Несколько инструкций принимают немедленный аргумент. Как и Pascal, p-код строго типизирован , поддерживая логические (b), символьные (c), целые (i), вещественные (r), множества (s) и указатели (a) типы данных изначально.

Несколько простых инструкций:

Стек Инн. Описание стека до после adi i1 i2 i1+i2 сложить два целых числаadr r1 r2 r1+r2 сложить два реальных числаinn i1 s1 b1 установить членство; b1 = является ли i1 членом s1ldi i1 i1 i1 загрузить целую константуmov a1 a2 a2 ходне b1 b1 -b1 логическое отрицание

Среда

Подобно реальному целевому ЦП, p-System имеет только один стек, который совместно используется кадрами стека процедур (предоставляя адрес возврата и т. д.) и аргументами локальных инструкций. Три регистра машины указывают на стек (который растет вверх):

Также присутствует константная область, а ниже — куча, растущая вниз по направлению к стеку. Регистр NP (новый указатель) указывает на вершину (самый низкий используемый адрес) кучи. Когда EP становится больше NP, память машины исчерпывается.

Пятый регистр, PC, указывает на текущую инструкцию в области кода.

Вызов конвенции

Стековые фреймы выглядят так:

ЭП -> локальный стекСП -> ... местные жители ... параметры ... обратный адрес (предыдущий ПК) предыдущий EP динамическая ссылка (предыдущий MP) статическая ссылка (MP окружающей процедуры)MP -> возвращаемое значение функции

Последовательность вызова процедуры работает следующим образом: вызов начинается с

мст н

где nуказывает разницу в уровнях вложенности (помните, что Pascal поддерживает вложенные процедуры). Эта инструкция пометит стек , т.е. зарезервирует первые пять ячеек указанного выше стекового кадра и инициализирует предыдущую EP, динамическую и статическую ссылку. Затем вызывающий вычисляет и помещает любые параметры для процедуры, а затем выдает

чашка н, п

для вызова пользовательской процедуры ( nгде число параметров, pадрес процедуры). Это сохранит PC в ячейке обратного адреса и установит адрес процедуры как новый PC.

Пользовательские процедуры начинаются с двух инструкций

ent 1, я ent 2, j

Первый устанавливает SP в MP + i, второй устанавливает EP в SP + j. Таким iобразом, по сути, указывается пространство, зарезервированное для локальных переменных (плюс количество параметров плюс 5), и jуказывается количество записей, необходимых локально для стека. На этом этапе проверяется исчерпание памяти.

Возврат к вызывающему абоненту осуществляется через

ретС

с Cуказанием типа возвращаемого значения (i, r, c, b, a, как указано выше, и p для отсутствия возвращаемого значения). Возвращаемое значение должно быть предварительно сохранено в соответствующей ячейке. Для всех типов, кроме p, возврат оставит это значение в стеке.

Вместо вызова пользовательской процедуры (cup) qможно вызвать стандартную процедуру с помощью

csp д

Эти стандартные процедуры представляют собой процедуры Pascal, такие как readln()( csp rln), sin()( csp sin) и т. д. Характерной особенностью eof()является то, что вместо них используется инструкция p-Code.

Пример машины

Никлаус Вирт описал простую машину p-кода в книге 1976 года «Алгоритмы + Структуры данных = Программы» . Машина имела 3 регистра — счетчик программ p , базовый регистр b и регистр вершины стека t . Было 8 инструкций:

  1. lit 0, a : постоянная нагрузка a
  2. opr 0, a : выполнить операцию a (13 операций: RETURN, 5 математических функций и 7 функций сравнения)
  3. lod l, a : переменная нагрузки l , a
  4. sto l, a : сохранить переменную l , a
  5. cal l, a : вызов процедуры a на уровне l
  6. int 0, a : увеличить t-регистр на a
  7. jmp 0, a : перейти к
  8. jpc 0, a : условный переход к [ 5]

Это код машины, написанный на языке Паскаль:

const amax = 2047 ; {максимальный адрес} levmax = 3 ; {максимальная глубина вложенности блоков} cxmax = 200 ; {размер массива кода}   тип fct = ( lit , opr , lod , sto , cal , int , jmp , jpc ) ; инструкция = упакованная запись f : fct ; l : 0 .. levmax ; a : 0 .. amax ; конец ;   var code : массив [ 0 .. cxmax ] инструкций ;    процедура интерпретации ;  константный размер стека = 500 ;    var p , b , t : целое число ; {регистры программы, базы, верхнего стека} i : инструкция ; {регистр инструкции} s : массив [ 1 .. stacksize ] целых чисел ; {хранилище данных}               function base ( l : integer ) : integer ; var b1 : integer ; begin b1 := b ; {найти уровень base l вниз} while l > 0 do begin b1 := s [ b1 ] ; l := l - 1 end ; base := b1 end {base} ;                               begin writeln ( ' start 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 : начало t := t - 1 ; s [ t ] := s [ t ] + s [ t + 1 ] конец ; 3 : начало t := t - 1 ; s [ t ] := s [ t ] - s [ t + 1 ] конец ; 4 : начало t := t - 1 ; s [ t ] := s [ t ] * s [ t + 1 ] конец ;                                                                                                                         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 : начало t := t - 1 ; s [ t ] := ord ( s [ t ] >= s [ t + 1 ]) конец ; 12 : начало t := t - 1 ; s [ t ] := ord ( s [ t ] > s [ t + 1 ]) конец ; 13 : начало t := t - 1 ; s [ t ] := ord ( s [ t ]                                                                                                        <= s [ t + 1 ]) конец ; конец ; lod : begin t := t + 1 ; s [ t ] := s [ base ( l ) + a ] конец ; sto : begin s [ base ( l ) + a ] := s [ t ] ; writeln ( s [ t ]) ; t := t - 1 конец ; cal : begin {сгенерировать новую метку блока} s [ t + 1 ] := base ( l ) ; s [ t + 2 ] := b ; s [ t + 3 ] := p ; b := t + 1 ; p := a конец ; 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} ;                                                                                            

Эта машина использовалась для запуска PL/0 Вирта , компилятора подмножества Паскаля, используемого для обучения разработке компиляторов. [6] [ проверка не удалась ]

Microsoft P-код

P-Code — это название нескольких фирменных промежуточных языков Microsoft . Они предоставили альтернативный двоичный формат машинному коду . В разное время Microsoft заявляла, что p-code — это сокращение от упакованного кода [7] или псевдокода [8] .

Microsoft p-code использовался в Visual C++ и Visual Basic . Как и другие реализации p-code, Microsoft p-code позволял создавать более компактный исполняемый файл за счет более медленного выполнения.

Другие реализации

Смотрите также

Ссылки

  1. ^ Аптон, Эбен; Дантеманн, Джеффри; Робертс, Ральф; Мамтора, Тим; Эверард, Бен (2016-09-13). Изучение архитектуры компьютера с Raspberry Pi. John Wiley & Sons. ISBN 978-1-119-18393-8.
  2. ^ Вирт, Никлаус ; Вебер, Хельмут (1966). «ЭЙЛЕР: обобщение АЛГОЛА и его формальное определение: Часть II». Сообщения ACM . 9 (2). Нью-Йорк, США: Ассоциация вычислительной техники (ACM): 89–99. doi : 10.1145/365170.365202 . S2CID  12124100.
  3. ^ Нори, Кесав В.; Амманн, Урс; Дженсен, Кэтлин; Нэгели, Ганс-Генрих; Якоби, Кристиан (1975). Замечания по реализации компилятора Pascal P. Цюрих, Швейцария: Eidgenössische Technische Hochschule (ETH).
  4. ^ Пайк, Роберт С. (2016). «Проектирование ассемблера Go». YouTube (выступление на конференции). Архивировано из оригинала 11.12.2021 . Получено 25.08.2017 .
  5. ^ "Архивы категории: Wirth - Euler - Разработано Никлаусом Виртом и Хельмутом Вебером". Pascal для малых машин - языки Wirth, Pascal, UCSD, Turbo, Delphi, Freepascal, Oberon . 2018-08-02.
  6. ^ Альперт, Дональд (сентябрь 1979 г.). Интерпретатор P-кода Pascal для Стэнфордской премии Emmy (PDF) (Отчет). Лаборатория компьютерных систем, кафедры электротехники и компьютерных наук, Стэнфордский университет. Техническое примечание № 164.
  7. ^ Падавер, Энди (апрель 1992 г.). "Microsoft P-Code Technology". Microsoft Developer Network . Архивировано из оригинала 2001-02-22.
  8. ^ "Компиляция вашего проекта в машинный код". Документация Visual Studio 6.0 . 2007. Архивировано из оригинала 27.02.2007.

Дальнейшее чтение

Внешние ссылки