@@ -8,12 +8,12 @@ walkthrough of the static structure of a component and the
8
8
being specified here.
9
9
10
10
* [ Supporting definitions] ( #supporting-definitions )
11
- * [ Despecialization] ( #despecialization )
12
- * [ Alignment] ( #alignment )
13
- * [ Element Size] ( #element-size )
14
11
* [ Context] ( #context )
15
12
* [ Canonical ABI Options] ( #canonical-abi-options )
16
13
* [ Runtime State] ( #runtime-state )
14
+ * [ Despecialization] ( #despecialization )
15
+ * [ Alignment] ( #alignment )
16
+ * [ Element Size] ( #element-size )
17
17
* [ Loading] ( #loading )
18
18
* [ Storing] ( #storing )
19
19
* [ Flattening] ( #flattening )
@@ -71,177 +71,9 @@ intentionally propagate OOM into the appropriate explicit return value of the
71
71
function's declared return type.
72
72
73
73
74
- ### Despecialization
75
-
76
- [ In the explainer] [ Type Definitions ] , component value types are classified as
77
- either * fundamental* or * specialized* , where the specialized value types are
78
- defined by expansion into fundamental value types. In most cases, the canonical
79
- ABI of a specialized value type is the same as its expansion so, to avoid
80
- repetition, the other definitions below use the following ` despecialize `
81
- function to replace specialized value types with their expansion:
82
- ``` python
83
- def despecialize (t ):
84
- match t:
85
- case Tuple(ts) : return Record([ Field(str (i), t) for i,t in enumerate (ts) ])
86
- case Enum(labels) : return Variant([ Case(l, None ) for l in labels ])
87
- case Option(t) : return Variant([ Case(" none" , None ), Case(" some" , t) ])
88
- case Result(ok, error) : return Variant([ Case(" ok" , ok), Case(" error" , error) ])
89
- case _ : return t
90
- ```
91
- The specialized value types ` string ` and ` flags ` are missing from this list
92
- because they are given specialized canonical ABI representations distinct from
93
- their respective expansions.
94
-
95
-
96
- ### Alignment
97
-
98
- Each value type is assigned an [ alignment] which is used by subsequent
99
- Canonical ABI definitions. Presenting the definition of ` alignment ` piecewise,
100
- we start with the top-level case analysis:
101
- ``` python
102
- def alignment (t ):
103
- match despecialize(t):
104
- case Bool() : return 1
105
- case S8() | U8() : return 1
106
- case S16() | U16() : return 2
107
- case S32() | U32() : return 4
108
- case S64() | U64() : return 8
109
- case F32() : return 4
110
- case F64() : return 8
111
- case Char() : return 4
112
- case String() : return 4
113
- case List(t, l) : return alignment_list(t, l)
114
- case Record(fields) : return alignment_record(fields)
115
- case Variant(cases) : return alignment_variant(cases)
116
- case Flags(labels) : return alignment_flags(labels)
117
- case Own(_) | Borrow(_) : return 4
118
- ```
119
-
120
- List alignment is the same as tuple alignment when the length is fixed and
121
- otherwise uses the alignment of pointers.
122
- ``` python
123
- def alignment_list (elem_type , maybe_length ):
124
- if maybe_length is not None :
125
- return alignment(elem_type)
126
- return 4
127
- ```
128
-
129
- Record alignment is tuple alignment, with the definitions split for reuse below:
130
- ``` python
131
- def alignment_record (fields ):
132
- a = 1
133
- for f in fields:
134
- a = max (a, alignment(f.t))
135
- return a
136
- ```
137
-
138
- As an optimization, ` variant ` discriminants are represented by the smallest integer
139
- covering the number of cases in the variant (with cases numbered in order from
140
- ` 0 ` to ` len(cases)-1 ` ). Depending on the payload type, this can allow more
141
- compact representations of variants in memory. This smallest integer type is
142
- selected by the following function, used above and below:
143
- ``` python
144
- def alignment_variant (cases ):
145
- return max (alignment(discriminant_type(cases)), max_case_alignment(cases))
146
-
147
- def discriminant_type (cases ):
148
- n = len (cases)
149
- assert (0 < n < (1 << 32 ))
150
- match math.ceil(math.log2(n)/ 8 ):
151
- case 0 : return U8()
152
- case 1 : return U8()
153
- case 2 : return U16()
154
- case 3 : return U32()
155
-
156
- def max_case_alignment (cases ):
157
- a = 1
158
- for c in cases:
159
- if c.t is not None :
160
- a = max (a, alignment(c.t))
161
- return a
162
- ```
163
-
164
- As an optimization, ` flags ` are represented as packed bit-vectors. Like variant
165
- discriminants, ` flags ` use the smallest integer that fits all the bits, falling
166
- back to sequences of ` i32 ` s when there are more than 32 flags.
167
- ``` python
168
- def alignment_flags (labels ):
169
- n = len (labels)
170
- assert (0 < n <= 32 )
171
- if n <= 8 : return 1
172
- if n <= 16 : return 2
173
- return 4
174
- ```
175
-
176
- Handle types are passed as ` i32 ` indices into the ` Table[HandleElem] `
177
- introduced below.
178
-
179
-
180
- ### Element Size
181
-
182
- Each value type is also assigned an ` elem_size ` which is the number of bytes
183
- used when values of the type are stored as elements of a ` list ` . Having this
184
- byte size be a static property of the type instead of attempting to use a
185
- variable-length element-encoding scheme both simplifies the implementation and
186
- maps well to languages which represent ` list ` s as random-access arrays. Empty
187
- types, such as records with no fields, are not permitted, to avoid
188
- complications in source languages.
189
- ``` python
190
- def elem_size (t ):
191
- match despecialize(t):
192
- case Bool() : return 1
193
- case S8() | U8() : return 1
194
- case S16() | U16() : return 2
195
- case S32() | U32() : return 4
196
- case S64() | U64() : return 8
197
- case F32() : return 4
198
- case F64() : return 8
199
- case Char() : return 4
200
- case String() : return 8
201
- case List(t, l) : return elem_size_list(t, l)
202
- case Record(fields) : return elem_size_record(fields)
203
- case Variant(cases) : return elem_size_variant(cases)
204
- case Flags(labels) : return elem_size_flags(labels)
205
- case Own(_) | Borrow(_) : return 4
206
-
207
- def elem_size_list (elem_type , maybe_length ):
208
- if maybe_length is not None :
209
- return maybe_length * elem_size(elem_type)
210
- return 8
211
-
212
- def elem_size_record (fields ):
213
- s = 0
214
- for f in fields:
215
- s = align_to(s, alignment(f.t))
216
- s += elem_size(f.t)
217
- assert (s > 0 )
218
- return align_to(s, alignment_record(fields))
219
-
220
- def align_to (ptr , alignment ):
221
- return math.ceil(ptr / alignment) * alignment
222
-
223
- def elem_size_variant (cases ):
224
- s = elem_size(discriminant_type(cases))
225
- s = align_to(s, max_case_alignment(cases))
226
- cs = 0
227
- for c in cases:
228
- if c.t is not None :
229
- cs = max (cs, elem_size(c.t))
230
- s += cs
231
- return align_to(s, alignment_variant(cases))
232
-
233
- def elem_size_flags (labels ):
234
- n = len (labels)
235
- assert (0 < n <= 32 )
236
- if n <= 8 : return 1
237
- if n <= 16 : return 2
238
- return 4
239
- ```
240
-
241
74
### Context
242
75
243
- The subsequent definitions of lifting and lowering depend on three kinds of
244
- ambient information:
76
+ The subsequent definitions depend on three kinds of ambient information:
245
77
* static ABI options supplied via [ ` canonopt ` ]
246
78
* dynamic state in the containing component instance
247
79
* dynamic state in the [ current task]
@@ -263,6 +95,7 @@ The `cx` parameter in functions below refers to the ambient `Context`. The
263
95
` Task ` and ` Subtask ` classes derive ` Context ` and thus having a ` task ` or
264
96
` subtask ` also establishes the ambient ` Context ` .
265
97
98
+
266
99
### Canonical ABI Options
267
100
268
101
The ` opts ` field of ` Context ` contains all the possible [ ` canonopt ` ]
@@ -282,6 +115,7 @@ class CanonicalOptions:
282
115
reason that ` async ` is a keyword and most branches below want to start with the
283
116
` sync = True ` case.)
284
117
118
+
285
119
### Runtime State
286
120
287
121
The ` inst ` field of ` Context ` points to the component instance which the
@@ -886,6 +720,174 @@ stack frame.
886
720
return self .flat_results
887
721
```
888
722
723
+
724
+ ### Despecialization
725
+
726
+ [ In the explainer] [ Type Definitions ] , component value types are classified as
727
+ either * fundamental* or * specialized* , where the specialized value types are
728
+ defined by expansion into fundamental value types. In most cases, the canonical
729
+ ABI of a specialized value type is the same as its expansion so, to avoid
730
+ repetition, the other definitions below use the following ` despecialize `
731
+ function to replace specialized value types with their expansion:
732
+ ``` python
733
+ def despecialize (t ):
734
+ match t:
735
+ case Tuple(ts) : return Record([ Field(str (i), t) for i,t in enumerate (ts) ])
736
+ case Enum(labels) : return Variant([ Case(l, None ) for l in labels ])
737
+ case Option(t) : return Variant([ Case(" none" , None ), Case(" some" , t) ])
738
+ case Result(ok, error) : return Variant([ Case(" ok" , ok), Case(" error" , error) ])
739
+ case _ : return t
740
+ ```
741
+ The specialized value types ` string ` and ` flags ` are missing from this list
742
+ because they are given specialized canonical ABI representations distinct from
743
+ their respective expansions.
744
+
745
+
746
+ ### Alignment
747
+
748
+ Each value type is assigned an [ alignment] which is used by subsequent
749
+ Canonical ABI definitions. Presenting the definition of ` alignment ` piecewise,
750
+ we start with the top-level case analysis:
751
+ ``` python
752
+ def alignment (t ):
753
+ match despecialize(t):
754
+ case Bool() : return 1
755
+ case S8() | U8() : return 1
756
+ case S16() | U16() : return 2
757
+ case S32() | U32() : return 4
758
+ case S64() | U64() : return 8
759
+ case F32() : return 4
760
+ case F64() : return 8
761
+ case Char() : return 4
762
+ case String() : return 4
763
+ case List(t, l) : return alignment_list(t, l)
764
+ case Record(fields) : return alignment_record(fields)
765
+ case Variant(cases) : return alignment_variant(cases)
766
+ case Flags(labels) : return alignment_flags(labels)
767
+ case Own(_) | Borrow(_) : return 4
768
+ ```
769
+
770
+ List alignment is the same as tuple alignment when the length is fixed and
771
+ otherwise uses the alignment of pointers.
772
+ ``` python
773
+ def alignment_list (elem_type , maybe_length ):
774
+ if maybe_length is not None :
775
+ return alignment(elem_type)
776
+ return 4
777
+ ```
778
+
779
+ Record alignment is tuple alignment, with the definitions split for reuse below:
780
+ ``` python
781
+ def alignment_record (fields ):
782
+ a = 1
783
+ for f in fields:
784
+ a = max (a, alignment(f.t))
785
+ return a
786
+ ```
787
+
788
+ As an optimization, ` variant ` discriminants are represented by the smallest integer
789
+ covering the number of cases in the variant (with cases numbered in order from
790
+ ` 0 ` to ` len(cases)-1 ` ). Depending on the payload type, this can allow more
791
+ compact representations of variants in memory. This smallest integer type is
792
+ selected by the following function, used above and below:
793
+ ``` python
794
+ def alignment_variant (cases ):
795
+ return max (alignment(discriminant_type(cases)), max_case_alignment(cases))
796
+
797
+ def discriminant_type (cases ):
798
+ n = len (cases)
799
+ assert (0 < n < (1 << 32 ))
800
+ match math.ceil(math.log2(n)/ 8 ):
801
+ case 0 : return U8()
802
+ case 1 : return U8()
803
+ case 2 : return U16()
804
+ case 3 : return U32()
805
+
806
+ def max_case_alignment (cases ):
807
+ a = 1
808
+ for c in cases:
809
+ if c.t is not None :
810
+ a = max (a, alignment(c.t))
811
+ return a
812
+ ```
813
+
814
+ As an optimization, ` flags ` are represented as packed bit-vectors. Like variant
815
+ discriminants, ` flags ` use the smallest integer that fits all the bits, falling
816
+ back to sequences of ` i32 ` s when there are more than 32 flags.
817
+ ``` python
818
+ def alignment_flags (labels ):
819
+ n = len (labels)
820
+ assert (0 < n <= 32 )
821
+ if n <= 8 : return 1
822
+ if n <= 16 : return 2
823
+ return 4
824
+ ```
825
+
826
+ Handle types are passed as ` i32 ` indices into the ` Table[HandleElem] `
827
+ introduced below.
828
+
829
+
830
+ ### Element Size
831
+
832
+ Each value type is also assigned an ` elem_size ` which is the number of bytes
833
+ used when values of the type are stored as elements of a ` list ` . Having this
834
+ byte size be a static property of the type instead of attempting to use a
835
+ variable-length element-encoding scheme both simplifies the implementation and
836
+ maps well to languages which represent ` list ` s as random-access arrays. Empty
837
+ types, such as records with no fields, are not permitted, to avoid
838
+ complications in source languages.
839
+ ``` python
840
+ def elem_size (t ):
841
+ match despecialize(t):
842
+ case Bool() : return 1
843
+ case S8() | U8() : return 1
844
+ case S16() | U16() : return 2
845
+ case S32() | U32() : return 4
846
+ case S64() | U64() : return 8
847
+ case F32() : return 4
848
+ case F64() : return 8
849
+ case Char() : return 4
850
+ case String() : return 8
851
+ case List(t, l) : return elem_size_list(t, l)
852
+ case Record(fields) : return elem_size_record(fields)
853
+ case Variant(cases) : return elem_size_variant(cases)
854
+ case Flags(labels) : return elem_size_flags(labels)
855
+ case Own(_) | Borrow(_) : return 4
856
+
857
+ def elem_size_list (elem_type , maybe_length ):
858
+ if maybe_length is not None :
859
+ return maybe_length * elem_size(elem_type)
860
+ return 8
861
+
862
+ def elem_size_record (fields ):
863
+ s = 0
864
+ for f in fields:
865
+ s = align_to(s, alignment(f.t))
866
+ s += elem_size(f.t)
867
+ assert (s > 0 )
868
+ return align_to(s, alignment_record(fields))
869
+
870
+ def align_to (ptr , alignment ):
871
+ return math.ceil(ptr / alignment) * alignment
872
+
873
+ def elem_size_variant (cases ):
874
+ s = elem_size(discriminant_type(cases))
875
+ s = align_to(s, max_case_alignment(cases))
876
+ cs = 0
877
+ for c in cases:
878
+ if c.t is not None :
879
+ cs = max (cs, elem_size(c.t))
880
+ s += cs
881
+ return align_to(s, alignment_variant(cases))
882
+
883
+ def elem_size_flags (labels ):
884
+ n = len (labels)
885
+ assert (0 < n <= 32 )
886
+ if n <= 8 : return 1
887
+ if n <= 16 : return 2
888
+ return 4
889
+ ```
890
+
889
891
### Loading
890
892
891
893
The ` load ` function defines how to read a value of a given value type ` t `
0 commit comments