[log] Use log for --trace-maps

This is an intermediate CL to move the complete --trace-map infrastructure to
a log-based version.

Change-Id: I0673052b1b87fe338e38dc609434a52af6a0652d
Reviewed-on: https://chromium-review.googlesource.com/738835
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48988}
This commit is contained in:
Camillo Bruni 2017-10-26 20:01:08 -07:00 committed by Commit Bot
parent e8636cd75b
commit c3ad1e9067
11 changed files with 159 additions and 82 deletions

View File

@ -5353,14 +5353,13 @@ Genesis::Genesis(
isolate->set_context(*native_context()); isolate->set_context(*native_context());
isolate->counters()->contexts_created_by_snapshot()->Increment(); isolate->counters()->contexts_created_by_snapshot()->Increment();
if (FLAG_trace_maps) { if (FLAG_trace_maps) {
DisallowHeapAllocation no_gc;
Handle<JSFunction> object_fun = isolate->object_function(); Handle<JSFunction> object_fun = isolate->object_function();
int sfi_id = -1; Map* initial_map = object_fun->initial_map();
#if V8_SFI_HAS_UNIQUE_ID LOG(isolate, MapDetails(initial_map));
sfi_id = object_fun->shared()->unique_id(); LOG(isolate, MapEvent("InitialMap", nullptr, initial_map, "Object",
#endif // V8_SFI_HAS_UNIQUE_ID object_fun->shared()));
PrintF("[TraceMap: InitialMap map= %p SFI= %d_Object ]\n", LOG(isolate, LogAllTransitions(initial_map));
reinterpret_cast<void*>(object_fun->initial_map()), sfi_id);
Map::TraceAllTransitions(object_fun->initial_map());
} }
if (context_snapshot_index == 0) { if (context_snapshot_index == 0) {

View File

@ -873,6 +873,7 @@ DEFINE_BOOL(trace_prototype_users, false,
DEFINE_BOOL(use_verbose_printer, true, "allows verbose printing") DEFINE_BOOL(use_verbose_printer, true, "allows verbose printing")
DEFINE_BOOL(trace_for_in_enumerate, false, "Trace for-in enumerate slow-paths") DEFINE_BOOL(trace_for_in_enumerate, false, "Trace for-in enumerate slow-paths")
DEFINE_BOOL(trace_maps, false, "trace map creation") DEFINE_BOOL(trace_maps, false, "trace map creation")
DEFINE_IMPLICATION(trace_maps, log_code)
// parser.cc // parser.cc
DEFINE_BOOL(allow_natives_syntax, false, "allow natives syntax") DEFINE_BOOL(allow_natives_syntax, false, "allow natives syntax")

View File

@ -139,6 +139,7 @@ void Log::MessageBuilder::AppendString(String* str) {
} }
void Log::MessageBuilder::AppendString(const char* string) { void Log::MessageBuilder::AppendString(const char* string) {
if (string == nullptr) return;
for (const char* p = string; *p != '\0'; p++) { for (const char* p = string; *p != '\0'; p++) {
this->AppendCharacter(*p); this->AppendCharacter(*p);
} }

View File

@ -1352,6 +1352,65 @@ void Logger::ICEvent(const char* type, bool keyed, Map* map, Object* key,
msg.WriteToLogFile(); msg.WriteToLogFile();
} }
void Logger::LogAllTransitions(Map* map) {
DisallowHeapAllocation no_gc;
if (!log_->IsEnabled() || !FLAG_trace_maps) return;
TransitionsAccessor transitions(map, &no_gc);
int num_transitions = transitions.NumberOfTransitions();
for (int i = 0; i < num_transitions; ++i) {
Map* target = transitions.GetTarget(i);
Name* key = transitions.GetKey(i);
MapDetails(target);
MapEvent("Transition", map, target, nullptr, key);
LogAllTransitions(target);
}
}
void Logger::MapEvent(const char* type, Map* from, Map* to, const char* reason,
HeapObject* name_or_sfi) {
DisallowHeapAllocation no_gc;
if (!log_->IsEnabled() || !FLAG_trace_maps) return;
// TODO(cbruni): Remove once --trace-maps is fully migrated.
if (from) MapDetails(from);
if (to) MapDetails(to);
int line = -1;
int column = -1;
Address pc = 0;
if (!isolate_->bootstrapper()->IsActive()) {
pc = isolate_->GetAbstractPC(&line, &column);
}
Log::MessageBuilder msg(log_);
msg << "map" << kNext << type << kNext << timer_.Elapsed().InMicroseconds()
<< kNext << reinterpret_cast<void*>(from) << kNext
<< reinterpret_cast<void*>(to) << kNext << reinterpret_cast<void*>(pc)
<< kNext << line << kNext << column << kNext << reason << kNext;
if (name_or_sfi) {
if (name_or_sfi->IsName()) {
msg << Name::cast(name_or_sfi);
} else if (name_or_sfi->IsSharedFunctionInfo()) {
SharedFunctionInfo* sfi = SharedFunctionInfo::cast(name_or_sfi);
msg << sfi->DebugName();
#if V8_SFI_HAS_UNIQUE_ID
msg << " " << sfi->unique_id();
#endif // V8_SFI_HAS_UNIQUE_ID
}
}
msg.WriteToLogFile();
}
void Logger::MapDetails(Map* map) {
if (!log_->IsEnabled() || !FLAG_trace_maps) return;
DisallowHeapAllocation no_gc;
Log::MessageBuilder msg(log_);
msg << "map-details" << kNext << timer_.Elapsed().InMicroseconds() << kNext
<< reinterpret_cast<void*>(map) << kNext;
std::ostringstream buffer;
map->PrintMapDetails(buffer);
msg << buffer.str().c_str();
msg.WriteToLogFile();
}
void Logger::StopProfiler() { void Logger::StopProfiler() {
if (!log_->IsEnabled()) return; if (!log_->IsEnabled()) return;
if (profiler_ != nullptr) { if (profiler_ != nullptr) {

View File

@ -195,6 +195,12 @@ class Logger : public CodeEventListener {
char old_state, char new_state, const char* modifier, char old_state, char new_state, const char* modifier,
const char* slow_stub_reason); const char* slow_stub_reason);
void LogAllTransitions(Map* map);
void MapEvent(const char* type, Map* from, Map* to,
const char* reason = nullptr,
HeapObject* name_or_sfi = nullptr);
void MapDetails(Map* map);
// ==== Events logged by --log-gc. ==== // ==== Events logged by --log-gc. ====
// Heap sampling events: start, end, and individual types. // Heap sampling events: start, end, and individual types.
void HeapSampleBeginEvent(const char* space, const char* kind); void HeapSampleBeginEvent(const char* space, const char* kind);

View File

@ -3419,6 +3419,9 @@ bool Map::is_callable() const {
void Map::deprecate() { void Map::deprecate() {
set_bit_field3(Deprecated::update(bit_field3(), true)); set_bit_field3(Deprecated::update(bit_field3(), true));
if (FLAG_trace_maps) {
LOG(GetIsolate(), MapEvent("Deprecate", this, nullptr));
}
} }
bool Map::is_deprecated() const { return Deprecated::decode(bit_field3()); } bool Map::is_deprecated() const { return Deprecated::decode(bit_field3()); }

View File

@ -1652,29 +1652,20 @@ int Name::NameShortPrint(Vector<char> str) {
} }
} }
#if defined(DEBUG) || defined(OBJECT_PRINT) void Map::PrintMapDetails(std::ostream& os, JSObject* holder) {
// This method is only meant to be called from gdb for debugging purposes. DisallowHeapAllocation no_gc;
// Since the string can also be in two-byte encoding, non-Latin1 characters #ifdef OBJECT_PRINT
// will be ignored in the output. this->MapPrint(os);
char* String::ToAsciiArray() { #else
// Static so that subsequent calls frees previously allocated space. os << "Map=" << reinterpret_cast<void*>(this);
// This also means that previous results will be overwritten. #endif
static char* buffer = nullptr; os << "\n";
if (buffer != nullptr) delete[] buffer; instance_descriptors()->PrintDescriptors(os);
buffer = new char[length() + 1]; if (is_dictionary_map() && holder != nullptr) {
WriteToFlat(this, reinterpret_cast<uint8_t*>(buffer), 0, length()); os << holder->property_dictionary() << "\n";
buffer[length()] = 0; }
return buffer;
} }
void DescriptorArray::Print() {
OFStream os(stdout);
this->PrintDescriptors(os);
os << std::flush;
}
void DescriptorArray::PrintDescriptors(std::ostream& os) { // NOLINT void DescriptorArray::PrintDescriptors(std::ostream& os) { // NOLINT
HandleScope scope(GetIsolate()); HandleScope scope(GetIsolate());
os << "Descriptor array #" << number_of_descriptors() << ":"; os << "Descriptor array #" << number_of_descriptors() << ":";
@ -1715,6 +1706,26 @@ void DescriptorArray::PrintDescriptorDetails(std::ostream& os, int descriptor,
} }
} }
#if defined(DEBUG) || defined(OBJECT_PRINT)
// This method is only meant to be called from gdb for debugging purposes.
// Since the string can also be in two-byte encoding, non-Latin1 characters
// will be ignored in the output.
char* String::ToAsciiArray() {
// Static so that subsequent calls frees previously allocated space.
// This also means that previous results will be overwritten.
static char* buffer = nullptr;
if (buffer != nullptr) delete[] buffer;
buffer = new char[length() + 1];
WriteToFlat(this, reinterpret_cast<uint8_t*>(buffer), 0, length());
buffer[length()] = 0;
return buffer;
}
void DescriptorArray::Print() {
OFStream os(stdout);
this->PrintDescriptors(os);
os << std::flush;
}
// static // static
void TransitionsAccessor::PrintOneTransition(std::ostream& os, Name* key, void TransitionsAccessor::PrintOneTransition(std::ostream& os, Name* key,
Map* target, Object* raw_target) { Map* target, Object* raw_target) {

View File

@ -6219,9 +6219,7 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
NotifyMapChange(old_map, new_map, isolate); NotifyMapChange(old_map, new_map, isolate);
if (FLAG_trace_maps) { if (FLAG_trace_maps) {
PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n", LOG(isolate, MapEvent("SlowToFast", *old_map, *new_map, reason));
reinterpret_cast<void*>(*old_map), reinterpret_cast<void*>(*new_map),
reason);
} }
if (instance_descriptor_length == 0) { if (instance_descriptor_length == 0) {
@ -9040,9 +9038,7 @@ Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode,
isolate->counters()->maps_normalized()->Increment(); isolate->counters()->maps_normalized()->Increment();
} }
if (FLAG_trace_maps) { if (FLAG_trace_maps) {
PrintF("[TraceMaps: Normalize from= %p to= %p reason= %s ]\n", LOG(isolate, MapEvent("Normalize", *fast_map, *new_map, reason));
reinterpret_cast<void*>(*fast_map),
reinterpret_cast<void*>(*new_map), reason);
} }
} }
fast_map->NotifyLeafMapLayoutChange(); fast_map->NotifyLeafMapLayoutChange();
@ -9208,30 +9204,6 @@ Handle<Map> Map::ShareDescriptor(Handle<Map> map,
return result; return result;
} }
// static
void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) {
if (FLAG_trace_maps) {
PrintF("[TraceMaps: %s from= %p to= %p name= ", what,
reinterpret_cast<void*>(from), reinterpret_cast<void*>(to));
name->NameShortPrint();
PrintF(" ]\n");
}
}
// static
void Map::TraceAllTransitions(Map* map) {
DisallowHeapAllocation no_gc;
TransitionsAccessor transitions(map, &no_gc);
int num_transitions = transitions.NumberOfTransitions();
for (int i = -0; i < num_transitions; ++i) {
Map* target = transitions.GetTarget(i);
Name* key = transitions.GetKey(i);
Map::TraceTransition("Transition", map, target, key);
Map::TraceAllTransitions(target);
}
}
void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child, void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
Handle<Name> name, SimpleTransitionFlag flag) { Handle<Name> name, SimpleTransitionFlag flag) {
Isolate* isolate = parent->GetIsolate(); Isolate* isolate = parent->GetIsolate();
@ -9255,10 +9227,14 @@ void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
} }
if (parent->is_prototype_map()) { if (parent->is_prototype_map()) {
DCHECK(child->is_prototype_map()); DCHECK(child->is_prototype_map());
Map::TraceTransition("NoTransition", *parent, *child, *name); if (FLAG_trace_maps) {
LOG(isolate, MapEvent("Transition", *parent, *child, "prototype", *name));
}
} else { } else {
TransitionsAccessor(parent).Insert(name, child, flag); TransitionsAccessor(parent).Insert(name, child, flag);
Map::TraceTransition("Transition", *parent, *child, *name); if (FLAG_trace_maps) {
LOG(isolate, MapEvent("Transition", *parent, *child, "", *name));
}
} }
} }
@ -9298,9 +9274,8 @@ Handle<Map> Map::CopyReplaceDescriptors(
(map->is_prototype_map() || (map->is_prototype_map() ||
!(flag == INSERT_TRANSITION && !(flag == INSERT_TRANSITION &&
TransitionsAccessor(map).CanHaveMoreTransitions()))) { TransitionsAccessor(map).CanHaveMoreTransitions()))) {
PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n", LOG(map->GetIsolate(), MapEvent("ReplaceDescriptors", *map, *result, reason,
reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result), maybe_name.is_null() ? nullptr : *name));
reason);
} }
return result; return result;
} }
@ -9488,11 +9463,9 @@ Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) {
} }
if (FLAG_trace_maps) { if (FLAG_trace_maps) {
PrintF("[TraceMaps: CopyForTransition from= %p to= %p reason= %s ]\n", LOG(map->GetIsolate(),
reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*new_map), MapEvent("CopyForTransition", *map, *new_map, reason));
reason);
} }
return new_map; return new_map;
} }
@ -12743,13 +12716,8 @@ void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
function->set_prototype_or_initial_map(*map); function->set_prototype_or_initial_map(*map);
map->SetConstructor(*function); map->SetConstructor(*function);
if (FLAG_trace_maps) { if (FLAG_trace_maps) {
int sfi_id = -1; LOG(map->GetIsolate(), MapEvent("InitialMap", nullptr, *map, "",
#if V8_SFI_HAS_UNIQUE_ID function->shared()->DebugName()));
sfi_id = function->shared()->unique_id();
#endif // V8_SFI_HAS_UNIQUE_ID
PrintF("[TraceMaps: InitialMap map= %p SFI= %d_%s ]\n",
reinterpret_cast<void*>(*map), sfi_id,
function->shared()->DebugName()->ToCString().get());
} }
} }

