@@ -8,12 +8,12 @@ walkthrough of the static structure of a component and the
88being specified here.
99
1010* [ Supporting definitions] ( #supporting-definitions )
11- * [ Despecialization] ( #despecialization )
12- * [ Alignment] ( #alignment )
13- * [ Element Size] ( #element-size )
1411 * [ Context] ( #context )
1512 * [ Canonical ABI Options] ( #canonical-abi-options )
1613 * [ Runtime State] ( #runtime-state )
14+ * [ Despecialization] ( #despecialization )
15+ * [ Alignment] ( #alignment )
16+ * [ Element Size] ( #element-size )
1717 * [ Loading] ( #loading )
1818 * [ Storing] ( #storing )
1919 * [ Flattening] ( #flattening )
@@ -71,177 +71,9 @@ intentionally propagate OOM into the appropriate explicit return value of the
7171function's declared return type.
7272
7373
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-
24174### Context
24275
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:
24577* static ABI options supplied via [ ` canonopt ` ]
24678* dynamic state in the containing component instance
24779* dynamic state in the [ current task]
@@ -263,6 +95,7 @@ The `cx` parameter in functions below refers to the ambient `Context`. The
26395` Task ` and ` Subtask ` classes derive ` Context ` and thus having a ` task ` or
26496` subtask ` also establishes the ambient ` Context ` .
26597
98+
26699### Canonical ABI Options
267100
268101The ` opts ` field of ` Context ` contains all the possible [ ` canonopt ` ]
@@ -282,6 +115,7 @@ class CanonicalOptions:
282115reason that ` async ` is a keyword and most branches below want to start with the
283116` sync = True ` case.)
284117
118+
285119### Runtime State
286120
287121The ` inst ` field of ` Context ` points to the component instance which the
@@ -886,6 +720,174 @@ stack frame.
886720 return self .flat_results
887721```
888722
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+
889891### Loading
890892
891893The ` load ` function defines how to read a value of a given value type ` t `
0 commit comments