Skip to content

Notes on Runtime Library

Robin Sommer edited this page Apr 29, 2020 · 11 revisions

Some pieces of the HILTI/Spicy runtime libraries come with some specific constraints and/or design goals. We collect some notes on that here.

libhilti-rt

Types

Iterable containers (bytes/list/map/set/stream/vector)

  • Our iterator interfaces aren't standard compliant at the moment, we should make them so.

  • Different from iterators in the C++ standard library, we need iterators to be safe against undefined behavior. We want the following semantics:

    • An existing iterator must generally remain valid as long as the underlying container sticks around.

    • An existing iterator becomes invalid in two cases:

      1. The underlying container gets destroyed.
      2. Due to container changes, the iterator's current position semantically does not "make sense" anymore. For example, a vector iterator pointing to an index i will be invalid once the vector shrinks to less than i+1 elements. (Note the "semantically" here: For example, resizing of a vector's internal array should not invalidate any iterators.)
    • Once invalid, any attempt to deference an iterator must throw an exception.

    • Even when invalid, iterator operations other than dereferencing should remain supported. For example, if one keep incrementing a vector iterator beyond the vector's size, it may eventually become valid again if the vector grows sufficiently. (This property is particularly important for streams; we'll discuss that further down below.)

    • As the previous bullet suggests, it is possible for an invalid iterator to become valid once more if the container changes accordingly.

    • Iterators must not prevent their underlying containers from being destroyed (e.g., they can't store a strong reference to the container, as that would force it to stay around until the iterator dies.)

  • These safe properties came with some overhead.

    • Generally we accept that overhead.

    • Internally, however, we should avoid the overhead where we safely can. For example, if another part of libhilti-rt executes an iteration over a bytes instance where iterators can't become invalid while the operation is in progress, we should just skip the safety checks (this is the reason for the current "Safe" vs "Non-Safe" iterators; but not sure that's the best way to approach it).

    • Longer-term, the code generator could make use of such "unsafe" paths as well in cases where it can guarantee that the safety properties are still maintained by the particular code being generated.