Skip to content

Commit 321a751

Browse files
committed
more work on host function and action definitions
1 parent fb6ff08 commit 321a751

File tree

6 files changed

+55
-97
lines changed

6 files changed

+55
-97
lines changed

document/core/appendix/properties.rst

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -156,52 +156,17 @@ Module instances are classified by *module contexts*, which are regular :ref:`co
156156

157157
* The :ref:`function type <syntax-functype>` :math:`\functype` must be :ref:`valid <valid-functype>`.
158158

159-
* Let :math:`[t_1^\ast] \to [t_2^\ast]` be the :ref:`function type <syntax-functype>` :math:`\functype`.
160-
161-
* For every :ref:`valid <valid-store>` :ref:`store <syntax-store>` :math:`S_1` :ref:`extending <extend-store>` :math:`S` and every sequence :math:`\val^\ast` of :ref:`values <syntax-val>` whose :ref:`types <valid-val>` coincide with :math:`t_1^\ast`:
162-
163-
* :ref:`Executing <exec-invoke-host>` :math:`\X{hf}` in store :math:`S_1` with arguments :math:`\val^\ast` has a non-empty set of possible outcomes.
164-
165-
* For every element :math:`R` of this set:
166-
167-
* Either :math:`R` must be :math:`\bot` (i.e., divergence).
168-
169-
* Or :math:`R` consists of a :ref:`valid <valid-store>` :ref:`store <syntax-store>` :math:`S_2` :ref:`extending <extend-store>` :math:`S_1` and a :ref:`result <syntax-result>` :math:`\result` whose :ref:`type <valid-result>` coincides with :math:`[t_2^\ast]`.
170-
171159
* Then the function instance is valid with :ref:`function type <syntax-functype>` :math:`\functype`.
172160

173161
.. math::
174162
\frac{
175163
\begin{array}[b]{@{}l@{}}
176164
\vdashfunctype [t_1^\ast] \to [t_2^\ast] \ok \\
177165
\end{array}
178-
\quad
179-
\begin{array}[b]{@{}l@{}}
180-
\forall S_1, \val^\ast,~
181-
{\vdashstore S_1 \ok} \wedge
182-
{\vdashstoreextends S \extendsto S_1} \wedge
183-
{S_1 \vdashresult \val^\ast : [t_1^\ast]}
184-
\Longrightarrow {} \\ \qquad
185-
\X{hf}(S_1; \val^\ast) \supset \emptyset \wedge {} \\ \qquad
186-
\forall R \in \X{hf}(S_1; \val^\ast),~
187-
R = \bot \vee {} \\ \qquad\qquad
188-
\exists S_2, \result,~
189-
{\vdashstore S_2 \ok} \wedge
190-
{\vdashstoreextends S_1 \extendsto S_2} \wedge
191-
{S_2 \vdashresult \result : [t_2^\ast]} \wedge
192-
R = (S_2; \result)
193-
\end{array}
194166
}{
195167
S \vdashfuncinst \{\FITYPE~[t_1^\ast] \to [t_2^\ast], \FIHOSTCODE~\X{hf}\} : [t_1^\ast] \to [t_2^\ast]
196168
}
197169
198-
.. note::
199-
This rule states that, if appropriate pre-conditions about store and arguments are satisfied, then executing the host function must satisfy appropriate post-conditions about store and results.
200-
The post-conditions match the ones in the :ref:`execution rule <exec-invoke-host>` for invoking host functions.
201-
202-
Any store under which the function is invoked is assumed to be an extension of the current store.
203-
That way, the function itself is able to make sufficient assumptions about future stores.
204-
205170
206171
.. index:: table type, table instance, limits, function address
207172
.. _valid-tableinst:

document/core/exec/instructions.rst

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4149,9 +4149,7 @@ During its execution, a host function call may do any of the following.
41494149
- Terminate with a list of values that respects the host function's type annotation.
41504150
- Terminate with a trap.
41514151

4152-
.. todo:: better prose
4153-
4154-
.. todo:: reconcile with old-style host function formulation
4152+
.. todo:: better prose, evaluate alternative approach where host may directly emit shared memory events
41554153

41564154
.. math::
41574155
~\\[-1ex]
@@ -4189,20 +4187,6 @@ During its execution, a host function call may do any of the following.
41894187
\end{array}
41904188
\end{array}
41914189
4192-
.. todo:: reconcile with old-style host function formulation
4193-
4194-
Here, :math:`\X{hf}(S; \val^n)` denotes the implementation-defined execution of host function :math:`\X{hf}` in current store :math:`S` with arguments :math:`\val^n`.
4195-
It yields a set of possible outcomes, where each element is either a pair of a modified store :math:`S'` and a :ref:`result <syntax-result>`
4196-
or the special value :math:`\bot` indicating divergence.
4197-
A host function is non-deterministic if there is at least one argument for which the set of outcomes is not singular.
4198-
4199-
For a WebAssembly implementation to be :ref:`sound <soundness>` in the presence of host functions,
4200-
every :ref:`host function instance <syntax-funcinst>` must be :ref:`valid <valid-hostfuncinst>`,
4201-
which means that it adheres to suitable pre- and post-conditions:
4202-
under a :ref:`valid store <valid-store>` :math:`S`, and given arguments :math:`\val^n` matching the ascribed parameter types :math:`t_1^n`,
4203-
executing the host function must yield a non-empty set of possible outcomes each of which is either divergence or consists of a valid store :math:`S'` that is an :ref:`extension <extend-store>` of :math:`S` and a result matching the ascribed return types :math:`t_2^m`.
4204-
All these notions are made precise in the :ref:`Appendix <soundness>`.
4205-
42064190
.. note::
42074191
A host function can call back into WebAssembly by :ref:`invoking <exec-invocation>` a function :ref:`exported <syntax-export>` from a :ref:`module <syntax-module>`.
42084192
However, the effects of any such call are subsumed by the non-deterministic behavior allowed for the host function.

document/core/exec/modules.rst

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -658,11 +658,15 @@ It is up to the :ref:`embedder <embedder>` to define how such conditions are rep
658658

659659
4. For each :ref:`external value <syntax-externval>` :math:`\externval_i` in :math:`\externval^n` and :ref:`external type <syntax-externtype>` :math:`\externtype'_i` in :math:`\externtype_{\F{im}}^n`, do:
660660

661-
a. If :math:`\externval_i` is not :ref:`valid <valid-externval>` with an :ref:`external type <syntax-externtype>` :math:`\externtype_i` in store :math:`S`, then:
661+
a. If :math:`\externval_i` is :ref:`valid <valid-externval>` with an :ref:`external type <syntax-externtype>` :math:`\externtype_i` in store :math:`S`, then:
662+
663+
i. Assert: in checking the validity of :math:`\externval_i`, the :ref:`shared memory actions <syntax-act>` :math:`\X{act}_i^?` are performed.
664+
665+
b. Else:
662666

663667
i. Fail.
664668

665-
b. If :math:`\externtype_i` does not :ref:`match <match-externtype>` :math:`\externtype'_i`, then:
669+
c. If :math:`\externtype_i` does not :ref:`match <match-externtype>` :math:`\externtype'_i`, then:
666670

667671
i. Fail.
668672

@@ -698,11 +702,13 @@ It is up to the :ref:`embedder <embedder>` to define how such conditions are rep
698702

699703
11. Let :math:`\moduleinst` be a new module instance :ref:`allocated <alloc-module>` from :math:`\module` in store :math:`S` with imports :math:`\externval^n`, global initializer values :math:`\val^\ast`, and element segment contents :math:`(\reff^\ast)^\ast`, and let :math:`S'` be the extended store produced by module allocation.
700704

701-
12. Let :math:`F` be the auxiliary :ref:`frame <syntax-frame>` :math:`\{ \AMODULE~\moduleinst, \ALOCALS~\epsilon \}`.
705+
12. Assert: in allocating :math:`\moduleinst`, the :ref:`shared memory actions <syntax-act>` :math:`\X{act_{\F{m}}}^\ast` are performed.
706+
707+
13. Let :math:`F` be the auxiliary :ref:`frame <syntax-frame>` :math:`\{ \AMODULE~\moduleinst, \ALOCALS~\epsilon \}`.
702708

703-
13. Push the frame :math:`F` to the stack.
709+
14. Push the frame :math:`F` to the stack.
704710

