@@ -14,14 +14,12 @@ from raw bytes to typed `Value` objects according to Rust's memory layout rules.
1414requires "../ty.md"
1515requires "value.md"
1616requires "numbers.md"
17- requires "../alloc.md"
1817
1918module RT-DECODING
2019 imports BOOL
2120 imports MAP
2221
2322 imports TYPES
24- imports ALLOC
2523 imports RT-VALUE-SYNTAX
2624 imports RT-NUMBERS
2725 imports RT-TYPES
@@ -37,9 +35,9 @@ and arrays (where layout is trivial).
3735### Decoding ` PrimitiveType ` s
3836
3937``` k
40- syntax Evaluation ::= #decodeValue ( Bytes , TypeInfo , Map ) [function, total, symbol(decodeValue)]
41- | UnableToDecodeValue ( Bytes , TypeInfo ) [symbol(Evaluation::UnableToDecodeValue )]
42- | UnableToDecodeAlloc( Bytes , Ty , ProvenanceMapEntries ) [symbol(Evaluation::UnableToDecodeAlloc )]
38+ syntax Evaluation ::= #decodeValue ( Bytes , TypeInfo , Map ) [function, total, symbol(decodeValue)]
39+ | UnableToDecode ( Bytes , TypeInfo ) [symbol(Evaluation::UnableToDecode )]
40+ | UnableToDecodePy ( msg: String ) [symbol(Evaluation::UnableToDecodePy )]
4341
4442 // Boolean: should be one byte with value one or zero
4543 rule #decodeValue(BYTES, typeInfoPrimitiveType(primTypeBool), _TYPEMAP) => BoolVal(false)
@@ -83,7 +81,7 @@ rule #decodeValue(BYTES, typeInfoArrayType(ELEMTY, noTyConst), TYPEMAP)
8381All unimplemented cases will become thunks by way of this default rule:
8482
8583``` k
86- rule #decodeValue(BYTES, TYPEINFO, _TYPEMAP) => UnableToDecodeValue (BYTES, TYPEINFO) [owise]
84+ rule #decodeValue(BYTES, TYPEINFO, _TYPEMAP) => UnableToDecode (BYTES, TYPEINFO) [owise]
8785```
8886
8987## Helper function to determine the expected byte length for a type
@@ -283,100 +281,6 @@ by the element size, then uses the same element-by-element decoding approach as
283281 [preserves-definedness]
284282```
285283
286- # Decoding the allocated constants into a memory map
287-
288- When the program starts, all allocated constants are stored in the ` <memory> ` cell in the configuration,
289- as a mapping of ` AllocId -> Value ` , decoding the allocations to values using the above functions.
290-
291- Besides actual byte allocations, we often find allocations with provenance,
292- as slim or fat pointers pointing to other static allocations.
293- One example of this is allocated error strings, whose length is stored in a fat pointer that is itself an allocated constant.
294-
295-
296- The basic decoding function is very similar to ` #decodeConstant ` but returns its result as a singleton ` Map ` instead of a mere value.
297-
298- ``` k
299- syntax Map ::= #decodeAlloc ( AllocId , Ty , Allocation , Map ) [function] // returns AllocId |-> Value
300- // ----------------------------------------------------------
301- rule #decodeAlloc(ID, TY, allocation(BYTES, provenanceMap(.ProvenanceMapEntries), _ALIGN, _MUT), TYPEMAP)
302- => ID |-> #decodeValue(BYTES, {TYPEMAP[TY]}:>TypeInfo, TYPEMAP)
303- requires TY in_keys(TYPEMAP)
304- andBool isTypeInfo(TYPEMAP[TY])
305- ```
306-
307- If there are entries in the provenance map, then the decoder must create references to other allocations.
308- Each entry replaces a pointer starting at a certain offset in the bytes.
309- The pointee of the respective pointer is determined by type _ layout_ of the type to decode.
310-
311- Simple cases of offset 0 and reference types can be implemented here without consideration of layout.
312- The reference metadata is either determined statically by type, or filled in from the bytes for fat pointers.
313-
314- ``` k
315- // if length(BYTES) ==Int 16 decode BYTES[9..16] as dynamic size.
316- rule #decodeAlloc(
317- ID,
318- TY,
319- allocation(BYTES, provenanceMap(provenanceMapEntry(0, REF_ID) ), _ALIGN, _MUT),
320- TYPEMAP
321- )
322- => ID |-> AllocRef(REF_ID, .ProjectionElems, dynamicSize(Bytes2Int(substrBytes(BYTES, 8, 16), LE, Unsigned)))
323- requires TY in_keys(TYPEMAP)
324- andBool isTypeInfo(TYPEMAP[TY])
325- andBool isTy(pointeeTy({TYPEMAP[TY]}:>TypeInfo)) // ensures this is a reference type
326- andBool lengthBytes(BYTES) ==Int 16 // sufficient data to decode dynamic size (assumes usize == u64)
327- andBool dynamicSize(1) ==K #metadata(pointeeTy({TYPEMAP[TY]}:>TypeInfo), TYPEMAP) // expect fat pointer
328- [preserves-definedness] // valid type lookup ensured
329-
330- // Otherwise query type information for static size and insert it.
331- rule #decodeAlloc(
332- ID,
333- TY,
334- allocation(BYTES, provenanceMap(provenanceMapEntry(0, REF_ID) ), _ALIGN, _MUT),
335- TYPEMAP
336- )
337- => ID |-> AllocRef(REF_ID, .ProjectionElems, #metadata(pointeeTy({TYPEMAP[TY]}:>TypeInfo), TYPEMAP))
338- requires TY in_keys(TYPEMAP)
339- andBool isTypeInfo(TYPEMAP[TY])
340- andBool isTy(pointeeTy({TYPEMAP[TY]}:>TypeInfo)) // ensures this is a reference type
341- andBool lengthBytes(BYTES) ==Int 8 // single slim pointer (assumes usize == u64)
342- [priority(60), preserves-definedness] // valid type lookup ensured
343- ```
344-
345- Allocations with more than one provenance map entry or witn non-reference types remain undecoded.
346-
347- ``` k
348- rule #decodeAlloc(ID, TY, allocation(BYTES, provenanceMap(ENTRIES), _ALIGN, _MUT), _TYPEMAP)
349- => ID |-> UnableToDecodeAlloc(BYTES, TY, ENTRIES)
350- [owise]
351- ```
352-
353- The entire set of ` GlobalAllocs ` is decoded by iterating over the list.
354- It is assumed that the given ` Ty -> TypeInfo ` map contains all types required.
355-
356- ``` k
357- syntax Map ::= #decodeAllocs ( GlobalAllocs , Map ) [function, total, symbol("decodeAllocs") ] // AllocId |-> Thing
358- | #decodeAllocsAux ( Map , GlobalAllocs , Map ) [function, total, symbol("decodeAllocsAux")] // accumulating version
359- // -----------------------------------------------------------------------------------------------
360- rule #decodeAllocs(ALLOCS, TYPEMAP) => #decodeAllocsAux(.Map, ALLOCS, TYPEMAP)
361-
362- rule #decodeAllocsAux(ACCUM, .GlobalAllocs, _TYPEMAP) => ACCUM
363- rule #decodeAllocsAux(ACCUM, globalAllocEntry(ID, TY, Memory(ALLOC)) ALLOCS, TYPEMAP)
364- => #decodeAllocsAux(ACCUM #decodeAlloc(ID, TY, ALLOC, TYPEMAP), ALLOCS, TYPEMAP)
365- requires TY in_keys(TYPEMAP)
366- [preserves-definedness]
367- ```
368-
369- If the type of an alloc cannot be found, or for non-` Memory ` allocs, the raw data is stored in a super-sort of ` Value ` .
370- This ensures that the function is total (anyway lookups require constraining the sort).
371-
372- ``` k
373- syntax AllocData ::= Value | AllocData ( Ty , GlobalAllocKind )
374-
375- rule #decodeAllocsAux(ACCUM, globalAllocEntry(ID, TY, OTHER) ALLOCS, TYPEMAP)
376- => #decodeAllocsAux(ACCUM ID |-> AllocData(TY, OTHER), ALLOCS, TYPEMAP)
377- [owise]
378- ```
379-
380284``` k
381285endmodule
382286```
0 commit comments