Propagate DeoptInfo to cpu-profiler
authorloislo <loislo@chromium.org>
Tue, 10 Feb 2015 14:32:42 +0000 (06:32 -0800)
committerCommit bot <commit-bot@chromium.org>
Tue, 10 Feb 2015 14:33:00 +0000 (14:33 +0000)
1) Deoptimizer::Reason was replaced with Deoptimizer::DeoptInfo
because it also has raw position. Also the old name clashes with DeoptReason enum.

2) c_entry_fp assignment call was added to EntryGenerator::Generate
So we can calculate sp and have a chance to record the stack for the deopting function.
btw it makes the test stable.

3) new kind of CodeEvents was added to cpu-profiler

4) GetDeoptInfo method was extracted from PrintDeoptLocation.
So it could be reused in cpu profiler.

BUG=452067
LOG=n

Review URL: https://codereview.chromium.org/910773002

Cr-Commit-Position: refs/heads/master@{#26545}

26 files changed:
src/arm/deoptimizer-arm.cc
src/arm/lithium-codegen-arm.cc
src/arm64/deoptimizer-arm64.cc
src/arm64/lithium-codegen-arm64.cc
src/cpu-profiler-inl.h
src/cpu-profiler.cc
src/cpu-profiler.h
src/deoptimizer.cc
src/deoptimizer.h
src/ia32/deoptimizer-ia32.cc
src/ia32/lithium-codegen-ia32.cc
src/lithium-codegen.cc
src/lithium-codegen.h
src/log.cc
src/log.h
src/mips/deoptimizer-mips.cc
src/mips/lithium-codegen-mips.cc
src/mips64/lithium-codegen-mips64.cc
src/objects.cc
src/ppc/lithium-codegen-ppc.cc
src/profile-generator-inl.h
src/profile-generator.h
src/x64/deoptimizer-x64.cc
src/x64/lithium-codegen-x64.cc
src/x87/lithium-codegen-x87.cc
test/cctest/test-cpu-profiler.cc

index b3a6173cf0de82622b26fabe8b905455d3df1929..be05344e166207174079387400e471c119480201 100644 (file)
@@ -165,6 +165,9 @@ void Deoptimizer::EntryGenerator::Generate() {
   // handle this a bit differently.
   __ stm(db_w, sp, restored_regs  | sp.bit() | lr.bit() | pc.bit());
 
+  __ mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
+  __ str(fp, MemOperand(ip));
+
   const int kSavedRegistersAreaSize =
       (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize;
 
index 1b12643fbc421f06b123b14ce2ef971f5597bf17..8388999dcd2a241f2e58ee96d23c74bcf9308ee6 100644 (file)
@@ -336,7 +336,7 @@ bool LCodeGen::GenerateJumpTable() {
 
       DCHECK_EQ(jump_table_[0].bailout_type, table_entry->bailout_type);
       Address entry = table_entry->address;
-      DeoptComment(table_entry->reason);
+      DeoptComment(table_entry->deopt_info);
 
       // Second-level deopt table entries are contiguous and small, so instead
       // of loading the full, absolute address of each one, load an immediate
@@ -893,17 +893,17 @@ void LCodeGen::DeoptimizeIf(Condition condition, LInstruction* instr,
     __ stop("trap_on_deopt", condition);
   }
 
-  Deoptimizer::Reason reason(instr->hydrogen_value()->position().raw(),
-                             instr->Mnemonic(), deopt_reason);
+  Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position().raw(),
+                                    instr->Mnemonic(), deopt_reason);
   DCHECK(info()->IsStub() || frame_is_built_);
   // Go through jump table if we need to handle condition, build frame, or
   // restore caller doubles.
   if (condition == al && frame_is_built_ &&
       !info()->saves_caller_doubles()) {
-    DeoptComment(reason);
+    DeoptComment(deopt_info);
     __ Call(entry, RelocInfo::RUNTIME_ENTRY);
   } else {
-    Deoptimizer::JumpTableEntry table_entry(entry, reason, bailout_type,
+    Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
                                             !frame_is_built_);
     // We often have several deopts to the same entry, reuse the last
     // jump entry if this is the case.
index b83bbbe121e52d6d8cbcc56baab5a4eaa41dcb48..8c4b776efe2c5ea0774551fe996f0e242d909e4c 100644 (file)
@@ -132,6 +132,9 @@ void Deoptimizer::EntryGenerator::Generate() {
   saved_registers.Combine(fp);
   __ PushCPURegList(saved_registers);
 
+  __ Mov(x3, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
+  __ Str(fp, MemOperand(x3));
+
   const int kSavedRegistersAreaSize =
       (saved_registers.Count() * kXRegSize) +
       (saved_fp_registers.Count() * kDRegSize);
index b0c9258dd06fd2608f5a191507888ad68524ccda..b1358ccf61519d7b737e463b151822204b1087b4 100644 (file)
@@ -856,7 +856,7 @@ bool LCodeGen::GenerateJumpTable() {
       __ Bind(&table_entry->label);
 
       Address entry = table_entry->address;
-      DeoptComment(table_entry->reason);
+      DeoptComment(table_entry->deopt_info);
 
       // Second-level deopt table entries are contiguous and small, so instead
       // of loading the full, absolute address of each one, load the base
@@ -1057,18 +1057,18 @@ void LCodeGen::DeoptimizeBranch(
     __ Bind(&dont_trap);
   }
 
-  Deoptimizer::Reason reason(instr->hydrogen_value()->position().raw(),
-                             instr->Mnemonic(), deopt_reason);
+  Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position().raw(),
+                                    instr->Mnemonic(), deopt_reason);
   DCHECK(info()->IsStub() || frame_is_built_);
   // Go through jump table if we need to build frame, or restore caller doubles.
   if (branch_type == always &&
       frame_is_built_ && !info()->saves_caller_doubles()) {
-    DeoptComment(reason);
+    DeoptComment(deopt_info);
     __ Call(entry, RelocInfo::RUNTIME_ENTRY);
   } else {
     Deoptimizer::JumpTableEntry* table_entry =
-        new (zone()) Deoptimizer::JumpTableEntry(entry, reason, bailout_type,
-                                                 !frame_is_built_);
+        new (zone()) Deoptimizer::JumpTableEntry(
+            entry, deopt_info, bailout_type, !frame_is_built_);
     // We often have several deopts to the same entry, reuse the last
     // jump entry if this is the case.
     if (jump_table_.is_empty() ||
index c63a9c3cc251dd4805a14b122db20fb5fae0de9f..b1adc1bc8f23e19cfda7e7a6ce213de3996f5f86 100644 (file)
@@ -36,6 +36,15 @@ void CodeDisableOptEventRecord::UpdateCodeMap(CodeMap* code_map) {
 }
 
 
+void CodeDeoptEventRecord::UpdateCodeMap(CodeMap* code_map) {
+  CodeEntry* entry = code_map->FindEntry(start);
+  if (entry != NULL) {
+    entry->set_deopt_reason(deopt_reason);
+    entry->set_deopt_location(raw_position);
+  }
+}
+
+
 void SharedFunctionInfoMoveEventRecord::UpdateCodeMap(CodeMap* code_map) {
   code_map->MoveCode(from, to);
 }
index 456770b4c67c122e0db54063431ee7e22dd4eee9..c276bb6d6079dcd065340b16a817681dc930f713 100644 (file)
@@ -7,6 +7,7 @@
 #include "src/cpu-profiler-inl.h"
 
 #include "src/compiler.h"
+#include "src/deoptimizer.h"
 #include "src/frames-inl.h"
 #include "src/hashmap.h"
 #include "src/log-inl.h"
@@ -38,6 +39,19 @@ void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) {
 }
 
 
+void ProfilerEventsProcessor::AddDeoptStack(Isolate* isolate, Address from,
+                                            int fp_to_sp_delta) {
+  TickSampleEventRecord record(last_code_event_id_);
+  RegisterState regs;
+  Address fp = isolate->c_entry_fp(isolate->thread_local_top());
+  regs.sp = fp - fp_to_sp_delta;
+  regs.fp = fp;
+  regs.pc = from;
+  record.sample.Init(isolate, regs, TickSample::kSkipCEntryFrame);
+  ticks_from_vm_buffer_.Enqueue(record);
+}
+
+
 void ProfilerEventsProcessor::AddCurrentStack(Isolate* isolate) {
   TickSampleEventRecord record(last_code_event_id_);
   RegisterState regs;
@@ -329,6 +343,19 @@ void CpuProfiler::CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) {
 }
 
 
+void CpuProfiler::CodeDeoptEvent(Code* code, int bailout_id, Address pc,
+                                 int fp_to_sp_delta) {
+  CodeEventsContainer evt_rec(CodeEventRecord::CODE_DEOPT);
+  CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_;
+  Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(code, bailout_id);
+  rec->start = code->address();
+  rec->deopt_reason = Deoptimizer::GetDeoptReason(info.deopt_reason);
+  rec->raw_position = info.raw_position;
+  processor_->Enqueue(evt_rec);
+  processor_->AddDeoptStack(isolate_, pc, fp_to_sp_delta);
+}
+
+
 void CpuProfiler::CodeDeleteEvent(Address from) {
 }
 
index 4dc5643aa1bc73fe8ccbcba72492e07f0d71ed2a..140de3b906084df41fe9e10d2549bd24195b805e 100644 (file)
@@ -23,12 +23,13 @@ class CpuProfile;
 class CpuProfilesCollection;
 class ProfileGenerator;
 
-#define CODE_EVENTS_TYPE_LIST(V)                                   \
-  V(CODE_CREATION,    CodeCreateEventRecord)                       \
-  V(CODE_MOVE,        CodeMoveEventRecord)                         \
-  V(CODE_DISABLE_OPT, CodeDisableOptEventRecord)                   \
-  V(SHARED_FUNC_MOVE, SharedFunctionInfoMoveEventRecord)           \
-  V(REPORT_BUILTIN,   ReportBuiltinEventRecord)
+#define CODE_EVENTS_TYPE_LIST(V)                         \
+  V(CODE_CREATION, CodeCreateEventRecord)                \
+  V(CODE_MOVE, CodeMoveEventRecord)                      \
+  V(CODE_DISABLE_OPT, CodeDisableOptEventRecord)         \
+  V(CODE_DEOPT, CodeDeoptEventRecord)                    \
+  V(SHARED_FUNC_MOVE, SharedFunctionInfoMoveEventRecord) \
+  V(REPORT_BUILTIN, ReportBuiltinEventRecord)
 
 
 class CodeEventRecord {
@@ -75,6 +76,16 @@ class CodeDisableOptEventRecord : public CodeEventRecord {
 };
 
 
+class CodeDeoptEventRecord : public CodeEventRecord {
+ public:
+  Address start;
+  const char* deopt_reason;
+  int raw_position;
+
+  INLINE(void UpdateCodeMap(CodeMap* code_map));
+};
+
+
 class SharedFunctionInfoMoveEventRecord : public CodeEventRecord {
  public:
   Address from;
@@ -137,6 +148,7 @@ class ProfilerEventsProcessor : public base::Thread {
 
   // Puts current stack into tick sample events buffer.
   void AddCurrentStack(Isolate* isolate);
+  void AddDeoptStack(Isolate* isolate, Address from, int fp_to_sp_delta);
 
   // Tick sample events are filled directly in the buffer of the circular
   // queue (because the structure is of fixed width, but usually not all
@@ -233,6 +245,8 @@ class CpuProfiler : public CodeEventListener {
   virtual void CodeMovingGCEvent() {}
   virtual void CodeMoveEvent(Address from, Address to);
   virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared);
+  virtual void CodeDeoptEvent(Code* code, int bailout_id, Address pc,
+                              int fp_to_sp_delta);
   virtual void CodeDeleteEvent(Address from);
   virtual void GetterCallbackEvent(Name* name, Address entry_point);
   virtual void RegExpCodeCreateEvent(Code* code, String* source);
index 02762f54dc63da4ea66650b37f546c13b779dbda..5ce3fa3aa4c069b77143491e058d26176131a9c5 100644 (file)
@@ -592,7 +592,6 @@ Deoptimizer::Deoptimizer(Isolate* isolate,
     }
   }
   compiled_code_ = FindOptimizedCode(function, optimized_code);
-
 #if DEBUG
   DCHECK(compiled_code_ != NULL);
   if (type == EAGER || type == SOFT || type == LAZY) {
@@ -609,6 +608,10 @@ Deoptimizer::Deoptimizer(Isolate* isolate,
   CHECK(AllowHeapAllocation::IsAllowed());
   disallow_heap_allocation_ = new DisallowHeapAllocation();
 #endif  // DEBUG
+  if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
+    PROFILE(isolate_, CodeDeoptEvent(compiled_code_, bailout_id_, from_,
+                                     fp_to_sp_delta_));
+  }
   unsigned size = ComputeInputFrameSize();
   input_ = new(size) FrameDescription(size, function);
   input_->SetFrameType(frame_type);
@@ -747,11 +750,6 @@ int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
 // We rely on this function not causing a GC.  It is called from generated code
 // without having a real stack frame in place.
 void Deoptimizer::DoComputeOutputFrames() {
-  // Print some helpful diagnostic information.
-  if (FLAG_log_timer_events &&
-      compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
-    LOG(isolate(), CodeDeoptEvent(compiled_code_));
-  }
   base::ElapsedTimer timer;
 
   // Determine basic deoptimization information.  The optimized frame is
@@ -3637,4 +3635,36 @@ const char* Deoptimizer::GetDeoptReason(DeoptReason deopt_reason) {
 #undef DEOPT_MESSAGES_TEXTS
   return deopt_messages_[deopt_reason];
 }
+
+
+Deoptimizer::DeoptInfo Deoptimizer::GetDeoptInfo(Code* code, int bailout_id) {
+  int last_position = 0;
+  Isolate* isolate = code->GetIsolate();
+  Deoptimizer::DeoptReason last_reason = Deoptimizer::kNoReason;
+  int mask = RelocInfo::ModeMask(RelocInfo::DEOPT_REASON) |
+             RelocInfo::ModeMask(RelocInfo::POSITION) |
+             RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
+  for (RelocIterator it(code, mask); !it.done(); it.next()) {
+    RelocInfo* info = it.rinfo();
+    if (info->rmode() == RelocInfo::POSITION) {
+      last_position = static_cast<int>(info->data());
+    } else if (info->rmode() == RelocInfo::DEOPT_REASON) {
+      last_reason = static_cast<Deoptimizer::DeoptReason>(info->data());
+    } else if (last_reason != Deoptimizer::kNoReason) {
+      if ((bailout_id ==
+           Deoptimizer::GetDeoptimizationId(isolate, info->target_address(),
+                                            Deoptimizer::EAGER)) ||
+          (bailout_id ==
+           Deoptimizer::GetDeoptimizationId(isolate, info->target_address(),
+                                            Deoptimizer::SOFT)) ||
+          (bailout_id ==
+           Deoptimizer::GetDeoptimizationId(isolate, info->target_address(),
+                                            Deoptimizer::LAZY))) {
+        CHECK(RelocInfo::IsRuntimeEntry(info->rmode()));
+        return DeoptInfo(last_position, NULL, last_reason);
+      }
+    }
+  }
+  return DeoptInfo(0, NULL, Deoptimizer::kNoReason);
+}
 } }  // namespace v8::internal
index 7245810f21ceb0db0f44e1b36fd1699cc6444d65..35c3cbe66c49a7517fbf87f9c1779ede62f5192c 100644 (file)
@@ -184,41 +184,43 @@ class Deoptimizer : public Malloced {
 
   static const char* GetDeoptReason(DeoptReason deopt_reason);
 
-  struct Reason {
-    Reason(int r, const char* m, DeoptReason d)
+  struct DeoptInfo {
+    DeoptInfo(int r, const char* m, DeoptReason d)
         : raw_position(r), mnemonic(m), deopt_reason(d) {}
 
-    bool operator==(const Reason& other) const {
+    bool operator==(const DeoptInfo& other) const {
       return raw_position == other.raw_position &&
              CStringEquals(mnemonic, other.mnemonic) &&
              deopt_reason == other.deopt_reason;
     }
 
-    bool operator!=(const Reason& other) const { return !(*this == other); }
+    bool operator!=(const DeoptInfo& other) const { return !(*this == other); }
 
     int raw_position;
     const char* mnemonic;
     DeoptReason deopt_reason;
   };
 
+  static DeoptInfo GetDeoptInfo(Code* code, int bailout_id);
+
   struct JumpTableEntry : public ZoneObject {
-    inline JumpTableEntry(Address entry, const Reason& the_reason,
+    inline JumpTableEntry(Address entry, const DeoptInfo& deopt_info,
                           Deoptimizer::BailoutType type, bool frame)
         : label(),
           address(entry),
-          reason(the_reason),
+          deopt_info(deopt_info),
           bailout_type(type),
           needs_frame(frame) {}
 
     bool IsEquivalentTo(const JumpTableEntry& other) const {
       return address == other.address && bailout_type == other.bailout_type &&
              needs_frame == other.needs_frame &&
-             (!FLAG_trace_deopt || reason == other.reason);
+             (!FLAG_trace_deopt || deopt_info == other.deopt_info);
     }
 
     Label label;
     Address address;
-    Reason reason;
+    DeoptInfo deopt_info;
     Deoptimizer::BailoutType bailout_type;
     bool needs_frame;
   };
index e451fcc9e6fa0fa40f47034d9abb655d32c59318..4c1475b9d25c17f82698a027effc88fd059c39bd 100644 (file)
@@ -244,6 +244,9 @@ void Deoptimizer::EntryGenerator::Generate() {
 
   __ pushad();
 
+  ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, isolate());
+  __ mov(Operand::StaticVariable(c_entry_fp_address), ebp);
+
   const int kSavedRegistersAreaSize = kNumberOfRegisters * kPointerSize +
                                       kDoubleRegsSize;
 
index 3e6de5f0bc61f7ea0fc1ae51c437f4cdaadfbbaa..40a0ca3c23fcb91dd07ac2ce1401447e66c40f8f 100644 (file)
@@ -384,7 +384,7 @@ bool LCodeGen::GenerateJumpTable() {
     Deoptimizer::JumpTableEntry* table_entry = &jump_table_[i];
     __ bind(&table_entry->label);
     Address entry = table_entry->address;
-    DeoptComment(table_entry->reason);
+    DeoptComment(table_entry->deopt_info);
     if (table_entry->needs_frame) {
       DCHECK(!info()->saves_caller_doubles());
       __ push(Immediate(ExternalReference::ForDeoptEntry(entry)));
@@ -861,14 +861,14 @@ void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr,
     __ bind(&done);
   }
 
-  Deoptimizer::Reason reason(instr->hydrogen_value()->position().raw(),
-                             instr->Mnemonic(), deopt_reason);
+  Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position().raw(),
+                                    instr->Mnemonic(), deopt_reason);
   DCHECK(info()->IsStub() || frame_is_built_);
   if (cc == no_condition && frame_is_built_) {
-    DeoptComment(reason);
+    DeoptComment(deopt_info);
     __ call(entry, RelocInfo::RUNTIME_ENTRY);
   } else {
-    Deoptimizer::JumpTableEntry table_entry(entry, reason, bailout_type,
+    Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
                                             !frame_is_built_);
     // We often have several deopts to the same entry, reuse the last
     // jump entry if this is the case.
index 12d8e2f3eebbf79b3ce1af604d133bf10dbfa5c6..242db222f2db03c60eaa3828cc1a02e36c119981 100644 (file)
@@ -152,8 +152,8 @@ void LCodeGenBase::Comment(const char* format, ...) {
 }
 
 
-void LCodeGenBase::DeoptComment(const Deoptimizer::Reason& reason) {
-  masm()->RecordDeoptReason(reason.deopt_reason, reason.raw_position);
+void LCodeGenBase::DeoptComment(const Deoptimizer::DeoptInfo& deopt_info) {
+  masm()->RecordDeoptReason(deopt_info.deopt_reason, deopt_info.raw_position);
 }
 
 
index 40d4d8e4f8e733224f9c36e7c04c8a1e300c1dd7..17bf78cac0cd3cc662cad53ed642670f4f88c27d 100644 (file)
@@ -35,7 +35,7 @@ class LCodeGenBase BASE_EMBEDDED {
   HGraph* graph() const;
 
   void FPRINTF_CHECKING Comment(const char* format, ...);
-  void DeoptComment(const Deoptimizer::Reason& reason);
+  void DeoptComment(const Deoptimizer::DeoptInfo& deopt_info);
 
   bool GenerateBody();
   virtual void GenerateBodyInstructionPre(LInstruction* instr) {}
index 3f1c970885183f88721d2510d8aa72c6162b98bb..35cf0aa90bbbdd7eb1fba0dab19049c1eb486693 100644 (file)
@@ -911,9 +911,10 @@ void Logger::SharedLibraryEvent(const std::string& library_path,
 }
 
 
-void Logger::CodeDeoptEvent(Code* code) {
-  if (!log_->IsEnabled()) return;
-  DCHECK(FLAG_log_internal_timer_events);
+void Logger::CodeDeoptEvent(Code* code, int bailout_id, Address from,
+                            int fp_to_sp_delta) {
+  PROFILER_LOG(CodeDeoptEvent(code, bailout_id, from, fp_to_sp_delta));
+  if (!log_->IsEnabled() || !FLAG_log_internal_timer_events) return;
   Log::MessageBuilder msg(log_);
   int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
   msg.Append("code-deopt,%ld,%d", since_epoch, code->CodeSize());
index abf35f0ebc5ddcf0373f598d0cf48eee1d479e5c..bb7ff32e7d6d8163d92531cce1494cbc4f0fb3f8 100644 (file)
--- a/src/log.h
+++ b/src/log.h
@@ -292,7 +292,8 @@ class Logger {
                           uintptr_t start,
                           uintptr_t end);
 
-  void CodeDeoptEvent(Code* code);
+  void CodeDeoptEvent(Code* code, int bailout_id, Address from,
+                      int fp_to_sp_delta);
   void CurrentTimeEvent();
 
   void TimerEvent(StartEnd se, const char* name);
index e39b3689789acebd80c7229726cfb2b3fdc9e64c..3dfc64a6058f974828de4db33eda38988832fdab 100644 (file)
@@ -162,6 +162,9 @@ void Deoptimizer::EntryGenerator::Generate() {
     }
   }
 
+  __ li(a2, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
+  __ sw(fp, MemOperand(a2));
+
   const int kSavedRegistersAreaSize =
       (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize;
 
index 2ecd826124c54f5933e12023f82505c49040ed7c..46b5471f66c39ffc2604ca0940a3aef5f4ed1f30 100644 (file)
@@ -337,7 +337,7 @@ bool LCodeGen::GenerateJumpTable() {
 
       DCHECK(table_entry->bailout_type == jump_table_[0].bailout_type);
       Address entry = table_entry->address;
-      DeoptComment(table_entry->reason);
+      DeoptComment(table_entry->deopt_info);
 
       // Second-level deopt table entries are contiguous and small, so instead
       // of loading the full, absolute address of each one, load an immediate
@@ -856,17 +856,17 @@ void LCodeGen::DeoptimizeIf(Condition condition, LInstruction* instr,
     __ bind(&skip);
   }
 
-  Deoptimizer::Reason reason(instr->hydrogen_value()->position().raw(),
-                             instr->Mnemonic(), deopt_reason);
+  Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position().raw(),
+                                    instr->Mnemonic(), deopt_reason);
   DCHECK(info()->IsStub() || frame_is_built_);
   // Go through jump table if we need to handle condition, build frame, or
   // restore caller doubles.
   if (condition == al && frame_is_built_ &&
       !info()->saves_caller_doubles()) {
-    DeoptComment(reason);
+    DeoptComment(deopt_info);
     __ Call(entry, RelocInfo::RUNTIME_ENTRY, condition, src1, src2);
   } else {
-    Deoptimizer::JumpTableEntry table_entry(entry, reason, bailout_type,
+    Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
                                             !frame_is_built_);
     // We often have several deopts to the same entry, reuse the last
     // jump entry if this is the case.
index fa86b495a9e409462d17044299dcd40e4b790cf3..49c465086e62fe33801815811c17601d858d2f62 100644 (file)
@@ -309,7 +309,7 @@ bool LCodeGen::GenerateJumpTable() {
     Deoptimizer::JumpTableEntry* table_entry = &jump_table_[i];
     __ bind(&table_entry->label);
     Address entry = table_entry->address;
-    DeoptComment(table_entry->reason);
+    DeoptComment(table_entry->deopt_info);
     __ li(t9, Operand(ExternalReference::ForDeoptEntry(entry)));
     if (table_entry->needs_frame) {
       DCHECK(!info()->saves_caller_doubles());
@@ -806,17 +806,17 @@ void LCodeGen::DeoptimizeIf(Condition condition, LInstruction* instr,
     __ bind(&skip);
   }
 
-  Deoptimizer::Reason reason(instr->hydrogen_value()->position().raw(),
-                             instr->Mnemonic(), deopt_reason);
+  Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position().raw(),
+                                    instr->Mnemonic(), deopt_reason);
   DCHECK(info()->IsStub() || frame_is_built_);
   // Go through jump table if we need to handle condition, build frame, or
   // restore caller doubles.
   if (condition == al && frame_is_built_ &&
       !info()->saves_caller_doubles()) {
-    DeoptComment(reason);
+    DeoptComment(deopt_info);
     __ Call(entry, RelocInfo::RUNTIME_ENTRY, condition, src1, src2);
   } else {
-    Deoptimizer::JumpTableEntry table_entry(entry, reason, bailout_type,
+    Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
                                             !frame_is_built_);
     // We often have several deopts to the same entry, reuse the last
     // jump entry if this is the case.
index 20fd66b37eb90b1f1523627350edace29096bfa9..e8bb005dc8b8f46ae88b0b68dc75e3b5ef773e2f 100644 (file)
@@ -11084,30 +11084,10 @@ Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) {
 
 
 void Code::PrintDeoptLocation(FILE* out, int bailout_id) {
-  int last_position = 0;
-  Deoptimizer::DeoptReason last_reason = Deoptimizer::kNoReason;
-  int mask = RelocInfo::ModeMask(RelocInfo::DEOPT_REASON) |
-             RelocInfo::ModeMask(RelocInfo::POSITION) |
-             RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
-  for (RelocIterator it(this, mask); !it.done(); it.next()) {
-    RelocInfo* info = it.rinfo();
-    if (info->rmode() == RelocInfo::POSITION) {
-      last_position = static_cast<int>(info->data());
-    } else if (info->rmode() == RelocInfo::DEOPT_REASON) {
-      last_reason = static_cast<Deoptimizer::DeoptReason>(info->data());
-    } else if (last_reason != Deoptimizer::kNoReason) {
-      if ((bailout_id == Deoptimizer::GetDeoptimizationId(
-              GetIsolate(), info->target_address(), Deoptimizer::EAGER)) ||
-          (bailout_id == Deoptimizer::GetDeoptimizationId(
-              GetIsolate(), info->target_address(), Deoptimizer::SOFT)) ||
-          (bailout_id == Deoptimizer::GetDeoptimizationId(
-              GetIsolate(), info->target_address(), Deoptimizer::LAZY))) {
-        CHECK(RelocInfo::IsRuntimeEntry(info->rmode()));
-        PrintF(out, "            ;;; deoptimize at %d: %s\n", last_position,
-               Deoptimizer::GetDeoptReason(last_reason));
-        return;
-      }
-    }
+  Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, bailout_id);
+  if (info.deopt_reason != Deoptimizer::kNoReason || info.raw_position != 0) {
+    PrintF(out, "            ;;; deoptimize at %d: %s\n", info.raw_position,
+           Deoptimizer::GetDeoptReason(info.deopt_reason));
   }
 }
 
index c1f2ecd443913ca7d7ab23231ee5882a0609952b..665c14e2ee20914527b4d3c9ecd20af70467782f 100644 (file)
@@ -327,7 +327,7 @@ bool LCodeGen::GenerateJumpTable() {
 
       DCHECK_EQ(jump_table_[0].bailout_type, table_entry->bailout_type);
       Address entry = table_entry->address;
-      DeoptComment(table_entry->reason);
+      DeoptComment(table_entry->deopt_info);
 
       // Second-level deopt table entries are contiguous and small, so instead
       // of loading the full, absolute address of each one, load an immediate
@@ -812,16 +812,16 @@ void LCodeGen::DeoptimizeIf(Condition cond, LInstruction* instr,
     __ stop("trap_on_deopt", cond, kDefaultStopCode, cr);
   }
 
-  Deoptimizer::Reason reason(instr->hydrogen_value()->position().raw(),
-                             instr->Mnemonic(), deopt_reason);
+  Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position().raw(),
+                                    instr->Mnemonic(), deopt_reason);
   DCHECK(info()->IsStub() || frame_is_built_);
   // Go through jump table if we need to handle condition, build frame, or
   // restore caller doubles.
   if (cond == al && frame_is_built_ && !info()->saves_caller_doubles()) {
-    DeoptComment(reason);
+    DeoptComment(deopt_info);
     __ Call(entry, RelocInfo::RUNTIME_ENTRY);
   } else {
-    Deoptimizer::JumpTableEntry table_entry(entry, reason, bailout_type,
+    Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
                                             !frame_is_built_);
     // We often have several deopts to the same entry, reuse the last
     // jump entry if this is the case.
index c53d749918e2d036393d535730eb09d5e670fb8e..3e8204618dbfe4f090fd07a2f720ebe56e3ab7a6 100644 (file)
@@ -25,6 +25,8 @@ CodeEntry::CodeEntry(Logger::LogEventsAndTags tag, const char* name,
       script_id_(v8::UnboundScript::kNoScriptId),
       no_frame_ranges_(NULL),
       bailout_reason_(kEmptyBailoutReason),
+      deopt_reason_(kEmptyBailoutReason),
+      deopt_location_(0),
       line_info_(line_info),
       instruction_start_(instruction_start) {}
 
index 2127a1e1ca78179be71aedab100cc152b9c7e8e7..17ec10b44d3ac9fd311e2786fda159893504132c 100644 (file)
@@ -90,6 +90,10 @@ class CodeEntry {
   void set_bailout_reason(const char* bailout_reason) {
     bailout_reason_ = bailout_reason;
   }
+  void set_deopt_reason(const char* deopt_reason) {
+    deopt_reason_ = deopt_reason;
+  }
+  void set_deopt_location(int location) { deopt_location_ = location; }
   const char* bailout_reason() const { return bailout_reason_; }
 
   static inline bool is_js_function_tag(Logger::LogEventsAndTags tag);
@@ -130,6 +134,8 @@ class CodeEntry {
   int script_id_;
   List<OffsetRange>* no_frame_ranges_;
   const char* bailout_reason_;
+  const char* deopt_reason_;
+  int deopt_location_;
   JITLineInfoTable* line_info_;
   Address instruction_start_;
 
index 54fe9b0cfeeb2466597828d55f316fa220b88c51..2fc61814c881d856452a8bf1cc77e17c59787cbe 100644 (file)
@@ -160,6 +160,8 @@ void Deoptimizer::EntryGenerator::Generate() {
   const int kSavedRegistersAreaSize = kNumberOfRegisters * kRegisterSize +
                                       kDoubleRegsSize;
 
+  __ Store(ExternalReference(Isolate::kCEntryFPAddress, isolate()), rbp);
+
   // We use this to keep the value of the fifth argument temporarily.
   // Unfortunately we can't store it directly in r8 (used for passing
   // this on linux), since it is another parameter passing register on windows.
index 589db684ff22f4418a70f1f094d4c44c94c25da1..ca5c04cc9e9f504dad0cb2fa107f499a25c5566e 100644 (file)
@@ -304,7 +304,7 @@ bool LCodeGen::GenerateJumpTable() {
     Deoptimizer::JumpTableEntry* table_entry = &jump_table_[i];
     __ bind(&table_entry->label);
     Address entry = table_entry->address;
-    DeoptComment(table_entry->reason);
+    DeoptComment(table_entry->deopt_info);
     if (table_entry->needs_frame) {
       DCHECK(!info()->saves_caller_doubles());
       __ Move(kScratchRegister, ExternalReference::ForDeoptEntry(entry));
@@ -768,17 +768,17 @@ void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr,
     __ bind(&done);
   }
 
-  Deoptimizer::Reason reason(instr->hydrogen_value()->position().raw(),
-                             instr->Mnemonic(), deopt_reason);
+  Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position().raw(),
+                                    instr->Mnemonic(), deopt_reason);
   DCHECK(info()->IsStub() || frame_is_built_);
   // Go through jump table if we need to handle condition, build frame, or
   // restore caller doubles.
   if (cc == no_condition && frame_is_built_ &&
       !info()->saves_caller_doubles()) {
-    DeoptComment(reason);
+    DeoptComment(deopt_info);
     __ call(entry, RelocInfo::RUNTIME_ENTRY);
   } else {
-    Deoptimizer::JumpTableEntry table_entry(entry, reason, bailout_type,
+    Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
                                             !frame_is_built_);
     // We often have several deopts to the same entry, reuse the last
     // jump entry if this is the case.
index 76edbb095e1c906c71c201548e475544655f799d..13614b0231a1a7da26f3c7208dab0357cc847e32 100644 (file)
@@ -381,7 +381,7 @@ bool LCodeGen::GenerateJumpTable() {
     Deoptimizer::JumpTableEntry* table_entry = &jump_table_[i];
     __ bind(&table_entry->label);
     Address entry = table_entry->address;
-    DeoptComment(table_entry->reason);
+    DeoptComment(table_entry->deopt_info);
     if (table_entry->needs_frame) {
       DCHECK(!info()->saves_caller_doubles());
       __ push(Immediate(ExternalReference::ForDeoptEntry(entry)));
@@ -1143,14 +1143,14 @@ void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr,
     __ bind(&done);
   }
 
-  Deoptimizer::Reason reason(instr->hydrogen_value()->position().raw(),
-                             instr->Mnemonic(), deopt_reason);
+  Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position().raw(),
+                                    instr->Mnemonic(), deopt_reason);
   DCHECK(info()->IsStub() || frame_is_built_);
   if (cc == no_condition && frame_is_built_) {
-    DeoptComment(reason);
+    DeoptComment(deopt_info);
     __ call(entry, RelocInfo::RUNTIME_ENTRY);
   } else {
-    Deoptimizer::JumpTableEntry table_entry(entry, reason, bailout_type,
+    Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
                                             !frame_is_built_);
     // We often have several deopts to the same entry, reuse the last
     // jump entry if this is the case.
index c6a31dd27ecdae11a5385e388cd05d04b838cc5b..1f768790939251725d1ffe772e0e755ffae0ddc2 100644 (file)
@@ -493,6 +493,17 @@ static void CheckSimpleBranch(v8::Isolate* isolate,
 }
 
 
+static const v8::CpuProfileNode* GetSimpleBranch(v8::Isolate* isolate,
+                                                 const v8::CpuProfileNode* node,
+                                                 const char* names[],
+                                                 int length) {
+  for (int i = 0; i < length; i++) {
+    node = GetChild(isolate, node, names[i]);
+  }
+  return node;
+}
+
+
 static const char* cpu_profiler_test_source = "function loop(timeout) {\n"
 "  this.mmm = 0;\n"
 "  var start = Date.now();\n"
@@ -1706,3 +1717,48 @@ TEST(DontStopOnFinishedProfileDelete) {
   outer_profile = NULL;
   CHECK_EQ(0, iprofiler->GetProfilesCount());
 }
+
+
+static const char* collect_deopt_events_test_source =
+    "function opt_function(value) {\n"
+    "  return value / 10;\n"
+    "}\n"
+    "\n"
+    "function test(value) {\n"
+    "  return opt_function(value);\n"
+    "}\n"
+    "\n"
+    "startProfiling();\n"
+    "\n"
+    "for (var i = 0; i < 10; ++i) test(10);\n"
+    "\n"
+    "%OptimizeFunctionOnNextCall(opt_function)\n"
+    "\n"
+    "for (var i = 0; i < 10; ++i) test(10);\n"
+    "\n"
+    "for (var i = 0; i < 10; ++i) test(undefined);\n"
+    "\n"
+    "stopProfiling();\n"
+    "\n";
+
+
+TEST(CollectDeoptEvents) {
+  if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
+  i::FLAG_allow_natives_syntax = true;
+  v8::HandleScope scope(CcTest::isolate());
+  v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
+  v8::Context::Scope context_scope(env);
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::CpuProfiler* profiler = isolate->GetCpuProfiler();
+  i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
+
+  v8::Script::Compile(v8_str(collect_deopt_events_test_source))->Run();
+  i::CpuProfile* iprofile = iprofiler->GetProfile(0);
+  iprofile->Print();
+  v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
+  const char* branch[] = {"", "test", "opt_function"};
+  const v8::CpuProfileNode* opt_function = GetSimpleBranch(
+      env->GetIsolate(), profile->GetTopDownRoot(), branch, arraysize(branch));
+  CHECK(opt_function);
+  iprofiler->DeleteProfile(iprofile);
+}