705-
14. For each :ref:`element segment <syntax-elem>` :math:`\elem_i` in :math:`\module.\MELEMS` whose :ref:`mode <syntax-elemmode>` is of the form :math:`\EACTIVE~\{ \ETABLE~\tableidx_i, \EOFFSET~\X{einstr}^\ast_i~\END \}`, do:
711+
15. For each :ref:`element segment <syntax-elem>` :math:`\elem_i` in :math:`\module.\MELEMS` whose :ref:`mode <syntax-elemmode>` is of the form :math:`\EACTIVE~\{ \ETABLE~\tableidx_i, \EOFFSET~\X{einstr}^\ast_i~\END \}`, do:
706712

707713
a. Let :math:`n` be the length of the vector :math:`\elem_i.\EINIT`.
708714

@@ -716,11 +722,11 @@ It is up to the :ref:`embedder <embedder>` to define how such conditions are rep
716722

717723
f. :ref:`Execute <exec-elem.drop>` the instruction :math:`\ELEMDROP~i`.
718724

719-
15. For each :ref:`element segment <syntax-elem>` :math:`\elem_i` in :math:`\module.\MELEMS` whose :ref:`mode <syntax-elemmode>` is of the form :math:`\EDECLARATIVE`, do:
725+
16. For each :ref:`element segment <syntax-elem>` :math:`\elem_i` in :math:`\module.\MELEMS` whose :ref:`mode <syntax-elemmode>` is of the form :math:`\EDECLARATIVE`, do:
720726

721727
a. :ref:`Execute <exec-elem.drop>` the instruction :math:`\ELEMDROP~i`.
722728

723-
16. For each :ref:`data segment <syntax-data>` :math:`\data_i` in :math:`\module.\MDATAS` whose :ref:`mode <syntax-datamode>` is of the form :math:`\DACTIVE~\{ \DMEM~\memidx_i, \DOFFSET~\X{dinstr}^\ast_i~\END \}`, do:
729+
17. For each :ref:`data segment <syntax-data>` :math:`\data_i` in :math:`\module.\MDATAS` whose :ref:`mode <syntax-datamode>` is of the form :math:`\DACTIVE~\{ \DMEM~\memidx_i, \DOFFSET~\X{dinstr}^\ast_i~\END \}`, do:
724730

725731
a. Assert: :math:`\memidx_i` is :math:`0`.
726732

@@ -736,15 +742,15 @@ It is up to the :ref:`embedder <embedder>` to define how such conditions are rep
736742

737743
g. :ref:`Execute <exec-data.drop>` the instruction :math:`\DATADROP~i`.
738744

739-
17. If the :ref:`start function <syntax-start>` :math:`\module.\MSTART` is not empty, then:
745+
18. If the :ref:`start function <syntax-start>` :math:`\module.\MSTART` is not empty, then:
740746

741747
a. Let :math:`\start` be the :ref:`start function <syntax-start>` :math:`\module.\MSTART`.
742748

743749
b. :ref:`Execute <exec-call>` the instruction :math:`\CALL~\start.\SFUNC`.
744750

745-
18. Assert: due to :ref:`validation <valid-module>`, the frame :math:`F` is now on the top of the stack.
751+
19. Assert: due to :ref:`validation <valid-module>`, the frame :math:`F` is now on the top of the stack.
746752

747-
19. Pop the frame :math:`F` from the stack.
753+
20. Pop the frame :math:`F` from the stack.
748754

749755

750756
.. math::
@@ -753,7 +759,7 @@ It is up to the :ref:`embedder <embedder>` to define how such conditions are rep
753759
\begin{array}{@{}rcll}
754760
\instantiate(S, \module, \externval^k) &=& S'; F;
755761
\begin{array}[t]{@{}l@{}}
756-
(\PERFORM~(\X{act}^?)^k) \\
762+
(\PERFORM~(\X{act}^?))^k \\
757763
(\PERFORM~\X{act_{\F{m}}}^\ast) \\
758764
\F{runelem}_0(\elem^n[0])~\dots~\F{runelem}_{n-1}(\elem^n[n-1]) \\
759765
\F{rundata}_0(\data^m[0])~\dots~\F{rundata}_{m-1}(\data^m[m-1]) \\

