The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]



Вариант для распечатки  
Пред. тема | След. тема 
Форум Разговоры, обсуждение новостей
Режим отображения отдельной подветви беседы [ Отслеживать ]

Оглавление

Выпуск языка программирования Rust 1.54, opennews (??), 29-Июл-21, (0) [смотреть все]

Сообщения [Сортировка по времени | RSS]


249. "Выпуск языка программирования Rust 1.54"  –1 +/
Сообщение от Хан (?), 30-Июл-21, 07:25 
В общем то Си разрешает функциям возращать структуры, но это просто офигительные дополнительные расходы на копирование, представь если структура большая и не помещается в регистры которых в x86 кот наплакал, поэтому компилятор может так использовать стек для возврата не сбрасывая его указатель перед выходом из функции и лишь потом сбросить его чтобы было время сохранить значения, а если и этого не хватает тогда в зависимости от компилятора могут быть различные грязные хуки но опять же двойным а то и тройным копированием...

Поэтому проще, быстрее и надежнее пробрасывать ссылку(адрес) на static память вызываемой функции в вызываемую и работать с ней как с обычной глобальной переменной

Ответить | Правка | Наверх | Cообщить модератору

285. "Выпуск языка программирования Rust 1.54"  +/
Сообщение от n00by (ok), 30-Июл-21, 09:35 
> В общем то Си разрешает функциям возращать структуры, но это просто офигительные
> дополнительные расходы на копирование

Не должно быть копирования. Достаточно зарезервировать стек перед вызовом.

Ответить | Правка | Наверх | Cообщить модератору

318. "Выпуск языка программирования Rust 1.54"  +/
Сообщение от Аноним (165), 30-Июл-21, 12:18 
Будет или нет копирование - зависит от оптимизатора и конкретного кода. Хинто: сравни x=f(x) и y=f(x)
Ответить | Правка | Наверх | Cообщить модератору

323. "Выпуск языка программирования Rust 1.54"  +1 +/
Сообщение от n00by (ok), 30-Июл-21, 13:08 
> сравни x=f(x) и y=f(x)

Нет разницы, пока мы говорим о возврате структуры из функции, а не подменяем предмет обсуждения на сравнение f(x,y) и f(y,x). Что бы избежать копирования, достаточно передать её адрес неявным аргументом.

Ответить | Правка | Наверх | Cообщить модератору

340. "Выпуск языка программирования Rust 1.54"  –1 +/
Сообщение от Хан (?), 30-Июл-21, 14:43 
Ну смотри стек функция не сбросила и сохранила в нем возвращаемое значение, но его же нужно как то обработать, а перед этим сохранить

Копирование 1
Из стека в регистры
Копирование 2
Из регистров в память

После чего сбросить стек

Ответить | Правка | К родителю #285 | Наверх | Cообщить модератору

348. "Выпуск языка программирования Rust 1.54"  +1 +/
Сообщение от n00by (ok), 30-Июл-21, 15:41 
Что значит "сбросить стек"?

Вы предполагаете, что структура при возврате из функции куда-то копируется. Значит место (приёмник) зарезервировано в памяти. Для чего указатель стека уменьшается на размер структуры (плюс выравнивание, но это не существенно). Происходит это при определении экземпляра. То есть до вызова функции.

struct foo r;
r = foo_construct();

Далее в теле функции определяется второй экземпляр структуры и как-либо инициализируется.

struct foo
foo_construct()
{
  return (struct foo) { /* ... */ };
}

Локальные переменные живут до выхода из функции. Соответственно, при выполнении return, по-Вашему, необходимо скопировать данные из локального для вызванной функции экземпляра в стек вызывающей.
Представьте, что один из членов структуры инициализирован указателем на неё. Что предпринять в данном случае? Как видим, копирование вообще решением не является.
С другой стороны, если копирование должно быть выполнено до выхода из функции -- значит адрес приёмника каким-то образом в теле функции известен. А раз он известен, то незачем создавать локальную структуру, достаточно формировать результат непосредственно в стековом кадре вызывающей функции. На практике передаётся неявным аргументом указатель (как this в C++), либо функция-конструктор встраивается.

Ответить | Правка | Наверх | Cообщить модератору

370. "Выпуск языка программирования Rust 1.54"  +/
Сообщение от Хан (?), 30-Июл-21, 17:03 
Сбросить стек значит вернуть указатель стека в изначальное положение которое было до вызова функции(чтобы не получить переполнение стека)


... ну смотри ты говоришь что во время return локальные переменные копируются в стек вызываемой функции... только вот стек общий на всю программу(можешь себе представить стек разделяемой памятью фиксированного размера)


Отсюда ты и говоришь про некий адрес приемника... там адреса не нужны это или регистры или стек которые заранее известны

Локальной памяти не существует(она хранится в стеке), название неправильное, оно не отражает ее природу, в отличии от определения автоматической памяти

Ответить | Правка | Наверх | Cообщить модератору

371. "Выпуск языка программирования Rust 1.54"  +/
Сообщение от Хан (?), 30-Июл-21, 17:07 
*в стек вызывающей

Короче суть такова что стек один на всех, а не укаждого свой

Ответить | Правка | Наверх | Cообщить модератору

398. "Выпуск языка программирования Rust 1.54"  +/
Сообщение от n00by (ok), 30-Июл-21, 18:36 
> Сбросить стек значит вернуть указатель стека в изначальное положение которое было до
> вызова функции(чтобы не получить переполнение стека)

"Восстановить" вместо "сбросить" было бы понятнее. Вернуть значение указателя нужно, что бы можно было дальше обращаться к своим локальным переменным. А то до переполнения дело не дойдёт.)

Единственно что, в зависимости от конвенции вызова, аргументы (если таковые были переданы через стек) могут быть оставлены на стеке (cdecl) или сняты вызывающей стороной (ctdcall). То есть при выходе из подпрограммы вершине стека не обязательно сразу же вернётся прежнее значение.

> ... ну смотри ты говоришь что во время return локальные переменные копируются
> в стек вызываемой функции...

Я говорю, что копирование вообще неправильно (почему -- подробнее можно почитать про глубокое копирование в С++). Но если бы оно было, то там ему самое место.

> только вот стек общий на всю программу(можешь
> себе представить стек разделяемой памятью фиксированного размера)

Стек общий, но у меня говорится о стековых кадрах. То есть об областях стека, где подпрограммы хранят свои локальные переменные. Дословно: достаточно формировать результат непосредственно в стековом кадре вызывающей функции.

По поводу разделяемой памяти - в моём понимании это страницы ОЗУ, которые принадлежат различным адресным пространствам (процессам). Стека в такой памяти быть не должно.

> Отсюда ты и говоришь про некий адрес приемника... там адреса не нужны
> это или регистры или стек которые заранее известны

Если возвращающая структуру функция (назовём её конструктором) вызывается из одного места, тогда строение стекового кадра вызывающей стороны действительно известно и однозначно, можно не передавать адрес для сохранения результата. Но в таком случае конструктор скорее всего окажется встроен (inline).

Если же вызывается из разных мест, или для массива структур, то придётся передавать адрес конструктору. И этот же адрес потребовался бы, если бы пришлось копировать структуры.

> Локальной памяти не существует(она хранится в стеке), название неправильное, оно не отражает
> ее природу, в отличии от определения автоматической памяти

Как раз вместо "автоматической памяти" в стандарте языка Си определено время жизни объектов (аutomatic storage duration). И опять же, у меня "локальные переменные". Кадр стека локален для каждого вхождения в подпрограмму, поскольку обращение к нему происходит относительно регистра стека.

> Короче суть такова что стек один на всех, а не укаждого свой

Вот именно. Потому, предприняв меры (передав указатель на место под результат), можно создавать структуру сразу в нужном месте и без копирования.

Ответить | Правка | К родителю #370 | Наверх | Cообщить модератору

428. "Выпуск языка программирования Rust 1.54"  +/
Сообщение от Хан (?), 30-Июл-21, 19:52 
Ты умный чел сразу видно.. но пиши чут чут попроще тип без такого формализма читать сложно...

Указатель стека нужно возвращать/сбрасывать дабы он не вышел за границы стека, ведь проверки границ стека как и массива не предусмотрено, разве что проц выкинет исключение на стек и Ояс завершит программу в отличии от массива

Спор насчет локальных или автоматических переменных ниочем, это же логично что с вызовом подпрограммы формируется ее стековый фрейм, а фрейм вызывающей не очищается так как она не завершена

Ясно что можно передавать структуру по указателю, мы же говорили про накладные расходы при передаче по значению

Насчет конструктуров и стековых фреймов чет не понял...

Ответить | Правка | Наверх | Cообщить модератору

434. "Выпуск языка программирования Rust 1.54"  +/
Сообщение от Хан (?), 30-Июл-21, 20:10 
С друго стороны такие хитроумные манипуляции похожи на костыль из разряда передать массив(до 8 байт) запаковать в long и вернуть по значению а потом распаковать снова в массив
Ответить | Правка | Наверх | Cообщить модератору

503. "Выпуск языка программирования Rust 1.54"  +/
Сообщение от n00by (ok), 31-Июл-21, 08:14 
> Ты умный чел сразу видно.. но пиши чут чут попроще тип без
> такого формализма читать сложно...

Короче пушим дворды и зовём функу потом попаем. Это называется сидекл. В стдкол функа сама попает ретн. А в фастколе параметры в регистрах. :)

> Указатель стека нужно возвращать/сбрасывать дабы он не вышел за границы стека, ведь
> проверки границ стека как и массива не предусмотрено, разве что проц
> выкинет исключение на стек и Ояс завершит программу в отличии от
> массива

