Skip to content

Commit 50a39dd

Browse files
committed
Refactor CABI Python code to remove 'Value' class, which wasn't really necessary
1 parent 26eac7b commit 50a39dd

File tree

3 files changed

+100
-97
lines changed

3 files changed

+100
-97
lines changed

design/mvp/CanonicalABI.md

Lines changed: 50 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,27 +1181,31 @@ def join(a, b):
11811181

11821182
### Flat Lifting
11831183

1184-
The `lift_flat` function defines how to convert zero or more core values into a
1185-
single high-level value of type `t`. The values are given by a value iterator
1186-
that iterates over a complete parameter or result list and asserts that the
1187-
expected and actual types line up. Presenting the definition of `lift_flat`
1188-
piecewise, we start with the top-level case analysis:
1184+
Values are lifted by iterating over a list of parameter or result Core
1185+
WebAssembly values:
11891186
```python
11901187
@dataclass
1191-
class Value:
1192-
t: str # 'i32'|'i64'|'f32'|'f64'
1193-
v: int|float
1194-
1195-
@dataclass
1196-
class ValueIter:
1197-
values: list[Value]
1188+
class CoreValueIter:
1189+
values: list[int|float]
11981190
i = 0
11991191
def next(self, t):
12001192
v = self.values[self.i]
12011193
self.i += 1
1202-
assert(v.t == t)
1203-
return v.v
1204-
1194+
match t:
1195+
case 'i32': assert(isinstance(v, int) and 0 <= v < 2**32)
1196+
case 'i64': assert(isinstance(v, int) and 0 <= v < 2**64)
1197+
case 'f32': assert(isinstance(v, (int,float)))
1198+
case 'f64': assert(isinstance(v, (int,float)))
1199+
case _ : assert(False)
1200+
return v
1201+
```
1202+
The `match` is only used for spec-level assertions; no runtime typecase is
1203+
required.
1204+
1205+
The `lift_flat` function defines how to convert a list of core values into a
1206+
single high-level value of type `t`. Presenting the definition of `lift_flat`
1207+
piecewise, we start with the top-level case analysis:
1208+
```python
12051209
def lift_flat(cx, vi, t):
12061210
match despecialize(t):
12071211
case Bool() : return convert_int_to_bool(vi.next('i32'))
@@ -1328,25 +1332,25 @@ piecewise, we start with the top-level case analysis:
13281332
```python
13291333
def lower_flat(cx, v, t):
13301334
match despecialize(t):
1331-
case Bool() : return [Value('i32', int(v))]
1332-
case U8() : return [Value('i32', v)]
1333-
case U16() : return [Value('i32', v)]
1334-
case U32() : return [Value('i32', v)]
1335-
case U64() : return [Value('i64', v)]
1335+
case Bool() : return [int(v)]
1336+
case U8() : return [v]
1337+
case U16() : return [v]
1338+
case U32() : return [v]
1339+
case U64() : return [v]
13361340
case S8() : return lower_flat_signed(v, 32)
13371341
case S16() : return lower_flat_signed(v, 32)
13381342
case S32() : return lower_flat_signed(v, 32)
13391343
case S64() : return lower_flat_signed(v, 64)
1340-
case F32() : return [Value('f32', maybe_scramble_nan32(v))]
1341-
case F64() : return [Value('f64', maybe_scramble_nan64(v))]
1342-
case Char() : return [Value('i32', char_to_i32(v))]
1344+
case F32() : return [maybe_scramble_nan32(v)]
1345+
case F64() : return [maybe_scramble_nan64(v)]
1346+
case Char() : return [char_to_i32(v)]
13431347
case String() : return lower_flat_string(cx, v)
13441348
case List(t) : return lower_flat_list(cx, v, t)
13451349
case Record(fields) : return lower_flat_record(cx, v, fields)
13461350
case Variant(cases) : return lower_flat_variant(cx, v, cases)
13471351
case Flags(labels) : return lower_flat_flags(v, labels)
1348-
case Own() : return [Value('i32', lower_own(cx, v, t))]
1349-
case Borrow() : return [Value('i32', lower_borrow(cx, v, t))]
1352+
case Own() : return [lower_own(cx, v, t)]
1353+
case Borrow() : return [lower_borrow(cx, v, t)]
13501354
```
13511355

13521356
Since component-level values are assumed in-range and, as previously stated,
@@ -1358,7 +1362,7 @@ would be a no-op in hardware):
13581362
def lower_flat_signed(i, core_bits):
13591363
if i < 0:
13601364
i += (1 << core_bits)
1361-
return [Value('i' + str(core_bits), i)]
1365+
return [i]
13621366
```
13631367

