Fix CPU profiling for Crankshaft.
authormikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 22 Feb 2011 16:31:24 +0000 (16:31 +0000)
committermikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 22 Feb 2011 16:31:24 +0000 (16:31 +0000)
The main issue was due to multiple recompilations of functions.  Now
code objects are grouped by function using SFI object address.
JSFunction objects are no longer tracked, instead we track SFI object
moves. To pick a correct code version, we now sample return addresses
instead of JSFunction addresses.

tools/{linux|mac|windows}-tickprocessor scripts differentiate
between code optimization states for the same function
(using * and ~ prefixes introduced earlier).

DevTools CPU profiler treats all variants of function code as
a single function.

ll_prof treats each optimized variant as a separate entry, because
it can disassemble each one of them.

tickprocessor.py not updated -- it is deprecated and will be removed.

BUG=v8/1087,b/3178160
TEST=all existing tests pass, including Chromium layout tests

Review URL: http://codereview.chromium.org/6551011

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6902 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

24 files changed:
src/compiler.cc
src/compiler.h
src/cpu-profiler-inl.h
src/cpu-profiler.cc
src/cpu-profiler.h
src/handles.cc
src/heap.cc
src/hydrogen.cc
src/log-utils.cc
src/log.cc
src/log.h
src/mark-compact.cc
src/platform.h
src/profile-generator-inl.h
src/profile-generator.cc
src/profile-generator.h
test/cctest/test-cpu-profiler.cc
test/cctest/test-log-stack-tracer.cc
test/cctest/test-log.cc
test/cctest/test-profile-generator.cc
test/mjsunit/tools/tickprocessor-test-func-info.log
tools/ll_prof.py
tools/profile.js
tools/tickprocessor.js

index 5b49cdf..f392cce 100755 (executable)
@@ -261,10 +261,8 @@ static bool MakeCrankshaftCode(CompilationInfo* info) {
       Handle<SharedFunctionInfo> shared = info->shared_info();
       shared->EnableDeoptimizationSupport(*unoptimized.code());
       // The existing unoptimized code was replaced with the new one.
-      Compiler::RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG,
-          Handle<String>(shared->DebugName()),
-          shared->start_position(),
-          &unoptimized);
+      Compiler::RecordFunctionCompilation(
+          Logger::LAZY_COMPILE_TAG, &unoptimized, shared);
     }
   }
 
@@ -414,13 +412,25 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
     return Handle<SharedFunctionInfo>::null();
   }
 
+  // Allocate function.
   ASSERT(!info->code().is_null());
+  Handle<SharedFunctionInfo> result =
+      Factory::NewSharedFunctionInfo(
+          lit->name(),
+          lit->materialized_literal_count(),
+          info->code(),
+          SerializedScopeInfo::Create(info->scope()));
+
+  ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
+  Compiler::SetFunctionInfo(result, lit, true, script);
+
   if (script->name()->IsString()) {
     PROFILE(CodeCreateEvent(
         info->is_eval()
             ? Logger::EVAL_TAG
             : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
         *info->code(),
+        *result,
         String::cast(script->name())));
     GDBJIT(AddCode(Handle<String>(String::cast(script->name())),
                    script,
@@ -431,21 +441,11 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
             ? Logger::EVAL_TAG
             : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
         *info->code(),
-        ""));
+        *result,
+        Heap::empty_string()));
     GDBJIT(AddCode(Handle<String>(), script, info->code()));
   }
 
-  // Allocate function.
-  Handle<SharedFunctionInfo> result =
-      Factory::NewSharedFunctionInfo(
-          lit->name(),
-          lit->materialized_literal_count(),
-          info->code(),
-          SerializedScopeInfo::Create(info->scope()));
-
-  ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
-  Compiler::SetFunctionInfo(result, lit, true, script);
-
   // Hint to the runtime system used when allocating space for initial
   // property space by setting the expected number of properties for
   // the instances of the function.
@@ -612,10 +612,7 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
       ASSERT(!info->code().is_null());
       Handle<Code> code = info->code();
       Handle<JSFunction> function = info->closure();
-      RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG,
-                                Handle<String>(shared->DebugName()),
-                                shared->start_position(),
-                                info);
+      RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared);
 
       if (info->IsOptimizing()) {
         function->ReplaceCode(*code);
@@ -723,10 +720,6 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
     ASSERT(!info.code().is_null());
 
     // Function compilation complete.
-    RecordFunctionCompilation(Logger::FUNCTION_TAG,
-                              literal->debug_name(),
-                              literal->start_position(),
-                              &info);
     scope_info = SerializedScopeInfo::Create(info.scope());
   }
 
@@ -737,6 +730,7 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
                                      info.code(),
                                      scope_info);
   SetFunctionInfo(result, literal, false, script);
+  RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result);
   result->set_allows_lazy_compilation(allow_lazy);
 
   // Set the expected number of properties for instances and return
@@ -775,28 +769,31 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
 
 
 void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag,
-                                         Handle<String> name,
-                                         int start_position,
-                                         CompilationInfo* info) {
+                                         CompilationInfo* info,
+                                         Handle<SharedFunctionInfo> shared) {
+  // SharedFunctionInfo is passed separately, because if CompilationInfo
+  // was created using Script object, it will not have it.
+
   // Log the code generation. If source information is available include
   // script name and line number. Check explicitly whether logging is
   // enabled as finding the line number is not free.
-  if (Logger::is_logging() ||
-      CpuProfiler::is_profiling()) {
+  if (Logger::is_logging() || CpuProfiler::is_profiling()) {
     Handle<Script> script = info->script();
     Handle<Code> code = info->code();
+    if (*code == Builtins::builtin(Builtins::LazyCompile)) return;
     if (script->name()->IsString()) {
-      int line_num = GetScriptLineNumber(script, start_position) + 1;
+      int line_num = GetScriptLineNumber(script, shared->start_position()) + 1;
       USE(line_num);
       PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
                               *code,
-                              *name,
+                              *shared,
                               String::cast(script->name()),
                               line_num));
     } else {
       PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
                               *code,
-                              *name));
+                              *shared,
+                              shared->DebugName()));
     }
   }
 
index 239bea3..e0a437a 100644 (file)
@@ -265,9 +265,8 @@ class Compiler : public AllStatic {
 #endif
 
   static void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
-                                        Handle<String> name,
-                                        int start_position,
-                                        CompilationInfo* info);
+                                        CompilationInfo* info,
+                                        Handle<SharedFunctionInfo> shared);
 };
 
 
index 5df5893..440dedc 100644 (file)
@@ -41,6 +41,9 @@ namespace internal {
 
 void CodeCreateEventRecord::UpdateCodeMap(CodeMap* code_map) {
   code_map->AddCode(start, entry, size);
+  if (sfi_address != NULL) {
+    entry->set_shared_id(code_map->GetSFITag(sfi_address));
+  }
 }
 
 
@@ -54,8 +57,8 @@ void CodeDeleteEventRecord::UpdateCodeMap(CodeMap* code_map) {
 }
 
 
-void CodeAliasEventRecord::UpdateCodeMap(CodeMap* code_map) {
-  code_map->AddAlias(start, entry, code_start);
+void SFIMoveEventRecord::UpdateCodeMap(CodeMap* code_map) {
+  code_map->MoveCode(from, to);
 }
 
 
index fcf539f..ad04a00 100644 (file)
@@ -53,13 +53,7 @@ ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator)
       ticks_buffer_(sizeof(TickSampleEventRecord),
                     kTickSamplesBufferChunkSize,
                     kTickSamplesBufferChunksCount),
-      enqueue_order_(0),
-      known_functions_(new HashMap(AddressesMatch)) {
-}
-
-
-ProfilerEventsProcessor::~ProfilerEventsProcessor() {
-  delete known_functions_;
+      enqueue_order_(0) {
 }
 
 
@@ -75,6 +69,7 @@ void ProfilerEventsProcessor::CallbackCreateEvent(Logger::LogEventsAndTags tag,
   rec->start = start;
   rec->entry = generator_->NewCodeEntry(tag, prefix, name);
   rec->size = 1;
+  rec->sfi_address = NULL;
   events_buffer_.Enqueue(evt_rec);
 }
 
@@ -84,7 +79,8 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
                                               String* resource_name,
                                               int line_number,
                                               Address start,
-                                              unsigned size) {
+                                              unsigned size,
+                                              Address sfi_address) {
   if (FilterOutCodeCreateEvent(tag)) return;
   CodeEventsContainer evt_rec;
   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
@@ -93,6 +89,7 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
   rec->start = start;
   rec->entry = generator_->NewCodeEntry(tag, name, resource_name, line_number);
   rec->size = size;
+  rec->sfi_address = sfi_address;
   events_buffer_.Enqueue(evt_rec);
 }
 
@@ -109,6 +106,7 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
   rec->start = start;
   rec->entry = generator_->NewCodeEntry(tag, name);
   rec->size = size;
+  rec->sfi_address = NULL;
   events_buffer_.Enqueue(evt_rec);
 }
 
@@ -125,6 +123,7 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
   rec->start = start;
   rec->entry = generator_->NewCodeEntry(tag, args_count);
   rec->size = size;
+  rec->sfi_address = NULL;
   events_buffer_.Enqueue(evt_rec);
 }
 
@@ -150,57 +149,14 @@ void ProfilerEventsProcessor::CodeDeleteEvent(Address from) {
 }
 
 
-void ProfilerEventsProcessor::FunctionCreateEvent(Address alias,
-                                                  Address start,
-                                                  int security_token_id) {
+void ProfilerEventsProcessor::SFIMoveEvent(Address from, Address to) {
   CodeEventsContainer evt_rec;
-  CodeAliasEventRecord* rec = &evt_rec.CodeAliasEventRecord_;
-  rec->type = CodeEventRecord::CODE_ALIAS;
+  SFIMoveEventRecord* rec = &evt_rec.SFIMoveEventRecord_;
+  rec->type = CodeEventRecord::SFI_MOVE;
   rec->order = ++enqueue_order_;
-  rec->start = alias;
-  rec->entry = generator_->NewCodeEntry(security_token_id);
-  rec->code_start = start;
+  rec->from = from;
+  rec->to = to;
   events_buffer_.Enqueue(evt_rec);
-
-  known_functions_->Lookup(alias, AddressHash(alias), true);
-}
-
-
-void ProfilerEventsProcessor::FunctionMoveEvent(Address from, Address to) {
-  CodeMoveEvent(from, to);
-
-  if (IsKnownFunction(from)) {
-    known_functions_->Remove(from, AddressHash(from));
-    known_functions_->Lookup(to, AddressHash(to), true);
-  }
-}
-
-
-void ProfilerEventsProcessor::FunctionDeleteEvent(Address from) {
-  CodeDeleteEvent(from);
-
-  known_functions_->Remove(from, AddressHash(from));
-}
-
-
-bool ProfilerEventsProcessor::IsKnownFunction(Address start) {
-  HashMap::Entry* entry =
-      known_functions_->Lookup(start, AddressHash(start), false);
-  return entry != NULL;
-}
-
-
-void ProfilerEventsProcessor::ProcessMovedFunctions() {
-  for (int i = 0; i < moved_functions_.length(); ++i) {
-    JSFunction* function = moved_functions_[i];
-    CpuProfiler::FunctionCreateEvent(function);
-  }
-  moved_functions_.Clear();
-}
-
-
-void ProfilerEventsProcessor::RememberMovedFunction(JSFunction* function) {
-  moved_functions_.Add(function);
 }
 
 
@@ -227,13 +183,12 @@ void ProfilerEventsProcessor::AddCurrentStack() {
   TickSample* sample = &record.sample;
   sample->state = Top::current_vm_state();
   sample->pc = reinterpret_cast<Address>(sample);  // Not NULL.
+  sample->tos = NULL;
   sample->frames_count = 0;
   for (StackTraceFrameIterator it;
        !it.done() && sample->frames_count < TickSample::kMaxFramesCount;
        it.Advance()) {
-    JavaScriptFrame* frame = it.frame();
-    sample->stack[sample->frames_count++] =
-        reinterpret_cast<Address>(frame->function());
+    sample->stack[sample->frames_count++] = it.frame()->pc();
   }
   record.order = enqueue_order_;
   ticks_from_vm_buffer_.Enqueue(record);
@@ -393,20 +348,38 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
       Heap::empty_string(),
       v8::CpuProfileNode::kNoLineNumberInfo,
       code->address(),
-      code->ExecutableSize());
+      code->ExecutableSize(),
+      NULL);
 }
 
 
 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
-                           Code* code, String* name,
-                           String* source, int line) {
+                                  Code* code,
+                                  SharedFunctionInfo* shared,
+                                  String* name) {
   singleton_->processor_->CodeCreateEvent(
       tag,
       name,
+      Heap::empty_string(),
+      v8::CpuProfileNode::kNoLineNumberInfo,
+      code->address(),
+      code->ExecutableSize(),
+      shared->address());
+}
+
+
+void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
+                                  Code* code,
+                                  SharedFunctionInfo* shared,
+                                  String* source, int line) {
+  singleton_->processor_->CodeCreateEvent(
+      tag,
+      shared->DebugName(),
       source,
       line,
       code->address(),
-      code->ExecutableSize());
+      code->ExecutableSize(),
+      shared->address());
 }
 
 
@@ -430,44 +403,8 @@ void CpuProfiler::CodeDeleteEvent(Address from) {
 }
 
 
-void CpuProfiler::FunctionCreateEvent(JSFunction* function) {
-  int security_token_id = TokenEnumerator::kNoSecurityToken;
-  if (function->unchecked_context()->IsContext()) {
-    security_token_id = singleton_->token_enumerator_->GetTokenId(
-        function->context()->global_context()->security_token());
-  }
-  singleton_->processor_->FunctionCreateEvent(
-      function->address(),
-      function->shared()->code()->address(),
-      security_token_id);
-}
-
-
-void CpuProfiler::ProcessMovedFunctions() {
-  singleton_->processor_->ProcessMovedFunctions();
-}
-
-
-void CpuProfiler::FunctionCreateEventFromMove(JSFunction* function) {
-  // This function is called from GC iterators (during Scavenge,
-  // MC, and MS), so marking bits can be set on objects. That's
-  // why unchecked accessors are used here.
-
-  // The same function can be reported several times.
-  if (function->unchecked_code() == Builtins::builtin(Builtins::LazyCompile)
-      || singleton_->processor_->IsKnownFunction(function->address())) return;
-
-  singleton_->processor_->RememberMovedFunction(function);
-}
-
-
-void CpuProfiler::FunctionMoveEvent(Address from, Address to) {
-  singleton_->processor_->FunctionMoveEvent(from, to);
-}
-
-
-void CpuProfiler::FunctionDeleteEvent(Address from) {
-  singleton_->processor_->FunctionDeleteEvent(from);
+void CpuProfiler::SFIMoveEvent(Address from, Address to) {
+  singleton_->processor_->SFIMoveEvent(from, to);
 }
 
 
@@ -539,7 +476,6 @@ void CpuProfiler::StartProcessorIfNotStarted() {
         FLAG_log_code = saved_log_code_flag;
       }
       Logger::LogCompiledFunctions();
-      Logger::LogFunctionObjects();
       Logger::LogAccessorCallbacks();
     }
     // Enable stack sampling.
index 10165f6..1ebbfeb 100644 (file)
@@ -50,7 +50,7 @@ class TokenEnumerator;
   V(CODE_CREATION, CodeCreateEventRecord)       \
   V(CODE_MOVE,     CodeMoveEventRecord)         \
   V(CODE_DELETE,   CodeDeleteEventRecord)       \
-  V(CODE_ALIAS,    CodeAliasEventRecord)
+  V(SFI_MOVE,      SFIMoveEventRecord)
 
 
 class CodeEventRecord {
@@ -73,6 +73,7 @@ class CodeCreateEventRecord : public CodeEventRecord {
   Address start;
   CodeEntry* entry;
   unsigned size;
+  Address sfi_address;
 
   INLINE(void UpdateCodeMap(CodeMap* code_map));
 };
@@ -95,11 +96,10 @@ class CodeDeleteEventRecord : public CodeEventRecord {
 };
 
 
-class CodeAliasEventRecord : public CodeEventRecord {
+class SFIMoveEventRecord : public CodeEventRecord {
  public:
-  Address start;
-  CodeEntry* entry;
-  Address code_start;
+  Address from;
+  Address to;
 
   INLINE(void UpdateCodeMap(CodeMap* code_map));
 };
@@ -134,7 +134,7 @@ class TickSampleEventRecord BASE_EMBEDDED {
 class ProfilerEventsProcessor : public Thread {
  public:
   explicit ProfilerEventsProcessor(ProfileGenerator* generator);
-  virtual ~ProfilerEventsProcessor();
+  virtual ~ProfilerEventsProcessor() {}
 
   // Thread control.
   virtual void Run();
@@ -148,7 +148,8 @@ class ProfilerEventsProcessor : public Thread {
   void CodeCreateEvent(Logger::LogEventsAndTags tag,
                        String* name,
                        String* resource_name, int line_number,
-                       Address start, unsigned size);
+                       Address start, unsigned size,
+                       Address sfi_address);
   void CodeCreateEvent(Logger::LogEventsAndTags tag,
                        const char* name,
                        Address start, unsigned size);
@@ -157,17 +158,12 @@ class ProfilerEventsProcessor : public Thread {
                        Address start, unsigned size);
   void CodeMoveEvent(Address from, Address to);
   void CodeDeleteEvent(Address from);
-  void FunctionCreateEvent(Address alias, Address start, int security_token_id);
-  void FunctionMoveEvent(Address from, Address to);
-  void FunctionDeleteEvent(Address from);
+  void SFIMoveEvent(Address from, Address to);
   void RegExpCodeCreateEvent(Logger::LogEventsAndTags tag,
                              const char* prefix, String* name,
                              Address start, unsigned size);
   // Puts current stack into tick sample events buffer.
   void AddCurrentStack();
-  bool IsKnownFunction(Address start);
-  void ProcessMovedFunctions();
-  void RememberMovedFunction(JSFunction* function);
 
   // Tick sample events are filled directly in the buffer of the circular
   // queue (because the structure is of fixed width, but usually not all
@@ -188,13 +184,6 @@ class ProfilerEventsProcessor : public Thread {
   bool ProcessTicks(unsigned dequeue_order);
 
   INLINE(static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag));
-  INLINE(static bool AddressesMatch(void* key1, void* key2)) {
-    return key1 == key2;
-  }
-  INLINE(static uint32_t AddressHash(Address addr)) {
-    return ComputeIntegerHash(
-        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr)));
-  }
 
   ProfileGenerator* generator_;
   bool running_;
@@ -202,10 +191,6 @@ class ProfilerEventsProcessor : public Thread {
   SamplingCircularQueue ticks_buffer_;
   UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
   unsigned enqueue_order_;
-
-  // Used from the VM thread.
-  HashMap* known_functions_;
-  List<JSFunction*> moved_functions_;
 };
 
 } }  // namespace v8::internal
