Skip to content

Commit e546684

Browse files
committed
Extract the BitMask support to a separate file
1 parent 3f04710 commit e546684

File tree

2 files changed

+321
-288
lines changed

2 files changed

+321
-288
lines changed
Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
//===--- Bitmask.h - Swift Bitmask type for Reflection ----*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 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+
// Used by TypeLowering logic to compute masks for in-memory representations
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_REFLECTION_BITMASK_H
18+
#define SWIFT_REFLECTION_BITMASK_H
19+
20+
#include "swift/Remote/MemoryReader.h"
21+
#include <sstream>
22+
23+
namespace swift {
24+
namespace reflection {
25+
26+
// A variable-length bitmap used to track "spare bits" for general multi-payload
27+
// enums. Note: These are not arbitrary-sized! They are always a multiple
28+
// of 8 bits in size, and always aligned on an 8-bit boundary.
29+
class BitMask {
30+
static constexpr unsigned maxSize = 128 * 1024 * 1024; // 128MB
31+
32+
unsigned size; // Size of mask _in bytes_
33+
uint8_t *mask;
34+
public:
35+
~BitMask() {
36+
free(mask);
37+
}
38+
// Construct a bitmask of the appropriate number of bytes
39+
// initialized to all bits set
40+
BitMask(unsigned sizeInBytes = 0): size(sizeInBytes) {
41+
assert(size < maxSize && "Trying to build a too-large bitmask");
42+
if (size > maxSize || size == 0) {
43+
size = 0;
44+
mask = nullptr;
45+
return;
46+
}
47+
48+
mask = (uint8_t *)malloc(size);
49+
50+
if (!mask) {
51+
// Malloc might fail if size is large due to some bad data. Assert in
52+
// asserts builds, and fail gracefully in non-asserts builds by
53+
// constructing an empty BitMask.
54+
assert(false && "Failed to allocate BitMask");
55+
size = 0;
56+
return;
57+
}
58+
59+
memset(mask, 0xff, size);
60+
}
61+
// Construct a bitmask of the appropriate number of bytes
62+
// initialized with bits from the specified buffer
63+
BitMask(unsigned sizeInBytes, const uint8_t *initialValue,
64+
unsigned initialValueBytes, unsigned offset)
65+
: size(sizeInBytes) {
66+
// Gracefully fail by constructing an empty mask if we exceed the size
67+
// limit.
68+
if (size > maxSize) {
69+
size = 0;
70+
mask = nullptr;
71+
return;
72+
}
73+
74+
// Bad data could cause the initial value location to be off the end of our
75+
// size. If initialValueBytes + offset is beyond sizeInBytes (or overflows),
76+
// assert in asserts builds, and fail gracefully in non-asserts builds by
77+
// constructing an empty BitMask.
78+
bool overflowed = false;
79+
unsigned initialValueEnd =
80+
llvm::SaturatingAdd(initialValueBytes, offset, &overflowed);
81+
if (overflowed) {
82+
assert(false && "initialValueBytes + offset overflowed");
83+
size = 0;
84+
mask = nullptr;
85+
return;
86+
}
87+
assert(initialValueEnd <= sizeInBytes);
88+
if (initialValueEnd > size) {
89+
assert(false && "initialValueBytes + offset is greater than size");
90+
size = 0;
91+
mask = nullptr;
92+
return;
93+
}
94+
95+
mask = (uint8_t *)calloc(1, size);
96+
97+
if (!mask) {
98+
// Malloc might fail if size is large due to some bad data. Assert in
99+
// asserts builds, and fail gracefully in non-asserts builds by
100+
// constructing an empty BitMask.
101+
assert(false && "Failed to allocate BitMask");
102+
size = 0;
103+
return;
104+
}
105+
106+
memcpy(mask + offset, initialValue, initialValueBytes);
107+
}
108+
// Move constructor moves ownership and zeros the src
109+
BitMask(BitMask&& src) noexcept: size(src.size), mask(std::move(src.mask)) {
110+
src.size = 0;
111+
src.mask = nullptr;
112+
}
113+
// Copy constructor makes a copy of the mask storage
114+
BitMask(const BitMask& src) noexcept: size(src.size), mask(nullptr) {
115+
mask = (uint8_t *)malloc(size);
116+
memcpy(mask, src.mask, size);
117+
}
118+
119+
std::string str() const {
120+
std::ostringstream buff;
121+
buff << size << ":0x";
122+
for (unsigned i = 0; i < size; i++) {
123+
buff << std::hex << ((mask[i] >> 4) & 0x0f) << (mask[i] & 0x0f);
124+
}
125+
return buff.str();
126+
}
127+
128+
bool operator==(const BitMask& rhs) const {
129+
// The two masks may be of different sizes.
130+
// The common prefix must be identical.
131+
size_t common = std::min(size, rhs.size);
132+
if (memcmp(mask, rhs.mask, common) != 0)
133+
return false;
134+
// The remainder of the longer mask must be
135+
// all zero bits.
136+
unsigned mustBeZeroSize = std::max(size, rhs.size) - common;
137+
uint8_t *mustBeZero;
138+
if (size < rhs.size) {
139+
mustBeZero = rhs.mask + size;
140+
} else if (size > rhs.size) {
141+
mustBeZero = mask + rhs.size;
142+
}
143+
for (unsigned i = 0; i < mustBeZeroSize; ++i) {
144+
if (mustBeZero[i] != 0) {
145+
return false;
146+
}
147+
}
148+
return true;
149+
}
150+
151+
bool operator!=(const BitMask& rhs) const {
152+
return !(*this == rhs);
153+
}
154+
155+
bool isNonZero() const { return !isZero(); }
156+
157+
bool isZero() const {
158+
for (unsigned i = 0; i < size; ++i) {
159+
if (mask[i] != 0) {
160+
return false;
161+
}
162+
}
163+
return true;
164+
}
165+
166+
void makeZero() {
167+
memset(mask, 0, size * sizeof(mask[0]));
168+
}
169+
170+
void complement() {
171+
for (unsigned i = 0; i < size; ++i) {
172+
mask[i] = ~mask[i];
173+
}
174+
}
175+
176+
int countSetBits() const {
177+
static const int counter[] =
178+
{0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
179+
int bits = 0;
180+
for (unsigned i = 0; i < size; ++i) {
181+
bits += counter[mask[i] >> 4] + counter[mask[i] & 15];
182+
}
183+
return bits;
184+
}
185+
186+
int countZeroBits() const {
187+
static const int counter[] =
188+
{4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
189+
int bits = 0;
190+
for (unsigned i = 0; i < size; ++i) {
191+
bits += counter[mask[i] >> 4] + counter[mask[i] & 15];
192+
}
193+
return bits;
194+
}
195+
196+
// Treat the provided value as a mask, `and` it with
197+
// the part of the mask at the provided byte offset.
198+
// Bits outside the specified area are unchanged.
199+
template<typename IntegerType>
200+
void andMask(IntegerType value, unsigned byteOffset) {
201+
andMask((void *)&value, sizeof(value), byteOffset);
202+
}
203+
204+
// As above, but using the provided bitmask instead
205+
// of an integer.
206+
void andMask(BitMask mask, unsigned offset) {
207+
andMask(mask.mask, mask.size, offset);
208+
}
209+
210+
// As above, but using the complement of the
211+
// provided mask.
212+
void andNotMask(BitMask mask, unsigned offset) {
213+
if (offset < size) {
214+
andNotMask(mask.mask, mask.size, offset);
215+
}
216+
}
217+
218+
// Zero all bits except for the `n` most significant ones.
219+
void keepOnlyMostSignificantBits(unsigned n) {
220+
if (size < 1) {
221+
return;
222+
}
223+
#if defined(__BIG_ENDIAN__)
224+
assert(false && "Big endian not supported for readMaskedInteger");
225+
#else
226+
unsigned count = 0;
227+
unsigned i = size;
228+
while (i > 0) {
229+
i -= 1;
230+
if (count < n) {
231+
for (int b = 128; b > 0; b >>= 1) {
232+
if (count >= n) {
233+
mask[i] &= ~b;
234+
} else if ((mask[i] & b) != 0) {
235+
++count;
236+
}
237+
}
238+
} else {
239+
mask[i] = 0;
240+
}
241+
}
242+
#endif
243+
}
244+
245+
unsigned numBits() const {
246+
return size * 8;
247+
}
248+
249+
unsigned numSetBits() const {
250+
unsigned count = 0;
251+
for (unsigned i = 0; i < size; ++i) {
252+
if (mask[i] != 0) {
253+
for (unsigned b = 1; b < 256; b <<= 1) {
254+
if ((mask[i] & b) != 0) {
255+
++count;
256+
}
257+
}
258+
}
259+
}
260+
return count;
261+
}
262+
263+
// Read a mask-sized area from the target and collect
264+
// the masked bits into a single integer.
265+
template<typename IntegerType>
266+
bool readMaskedInteger(remote::MemoryReader &reader,
267+
remote::RemoteAddress address,
268+
IntegerType *dest) const {
269+
auto data = reader.readBytes(address, size);
270+
if (!data) {
271+
return false;
272+
}
273+
#if defined(__BIG_ENDIAN__)
274+
assert(false && "Big endian not supported for readMaskedInteger");
275+
#else
276+
IntegerType result = 0;
277+
IntegerType resultBit = 1; // Start from least-significant bit
278+
auto bytes = static_cast<const uint8_t *>(data.get());
279+
for (unsigned i = 0; i < size; ++i) {
280+
for (unsigned b = 1; b < 256; b <<= 1) {
281+
if ((mask[i] & b) != 0) {
282+
if ((bytes[i] & b) != 0) {
283+
result |= resultBit;
284+
}
285+
resultBit <<= 1;
286+
}
287+
}
288+
}
289+
*dest = result;
290+
return true;
291+
#endif
292+
}
293+
294+
private:
295+
void andMask(void *maskData, unsigned len, unsigned offset) {
296+
if (offset < size) {
297+
unsigned common = std::min(len, size - offset);
298+
uint8_t *maskBytes = (uint8_t *)maskData;
299+
for (unsigned i = 0; i < common; ++i) {
300+
mask[i + offset] &= maskBytes[i];
301+
}
302+
}
303+
}
304+
305+
void andNotMask(void *maskData, unsigned len, unsigned offset) {
306+
assert(offset < size);
307+
if (offset < size) {
308+
unsigned common = std::min(len, size - offset);
309+
uint8_t *maskBytes = (uint8_t *)maskData;
310+
for (unsigned i = 0; i < common; ++i) {
311+
mask[i + offset] &= ~maskBytes[i];
312+
}
313+
}
314+
}
315+
};
316+
317+
} // namespace reflection
318+
} // namespace swift
319+
320+
#endif

0 commit comments

Comments
 (0)