Верно. Но это не главное. Допустим, перед вызовом подпрограммы по адресу [rsp - 8] что-то сохранили. Подпрограмма изменила указатель стека, отработала, произошёл возврат. В rsp другое значение, и по [rsp - 8] прочитали мусор. Так до переполнения дело не дойдёт.

> Спор насчет локальных или автоматических переменных ниочем, это же логично что с
> вызовом подпрограммы формируется ее стековый фрейм, а фрейм вызывающей не очищается
> так как она не завершена

Так я и не спорю.

> Ясно что можно передавать структуру по указателю, мы же говорили про накладные
> расходы при передаче по значению

Я говорю только по поводу возврата структур https://www.opennet.ru/openforum/vsluhforumID3/124921.html#249
то есть отвечал вот на это:
> В общем то Си разрешает функциям возращать структуры, но это просто офигительные
> дополнительные расходы на копирование

С передачей всё верно. Если вызываемая функция меняет переданный аргумент и эти изменения не нужны вызывающей стороне, приходится создавать копию. Это дополнительные расходы, но без них запортится оригинал. Иначе передаём по указателю (константной ссылке в С++).

При возврате нет смысла создавать копию.

> Насчет конструктуров и стековых фреймов чет не понял...

Конструктором я назвал функцию, которая возвращает структуру, что бы меньше писать.

Про фреймы просто надо подумать, как в ассемблере будет выглядеть сишный псевдокод из исходного объяснения https://www.opennet.ru/openforum/vsluhforumID3/124921.html#348

Вот как оно описано в "System V Application Binary Interface AMD64 Architecture Processor Supplement"

The returning of values is done according to the following algorithm:

2. If the type has class MEMORY, then the caller provides space for the return
value and passes the address of this storage in %rdi as if it were the first
argument to the function. In effect, this address becomes a “hidden” first ar-
gument. This storage must not overlap any data visible to the callee through
other names than this argument.
On return %rax will contain the address that has been passed in by the
caller in %rdi.

Ответить | Правка | К родителю #428 | Наверх | Cообщить модератору

394. "Выпуск языка программирования Rust 1.54"  +/
Сообщение от Хан (?), 30-Июл-21, 18:16 
Локальные(автоматические) переменные могут и после выхода из функции, до тех пор пока не сбросится стек, это как раз случай возврата большой структуры для которой не хватает регистров
Ответить | Правка | К родителю #348 | Наверх | Cообщить модератору

402. "Выпуск языка программирования Rust 1.54"  +/
Сообщение от n00by (ok), 30-Июл-21, 18:42 
> Локальные(автоматические) переменные могут и после выхода из функции, до тех пор пока
> не сбросится стек, это как раз случай возврата большой структуры для
> которой не хватает регистров

Не стоит на это полагаться! Прерывание разрушит содержимое стека. System V x86-64 ABI гарантирует всего 128 байт Красной Зоны.

Ответить | Правка | Наверх | Cообщить модератору

414. "Выпуск языка программирования Rust 1.54"  +/
Сообщение от Хан (?), 30-Июл-21, 19:14 
Это уже особенности ОС как я понимаю....

Ответить | Правка | Наверх | Cообщить модератору

425. "Выпуск языка программирования Rust 1.54"  +/
Сообщение от n00by (ok), 30-Июл-21, 19:48 
Особенность ОС это наличие красной зоны, или переключение адресного пространства/стека в обработчике прерывания, или гарантированное отсутствие прерываний. В общем же случае данные за вершиной стека сразу невалидны. И ловить это дело не слишком просто, особенно, если о таком не знать, а под отладчиком оно не проявится. :)
Ответить | Правка | Наверх | Cообщить модератору

429. "Выпуск языка программирования Rust 1.54"  +/
Сообщение от Хан (?), 30-Июл-21, 19:53 
Скинь ссылку где это описано, я чет с этим не сталкивался
Ответить | Правка | Наверх | Cообщить модератору

504. "Выпуск языка программирования Rust 1.54"  +/
Сообщение от n00by (ok), 31-Июл-21, 08:26 
> Скинь ссылку где это описано, я чет с этим не сталкивался

Параграф 3.2.2 The Stack Frame

System V Application Binary Interface
AMD64 Architecture Processor Supplement
Draft Version 0.99.7

https://www.uclibc.org/docs/psABI-x86_64.pdf

Ответить | Правка | Наверх | Cообщить модератору

505. "Выпуск языка программирования Rust 1.54"  +/
Сообщение от n00by (ok), 31-Июл-21, 08:33 
Вот новее версия в исходниках https://gitlab.com/x86-psABIs/x86-64-ABI

Вот pdf версии 1.0 https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0...

Ответить | Правка | К родителю #429 | Наверх | Cообщить модератору

Архив | Удалить

Рекомендовать для помещения в FAQ | Индекс форумов | Темы | Пред. тема | След. тема




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру