| 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
|
|
|
|
|
|
|