Commit 37ee4819 authored by Kenton Varda's avatar Kenton Varda

Disable use of unit analysis (via kj::Quantity) by default (since it has some…

Disable use of unit analysis (via kj::Quantity) by default (since it has some overhead), but enable it specifically for dev builds.
parent f87e62bd
...@@ -19,7 +19,7 @@ once: ...@@ -19,7 +19,7 @@ once:
CXXFLAGS="$(EXTRA_FLAG) -std=c++11 -O2 -DNDEBUG -Wall" LIBS='-lz -pthread' $(EKAM) -j6 CXXFLAGS="$(EXTRA_FLAG) -std=c++11 -O2 -DNDEBUG -Wall" LIBS='-lz -pthread' $(EKAM) -j6
continuous: continuous:
CXXFLAGS="$(EXTRA_FLAG) -std=c++11 -g -Wall" LIBS='-lz -pthread' $(EKAM) -j6 -c -n :51315 CXXFLAGS="$(EXTRA_FLAG) -std=c++11 -g -DCAPNP_DEBUG_TYPES=1 -Wall" LIBS='-lz -pthread' $(EKAM) -j6 -c -n :51315
continuous-opt: continuous-opt:
CXXFLAGS="$(EXTRA_FLAG) -std=c++11 -O2 -DNDEBUG -Wall" LIBS='-lz -pthread' $(EKAM) -j6 -c -n :51315 CXXFLAGS="$(EXTRA_FLAG) -std=c++11 -O2 -DNDEBUG -Wall" LIBS='-lz -pthread' $(EKAM) -j6 -c -n :51315
......
...@@ -62,23 +62,17 @@ class word { uint64_t content KJ_UNUSED_MEMBER; KJ_DISALLOW_COPY(word); public: ...@@ -62,23 +62,17 @@ class word { uint64_t content KJ_UNUSED_MEMBER; KJ_DISALLOW_COPY(word); public:
static_assert(sizeof(byte) == 1, "uint8_t is not one byte?"); static_assert(sizeof(byte) == 1, "uint8_t is not one byte?");
static_assert(sizeof(word) == 8, "uint64_t is not 8 bytes?"); static_assert(sizeof(word) == 8, "uint64_t is not 8 bytes?");
namespace _ { class BitLabel; class ElementLabel; struct WirePointer; } #if CAPNP_DEBUG_TYPES
// Set CAPNP_DEBUG_TYPES to 1 to use kj::Quantity for "count" types. Otherwise, plain integers are
#ifndef KJ_DEBUG_TYPES // used. All the code should still operate exactly the same, we just lose compile-time checking.
#define KJ_DEBUG_TYPES 1 // Note that this will also change symbol names, so it's important that the library and any clients
// Set this to zero to degrade all the "count" types below to being plain integers. All the code // be compiled with the same setting here.
// should still operate exactly the same, we just lose compile-time checking. Note that this will
// also change symbol names, so it's important that the library and any clients be compiled with
// the same setting here.
// //
// TODO(soon): Decide policy on this. It may make sense to only use KJ_DEBUG_TYPES when // We disable this by default to reduce symbol name size and avoid any possibility of the compiler
// compiling the tests of libraries that explicitly want the safety (like Cap'n Proto), but // failing to fully-optimize the types, but anyone modifying Cap'n Proto itself should enable this
// disable it for all real builds, as some clients may find this safety tiring. Also, need to // during development and testing.
// benchmark to verify there really is no perf hit.
#endif namespace _ { class BitLabel; class ElementLabel; struct WirePointer; }
#if KJ_DEBUG_TYPES
typedef kj::Quantity<uint, _::BitLabel> BitCount; typedef kj::Quantity<uint, _::BitLabel> BitCount;
typedef kj::Quantity<uint8_t, _::BitLabel> BitCount8; typedef kj::Quantity<uint8_t, _::BitLabel> BitCount8;
...@@ -110,6 +104,40 @@ typedef kj::Quantity<uint16_t, _::WirePointer> WirePointerCount16; ...@@ -110,6 +104,40 @@ typedef kj::Quantity<uint16_t, _::WirePointer> WirePointerCount16;
typedef kj::Quantity<uint32_t, _::WirePointer> WirePointerCount32; typedef kj::Quantity<uint32_t, _::WirePointer> WirePointerCount32;
typedef kj::Quantity<uint64_t, _::WirePointer> WirePointerCount64; typedef kj::Quantity<uint64_t, _::WirePointer> WirePointerCount64;
template <typename T, typename U>
inline constexpr U* operator+(U* ptr, kj::Quantity<T, U> offset) {
return ptr + offset / kj::unit<kj::Quantity<T, U>>();
}
template <typename T, typename U>
inline constexpr const U* operator+(const U* ptr, kj::Quantity<T, U> offset) {
return ptr + offset / kj::unit<kj::Quantity<T, U>>();
}
template <typename T, typename U>
inline constexpr U* operator+=(U*& ptr, kj::Quantity<T, U> offset) {
return ptr = ptr + offset / kj::unit<kj::Quantity<T, U>>();
}
template <typename T, typename U>
inline constexpr const U* operator+=(const U*& ptr, kj::Quantity<T, U> offset) {
return ptr = ptr + offset / kj::unit<kj::Quantity<T, U>>();
}
template <typename T, typename U>
inline constexpr U* operator-(U* ptr, kj::Quantity<T, U> offset) {
return ptr - offset / kj::unit<kj::Quantity<T, U>>();
}
template <typename T, typename U>
inline constexpr const U* operator-(const U* ptr, kj::Quantity<T, U> offset) {
return ptr - offset / kj::unit<kj::Quantity<T, U>>();
}
template <typename T, typename U>
inline constexpr U* operator-=(U*& ptr, kj::Quantity<T, U> offset) {
return ptr = ptr - offset / kj::unit<kj::Quantity<T, U>>();
}
template <typename T, typename U>
inline constexpr const U* operator-=(const U*& ptr, kj::Quantity<T, U> offset) {
return ptr = ptr - offset / kj::unit<kj::Quantity<T, U>>();
}
#else #else
typedef uint BitCount; typedef uint BitCount;
...@@ -170,44 +198,6 @@ inline constexpr decltype(BITS / ELEMENTS) bitsPerElement() { ...@@ -170,44 +198,6 @@ inline constexpr decltype(BITS / ELEMENTS) bitsPerElement() {
return sizeof(T) * 8 * BITS / ELEMENTS; return sizeof(T) * 8 * BITS / ELEMENTS;
} }
#ifndef __CDT_PARSER__
template <typename T, typename U>
inline constexpr U* operator+(U* ptr, kj::Quantity<T, U> offset) {
return ptr + offset / kj::unit<kj::Quantity<T, U>>();
}
template <typename T, typename U>
inline constexpr const U* operator+(const U* ptr, kj::Quantity<T, U> offset) {
return ptr + offset / kj::unit<kj::Quantity<T, U>>();
}
template <typename T, typename U>
inline constexpr U* operator+=(U*& ptr, kj::Quantity<T, U> offset) {
return ptr = ptr + offset / kj::unit<kj::Quantity<T, U>>();
}
template <typename T, typename U>
inline constexpr const U* operator+=(const U*& ptr, kj::Quantity<T, U> offset) {
return ptr = ptr + offset / kj::unit<kj::Quantity<T, U>>();
}
template <typename T, typename U>
inline constexpr U* operator-(U* ptr, kj::Quantity<T, U> offset) {
return ptr - offset / kj::unit<kj::Quantity<T, U>>();
}
template <typename T, typename U>
inline constexpr const U* operator-(const U* ptr, kj::Quantity<T, U> offset) {
return ptr - offset / kj::unit<kj::Quantity<T, U>>();
}
template <typename T, typename U>
inline constexpr U* operator-=(U*& ptr, kj::Quantity<T, U> offset) {
return ptr = ptr - offset / kj::unit<kj::Quantity<T, U>>();
}
template <typename T, typename U>
inline constexpr const U* operator-=(const U*& ptr, kj::Quantity<T, U> offset) {
return ptr = ptr - offset / kj::unit<kj::Quantity<T, U>>();
}
#endif
inline constexpr ByteCount intervalLength(const byte* a, const byte* b) { inline constexpr ByteCount intervalLength(const byte* a, const byte* b) {
return uint(b - a) * BYTES; return uint(b - a) * BYTES;
} }
......
...@@ -195,17 +195,17 @@ static_assert(POINTERS * BITS_PER_POINTER / BITS_PER_BYTE / BYTES == sizeof(Wire ...@@ -195,17 +195,17 @@ static_assert(POINTERS * BITS_PER_POINTER / BITS_PER_BYTE / BYTES == sizeof(Wire
// ======================================================================================= // =======================================================================================
struct WireHelpers { struct WireHelpers {
static KJ_ALWAYS_INLINE(WordCount roundUpToWords(BitCount64 bits)) { static KJ_ALWAYS_INLINE(WordCount roundBitsUpToWords(BitCount64 bits)) {
static_assert(sizeof(word) == 8, "This code assumes 64-bit words."); static_assert(sizeof(word) == 8, "This code assumes 64-bit words.");
return (bits + 63 * BITS) / BITS_PER_WORD; return (bits + 63 * BITS) / BITS_PER_WORD;
} }
static KJ_ALWAYS_INLINE(WordCount roundUpToWords(ByteCount bytes)) { static KJ_ALWAYS_INLINE(WordCount roundBytesUpToWords(ByteCount bytes)) {
static_assert(sizeof(word) == 8, "This code assumes 64-bit words."); static_assert(sizeof(word) == 8, "This code assumes 64-bit words.");
return (bytes + 7 * BYTES) / BYTES_PER_WORD; return (bytes + 7 * BYTES) / BYTES_PER_WORD;
} }
static KJ_ALWAYS_INLINE(ByteCount roundUpToBytes(BitCount bits)) { static KJ_ALWAYS_INLINE(ByteCount roundBitsUpToBytes(BitCount bits)) {
return (bits + 7 * BITS) / BITS_PER_BYTE; return (bits + 7 * BITS) / BITS_PER_BYTE;
} }
...@@ -367,7 +367,7 @@ struct WireHelpers { ...@@ -367,7 +367,7 @@ struct WireHelpers {
case FieldSize::FOUR_BYTES: case FieldSize::FOUR_BYTES:
case FieldSize::EIGHT_BYTES: case FieldSize::EIGHT_BYTES:
memset(ptr, 0, memset(ptr, 0,
roundUpToWords(ElementCount64(tag->listRef.elementCount()) * roundBitsUpToWords(ElementCount64(tag->listRef.elementCount()) *
dataBitsPerElement(tag->listRef.elementSize())) dataBitsPerElement(tag->listRef.elementSize()))
* BYTES_PER_WORD / BYTES); * BYTES_PER_WORD / BYTES);
break; break;
...@@ -475,7 +475,7 @@ struct WireHelpers { ...@@ -475,7 +475,7 @@ struct WireHelpers {
case FieldSize::TWO_BYTES: case FieldSize::TWO_BYTES:
case FieldSize::FOUR_BYTES: case FieldSize::FOUR_BYTES:
case FieldSize::EIGHT_BYTES: { case FieldSize::EIGHT_BYTES: {
WordCount totalWords = roundUpToWords( WordCount totalWords = roundBitsUpToWords(
ElementCount64(ref->listRef.elementCount()) * ElementCount64(ref->listRef.elementCount()) *
dataBitsPerElement(ref->listRef.elementSize())); dataBitsPerElement(ref->listRef.elementSize()));
KJ_REQUIRE(boundsCheck(segment, ptr, ptr + totalWords), KJ_REQUIRE(boundsCheck(segment, ptr, ptr + totalWords),
...@@ -602,7 +602,7 @@ struct WireHelpers { ...@@ -602,7 +602,7 @@ struct WireHelpers {
case FieldSize::TWO_BYTES: case FieldSize::TWO_BYTES:
case FieldSize::FOUR_BYTES: case FieldSize::FOUR_BYTES:
case FieldSize::EIGHT_BYTES: { case FieldSize::EIGHT_BYTES: {
WordCount wordCount = roundUpToWords( WordCount wordCount = roundBitsUpToWords(
ElementCount64(src->listRef.elementCount()) * ElementCount64(src->listRef.elementCount()) *
dataBitsPerElement(src->listRef.elementSize())); dataBitsPerElement(src->listRef.elementSize()));
const word* srcPtr = src->target(); const word* srcPtr = src->target();
...@@ -809,7 +809,7 @@ struct WireHelpers { ...@@ -809,7 +809,7 @@ struct WireHelpers {
auto step = (dataSize + pointerCount * BITS_PER_POINTER) / ELEMENTS; auto step = (dataSize + pointerCount * BITS_PER_POINTER) / ELEMENTS;
// Calculate size of the list. // Calculate size of the list.
WordCount wordCount = roundUpToWords(ElementCount64(elementCount) * step); WordCount wordCount = roundBitsUpToWords(ElementCount64(elementCount) * step);
// Allocate the list. // Allocate the list.
word* ptr = allocate(ref, segment, wordCount, WirePointer::LIST); word* ptr = allocate(ref, segment, wordCount, WirePointer::LIST);
...@@ -1153,7 +1153,7 @@ struct WireHelpers { ...@@ -1153,7 +1153,7 @@ struct WireHelpers {
} }
// Zero out old location. See explanation in getWritableStructPointer(). // Zero out old location. See explanation in getWritableStructPointer().
memset(oldPtr, 0, roundUpToBytes(oldStep * elementCount) / BYTES); memset(oldPtr, 0, roundBitsUpToBytes(oldStep * elementCount) / BYTES);
return ListBuilder(origSegment, newPtr, newStep * BITS_PER_WORD, elementCount, return ListBuilder(origSegment, newPtr, newStep * BITS_PER_WORD, elementCount,
newDataSize * BITS_PER_WORD, newPointerCount); newDataSize * BITS_PER_WORD, newPointerCount);
...@@ -1175,7 +1175,7 @@ struct WireHelpers { ...@@ -1175,7 +1175,7 @@ struct WireHelpers {
dataBitsPerElement(elementSize.preferredListEncoding) * ELEMENTS; dataBitsPerElement(elementSize.preferredListEncoding) * ELEMENTS;
WordCount totalWords = WordCount totalWords =
roundUpToWords(BitCount64(newDataSize) * (elementCount / ELEMENTS)); roundBitsUpToWords(BitCount64(newDataSize) * (elementCount / ELEMENTS));
// Don't let allocate() zero out the object just yet. // Don't let allocate() zero out the object just yet.
zeroPointerAndFars(origSegment, origRef); zeroPointerAndFars(origSegment, origRef);
...@@ -1201,7 +1201,7 @@ struct WireHelpers { ...@@ -1201,7 +1201,7 @@ struct WireHelpers {
} }
// Zero out old location. See explanation in getWritableStructPointer(). // Zero out old location. See explanation in getWritableStructPointer().
memset(oldPtr, 0, roundUpToBytes(oldStep * elementCount) / BYTES); memset(oldPtr, 0, roundBitsUpToBytes(oldStep * elementCount) / BYTES);
return ListBuilder(origSegment, newPtr, newDataSize / ELEMENTS, elementCount, return ListBuilder(origSegment, newPtr, newDataSize / ELEMENTS, elementCount,
newDataSize, 0 * POINTERS); newDataSize, 0 * POINTERS);
...@@ -1215,7 +1215,7 @@ struct WireHelpers { ...@@ -1215,7 +1215,7 @@ struct WireHelpers {
ByteCount byteSize = size + 1 * BYTES; ByteCount byteSize = size + 1 * BYTES;
// Allocate the space. // Allocate the space.
word* ptr = allocate(ref, segment, roundUpToWords(byteSize), WirePointer::LIST); word* ptr = allocate(ref, segment, roundBytesUpToWords(byteSize), WirePointer::LIST);
// Initialize the pointer. // Initialize the pointer.
ref->listRef.set(FieldSize::BYTE, byteSize * (1 * ELEMENTS / BYTES)); ref->listRef.set(FieldSize::BYTE, byteSize * (1 * ELEMENTS / BYTES));
...@@ -1253,7 +1253,7 @@ struct WireHelpers { ...@@ -1253,7 +1253,7 @@ struct WireHelpers {
static KJ_ALWAYS_INLINE(Data::Builder initDataPointer( static KJ_ALWAYS_INLINE(Data::Builder initDataPointer(
WirePointer* ref, SegmentBuilder* segment, ByteCount size)) { WirePointer* ref, SegmentBuilder* segment, ByteCount size)) {
// Allocate the space. // Allocate the space.
word* ptr = allocate(ref, segment, roundUpToWords(size), WirePointer::LIST); word* ptr = allocate(ref, segment, roundBytesUpToWords(size), WirePointer::LIST);
// Initialize the pointer. // Initialize the pointer.
ref->listRef.set(FieldSize::BYTE, size * (1 * ELEMENTS / BYTES)); ref->listRef.set(FieldSize::BYTE, size * (1 * ELEMENTS / BYTES));
...@@ -1334,7 +1334,7 @@ struct WireHelpers { ...@@ -1334,7 +1334,7 @@ struct WireHelpers {
} }
static void setStructPointer(SegmentBuilder* segment, WirePointer* ref, StructReader value) { static void setStructPointer(SegmentBuilder* segment, WirePointer* ref, StructReader value) {
WordCount dataSize = roundUpToWords(value.dataSize); WordCount dataSize = roundBitsUpToWords(value.dataSize);
WordCount totalSize = dataSize + value.pointerCount * WORDS_PER_POINTER; WordCount totalSize = dataSize + value.pointerCount * WORDS_PER_POINTER;
word* ptr = allocate(ref, segment, totalSize, WirePointer::STRUCT); word* ptr = allocate(ref, segment, totalSize, WirePointer::STRUCT);
...@@ -1354,7 +1354,7 @@ struct WireHelpers { ...@@ -1354,7 +1354,7 @@ struct WireHelpers {
} }
static void setListPointer(SegmentBuilder* segment, WirePointer* ref, ListReader value) { static void setListPointer(SegmentBuilder* segment, WirePointer* ref, ListReader value) {
WordCount totalSize = roundUpToWords(value.elementCount * value.step); WordCount totalSize = roundBitsUpToWords(value.elementCount * value.step);
if (value.step * ELEMENTS <= BITS_PER_WORD * WORDS) { if (value.step * ELEMENTS <= BITS_PER_WORD * WORDS) {
// List of non-structs. // List of non-structs.
...@@ -1391,7 +1391,7 @@ struct WireHelpers { ...@@ -1391,7 +1391,7 @@ struct WireHelpers {
word* ptr = allocate(ref, segment, totalSize + POINTER_SIZE_IN_WORDS, WirePointer::LIST); word* ptr = allocate(ref, segment, totalSize + POINTER_SIZE_IN_WORDS, WirePointer::LIST);
ref->listRef.setInlineComposite(totalSize); ref->listRef.setInlineComposite(totalSize);
WordCount dataSize = roundUpToWords(value.structDataSize); WordCount dataSize = roundBitsUpToWords(value.structDataSize);
WirePointerCount pointerCount = value.structPointerCount; WirePointerCount pointerCount = value.structPointerCount;
WirePointer* tag = reinterpret_cast<WirePointer*>(ptr); WirePointer* tag = reinterpret_cast<WirePointer*>(ptr);
...@@ -1588,7 +1588,7 @@ struct WireHelpers { ...@@ -1588,7 +1588,7 @@ struct WireHelpers {
auto step = (dataSize + pointerCount * BITS_PER_POINTER) / ELEMENTS; auto step = (dataSize + pointerCount * BITS_PER_POINTER) / ELEMENTS;
KJ_REQUIRE(boundsCheck(segment, ptr, ptr + KJ_REQUIRE(boundsCheck(segment, ptr, ptr +
roundUpToWords(ElementCount64(ref->listRef.elementCount()) * step)), roundBitsUpToWords(ElementCount64(ref->listRef.elementCount()) * step)),
"Message contains out-of-bounds list pointer.") { "Message contains out-of-bounds list pointer.") {
goto useDefault; goto useDefault;
} }
...@@ -1645,7 +1645,7 @@ struct WireHelpers { ...@@ -1645,7 +1645,7 @@ struct WireHelpers {
} }
KJ_REQUIRE(boundsCheck(segment, ptr, ptr + KJ_REQUIRE(boundsCheck(segment, ptr, ptr +
roundUpToWords(ref->listRef.elementCount() * (1 * BYTES / ELEMENTS))), roundBytesUpToWords(ref->listRef.elementCount() * (1 * BYTES / ELEMENTS))),
"Message contained out-of-bounds text pointer.") { "Message contained out-of-bounds text pointer.") {
goto useDefault; goto useDefault;
} }
...@@ -1692,7 +1692,7 @@ struct WireHelpers { ...@@ -1692,7 +1692,7 @@ struct WireHelpers {
} }
KJ_REQUIRE(boundsCheck(segment, ptr, ptr + KJ_REQUIRE(boundsCheck(segment, ptr, ptr +
roundUpToWords(ref->listRef.elementCount() * (1 * BYTES / ELEMENTS))), roundBytesUpToWords(ref->listRef.elementCount() * (1 * BYTES / ELEMENTS))),
"Message contained out-of-bounds data pointer.") { "Message contained out-of-bounds data pointer.") {
goto useDefault; goto useDefault;
} }
...@@ -1785,7 +1785,7 @@ struct WireHelpers { ...@@ -1785,7 +1785,7 @@ struct WireHelpers {
WirePointerCount pointerCount = pointersPerElement(elementSize) * ELEMENTS; WirePointerCount pointerCount = pointersPerElement(elementSize) * ELEMENTS;
auto step = (dataSize + pointerCount * BITS_PER_POINTER) / ELEMENTS; auto step = (dataSize + pointerCount * BITS_PER_POINTER) / ELEMENTS;
ElementCount elementCount = ref->listRef.elementCount(); ElementCount elementCount = ref->listRef.elementCount();
WordCount wordCount = roundUpToWords(ElementCount64(elementCount) * step); WordCount wordCount = roundBitsUpToWords(ElementCount64(elementCount) * step);
KJ_REQUIRE(boundsCheck(segment, ptr, ptr + wordCount), KJ_REQUIRE(boundsCheck(segment, ptr, ptr + wordCount),
"Message contains out-of-bounds list pointer.") { "Message contains out-of-bounds list pointer.") {
...@@ -1978,7 +1978,7 @@ bool StructReader::isPointerFieldNull(WirePointerCount ptrIndex) const { ...@@ -1978,7 +1978,7 @@ bool StructReader::isPointerFieldNull(WirePointerCount ptrIndex) const {
} }
WordCount64 StructReader::totalSize() const { WordCount64 StructReader::totalSize() const {
WordCount64 result = WireHelpers::roundUpToWords(dataSize) + pointerCount * WORDS_PER_POINTER; WordCount64 result = WireHelpers::roundBitsUpToWords(dataSize) + pointerCount * WORDS_PER_POINTER;
for (uint i = 0; i < pointerCount / POINTERS; i++) { for (uint i = 0; i < pointerCount / POINTERS; i++) {
result += WireHelpers::totalSize(segment, pointers + i, nestingLimit); result += WireHelpers::totalSize(segment, pointers + i, nestingLimit);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment