OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Среда, 04 Декабрь, 2024 00:03

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 5 ] 
Автор Сообщение
 Заголовок сообщения: как сделать объединения (юнионы)?
СообщениеДобавлено: Вторник, 08 Февраль, 2022 18:06 

Зарегистрирован: Понедельник, 11 Сентябрь, 2017 13:23
Сообщения: 1612
Хочу добавить в ЯОС юнионы. Соответственно, вопрос, как их организовать? Понятно, что они должны быть безопасными. Первая идея была такая:
Код:
тип объ = объединение(з1,з2);
тип з1 = запись (объ) перем а: цел32 кон;
тип з2 = запись (объ) перем а: цел64 кон;


Компилятор сначала разбирает тип "объ", запоминает, что это объединение, но не трогает список из его "аргументов". Получается просто запись с нулём полей. Далее от разбирает
типы з1 и з2 (они являются потомками типа "объ" и содержат, соответственно, поле а, но разного типа). Далее
компилятор возвращается к типу объ и определяет ему запас места, который не входит в состав потомков записи, но до которых всегда дополняется экземпляр объ. Запас определяется как максимальный размер из размеров з1 и з2, т.е. в объ всегда фактически поместится любой допустимый элемент объединения.

Далее в основном весь доступ происходит через обычные механизмы Оберона (т.е. WITH/просейТип и охрану типов), единственное, что пока неясно - это защита от подмены значения объединения в ситуации, когда кто-то уже
пользуется им.

Например, пусть уОбъ = укль на объ. Тогда Можно создать новый экземпляр объ на куче, заполнить его записью з1 и записать куда-нибудь в какую-нибудь переменную. Но потом внезапно делается присваивание уОбъ^ := экземпляр_з2 - и всё, система сломана.

Самое простое - это запретить такое присваивание, но кажется, что таким образом работать не будет - при всяческих обменах с Си, для которых, собственно и нужны такие объединения, наверняка принято переиспользовать экземпляры объединений, чтобы не выделять память при каждом вызове.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 10 Февраль, 2022 18:31 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 473
Среди Паскаль-производных языков понравилось решение в MSElang (разработчик известных в соответствующих кругах MSEgui/MSEide для Freepascal задумал свой вариант Паскаля, к сожалению, проект заглох со смертью автора):
https://gitlab.com/mseide-msegui/mselang/-/wikis/home/mselang_objects#variantpart
Цитата:
Variant part

After regular fields there can be a variant part where the variant items share the same memory. Managed types like strings and dynamic arrays are not allowed in variant part.
Examples:
Код:
type
 objty = object
  f1: int32;
  (f2: int32; f3: int32;);
  (f4: int32;);
 end;

f2 and f4 are allocated at the same memory address.

Managed-тиы в вариантной части недопустимы, мол для "системных" нужд ограничение приемлемо. Встречаются альтернативные приёмы, например, Pointer Ownership Model:
https://resources.sei.cmu.edu/asset_files/whitepaper/2013_019_001_55008.pdf

Это политика "владения" указателями, в частности для С/С++ - статический анализ кода (с ограничениями) для верификации работы со ссылками в программе, где предусмотрены правила и для "объединений". Так по мотивам, упрощённо, к примеру, при записи данных в "вариантное" поле f4 у объекта типа objty (согласно выдержке выше) поля f2 и f3 должны считаться далее невалидными, если предшествовала какая-то работа с ними и их тип данных управляемый (соответственно, при потребности должна быть выполнена явная или неявная установка в null или финализация и т.п.).

Можно ещё глянуть в сторону AdaCore. В тех краях несколько лет назад было активное обсуждение потенциальной модели указателей для SPARK, без сборщика мусора с соответствующим уровнем безопасности и потенциалом для верификации, включая и поддержку вариантных типов-записей (статейка выше -- по наводке с тамошних форумов). Не в курсе, как дела обстоят на сегодня. У AdaCore кроме Ada/SPARK есть ещё и экспериментальный язык-платформа ParaSail, где, вроде бы, уже отработана модель "владеющих" указателей, но есть существенные ограничения (кроме "владеющих" нужны и иные, "не владеющие" указатели).
В общем, полезно покопаться в "адских кругах"...


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 10 Февраль, 2022 19:28 

Зарегистрирован: Понедельник, 11 Сентябрь, 2017 13:23
Сообщения: 1612
Касаемо запрета на указатели, да, куча не порушится, но и сишную программу так, по-моему, нельзя портировать.