View File

@ -141,15 +141,14 @@ class DescriptorArray : public FixedArray {
static const int kEntryValueIndex = 2; static const int kEntryValueIndex = 2;
static const int kEntrySize = 3; static const int kEntrySize = 3;
// Print all the descriptors.
void PrintDescriptors(std::ostream& os); // NOLINT
void PrintDescriptorDetails(std::ostream& os, int descriptor,
PropertyDetails::PrintMode mode);
#if defined(DEBUG) || defined(OBJECT_PRINT) #if defined(DEBUG) || defined(OBJECT_PRINT)
// For our gdb macros, we should perhaps change these in the future. // For our gdb macros, we should perhaps change these in the future.
void Print(); void Print();
// Print all the descriptors.
void PrintDescriptors(std::ostream& os); // NOLINT
void PrintDescriptorDetails(std::ostream& os, int descriptor,
PropertyDetails::PrintMode mode);
#endif #endif
#ifdef DEBUG #ifdef DEBUG

View File

@ -833,8 +833,7 @@ class Map : public HeapObject {
// Returns true if given field is unboxed double. // Returns true if given field is unboxed double.
inline bool IsUnboxedDoubleField(FieldIndex index) const; inline bool IsUnboxedDoubleField(FieldIndex index) const;
static void TraceTransition(const char* what, Map* from, Map* to, Name* name); void PrintMapDetails(std::ostream& os, JSObject* holder = nullptr);
static void TraceAllTransitions(Map* map);
static inline Handle<Map> AddMissingTransitionsForTesting( static inline Handle<Map> AddMissingTransitionsForTesting(
Handle<Map> split_map, Handle<DescriptorArray> descriptors, Handle<Map> split_map, Handle<DescriptorArray> descriptors,

View File

@ -697,3 +697,34 @@ TEST(LogAll) {
} }
isolate->Dispose(); isolate->Dispose();
} }
TEST(TraceMaps) {
SETUP_FLAGS();
i::FLAG_trace_maps = true;
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
{
ScopedLoggerInitializer logger(saved_log, saved_prof, isolate);
// Try to create many different kind of maps to make sure the logging won't
// crash. More detailed tests are implemented separately.
const char* source_text =
"let a = {};"
"for (let i = 0; i < 500; i++) { a['p'+i] = i };"
"class Test { constructor(i) { this.a = 1; this['p'+i] = 1; }};"
"let t = new Test();"
"t.b = 1; t.c = 1; t.d = 3;"
"for (let i = 0; i < 100; i++) { t = new Test(i) };"
"t.b = {};";
CompileRun(source_text);
logger.StopLogging();
// Mostly superficial checks.
CHECK(logger.FindLine("map,InitialMap", ",0x"));
CHECK(logger.FindLine("map,Transition", ",0x"));
CHECK(logger.FindLine("map-details", ",0x"));
}
i::FLAG_trace_maps = false;
isolate->Dispose();
}