document/core/exec/relaxed.rst

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,9 @@ Preliminary Definitions
4040
\tearfreeact \ldots & = & \ldots \\
4141
\sameact \ldots & = & \ldots \\
4242
\\
43-
\X{func}_{\loc}(\evt) \ldots & = & \X{func}(\act) \ldots \\
43+
\X{func}_{\reg}(\evt) \ldots & = & \X{func}(\act) \ldots \\
4444
\end{array}
4545
46-
.. todo:: need to refactor len+data in actions
47-
4846
4947
.. _relaxed-trace:
5048

@@ -76,97 +74,97 @@ Consistency
7674

7775
.. math::
7876
\frac{
79-
\forall \loc, \, \vdash_{\loc} \X{tr} \consistentwith
77+
\forall \reg, \, \vdash_{\reg} \X{tr} \consistentwith
8078
}{
8179
\vdash \X{tr} \consistent
8280
}
8381
8482
.. math::
8583
\frac{
8684
\begin{array}[b]{@{}l@{}}
87-
\forall \evt_R \in \readingact_{\loc}(\X{tr}), \exists \evt_W^\ast,
88-
\X{tr} \vdash_{\loc} \evt_R \readseachfrom \evt_W^\ast \\
85+
\forall \evt_R \in \readingact_{\reg}(\X{tr}), \exists \evt_W^\ast,
86+
\X{tr} \vdash_{\reg} \evt_R \readseachfrom \evt_W^\ast \\
8987
\forall \evt_I, \evt \in \X{tr}, \,
90-
\ordact_{\loc}(\evt_I) = \INIT \wedge
88+
\ordact_{\reg}(\evt_I) = \INIT \wedge
9189
\evt_I \neq \evt \wedge
9290
\overlapact(\evt_I, \evt) \Rightarrow \evt_I \prechb \evt
9391
\end{array}
9492
}{
95-
\vdash_{\loc} \X{tr} \consistentwith
93+
\vdash_{\reg} \X{tr} \consistentwith
9694
}
9795
9896
.. math::
9997
\frac{
10098
\begin{array}[b]{@{}c@{}}
101-
\left|\evt_W^\ast\right| = |\readact_{\loc}(\evt_R)| \\
99+
\left|\evt_W^\ast\right| = |\readact_{\reg}(\evt_R)| \\
102100
\forall i < |\evt_W^\ast|,
103-
\X{tr} \vdash_{\loc}^i \evt_R \readsfrom \left(\evt_W^\ast[i]\right)
101+
\X{tr} \vdash_{\reg}^i \evt_R \readsfrom \left(\evt_W^\ast[i]\right)
104102
\\
105-
\vdash_{\loc} \evt_R \notear \evt_W^\ast
103+
\vdash_{\reg} \evt_R \notear \evt_W^\ast
106104
\end{array}
107105
}{
108-
\X{tr} \vdash_{\loc} \evt_R \readseachfrom \evt_W^\ast
106+
\X{tr} \vdash_{\reg} \evt_R \readseachfrom \evt_W^\ast
109107
}
110108
111109
.. math::
112110
\frac{
113111
\begin{array}[b]{@{}l@{}}
114112
\evt_R \neq \evt_W \\
115-
\evt_W \in \writingact_{\loc}(\X{tr})
113+
\evt_W \in \writingact_{\reg}(\X{tr})
116114
\end{array}
117115
\qquad
118116
\begin{array}[b]{@{}r@{}}
119-
\X{tr} \vdash_{\loc}^{i,k} \evt_R \valueconsistent \evt_W \\
120-
\X{tr} \vdash_{\loc}^k \evt_R \hbconsistent \evt_W
117+
\X{tr} \vdash_{\reg}^{i,k} \evt_R \valueconsistent \evt_W \\
118+
\X{tr} \vdash_{\reg}^k \evt_R \hbconsistent \evt_W
121119
\end{array}
122120
\qquad
123-
\X{tr} \vdash_{\loc} \evt_R \sclastvisible \evt^\ast_W
121+
\X{tr} \vdash_{\reg} \evt_R \sclastvisible \evt^\ast_W
124122
}{
125-
\X{tr} \vdash_{\loc}^i \evt_R \readsfrom \evt_W
123+
\X{tr} \vdash_{\reg}^i \evt_R \readsfrom \evt_W
126124
}
127125
128126
.. math::
129127
\frac{
130128
\begin{array}[b]{@{}r@{~}c@{~}l@{}}
131-
\readact_{\loc}(\evt_R)[i] &=& \writeact_{\loc}(\evt_W)[j] \\
132-
k = \offsetact_{\loc}(\evt_R) + i &=& \offsetact_{\loc}(\evt_W) + j
129+
\readact_{\reg}(\evt_R)[i] &=& \writeact_{\reg}(\evt_W)[j] \\
130+
k = \offsetact_{\reg}(\evt_R) + i &=& \offsetact_{\reg}(\evt_W) + j
133131
\end{array}
134132
}{
135-
\X{tr} \vdash_{\loc}^{i,k} \evt_R \valueconsistent \evt_W
133+
\X{tr} \vdash_{\reg}^{i,k} \evt_R \valueconsistent \evt_W
136134
}
137135
138136
.. math::
139137
\frac{
140138
\begin{array}[b]{@{}c}
141139
\neg (\evt_R \prechb \evt_W) \\
142-
\syncact_{\loc}(\evt_W, \evt_R) \Rightarrow \evt_W \prechb \evt_R
140+
\syncact_{\reg}(\evt_W, \evt_R) \Rightarrow \evt_W \prechb \evt_R
143141
\end{array}
144142
\qquad
145143
\begin{array}[b]{@{}l@{}}
146-
\forall \evt'_W \in \writingact_{\loc}(\X{tr}),\\
147-
\quad \evt_W \prechb \evt'_W \prechb \evt_R \Rightarrow k \notin \rangeact_{\loc}(\evt'_W)
144+
\forall \evt'_W \in \writingact_{\reg}(\X{tr}),\\
145+
\quad \evt_W \prechb \evt'_W \prechb \evt_R \Rightarrow k \notin \rangeact_{\reg}(\evt'_W)
148146
\end{array}
149147
}{
150-
\X{tr} \vdash_{\loc}^k \evt_R \hbconsistent \evt_W
148+
\X{tr} \vdash_{\reg}^k \evt_R \hbconsistent \evt_W
151149
}
152150
153151
.. math::
154152
\frac{
155153
\begin{array}[b]{@{}l@{\qquad}l@{}}
156-
\forall \evt'_W \in \writingact_{\loc}(\X{tr}), \evt_W \prechb \evt_R \Rightarrow \\
157-
\quad \evt_W \prectot \evt'_W \prectot \evt_R \wedge \syncact_{\loc}(\evt_W, \evt_R) \Rightarrow \neg \syncact_{\loc}(\evt'_W, \evt_R) \\
158-
\quad \evt_W \prechb \evt'_W \prectot \evt_R \Rightarrow \neg\syncact_{\loc}(\evt'_W, \evt_R) \\
159-
\quad \evt_W \prectot \evt'_W \prechb \evt_R \Rightarrow \neg\syncact_{\loc}(\evt_W, \evt'_W)
154+
\forall \evt'_W \in \writingact_{\reg}(\X{tr}), \evt_W \prechb \evt_R \Rightarrow \\
155+
\quad \evt_W \prectot \evt'_W \prectot \evt_R \wedge \syncact_{\reg}(\evt_W, \evt_R) \Rightarrow \neg \syncact_{\reg}(\evt'_W, \evt_R) \\
156+
\quad \evt_W \prechb \evt'_W \prectot \evt_R \Rightarrow \neg\syncact_{\reg}(\evt'_W, \evt_R) \\
157+
\quad \evt_W \prectot \evt'_W \prechb \evt_R \Rightarrow \neg\syncact_{\reg}(\evt_W, \evt'_W)
160158
\end{array}
161159
}{
162-
\X{tr} \vdash_{\loc} \evt_R \sclastvisible \evt_W
160+
\X{tr} \vdash_{\reg} \evt_R \sclastvisible \evt_W
163161
}
164162
165163
.. math::
166164
\frac{
167-
\tearfreeact_{\loc}(\evt_R) \Rightarrow |\{\evt_W \in \evt_W^\ast ~|~ \sameact_{\loc}(\evt_R, \evt_W) \wedge \tearfreeact_{\loc}(\evt_W)\}| \leq 1
165+
\tearfreeact_{\reg}(\evt_R) \Rightarrow |\{\evt_W \in \evt_W^\ast ~|~ \sameact_{\reg}(\evt_R, \evt_W) \wedge \tearfreeact_{\reg}(\evt_W)\}| \leq 1
168166
}{
169-
\vdash_{\loc} \evt_R \notear \evt_W^\ast
167+
\vdash_{\reg} \evt_R \notear \evt_W^\ast
170168
}
171169
172170