13641368
Since strings and lists are stored in linear memory, lifting can reuse the
@@ -1367,11 +1371,11 @@ previous definitions; only the resulting pointers are returned differently
13671371
```python
13681372
def lower_flat_string(cx, v):
13691373
ptr, packed_length = store_string_into_range(cx, v)
1370-
return [Value('i32', ptr), Value('i32', packed_length)]
1374+
return [ptr, packed_length]
13711375

13721376
def lower_flat_list(cx, v, elem_type):
13731377
(ptr, length) = store_list_into_range(cx, v, elem_type)
1374-
return [Value('i32', ptr), Value('i32', length)]
1378+
return [ptr, length]
13751379
```
13761380

13771381
Records are lowered by recursively lowering their fields:
@@ -1396,17 +1400,17 @@ def lower_flat_variant(cx, v, cases):
13961400
payload = []
13971401
else:
13981402
payload = lower_flat(cx, case_value, c.t)
1399-
for i,have in enumerate(payload):
1400-
want = flat_types.pop(0)
1401-
match (have.t, want):
1402-
case ('f32', 'i32') : payload[i] = Value('i32', encode_float_as_i32(have.v))
1403-
case ('i32', 'i64') : payload[i] = Value('i64', have.v)
1404-
case ('f32', 'i64') : payload[i] = Value('i64', encode_float_as_i32(have.v))
1405-
case ('f64', 'i64') : payload[i] = Value('i64', encode_float_as_i64(have.v))
1406-
case _ : pass
1407-
for want in flat_types:
1408-
payload.append(Value(want, 0))
1409-
return [Value('i32', case_index)] + payload
1403+
for i,(fv,have) in enumerate(zip(payload, flatten_type(c.t))):
1404+
want = flat_types.pop(0)
1405+
match (have, want):
1406+
case ('f32', 'i32') : payload[i] = encode_float_as_i32(fv)
1407+
case ('i32', 'i64') : payload[i] = fv
1408+
case ('f32', 'i64') : payload[i] = encode_float_as_i32(fv)
1409+
case ('f64', 'i64') : payload[i] = encode_float_as_i64(fv)
1410+
case _ : pass
1411+
for _ in flat_types:
1412+
payload.append(0)
1413+
return [case_index] + payload
14101414
```
14111415

14121416
Finally, flags are lowered by slicing the bit vector into `i32` chunks:
@@ -1415,7 +1419,7 @@ def lower_flat_flags(v, labels):
14151419
i = pack_flags_into_int(v, labels)
14161420
flat = []
14171421
for _ in range(num_i32_flags(labels)):
1418-
flat.append(Value('i32', i & 0xffffffff))
1422+
flat.append(i & 0xffffffff)
14191423
i >>= 32
14201424
assert(i == 0)
14211425
return flat
@@ -1424,8 +1428,8 @@ def lower_flat_flags(v, labels):
14241428
### Lifting and Lowering Values
14251429

14261430
The `lift_values` function defines how to lift a list of at most `max_flat`
1427-
core parameters or results given by the `ValueIter` `vi` into a tuple of values
1428-
with types `ts`:
1431+
core parameters or results given by the `CoreValueIter` `vi` into a tuple of
1432+
values with types `ts`:
14291433
```python
14301434
def lift_values(cx, max_flat, vi, ts):
14311435
flat_types = flatten_types(ts)
@@ -1457,7 +1461,7 @@ def lower_values(cx, max_flat, vs, ts, out_param = None):
14571461
trap_if(ptr != align_to(ptr, alignment(tuple_type)))
14581462
trap_if(ptr + size(tuple_type) > len(cx.opts.memory))
14591463
store(cx, tuple_value, tuple_type, ptr)
1460-
return [ Value('i32', ptr) ]
1464+
return [ptr]
14611465
else:
14621466
flat_vals = []
14631467
for i in range(len(vs)):
@@ -1517,7 +1521,7 @@ def canon_lift(opts, inst, callee, ft, args):
15171521
except CoreWebAssemblyException:
15181522
trap()
15191523

