Index: src/log.cc |
diff --git a/src/log.cc b/src/log.cc |
index 9acb7f785754d9436ac705c690402fa0f1e52683..0dec99af18122c6dbb9fc1de24169640a722dc14 100644 |
--- a/src/log.cc |
+++ b/src/log.cc |
@@ -30,6 +30,7 @@ |
#include "v8.h" |
#include "bootstrapper.h" |
+#include "global-handles.h" |
#include "log.h" |
#include "macro-assembler.h" |
#include "serialize.h" |
@@ -637,6 +638,24 @@ void Logger::DeleteEvent(const char* name, void* object) { |
} |
+void Logger::CallbackEvent(const char* class_name, const char* method_name, |
+ Address entry_point) { |
+#ifdef ENABLE_LOGGING_AND_PROFILING |
+ if (!Log::IsEnabled() || !FLAG_log_code) return; |
+ LogMessageBuilder msg; |
+ msg.Append("%s,%s,", |
+ log_events_[CODE_CREATION_EVENT], log_events_[CALLBACK_TAG]); |
+ msg.AppendAddress(entry_point); |
+ msg.Append(",0,\""); |
+ if (class_name != NULL) { |
+ msg.Append("%s.", class_name); |
+ } |
+ msg.Append("%s\"\n", method_name); |
+ msg.WriteToLogFile(); |
+#endif |
+} |
+ |
+ |
#ifdef ENABLE_LOGGING_AND_PROFILING |
// A class that contains all common code dealing with record compression. |
@@ -1071,6 +1090,7 @@ void Logger::ResumeProfiler(int flags) { |
LOG(UncheckedStringEvent("profiler", "resume")); |
FLAG_log_code = true; |
LogCompiledFunctions(); |
+ LogCallbacks(); |
if (!FLAG_sliding_state_window) ticker_->Start(); |
} |
profiler_->resume(); |
@@ -1201,6 +1221,69 @@ void Logger::LogCompiledFunctions() { |
DeleteArray(sfis); |
} |
+ |
+namespace { |
+ |
+class FunctionTemplateInfosVisitor : public ObjectVisitor { |
+ public: |
+ virtual ~FunctionTemplateInfosVisitor() {} |
+ virtual void VisitPointers(Object** start, Object** end) { |
+ for (Object** p = start; p < end; ++p) { |
+ VisitFTI(*p); |
+ } |
+ } |
+ |
+ private: |
+ void VisitFTI(Object* o) { |
+ // The data about callbacks is in fact dynamically typed |
+ // (Object ptrs are used), so we use runtime type checking |
+ // to be sure that we retrieve the right thing. |
+ if (!o->IsFunctionTemplateInfo()) |
+ return; |
+ AssertNoAllocation no_alloc; |
+ FunctionTemplateInfo* fti = FunctionTemplateInfo::cast(o); |
+ if (!fti->prototype_template()->IsObjectTemplateInfo()) |
+ return; |
+ SmartPointer<char> class_name; |
+ if (fti->class_name()->IsString()) { |
+ class_name = String::cast(fti->class_name())-> |
+ ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); |
+ } |
+ ObjectTemplateInfo* proto = |
+ ObjectTemplateInfo::cast(fti->prototype_template()); |
+ NeanderArray props(Handle<Object>(proto->property_list())); |
+ // Properties are triples: [property name, entry point, attributes]. |
+ // See Template::Set in api.cc. |
+ for (int i = 0; i < props.length(); i += 3) { |
+ if (!props.get(i)->IsString() |
+ || !props.get(i + 1)->IsFunctionTemplateInfo()) |
+ continue; |
+ FunctionTemplateInfo* native_fti = |
+ FunctionTemplateInfo::cast(props.get(i + 1)); |
+ Object* raw_call_data = native_fti->call_code(); |
+ if (raw_call_data->IsUndefined()) |
+ continue; |
+ CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data); |
+ Object* callback_obj = call_data->callback(); |
+ Address entry_point = v8::ToCData<Address>(callback_obj); |
+ SmartPointer<char> method_name( |
+ String::cast(props.get(i))-> |
+ ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL)); |
+ LOG(CallbackEvent(*class_name, *method_name, entry_point)); |
+ } |
+ } |
+}; |
+ |
+} // anonymous namespace |
+ |
+ |
+void Logger::LogCallbacks() { |
+ // We are looking for callbacks information exposed via persistent |
+ // FunctionTemplate objects. |
+ FunctionTemplateInfosVisitor visitor; |
+ GlobalHandles::IterateStrongRoots(&visitor); |
+} |
+ |
#endif |