| Index: base/trace_event/memory_allocator_dump.cc
 | 
| diff --git a/base/trace_event/memory_allocator_dump.cc b/base/trace_event/memory_allocator_dump.cc
 | 
| index 1d2fb3f67ad08914d513f41a9bcb52a7675ad63e..77c32ec3d8ad7ccdeabe6655c9ae0e85cbe1871b 100644
 | 
| --- a/base/trace_event/memory_allocator_dump.cc
 | 
| +++ b/base/trace_event/memory_allocator_dump.cc
 | 
| @@ -15,114 +15,105 @@
 | 
|  namespace base {
 | 
|  namespace trace_event {
 | 
|  
 | 
| -// static
 | 
| -const char MemoryAllocatorDump::kRootHeap[] = "";
 | 
| -
 | 
| -// static
 | 
| -std::string MemoryAllocatorDump::GetAbsoluteName(
 | 
| -    const std::string& allocator_name,
 | 
| -    const std::string& heap_name) {
 | 
| -  return allocator_name + (heap_name == kRootHeap ? "" : "/" + heap_name);
 | 
| +namespace {
 | 
| +// Returns the c-string pointer from a dictionary value without performing extra
 | 
| +// std::string copies. The ptr will be valid as long as the value exists.
 | 
| +bool GetDictionaryValueAsCStr(const DictionaryValue* dict_value,
 | 
| +                              const std::string& key,
 | 
| +                              const char** out_cstr) {
 | 
| +  const Value* value = nullptr;
 | 
| +  const StringValue* str_value = nullptr;
 | 
| +  if (!dict_value->GetWithoutPathExpansion(key, &value))
 | 
| +    return false;
 | 
| +  if (!value->GetAsString(&str_value))
 | 
| +    return false;
 | 
| +  *out_cstr = str_value->GetString().c_str();
 | 
| +  return true;
 | 
|  }
 | 
| +}  // namespace
 | 
|  
 | 
| -MemoryAllocatorDump::MemoryAllocatorDump(const std::string& allocator_name,
 | 
| -                                         const std::string& heap_name,
 | 
| +const char MemoryAllocatorDump::kNameOuterSize[] = "outer_size";
 | 
| +const char MemoryAllocatorDump::kNameInnerSize[] = "inner_size";
 | 
| +const char MemoryAllocatorDump::kNameObjectsCount[] = "objects_count";
 | 
| +const char MemoryAllocatorDump::kTypeScalar[] = "scalar";
 | 
| +const char MemoryAllocatorDump::kTypeString[] = "string";
 | 
| +const char MemoryAllocatorDump::kUnitsBytes[] = "bytes";
 | 
| +const char MemoryAllocatorDump::kUnitsObjects[] = "objects";
 | 
| +
 | 
| +MemoryAllocatorDump::MemoryAllocatorDump(const std::string& absolute_name,
 | 
|                                           ProcessMemoryDump* process_memory_dump)
 | 
| -    : allocator_name_(allocator_name),
 | 
| -      heap_name_(heap_name),
 | 
| -      process_memory_dump_(process_memory_dump),
 | 
| -      physical_size_in_bytes_(0),
 | 
| -      allocated_objects_count_(0),
 | 
| -      allocated_objects_size_in_bytes_(0) {
 | 
| -  // The allocator name cannot be empty or contain slash separators.
 | 
| -  DCHECK(!allocator_name.empty());
 | 
| -  DCHECK_EQ(std::string::npos, allocator_name.find_first_of('/'));
 | 
| -
 | 
| -  // The heap_name can be empty and contain slash separator, but not
 | 
| -  // leading or trailing ones.
 | 
| -  DCHECK(heap_name.empty() ||
 | 
| -         (heap_name[0] != '/' && *heap_name.rbegin() != '/'));
 | 
| +    : absolute_name_(absolute_name), process_memory_dump_(process_memory_dump) {
 | 
| +  // The |absolute_name| cannot be empty.
 | 
| +  DCHECK(!absolute_name.empty());
 | 
| +
 | 
| +  // The |absolute_name| can contain slash separator, but not leading or
 | 
| +  // trailing ones.
 | 
| +  DCHECK(absolute_name[0] != '/' && *absolute_name.rbegin() != '/');
 | 
|  
 | 
|    // Dots are not allowed anywhere as the underlying base::DictionaryValue
 | 
|    // would treat them magically and split in sub-nodes, which is not intended.
 | 
| -  DCHECK_EQ(std::string::npos, allocator_name.find_first_of('.'));
 | 
| -  DCHECK_EQ(std::string::npos, heap_name.find_first_of('.'));
 | 
| +  DCHECK_EQ(std::string::npos, absolute_name.find_first_of('.'));
 | 
|  }
 | 
|  
 | 
|  MemoryAllocatorDump::~MemoryAllocatorDump() {
 | 
|  }
 | 
|  
 | 
| -void MemoryAllocatorDump::SetAttribute(const std::string& name, int value) {
 | 
| -  DCHECK(GetAttributesTypeInfo().Exists(allocator_name_, name))
 | 
| -      << "attribute '" << name << "' not declared."
 | 
| -      << "See MemoryDumpProvider.DeclareAllocatorAttribute()";
 | 
| -  attributes_values_.SetInteger(name, value);
 | 
| +void MemoryAllocatorDump::Add(const std::string& name,
 | 
| +                              const char* type,
 | 
| +                              const char* units,
 | 
| +                              scoped_ptr<Value> value) {
 | 
| +  scoped_ptr<DictionaryValue> attribute(new DictionaryValue());
 | 
| +  DCHECK(!attributes_.HasKey(name));
 | 
| +  attribute->SetStringWithoutPathExpansion("type", type);
 | 
| +  attribute->SetStringWithoutPathExpansion("units", units);
 | 
| +  attribute->SetWithoutPathExpansion("value", value.Pass());
 | 
| +  attributes_.SetWithoutPathExpansion(name, attribute.Pass());
 | 
|  }
 | 
|  
 | 
| -std::string MemoryAllocatorDump::GetAbsoluteName() const {
 | 
| -  return GetAbsoluteName(allocator_name_, heap_name_);
 | 
| +bool MemoryAllocatorDump::Get(const std::string& name,
 | 
| +                              const char** out_type,
 | 
| +                              const char** out_units,
 | 
| +                              const Value** out_value) const {
 | 
| +  const DictionaryValue* attribute = nullptr;
 | 
| +  if (!attributes_.GetDictionaryWithoutPathExpansion(name, &attribute))
 | 
| +    return false;
 | 
| +
 | 
| +  if (!GetDictionaryValueAsCStr(attribute, "type", out_type))
 | 
| +    return false;
 | 
| +
 | 
| +  if (!GetDictionaryValueAsCStr(attribute, "units", out_units))
 | 
| +    return false;
 | 
| +
 | 
| +  if (!attribute->GetWithoutPathExpansion("value", out_value))
 | 
| +    return false;
 | 
| +
 | 
| +  return true;
 | 
|  }
 | 
|  
 | 
| -int MemoryAllocatorDump::GetIntegerAttribute(const std::string& name) const {
 | 
| -  int value = -1;
 | 
| -  bool res = attributes_values_.GetInteger(name, &value);
 | 
| -  DCHECK(res) << "Attribute '" << name << "' not found";
 | 
| -  return value;
 | 
| +void MemoryAllocatorDump::AddScalar(const std::string& name,
 | 
| +                                    const char* units,
 | 
| +                                    uint64 value) {
 | 
| +  scoped_ptr<Value> hex_value(new StringValue(StringPrintf("%" PRIx64, value)));
 | 
| +  Add(name, kTypeScalar, units, hex_value.Pass());
 | 
|  }
 | 
|  
 | 
| -void MemoryAllocatorDump::AsValueInto(TracedValue* value) const {
 | 
| -  static const char kHexFmt[] = "%" PRIx64;
 | 
| +void MemoryAllocatorDump::AddString(const std::string& name,
 | 
| +                                    const char* units,
 | 
| +                                    const std::string& value) {
 | 
| +  scoped_ptr<Value> str_value(new StringValue(value));
 | 
| +  Add(name, kTypeString, units, str_value.Pass());
 | 
| +}
 | 
|  
 | 
| -  value->BeginDictionary(GetAbsoluteName().c_str());
 | 
| +void MemoryAllocatorDump::AsValueInto(TracedValue* value) const {
 | 
| +  value->BeginDictionary(absolute_name_.c_str());
 | 
|    value->BeginDictionary("attrs");
 | 
|  
 | 
| -  // TODO(primiano): these hard-coded types are temporary to transition to the
 | 
| -  // new generalized attribute format. This code will be refactored by the end
 | 
| -  // of May 2015.
 | 
| -  value->BeginDictionary("outer_size");
 | 
| -  value->SetString("type", "scalar");
 | 
| -  value->SetString("units", "bytes");
 | 
| -  value->SetString("value", StringPrintf(kHexFmt, physical_size_in_bytes_));
 | 
| -  value->EndDictionary();
 | 
| -
 | 
| -  value->BeginDictionary("inner_size");
 | 
| -  value->SetString("type", "scalar");
 | 
| -  value->SetString("units", "bytes");
 | 
| -  value->SetString("value",
 | 
| -                   StringPrintf(kHexFmt, allocated_objects_size_in_bytes_));
 | 
| -  value->EndDictionary();
 | 
| -
 | 
| -  value->BeginDictionary("objects_count");
 | 
| -  value->SetString("type", "scalar");
 | 
| -  value->SetString("units", "objects");
 | 
| -  value->SetString("value", StringPrintf(kHexFmt, allocated_objects_count_));
 | 
| -  value->EndDictionary();
 | 
| -
 | 
| -  // Copy all the extra attributes.
 | 
| -  for (DictionaryValue::Iterator it(attributes_values_); !it.IsAtEnd();
 | 
| -       it.Advance()) {
 | 
| -    const std::string& attr_name = it.key();
 | 
| -    const Value& attr_value = it.value();
 | 
| -    value->BeginDictionary(attr_name.c_str());
 | 
| -    value->SetValue("value", attr_value.DeepCopy());
 | 
| -
 | 
| -    const std::string& attr_type =
 | 
| -        GetAttributesTypeInfo().Get(allocator_name_, attr_name);
 | 
| -    DCHECK(!attr_type.empty());
 | 
| -    value->SetString("type", "scalar");
 | 
| -    value->SetString("units", attr_type);
 | 
| -
 | 
| -    value->EndDictionary();  // "arg_name": { "type": "...", "value": "..." }
 | 
| -  }
 | 
| +  for (DictionaryValue::Iterator it(attributes_); !it.IsAtEnd(); it.Advance())
 | 
| +    value->SetValue(it.key().c_str(), it.value().DeepCopy());
 | 
|  
 | 
|    value->EndDictionary();  // "attrs": { ... }
 | 
|    value->EndDictionary();  // "allocator_name/heap_subheap": { ... }
 | 
|  }
 | 
|  
 | 
| -const MemoryAllocatorAttributesTypeInfo&
 | 
| -MemoryAllocatorDump::GetAttributesTypeInfo() const {
 | 
| -  return process_memory_dump_->session_state()->allocators_attributes_type_info;
 | 
| -}
 | 
| -
 | 
|  }  // namespace trace_event
 | 
|  }  // namespace base
 | 
| 
 |