stringtranslate.com

Машина P-кода

В программировании на компьютере машина P-кода ( переносная машина кода [1] ) — это виртуальная машина, предназначенная для выполнения P-кода, языка ассемблера или машинного кода гипотетического центрального процессора (ЦП). Термин «машина P-кода» применяется в общем смысле ко всем таким машинам (таким как виртуальная машина Java (JVM) и предварительно скомпилированный код MATLAB ), а также к конкретным реализациям, использующим эти машины. Одним из наиболее заметных применений машин P-кода является P-машина системы Pascal-P . Разработчики реализации Pascal UCSD в этой системе истолковывали 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-кода следует двухэтапному подходу, включающему перевод в P-код и выполнение путем интерпретации или оперативной компиляции (JIT) через машину P-кода.

Такое разделение позволяет отделить разработку интерпретатора P-кода от базового компилятора машинного кода, который должен учитывать машинно-зависимое поведение при генерации своего байт-кода . Таким образом, интерпретатор P-кода также может быть реализован быстрее, а возможность интерпретировать код во время выполнения позволяет проводить дополнительные проверки во время выполнения , которые могут быть недоступны в машинном коде. Кроме того, поскольку P-код основан на идеальной виртуальной машине, программа P-кода часто может быть меньше той же программы, переведенной в машинный код. И наоборот, двухэтапная интерпретация программы на основе P-кода приводит к более медленной скорости выполнения, хотя иногда это можно решить с помощью компиляции just-in-time , а ее более простую структуру легче реверсировать, чем машинный код.

Реализации 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.

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

ент 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-код — это название нескольких фирменных промежуточных языков Microsoft . Они предоставили альтернативный двоичный формат машинному коду . В разное время Microsoft заявляла, что P-код — это сокращение от упакованного кода [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.

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

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