Skip to content

Commit d073a62

Browse files
committed
Upgrade LLVM profiling runtime to version 10
Fixes #23
1 parent 6db9ae0 commit d073a62

9 files changed

+291
-55
lines changed

minicov/c/InstrProfiling.h

+29-8
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ typedef struct ValueProfNode {
4848
#include "profile/InstrProfData.inc"
4949
} ValueProfNode;
5050

51+
typedef struct COMPILER_RT_ALIGNAS(INSTR_PROF_DATA_ALIGNMENT) VTableProfData {
52+
#define INSTR_PROF_VTABLE_DATA(Type, LLVMType, Name, Initializer) Type Name;
53+
#include "profile/InstrProfData.inc"
54+
} VTableProfData;
55+
5156
/*!
5257
* \brief Return 1 if profile counters are continuously synced to the raw
5358
* profile via an mmap(). This is in contrast to the default mode, in which
@@ -102,12 +107,16 @@ const __llvm_profile_data *__llvm_profile_begin_data(void);
102107
const __llvm_profile_data *__llvm_profile_end_data(void);
103108
const char *__llvm_profile_begin_names(void);
104109
const char *__llvm_profile_end_names(void);
110+
const char *__llvm_profile_begin_vtabnames(void);
111+
const char *__llvm_profile_end_vtabnames(void);
105112
char *__llvm_profile_begin_counters(void);
106113
char *__llvm_profile_end_counters(void);
107114
char *__llvm_profile_begin_bitmap(void);
108115
char *__llvm_profile_end_bitmap(void);
109116
ValueProfNode *__llvm_profile_begin_vnodes();
110117
ValueProfNode *__llvm_profile_end_vnodes();
118+
const VTableProfData *__llvm_profile_begin_vtables();
119+
const VTableProfData *__llvm_profile_end_vtables();
111120
uint32_t *__llvm_profile_begin_orderfile();
112121

113122
/*!
@@ -251,20 +260,31 @@ uint64_t __llvm_profile_get_num_bitmap_bytes(const char *Begin,
251260
/*! \brief Get the size of the profile name section in bytes. */
252261
uint64_t __llvm_profile_get_name_size(const char *Begin, const char *End);
253262

254-
/* ! \brief Given the sizes of the data and counter information, return the
255-
* number of padding bytes before and after the counters, and after the names,
256-
* in the raw profile.
263+
/*! \brief Get the number of virtual table profile data entries */
264+
uint64_t __llvm_profile_get_num_vtable(const VTableProfData *Begin,
265+
const VTableProfData *End);
266+
267+
/*! \brief Get the size of virtual table profile data in bytes. */
268+
uint64_t __llvm_profile_get_vtable_section_size(const VTableProfData *Begin,
269+
const VTableProfData *End);
270+
271+
/* ! \brief Given the sizes of the data and counter information, computes the
272+
* number of padding bytes before and after the counter section, as well as the
273+
* number of padding bytes after other setions in the raw profile.
274+
* Returns -1 upon errors and 0 upon success. Output parameters should be used
275+
* iff return value is 0.
257276
*
258277
* Note: When mmap() mode is disabled, no padding bytes before/after counters
259278
* are needed. However, in mmap() mode, the counter section in the raw profile
260279
* must be page-aligned: this API computes the number of padding bytes
261280
* needed to achieve that.
262281
*/
263-
void __llvm_profile_get_padding_sizes_for_counters(
282+
int __llvm_profile_get_padding_sizes_for_counters(
264283
uint64_t DataSize, uint64_t CountersSize, uint64_t NumBitmapBytes,
265-
uint64_t NamesSize, uint64_t *PaddingBytesBeforeCounters,
266-
uint64_t *PaddingBytesAfterCounters, uint64_t *PaddingBytesAfterBitmap,
267-
uint64_t *PaddingBytesAfterNames);
284+
uint64_t NamesSize, uint64_t VTableSize, uint64_t VNameSize,
285+
uint64_t *PaddingBytesBeforeCounters, uint64_t *PaddingBytesAfterCounters,
286+
uint64_t *PaddingBytesAfterBitmap, uint64_t *PaddingBytesAfterNames,
287+
uint64_t *PaddingBytesAfterVTable, uint64_t *PaddingBytesAfterVNames);
268288

269289
/*!
270290
* \brief Set the flag that profile data has been dumped to the file.
@@ -293,7 +313,8 @@ COMPILER_RT_VISIBILITY extern int INSTR_PROF_PROFILE_RUNTIME_VAR;
293313
* variable is defined as weak so that compiler can emit an overriding
294314
* definition depending on user option.
295315
*/
296-
extern uint64_t INSTR_PROF_RAW_VERSION_VAR; /* __llvm_profile_raw_version */
316+
COMPILER_RT_VISIBILITY extern uint64_t
317+
INSTR_PROF_RAW_VERSION_VAR; /* __llvm_profile_raw_version */
297318

298319
/*!
299320
* This variable is a weak symbol defined in InstrProfiling.c. It allows

minicov/c/InstrProfilingBuffer.c

+74-15
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,18 @@ uint64_t __llvm_profile_get_size_for_buffer(void) {
5151
const char *BitmapEnd = __llvm_profile_end_bitmap();
5252
const char *NamesBegin = __llvm_profile_begin_names();
5353
const char *NamesEnd = __llvm_profile_end_names();
54+
const VTableProfData *VTableBegin = __llvm_profile_begin_vtables();
55+
const VTableProfData *VTableEnd = __llvm_profile_end_vtables();
56+
const char *VNamesBegin = __llvm_profile_begin_vtabnames();
57+
const char *VNamesEnd = __llvm_profile_end_vtabnames();
5458

5559
return __llvm_profile_get_size_for_buffer_internal(
5660
DataBegin, DataEnd, CountersBegin, CountersEnd, BitmapBegin, BitmapEnd,
57-
NamesBegin, NamesEnd);
61+
NamesBegin, NamesEnd, VTableBegin, VTableEnd, VNamesBegin, VNamesEnd);
5862
}
5963

64+
// NOTE: Caller should guarantee that `Begin` and `End` specifies a half-open
65+
// interval [Begin, End). Namely, `End` is one-byte past the end of the array.
6066
COMPILER_RT_VISIBILITY
6167
uint64_t __llvm_profile_get_num_data(const __llvm_profile_data *Begin,
6268
const __llvm_profile_data *End) {
@@ -71,6 +77,26 @@ uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin,
7177
return __llvm_profile_get_num_data(Begin, End) * sizeof(__llvm_profile_data);
7278
}
7379

80+
// Counts the number of `VTableProfData` elements within the range of [Begin,
81+
// End). Caller should guarantee that End points to one byte past the inclusive
82+
// range.
83+
// FIXME: Add a compiler-rt test to make sure the number of vtables in the
84+
// raw profile is the same as the number of vtable elements in the instrumented
85+
// binary.
86+
COMPILER_RT_VISIBILITY
87+
uint64_t __llvm_profile_get_num_vtable(const VTableProfData *Begin,
88+
const VTableProfData *End) {
89+
// Convert pointers to intptr_t to use integer arithmetic.
90+
intptr_t EndI = (intptr_t)End, BeginI = (intptr_t)Begin;
91+
return (EndI - BeginI) / sizeof(VTableProfData);
92+
}
93+
94+
COMPILER_RT_VISIBILITY
95+
uint64_t __llvm_profile_get_vtable_section_size(const VTableProfData *Begin,
96+
const VTableProfData *End) {
97+
return (intptr_t)(End) - (intptr_t)(Begin);
98+
}
99+
74100
COMPILER_RT_VISIBILITY size_t __llvm_profile_counter_entry_size(void) {
75101
if (__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE)
76102
return sizeof(uint8_t);
@@ -119,21 +145,33 @@ static int needsCounterPadding(void) {
119145
}
120146

121147
COMPILER_RT_VISIBILITY
122-
void __llvm_profile_get_padding_sizes_for_counters(
148+
int __llvm_profile_get_padding_sizes_for_counters(
123149
uint64_t DataSize, uint64_t CountersSize, uint64_t NumBitmapBytes,
124-
uint64_t NamesSize, uint64_t *PaddingBytesBeforeCounters,
125-
uint64_t *PaddingBytesAfterCounters, uint64_t *PaddingBytesAfterBitmapBytes,
126-
uint64_t *PaddingBytesAfterNames) {
150+
uint64_t NamesSize, uint64_t VTableSize, uint64_t VNameSize,
151+
uint64_t *PaddingBytesBeforeCounters, uint64_t *PaddingBytesAfterCounters,
152+
uint64_t *PaddingBytesAfterBitmapBytes, uint64_t *PaddingBytesAfterNames,
153+
uint64_t *PaddingBytesAfterVTable, uint64_t *PaddingBytesAfterVName) {
154+
// Counter padding is needed only if continuous mode is enabled.
127155
if (!needsCounterPadding()) {
128156
*PaddingBytesBeforeCounters = 0;
129157
*PaddingBytesAfterCounters =
130158
__llvm_profile_get_num_padding_bytes(CountersSize);
131159
*PaddingBytesAfterBitmapBytes =
132160
__llvm_profile_get_num_padding_bytes(NumBitmapBytes);
133161
*PaddingBytesAfterNames = __llvm_profile_get_num_padding_bytes(NamesSize);
134-
return;
162+
if (PaddingBytesAfterVTable != NULL)
163+
*PaddingBytesAfterVTable =
164+
__llvm_profile_get_num_padding_bytes(VTableSize);
165+
if (PaddingBytesAfterVName != NULL)
166+
*PaddingBytesAfterVName = __llvm_profile_get_num_padding_bytes(VNameSize);
167+
return 0;
135168
}
136169

170+
// Value profiling not supported in continuous mode at profile-write time.
171+
// Return -1 to alert the incompatibility.
172+
if (VTableSize != 0 || VNameSize != 0)
173+
return -1;
174+
137175
// In continuous mode, the file offsets for headers and for the start of
138176
// counter sections need to be page-aligned.
139177
*PaddingBytesBeforeCounters =
@@ -142,34 +180,52 @@ void __llvm_profile_get_padding_sizes_for_counters(
142180
*PaddingBytesAfterBitmapBytes =
143181
calculateBytesNeededToPageAlign(NumBitmapBytes);
144182
*PaddingBytesAfterNames = calculateBytesNeededToPageAlign(NamesSize);
183+
// Set these two variables to zero to avoid uninitialized variables
184+
// even if VTableSize and VNameSize are known to be zero.
185+
if (PaddingBytesAfterVTable != NULL)
186+
*PaddingBytesAfterVTable = 0;
187+
if (PaddingBytesAfterVName != NULL)
188+
*PaddingBytesAfterVName = 0;
189+
return 0;
145190
}
146191

147192
COMPILER_RT_VISIBILITY
148193
uint64_t __llvm_profile_get_size_for_buffer_internal(
149194
const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
150195
const char *CountersBegin, const char *CountersEnd, const char *BitmapBegin,
151-
const char *BitmapEnd, const char *NamesBegin, const char *NamesEnd) {
196+
const char *BitmapEnd, const char *NamesBegin, const char *NamesEnd,
197+
const VTableProfData *VTableBegin, const VTableProfData *VTableEnd,
198+
const char *VNamesBegin, const char *VNamesEnd) {
152199
/* Match logic in __llvm_profile_write_buffer(). */
153200
const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char);
154201
uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
155202
uint64_t CountersSize =
156203
__llvm_profile_get_counters_size(CountersBegin, CountersEnd);
157204
const uint64_t NumBitmapBytes =
158205
__llvm_profile_get_num_bitmap_bytes(BitmapBegin, BitmapEnd);
206+
const uint64_t VTableSize =
207+
__llvm_profile_get_vtable_section_size(VTableBegin, VTableEnd);
208+
const uint64_t VNameSize =
209+
__llvm_profile_get_name_size(VNamesBegin, VNamesEnd);
159210

160211
/* Determine how much padding is needed before/after the counters and after
161212
* the names. */
162213
uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,
163-
PaddingBytesAfterNames, PaddingBytesAfterBitmapBytes;
214+
PaddingBytesAfterNames, PaddingBytesAfterBitmapBytes,
215+
PaddingBytesAfterVTable, PaddingBytesAfterVNames;
164216
__llvm_profile_get_padding_sizes_for_counters(
165-
DataSize, CountersSize, NumBitmapBytes, NamesSize,
166-
&PaddingBytesBeforeCounters, &PaddingBytesAfterCounters,
167-
&PaddingBytesAfterBitmapBytes, &PaddingBytesAfterNames);
217+
DataSize, CountersSize, NumBitmapBytes, NamesSize, 0 /* VTableSize */,
218+
0 /* VNameSize */, &PaddingBytesBeforeCounters,
219+
&PaddingBytesAfterCounters, &PaddingBytesAfterBitmapBytes,
220+
&PaddingBytesAfterNames, &PaddingBytesAfterVTable,
221+
&PaddingBytesAfterVNames);
168222

169223
return sizeof(__llvm_profile_header) + __llvm_write_binary_ids(NULL) +
170224
DataSize + PaddingBytesBeforeCounters + CountersSize +
171225
PaddingBytesAfterCounters + NumBitmapBytes +
172-
PaddingBytesAfterBitmapBytes + NamesSize + PaddingBytesAfterNames;
226+
PaddingBytesAfterBitmapBytes + NamesSize + PaddingBytesAfterNames +
227+
VTableSize + PaddingBytesAfterVTable + VNameSize +
228+
PaddingBytesAfterVNames;
173229
}
174230

