Можно ли сгенерировать функции ansi C с информацией о типе для движущейся реализации G C? - PullRequest
1 голос
/ 07 мая 2020

Мне интересно, какие существуют методы для добавления информации о типе к сгенерированным C методам. Я переношу язык программирования более высокого уровня на C и хочу добавить движущийся сборщик мусора. Однако для этого мне нужны переменные метода, чтобы иметь информацию о типе, иначе я мог бы изменить примитивное значение, которое выглядит как указатель.

Очевидным подходом было бы инкапсулировать все (примитивные и непримитивные) переменные в структура, которая имеет дополнительную (перечисляемую) переменную для ввода информации, однако это приведет к накладным расходам памяти и производительности, транспилированный код предназначен именно для встроенных платформ. Если бы я согласился с накладными расходами памяти, очевидным вариантом было бы использовать дескриптор кучи для всех объектов, и тогда я мог бы свободно перемещать блоки кучи. Однако мне интересно, есть ли более эффективный лучший подход.

Я придумал потенциальное решение, а именно: предварительно объявить и сгруппировать переменные в зависимости от того, примитивны они или нет (я могу сделать это в transpiler) и добавьте переменную смещения к каждому методу в конце (мне нужно иметь возможность точно найти ее при сканировании области стека), которая сообщает мне, где начинаются непримитивные переменные и где они заканчиваются, поэтому я могу только отсканируйте те. Это означает, что каждый метод будет использовать дополнительную 16/32-битную (в зависимости от архитектуры) память, однако это все равно должно быть более эффективным с точки зрения памяти, чем подход дескриптора кучи.

Пример:

void my_func() {
  int i = 5;
  int z = 3;
  bool b = false;
  void* person;
  void* person_info = ...;
  .... // logic
  volatile int offset = 0x034;
}
• 1009 Могу ли я заставить компилятор поместить некоторые данные в кадр стека метода (используя volatile)? Могу ли я точно найти смещение при сканировании стека?

Я бы хотел избежать сборки, чтобы этот подход мог работать (по умолчанию) на нескольких платформах, однако я открыты для методов, даже если они включают сборку (если они надежны).

1 Ответ

4 голосов
/ 07 мая 2020

Информация о вводе могла быть как-то закодирована в имени C функции; это делается C ++ и другими реализациями и называется name mangling .

Фактически, вы можете решить, поскольку весь ваш код C генерируется, принять другое соглашение: генерировать long C идентификаторов, которые являются практически уникальными и своего рода случайными для всей программы, например, tiziw_7oa7eIzzcxv03TmmZ, и хранят свою информацию о типе в другом месте (например, в некоторой базе данных). На Linux такой подход удобен как для libbacktrace , так и для dlsym (3) + dladdr (3) (и, конечно, nm ( 1) или readelf (1) или gdb (1) ), поэтому используется в обоих проектах bismon и RefPerSys .

Информация о вводе практически привязана к соглашениям о вызовах и ABI s. Например, x86-64 ABI для Linux предписывает разные регистры процессора для передачи с плавающей запятой или указателей.

Прочтите руководство Сборка мусора или хотя бы P.Wilson Однопроцессорные методы сборки мусора опрос. Вы можете решить использовать целые числа с тегами вместо их упаковки, и вы можете решить использовать консервативное G C (например, G C Бёма) вместо точного. В моем старом проекте G CC MELT я создал код C или C ++ для генерального копирования G C. Подобные методы используются как в Bismon , так и в RefPerSys .

Поскольку вы выполняете перенос в C, рассмотрите также альтернативы, такие как libgccjit или LLVM . Посмотрите на libjit и asmjit .

Изучите также реализацию других транспиляторов (компиляторы для C), включая Chicken / Scheme и Bigloo .

Может ли компилятор G CC изменить порядок переменных в соответствии с тем, как они объявлены в исходном коде?

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

Могу ли я заставить компилятор поместить некоторые данные в кадр стека метода (используя volatile)?

Лучше сгенерировать одну struct переменную, содержащую все переменные вашего языка, и оставить оптимизацию компилятору. Вы будете удивлены (см. этот черновик отчета).

Могу ли я точно определить смещение при сканировании стопки?

Это самый сложно, и зависит много от оптимизаций компилятора (например, если вы запускаете gcc с -O1 или -O3 на сгенерированном коде C; в некоторых случаи недавнего G CC -eg G CC 9 или G CC 10 на x86-64 для Linux - может tail-call optimizations; проверьте, скомпилировав с помощью gcc -O3 -S -fverbose-asm, а затем заглянув в созданный код ассемблера). Если вы согласны с некоторыми хитростями c, специфичными для небольшого целевого процессора и компилятора, это выполнимо. Изучите реализацию компилятора Ocaml .

Отправьте мне (на basile@starynkevitch.net) электронное письмо для обсуждения. Пожалуйста, укажите в нем URL-адрес вашего вопроса.

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

Если у вас есть исключения в вашем языке, будьте очень осторожны. Вы можете с большой осторожностью генерировать звонки на longjmp.

См., Конечно, этот ответ мой.

С помощью методов транспиляции зло в подробнее

На Linux (конкретно!) см. также мою manydl. c программу. Он демонстрирует, что на ноутбуке Linux x86-64 вы можете на практике сгенерировать сотни тысяч dlopen (3) -ed плагинов . Прочтите тогда Как писать разделяемые библиотеки

Изучите также реализацию SBCL и GNU Prolog , по крайней мере для вдохновения.

PS. Мечта о полностью независимом от архитектуры и операционной системе транспилере - это иллюзия.

...