bytecode_lang/ids.rs
1//! Dense index types.
2//!
3//! Every cross-reference in a module is a plain integer index into a table,
4//! never a pointer or a name lookup, so a decoded module is usable as is and a
5//! VM resolves each reference with one bounds-checked load. Each kind of index
6//! has its own newtype so a function index can never be passed where a
7//! constant index is expected.
8//!
9//! The decoder checks only that indices are well-formed numbers; whether an
10//! index is *in range* for its table is the verifier's job (see
11//! `docs/API.md`), and every accessor that follows an index returns `Option`.
12
13index_type! {
14 /// A register in the running function's frame.
15 ///
16 /// Registers are numbered from zero. The first registers hold the
17 /// function's parameters, in order; the rest are locals. Every register
18 /// has a declared [`ValType`](crate::ValType). The 16-bit width allows
19 /// 65,536 registers per function.
20 ///
21 /// # Examples
22 ///
23 /// ```
24 /// use bytecode_lang::Reg;
25 ///
26 /// assert_eq!(Reg(3).to_string(), "r3");
27 /// assert_eq!(Reg(3).index(), 3);
28 /// ```
29 Reg(u16) => "r"
30}
31
32index_type! {
33 /// An instruction index within one function: the destination of a branch.
34 ///
35 /// Targets are absolute, already resolved positions in the function's
36 /// code. They are never symbolic labels, so the encoded form can be
37 /// executed without a fix-up table (the defect class of family issue H02).
38 /// Every instruction is one slot wide, so every target is an instruction
39 /// boundary.
40 ///
41 /// # Examples
42 ///
43 /// ```
44 /// use bytecode_lang::Target;
45 ///
46 /// assert_eq!(Target(12).to_string(), "@12");
47 /// ```
48 Target(u32) => "@"
49}
50
51index_type! {
52 /// An index into the module's constant pool.
53 ///
54 /// # Examples
55 ///
56 /// ```
57 /// use bytecode_lang::ConstId;
58 ///
59 /// assert_eq!(ConstId(0).to_string(), "k0");
60 /// ```
61 ConstId(u32) => "k"
62}
63
64index_type! {
65 /// An index into the module's function table.
66 ///
67 /// # Examples
68 ///
69 /// ```
70 /// use bytecode_lang::FuncId;
71 ///
72 /// assert_eq!(FuncId(2).to_string(), "f2");
73 /// ```
74 FuncId(u32) => "f"
75}
76
77index_type! {
78 /// An index into the module's import table (host functions).
79 ///
80 /// # Examples
81 ///
82 /// ```
83 /// use bytecode_lang::ImportId;
84 ///
85 /// assert_eq!(ImportId(1).to_string(), "imp1");
86 /// ```
87 ImportId(u32) => "imp"
88}
89
90index_type! {
91 /// An index into the module's global table.
92 ///
93 /// # Examples
94 ///
95 /// ```
96 /// use bytecode_lang::GlobalId;
97 ///
98 /// assert_eq!(GlobalId(4).to_string(), "g4");
99 /// ```
100 GlobalId(u32) => "g"
101}
102
103index_type! {
104 /// An index into the module's type table.
105 ///
106 /// # Examples
107 ///
108 /// ```
109 /// use bytecode_lang::TypeId;
110 ///
111 /// assert_eq!(TypeId(7).to_string(), "t7");
112 /// ```
113 TypeId(u32) => "t"
114}
115
116index_type! {
117 /// An index into the module's string table.
118 ///
119 /// # Examples
120 ///
121 /// ```
122 /// use bytecode_lang::StrId;
123 ///
124 /// assert_eq!(StrId(5).to_string(), "s5");
125 /// ```
126 StrId(u32) => "s"
127}
128
129index_type! {
130 /// An index into the running function's name list, which maps it to a
131 /// [`StrId`].
132 ///
133 /// Property instructions need two registers and a name in one eight-byte
134 /// instruction, which leaves 16 bits for the name. Routing names through a
135 /// per-function list (as Lua and V8 do with their per-function constant
136 /// pools) keeps the module's string table unbounded while each function
137 /// may still name 65,536 distinct properties.
138 ///
139 /// # Examples
140 ///
141 /// ```
142 /// use bytecode_lang::NameRef;
143 ///
144 /// assert_eq!(NameRef(0).to_string(), "n0");
145 /// ```
146 NameRef(u16) => "n"
147}
148
149index_type! {
150 /// An index into the running function's type list, which maps it to a
151 /// [`TypeId`].
152 ///
153 /// Used by the instructions that need a type next to two or three
154 /// registers ([`Inst::IsType`](crate::Inst::IsType),
155 /// [`Inst::NewArray`](crate::Inst::NewArray), ...), for the same reason as
156 /// [`NameRef`].
157 ///
158 /// # Examples
159 ///
160 /// ```
161 /// use bytecode_lang::TypeRef;
162 ///
163 /// assert_eq!(TypeRef(1).to_string(), "ty1");
164 /// ```
165 TypeRef(u16) => "ty"
166}
167
168index_type! {
169 /// An index into the running function's jump tables (see
170 /// [`Inst::Switch`](crate::Inst::Switch)).
171 ///
172 /// # Examples
173 ///
174 /// ```
175 /// use bytecode_lang::TableId;
176 ///
177 /// assert_eq!(TableId(0).to_string(), "jt0");
178 /// ```
179 TableId(u32) => "jt"
180}
181
182index_type! {
183 /// An index into the running function's call shapes (see
184 /// [`Inst::DCallShape`](crate::Inst::DCallShape) and
185 /// [`CallShape`](crate::CallShape)): which window arguments are positional,
186 /// named, or spread. 16-bit, like [`NameRef`], so a function may use 65,536
187 /// distinct shapes.
188 ///
189 /// # Examples
190 ///
191 /// ```
192 /// use bytecode_lang::ShapeId;
193 ///
194 /// assert_eq!(ShapeId(2).to_string(), "cs2");
195 /// ```
196 ShapeId(u16) => "cs"
197}
198
199index_type! {
200 /// A field slot of a struct type, counted across the whole parent chain
201 /// (a struct's fields start with its parent's).
202 ///
203 /// # Examples
204 ///
205 /// ```
206 /// use bytecode_lang::FieldIdx;
207 ///
208 /// assert_eq!(FieldIdx(2).to_string(), "#2");
209 /// ```
210 FieldIdx(u16) => "#"
211}
212
213index_type! {
214 /// A captured value of the running closure (see
215 /// [`Inst::GetUpval`](crate::Inst::GetUpval)).
216 ///
217 /// # Examples
218 ///
219 /// ```
220 /// use bytecode_lang::UpvalIdx;
221 ///
222 /// assert_eq!(UpvalIdx(0).to_string(), "u0");
223 /// ```
224 UpvalIdx(u16) => "u"
225}