175231
COMPILER_RT_VISIBILITY
@@ -191,7 +247,10 @@ COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer_internal(
191247
const char *NamesBegin, const char *NamesEnd) {
192248
ProfDataWriter BufferWriter;
193249
initBufferWriter(&BufferWriter, Buffer);
194-
return lprofWriteDataImpl(&BufferWriter, DataBegin, DataEnd, CountersBegin,
195-
CountersEnd, BitmapBegin, BitmapEnd, 0, NamesBegin,
196-
NamesEnd, 0);
250+
// Set virtual table arguments to NULL since they are not supported yet.
251+
return lprofWriteDataImpl(
252+
&BufferWriter, DataBegin, DataEnd, CountersBegin, CountersEnd,
253+
BitmapBegin, BitmapEnd, /*VPDataReader=*/0, NamesBegin, NamesEnd,
254+
/*VTableBegin=*/NULL, /*VTableEnd=*/NULL, /*VNamesBegin=*/NULL,
255+
/*VNamesEnd=*/NULL, /*SkipNameDataWrite=*/0);
197256
}

minicov/c/InstrProfilingInternal.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
uint64_t __llvm_profile_get_size_for_buffer_internal(
2323
const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
2424
const char *CountersBegin, const char *CountersEnd, const char *BitmapBegin,
25-
const char *BitmapEnd, const char *NamesBegin, const char *NamesEnd);
25+
const char *BitmapEnd, const char *NamesBegin, const char *NamesEnd,
26+
const VTableProfData *VTableBegin, const VTableProfData *VTableEnd,
27+
const char *VNamesBegin, const char *VNamesEnd);
2628

