Skip to content

Commit 25c19bb

Browse files
authored
Merge pull request #19451 from jrose-apple/stable-view
[Serialization] Give swiftdocs a stable version
2 parents 8315c30 + 76e5488 commit 25c19bb

20 files changed

+895
-635
lines changed

docs/StableBitcode.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Making Backwards-Compatible Changes in the LLVM Bitstream Format
2+
3+
Swift uses the [LLVM bitstream][] format for some of its serialization logic. This format was invented as a container for LLVM IR. It is a binary format supporting two basic structures: *blocks,* which define regions of the file, and *records,* which contain data fields that can be up to 64 bits. It has a few nice properties that make it a useful container format for us as well:
4+
5+
- It is easy to skip over an entire block, because the block's length is recorded at its start.
6+
7+
- It is possible to jump to specific offsets *within* a block without having to reparse from the start of the block.
8+
9+
- A format change doesn't immediately invalidate existing bitstream files, because the stream includes layout information for each record.
10+
11+
However, it has some disadvantages as well:
12+
13+
- Each record can only contain one variable-sized entry (either an array or a "blob" of bytes).
14+
15+
- Higher-level features like cross-references or lookup by key have to be built on top of the format, usually in a way that the existing tooling doesn't understand.
16+
17+
You can view the contents of any LLVM bitstream using the `llvm-bcanalyzer` tool's `-dump` option.
18+
19+
[LLVM bitstream]: http://llvm.org/docs/BitCodeFormat.html
20+
21+
22+
## Backwards-compatibility
23+
24+
For a format change to be backwards-compatible, we need the v5 tools to be able to read a file generated by the v6 tools. At a high level, this means that whatever data is introduced in v6, it doesn't interfere with what v5 is looking for.
25+
26+
(We also care about *forwards*-compatibility, which says that the v6 tools is able to read a file generated by the v5 tools. This is usually easier to maintain, because the v5 format is already known.)
27+
28+
In practice, there are a few ways to accomplish this with LLVM bitstreams:
29+
30+
- If the deserialization logic is set to skip over any blocks it doesn't understand, a new format can always add new blocks.
31+
32+
- If the deserialization logic is set to skip over any *records* it doesn't understand, a new format can always add new *records.* Be careful, though, of records that are expected to appear immediately after another record---if you put a new record between them, you may break the expectations of older compilers.
33+
34+
- If the deserialization logic always looks for a possible blob entry in records (i.e. passing a StringRef out-parameter to BitstreamCursor's `readRecord`), a new format can add blob data to an existing record that does not have it.
35+
36+
- If the deserialization logic always checks for a minimum number of fields in a record before extracting those fields, or if the only field in a record is blob data, a new format can add new fields to an existing record, as long as they come after any existing non-blob fields.
37+
38+
Note that the BCRecordLayout DSL expects the number of fields to **match exactly**. If you want to use BCRecordLayout's `readRecord` method, the deserialization logic will have to check that the deserialized data has the correct number of fields ahead of time. If it has more fields, you can make an ArrayRef that slices off the extra ones; if it has fewer, you're reading from an old format and will need to use a different BCRecordLayout, or just read them manually.
39+
40+
(We could also add more API to BCRecordLayout to make this easier. It's part of LLVM, but it's a part of LLVM originally contributed by Swift folks.)
41+
42+
Note also that it's still okay to use BCRecordLayout for *serialization.* It's only deserialization where we have to be careful about multiple formats.
43+
44+
Remember that any new data will be *ignored* by the old tools. If it's something that *should* affect how old tools read the file, it must be encoded in an existing field; if that's impossible, you have a backwards-incompatible change and should bump the major version number of the file.
45+
46+
If the existing deserialization logic is already checking for the exact size of a record (and therefore preventing new fields from being added), one trick is to put a second record after the first, and check for its presence in the new version of the tools. As long as the old logic is set up to skip unknown records, this shouldn't cause any problems.

include/swift/Serialization/DeclTypeRecordNodes.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777
#endif
7878

7979
// These IDs must \em not be renumbered or reordered without incrementing
80-
// VERSION_MAJOR in ModuleFormat.h. Names, however, may change.
80+
// the version in ModuleFormat.h. Names, however, may change.
8181
FIRST_TYPE(BUILTIN_ALIAS, 1)
8282
TYPE(GENERIC_TYPE_PARAM)
8383
TYPE(DEPENDENT_MEMBER)

include/swift/Serialization/ModuleFile.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,11 @@ class ModuleFile
548548
/// Returns false if there was an error.
549549
bool readCommentBlock(llvm::BitstreamCursor &cursor);
550550

551+
/// Loads data from #ModuleDocInputBuffer.
552+
///
553+
/// Returns false if there was an error.
554+
bool readModuleDocIfPresent();
555+
551556
/// Recursively reads a pattern from \c DeclTypeCursor.
552557
llvm::Expected<Pattern *> readPattern(DeclContext *owningDC);
553558

@@ -626,6 +631,9 @@ class ModuleFile
626631
theModule.reset(new ModuleFile(std::move(moduleInputBuffer),
627632
std::move(moduleDocInputBuffer),
628633
isFramework, info, extInfo));
634+
assert(info.status == Status::Valid ||
635+
info.status == theModule->getStatus());
636+
info.status = theModule->getStatus();
629637
return info;
630638
}
631639

0 commit comments

Comments
 (0)