@@ -141,23 +141,10 @@ def alignment_flags(labels):
141
141
142
142
### Size
143
143
144
- Each interface type is assigned two slightly-different measures of "size":
145
- * its "byte size", which is the smallest number of bytes covering all its
146
- fields when stored at an aligned address in linear memory; and
147
- * its "element size", which is the size of the type when stored as an element
148
- of a list, which may include additional padding at the end to ensure the
149
- alignment of the next element.
150
-
151
- These two measures are defined by the following functions, which build on
152
- the preceding alignment functions:
144
+ Each interface type is also assigned a ` size ` , measured in bytes, which
145
+ corresponds the ` sizeof ` operator in C:
153
146
``` python
154
- def elem_size (t ):
155
- return align_to(byte_size(t), alignment(t))
156
-
157
- def align_to (ptr , alignment ):
158
- return math.ceil(ptr / alignment) * alignment
159
-
160
- def byte_size (t ):
147
+ def size (t ):
161
148
match despecialize(t):
162
149
case Bool() : return 1
163
150
case S8() | U8() : return 1
@@ -168,26 +155,30 @@ def byte_size(t):
168
155
case Float64() : return 8
169
156
case Char() : return 4
170
157
case String() | List(_) : return 8
171
- case Record(fields) : return byte_size_record (fields)
172
- case Variant(cases) : return byte_size_variant (cases)
173
- case Flags(labels) : return byte_size_flags (labels)
158
+ case Record(fields) : return size_record (fields)
159
+ case Variant(cases) : return size_variant (cases)
160
+ case Flags(labels) : return size_flags (labels)
174
161
175
- def byte_size_record (fields ):
162
+ def size_record (fields ):
176
163
s = 0
177
164
for f in fields:
178
165
s = align_to(s, alignment(f.t))
179
- s += byte_size(f.t)
180
- return s
166
+ s += size(f.t)
167
+ return align_to(s, alignment(Record(fields)))
168
+
169
+ def align_to (ptr , alignment ):
170
+ return math.ceil(ptr / alignment) * alignment
181
171
182
- def byte_size_variant (cases ):
183
- s = byte_size (discriminant_type(cases))
172
+ def size_variant (cases ):
173
+ s = size (discriminant_type(cases))
184
174
s = align_to(s, max_alignment(types_of(cases)))
185
175
cs = 0
186
176
for c in cases:
187
- cs = max (cs, byte_size(c.t))
188
- return s + cs
177
+ cs = max (cs, size(c.t))
178
+ s += cs
179
+ return align_to(s, alignment(Variant(cases)))
189
180
190
- def byte_size_flags (labels ):
181
+ def size_flags (labels ):
191
182
n = len (labels)
192
183
if n <= 8 : return 1
193
184
if n <= 16 : return 2
@@ -316,8 +307,7 @@ def load_string_from_range(opts, ptr, tagged_code_units):
316
307
return (s, opts.string_encoding, tagged_code_units)
317
308
```
318
309
319
- Lists and records are loaded by recursively loading their elements/fields.
320
- Note that lists use ` elem_size ` while records use ` byte_size ` .
310
+ Lists and records are loaded by recursively loading their elements/fields:
321
311
``` python
322
312
def load_list (opts , ptr , elem_type ):
323
313
begin = load_int(opts, ptr, 4 )
@@ -326,18 +316,18 @@ def load_list(opts, ptr, elem_type):
326
316
327
317
def load_list_from_range (opts , ptr , length , elem_type ):
328
318
trap_if(ptr != align_to(ptr, alignment(elem_type)))
329
- trap_if(ptr + length * elem_size (elem_type) > len (opts.memory))
319
+ trap_if(ptr + length * size (elem_type) > len (opts.memory))
330
320
a = []
331
321
for i in range (length):
332
- a.append(load(opts, ptr + i * elem_size (elem_type), elem_type))
322
+ a.append(load(opts, ptr + i * size (elem_type), elem_type))
333
323
return a
334
324
335
325
def load_record (opts , ptr , fields ):
336
326
record = {}
337
327
for field in fields:
338
328
ptr = align_to(ptr, alignment(field.t))
339
329
record[field.label] = load(opts, ptr, field.t)
340
- ptr += byte_size (field.t)
330
+ ptr += size (field.t)
341
331
return record
342
332
```
343
333
As a technical detail: the ` align_to ` in the loop in ` load_record ` is
@@ -354,7 +344,7 @@ tables at compile-time so that variant-passing is always O(1) and not involving
354
344
string operations.
355
345
``` python
356
346
def load_variant (opts , ptr , cases ):
357
- disc_size = byte_size (discriminant_type(cases))
347
+ disc_size = size (discriminant_type(cases))
358
348
disc = load_int(opts, ptr, disc_size)
359
349
ptr += disc_size
360
350
trap_if(disc >= len (cases))
@@ -382,7 +372,7 @@ derived from the ordered labels of the `flags` type. The code here takes
382
372
advantage of Python's support for integers of arbitrary width.
383
373
``` python
384
374
def load_flags (opts , ptr , labels ):
385
- i = load_int(opts, ptr, byte_size_flags (labels))
375
+ i = load_int(opts, ptr, size_flags (labels))
386
376
return unpack_flags_from_int(i, labels)
387
377
388
378
def unpack_flags_from_int (i , labels ):
@@ -647,20 +637,20 @@ def store_list(opts, v, ptr, elem_type):
647
637
store_int(opts, length, ptr + 4 , 4 )
648
638
649
639
def store_list_into_range (opts , v , elem_type ):
650
- byte_length = len (v) * elem_size (elem_type)
640
+ byte_length = len (v) * size (elem_type)
651
641
trap_if(byte_length >= (1 << 32 ))
652
642
ptr = opts.realloc(0 , 0 , alignment(elem_type), byte_length)
653
643
trap_if(ptr != align_to(ptr, alignment(elem_type)))
654
644
trap_if(ptr + byte_length > len (opts.memory))
655
645
for i,e in enumerate (v):
656
- store(opts, e, elem_type, ptr + i * elem_size (elem_type))
646
+ store(opts, e, elem_type, ptr + i * size (elem_type))
657
647
return (ptr, len (v))
658
648
659
649
def store_record (opts , v , ptr , fields ):
660
650
for f in fields:
661
651
ptr = align_to(ptr, alignment(f.t))
662
652
store(opts, v[f.label], f.t, ptr)
663
- ptr += byte_size (f.t)
653
+ ptr += size (f.t)
664
654
```
665
655
666
656
Variants are stored using the ` | ` -separated list of ` defaults-to ` cases built
@@ -672,7 +662,7 @@ case indices to the consumer's case indices.
672
662
``` python
673
663
def store_variant (opts , v , ptr , cases ):
674
664
case_index, case_value = match_case(v, cases)
675
- disc_size = byte_size (discriminant_type(cases))
665
+ disc_size = size (discriminant_type(cases))
676
666
store_int(opts, case_index, ptr, disc_size)
677
667
ptr += disc_size
678
668
ptr = align_to(ptr, max_alignment(types_of(cases)))
@@ -697,7 +687,7 @@ to variants.
697
687
``` python
698
688
def store_flags (opts , v , ptr , labels ):
699
689
i = pack_flags_into_int(v, labels)
700
- store_int(opts, i, ptr, byte_size_flags (labels))
690
+ store_int(opts, i, ptr, size_flags (labels))
701
691
702
692
def pack_flags_into_int (v , labels ):
703
693
i = 0
@@ -1067,7 +1057,7 @@ def lower(opts, max_flat, vs, ts, out_param = None):
1067
1057
tuple_type = Tuple(functype.params)
1068
1058
tuple_value = {str (i): v for i,v in enumerate (vs)}
1069
1059
if out_param is None :
1070
- ptr = opts.realloc(0 , 0 , alignment(tuple_type), byte_size (tuple_type))
1060
+ ptr = opts.realloc(0 , 0 , alignment(tuple_type), size (tuple_type))
1071
1061
else :
1072
1062
ptr = out_param.next(' i32' )
1073
1063
trap_if(ptr != align_to(ptr, alignment(tuple_type)))
0 commit comments