Цитата:
при записи данных в "вариантное" поле f4 у объекта типа objty (согласно выдержке выше) поля f2 и f3 должны считаться далее невалидными


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

За прошедшее время надумал такие варианты:

А. Данные разных типов на самом деле не пересекаются, т.е. объединение не экономит память. Соответственно, при присваивании нового типа можно даже не трогать все поля от старого типа, но лучше их обнулить, иначе будет утечка памяти по ссылкам с умерших полей. Вроде маразм, но для портирования программ из Си подходит. Не подходит только для случая, когда нужно целенаправленно подменить тип на другой и добиться этим какой-то цели. В таких случаях будем выбрасывать исключение и сделаем специальную операцию "переинтерпретации смысла", чтобы можно было в явном виде сказать, что мы записали один тип, а читаем другой. Тогда переводим программу, запускаем её, смотрим, где падает, и там, где это не ошибка, вставляем "переинтерпретацию смысла".

Б. Данные пересекаются, но чтение и запись должны защищаться монитором. Это, ясно дело, чревато клинчами и вообще замедление. Перед чтением поля налагаем блокировку, проверяем, что тип соответствует ожидаемому, а потом только читаем. То же для записи. Самое плохое, что если запись участвует в каком-то объединении, то нужно _всегда_ работать с ней только через блокировку, даже для применений, не связанных с объединением. Поле "тип" просто так поменять нельзя, можно только вместе с данными. Сборщик мусора не должен вызываться во время блокировки.

В. Прятать реальное содержимое за ещё одним указателем на запись конкретного типа. При смене типа старое содержимое указателя бросаем, а новое выделяем на куче и переставляем указатель на него. Тогда копии данных иного типа не будут повреждены, но запись утратит целостность, т.е. её можно будет скопировать, потом сменить тип, и после этого копия перестанет быть равна оригиналу. И плюс нагрузка на сборщик мусора увеличивается.

Все три варианта, конечно, плохие.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 10 Февраль, 2022 19:29 

Зарегистрирован: Понедельник, 11 Сентябрь, 2017 13:23
Сообщения: 1612
Проблема ещё в том, что в АО общая память, поэтому любое рассуждение, включающее в себя "после X верно Y" требует применения блокировок, а задача применения блокировок резко всё усложняет.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 11 Февраль, 2022 20:17 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 473
Что-то, в целом, какие-то необычные, что ли, "объединения" вырисовываются...
budden писал(а):
Так можно, но нужно тогда отлеживать все ссылки глобально, чтобы можно было убедиться, что в этом месте нет каких-то копий ссылки на эту же запись, через которую ничего не подозревающие бедолаги получат доступ к старым полям.

А если ещё и правила сформулировать на манер адовского SPARK насчёт выявления и запрета "модифицирующих" алиасов на объекты, то в итоге отнюдь не компактным репорт о языке окажется... А, главное, нужно уметь, как SPARK...

Имхо, "приземленный" вариант -- ограниченные "разделяемые" поля по месту, указанные выше, без какого-то managed или только untagged. Это альтернативные представления одних и тех же данных, которые должны быть доступны одновременно. Аналогичные правила должны быть и для директивы аля absolutе для "биндинга" переменных и параметров процедур. Остальные "объединения" должны быть под защитой типа или под "тегом" в рамках стандартных структурных типов.
Среди Оберонов впечатлила идея переосмысления Паскалевских вариантных записей в виде "процедурно-параметрического полиморфизма":
https://forum.oberoncore.ru/viewtopic.php?f=155&t=6656&start=80#p113659
http://www.softcraft.ru/ppp/

Я не в курсе конкретики в реализации оригинального проекта, но предположительно можно даже на стеке объявлять/переопределять "вариантные" объекты в случае локальных типов (объявляемых с LOCAL -- расширение типов только в границах модуля-владельца и его модулей-расширений), на манер вариантных записей в Ada с дискриминантами.
Модель типов универсальная, гибкая (видится потенциал и для "дженериков"). Если не ошибаюсь, изначально проект развивался как расширение Оберона 2, но затем произошла трансформация в собственный диалект (O2M) -- было убрано исходное "расширение" типов-записей, т.к. функционал пересекается. А в случае с А2 модель типов пересекается ещё и с object (хотя здесь терм можно рассматривать лишь как алиас для объявления указателя на запись), и с enum, однако...


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 5 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2024, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB