Понял, что мне очень сильно не нравится пухлое представление самых частоупотребимых сущностей: коротких чисел и символов.
Я не проводил никаких исследований на эту тему, но что-то мне подсказывает, что весьма существенная часть реальных переменных, используемых в эмбеде - 16-битные. Размеры буферов, индексы внутри них, разрешение дисплеев, скорости перемещения и т.п., и т.д. - всё это чаще представимо в виде небольших чисел, высокая разрядность тут ни к чему, да и дорого. Кроме этого, существенная часть всяких рабочих переменных записывается в виде одно-, двух- и трёхбуквенных мнемоник, типа x, v1, lst и так далее. То есть имеет смысл подумать над максимально компактным представлением некоторых данных (сохранив, разумеется, возможность представления более крупных данных в неприкосновенности: 32- и 64-битные числа, равно как и ДлинныеИПонятныеИменаПеременных тоже имеют право быть!).
Хак относится к little-endian машинам минимум 32-битной разрядности. Для адаптации его к big-endian нужно поменять порядок полей в структурах.
Все данные и указатели оборачиваются в специальные структуры с тэгами, позволяющими определить вид содержимого.
N
31
30
29
28..24
23..16
15..8
7..0
CAR mnemonic
gc
cons
category
opt
data
data
data
When 0
working
Atomic
container
Atomic options
Misc.data
When 1
garbage
Cons cell
pointer
pointer>>3
CDR
t.b.d.
В том случае, если данные можно полностью уместить внутрь поля data одного такого регистра, представление данных получается таким:
N
31
30
29
28..24
23..0
|← 8 bits →|
CAR mnemonic
gc
cons
category
opt
data
0
0
0
options
Atomic container data
CDR
Not available; has no meaning; don't try to use it
В том случае, если данные можно полностью уместить внутрь ячейки (которая, по традиции, представляет собой пару указателей, но на самом деле не обязательно является парой именно УКАЗАТЕЛЕЙ (просто таков её размер)), представление данных получается немного иным. В поле CAR лежит некое краткое описание типа данных и, опционально, кусочек этих данных (возможно, какие-то служебные сведения), а в поле CDR лежит либо указатель (например, на C-style строку), либо какая-то иная нужная нам порция данных (например, 32-битное число):
N
31
30
29
28..24
23..16
15..0
CAR mnemonic
gc
cons
category
opt
flags
data
0
0
1
options
Atomic flags
Additional atomic data
CDR
Atom's data (also can be pointer with any align)
CONS-ячейка, с учётом этих оптимизаций, выглядит так:
N
31
30
29
28..24
23..16
15..8
7..0
CAR mnemonic
gc
cons
category
opt
data
0
1
0: container
options
Atomic container data
1: pointer
Pointer to CAR; shifted >> 3 (align 8)
CDR mnemonic
-
-
size
opt
data
0: container
options
Atomic container data
1: pointer
Pointer to CDR; shifted >> 3 (align 8)
Низкоуровневый код выглядит несколько странно, но однако же, простенький тяп-ляп тест даёт такой результат:
atomic cell; generic form; [retrieve-long-data, length 18]
atomic cell; short form; [symbol]
atomic container [a4]
В квадратных скобках - гипотетические имена символов. В первом случае имя не помещается ни в указатель, ни даже в ячейку, и хранится в куче как обычная C-строка (в атом же занесён указатель на эту строку). Во втором случае имя не помещается в указатель, но влезает в ячейку, в третьем случае имя полностью уместилось внутрь указателя. Для коротких имён экономия памяти получается весьма существенной, с лихвой окупающая пару дополнительных проверок нескольких битов.
Правильная организация структур данных - залог успеха.