2729
/*!
2830
* \brief Write instrumentation data to the given buffer, given explicit
@@ -156,7 +158,9 @@ int lprofWriteDataImpl(ProfDataWriter *Writer,
156158
const char *CountersBegin, const char *CountersEnd,
157159
const char *BitmapBegin, const char *BitmapEnd,
158160
VPDataReaderType *VPDataReader, const char *NamesBegin,
159-
const char *NamesEnd, int SkipNameDataWrite);
161+
const char *NamesEnd, const VTableProfData *VTableBegin,
162+
const VTableProfData *VTableEnd, const char *VNamesBegin,
163+
const char *VNamesEnd, int SkipNameDataWrite);
160164

161165
/* Merge value profile data pointed to by SrcValueProfData into
162166
* in-memory profile counters pointed by to DstData. */

minicov/c/InstrProfilingMerge.c

+21-2
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,26 @@ static uintptr_t signextIfWin64(void *V) {
106106
#endif
107107
}
108108

109+
// Skip names section, vtable profile data section and vtable names section
110+
// for runtime profile merge. To merge runtime addresses from multiple
111+
// profiles collected from the same instrumented binary, the binary should be
112+
// loaded at fixed base address (e.g., build with -no-pie, or run with ASLR
113+
// disabled). In this set-up these three sections remain unchanged.
114+
static uint64_t
115+
getDistanceFromCounterToValueProf(const __llvm_profile_header *const Header) {
116+
const uint64_t VTableSectionSize =
117+
Header->NumVTables * sizeof(VTableProfData);
118+
const uint64_t PaddingBytesAfterVTableSection =
119+
__llvm_profile_get_num_padding_bytes(VTableSectionSize);
120+
const uint64_t VNamesSize = Header->VNamesSize;
121+
const uint64_t PaddingBytesAfterVNamesSize =
122+
__llvm_profile_get_num_padding_bytes(VNamesSize);
123+
return Header->NamesSize +
124+
__llvm_profile_get_num_padding_bytes(Header->NamesSize) +
125+
VTableSectionSize + PaddingBytesAfterVTableSection + VNamesSize +
126+
PaddingBytesAfterVNamesSize;
127+
}
128+
109129
COMPILER_RT_VISIBILITY
110130
int __llvm_profile_merge_from_buffer(const char *ProfileData,
111131
uint64_t ProfileSize) {
@@ -136,8 +156,7 @@ int __llvm_profile_merge_from_buffer(const char *ProfileData,
136156
SrcBitmapStart = SrcCountersEnd;
137157
SrcNameStart = SrcBitmapStart + Header->NumBitmapBytes;
138158
SrcValueProfDataStart =
139-
SrcNameStart + Header->NamesSize +
140-
__llvm_profile_get_num_padding_bytes(Header->NamesSize);
159+
SrcNameStart + getDistanceFromCounterToValueProf(Header);
141160
if (SrcNameStart < SrcCountersStart || SrcNameStart < SrcBitmapStart)
142161
return 1;
143162

minicov/c/InstrProfilingPlatformLinux.c

+21
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,12 @@
1717
#define PROF_DATA_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_DATA_COMMON)
1818
#define PROF_NAME_START INSTR_PROF_SECT_START(INSTR_PROF_NAME_COMMON)
1919
#define PROF_NAME_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_NAME_COMMON)
20+
#define PROF_VNAME_START INSTR_PROF_SECT_START(INSTR_PROF_VNAME_COMMON)
21+
#define PROF_VNAME_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_VNAME_COMMON)
2022
#define PROF_CNTS_START INSTR_PROF_SECT_START(INSTR_PROF_CNTS_COMMON)
2123
#define PROF_CNTS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_CNTS_COMMON)
24+
#define PROF_VTABLE_START INSTR_PROF_SECT_START(INSTR_PROF_VTAB_COMMON)
25+
#define PROF_VTABLE_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_VTAB_COMMON)
2226
#define PROF_BITS_START INSTR_PROF_SECT_START(INSTR_PROF_BITS_COMMON)
2327
#define PROF_BITS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_BITS_COMMON)
2428
#define PROF_ORDERFILE_START INSTR_PROF_SECT_START(INSTR_PROF_ORDERFILE_COMMON)
@@ -34,6 +38,10 @@ extern __llvm_profile_data PROF_DATA_STOP COMPILER_RT_VISIBILITY
3438
COMPILER_RT_WEAK;
3539
extern char PROF_CNTS_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
3640
extern char PROF_CNTS_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
41+
extern VTableProfData PROF_VTABLE_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
42+
extern VTableProfData PROF_VTABLE_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
43+
extern char PROF_VNAME_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
44+
extern char PROF_VNAME_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
3745
extern char PROF_BITS_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
3846
extern char PROF_BITS_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
3947
extern uint32_t PROF_ORDERFILE_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
@@ -56,6 +64,19 @@ COMPILER_RT_VISIBILITY const char *__llvm_profile_begin_names(void) {
5664
COMPILER_RT_VISIBILITY const char *__llvm_profile_end_names(void) {
5765
return &PROF_NAME_STOP;
5866
}
67+
COMPILER_RT_VISIBILITY const char *__llvm_profile_begin_vtabnames(void) {
68+
return &PROF_VNAME_START;
69+
}
70+
COMPILER_RT_VISIBILITY const char *__llvm_profile_end_vtabnames(void) {
71+
return &PROF_VNAME_STOP;
72+
}
73+
COMPILER_RT_VISIBILITY const VTableProfData *
74+
__llvm_profile_begin_vtables(void) {
75+
return &PROF_VTABLE_START;
76+
}
77+
COMPILER_RT_VISIBILITY const VTableProfData *__llvm_profile_end_vtables(void) {
78+
return &PROF_VTABLE_STOP;
79+
}
5980
COMPILER_RT_VISIBILITY char *__llvm_profile_begin_counters(void) {
6081
return &PROF_CNTS_START;
6182
}

minicov/c/InstrProfilingPlatformOther.c

+15
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,12 @@
1717

1818
static const __llvm_profile_data *DataFirst = NULL;
1919
static const __llvm_profile_data *DataLast = NULL;
20+
static const VTableProfData *VTableProfDataFirst = NULL;
21+
static const VTableProfData *VTableProfDataLast = NULL;
2022
static const char *NamesFirst = NULL;
2123
static const char *NamesLast = NULL;
24+
static const char *VNamesFirst = NULL;
25+
static const char *VNamesLast = NULL;
2226
static const char *BitmapFirst = NULL;
2327
static const char *BitmapLast = NULL;
2428
static char *CountersFirst = NULL;
@@ -81,11 +85,22 @@ COMPILER_RT_VISIBILITY
8185
const __llvm_profile_data *__llvm_profile_begin_data(void) { return DataFirst; }
8286
COMPILER_RT_VISIBILITY
8387
const __llvm_profile_data *__llvm_profile_end_data(void) { return DataLast; }
88+
COMPILER_RT_VISIBILITY const VTableProfData *
89+
__llvm_profile_begin_vtables(void) {
90+
return VTableProfDataFirst;
91+
}
92+
COMPILER_RT_VISIBILITY const VTableProfData *__llvm_profile_end_vtables(void) {
93+
return VTableProfDataLast;
94+
}
8495
COMPILER_RT_VISIBILITY
8596
const char *__llvm_profile_begin_names(void) { return NamesFirst; }
8697
COMPILER_RT_VISIBILITY
8798
const char *__llvm_profile_end_names(void) { return NamesLast; }
8899
COMPILER_RT_VISIBILITY
100+
const char *__llvm_profile_begin_vtabnames(void) { return VNamesFirst; }
101+
COMPILER_RT_VISIBILITY
102+
const char *__llvm_profile_end_vtabnames(void) { return VNamesLast; }
103+
COMPILER_RT_VISIBILITY
89104
char *__llvm_profile_begin_counters(void) { return CountersFirst; }
90105
COMPILER_RT_VISIBILITY
91106
char *__llvm_profile_end_counters(void) { return CountersLast; }

0 commit comments

Comments
 (0)