Сравнивайте с английским: нажмите на абзац — оригинал откроется в окне. Кнопка EN под абзацем показывает его прямо в тексте.
Содержание
Введение
В компьютерном программировании, тханк — это подпрограмма, используемая для внедрения вычисления в другую подпрограмму. Тханки в основном используются для отсрочки вычисления до тех пор, пока не потребуется его результат, или для вставки операций в начало или конец другой подпрограммы. Они также широко применяются при генерации кода компилятором и в модульном программировании. Термин возник как шутливая, неправильная форма глагола "думать". Он отсылает к первоначальному использованию тханков в компиляторах ALGOL 60, которым требовался специальный анализ (обдумывание) для определения, какую рутину следует сгенерировать.
Computing term
In computer programming, a thunk is a subroutine used to inject a calculation into another subroutine. Thunks are primarily used to delay a calculation until its result is needed, or to insert operations at the beginning or end of the other subroutine. They have many other applications in compiler code generation and modular programming. The term originated as a whimsical irregular form of the verb think. It refers to the original use of thunks in ALGOL 60 compilers, which required special analysis (thought) to determine what type of routine to generate.
Предыстория
В первые годы исследований компиляторов проводились широкие эксперименты с различными стратегиями вычисления. Ключевым вопросом было то, как компилировать вызов подпрограммы, если аргументы могут быть произвольными математическими выражениями, а не константами. Один из подходов, известный как "вызов по значению", вычисляет все аргументы перед вызовом и затем передает полученные значения в подпрограмму. В конкурирующем подходе "вызов по имени" подпрограмма получает невычисленное выражение аргумента и должна самостоятельно его вычислить. Простая реализация "вызова по имени" может подставлять код выражения аргумента вместо каждого вхождения соответствующего параметра в подпрограмму, но это может привести к созданию нескольких версий подпрограммы и множеству копий кода выражения. Для улучшения компилятор может генерировать вспомогательную подпрограмму, называемую thunk, которая вычисляет значение аргумента. Адрес и окружение этой вспомогательной подпрограммы затем передаются исходной подпрограмме вместо исходного аргумента, где она может быть вызвана столько раз, сколько необходимо. Питер Ингерман впервые описал thunk в контексте языка программирования ALGOL 60, который поддерживает вычисление по имени.
The early years of compiler research saw broad experimentation with different evaluation strategies. A key question was how to compile a subroutine call if the arguments can be arbitrary mathematical expressions rather than constants. One approach, known as "call by value", calculates all of the arguments before the call and then passes the resulting values to the subroutine. In the rival "call by name" approach, the subroutine receives the unevaluated argument expression and must evaluate it. A simple implementation of "call by name" might substitute the code of an argument expression for each appearance of the corresponding parameter in the subroutine, but this can produce multiple versions of the subroutine and multiple copies of the expression code. As an improvement, the compiler can generate a helper subroutine, called a thunk, that calculates the value of the argument. The address and environment of this helper subroutine are then passed to the original subroutine in place of the original argument, where it can be called as many times as needed. Peter Ingerman first described thunks in reference to the ALGOL 60 programming language, which supports call by name evaluation.
Числовые расчеты, требующие оценки в нескольких точках
В рутинных вычислениях, таких как интегрирование, требуется вычислять выражение в нескольких точках. В языках, не поддерживающих замыкания или передачу параметров по значению, для этого использовался вызов по имени.
Routines for computations such as integration need to calculate an expression at multiple points. Call by name was used for this purpose in languages that didn't support closures or procedure parameters.
Совместимость
Thunks широко используются для обеспечения взаимодействия между программными модулями, чьи процедуры не могут вызывать друг друга напрямую. Это может происходить из-за различных соглашений о вызовах, выполнения в разных режимах процессора или адресных пространствах, или, по крайней мере, одна из них выполняется в виртуальной машине. Компилятор (или другой инструмент) может решить эту проблему, генерируя thunk, который автоматизирует дополнительные шаги, необходимые для вызова целевой процедуры, будь то преобразование аргументов, их копирование в другое место или переключение режима процессора. Успешный thunk минимизирует дополнительную работу, которую должен выполнить вызывающий код по сравнению с обычным вызовом. Большая часть литературы, посвященная thunks для взаимодействия, относится к различным платформам Wintel, включая MS DOS, OS/2, Windows и .NET, а также к переходу от 16-битной к 32-битной адресации памяти. По мере перехода клиентов с одной платформы на другую, thunks были необходимы для поддержки устаревшего программного обеспечения, написанного для старых платформ. Переход от 32-битного кода к 64-битному на x86 также использует форму thunking (WoW64). Однако, поскольку адресное пространство x86-64 больше, чем доступное для 32-битного кода, старый механизм "универсального thunk" нельзя использовать для вызова 64-битного кода из 32-битного кода. Единственным случаем вызова 64-битного кода из 32-битного является thunking Windows API в WoW64 для 32-битной версии.
Thunks have been widely used to provide interoperability between software modules whose routines cannot call each other directly. This may occur because the routines have different calling conventions, run in different CPU modes or address spaces, or at least one runs in a virtual machine. A compiler (or other tool) can solve this problem by generating a thunk that automates the additional steps needed to call the target routine, whether that is transforming arguments, copying them to another location, or switching the CPU mode. A successful thunk minimizes the extra work the caller must do compared to a normal call. Much of the literature on interoperability thunks relates to various Wintel platforms, including MS DOS, OS/2, Windows and NET, and to the transition from 16 bit to 32 bit memory addressing. As customers have migrated from one platform to another, thunks have been essential to support legacy software written for the older platforms. The transition from 32 bit to 64 bit code on x86 also uses a form of thunking (WoW64). However, because the x86 64 address space is larger than the one available to 32 bit code, the old "generic thunk" mechanism could not be used to call 64 bit code from 32 bit code. The only case of 32 bit code calling 64 bit code is in the WoW64's thunking of Windows APIs to 32 bit.
Наложения и динамические связи
На системах, не имеющих аппаратной поддержки автоматической виртуальной памяти, thunks могут реализовать ограниченную форму виртуальной памяти, известную как наложения. При использовании наложений разработчик разделяет код программы на сегменты, которые можно загружать и выгружать независимо, и определяет точки входа в каждый сегмент. Сегмент, вызывающий другой сегмент, должен делать это косвенно, через таблицу переходов. Когда сегмент находится в памяти, записи в его таблице переходов осуществляют переход внутрь этого сегмента. Когда сегмент выгружается, его записи заменяются "thunks перезагрузки", которые могут загрузить его по требованию. Аналогично, системы, динамически связывающие модули программы во время выполнения, могут использовать thunks для соединения этих модулей. Каждый модуль может вызывать другие через таблицу thunks, которую компоновщик заполняет при загрузке модуля. Таким образом, модули могут взаимодействовать, не имея предварительных знаний об их расположении в памяти.
On systems that lack automatic virtual memory hardware, thunks can implement a limited form of virtual memory known as overlays. With overlays, a developer divides a program's code into segments that can be loaded and unloaded independently, and identifies the entry points into each segment. A segment that calls into another segment must do so indirectly via a branch table. When a segment is in memory, its branch table entries jump into the segment. When a segment is unloaded, its entries are replaced with "reload thunks" that can reload it on demand. Similarly, systems that dynamically link modules of a program together at run time can use thunks to connect the modules. Each module can call the others through a table of thunks that the linker fills in when it loads the module. This way the modules can interact without prior knowledge of where they are located in memory.