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 "include/v8-profiler.h" |
7 #include "src/frames-inl.h" | 8 #include "src/frames-inl.h" |
| 9 #include "src/msan.h" |
| 10 #include "src/simulator.h" |
8 #include "src/vm-state-inl.h" | 11 #include "src/vm-state-inl.h" |
9 | 12 |
10 | |
11 namespace v8 { | 13 namespace v8 { |
12 namespace internal { | |
13 | 14 |
14 namespace { | 15 namespace { |
15 | 16 |
16 bool IsSamePage(byte* ptr1, byte* ptr2) { | 17 bool IsSamePage(i::byte* ptr1, i::byte* ptr2) { |
17 const uint32_t kPageSize = 4096; | 18 const uint32_t kPageSize = 4096; |
18 uintptr_t mask = ~static_cast<uintptr_t>(kPageSize - 1); | 19 uintptr_t mask = ~static_cast<uintptr_t>(kPageSize - 1); |
19 return (reinterpret_cast<uintptr_t>(ptr1) & mask) == | 20 return (reinterpret_cast<uintptr_t>(ptr1) & mask) == |
20 (reinterpret_cast<uintptr_t>(ptr2) & mask); | 21 (reinterpret_cast<uintptr_t>(ptr2) & mask); |
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(i::Address address) { |
26 struct Pattern { | 27 struct Pattern { |
27 int bytes_count; | 28 int bytes_count; |
28 byte bytes[8]; | 29 i::byte bytes[8]; |
29 int offsets[4]; | 30 int offsets[4]; |
30 }; | 31 }; |
31 byte* pc = reinterpret_cast<byte*>(address); | 32 i::byte* pc = reinterpret_cast<i::byte*>(address); |
32 static Pattern patterns[] = { | 33 static Pattern patterns[] = { |
33 #if V8_HOST_ARCH_IA32 | 34 #if V8_HOST_ARCH_IA32 |
34 // push %ebp | 35 // push %ebp |
35 // mov %esp,%ebp | 36 // mov %esp,%ebp |
36 {3, {0x55, 0x89, 0xe5}, {0, 1, -1}}, | 37 {3, {0x55, 0x89, 0xe5}, {0, 1, -1}}, |
37 // pop %ebp | 38 // pop %ebp |
38 // ret N | 39 // ret N |
39 {2, {0x5d, 0xc2}, {0, 1, -1}}, | 40 {2, {0x5d, 0xc2}, {0, 1, -1}}, |
40 // pop %ebp | 41 // pop %ebp |
41 // ret | 42 // ret |
(...skipping 30 matching lines...) Expand all Loading... |
72 } | 73 } |
73 } | 74 } |
74 return false; | 75 return false; |
75 } | 76 } |
76 | 77 |
77 } // namespace | 78 } // namespace |
78 | 79 |
79 // | 80 // |
80 // StackTracer implementation | 81 // StackTracer implementation |
81 // | 82 // |
82 DISABLE_ASAN void TickSample::Init(Isolate* isolate, | 83 DISABLE_ASAN void TickSample::Init(Isolate* v8_isolate, |
83 const v8::RegisterState& regs, | 84 const RegisterState& regs, |
84 RecordCEntryFrame record_c_entry_frame, | 85 RecordCEntryFrame record_c_entry_frame, |
85 bool update_stats) { | 86 bool update_stats) { |
86 timestamp = base::TimeTicks::HighResolutionNow(); | |
87 this->update_stats = update_stats; | 87 this->update_stats = update_stats; |
88 | 88 |
89 SampleInfo info; | 89 SampleInfo info; |
90 if (GetStackSample(isolate, regs, record_c_entry_frame, | 90 if (GetStackSample(v8_isolate, const_cast<RegisterState&>(regs), |
91 reinterpret_cast<void**>(&stack[0]), kMaxFramesCount, | 91 record_c_entry_frame, reinterpret_cast<void**>(&stack[0]), |
92 &info)) { | 92 kMaxFramesCount, &info)) { |
93 state = info.vm_state; | 93 state = info.vm_state; |
94 pc = static_cast<Address>(regs.pc); | 94 pc = regs.pc; |
95 frames_count = static_cast<unsigned>(info.frames_count); | 95 frames_count = static_cast<unsigned>(info.frames_count); |
96 has_external_callback = info.external_callback_entry != nullptr; | 96 has_external_callback = info.external_callback_entry != nullptr; |
97 if (has_external_callback) { | 97 if (has_external_callback) { |
98 external_callback_entry = | 98 external_callback_entry = info.external_callback_entry; |
99 static_cast<Address>(info.external_callback_entry); | |
100 } else if (frames_count) { | 99 } else if (frames_count) { |
101 // sp register may point at an arbitrary place in memory, make | 100 // sp register may point at an arbitrary place in memory, make |
102 // sure MSAN doesn't complain about it. | 101 // sure MSAN doesn't complain about it. |
103 MSAN_MEMORY_IS_INITIALIZED(regs.sp, sizeof(Address)); | 102 MSAN_MEMORY_IS_INITIALIZED(regs.sp, sizeof(void*)); |
104 // Sample potential return address value for frameless invocation of | 103 // Sample potential return address value for frameless invocation of |
105 // stubs (we'll figure out later, if this value makes sense). | 104 // stubs (we'll figure out later, if this value makes sense). |
106 tos = Memory::Address_at(reinterpret_cast<Address>(regs.sp)); | 105 tos = i::Memory::Address_at(reinterpret_cast<i::Address>(regs.sp)); |
107 } else { | 106 } else { |
108 tos = nullptr; | 107 tos = nullptr; |
109 } | 108 } |
110 } else { | 109 } else { |
111 // It is executing JS but failed to collect a stack trace. | 110 // It is executing JS but failed to collect a stack trace. |
112 // Mark the sample as spoiled. | 111 // Mark the sample as spoiled. |
113 timestamp = base::TimeTicks(); | |
114 pc = nullptr; | 112 pc = nullptr; |
115 } | 113 } |
116 } | 114 } |
117 | 115 |
118 bool TickSample::GetStackSample(Isolate* isolate, const v8::RegisterState& regs, | 116 bool TickSample::GetStackSample(Isolate* v8_isolate, const RegisterState& regs, |
119 RecordCEntryFrame record_c_entry_frame, | 117 RecordCEntryFrame record_c_entry_frame, |
120 void** frames, size_t frames_limit, | 118 void** frames, size_t frames_limit, |
121 v8::SampleInfo* sample_info) { | 119 v8::SampleInfo* sample_info) { |
| 120 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
122 sample_info->frames_count = 0; | 121 sample_info->frames_count = 0; |
123 sample_info->vm_state = isolate->current_vm_state(); | 122 sample_info->vm_state = isolate->current_vm_state(); |
124 sample_info->external_callback_entry = nullptr; | 123 sample_info->external_callback_entry = nullptr; |
125 if (sample_info->vm_state == GC) return true; | 124 if (sample_info->vm_state == GC) return true; |
126 | 125 |
127 Address js_entry_sp = isolate->js_entry_sp(); | 126 i::Address js_entry_sp = isolate->js_entry_sp(); |
128 if (js_entry_sp == nullptr) return true; // Not executing JS now. | 127 if (js_entry_sp == nullptr) return true; // Not executing JS now. |
129 DCHECK(regs.sp); | 128 DCHECK(regs.sp); |
130 | 129 |
131 if (regs.pc && IsNoFrameRegion(static_cast<Address>(regs.pc))) { | 130 if (regs.pc && IsNoFrameRegion(static_cast<i::Address>(regs.pc))) { |
132 // Can't collect stack. | 131 // Can't collect stack. |
133 return false; | 132 return false; |
134 } | 133 } |
135 | 134 |
136 ExternalCallbackScope* scope = isolate->external_callback_scope(); | 135 i::ExternalCallbackScope* scope = isolate->external_callback_scope(); |
137 Address handler = Isolate::handler(isolate->thread_local_top()); | 136 i::Address handler = i::Isolate::handler(isolate->thread_local_top()); |
138 // If there is a handler on top of the external callback scope then | 137 // If there is a handler on top of the external callback scope then |
139 // we have already entrered JavaScript again and the external callback | 138 // we have already entrered JavaScript again and the external callback |
140 // is not the top function. | 139 // is not the top function. |
141 if (scope && scope->scope_address() < handler) { | 140 if (scope && scope->scope_address() < handler) { |
142 sample_info->external_callback_entry = | 141 sample_info->external_callback_entry = |
143 *scope->callback_entrypoint_address(); | 142 *scope->callback_entrypoint_address(); |
144 } | 143 } |
145 | 144 |
146 SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp), | 145 i::SafeStackFrameIterator it(isolate, reinterpret_cast<i::Address>(regs.fp), |
147 reinterpret_cast<Address>(regs.sp), js_entry_sp); | 146 reinterpret_cast<i::Address>(regs.sp), |
| 147 js_entry_sp); |
148 size_t i = 0; | 148 size_t i = 0; |
149 if (record_c_entry_frame == kIncludeCEntryFrame && !it.done() && | 149 if (record_c_entry_frame == kIncludeCEntryFrame && !it.done() && |
150 (it.top_frame_type() == StackFrame::EXIT || | 150 (it.top_frame_type() == internal::StackFrame::EXIT || |
151 it.top_frame_type() == StackFrame::BUILTIN_EXIT)) { | 151 it.top_frame_type() == internal::StackFrame::BUILTIN_EXIT)) { |
152 frames[i++] = isolate->c_function(); | 152 frames[i++] = isolate->c_function(); |
153 } | 153 } |
154 while (!it.done() && i < frames_limit) { | 154 while (!it.done() && i < frames_limit) { |
155 if (it.frame()->is_interpreted()) { | 155 if (it.frame()->is_interpreted()) { |
156 // For interpreted frames use the bytecode array pointer as the pc. | 156 // For interpreted frames use the bytecode array pointer as the pc. |
157 InterpretedFrame* frame = static_cast<InterpretedFrame*>(it.frame()); | 157 i::InterpretedFrame* frame = |
| 158 static_cast<i::InterpretedFrame*>(it.frame()); |
158 // Since the sampler can interrupt execution at any point the | 159 // Since the sampler can interrupt execution at any point the |
159 // bytecode_array might be garbage, so don't dereference it. | 160 // bytecode_array might be garbage, so don't dereference it. |
160 Address bytecode_array = | 161 i::Address bytecode_array = |
161 reinterpret_cast<Address>(frame->GetBytecodeArray()) - kHeapObjectTag; | 162 reinterpret_cast<i::Address>(frame->GetBytecodeArray()) - |
162 frames[i++] = bytecode_array + BytecodeArray::kHeaderSize + | 163 i::kHeapObjectTag; |
| 164 frames[i++] = bytecode_array + i::BytecodeArray::kHeaderSize + |
163 frame->GetBytecodeOffset(); | 165 frame->GetBytecodeOffset(); |
164 } else { | 166 } else { |
165 frames[i++] = it.frame()->pc(); | 167 frames[i++] = it.frame()->pc(); |
166 } | 168 } |
167 it.Advance(); | 169 it.Advance(); |
168 } | 170 } |
169 sample_info->frames_count = i; | 171 sample_info->frames_count = i; |
170 return true; | 172 return true; |
171 } | 173 } |
172 | 174 |
| 175 namespace internal { |
| 176 |
| 177 void TickSample::Init(Isolate* isolate, const v8::RegisterState& state, |
| 178 RecordCEntryFrame record_c_entry_frame, |
| 179 bool update_stats) { |
| 180 v8::TickSample::Init(reinterpret_cast<v8::Isolate*>(isolate), state, |
| 181 record_c_entry_frame, update_stats); |
| 182 if (pc == nullptr) return; |
| 183 timestamp = base::TimeTicks::HighResolutionNow(); |
| 184 } |
| 185 |
173 #if defined(USE_SIMULATOR) | 186 #if defined(USE_SIMULATOR) |
174 bool SimulatorHelper::FillRegisters(Isolate* isolate, | 187 bool SimulatorHelper::FillRegisters(Isolate* isolate, |
175 v8::RegisterState* state) { | 188 v8::RegisterState* state) { |
176 Simulator *simulator = isolate->thread_local_top()->simulator_; | 189 Simulator* simulator = isolate->thread_local_top()->simulator_; |
177 // Check if there is active simulator. | 190 // Check if there is active simulator. |
178 if (simulator == NULL) return false; | 191 if (simulator == NULL) return false; |
179 #if V8_TARGET_ARCH_ARM | 192 #if V8_TARGET_ARCH_ARM |
180 if (!simulator->has_bad_pc()) { | 193 if (!simulator->has_bad_pc()) { |
181 state->pc = reinterpret_cast<Address>(simulator->get_pc()); | 194 state->pc = reinterpret_cast<Address>(simulator->get_pc()); |
182 } | 195 } |
183 state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp)); | 196 state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp)); |
184 state->fp = reinterpret_cast<Address>(simulator->get_register( | 197 state->fp = |
185 Simulator::r11)); | 198 reinterpret_cast<Address>(simulator->get_register(Simulator::r11)); |
186 #elif V8_TARGET_ARCH_ARM64 | 199 #elif V8_TARGET_ARCH_ARM64 |
187 state->pc = reinterpret_cast<Address>(simulator->pc()); | 200 state->pc = reinterpret_cast<Address>(simulator->pc()); |
188 state->sp = reinterpret_cast<Address>(simulator->sp()); | 201 state->sp = reinterpret_cast<Address>(simulator->sp()); |
189 state->fp = reinterpret_cast<Address>(simulator->fp()); | 202 state->fp = reinterpret_cast<Address>(simulator->fp()); |
190 #elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 | 203 #elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 |
191 if (!simulator->has_bad_pc()) { | 204 if (!simulator->has_bad_pc()) { |
192 state->pc = reinterpret_cast<Address>(simulator->get_pc()); | 205 state->pc = reinterpret_cast<Address>(simulator->get_pc()); |
193 } | 206 } |
194 state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp)); | 207 state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp)); |
195 state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp)); | 208 state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp)); |
(...skipping 23 matching lines...) Expand all Loading... |
219 // it is not guaranteed to be atomic even when both host and target | 232 // it is not guaranteed to be atomic even when both host and target |
220 // are of same bitness. | 233 // are of same bitness. |
221 return false; | 234 return false; |
222 } | 235 } |
223 return true; | 236 return true; |
224 } | 237 } |
225 #endif // USE_SIMULATOR | 238 #endif // USE_SIMULATOR |
226 | 239 |
227 } // namespace internal | 240 } // namespace internal |
228 } // namespace v8 | 241 } // namespace v8 |
OLD | NEW |