@@ -251,23 +236,22 @@ class CpuProfiler {
   static void CodeCreateEvent(Logger::LogEventsAndTags tag,
                               Code* code, String* name);
   static void CodeCreateEvent(Logger::LogEventsAndTags tag,
-                              Code* code, String* name,
+                              Code* code,
+                              SharedFunctionInfo *shared,
+                              String* name);
+  static void CodeCreateEvent(Logger::LogEventsAndTags tag,
+                              Code* code,
+                              SharedFunctionInfo *shared,
                               String* source, int line);
   static void CodeCreateEvent(Logger::LogEventsAndTags tag,
                               Code* code, int args_count);
   static void CodeMovingGCEvent() {}
   static void CodeMoveEvent(Address from, Address to);
   static void CodeDeleteEvent(Address from);
-  static void FunctionCreateEvent(JSFunction* function);
-  // Reports function creation in case we had missed it (e.g.
-  // if it was created from compiled code).
-  static void FunctionCreateEventFromMove(JSFunction* function);
-  static void FunctionMoveEvent(Address from, Address to);
-  static void FunctionDeleteEvent(Address from);
   static void GetterCallbackEvent(String* name, Address entry_point);
   static void RegExpCodeCreateEvent(Code* code, String* source);
-  static void ProcessMovedFunctions();
   static void SetterCallbackEvent(String* name, Address entry_point);
+  static void SFIMoveEvent(Address from, Address to);
 
   static INLINE(bool is_profiling()) {
     return NoBarrier_Load(&is_profiling_);
index c5921c7..b48aa50 100644 (file)
@@ -847,9 +847,6 @@ static bool CompileLazyFunction(Handle<JSFunction> function,
     result = CompileLazyHelper(&info, flag);
     ASSERT(!result || function->is_compiled());
   }
-  if (result && function->is_compiled()) {
-    PROFILE(FunctionCreateEvent(*function));
-  }
   return result;
 }
 
@@ -869,9 +866,7 @@ bool CompileLazyInLoop(Handle<JSFunction> function,
 bool CompileOptimized(Handle<JSFunction> function, int osr_ast_id) {
   CompilationInfo info(function);
   info.SetOptimizing(osr_ast_id);
-  bool result = CompileLazyHelper(&info, KEEP_EXCEPTION);
-  if (result) PROFILE(FunctionCreateEvent(*function));
-  return result;
+  return CompileLazyHelper(&info, KEEP_EXCEPTION);
 }
 
 
index b9104a8..1fadec3 100644 (file)
@@ -515,7 +515,6 @@ bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) {
 
 #ifdef ENABLE_LOGGING_AND_PROFILING
   if (FLAG_log_gc) HeapProfiler::WriteSample();
-  if (CpuProfiler::is_profiling()) CpuProfiler::ProcessMovedFunctions();
 #endif
 
   return next_gc_likely_to_collect_more;
@@ -1350,9 +1349,8 @@ class ScavengingVisitor : public StaticVisitorBase {
     HEAP_PROFILE(ObjectMoveEvent(source->address(), target->address()));
 #if defined(ENABLE_LOGGING_AND_PROFILING)
     if (Logger::is_logging() || CpuProfiler::is_profiling()) {
-      if (target->IsJSFunction()) {
-        PROFILE(FunctionMoveEvent(source->address(), target->address()));
-        PROFILE(FunctionCreateEventFromMove(JSFunction::cast(target)));
+      if (target->IsSharedFunctionInfo()) {
+        PROFILE(SFIMoveEvent(source->address(), target->address()));
       }
     }
 #endif
index db99b89..3f2f6d1 100644 (file)
@@ -4099,10 +4099,7 @@ bool HGraphBuilder::TryInline(Call* expr) {
     if (!FullCodeGenerator::MakeCode(&inner_info)) return false;
     shared->EnableDeoptimizationSupport(*inner_info.code());
     Compiler::RecordFunctionCompilation(
-        Logger::FUNCTION_TAG,
-        Handle<String>(shared->DebugName()),
-        shared->start_position(),
-        &inner_info);
+        Logger::FUNCTION_TAG, &inner_info, shared);
   }
 
   // Save the pending call context and type feedback oracle. Set up new ones
index c7b7567..9a498ec 100644 (file)
@@ -300,6 +300,8 @@ void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) {
       Append("\\,");
     } else if (c == '\\') {
       Append("\\\\");
+    } else if (c == '\"') {
+      Append("\"\"");
     } else {
       Append("%lc", c);
     }
index 6eb3c9b..16aeadb 100644 (file)
@@ -147,7 +147,7 @@ bool Profiler::paused_ = false;
 // StackTracer implementation
 //
 void StackTracer::Trace(TickSample* sample) {
-  sample->function = NULL;
+  sample->tos = NULL;
   sample->frames_count = 0;
 
   // Avoid collecting traces while doing GC.
@@ -159,15 +159,9 @@ void StackTracer::Trace(TickSample* sample) {
     return;
   }
 
-  const Address function_address =
-      sample->fp + JavaScriptFrameConstants::kFunctionOffset;
-  if (SafeStackFrameIterator::IsWithinBounds(sample->sp, js_entry_sp,
-                                             function_address)) {
-    Object* object = Memory::Object_at(function_address);
-    if (object->IsHeapObject()) {
-      sample->function = HeapObject::cast(object)->address();
-    }
-  }
+  // Sample potential return address value for frameless invocation of
+  // stubs (we'll figure out later, if this value makes sense).
+  sample->tos = Memory::Address_at(sample->sp);
 
   int i = 0;
   const Address callback = Top::external_callback();
@@ -181,10 +175,7 @@ void StackTracer::Trace(TickSample* sample) {
   SafeStackTraceFrameIterator it(sample->fp, sample->sp,
                                  sample->sp, js_entry_sp);
   while (!it.done() && i < TickSample::kMaxFramesCount) {
-    Object* object = it.frame()->function_slot_object();
-    if (object->IsHeapObject()) {
-      sample->stack[i++] = HeapObject::cast(object)->address();
-    }
+    sample->stack[i++] = it.frame()->pc();
     it.Advance();
   }
   sample->frames_count = i;
@@ -710,17 +701,6 @@ void Logger::SetterCallbackEvent(String* name, Address entry_point) {
 }
 
 
-#ifdef ENABLE_LOGGING_AND_PROFILING
-static const char* ComputeMarker(Code* code) {
-  switch (code->kind()) {
-    case Code::FUNCTION: return code->optimizable() ? "~" : "";
-    case Code::OPTIMIZED_FUNCTION: return "*";
-    default: return "";
-  }
-}
-#endif
-
-
 void Logger::CodeCreateEvent(LogEventsAndTags tag,
                              Code* code,
                              const char* comment) {
@@ -731,7 +711,7 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
              kLogEventsNames[CODE_CREATION_EVENT],
              kLogEventsNames[tag]);
   msg.AppendAddress(code->address());
-  msg.Append(",%d,\"%s", code->ExecutableSize(), ComputeMarker(code));
+  msg.Append(",%d,\"", code->ExecutableSize());
   for (const char* p = comment; *p != '\0'; p++) {
     if (*p == '"') {
       msg.Append('\\');
@@ -746,9 +726,40 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
 }
 
 
-void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, String* name) {
+void Logger::CodeCreateEvent(LogEventsAndTags tag,
+                             Code* code,
+                             String* name) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (name != NULL) {
+    SmartPointer<char> str =
+        name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+    CodeCreateEvent(tag, code, *str);
+  } else {
+    CodeCreateEvent(tag, code, "");
+  }
+#endif
+}
+
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+// ComputeMarker must only be used when SharedFunctionInfo is known.
+static const char* ComputeMarker(Code* code) {
+  switch (code->kind()) {
+    case Code::FUNCTION: return code->optimizable() ? "~" : "";
+    case Code::OPTIMIZED_FUNCTION: return "*";
+    default: return "";
+  }
+}
+#endif
+
+
+void Logger::CodeCreateEvent(LogEventsAndTags tag,
+                             Code* code,
+                             SharedFunctionInfo* shared,
+                             String* name) {
 #ifdef ENABLE_LOGGING_AND_PROFILING
   if (!Log::IsEnabled() || !FLAG_log_code) return;
+  if (code == Builtins::builtin(Builtins::LazyCompile)) return;
   LogMessageBuilder msg;
   SmartPointer<char> str =
       name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
@@ -756,7 +767,9 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, String* name) {
              kLogEventsNames[CODE_CREATION_EVENT],
              kLogEventsNames[tag]);
   msg.AppendAddress(code->address());
-  msg.Append(",%d,\"%s%s\"", code->ExecutableSize(), ComputeMarker(code), *str);
+  msg.Append(",%d,\"%s\",", code->ExecutableSize(), *str);
+  msg.AppendAddress(shared->address());
+  msg.Append(",%s", ComputeMarker(code));
   LowLevelCodeCreateEvent(code, &msg);
   msg.Append('\n');
   msg.WriteToLogFile();
@@ -764,26 +777,31 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, String* name) {
 }
 
 
+// Although, it is possible to extract source and line from
+// the SharedFunctionInfo object, we left it to caller
+// to leave logging functions free from heap allocations.
 void Logger::CodeCreateEvent(LogEventsAndTags tag,
-                             Code* code, String* name,
+                             Code* code,
+                             SharedFunctionInfo* shared,
                              String* source, int line) {
 #ifdef ENABLE_LOGGING_AND_PROFILING
   if (!Log::IsEnabled() || !FLAG_log_code) return;
   LogMessageBuilder msg;
-  SmartPointer<char> str =
-      name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+  SmartPointer<char> name =
+      shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
   SmartPointer<char> sourcestr =
       source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
   msg.Append("%s,%s,",
              kLogEventsNames[CODE_CREATION_EVENT],
              kLogEventsNames[tag]);
   msg.AppendAddress(code->address());
-  msg.Append(",%d,\"%s%s %s:%d\"",
+  msg.Append(",%d,\"%s %s:%d\",",
              code->ExecutableSize(),
-             ComputeMarker(code),
-             *str,
+             *name,
              *sourcestr,
              line);
+  msg.AppendAddress(shared->address());
+  msg.Append(",%s", ComputeMarker(code));
   LowLevelCodeCreateEvent(code, &msg);
   msg.Append('\n');
   msg.WriteToLogFile();
@@ -863,42 +881,9 @@ void Logger::SnapshotPositionEvent(Address addr, int pos) {
 }
 
 
-void Logger::FunctionCreateEvent(JSFunction* function) {
-#ifdef ENABLE_LOGGING_AND_PROFILING
-  // This function can be called from GC iterators (during Scavenge,
-  // MC, and MS), so marking bits can be set on objects. That's
-  // why unchecked accessors are used here.
-  if (!Log::IsEnabled() || !FLAG_log_code) return;
-  LogMessageBuilder msg;
-  msg.Append("%s,", kLogEventsNames[FUNCTION_CREATION_EVENT]);
-  msg.AppendAddress(function->address());
-  msg.Append(',');
-  msg.AppendAddress(function->unchecked_code()->address());
-  msg.Append('\n');
-  msg.WriteToLogFile();
-#endif
-}
-
-
-void Logger::FunctionCreateEventFromMove(JSFunction* function) {
-#ifdef ENABLE_LOGGING_AND_PROFILING
-  if (function->unchecked_code() != Builtins::builtin(Builtins::LazyCompile)) {
-    FunctionCreateEvent(function);
-  }
-#endif
-}
-
-
-void Logger::FunctionMoveEvent(Address from, Address to) {
+void Logger::SFIMoveEvent(Address from, Address to) {
 #ifdef ENABLE_LOGGING_AND_PROFILING
-  MoveEventInternal(FUNCTION_MOVE_EVENT, from, to);
-#endif
-}
-
-
-void Logger::FunctionDeleteEvent(Address from) {
-#ifdef ENABLE_LOGGING_AND_PROFILING
-  DeleteEventInternal(FUNCTION_DELETE_EVENT, from);
+  MoveEventInternal(SFI_MOVE_EVENT, from, to);
 #endif
 }
 
@@ -1118,7 +1103,7 @@ void Logger::TickEvent(TickSample* sample, bool overflow) {
   msg.Append(',');
   msg.AppendAddress(sample->sp);
   msg.Append(',');
-  msg.AppendAddress(sample->function);
+  msg.AppendAddress(sample->tos);
   msg.Append(",%d", static_cast<int>(sample->state));
   if (overflow) {
     msg.Append(",overflow");
@@ -1187,7 +1172,6 @@ void Logger::ResumeProfiler(int flags, int tag) {
         LOG(UncheckedStringEvent("profiler", "resume"));
         FLAG_log_code = true;
         LogCompiledFunctions();
-        LogFunctionObjects();
         LogAccessorCallbacks();
         if (!FLAG_sliding_state_window && !ticker_->IsActive()) {
           ticker_->Start();
@@ -1388,10 +1372,9 @@ void Logger::LogCompiledFunctions() {
   // During iteration, there can be heap allocation due to
   // GetScriptLineNumber call.
   for (int i = 0; i < compiled_funcs_count; ++i) {
+    if (*code_objects[i] == Builtins::builtin(Builtins::LazyCompile)) continue;
     Handle<SharedFunctionInfo> shared = sfis[i];
-    Handle<String> name(String::cast(shared->name()));
-    Handle<String> func_name(name->length() > 0 ?
-                             *name : shared->inferred_name());
+    Handle<String> func_name(shared->DebugName());
     if (shared->script()->IsScript()) {
       Handle<Script> script(Script::cast(shared->script()));
       if (script->name()->IsString()) {
@@ -1400,18 +1383,18 @@ void Logger::LogCompiledFunctions() {
         if (line_num > 0) {
           PROFILE(CodeCreateEvent(
               Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
-              *code_objects[i], *func_name,
+              *code_objects[i], *shared,
               *script_name, line_num + 1));
         } else {
           // Can't distinguish eval and script here, so always use Script.
           PROFILE(CodeCreateEvent(
               Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
-              *code_objects[i], *script_name));
+              *code_objects[i], *shared, *script_name));
         }
       } else {
         PROFILE(CodeCreateEvent(
             Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
-            *code_objects[i], *func_name));
+            *code_objects[i], *shared, *func_name));
       }
     } else if (shared->IsApiFunction()) {
       // API function.
@@ -1425,24 +1408,12 @@ void Logger::LogCompiledFunctions() {
       }
     } else {
       PROFILE(CodeCreateEvent(
-          Logger::LAZY_COMPILE_TAG, *code_objects[i], *func_name));
+          Logger::LAZY_COMPILE_TAG, *code_objects[i], *shared, *func_name));
     }
   }
 }
 
 
-void Logger::LogFunctionObjects() {
-  AssertNoAllocation no_alloc;
-  HeapIterator iterator;
-  for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
-    if (!obj->IsJSFunction()) continue;
-    JSFunction* jsf = JSFunction::cast(obj);
-    if (!jsf->is_compiled()) continue;
-    PROFILE(FunctionCreateEvent(jsf));
-  }
-}
-
-
 void Logger::LogAccessorCallbacks() {
   AssertNoAllocation no_alloc;
   HeapIterator iterator;
index 771709c..a808cd1 100644 (file)
--- a/src/log.h
+++ b/src/log.h
@@ -91,9 +91,7 @@ class LogMessageBuilder;
   V(CODE_MOVE_EVENT,                "code-move")                \
   V(CODE_DELETE_EVENT,              "code-delete")              \
   V(CODE_MOVING_GC,                 "code-moving-gc")           \
-  V(FUNCTION_CREATION_EVENT,        "function-creation")        \
-  V(FUNCTION_MOVE_EVENT,            "function-move")            \
-  V(FUNCTION_DELETE_EVENT,          "function-delete")          \
+  V(SFI_MOVE_EVENT,                 "sfi-move")                 \
   V(SNAPSHOT_POSITION_EVENT,        "snapshot-pos")             \
   V(TICK_EVENT,                     "tick")                     \
   V(REPEAT_META_EVENT,              "repeat")                   \
@@ -205,8 +203,15 @@ class Logger {
   // Emits a code create event.
   static void CodeCreateEvent(LogEventsAndTags tag,
                               Code* code, const char* source);
-  static void CodeCreateEvent(LogEventsAndTags tag, Code* code, String* name);
-  static void CodeCreateEvent(LogEventsAndTags tag, Code* code, String* name,
+  static void CodeCreateEvent(LogEventsAndTags tag,
+                              Code* code, String* name);
+  static void CodeCreateEvent(LogEventsAndTags tag,
+                              Code* code,
+                              SharedFunctionInfo* shared,
+                              String* name);
+  static void CodeCreateEvent(LogEventsAndTags tag,
+                              Code* code,
+                              SharedFunctionInfo* shared,
                               String* source, int line);
   static void CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count);
   static void CodeMovingGCEvent();
@@ -216,13 +221,8 @@ class Logger {
   static void CodeMoveEvent(Address from, Address to);
   // Emits a code delete event.
   static void CodeDeleteEvent(Address from);
-  // Emits a function object create event.
-  static void FunctionCreateEvent(JSFunction* function);
-  static void FunctionCreateEventFromMove(JSFunction* function);
-  // Emits a function move event.
-  static void FunctionMoveEvent(Address from, Address to);
-  // Emits a function delete event.
-  static void FunctionDeleteEvent(Address from);
+
+  static void SFIMoveEvent(Address from, Address to);
 
   static void SnapshotPositionEvent(Address addr, int pos);
 
@@ -273,8 +273,6 @@ class Logger {
 
   // Logs all compiled functions found in the heap.
   static void LogCompiledFunctions();
-  // Logs all compiled JSFunction objects found in the heap.
-  static void LogFunctionObjects();
   // Logs all accessor callbacks found in the heap.
   static void LogAccessorCallbacks();
   // Used for logging stubs found in the snapshot.
index 5c649d1..a3b769a 100644 (file)
@@ -2819,9 +2819,8 @@ int MarkCompactCollector::RelocateOldNonCodeObject(HeapObject* obj,
   ASSERT(!HeapObject::FromAddress(new_addr)->IsCode());
 
   HeapObject* copied_to = HeapObject::FromAddress(new_addr);
-  if (copied_to->IsJSFunction()) {
-    PROFILE(FunctionMoveEvent(old_addr, new_addr));
-    PROFILE(FunctionCreateEventFromMove(JSFunction::cast(copied_to)));
+  if (copied_to->IsSharedFunctionInfo()) {
+    PROFILE(SFIMoveEvent(old_addr, new_addr));
   }
   HEAP_PROFILE(ObjectMoveEvent(old_addr, new_addr));
 
@@ -2912,9 +2911,8 @@ int MarkCompactCollector::RelocateNewObject(HeapObject* obj) {
 #endif
 
   HeapObject* copied_to = HeapObject::FromAddress(new_addr);
-  if (copied_to->IsJSFunction()) {
-    PROFILE(FunctionMoveEvent(old_addr, new_addr));
-    PROFILE(FunctionCreateEventFromMove(JSFunction::cast(copied_to)));
+  if (copied_to->IsSharedFunctionInfo()) {
+    PROFILE(SFIMoveEvent(old_addr, new_addr));
   }
   HEAP_PROFILE(ObjectMoveEvent(old_addr, new_addr));
 
@@ -2931,8 +2929,6 @@ void MarkCompactCollector::ReportDeleteIfNeeded(HeapObject* obj) {
 #ifdef ENABLE_LOGGING_AND_PROFILING
   if (obj->IsCode()) {
     PROFILE(CodeDeleteEvent(obj->address()));
-  } else if (obj->IsJSFunction()) {
-    PROFILE(FunctionDeleteEvent(obj->address()));
   }
 #endif
 }
index 0d7d2e9..88825e6 100644 (file)
@@ -567,13 +567,13 @@ class TickSample {
         pc(NULL),
         sp(NULL),
         fp(NULL),
-        function(NULL),
+        tos(NULL),
         frames_count(0) {}
   StateTag state;  // The state of the VM.
-  Address pc;  // Instruction pointer.
-  Address sp;  // Stack pointer.
-  Address fp;  // Frame pointer.
-  Address function;  // The last called JS function.
+  Address pc;   // Instruction pointer.
+  Address sp;   // Stack pointer.
+  Address fp;   // Frame pointer.
+  Address tos;  // Top stack value (*sp).
   static const int kMaxFramesCount = 64;
   Address stack[kMaxFramesCount];  // Call stack.
   int frames_count;  // Number of captured frames.
index 3df6af0..4bcfa9b 100644 (file)
@@ -45,16 +45,6 @@ const char* StringsStorage::GetFunctionName(const char* name) {
 }
 
 
-CodeEntry::CodeEntry(int security_token_id)
-    : tag_(Logger::FUNCTION_TAG),
-      name_prefix_(kEmptyNamePrefix),
-      name_(""),
-      resource_name_(""),
-      line_number_(0),
-      security_token_id_(security_token_id) {
-}
-
-
 CodeEntry::CodeEntry(Logger::LogEventsAndTags tag,
                      const char* name_prefix,
                      const char* name,
@@ -66,6 +56,7 @@ CodeEntry::CodeEntry(Logger::LogEventsAndTags tag,
       name_(name),
       resource_name_(resource_name),
       line_number_(line_number),
+      shared_id_(0),
       security_token_id_(security_token_id) {
 }
 
index 06ee333..261b3d6 100644 (file)
@@ -156,13 +156,18 @@ void CodeEntry::CopyData(const CodeEntry& source) {
 
 uint32_t CodeEntry::GetCallUid() const {
   uint32_t hash = ComputeIntegerHash(tag_);
-  hash ^= ComputeIntegerHash(
-      static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_prefix_)));
-  hash ^= ComputeIntegerHash(
-      static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_)));
-  hash ^= ComputeIntegerHash(
-      static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_)));
-  hash ^= ComputeIntegerHash(line_number_);
+  if (shared_id_ != 0) {
+    hash ^= ComputeIntegerHash(
+        static_cast<uint32_t>(shared_id_));
+  } else {
+    hash ^= ComputeIntegerHash(
+        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_prefix_)));
+    hash ^= ComputeIntegerHash(
+        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_)));
+    hash ^= ComputeIntegerHash(
+        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_)));
+    hash ^= ComputeIntegerHash(line_number_);
+  }
   return hash;
 }
 
@@ -170,10 +175,12 @@ uint32_t CodeEntry::GetCallUid() const {
 bool CodeEntry::IsSameAs(CodeEntry* entry) const {
   return this == entry
       || (tag_ == entry->tag_
-          && name_prefix_ == entry->name_prefix_
-          && name_ == entry->name_
-          && resource_name_ == entry->resource_name_
-          && line_number_ == entry->line_number_);
+          && shared_id_ == entry->shared_id_
+          && (shared_id_ != 0
+              || (name_prefix_ == entry->name_prefix_
+                  && name_ == entry->name_
+                  && resource_name_ == entry->resource_name_
+                  && line_number_ == entry->line_number_)));
 }
 
 
@@ -458,23 +465,12 @@ void CpuProfile::Print() {
 }
 
 
+CodeEntry* const CodeMap::kSfiCodeEntry = NULL;
 const CodeMap::CodeTreeConfig::Key CodeMap::CodeTreeConfig::kNoKey = NULL;
 const CodeMap::CodeTreeConfig::Value CodeMap::CodeTreeConfig::kNoValue =
     CodeMap::CodeEntryInfo(NULL, 0);
 
 
-void CodeMap::AddAlias(Address start, CodeEntry* entry, Address code_start) {
-  CodeTree::Locator locator;
-  if (tree_.Find(code_start, &locator)) {
-    const CodeEntryInfo& code_info = locator.value();
-    if (tree_.Insert(start, &locator)) {
-      entry->CopyData(*code_info.entry);
-      locator.set_value(CodeEntryInfo(entry, code_info.size));
-    }
-  }
-}
-
-
 CodeEntry* CodeMap::FindEntry(Address addr) {
   CodeTree::Locator locator;
   if (tree_.FindGreatestLessThan(addr, &locator)) {
@@ -487,6 +483,22 @@ CodeEntry* CodeMap::FindEntry(Address addr) {
 }
 
 
+int CodeMap::GetSFITag(Address addr) {
+  CodeTree::Locator locator;
+  // For SFI entries, 'size' field is used to store their IDs.
+  if (tree_.Find(addr, &locator)) {
+    const CodeEntryInfo& entry = locator.value();
+    ASSERT(entry.entry == kSfiCodeEntry);
+    return entry.size;
+  } else {
+    tree_.Insert(addr, &locator);
+    int tag = next_sfi_tag_++;
+    locator.set_value(CodeEntryInfo(kSfiCodeEntry, tag));
+    return tag;
+  }
+}
+
+
 void CodeMap::CodeTreePrinter::Call(
     const Address& key, const CodeMap::CodeEntryInfo& value) {
   OS::Print("%p %5d %s\n", key, value.size, value.entry->name());
@@ -715,13 +727,6 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
 }
 
 
-CodeEntry* CpuProfilesCollection::NewCodeEntry(int security_token_id) {
-  CodeEntry* entry = new CodeEntry(security_token_id);
-  code_entries_.Add(entry);
-  return entry;
-}
-
-
 void CpuProfilesCollection::AddPathToCurrentProfiles(
     const Vector<CodeEntry*>& path) {
   // As starting / stopping profiles is rare relatively to this
@@ -784,19 +789,10 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
   if (sample.pc != NULL) {
     *entry++ = code_map_.FindEntry(sample.pc);
 
-    if (sample.function != NULL) {
-      *entry = code_map_.FindEntry(sample.function);
+    if (sample.tos != NULL) {
+      *entry = code_map_.FindEntry(sample.tos);
       if (*entry != NULL && !(*entry)->is_js_function()) {
         *entry = NULL;
-      } else {
-        CodeEntry* pc_entry = *entries.start();
-        if (pc_entry == NULL) {
-          *entry = NULL;
-        } else if (pc_entry->is_js_function()) {
-          // Use function entry in favor of pc entry, as function
-          // entry has security token.
-          *entries.start() = NULL;
-        }
       }
       entry++;
     }
index cacd27e..748714d 100644 (file)
@@ -88,7 +88,6 @@ class StringsStorage {
 
 class CodeEntry {
  public:
-  explicit INLINE(CodeEntry(int security_token_id));
   // CodeEntry doesn't own name strings, just references them.
   INLINE(CodeEntry(Logger::LogEventsAndTags tag,
                    const char* name_prefix,
@@ -103,6 +102,8 @@ class CodeEntry {
   INLINE(const char* name() const) { return name_; }
   INLINE(const char* resource_name() const) { return resource_name_; }
   INLINE(int line_number() const) { return line_number_; }
+  INLINE(int shared_id() const) { return shared_id_; }
+  INLINE(void set_shared_id(int shared_id)) { shared_id_ = shared_id; }
   INLINE(int security_token_id() const) { return security_token_id_; }
 
   INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag));
@@ -119,6 +120,7 @@ class CodeEntry {
   const char* name_;
   const char* resource_name_;
   int line_number_;
+  int shared_id_;
   int security_token_id_;
 
   DISALLOW_COPY_AND_ASSIGN(CodeEntry);
@@ -234,12 +236,12 @@ class CpuProfile {
 
 class CodeMap {
  public:
-  CodeMap() { }
+  CodeMap() : next_sfi_tag_(1) { }
   INLINE(void AddCode(Address addr, CodeEntry* entry, unsigned size));
   INLINE(void MoveCode(Address from, Address to));
   INLINE(void DeleteCode(Address addr));
-  void AddAlias(Address start, CodeEntry* entry, Address code_start);
   CodeEntry* FindEntry(Address addr);
+  int GetSFITag(Address addr);
 
   void Print();
 
@@ -267,7 +269,11 @@ class CodeMap {
     void Call(const Address& key, const CodeEntryInfo& value);
   };
 
+  // Fake CodeEntry pointer to distinguish SFI entries.
+  static CodeEntry* const kSfiCodeEntry;
+
   CodeTree tree_;
+  int next_sfi_tag_;
 
   DISALLOW_COPY_AND_ASSIGN(CodeMap);
 };
index 239d8ae..7f06bc3 100644 (file)
@@ -50,7 +50,7 @@ static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
                                    i::Address frame3 = NULL) {
   i::TickSample* sample = proc->TickSampleEvent();
   sample->pc = frame1;
-  sample->function = frame1;
+  sample->tos = frame1;
   sample->frames_count = 0;
   if (frame2 != NULL) {
     sample->stack[0] = frame2;
@@ -103,7 +103,8 @@ TEST(CodeEvents) {
                             i::Heap::empty_string(),
                             0,
                             ToAddress(0x1000),
-                            0x100);
+                            0x100,
+                            ToAddress(0x10000));
   processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
                             "bbb",
                             ToAddress(0x1200),
@@ -116,8 +117,6 @@ TEST(CodeEvents) {
   processor.CodeMoveEvent(ToAddress(0x1400), ToAddress(0x1500));
   processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600), 0x10);
   processor.CodeDeleteEvent(ToAddress(0x1600));
-  processor.FunctionCreateEvent(ToAddress(0x1700), ToAddress(0x1000),
-                                TokenEnumerator::kNoSecurityToken);
   // Enqueue a tick event to enable code events processing.
   EnqueueTickSampleEvent(&processor, ToAddress(0x1000));
 
@@ -139,9 +138,6 @@ TEST(CodeEvents) {
   CHECK_NE(NULL, entry4);
   CHECK_EQ("ddd", entry4->name());
   CHECK_EQ(NULL, generator.code_map()->FindEntry(ToAddress(0x1600)));
-  CodeEntry* entry5 = generator.code_map()->FindEntry(ToAddress(0x1700));
-  CHECK_NE(NULL, entry5);
-  CHECK_EQ(aaa_str, entry5->name());
 }
 
 
index c85f6c0..bf72184 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "v8.h"
 
+#include "api.h"
 #include "codegen.h"
 #include "log.h"
 #include "top.h"
@@ -200,16 +201,16 @@ static void InitializeVM() {
 }
 
 
-static void CheckJSFunctionAtAddress(const char* func_name, Address addr) {
-  CHECK(i::Heap::Contains(addr));
-  i::Object* obj = i::HeapObject::FromAddress(addr);
-  CHECK(obj->IsJSFunction());
-  CHECK(JSFunction::cast(obj)->shared()->name()->IsString());
-  i::SmartPointer<char> found_name =
-      i::String::cast(
-          JSFunction::cast(
-              obj)->shared()->name())->ToCString();
-  CHECK_EQ(func_name, *found_name);
+static bool IsAddressWithinFuncCode(JSFunction* function, Address addr) {
+  i::Code* code = function->code();
+  return code->contains(addr);
+}
+
+static bool IsAddressWithinFuncCode(const char* func_name, Address addr) {
+  v8::Local<v8::Value> func = env->Global()->Get(v8_str(func_name));
+  CHECK(func->IsFunction());
+  JSFunction* js_func = JSFunction::cast(*v8::Utils::OpenHandle(*func));
+  return IsAddressWithinFuncCode(js_func, addr);
 }
 
 
@@ -309,8 +310,8 @@ TEST(CFromJSStackTrace) {
 
   // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace"
   CHECK_GT(sample.frames_count, base + 1);
-  CheckJSFunctionAtAddress("JSFuncDoTrace", sample.stack[base + 0]);
-  CheckJSFunctionAtAddress("JSTrace", sample.stack[base + 1]);
+  CHECK(IsAddressWithinFuncCode("JSFuncDoTrace", sample.stack[base + 0]));
+  CHECK(IsAddressWithinFuncCode("JSTrace", sample.stack[base + 1]));
 }
 
 
@@ -351,9 +352,6 @@ TEST(PureJSStackTrace) {
   //           DoTraceHideCEntryFPAddress(EBP) [native]
   //             StackTracer::Trace
   //
-  // The last JS function called. It is only visible through
-  // sample.function, as its return address is above captured EBP value.
-  CheckJSFunctionAtAddress("JSFuncDoTrace", sample.function);
 
   // The VM state tracking keeps track of external callbacks and puts
   // them at the top of the sample stack.
@@ -363,8 +361,8 @@ TEST(PureJSStackTrace) {
 
   // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace"
   CHECK_GT(sample.frames_count, base + 1);
-  CheckJSFunctionAtAddress("JSTrace", sample.stack[base + 0]);
-  CheckJSFunctionAtAddress("OuterJSTrace", sample.stack[base + 1]);
+  CHECK(IsAddressWithinFuncCode("JSTrace", sample.stack[base + 0]));
+  CHECK(IsAddressWithinFuncCode("OuterJSTrace", sample.stack[base + 1]));
 }
 
 
index 032a183..30b8a48 100644 (file)
@@ -1053,10 +1053,10 @@ static bool AreFuncNamesEqual(CodeEntityInfo ref_s, CodeEntityInfo new_s) {
   // Skip size.
   ref_s = strchr(ref_s, ',') + 1;
   new_s = strchr(new_s, ',') + 1;
-  int ref_len = StrChrLen(ref_s, '\n');
-  int new_len = StrChrLen(new_s, '\n');
-  // If reference is anonymous (""), it's OK to have anything in new.
-  if (ref_len == 2) return true;
+  CHECK_EQ('"', ref_s[0]);
+  CHECK_EQ('"', new_s[0]);
+  int ref_len = StrChrLen(ref_s + 1, '\"');
+  int new_len = StrChrLen(new_s + 1, '\"');
   // A special case for ErrorPrototype. Haven't yet figured out why they
   // are different.
   const char* error_prototype = "\"ErrorPrototype";
@@ -1074,21 +1074,6 @@ static bool AreFuncNamesEqual(CodeEntityInfo ref_s, CodeEntityInfo new_s) {
       return true;
     }
   }
-  // Code objects can change their optimizability: code object may start
-  // as optimizable, but later be discovered to be actually not optimizable.
-  // Alas, we don't record this info as of now, so we allow cases when
-  // ref is thought to be optimizable while traverse finds it to be
-  // not optimizable.
-  if (ref_s[1] == '~') {  // Code object used to be optimizable
-    if (new_s[1] == ' ') {  // ...but later was set unoptimizable.
-      CHECK_EQ('"', ref_s[0]);
-      CHECK_EQ('"', new_s[0]);
-      ref_s += 2;  // Cut the leading quote and the marker
-      ref_len -= 2;
-      new_s += 1;  // Cut the leading quote only.
-      new_len -= 1;
-    }
-  }
   return ref_len == new_len && strncmp(ref_s, new_s, ref_len) == 0;
 }
 
index f849d40..c60d072 100644 (file)
@@ -600,13 +600,13 @@ TEST(RecordTickSample) {
   //      -> ccc -> aaa  - sample3
   TickSample sample1;
   sample1.pc = ToAddress(0x1600);
-  sample1.function = ToAddress(0x1500);
+  sample1.tos = ToAddress(0x1500);
   sample1.stack[0] = ToAddress(0x1510);
   sample1.frames_count = 1;
   generator.RecordTickSample(sample1);
   TickSample sample2;
   sample2.pc = ToAddress(0x1925);
-  sample2.function = ToAddress(0x1900);
+  sample2.tos = ToAddress(0x1900);
   sample2.stack[0] = ToAddress(0x1780);
   sample2.stack[1] = ToAddress(0x10000);  // non-existent.
   sample2.stack[2] = ToAddress(0x1620);
@@ -614,7 +614,7 @@ TEST(RecordTickSample) {
   generator.RecordTickSample(sample2);
   TickSample sample3;
   sample3.pc = ToAddress(0x1510);
-  sample3.function = ToAddress(0x1500);
+  sample3.tos = ToAddress(0x1500);
   sample3.stack[0] = ToAddress(0x1910);
   sample3.stack[1] = ToAddress(0x1610);
   sample3.frames_count = 2;
index 29a12f6..755fbb2 100644 (file)
@@ -3,11 +3,9 @@ shared-library,"/lib32/libm-2.7.so",0xf7db6000,0xf7dd9000
 shared-library,"ffffe000-fffff000",0xffffe000,0xfffff000
 profiler,"begin",1
 code-creation,Stub,0x424260,348,"CompareStub_GE"
-code-creation,LazyCompile,0x2a8100,18535,"DrawQube 3d-cube.js:188"
-function-creation,0x2d11b8,0x2a8100
-code-creation,LazyCompile,0x480100,3908,"DrawLine 3d-cube.js:17"
-function-creation,0x2d0f7c,0x480100
-tick,0x424284,0xbfffeea0,0x2d0f7c,0,0x2aaaa5
-tick,0x42429f,0xbfffed88,0x2d0f7c,0,0x2aacb4
+code-creation,LazyCompile,0x2a8100,18535,"DrawQube 3d-cube.js:188",0xf43abcac,
+code-creation,LazyCompile,0x480100,3908,"DrawLine 3d-cube.js:17",0xf43abc50,
+tick,0x424284,0xbfffeea0,0x480600,0,0x2aaaa5
+tick,0x42429f,0xbfffed88,0x480600,0,0x2aacb4
 tick,0x48063d,0xbfffec7c,0x2d0f7c,0,0x2aaec6
 profiler,"end"
index 398c530..7f12c13 100755 (executable)
@@ -311,7 +311,7 @@ class CodeLogReader(object):
     r"code-info,([^,]+),(\d+)")
 
   _CODE_CREATE_RE = re.compile(
-    r"code-creation,([^,]+),(0x[a-f0-9]+),(\d+),\"(.*)\"(?:,(\d+))?")
+    r"code-creation,([^,]+),(0x[a-f0-9]+),(\d+),\"(.*)\"(?:,(0x[a-f0-9]+),([~*])?)?(?:,(\d+))?")
 
   _CODE_MOVE_RE = re.compile(
     r"code-move,(0x[a-f0-9]+),(0x[a-f0-9]+)")
@@ -358,12 +358,18 @@ class CodeLogReader(object):
           name = self.address_to_snapshot_name[start_address]
           origin = JS_SNAPSHOT_ORIGIN
         else:
-          name = "%s:%s" % (match.group(1), match.group(4))
+          tag = match.group(1)
+          optimization_status = match.group(6)
+          func_name = match.group(4)
+          if optimization_status:
+            name = "%s:%s%s" % (tag, optimization_status, func_name)
+          else:
+            name = "%s:%s" % (tag, func_name)
           origin = JS_ORIGIN
         if self.is_snapshot:
           origin_offset = 0
         else:
-          origin_offset = int(match.group(5))
+          origin_offset = int(match.group(7))
         code = Code(name, start_address, end_address, origin, origin_offset)
         conficting_code = self.code_map.Find(start_address)
         if conficting_code:
index 03bee83..c9c9437 100644 (file)
@@ -38,11 +38,6 @@ function Profile() {
   this.bottomUpTree_ = new CallTree();
 };
 
-/**
- * Version of profiler log.
- */
-Profile.VERSION = 2;
-
 
 /**
  * Returns whether a function with the specified name must be skipped.
@@ -69,6 +64,18 @@ Profile.Operation = {
 
 
 /**
+ * Enum for code state regarding its dynamic optimization.
+ *
+ * @enum {number}
+ */
+Profile.CodeState = {
+  COMPILED: 0,
+  OPTIMIZABLE: 1,
+  OPTIMIZED: 2
+};
+
+
+/**
  * Called whenever the specified operation has failed finding a function
  * containing the specified address. Should be overriden by subclasses.
  * See the Profile.Operation enum for the list of
@@ -134,17 +141,30 @@ Profile.prototype.addCode = function(
 
 
 /**
- * Creates an alias entry for a code entry.
+ * Registers dynamic (JIT-compiled) code entry.
  *
- * @param {number} aliasAddr Alias address.
- * @param {number} addr Code entry address.
- */
-Profile.prototype.addCodeAlias = function(
-    aliasAddr, addr) {
-  var entry = this.codeMap_.findDynamicEntryByStartAddress(addr);
-  if (entry) {
-    this.codeMap_.addCode(aliasAddr, entry);
+ * @param {string} type Code entry type.
+ * @param {string} name Code entry name.
+ * @param {number} start Starting address.
+ * @param {number} size Code entry size.
+ * @param {number} funcAddr Shared function object address.
+ * @param {Profile.CodeState} state Optimization state.
+ */
+Profile.prototype.addFuncCode = function(
+    type, name, start, size, funcAddr, state) {
+  // As code and functions are in the same address space,
+  // it is safe to put them in a single code map.
+  var func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr);
+  if (!func) {
+    func = new Profile.FunctionEntry(name);
+    this.codeMap_.addCode(funcAddr, func);
+  } else if (func.name !== name) {
+    // Function object has been overwritten with a new one.
+    func.name = name;
   }
+  var entry = new Profile.DynamicFuncCodeEntry(size, type, func, state);
+  this.codeMap_.addCode(start, entry);
+  return entry;
 };
 
 
@@ -183,7 +203,7 @@ Profile.prototype.deleteCode = function(start) {
  * @param {number} from Current code entry address.
  * @param {number} to New code entry address.
  */
-Profile.prototype.safeMoveDynamicCode = function(from, to) {
+Profile.prototype.moveFunc = function(from, to) {
   if (this.codeMap_.findDynamicEntryByStartAddress(from)) {
     this.codeMap_.moveCode(from, to);
   }
@@ -191,18 +211,6 @@ Profile.prototype.safeMoveDynamicCode = function(from, to) {
 
 
 /**
- * Reports about deletion of a dynamic code entry.
- *
- * @param {number} start Starting address.
- */
-Profile.prototype.safeDeleteDynamicCode = function(start) {
-  if (this.codeMap_.findDynamicEntryByStartAddress(start)) {
-    this.codeMap_.deleteCode(start);
-  }
-};
-
-
-/**
  * Retrieves a code entry by an address.
  *
  * @param {number} addr Entry address.
@@ -383,14 +391,7 @@ Profile.DynamicCodeEntry = function(size, type, name) {
  * Returns node name.
  */
 Profile.DynamicCodeEntry.prototype.getName = function() {
-  var name = this.name;
-  if (name.length == 0) {
-    name = '<anonymous>';
-  } else if (name.charAt(0) == ' ') {
-    // An anonymous function with location: " aaa.js:10".
-    name = '<anonymous>' + name;
-  }
-  return this.type + ': ' + name;
+  return this.type + ': ' + this.name;
 };
 
 
@@ -403,9 +404,73 @@ Profile.DynamicCodeEntry.prototype.getRawName = function() {
 
 
 Profile.DynamicCodeEntry.prototype.isJSFunction = function() {
-  return this.type == "Function" ||
-    this.type == "LazyCompile" ||
-    this.type == "Script";
+  return false;
+};
+
+
+/**
+ * Creates a dynamic code entry.
+ *
+ * @param {number} size Code size.
+ * @param {string} type Code type.
+ * @param {Profile.FunctionEntry} func Shared function entry.
+ * @param {Profile.CodeState} state Code optimization state.
+ * @constructor
+ */
+Profile.DynamicFuncCodeEntry = function(size, type, func, state) {
+  CodeMap.CodeEntry.call(this, size);
+  this.type = type;
+  this.func = func;
+  this.state = state;
+};
+
+Profile.DynamicFuncCodeEntry.STATE_PREFIX = ["", "~", "*"];
+
+/**
+ * Returns node name.
+ */
+Profile.DynamicFuncCodeEntry.prototype.getName = function() {
+  var name = this.func.getName();
+  return this.type + ': ' + Profile.DynamicFuncCodeEntry.STATE_PREFIX[this.state] + name;
+};
+
+
+/**
+ * Returns raw node name (without type decoration).
+ */
+Profile.DynamicFuncCodeEntry.prototype.getRawName = function() {
+  return this.func.getName();
+};
+
+
+Profile.DynamicFuncCodeEntry.prototype.isJSFunction = function() {
+  return true;
+};
+
+
+/**
+ * Creates a shared function object entry.
+ *
+ * @param {string} name Function name.
+ * @constructor
+ */
+Profile.FunctionEntry = function(name) {
+  CodeMap.CodeEntry.call(this, 0, name);
+};
+
+
+/**
+ * Returns node name.
+ */
+Profile.FunctionEntry.prototype.getName = function() {
+  var name = this.name;
+  if (name.length == 0) {
+    name = '<anonymous>';
+  } else if (name.charAt(0) == ' ') {
+    // An anonymous function with location: " aaa.js:10".
+    name = '<anonymous>' + name;
+  }
+  return name;
 };
 
 
index db2f3c9..f105a21 100644 (file)
@@ -57,10 +57,23 @@ function readFile(fileName) {
 }
 
 
+/**
+ * Parser for dynamic code optimization state.
+ */
+function parseState(s) {
+  switch (s) {
+  case "": return Profile.CodeState.COMPILED;
+  case "~": return Profile.CodeState.OPTIMIZABLE;
+  case "*": return Profile.CodeState.OPTIMIZED;
+  }
+  throw new Error("unknown code state: " + s);
+}
+
+
 function SnapshotLogProcessor() {
   LogReader.call(this, {
       'code-creation': {
-          parsers: [null, parseInt, parseInt, null],
+          parsers: [null, parseInt, parseInt, null, 'var-args'],
           processor: this.processCodeCreation },
       'code-move': { parsers: [parseInt, parseInt],
           processor: this.processCodeMove },
@@ -69,6 +82,7 @@ function SnapshotLogProcessor() {
       'function-creation': null,
       'function-move': null,
       'function-delete': null,
+      'sfi-move': null,
       'snapshot-pos': { parsers: [parseInt, parseInt],
           processor: this.processSnapshotPosition }});
 
@@ -93,8 +107,14 @@ inherits(SnapshotLogProcessor, LogReader);
 
 
 SnapshotLogProcessor.prototype.processCodeCreation = function(
-    type, start, size, name) {
-  var entry = this.profile_.addCode(type, name, start, size);
+    type, start, size, name, maybe_func) {
+  if (maybe_func.length) {
+    var funcAddr = parseInt(maybe_func[0]);
+    var state = parseState(maybe_func[1]);
+    this.profile_.addFuncCode(type, name, start, size, funcAddr, state);
+  } else {
+    this.profile_.addCode(type, name, start, size);
+  }
 };
 
 
@@ -131,18 +151,14 @@ function TickProcessor(
       'shared-library': { parsers: [null, parseInt, parseInt],
           processor: this.processSharedLibrary },
       'code-creation': {
-          parsers: [null, parseInt, parseInt, null],
+          parsers: [null, parseInt, parseInt, null, 'var-args'],
           processor: this.processCodeCreation },
       'code-move': { parsers: [parseInt, parseInt],
           processor: this.processCodeMove },
       'code-delete': { parsers: [parseInt],
           processor: this.processCodeDelete },
-      'function-creation': { parsers: [parseInt, parseInt],
-          processor: this.processFunctionCreation },
-      'function-move': { parsers: [parseInt, parseInt],
+      'sfi-move': { parsers: [parseInt, parseInt],
           processor: this.processFunctionMove },
-      'function-delete': { parsers: [parseInt],
-          processor: this.processFunctionDelete },
       'snapshot-pos': { parsers: [parseInt, parseInt],
           processor: this.processSnapshotPosition },
       'tick': { parsers: [parseInt, parseInt, parseInt, parseInt, 'var-args'],
@@ -155,6 +171,9 @@ function TickProcessor(
           processor: this.processJSProducer },
       // Ignored events.
       'profiler': null,
+      'function-creation': null,
+      'function-move': null,
+      'function-delete': null,
       'heap-sample-stats': null,
       'heap-sample-item': null,
       'heap-js-cons-item': null,
@@ -285,9 +304,15 @@ TickProcessor.prototype.processSharedLibrary = function(
 
 
 TickProcessor.prototype.processCodeCreation = function(
-    type, start, size, name) {
+    type, start, size, name, maybe_func) {
   name = this.deserializedEntriesNames_[start] || name;
-  var entry = this.profile_.addCode(type, name, start, size);
+  if (maybe_func.length) {
+    var funcAddr = parseInt(maybe_func[0]);
+    var state = parseState(maybe_func[1]);
+    this.profile_.addFuncCode(type, name, start, size, funcAddr, state);
+  } else {
+    this.profile_.addCode(type, name, start, size);
+  }
 };
 
 
@@ -301,19 +326,8 @@ TickProcessor.prototype.processCodeDelete = function(start) {
 };
 
 
-TickProcessor.prototype.processFunctionCreation = function(
-    functionAddr, codeAddr) {
-  this.profile_.addCodeAlias(functionAddr, codeAddr);
-};
-
-
 TickProcessor.prototype.processFunctionMove = function(from, to) {
-  this.profile_.safeMoveDynamicCode(from, to);
-};
-
-
-TickProcessor.prototype.processFunctionDelete = function(start) {
-  this.profile_.safeDeleteDynamicCode(start);
+  this.profile_.moveFunc(from, to);
 };
 
 
@@ -330,7 +344,7 @@ TickProcessor.prototype.includeTick = function(vmState) {
 };
 
 
-TickProcessor.prototype.processTick = function(pc, sp, func, vmState, stack) {
+TickProcessor.prototype.processTick = function(pc, sp, tos, vmState, stack) {
   this.ticks_.total++;
   if (vmState == TickProcessor.VmStates.GC) this.ticks_.gc++;
   if (!this.includeTick(vmState)) {
@@ -338,19 +352,14 @@ TickProcessor.prototype.processTick = function(pc, sp, func, vmState, stack) {
     return;
   }
 
-  if (func) {
-    var funcEntry = this.profile_.findEntry(func);
+  if (tos) {
+    var funcEntry = this.profile_.findEntry(tos);
     if (!funcEntry || !funcEntry.isJSFunction || !funcEntry.isJSFunction()) {
-      func = 0;
-    } else {
-      var currEntry = this.profile_.findEntry(pc);
-      if (!currEntry || !currEntry.isJSFunction || currEntry.isJSFunction()) {
-        func = 0;
-      }
+      tos = 0;
     }
   }
 
-  this.profile_.recordTick(this.processStack(pc, func, stack));
+  this.profile_.recordTick(this.processStack(pc, tos, stack));
 };