@@ -1181,27 +1181,31 @@ def join(a, b):
1181
1181
1182
1182
### Flat Lifting
1183
1183
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:
1189
1186
``` python
1190
1187
@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 ]
1198
1190
i = 0
1199
1191
def next (self , t ):
1200
1192
v = self .values[self .i]
1201
1193
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
1205
1209
def lift_flat (cx , vi , t ):
1206
1210
match despecialize(t):
1207
1211
case Bool() : return convert_int_to_bool(vi.next(' i32' ))
@@ -1328,25 +1332,25 @@ piecewise, we start with the top-level case analysis:
1328
1332
``` python
1329
1333
def lower_flat (cx , v , t ):
1330
1334
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 ]
1336
1340
case S8() : return lower_flat_signed(v, 32 )
1337
1341
case S16() : return lower_flat_signed(v, 32 )
1338
1342
case S32() : return lower_flat_signed(v, 32 )
1339
1343
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)]
1343
1347
case String() : return lower_flat_string(cx, v)
1344
1348
case List(t) : return lower_flat_list(cx, v, t)
1345
1349
case Record(fields) : return lower_flat_record(cx, v, fields)
1346
1350
case Variant(cases) : return lower_flat_variant(cx, v, cases)
1347
1351
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)]
1350
1354
```
1351
1355
1352
1356
Since component-level values are assumed in-range and, as previously stated,
@@ -1358,7 +1362,7 @@ would be a no-op in hardware):
1358
1362
def lower_flat_signed (i , core_bits ):
1359
1363
if i < 0 :
1360
1364
i += (1 << core_bits)
1361
- return [Value( ' i ' + str (core_bits), i) ]
1365
+ return [i ]
1362
1366
```
1363
1367
1364
1368
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
1367
1371
``` python
1368
1372
def lower_flat_string (cx , v ):
1369
1373
ptr, packed_length = store_string_into_range(cx, v)
1370
- return [Value( ' i32 ' , ptr), Value( ' i32 ' , packed_length) ]
1374
+ return [ptr, packed_length]
1371
1375
1372
1376
def lower_flat_list (cx , v , elem_type ):
1373
1377
(ptr, length) = store_list_into_range(cx, v, elem_type)
1374
- return [Value( ' i32 ' , ptr), Value( ' i32 ' , length) ]
1378
+ return [ptr, length]
1375
1379
```
1376
1380
1377
1381
Records are lowered by recursively lowering their fields:
@@ -1396,17 +1400,17 @@ def lower_flat_variant(cx, v, cases):
1396
1400
payload = []
1397
1401
else :
1398
1402
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
1410
1414
```
1411
1415
1412
1416
Finally, flags are lowered by slicing the bit vector into ` i32 ` chunks:
@@ -1415,7 +1419,7 @@ def lower_flat_flags(v, labels):
1415
1419
i = pack_flags_into_int(v, labels)
1416
1420
flat = []
1417
1421
for _ in range (num_i32_flags(labels)):
1418
- flat.append(Value( ' i32 ' , i & 0x ffffffff) )
1422
+ flat.append(i & 0x ffffffff )
1419
1423
i >>= 32
1420
1424
assert (i == 0 )
1421
1425
return flat
@@ -1424,8 +1428,8 @@ def lower_flat_flags(v, labels):
1424
1428
### Lifting and Lowering Values
1425
1429
1426
1430
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 ` :
1429
1433
``` python
1430
1434
def lift_values (cx , max_flat , vi , ts ):
1431
1435
flat_types = flatten_types(ts)
@@ -1457,7 +1461,7 @@ def lower_values(cx, max_flat, vs, ts, out_param = None):
1457
1461
trap_if(ptr != align_to(ptr, alignment(tuple_type)))
1458
1462
trap_if(ptr + size(tuple_type) > len (cx.opts.memory))
1459
1463
store(cx, tuple_value, tuple_type, ptr)
1460
- return [ Value( ' i32 ' , ptr) ]
1464
+ return [ptr]
1461
1465
else :
1462
1466
flat_vals = []
1463
1467
for i in range (len (vs)):
@@ -1517,7 +1521,7 @@ def canon_lift(opts, inst, callee, ft, args):
1517
1521
except CoreWebAssemblyException:
1518
1522
trap()
1519
1523
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())
1521
1525
1522
1526
def post_return ():
1523
1527
if opts.post_return is not None :
@@ -1564,7 +1568,7 @@ def canon_lower(opts, inst, callee, calling_import, ft, flat_args):
1564
1568
if calling_import:
1565
1569
inst.may_enter = False
1566
1570
1567
- flat_args = ValueIter (flat_args)
1571
+ flat_args = CoreValueIter (flat_args)
1568
1572
args = lift_values(cx, MAX_FLAT_PARAMS , flat_args, ft.param_types())
1569
1573
1570
1574
results, post_return = callee(args)
@@ -1713,7 +1717,7 @@ validation specifies:
1713
1717
> Currently, that would require additional work in the toolchain to support so,
1714
1718
> for simplicity, the current proposal simply fixes a single ` i32 ` parameter type.
1715
1719
> 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.
1717
1721
> The inclusion of ` $ft ` ensures backwards compatibility for when arbitrary
1718
1722
> parameters are allowed.
1719
1723
0 commit comments