OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/profiler/tick-sample.h" | 5 #include "src/profiler/tick-sample.h" |
6 | 6 |
7 #include "src/frames-inl.h" | 7 #include "src/frames-inl.h" |
8 #include "src/vm-state-inl.h" | 8 #include "src/vm-state-inl.h" |
9 | 9 |
10 | 10 |
11 namespace v8 { | 11 namespace v8 { |
12 namespace internal { | 12 namespace internal { |
13 | 13 |
14 namespace { | 14 namespace { |
15 | 15 |
16 bool IsSamePage(byte* ptr1, byte* ptr2) { | 16 bool IsSamePage(byte* ptr1, byte* ptr2) { |
17 const uint32_t kPageSize = 4096; | 17 const uint32_t kPageSize = 4096; |
18 uintptr_t mask = ~static_cast<uintptr_t>(kPageSize - 1); | 18 uintptr_t mask = ~static_cast<uintptr_t>(kPageSize - 1); |
19 return (reinterpret_cast<uintptr_t>(ptr1) & mask) == | 19 return (reinterpret_cast<uintptr_t>(ptr1) & mask) == |
20 (reinterpret_cast<uintptr_t>(ptr2) & mask); | 20 (reinterpret_cast<uintptr_t>(ptr2) & mask); |
21 } | 21 } |
22 | 22 |
| 23 |
23 // Check if the code at specified address could potentially be a | 24 // Check if the code at specified address could potentially be a |
24 // frame setup code. | 25 // frame setup code. |
25 bool IsNoFrameRegion(Address address) { | 26 bool IsNoFrameRegion(Address address) { |
26 struct Pattern { | 27 struct Pattern { |
27 int bytes_count; | 28 int bytes_count; |
28 byte bytes[8]; | 29 byte bytes[8]; |
29 int offsets[4]; | 30 int offsets[4]; |
30 }; | 31 }; |
31 byte* pc = reinterpret_cast<byte*>(address); | 32 byte* pc = reinterpret_cast<byte*>(address); |
32 static Pattern patterns[] = { | 33 static Pattern patterns[] = { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 if (!memcmp(pc, pattern->bytes + offset, pattern->bytes_count - offset)) | 70 if (!memcmp(pc, pattern->bytes + offset, pattern->bytes_count - offset)) |
70 return true; | 71 return true; |
71 } | 72 } |
72 } | 73 } |
73 } | 74 } |
74 return false; | 75 return false; |
75 } | 76 } |
76 | 77 |
77 } // namespace | 78 } // namespace |
78 | 79 |
| 80 |
79 // | 81 // |
80 // StackTracer implementation | 82 // StackTracer implementation |
81 // | 83 // |
82 DISABLE_ASAN void TickSample::Init(Isolate* isolate, | 84 DISABLE_ASAN void TickSample::Init(Isolate* isolate, |
83 const v8::RegisterState& regs, | 85 const v8::RegisterState& regs, |
84 RecordCEntryFrame record_c_entry_frame, | 86 RecordCEntryFrame record_c_entry_frame, |
85 bool update_stats) { | 87 bool update_stats) { |
86 timestamp = base::TimeTicks::HighResolutionNow(); | 88 timestamp = base::TimeTicks::HighResolutionNow(); |
| 89 pc = reinterpret_cast<Address>(regs.pc); |
| 90 state = isolate->current_vm_state(); |
87 this->update_stats = update_stats; | 91 this->update_stats = update_stats; |
88 | 92 |
89 SampleInfo info; | 93 // Avoid collecting traces while doing GC. |
90 if (GetStackSample(isolate, regs, record_c_entry_frame, | 94 if (state == GC) return; |
91 reinterpret_cast<void**>(&stack[0]), kMaxFramesCount, | |
92 &info)) { | |
93 state = info.vm_state; | |
94 pc = static_cast<Address>(regs.pc); | |
95 frames_count = static_cast<unsigned>(info.frames_count); | |
96 has_external_callback = info.external_callback_entry != nullptr; | |
97 if (has_external_callback) { | |
98 external_callback_entry = | |
99 static_cast<Address>(info.external_callback_entry); | |
100 } else if (frames_count) { | |
101 // sp register may point at an arbitrary place in memory, make | |
102 // sure MSAN doesn't complain about it. | |
103 MSAN_MEMORY_IS_INITIALIZED(regs.sp, sizeof(Address)); | |
104 // Sample potential return address value for frameless invocation of | |
105 // stubs (we'll figure out later, if this value makes sense). | |
106 tos = Memory::Address_at(reinterpret_cast<Address>(regs.sp)); | |
107 } else { | |
108 tos = nullptr; | |
109 } | |
110 } else { | |
111 // It is executing JS but failed to collect a stack trace. | |
112 // Mark the sample as spoiled. | |
113 timestamp = base::TimeTicks(); | |
114 pc = nullptr; | |
115 } | |
116 } | |
117 | |
118 bool TickSample::GetStackSample(Isolate* isolate, const v8::RegisterState& regs, | |
119 RecordCEntryFrame record_c_entry_frame, | |
120 void** frames, size_t frames_limit, | |
121 v8::SampleInfo* sample_info) { | |
122 sample_info->frames_count = 0; | |
123 sample_info->vm_state = isolate->current_vm_state(); | |
124 sample_info->external_callback_entry = nullptr; | |
125 if (sample_info->vm_state == GC) return true; | |
126 | 95 |
127 Address js_entry_sp = isolate->js_entry_sp(); | 96 Address js_entry_sp = isolate->js_entry_sp(); |
128 if (js_entry_sp == 0) return true; // Not executing JS now. | 97 if (js_entry_sp == 0) return; // Not executing JS now. |
129 | 98 |
130 if (regs.pc && IsNoFrameRegion(static_cast<Address>(regs.pc))) { | 99 if (pc && IsNoFrameRegion(pc)) { |
131 // Can't collect stack. | 100 // Can't collect stack. Mark the sample as spoiled. |
132 return false; | 101 timestamp = base::TimeTicks(); |
| 102 pc = 0; |
| 103 return; |
133 } | 104 } |
134 | 105 |
135 ExternalCallbackScope* scope = isolate->external_callback_scope(); | 106 ExternalCallbackScope* scope = isolate->external_callback_scope(); |
136 Address handler = Isolate::handler(isolate->thread_local_top()); | 107 Address handler = Isolate::handler(isolate->thread_local_top()); |
137 // If there is a handler on top of the external callback scope then | 108 // If there is a handler on top of the external callback scope then |
138 // we have already entrered JavaScript again and the external callback | 109 // we have already entrered JavaScript again and the external callback |
139 // is not the top function. | 110 // is not the top function. |
140 if (scope && scope->scope_address() < handler) { | 111 if (scope && scope->scope_address() < handler) { |
141 sample_info->external_callback_entry = | 112 external_callback_entry = *scope->callback_entrypoint_address(); |
142 *scope->callback_entrypoint_address(); | 113 has_external_callback = true; |
| 114 } else { |
| 115 // sp register may point at an arbitrary place in memory, make |
| 116 // sure MSAN doesn't complain about it. |
| 117 MSAN_MEMORY_IS_INITIALIZED(regs.sp, sizeof(Address)); |
| 118 // Sample potential return address value for frameless invocation of |
| 119 // stubs (we'll figure out later, if this value makes sense). |
| 120 tos = Memory::Address_at(reinterpret_cast<Address>(regs.sp)); |
| 121 has_external_callback = false; |
143 } | 122 } |
144 | 123 |
145 SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp), | 124 SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp), |
146 reinterpret_cast<Address>(regs.sp), js_entry_sp); | 125 reinterpret_cast<Address>(regs.sp), js_entry_sp); |
| 126 top_frame_type = it.top_frame_type(); |
| 127 |
| 128 SampleInfo info; |
| 129 GetStackSample(isolate, regs, record_c_entry_frame, |
| 130 reinterpret_cast<void**>(&stack[0]), kMaxFramesCount, &info); |
| 131 frames_count = static_cast<unsigned>(info.frames_count); |
| 132 if (!frames_count) { |
| 133 // It is executing JS but failed to collect a stack trace. |
| 134 // Mark the sample as spoiled. |
| 135 timestamp = base::TimeTicks(); |
| 136 pc = 0; |
| 137 } |
| 138 } |
| 139 |
| 140 |
| 141 void TickSample::GetStackSample(Isolate* isolate, const v8::RegisterState& regs, |
| 142 RecordCEntryFrame record_c_entry_frame, |
| 143 void** frames, size_t frames_limit, |
| 144 v8::SampleInfo* sample_info) { |
| 145 sample_info->frames_count = 0; |
| 146 sample_info->vm_state = isolate->current_vm_state(); |
| 147 if (sample_info->vm_state == GC) return; |
| 148 |
| 149 Address js_entry_sp = isolate->js_entry_sp(); |
| 150 if (js_entry_sp == 0) return; // Not executing JS now. |
| 151 |
| 152 SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp), |
| 153 reinterpret_cast<Address>(regs.sp), js_entry_sp); |
147 size_t i = 0; | 154 size_t i = 0; |
148 if (record_c_entry_frame == kIncludeCEntryFrame && !it.done() && | 155 if (record_c_entry_frame == kIncludeCEntryFrame && !it.done() && |
149 it.top_frame_type() == StackFrame::EXIT) { | 156 it.top_frame_type() == StackFrame::EXIT) { |
150 frames[i++] = isolate->c_function(); | 157 frames[i++] = isolate->c_function(); |
151 } | 158 } |
152 while (!it.done() && i < frames_limit) { | 159 while (!it.done() && i < frames_limit) { |
153 if (it.frame()->is_interpreted()) { | 160 if (it.frame()->is_interpreted()) { |
154 // For interpreted frames use the bytecode array pointer as the pc. | 161 // For interpreted frames use the bytecode array pointer as the pc. |
155 InterpretedFrame* frame = static_cast<InterpretedFrame*>(it.frame()); | 162 InterpretedFrame* frame = static_cast<InterpretedFrame*>(it.frame()); |
156 // Since the sampler can interrupt execution at any point the | 163 // Since the sampler can interrupt execution at any point the |
157 // bytecode_array might be garbage, so don't dereference it. | 164 // bytecode_array might be garbage, so don't dereference it. |
158 Address bytecode_array = | 165 Address bytecode_array = |
159 reinterpret_cast<Address>(frame->GetBytecodeArray()) - kHeapObjectTag; | 166 reinterpret_cast<Address>(frame->GetBytecodeArray()) - kHeapObjectTag; |
160 frames[i++] = bytecode_array + BytecodeArray::kHeaderSize + | 167 frames[i++] = bytecode_array + BytecodeArray::kHeaderSize + |
161 frame->GetBytecodeOffset(); | 168 frame->GetBytecodeOffset(); |
162 } else { | 169 } else { |
163 frames[i++] = it.frame()->pc(); | 170 frames[i++] = it.frame()->pc(); |
164 } | 171 } |
165 it.Advance(); | 172 it.Advance(); |
166 } | 173 } |
167 sample_info->frames_count = i; | 174 sample_info->frames_count = i; |
168 return true; | |
169 } | 175 } |
170 | 176 |
| 177 |
171 #if defined(USE_SIMULATOR) | 178 #if defined(USE_SIMULATOR) |
172 bool SimulatorHelper::FillRegisters(Isolate* isolate, | 179 bool SimulatorHelper::FillRegisters(Isolate* isolate, |
173 v8::RegisterState* state) { | 180 v8::RegisterState* state) { |
174 Simulator *simulator = isolate->thread_local_top()->simulator_; | 181 Simulator *simulator = isolate->thread_local_top()->simulator_; |
175 // Check if there is active simulator. | 182 // Check if there is active simulator. |
176 if (simulator == NULL) return false; | 183 if (simulator == NULL) return false; |
177 #if V8_TARGET_ARCH_ARM | 184 #if V8_TARGET_ARCH_ARM |
178 if (!simulator->has_bad_pc()) { | 185 if (!simulator->has_bad_pc()) { |
179 state->pc = reinterpret_cast<Address>(simulator->get_pc()); | 186 state->pc = reinterpret_cast<Address>(simulator->get_pc()); |
180 } | 187 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 // it is not guaranteed to be atomic even when both host and target | 224 // it is not guaranteed to be atomic even when both host and target |
218 // are of same bitness. | 225 // are of same bitness. |
219 return false; | 226 return false; |
220 } | 227 } |
221 return true; | 228 return true; |
222 } | 229 } |
223 #endif // USE_SIMULATOR | 230 #endif // USE_SIMULATOR |
224 | 231 |
225 } // namespace internal | 232 } // namespace internal |
226 } // namespace v8 | 233 } // namespace v8 |
OLD | NEW |