Skip to content

Commit 6d0c9de

Browse files
authored
Merge pull request #18792 from ahoppen/swift-5.0-branch
[5.0] Cherry pick swiftSyntax related changes to swift-5.0-branch
2 parents 622a366 + dd006f1 commit 6d0c9de

File tree

117 files changed

+4401
-2869
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

117 files changed

+4401
-2869
lines changed

cmake/modules/AddSwift.cmake

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2022,7 +2022,7 @@ function(_add_swift_executable_single name)
20222022
cmake_parse_arguments(SWIFTEXE_SINGLE
20232023
"EXCLUDE_FROM_ALL;DONT_STRIP_NON_MAIN_SYMBOLS;DISABLE_ASLR"
20242024
"SDK;ARCHITECTURE"
2025-
"DEPENDS;LLVM_COMPONENT_DEPENDS;LINK_LIBRARIES;LINK_FAT_LIBRARIES"
2025+
"DEPENDS;LLVM_COMPONENT_DEPENDS;LINK_LIBRARIES;LINK_FAT_LIBRARIES;COMPILE_FLAGS"
20262026
${ARGN})
20272027

20282028
set(SWIFTEXE_SINGLE_SOURCES ${SWIFTEXE_SINGLE_UNPARSED_ARGUMENTS})
@@ -2096,6 +2096,7 @@ function(_add_swift_executable_single name)
20962096
MODULE_NAME ${name}
20972097
SDK ${SWIFTEXE_SINGLE_SDK}
20982098
ARCHITECTURE ${SWIFTEXE_SINGLE_ARCHITECTURE}
2099+
COMPILE_FLAGS ${SWIFTEXE_SINGLE_COMPILE_FLAGS}
20992100
IS_MAIN)
21002101
add_swift_source_group("${SWIFTEXE_SINGLE_EXTERNAL_SOURCES}")
21012102

@@ -2260,7 +2261,7 @@ function(add_swift_executable name)
22602261
cmake_parse_arguments(SWIFTEXE
22612262
"EXCLUDE_FROM_ALL;DONT_STRIP_NON_MAIN_SYMBOLS;DISABLE_ASLR"
22622263
""
2263-
"DEPENDS;LLVM_COMPONENT_DEPENDS;LINK_LIBRARIES"
2264+
"DEPENDS;LLVM_COMPONENT_DEPENDS;LINK_LIBRARIES;COMPILE_FLAGS"
22642265
${ARGN})
22652266

22662267
translate_flag(${SWIFTEXE_EXCLUDE_FROM_ALL}
@@ -2283,6 +2284,7 @@ function(add_swift_executable name)
22832284
LINK_LIBRARIES ${SWIFTEXE_LINK_LIBRARIES}
22842285
SDK ${SWIFT_HOST_VARIANT_SDK}
22852286
ARCHITECTURE ${SWIFT_HOST_VARIANT_ARCH}
2287+
COMPILE_FLAGS ${SWIFTEXE_COMPILE_FLAGS}
22862288
${SWIFTEXE_EXCLUDE_FROM_ALL_FLAG}
22872289
${SWIFTEXE_DONT_STRIP_NON_MAIN_SYMBOLS_FLAG}
22882290
${SWIFTEXE_DISABLE_ASLR_FLAG})
@@ -2301,11 +2303,16 @@ function(add_swift_host_tool executable)
23012303
ADDSWIFTHOSTTOOL # prefix
23022304
"" # options
23032305
"" # single-value args
2304-
"SWIFT_COMPONENT" # multi-value args
2306+
"SWIFT_COMPONENT;COMPILE_FLAGS;DEPENDS" # multi-value args
23052307
${ARGN})
23062308

23072309
# Create the executable rule.
2308-
add_swift_executable(${executable} ${ADDSWIFTHOSTTOOL_UNPARSED_ARGUMENTS})
2310+
add_swift_executable(
2311+
${executable}
2312+
${ADDSWIFTHOSTTOOL_UNPARSED_ARGUMENTS}
2313+
DEPENDS ${ADDSWIFTHOSTTOOL_DEPENDS}
2314+
COMPILE_FLAGS ${ADDSWIFTHOSTTOOL_COMPILE_FLAGS}
2315+
)
23092316

23102317
# And then create the install rule if we are asked to.
23112318
if (ADDSWIFTHOSTTOOL_SWIFT_COMPONENT)

