xref: /aosp_15_r20/external/emboss/doc/design_docs/default_values.md (revision 99e0aae7469b87d12f0ad23e61142c2d74c1ef70)
1# Design Sketch: Initializer Values for Fields
2
3## Motivation
4
5It is often useful to initialize a structure to some "un-set" value before
6starting to modify it.  For many structures, a simple `memset(buffer, sizeof
7*buffer, 0)` suffices, but other structures require specific values at specific
8locations, which are tedious to write out in user code.
9
10This design proposes two main elements:
11
121.  A way to specify initializer values for specific fields.
132.  A new feature in the generated C++ code to set the memory underlying a view
14    to those initializer values, or to 0 if no initializer was specified.
15
16
17## Initializer Value Syntax
18
19### Attribute
20
21The most straightforward option is to use the existing attribute syntax:
22
23    struct Foo:
24      0 [+2]  UInt  bar
25        [initialize_to: 7]
26
27The exact name TBD, but it should be somewhat visually distinct from the
28existing `$default` keyword for attributes, which specifies that an attribute
29should be used for all descendants of the current node, unless overridden:
30
31    [$default byte_order = "LittleEndian"]
32
33
34### New Syntax
35
36Other options might add new syntax.
37
38
39#### Suffix `= value`
40
41Suffix `= value` looks somewhat similar to the "initialize on construction"
42syntax in languages like C++:
43
44    struct Foo:
45      0 [+2]  UInt  bar = 7
46
47    class Foo {
48      int bar = 7;
49    };
50
51However, it also looks somewhat confusingly similar to the field number
52specifiers in Proto:
53
54    message Foo {
55      optional uint32 bar = 7;
56    }
57
58
59#### Something Else?
60
61It is difficult to come up with a syntax that is clear and concise, especially
62to a reader who is not particularly familiar with Emboss:
63
64    struct Foo:
65      0 [+2]  UInt  bar := 7
66
67    struct Foo:
68      0 [+2]  UInt  bar [7]
69
70    struct Foo:
71      0 [+2]  UInt [initialize to 7]  bar
72
73Feel free to propose other options.
74
75
76## `Initialize()` Method
77
78Emboss *views* do not own their backing storage: creating a view does not
79allocate memory, it just provides a structured, well, view of existing bytes.
80This means that there is not a natural place to automatically initialize a
81struct, the way that there is for an object in a typical programming language.
82
83Instead, I propose adding an `Initialize()` method (name TBD) to each view,
84which can be called to explicitly initialize the underlying memory.
85
86For `external` (`UInt`, `Bcd`, etc.) and `enum` views, `Initialize()` should
87just set the initializer value specified in the `.emb` file, or `0` if none was
88specified.
89
90For structure views (`struct` and `bits`), `Initialize()` should set the
91initializer values of each of their fields, recursively.
92
93TBD whether `Initialize()` should also zero out any bytes that are not part
94of any concrete field.
95
96
97## Implementation Notes
98
99This is a moderately complex change, touching both the front end and C++ back
100end of the compiler, as well as the C++ runtime.
101
102
103### Front End Changes
104
105On the front end, adding a new attribute is definitely the most straightforward
106change: mostly just adding the new attribute to `attributes.py`, and updating a
107few things in `dependency_checker.py`, `expression_bounds.py`, and possibly
108`constraints.py` to inspect the new attribute.
109
110
111### C++ Back End Changes
112
113On the back end, there are a couple of implementation strategies.
114
115The easiest strategy is to generate an `Initialize()` method on each structure
116type that recursively calls `Initialize()` on each field within the structure
117(in dependency-safe order, similar to `WriteToTextStream()`).
118
119An alternate strategy would be to generate an "empty image" for each structure,
120and have `Initialize()` `memcpy()` the image into its backing storage.  This
121seems like it would be faster at runtime, but may bloat binary size quite a bit
122-- a 4kb `struct` would need 4kb of const data in your binary to support
123`Initialize()`, whereas iteratively calling `Initialize()` on each element of
124an array does not require any extra code space for each element of the array.
125For this reason, there would likely still need to be a fallback to recursively
126calling `Initialize()`.
127
128Either way, fields with an explicit initializer value need to be wrapped in a
129view adapter when accessed, similar to how `[requires]` is handled now.
130
131Enum views can be generated with a simple `Initialize()` method that just sets
132their backing storage to 0.
133
134
135### C++ Runtime Changes
136
137Each of the views for Prelude types (`UInt`, `Int`, `Flag`, etc.) in
138`runtime/cpp/emboss_prelude.h` will need to have the new `Initialize()` method.
139