1520-
results = lift_values(cx, MAX_FLAT_RESULTS, ValueIter(flat_results), ft.result_types())
1524+
results = lift_values(cx, MAX_FLAT_RESULTS, CoreValueIter(flat_results), ft.result_types())
15211525

15221526
def post_return():
15231527
if opts.post_return is not None:
@@ -1564,7 +1568,7 @@ def canon_lower(opts, inst, callee, calling_import, ft, flat_args):
15641568
if calling_import:
15651569
inst.may_enter = False
15661570

1567-
flat_args = ValueIter(flat_args)
1571+
flat_args = CoreValueIter(flat_args)
15681572
args = lift_values(cx, MAX_FLAT_PARAMS, flat_args, ft.param_types())
15691573

15701574
results, post_return = callee(args)
@@ -1713,7 +1717,7 @@ validation specifies:
17131717
> Currently, that would require additional work in the toolchain to support so,
17141718
> for simplicity, the current proposal simply fixes a single `i32` parameter type.
17151719
> However, `thread.spawn` could be extended to allow arbitrary thread parameters
1716-
> in the future, once it's concretely beneficial to the toolchain.
1720+
> in the future, once it's concretely beneficial to the toolchain.
17171721
> The inclusion of `$ft` ensures backwards compatibility for when arbitrary
17181722
> parameters are allowed.
17191723

design/mvp/canonical-abi/definitions.py

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -890,19 +890,19 @@ def join(a, b):
890890
### Flat Lifting
891891

892892
@dataclass
893-
class Value:
894-
t: str # 'i32'|'i64'|'f32'|'f64'
895-
v: int|float
896-
897-
@dataclass
898-
class ValueIter:
899-
values: list[Value]
893+
class CoreValueIter:
894+
values: list[int|float]
900895
i = 0
901896
def next(self, t):
902897
v = self.values[self.i]
903898
self.i += 1
904-
assert(v.t == t)
905-
return v.v
899+
match t:
900+
case 'i32': assert(isinstance(v, int) and 0 <= v < 2**32)
901+
case 'i64': assert(isinstance(v, int) and 0 <= v < 2**64)
902+
case 'f32': assert(isinstance(v, (int,float)))
903+
case 'f64': assert(isinstance(v, (int,float)))
904+
case _ : assert(False)
905+
return v
906906

907907
def lift_flat(cx, vi, t):
908908
match despecialize(t):
@@ -995,38 +995,38 @@ def lift_flat_flags(vi, labels):
995995

996996
def lower_flat(cx, v, t):
997997
match despecialize(t):
998-
case Bool() : return [Value('i32', int(v))]
999-
case U8() : return [Value('i32', v)]
1000-
case U16() : return [Value('i32', v)]
1001-
case U32() : return [Value('i32', v)]
1002-
case U64() : return [Value('i64', v)]
998+
case Bool() : return [int(v)]
999+
case U8() : return [v]
1000+
case U16() : return [v]
1001+
case U32() : return [v]
1002+
case U64() : return [v]
10031003
case S8() : return lower_flat_signed(v, 32)
10041004
case S16() : return lower_flat_signed(v, 32)
10051005
case S32() : return lower_flat_signed(v, 32)
10061006
case S64() : return lower_flat_signed(v, 64)
1007-
case F32() : return [Value('f32', maybe_scramble_nan32(v))]
1008-
case F64() : return [Value('f64', maybe_scramble_nan64(v))]
1009-
case Char() : return [Value('i32', char_to_i32(v))]
1007+
case F32() : return [maybe_scramble_nan32(v)]
1008+
case F64() : return [maybe_scramble_nan64(v)]
1009+
case Char() : return [char_to_i32(v)]
10101010
case String() : return lower_flat_string(cx, v)
10111011
case List(t) : return lower_flat_list(cx, v, t)
10121012
case Record(fields) : return lower_flat_record(cx, v, fields)
10131013
case Variant(cases) : return lower_flat_variant(cx, v, cases)
10141014
case Flags(labels) : return lower_flat_flags(v, labels)
1015-
case Own() : return [Value('i32', lower_own(cx, v, t))]
1016-
case Borrow() : return [Value('i32', lower_borrow(cx, v, t))]
1015+
case Own() : return [lower_own(cx, v, t)]
1016+
case Borrow() : return [lower_borrow(cx, v, t)]
10171017