docs/ByteTree.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# ByteTree
2+
3+
The ByteTree format is a binary format to efficiently serialize and deserialize trees. It was designed to serialize the syntax tree in `libSyntax` but the framework allows serialisation of arbitrary trees. It currently offers a serialiser written in C++ and a deserialiser written in Swift.
4+
5+
## Overview
6+
The ByteTree format consists of two different constructs: *objects* and *scalars*. A scalar is a raw sequence of binary data. Scalars are untyped and the meaning of their binary data needs to be inferred by the client based on their position in the tree. An object consists of multiple *fields*, indexed by their position within the object, which again can be either objects or scalars.
7+
8+
## Serialization of scalars
9+
10+
A scalar is encoded as its size followed by the data. Size is a `uint_32` that represents the size of the data in bytes in little endian order.
11+
12+
For example, the string "Hello World" would be encoded as `(uint32_t)11` `"Hello World"`, or in hex `0B 00 00 00 48 65 6C 6C 6F 20 57 6F 72 6C 64`.
13+
14+
## Serialization of objects
15+
16+
An object consists of its size, measured in the number of fields and represented as a `uint_32t` in little endian order, followed by the direct concatenation of its fields. Because each field is again prefixed with its size, no delimites are necessary in between the fields.
17+
18+
Arrays are modelled as objects whose fields are all of the same type and whose length is variadic (and is indicated by the object's size).
19+
20+
## Versioning
21+
22+
The ByteTree format is prepended by a 4-byte protocol version number that describes the version of the object tree that was serialized. Its exact semantics are up to each specific application, but it is encouraged to interpret it as a two-comentent number where the first component, consisting of the first three bytes, is incremented for breaking changes and the last byte is incremented for backwards-compatible changes.
23+
24+
## Serialization safety
25+
26+
Since all fields in objects are accessed by their index, issues quickly arise if a new field is accidentally added at the beginning of an object. To prevent issues like this, the ByteTree serialiser and deserialiser requires the explicit specification of each field's index within the object. These indicies are never serialised. Their sole purpose is to check that all fields are read in the correct order in assertion builds.
Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
//===--- ByteTreeSerialization.h - ByteTree serialization -------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
/// \file
14+
/// \brief Provides an interface for serializing an object tree to a custom
15+
/// binary format called ByteTree.
16+
///
17+
//===----------------------------------------------------------------------===//
18+
19+
#ifndef SWIFT_BASIC_BYTETREESERIALIZATION_H
20+
#define SWIFT_BASIC_BYTETREESERIALIZATION_H
21+
22+
#include "llvm/Support/BinaryStreamError.h"
23+
#include "llvm/Support/BinaryStreamWriter.h"
24+
25+
namespace {
26+
// Only used by compiler if both template types are the same
27+
template <typename T, T>
28+
struct SameType;
29+
} // anonymous namespace
30+
31+
namespace swift {
32+
namespace byteTree {
33+
class ByteTreeWriter;
34+
35+
/// Add a template specialization of \c ObjectTraits for any that type
36+
/// serializes as an object consisting of multiple fields.
37+
template <class T>
38+
struct ObjectTraits {
39+
// Must provide:
40+
41+
/// Return the number of fields that will be written in \c write when
42+
/// \p Object gets serialized.
43+
// static unsigned numFields(const T &Object);
44+
45+
/// Serialize \p Object by calling \c Writer.write for all the fields of
46+
/// \p Object.
47+
// static void write(BinaryTreeWriter &Writer, const T &Object);
48+
};
49+
50+
/// Add a template specialization of \c ScalarTraits for any that type
51+
/// serializes into a raw set of bytes.
52+
template <class T>
53+
struct ScalarTraits {
54+
// Must provide:
55+
56+
/// Return the number of bytes the serialized format of \p Value will take up.
57+
// static unsigned size(const T &Value);
58+
59+
/// Serialize \p Value by writing its binary format into \p Writer. Any errors
60+
/// that may be returned by \p Writer can be returned by this function and
61+
/// will be handled on the call-side.
62+
// static llvm::Error write(llvm::BinaryStreamWriter &Writer, const T &Value);
63+
};
64+
65+
/// Add a template specialization of \c WrapperTypeTraits for any that type
66+
/// serializes as a type that already has a specialization of \c ScalarTypes.
67+
/// This will typically be useful for types like enums that have a 1-to-1
68+
/// mapping to e.g. an integer.
69+
template <class T>
70+
struct WrapperTypeTraits {
71+
// Must provide:
72+
73+
/// Write the serializable representation of \p Value to \p Writer. This will
74+
/// typically take the form \c Writer.write(convertedValue(Value), Index)
75+
/// where \c convertedValue has to be defined.
76+
// static void write(ByteTreeWriter &Writer, const T &Value, unsigned Index);
77+
};
78+
79+
// Test if ObjectTraits<T> is defined on type T.
80+
template <class T>
81+
struct has_ObjectTraits {
82+
using Signature_numFields = unsigned (*)(const T &);
83+
using Signature_write = void (*)(ByteTreeWriter &Writer, const T &Object);
84+
85+
template <typename U>
86+
static char test(SameType<Signature_numFields, &U::numFields> *,
87+
SameType<Signature_write, &U::write> *);
88+
89+
template <typename U>
90+
static double test(...);
91+
92+
public:
93+
static bool const value =
94+
(sizeof(test<ObjectTraits<T>>(nullptr, nullptr)) == 1);
95+
};
96+
97+
// Test if ScalarTraits<T> is defined on type T.
98+
template <class T>
99+
struct has_ScalarTraits {
100+
using Signature_size = unsigned (*)(const T &Object);
101+
using Signature_write = llvm::Error (*)(llvm::BinaryStreamWriter &Writer,
102+
const T &Object);
103+
104+
template <typename U>
105+
static char test(SameType<Signature_size, &U::size> *,
106+
SameType<Signature_write, &U::write> *);
107+
108+
template <typename U>
109+
static double test(...);
110+
111+
public:
112+
static bool const value =
113+
(sizeof(test<ScalarTraits<T>>(nullptr, nullptr)) == 1);
114+
};
115+
116+
// Test if WrapperTypeTraits<T> is defined on type T.
117+
template <class T>
118+
struct has_WrapperTypeTraits {
119+
using Signature_write = void (*)(ByteTreeWriter &Writer, const T &Object,
120+
unsigned Index);
121+
122+
template <typename U>
123+
static char test(SameType<Signature_write, &U::write> *);
124+
125+
template <typename U>
126+
static double test(...);
127+
128+
public:
129+
static bool const value = (sizeof(test<WrapperTypeTraits<T>>(nullptr)) == 1);
130+
};
131+
132+
class ByteTreeWriter {
133+
private:
134+
/// The writer to which the binary data is written.
135+
llvm::BinaryStreamWriter &StreamWriter;
136+
137+
/// The number of fields this object contains. \c UINT_MAX if it has not been
138+
/// set yet. No member may be written to the object if expected number of
139+
/// fields has not been set yet.
140+
unsigned NumFields = UINT_MAX;
141+
142+
/// The index of the next field to write. Used in assertion builds to keep
143+
/// track that no indicies are jumped and that the object contains the
144+
/// expected number of fields.
145+
unsigned CurrentFieldIndex = 0;
146+
147+
/// The \c ByteTreeWriter can only be constructed internally. Use
148+
/// \c ByteTreeWriter.write to serialize a new object.
149+
ByteTreeWriter(llvm::BinaryStreamWriter &StreamWriter)
150+
: StreamWriter(StreamWriter) {}
151+
152+
/// Set the expected number of fields the object written by this writer is
153+
/// expected to have.
154+
void setNumFields(uint32_t NumFields) {
155+
assert(NumFields != UINT_MAX &&
156+
"NumFields may not be reset since it has already been written to "
157+
"the byte stream");
158+
assert((this->NumFields == UINT_MAX) && "NumFields has already been set");
159+
160+
auto Error = StreamWriter.writeInteger(NumFields);
161+
(void)Error;
162+
assert(!Error);
163+
164+
this->NumFields = NumFields;
165+
}
166+
167+
/// Validate that \p Index is the next field that is expected to be written,
168+
/// does not exceed the number of fields in this object and that
169+
/// \c setNumFields has already been called.
170+
void validateAndIncreaseFieldIndex(unsigned Index) {
171+
assert((NumFields != UINT_MAX) &&
172+
"setNumFields must be called before writing any value");
173+
assert(Index == CurrentFieldIndex && "Writing index out of order");
174+
assert(Index < NumFields &&
175+
"Writing more fields than object is expected to have");
176+
177+
CurrentFieldIndex++;
178+
}
179+
180+
~ByteTreeWriter() {
181+
assert(CurrentFieldIndex == NumFields &&
182+
"Object had more or less elements than specified");
183+
}
184+
185+
public:
186+
/// Write a binary serialization of \p Object to \p StreamWriter, prefixing
187+
/// the stream by the specified ProtocolVersion.
188+
template <typename T>
189+
typename std::enable_if<has_ObjectTraits<T>::value, void>::type
190+
static write(uint32_t ProtocolVersion, llvm::BinaryStreamWriter &StreamWriter,
191+
const T &Object) {
192+
ByteTreeWriter Writer(StreamWriter);
193+
194+
auto Error = Writer.StreamWriter.writeInteger(ProtocolVersion);
195+
(void)Error;
196+
assert(!Error);
197+
198+
// There always is one root. We need to set NumFields so that index
199+
// validation succeeds, but we don't want to serialize this.
200+
Writer.NumFields = 1;
201+
Writer.write(Object, /*Index=*/0);
202+
}
203+
204+
template <typename T>
205+
typename std::enable_if<has_ObjectTraits<T>::value, void>::type
206+
write(const T &Object, unsigned Index) {
207+
validateAndIncreaseFieldIndex(Index);
208+
209+
auto ObjectWriter = ByteTreeWriter(StreamWriter);
210+
ObjectWriter.setNumFields(ObjectTraits<T>::numFields(Object));
211+
212+
ObjectTraits<T>::write(ObjectWriter, Object);
213+
}
214+
215+
template <typename T>
216+
typename std::enable_if<has_ScalarTraits<T>::value, void>::type
217+
write(const T &Value, unsigned Index) {
218+
validateAndIncreaseFieldIndex(Index);
219+
220+
uint32_t ValueSize = ScalarTraits<T>::size(Value);
221+
auto SizeError = StreamWriter.writeInteger(ValueSize);
222+
(void)SizeError;
223+
assert(!SizeError);
224+
225+
auto StartOffset = StreamWriter.getOffset();
226+
auto ContentError = ScalarTraits<T>::write(StreamWriter, Value);
227+
(void)ContentError;
228+
assert(!ContentError);
229+
(void)StartOffset;
230+
assert((StreamWriter.getOffset() - StartOffset == ValueSize) &&
231+
"Number of written bytes does not match size returned by "
232+
"ScalarTraits<T>::size");
233+
}
234+
235+
template <typename T>
236+
typename std::enable_if<has_WrapperTypeTraits<T>::value, void>::type
237+
write(const T &Value, unsigned Index) {
238+
auto LengthBeforeWrite = CurrentFieldIndex;
239+
WrapperTypeTraits<T>::write(*this, Value, Index);
240+
(void)LengthBeforeWrite;
241+
assert(CurrentFieldIndex == LengthBeforeWrite + 1 &&
242+
"WrapperTypeTraits did not call BinaryWriter.write");
243+
}
244+
};
245+
246+
// Define serialization schemes for common types
247+
248+
template <>
249+
struct ScalarTraits<uint8_t> {
250+
static unsigned size(const uint8_t &Value) { return 1; }
251+
static llvm::Error write(llvm::BinaryStreamWriter &Writer,
252+
const uint8_t &Value) {
253+
return Writer.writeInteger(Value);
254+
}
255+
};
256+
257+
template <>
258+
struct ScalarTraits<uint16_t> {
259+
static unsigned size(const uint16_t &Value) { return 2; }
260+
static llvm::Error write(llvm::BinaryStreamWriter &Writer,
261+
const uint16_t &Value) {
262+
return Writer.writeInteger(Value);
263+
}
264+
};
265+
266+
template <>
267+
struct ScalarTraits<uint32_t> {
268+
static unsigned size(const uint32_t &Value) { return 4; }
269+
static llvm::Error write(llvm::BinaryStreamWriter &Writer,
270+
const uint32_t &Value) {
271+
return Writer.writeInteger(Value);
272+
}
273+
};
274+
275+
template <>
276+
struct WrapperTypeTraits<bool> {
277+
static void write(ByteTreeWriter &Writer, const bool &Value,
278+
unsigned Index) {
279+
Writer.write(static_cast<uint8_t>(Value), Index);
280+
}
281+
};
282+
283+
template <>
284+
struct ScalarTraits<llvm::StringRef> {
285+
static unsigned size(const llvm::StringRef &Str) { return Str.size(); }
286+
static llvm::Error write(llvm::BinaryStreamWriter &Writer,
287+
const llvm::StringRef &Str) {
288+
return Writer.writeFixedString(Str);
289+
}
290+
};
291+
292+
template <>
293+
struct ScalarTraits<llvm::NoneType> {
294+
// Serialize llvm::None as a value with 0 length
295+
static unsigned size(const llvm::NoneType &None) { return 0; }
296+
static llvm::Error write(llvm::BinaryStreamWriter &Writer,
297+
const llvm::NoneType &None) {
298+
// Nothing to write
299+
return llvm::ErrorSuccess();
300+
}
301+
};
302+
303+
} // end namespace byteTree
304+
} // end namespace swift
305+
306+
#endif

0 commit comments

Comments
 (0)