IPB
ЛогинПароль:

> Правила раздела!

1. Заголовок или название темы должно быть информативным !
2. Все тексты фрагментов программ должны помещаться в теги [code] ... [/code] или [code=pas] ... [/code].
3. Прежде чем задавать вопрос, см. "FAQ" и используйте ПОИСК !
4. НЕ используйте форум для личного общения!
5. Самое главное - это раздел теоретический, т.е. никаких задач и программ (за исключением небольших фрагментов) - для этого есть отдельный раздел!

 
 Ответить  Открыть новую тему 
> Реализация локальных процедур и лямбда-функций.
сообщение
Сообщение #1


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


Возьмём такой код и посмотрим, что будет делать компилятор.

function outer(i: integer): integer;

function inner(j: integer): integer;

function inner2(k: integer): integer;
begin
result:=i+j+k+1;
end;

begin
result := i+j+inner2(i);
end;

begin
i:=1;
result := i+inner(i);
end;


Внутренняя функция должна иметь какой-то доступ к параметрам внешней. А так как параметры внешней расположены на стеке, то они не имеют фиксированного адреса (т.к. может быть вызов f-g-h или f-h, и внутри h переенные могут быть расположены как сразу за переменными f, так и после переменных g). И их адрес даже не обязательно фиксирован относитель начала стека на момент вызова внутренней функции.
Поэтому внутренняя функция имеет потайной параметр - указатель на вершину стека на момент вызова внешней функции. Через него и происходит адресация к переменным внешней функции.
Кстати, именно из-за этого локальные функции в Д7 нельзя передавать никуда по указателю. В других языках либо введено понятие "ссылка на функцию", которые хранит указатель на допольнительные данные, либо вообще все указатели хранят доп.информацию, либо ещё как-то выкручиваются, не знаю, как.
Но мне стало интересно, а как происходит работа с внутренней внутренней функцией. Передаются ли в неё два параметра (на вершины стеков внешних функций), или как-то ещё.
Оказалось, что передаётся один параметр - указатель на локальные переменные первой внутренней функции. Чтобы получить доступ к внешним локальным переменным, делается двойное разыменование: сначала разываменовываем указатель на переменные первой внутренней, среди них находим указатель на переменные внешней и уже его разыменовываем.
Эффективность такого подхода меня очень пугает. Почему был выбран именно такой вариант вместо передачи двух указателей?

Однако компилятор Д7 таки проводит оптимизации! Если внутренняя функция не обращается к переменым внешней, то в неё не передается указатель на стек. Увы, это единственная замеченная мной оптимизация.

Можно было сделать и больше оптимизаций.
Например, если внутренняя функция не вызывается ни в каких других внутренних функциях, то для неё вершина стека фиксирована относительно вершины стека внешней, то есть указатель передавать не надо. Этой оптимизации в Д7 нету.
Или, например, если используются только несколько параметров внешней (не более двух), то передать по ссылке только их, а не весь блок локальных переменных (тут надо понимать, что "передача по ссылке" - это не обязательно передача указателя, это может быть и передача самого значения с копированием обратно, причём передача хоть в регистре, что уберёт ненужную возню с разыменованиями и двойными разыменованиями).

Ну и про локальные лямбды, передаваемые наружу, у меня тоже есть некоторые вопросы, но об этом я спрошу в следующий раз.


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 





- Текстовая версия 20.04.2024 2:23
500Gb HDD, 6Gb RAM, 2 Cores, 7 EUR в месяц — такие хостинги правда бывают
Связь с администрацией: bu_gen в домене octagram.name