10181018
def lower_flat_signed(i, core_bits):
10191019
if i < 0:
10201020
i += (1 << core_bits)
1021-
return [Value('i' + str(core_bits), i)]
1021+
return [i]
10221022

10231023
def lower_flat_string(cx, v):
10241024
ptr, packed_length = store_string_into_range(cx, v)
1025-
return [Value('i32', ptr), Value('i32', packed_length)]
1025+
return [ptr, packed_length]
10261026

10271027
def lower_flat_list(cx, v, elem_type):
10281028
(ptr, length) = store_list_into_range(cx, v, elem_type)
1029-
return [Value('i32', ptr), Value('i32', length)]
1029+
return [ptr, length]
10301030

10311031
def lower_flat_record(cx, v, fields):
10321032
flat = []
@@ -1043,23 +1043,23 @@ def lower_flat_variant(cx, v, cases):
10431043
payload = []
10441044
else:
10451045
payload = lower_flat(cx, case_value, c.t)
1046-
for i,have in enumerate(payload):
1047-
want = flat_types.pop(0)
1048-
match (have.t, want):
1049-
case ('f32', 'i32') : payload[i] = Value('i32', encode_float_as_i32(have.v))
1050-
case ('i32', 'i64') : payload[i] = Value('i64', have.v)
1051-
case ('f32', 'i64') : payload[i] = Value('i64', encode_float_as_i32(have.v))
1052-
case ('f64', 'i64') : payload[i] = Value('i64', encode_float_as_i64(have.v))
1053-
case _ : pass
1054-
for want in flat_types:
1055-
payload.append(Value(want, 0))
1056-
return [Value('i32', case_index)] + payload
1046+
for i,(fv,have) in enumerate(zip(payload, flatten_type(c.t))):
1047+
want = flat_types.pop(0)
1048+
match (have, want):
1049+
case ('f32', 'i32') : payload[i] = encode_float_as_i32(fv)
1050+
case ('i32', 'i64') : payload[i] = fv
1051+
case ('f32', 'i64') : payload[i] = encode_float_as_i32(fv)
1052+
case ('f64', 'i64') : payload[i] = encode_float_as_i64(fv)
1053+
case _ : pass
1054+
for _ in flat_types:
1055+
payload.append(0)
1056+
return [case_index] + payload
10571057

10581058
def lower_flat_flags(v, labels):
10591059
i = pack_flags_into_int(v, labels)
10601060
flat = []
10611061
for _ in range(num_i32_flags(labels)):
1062-
flat.append(Value('i32', i & 0xffffffff))
1062+
flat.append(i & 0xffffffff)
10631063
i >>= 32
10641064
assert(i == 0)
10651065
return flat
@@ -1089,7 +1089,7 @@ def lower_values(cx, max_flat, vs, ts, out_param = None):
10891089
trap_if(ptr != align_to(ptr, alignment(tuple_type)))
10901090
trap_if(ptr + size(tuple_type) > len(cx.opts.memory))
10911091
store(cx, tuple_value, tuple_type, ptr)
1092-
return [ Value('i32', ptr) ]
1092+
return [ptr]
10931093
else:
10941094
flat_vals = []
10951095
for i in range(len(vs)):
@@ -1112,7 +1112,7 @@ def canon_lift(opts, inst, callee, ft, args):
11121112
except CoreWebAssemblyException:
11131113
trap()
11141114

1115-
results = lift_values(cx, MAX_FLAT_RESULTS, ValueIter(flat_results), ft.result_types())
1115+
results = lift_values(cx, MAX_FLAT_RESULTS, CoreValueIter(flat_results), ft.result_types())
11161116

11171117
def post_return():
11181118
if opts.post_return is not None:
@@ -1131,7 +1131,7 @@ def canon_lower(opts, inst, callee, calling_import, ft, flat_args):
11311131
if calling_import:
11321132
inst.may_enter = False
11331133

1134-
flat_args = ValueIter(flat_args)
1134+
flat_args = CoreValueIter(flat_args)
11351135
args = lift_values(cx, MAX_FLAT_PARAMS, flat_args, ft.param_types())
11361136

11371137
results, post_return = callee(args)

0 commit comments

Comments
 (0)