| Index: src/heap-snapshot-generator.cc
|
| diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc
|
| index 35cfcb4f68592c138b30b24c836aa490da4a7c09..b67aa0f3764ad1c190243c98ec4921c2d1c6454d 100644
|
| --- a/src/heap-snapshot-generator.cc
|
| +++ b/src/heap-snapshot-generator.cc
|
| @@ -34,6 +34,7 @@
|
| #include "heap-profiler.h"
|
| #include "debug.h"
|
| #include "types.h"
|
| +#include "v8conversions.h"
|
|
|
| namespace v8 {
|
| namespace internal {
|
| @@ -47,7 +48,8 @@ HeapGraphEdge::HeapGraphEdge(Type type, const char* name, int from, int to)
|
| ASSERT(type == kContextVariable
|
| || type == kProperty
|
| || type == kInternal
|
| - || type == kShortcut);
|
| + || type == kShortcut
|
| + || type == kWeak);
|
| }
|
|
|
|
|
| @@ -56,7 +58,7 @@ HeapGraphEdge::HeapGraphEdge(Type type, int index, int from, int to)
|
| from_index_(from),
|
| to_index_(to),
|
| index_(index) {
|
| - ASSERT(type == kElement || type == kHidden || type == kWeak);
|
| + ASSERT(type == kElement || type == kHidden);
|
| }
|
|
|
|
|
| @@ -71,7 +73,7 @@ HeapEntry::HeapEntry(HeapSnapshot* snapshot,
|
| Type type,
|
| const char* name,
|
| SnapshotObjectId id,
|
| - int self_size)
|
| + size_t self_size)
|
| : type_(type),
|
| children_count_(0),
|
| children_index_(-1),
|
| @@ -102,7 +104,7 @@ void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type,
|
| void HeapEntry::Print(
|
| const char* prefix, const char* edge_name, int max_depth, int indent) {
|
| STATIC_CHECK(sizeof(unsigned) == sizeof(id()));
|
| - OS::Print("%6d @%6u %*c %s%s: ",
|
| + OS::Print("%6" V8PRIuPTR " @%6u %*c %s%s: ",
|
| self_size(), id(), indent, ' ', prefix, edge_name);
|
| if (type() != kString) {
|
| OS::Print("%s %.40s\n", TypeAsString(), name_);
|
| @@ -150,7 +152,7 @@ void HeapEntry::Print(
|
| break;
|
| case HeapGraphEdge::kWeak:
|
| edge_prefix = "w";
|
| - OS::SNPrintF(index, "%d", edge.index());
|
| + edge_name = edge.name();
|
| break;
|
| default:
|
| OS::SNPrintF(index, "!!! unknown edge type: %d ", edge.type());
|
| @@ -192,7 +194,7 @@ template <> struct SnapshotSizeConstants<4> {
|
|
|
| template <> struct SnapshotSizeConstants<8> {
|
| static const int kExpectedHeapGraphEdgeSize = 24;
|
| - static const int kExpectedHeapEntrySize = 32;
|
| + static const int kExpectedHeapEntrySize = 40;
|
| };
|
|
|
| } // namespace
|
| @@ -275,7 +277,7 @@ HeapEntry* HeapSnapshot::AddGcSubrootEntry(int tag) {
|
| HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
|
| const char* name,
|
| SnapshotObjectId id,
|
| - int size) {
|
| + size_t size) {
|
| HeapEntry entry(this, type, name, id, size);
|
| entries_.Add(entry);
|
| return &entries_.last();
|
| @@ -898,10 +900,17 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) {
|
| HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
|
| HeapEntry::Type type,
|
| const char* name) {
|
| - int object_size = object->Size();
|
| - SnapshotObjectId object_id =
|
| - heap_object_map_->FindOrAddEntry(object->address(), object_size);
|
| - return snapshot_->AddEntry(type, name, object_id, object_size);
|
| + return AddEntry(object->address(), type, name, object->Size());
|
| +}
|
| +
|
| +
|
| +HeapEntry* V8HeapExplorer::AddEntry(Address address,
|
| + HeapEntry::Type type,
|
| + const char* name,
|
| + size_t size) {
|
| + SnapshotObjectId object_id = heap_object_map_->FindOrAddEntry(
|
| + address, static_cast<unsigned int>(size));
|
| + return snapshot_->AddEntry(type, name, object_id, size);
|
| }
|
|
|
|
|
| @@ -991,8 +1000,9 @@ class IndexedReferencesExtractor : public ObjectVisitor {
|
| }
|
| void VisitPointers(Object** start, Object** end) {
|
| for (Object** p = start; p < end; p++) {
|
| + ++next_index_;
|
| if (CheckVisitedAndUnmark(p)) continue;
|
| - generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, *p);
|
| + generator_->SetHiddenReference(parent_obj_, parent_, next_index_, *p);
|
| }
|
| }
|
| static void MarkVisitedField(HeapObject* obj, int offset) {
|
| @@ -1027,6 +1037,8 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
|
|
|
| if (obj->IsJSGlobalProxy()) {
|
| ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj));
|
| + } else if (obj->IsJSArrayBuffer()) {
|
| + ExtractJSArrayBufferReferences(entry, JSArrayBuffer::cast(obj));
|
| } else if (obj->IsJSObject()) {
|
| ExtractJSObjectReferences(entry, JSObject::cast(obj));
|
| } else if (obj->IsString()) {
|
| @@ -1045,6 +1057,8 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
|
| ExtractCodeCacheReferences(entry, CodeCache::cast(obj));
|
| } else if (obj->IsCode()) {
|
| ExtractCodeReferences(entry, Code::cast(obj));
|
| + } else if (obj->IsBox()) {
|
| + ExtractBoxReferences(entry, Box::cast(obj));
|
| } else if (obj->IsCell()) {
|
| ExtractCellReferences(entry, Cell::cast(obj));
|
| } else if (obj->IsPropertyCell()) {
|
| @@ -1114,11 +1128,13 @@ void V8HeapExplorer::ExtractJSObjectReferences(
|
| SetInternalReference(js_fun, entry,
|
| "context", js_fun->context(),
|
| JSFunction::kContextOffset);
|
| - for (int i = JSFunction::kNonWeakFieldsEndOffset;
|
| - i < JSFunction::kSize;
|
| - i += kPointerSize) {
|
| - SetWeakReference(js_fun, entry, i, *HeapObject::RawField(js_fun, i), i);
|
| - }
|
| + SetWeakReference(js_fun, entry,
|
| + "next_function_link", js_fun->next_function_link(),
|
| + JSFunction::kNextFunctionLinkOffset);
|
| + STATIC_CHECK(JSFunction::kNextFunctionLinkOffset
|
| + == JSFunction::kNonWeakFieldsEndOffset);
|
| + STATIC_CHECK(JSFunction::kNextFunctionLinkOffset + kPointerSize
|
| + == JSFunction::kSize);
|
| } else if (obj->IsGlobalObject()) {
|
| GlobalObject* global_obj = GlobalObject::cast(obj);
|
| SetInternalReference(global_obj, entry,
|
| @@ -1128,8 +1144,19 @@ void V8HeapExplorer::ExtractJSObjectReferences(
|
| "native_context", global_obj->native_context(),
|
| GlobalObject::kNativeContextOffset);
|
| SetInternalReference(global_obj, entry,
|
| + "global_context", global_obj->global_context(),
|
| + GlobalObject::kGlobalContextOffset);
|
| + SetInternalReference(global_obj, entry,
|
| "global_receiver", global_obj->global_receiver(),
|
| GlobalObject::kGlobalReceiverOffset);
|
| + STATIC_CHECK(GlobalObject::kHeaderSize - JSObject::kHeaderSize ==
|
| + 4 * kPointerSize);
|
| + } else if (obj->IsJSArrayBufferView()) {
|
| + JSArrayBufferView* view = JSArrayBufferView::cast(obj);
|
| + SetInternalReference(view, entry, "buffer", view->buffer(),
|
| + JSArrayBufferView::kBufferOffset);
|
| + SetWeakReference(view, entry, "weak_next", view->weak_next(),
|
| + JSArrayBufferView::kWeakNextOffset);
|
| }
|
| TagObject(js_obj->properties(), "(object properties)");
|
| SetInternalReference(obj, entry,
|
| @@ -1180,8 +1207,13 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
|
| }
|
|
|
| #define EXTRACT_CONTEXT_FIELD(index, type, name) \
|
| - SetInternalReference(context, entry, #name, context->get(Context::index), \
|
| - FixedArray::OffsetOfElementAt(Context::index));
|
| + if (Context::index < Context::FIRST_WEAK_SLOT) { \
|
| + SetInternalReference(context, entry, #name, context->get(Context::index), \
|
| + FixedArray::OffsetOfElementAt(Context::index)); \
|
| + } else { \
|
| + SetWeakReference(context, entry, #name, context->get(Context::index), \
|
| + FixedArray::OffsetOfElementAt(Context::index)); \
|
| + }
|
| EXTRACT_CONTEXT_FIELD(CLOSURE_INDEX, JSFunction, closure);
|
| EXTRACT_CONTEXT_FIELD(PREVIOUS_INDEX, Context, previous);
|
| EXTRACT_CONTEXT_FIELD(EXTENSION_INDEX, Object, extension);
|
| @@ -1193,13 +1225,16 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
|
| TagObject(context->runtime_context(), "(runtime context)");
|
| TagObject(context->embedder_data(), "(context data)");
|
| NATIVE_CONTEXT_FIELDS(EXTRACT_CONTEXT_FIELD);
|
| + EXTRACT_CONTEXT_FIELD(OPTIMIZED_FUNCTIONS_LIST, unused,
|
| + optimized_functions_list);
|
| + EXTRACT_CONTEXT_FIELD(OPTIMIZED_CODE_LIST, unused, optimized_code_list);
|
| + EXTRACT_CONTEXT_FIELD(DEOPTIMIZED_CODE_LIST, unused, deoptimized_code_list);
|
| + EXTRACT_CONTEXT_FIELD(NEXT_CONTEXT_LINK, unused, next_context_link);
|
| #undef EXTRACT_CONTEXT_FIELD
|
| - for (int i = Context::FIRST_WEAK_SLOT;
|
| - i < Context::NATIVE_CONTEXT_SLOTS;
|
| - ++i) {
|
| - SetWeakReference(context, entry, i, context->get(i),
|
| - FixedArray::OffsetOfElementAt(i));
|
| - }
|
| + STATIC_CHECK(Context::OPTIMIZED_FUNCTIONS_LIST == Context::FIRST_WEAK_SLOT);
|
| + STATIC_CHECK(Context::NEXT_CONTEXT_LINK + 1
|
| + == Context::NATIVE_CONTEXT_SLOTS);
|
| + STATIC_CHECK(Context::FIRST_WEAK_SLOT + 5 == Context::NATIVE_CONTEXT_SLOTS);
|
| }
|
| }
|
|
|
| @@ -1293,7 +1328,7 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
|
| "optimized_code_map", shared->optimized_code_map(),
|
| SharedFunctionInfo::kOptimizedCodeMapOffset);
|
| SetWeakReference(obj, entry,
|
| - 1, shared->initial_map(),
|
| + "initial_map", shared->initial_map(),
|
| SharedFunctionInfo::kInitialMapOffset);
|
| }
|
|
|
| @@ -1341,8 +1376,8 @@ void V8HeapExplorer::ExtractCodeCacheReferences(
|
| }
|
|
|
|
|
| -void V8HeapExplorer::TagCodeObject(Code* code, const char* external_name) {
|
| - TagObject(code, names_->GetFormatted("(%s code)", external_name));
|
| +void V8HeapExplorer::TagBuiltinCodeObject(Code* code, const char* name) {
|
| + TagObject(code, names_->GetFormatted("(%s builtin)", name));
|
| }
|
|
|
|
|
| @@ -1379,6 +1414,16 @@ void V8HeapExplorer::ExtractCodeReferences(int entry, Code* code) {
|
| SetInternalReference(code, entry,
|
| "constant_pool", code->constant_pool(),
|
| Code::kConstantPoolOffset);
|
| + if (code->kind() == Code::OPTIMIZED_FUNCTION) {
|
| + SetWeakReference(code, entry,
|
| + "next_code_link", code->next_code_link(),
|
| + Code::kNextCodeLinkOffset);
|
| + }
|
| +}
|
| +
|
| +
|
| +void V8HeapExplorer::ExtractBoxReferences(int entry, Box* box) {
|
| + SetInternalReference(box, entry, "value", box->value(), Box::kValueOffset);
|
| }
|
|
|
|
|
| @@ -1403,14 +1448,48 @@ void V8HeapExplorer::ExtractAllocationSiteReferences(int entry,
|
| AllocationSite::kTransitionInfoOffset);
|
| SetInternalReference(site, entry, "nested_site", site->nested_site(),
|
| AllocationSite::kNestedSiteOffset);
|
| - SetInternalReference(site, entry, "pretenure_data",
|
| - site->pretenure_data(),
|
| - AllocationSite::kPretenureDataOffset);
|
| - SetInternalReference(site, entry, "pretenure_create_count",
|
| - site->pretenure_create_count(),
|
| - AllocationSite::kPretenureCreateCountOffset);
|
| SetInternalReference(site, entry, "dependent_code", site->dependent_code(),
|
| AllocationSite::kDependentCodeOffset);
|
| + // Do not visit weak_next as it is not visited by the StaticVisitor,
|
| + // and we're not very interested in weak_next field here.
|
| + STATIC_CHECK(AllocationSite::kWeakNextOffset >=
|
| + AllocationSite::BodyDescriptor::kEndOffset);
|
| +}
|
| +
|
| +
|
| +class JSArrayBufferDataEntryAllocator : public HeapEntriesAllocator {
|
| + public:
|
| + JSArrayBufferDataEntryAllocator(size_t size, V8HeapExplorer* explorer)
|
| + : size_(size)
|
| + , explorer_(explorer) {
|
| + }
|
| + virtual HeapEntry* AllocateEntry(HeapThing ptr) {
|
| + return explorer_->AddEntry(
|
| + static_cast<Address>(ptr),
|
| + HeapEntry::kNative, "system / JSArrayBufferData", size_);
|
| + }
|
| + private:
|
| + size_t size_;
|
| + V8HeapExplorer* explorer_;
|
| +};
|
| +
|
| +
|
| +void V8HeapExplorer::ExtractJSArrayBufferReferences(
|
| + int entry, JSArrayBuffer* buffer) {
|
| + SetWeakReference(buffer, entry, "weak_next", buffer->weak_next(),
|
| + JSArrayBuffer::kWeakNextOffset);
|
| + SetWeakReference(buffer, entry,
|
| + "weak_first_view", buffer->weak_first_view(),
|
| + JSArrayBuffer::kWeakFirstViewOffset);
|
| + // Setup a reference to a native memory backing_store object.
|
| + if (!buffer->backing_store())
|
| + return;
|
| + size_t data_size = NumberToSize(heap_->isolate(), buffer->byte_length());
|
| + JSArrayBufferDataEntryAllocator allocator(data_size, this);
|
| + HeapEntry* data_entry =
|
| + filler_->FindOrAddEntry(buffer->backing_store(), &allocator);
|
| + filler_->SetNamedReference(HeapGraphEdge::kInternal,
|
| + entry, "backing_store", data_entry);
|
| }
|
|
|
|
|
| @@ -1635,24 +1714,20 @@ class RootsReferencesExtractor : public ObjectVisitor {
|
| }
|
| int strong_index = 0, all_index = 0, tags_index = 0, builtin_index = 0;
|
| while (all_index < all_references_.length()) {
|
| - if (strong_index < strong_references_.length() &&
|
| - strong_references_[strong_index] == all_references_[all_index]) {
|
| - explorer->SetGcSubrootReference(reference_tags_[tags_index].tag,
|
| - false,
|
| - all_references_[all_index]);
|
| - ++strong_index;
|
| - } else {
|
| - explorer->SetGcSubrootReference(reference_tags_[tags_index].tag,
|
| - true,
|
| - all_references_[all_index]);
|
| - }
|
| + bool is_strong = strong_index < strong_references_.length()
|
| + && strong_references_[strong_index] == all_references_[all_index];
|
| + explorer->SetGcSubrootReference(reference_tags_[tags_index].tag,
|
| + !is_strong,
|
| + all_references_[all_index]);
|
| if (reference_tags_[tags_index].tag ==
|
| VisitorSynchronization::kBuiltins) {
|
| ASSERT(all_references_[all_index]->IsCode());
|
| - explorer->TagCodeObject(Code::cast(all_references_[all_index]),
|
| + explorer->TagBuiltinCodeObject(
|
| + Code::cast(all_references_[all_index]),
|
| builtins->name(builtin_index++));
|
| }
|
| ++all_index;
|
| + if (is_strong) ++strong_index;
|
| if (reference_tags_[tags_index].index == all_index) ++tags_index;
|
| }
|
| }
|
| @@ -1677,11 +1752,21 @@ class RootsReferencesExtractor : public ObjectVisitor {
|
|
|
| bool V8HeapExplorer::IterateAndExtractReferences(
|
| SnapshotFillerInterface* filler) {
|
| - HeapIterator iterator(heap_, HeapIterator::kFilterUnreachable);
|
| -
|
| filler_ = filler;
|
| - bool interrupted = false;
|
|
|
| + // Make sure builtin code objects get their builtin tags
|
| + // first. Otherwise a particular JSFunction object could set
|
| + // its custom name to a generic builtin.
|
| + SetRootGcRootsReference();
|
| + RootsReferencesExtractor extractor(heap_);
|
| + heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG);
|
| + extractor.SetCollectingAllReferences();
|
| + heap_->IterateRoots(&extractor, VISIT_ALL);
|
| + extractor.FillReferences(this);
|
| +
|
| + // Now iterate the whole heap.
|
| + bool interrupted = false;
|
| + HeapIterator iterator(heap_, HeapIterator::kFilterUnreachable);
|
| // Heap iteration with filtering must be finished in any case.
|
| for (HeapObject* obj = iterator.next();
|
| obj != NULL;
|
| @@ -1696,12 +1781,6 @@ bool V8HeapExplorer::IterateAndExtractReferences(
|
| return false;
|
| }
|
|
|
| - SetRootGcRootsReference();
|
| - RootsReferencesExtractor extractor(heap_);
|
| - heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG);
|
| - extractor.SetCollectingAllReferences();
|
| - heap_->IterateRoots(&extractor, VISIT_ALL);
|
| - extractor.FillReferences(this);
|
| filler_ = NULL;
|
| return progress_->ProgressReport(true);
|
| }
|
| @@ -1823,17 +1902,17 @@ void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj,
|
|
|
| void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
|
| int parent_entry,
|
| - int index,
|
| + const char* reference_name,
|
| Object* child_obj,
|
| int field_offset) {
|
| ASSERT(parent_entry == GetEntry(parent_obj)->index());
|
| HeapEntry* child_entry = GetEntry(child_obj);
|
| if (child_entry == NULL) return;
|
| if (IsEssentialObject(child_obj)) {
|
| - filler_->SetIndexedReference(HeapGraphEdge::kWeak,
|
| - parent_entry,
|
| - index,
|
| - child_entry);
|
| + filler_->SetNamedReference(HeapGraphEdge::kWeak,
|
| + parent_entry,
|
| + reference_name,
|
| + child_entry);
|
| }
|
| IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
|
| }
|
| @@ -1905,10 +1984,17 @@ void V8HeapExplorer::SetGcSubrootReference(
|
| name,
|
| child_entry);
|
| } else {
|
| - filler_->SetIndexedAutoIndexReference(
|
| - is_weak ? HeapGraphEdge::kWeak : HeapGraphEdge::kElement,
|
| - snapshot_->gc_subroot(tag)->index(),
|
| - child_entry);
|
| + if (is_weak) {
|
| + filler_->SetNamedAutoIndexReference(
|
| + HeapGraphEdge::kWeak,
|
| + snapshot_->gc_subroot(tag)->index(),
|
| + child_entry);
|
| + } else {
|
| + filler_->SetIndexedAutoIndexReference(
|
| + HeapGraphEdge::kElement,
|
| + snapshot_->gc_subroot(tag)->index(),
|
| + child_entry);
|
| + }
|
| }
|
|
|
| // Add a shortcut to JS global object reference at snapshot root.
|
| @@ -2616,9 +2702,26 @@ int HeapSnapshotJSONSerializer::GetStringId(const char* s) {
|
| }
|
|
|
|
|
| -static int utoa(unsigned value, const Vector<char>& buffer, int buffer_pos) {
|
| +namespace {
|
| +
|
| +template<size_t size> struct ToUnsigned;
|
| +
|
| +template<> struct ToUnsigned<4> {
|
| + typedef uint32_t Type;
|
| +};
|
| +
|
| +template<> struct ToUnsigned<8> {
|
| + typedef uint64_t Type;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +
|
| +template<typename T>
|
| +static int utoa_impl(T value, const Vector<char>& buffer, int buffer_pos) {
|
| + STATIC_CHECK(static_cast<T>(-1) > 0); // Check that T is unsigned
|
| int number_of_digits = 0;
|
| - unsigned t = value;
|
| + T t = value;
|
| do {
|
| ++number_of_digits;
|
| } while (t /= 10);
|
| @@ -2626,7 +2729,7 @@ static int utoa(unsigned value, const Vector<char>& buffer, int buffer_pos) {
|
| buffer_pos += number_of_digits;
|
| int result = buffer_pos;
|
| do {
|
| - int last_digit = value % 10;
|
| + int last_digit = static_cast<int>(value % 10);
|
| buffer[--buffer_pos] = '0' + last_digit;
|
| value /= 10;
|
| } while (value);
|
| @@ -2634,6 +2737,14 @@ static int utoa(unsigned value, const Vector<char>& buffer, int buffer_pos) {
|
| }
|
|
|
|
|
| +template<typename T>
|
| +static int utoa(T value, const Vector<char>& buffer, int buffer_pos) {
|
| + typename ToUnsigned<sizeof(value)>::Type unsigned_value = value;
|
| + STATIC_CHECK(sizeof(value) == sizeof(unsigned_value));
|
| + return utoa_impl(unsigned_value, buffer, buffer_pos);
|
| +}
|
| +
|
| +
|
| void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge,
|
| bool first_edge) {
|
| // The buffer needs space for 3 unsigned ints, 3 commas, \n and \0
|
| @@ -2642,7 +2753,6 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge,
|
| EmbeddedVector<char, kBufferSize> buffer;
|
| int edge_name_or_index = edge->type() == HeapGraphEdge::kElement
|
| || edge->type() == HeapGraphEdge::kHidden
|
| - || edge->type() == HeapGraphEdge::kWeak
|
| ? edge->index() : GetStringId(edge->name());
|
| int buffer_pos = 0;
|
| if (!first_edge) {
|
| @@ -2671,9 +2781,10 @@ void HeapSnapshotJSONSerializer::SerializeEdges() {
|
|
|
|
|
| void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) {
|
| - // The buffer needs space for 5 unsigned ints, 5 commas, \n and \0
|
| + // The buffer needs space for 4 unsigned ints, 1 size_t, 5 commas, \n and \0
|
| static const int kBufferSize =
|
| - 5 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned // NOLINT
|
| + 4 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned // NOLINT
|
| + + MaxDecimalDigitsIn<sizeof(size_t)>::kUnsigned // NOLINT
|
| + 5 + 1 + 1;
|
| EmbeddedVector<char, kBufferSize> buffer;
|
| int buffer_pos = 0;
|
|
|