document/core/exec/runtime.rst

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,7 @@ This definition allows to index active labels surrounding a :ref:`branch <syntax
666666
.. _syntax-act:
667667
.. _syntax-ord:
668668
.. _syntax-loc:
669+
.. _syntax-reg:
669670
.. _syntax-fld:
670671
.. _syntax-storeval:
671672

@@ -697,10 +698,12 @@ Each event is annotated with a :ref:`time stamp <syntax-time>` that uniquely ide
697698
\SEQCST ~|~
698699
\INIT \\
699700
\production{(location)} & \loc &::=&
701+
\reg[\u32] \\
702+
\production{(region)} & \reg &::=&
700703
\addr.\fld \\
701704
\production{(field)} & \fld &::=&
702705
\LLEN ~|~
703-
\LDATA[\u32] \\
706+
\LDATA \\
704707
\production{(store value)} & \storeval &::=&
705708
\val ~|~
706709
b^\ast \\
@@ -710,8 +713,7 @@ Each event is annotated with a :ref:`time stamp <syntax-time>` that uniquely ide
710713
.. todo:: remove spawn from events in a typed way?
711714

712715
The access of *mutable* shared state is performed through the |ARD|, |AWR|, and |ARMW| actions.
713-
Each action accesses an abstract *location*, which consists of an :ref:`address <syntax-addr>` of a :ref:`shared <syntax-shared>` :ref:`memory <syntax-meminst>` instance and a symbolic *field* name in the respective object.
714-
This is either |LLEN| for the size or |LDATA| for the vector of bytes.
716+
Each action accesses an abstract *location*, which consists of an :ref:`address <syntax-addr>` of a :ref:`shared <syntax-shared>` :ref:`memory <syntax-meminst>` instance, a symbolic *field* name in the respective object (either |LLEN| for the size or |LDATA| for the vector of bytes), and an offset index into the field.
715717

716718
In each case, read and write actions record the *store value* that has been read or written, which is either a regular :ref:`value <syntax-val>` or a sequence of :ref:`bytes <syntax-byte>`, depending on the location accessed.
717719
An |ARMW| event, performing an atomic read-modify-write access, records both the store values read (first) and written (second);
@@ -736,6 +738,8 @@ Conventions
736738

737739
* The actions :math:`\ARD_{\ord}` and :math:`\AWR_{\ord}` are abbreviated to just :math:`\ARD` and :math:`\AWR` when :math:`\ord` is :math:`\UNORD`.
738740

741+
* A location may syntactically elide its :math:`[\u32]` offset in the case that it is 0.
742+
739743
The following auxiliary definition is used to classify whether an access will *tear*.
740744

741745
.. math::

document/core/util/macros.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,7 @@
11061106
.. |hostact| mathdef:: \xref{exec/runtime}{syntax-act}{\X{hostact}}
11071107
.. |ord| mathdef:: \xref{exec/runtime}{syntax-ord}{\X{ord}}
11081108
.. |loc| mathdef:: \xref{exec/runtime}{syntax-loc}{\X{loc}}
1109+
.. |reg| mathdef:: \xref{exec/runtime}{syntax-reg}{\X{reg}}
11091110
.. |fld| mathdef:: \xref{exec/runtime}{syntax-fld}{\X{fld}}
11101111
.. |storeval| mathdef:: \xref{exec/runtime}{syntax-storeval}{\X{storeval}}
11111112
.. |notears| mathdef:: \xref{exec/runtime}{syntax-ord}{\X{notears}}

0 commit comments

Comments
 (0)