Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/api.h" | 5 #include "src/api.h" |
| 6 | 6 |
| 7 #include <string.h> // For memcpy, strlen. | 7 #include <string.h> // For memcpy, strlen. |
| 8 #ifdef V8_USE_ADDRESS_SANITIZER | 8 #ifdef V8_USE_ADDRESS_SANITIZER |
| 9 #include <sanitizer/asan_interface.h> | 9 #include <sanitizer/asan_interface.h> |
| 10 #endif // V8_USE_ADDRESS_SANITIZER | 10 #endif // V8_USE_ADDRESS_SANITIZER |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 29 #include "src/char-predicates-inl.h" | 29 #include "src/char-predicates-inl.h" |
| 30 #include "src/code-stubs.h" | 30 #include "src/code-stubs.h" |
| 31 #include "src/compiler.h" | 31 #include "src/compiler.h" |
| 32 #include "src/context-measure.h" | 32 #include "src/context-measure.h" |
| 33 #include "src/contexts.h" | 33 #include "src/contexts.h" |
| 34 #include "src/conversions-inl.h" | 34 #include "src/conversions-inl.h" |
| 35 #include "src/counters.h" | 35 #include "src/counters.h" |
| 36 #include "src/debug/debug.h" | 36 #include "src/debug/debug.h" |
| 37 #include "src/deoptimizer.h" | 37 #include "src/deoptimizer.h" |
| 38 #include "src/execution.h" | 38 #include "src/execution.h" |
| 39 #include "src/frames-inl.h" | |
| 39 #include "src/gdb-jit.h" | 40 #include "src/gdb-jit.h" |
| 40 #include "src/global-handles.h" | 41 #include "src/global-handles.h" |
| 41 #include "src/icu_util.h" | 42 #include "src/icu_util.h" |
| 42 #include "src/isolate-inl.h" | 43 #include "src/isolate-inl.h" |
| 43 #include "src/json-parser.h" | 44 #include "src/json-parser.h" |
| 44 #include "src/json-stringifier.h" | 45 #include "src/json-stringifier.h" |
| 45 #include "src/messages.h" | 46 #include "src/messages.h" |
| 46 #include "src/parsing/parser.h" | 47 #include "src/parsing/parser.h" |
| 47 #include "src/parsing/scanner-character-streams.h" | 48 #include "src/parsing/scanner-character-streams.h" |
| 48 #include "src/pending-compilation-error-handler.h" | 49 #include "src/pending-compilation-error-handler.h" |
| 49 #include "src/profiler/cpu-profiler.h" | 50 #include "src/profiler/cpu-profiler.h" |
| 50 #include "src/profiler/heap-profiler.h" | 51 #include "src/profiler/heap-profiler.h" |
| 51 #include "src/profiler/heap-snapshot-generator-inl.h" | 52 #include "src/profiler/heap-snapshot-generator-inl.h" |
| 52 #include "src/profiler/profile-generator-inl.h" | 53 #include "src/profiler/profile-generator-inl.h" |
| 53 #include "src/profiler/tick-sample.h" | 54 #include "src/profiler/simulator-helper.h" |
| 54 #include "src/property-descriptor.h" | 55 #include "src/property-descriptor.h" |
| 55 #include "src/property-details.h" | 56 #include "src/property-details.h" |
| 56 #include "src/property.h" | 57 #include "src/property.h" |
| 57 #include "src/prototype.h" | 58 #include "src/prototype.h" |
| 58 #include "src/runtime-profiler.h" | 59 #include "src/runtime-profiler.h" |
| 59 #include "src/runtime/runtime.h" | 60 #include "src/runtime/runtime.h" |
| 60 #include "src/simulator.h" | 61 #include "src/simulator.h" |
| 61 #include "src/snapshot/natives.h" | 62 #include "src/snapshot/natives.h" |
| 62 #include "src/snapshot/snapshot.h" | 63 #include "src/snapshot/snapshot.h" |
| 63 #include "src/startup-data-util.h" | 64 #include "src/startup-data-util.h" |
| (...skipping 7493 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7557 isolate->heap()->CollectCodeStatistics(); | 7558 isolate->heap()->CollectCodeStatistics(); |
| 7558 | 7559 |
| 7559 code_statistics->code_and_metadata_size_ = isolate->code_and_metadata_size(); | 7560 code_statistics->code_and_metadata_size_ = isolate->code_and_metadata_size(); |
| 7560 code_statistics->bytecode_and_metadata_size_ = | 7561 code_statistics->bytecode_and_metadata_size_ = |
| 7561 isolate->bytecode_and_metadata_size(); | 7562 isolate->bytecode_and_metadata_size(); |
| 7562 return true; | 7563 return true; |
| 7563 } | 7564 } |
| 7564 | 7565 |
| 7565 void Isolate::GetStackSample(const RegisterState& state, void** frames, | 7566 void Isolate::GetStackSample(const RegisterState& state, void** frames, |
| 7566 size_t frames_limit, SampleInfo* sample_info) { | 7567 size_t frames_limit, SampleInfo* sample_info) { |
| 7568 #if defined(USE_SIMULATOR) | |
| 7567 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); | 7569 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); |
| 7568 #if defined(USE_SIMULATOR) | |
| 7569 RegisterState regs; | 7570 RegisterState regs; |
| 7570 regs.pc = state.pc; | 7571 regs.pc = state.pc; |
| 7571 regs.sp = state.sp; | 7572 regs.sp = state.sp; |
| 7572 regs.fp = state.fp; | 7573 regs.fp = state.fp; |
| 7573 if (!i::SimulatorHelper::FillRegisters(isolate, ®s)) { | 7574 if (!i::SimulatorHelper::FillRegisters(isolate, ®s)) { |
| 7574 sample_info->frames_count = 0; | 7575 sample_info->frames_count = 0; |
| 7575 sample_info->vm_state = OTHER; | 7576 sample_info->vm_state = OTHER; |
| 7576 sample_info->external_callback_entry = nullptr; | 7577 sample_info->external_callback_entry = nullptr; |
| 7577 return; | 7578 return; |
| 7578 } | 7579 } |
| 7579 #else | 7580 #else |
| 7580 const RegisterState& regs = state; | 7581 const RegisterState& regs = state; |
| 7581 #endif | 7582 #endif |
| 7582 i::TickSample::GetStackSample(isolate, regs, i::TickSample::kSkipCEntryFrame, | 7583 TickSample::GetStackSample(this, regs, TickSample::kSkipCEntryFrame, frames, |
| 7583 frames, frames_limit, sample_info); | 7584 frames_limit, sample_info); |
| 7584 } | 7585 } |
| 7585 | 7586 |
| 7586 size_t Isolate::NumberOfPhantomHandleResetsSinceLastCall() { | 7587 size_t Isolate::NumberOfPhantomHandleResetsSinceLastCall() { |
| 7587 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); | 7588 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); |
| 7588 size_t result = isolate->global_handles()->NumberOfPhantomHandleResets(); | 7589 size_t result = isolate->global_handles()->NumberOfPhantomHandleResets(); |
| 7589 isolate->global_handles()->ResetNumberOfPhantomHandleResets(); | 7590 isolate->global_handles()->ResetNumberOfPhantomHandleResets(); |
| 7590 return result; | 7591 return result; |
| 7591 } | 7592 } |
| 7592 | 7593 |
| 7593 void Isolate::SetEventLogger(LogEventCallback that) { | 7594 void Isolate::SetEventLogger(LogEventCallback that) { |
| (...skipping 658 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8252 Local<Value> value) { | 8253 Local<Value> value) { |
| 8253 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); | 8254 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| 8254 ENTER_V8(isolate); | 8255 ENTER_V8(isolate); |
| 8255 i::Handle<i::Object> val = Utils::OpenHandle(*value); | 8256 i::Handle<i::Object> val = Utils::OpenHandle(*value); |
| 8256 i::Handle<i::JSArray> result; | 8257 i::Handle<i::JSArray> result; |
| 8257 if (!i::Runtime::GetInternalProperties(isolate, val).ToHandle(&result)) | 8258 if (!i::Runtime::GetInternalProperties(isolate, val).ToHandle(&result)) |
| 8258 return MaybeLocal<Array>(); | 8259 return MaybeLocal<Array>(); |
| 8259 return Utils::ToLocal(result); | 8260 return Utils::ToLocal(result); |
| 8260 } | 8261 } |
| 8261 | 8262 |
| 8263 namespace { | |
| 8264 | |
| 8265 bool IsSamePage(i::byte* ptr1, i::byte* ptr2) { | |
| 8266 const uint32_t kPageSize = 4096; | |
| 8267 uintptr_t mask = ~static_cast<uintptr_t>(kPageSize - 1); | |
| 8268 return (reinterpret_cast<uintptr_t>(ptr1) & mask) == | |
| 8269 (reinterpret_cast<uintptr_t>(ptr2) & mask); | |
| 8270 } | |
| 8271 | |
| 8272 // Check if the code at specified address could potentially be a | |
| 8273 // frame setup code. | |
| 8274 bool IsNoFrameRegion(i::Address address) { | |
| 8275 struct Pattern { | |
| 8276 int bytes_count; | |
| 8277 i::byte bytes[8]; | |
| 8278 int offsets[4]; | |
| 8279 }; | |
| 8280 i::byte* pc = reinterpret_cast<i::byte*>(address); | |
| 8281 static Pattern patterns[] = { | |
| 8282 #if V8_HOST_ARCH_IA32 | |
| 8283 // push %ebp | |
| 8284 // mov %esp,%ebp | |
| 8285 {3, {0x55, 0x89, 0xe5}, {0, 1, -1}}, | |
| 8286 // pop %ebp | |
| 8287 // ret N | |
| 8288 {2, {0x5d, 0xc2}, {0, 1, -1}}, | |
| 8289 // pop %ebp | |
| 8290 // ret | |
| 8291 {2, {0x5d, 0xc3}, {0, 1, -1}}, | |
| 8292 #elif V8_HOST_ARCH_X64 | |
| 8293 // pushq %rbp | |
| 8294 // movq %rsp,%rbp | |
| 8295 {4, {0x55, 0x48, 0x89, 0xe5}, {0, 1, -1}}, | |
| 8296 // popq %rbp | |
| 8297 // ret N | |
| 8298 {2, {0x5d, 0xc2}, {0, 1, -1}}, | |
| 8299 // popq %rbp | |
| 8300 // ret | |
| 8301 {2, {0x5d, 0xc3}, {0, 1, -1}}, | |
| 8302 #endif | |
| 8303 {0, {}, {}} | |
| 8304 }; | |
| 8305 for (Pattern* pattern = patterns; pattern->bytes_count; ++pattern) { | |
| 8306 for (int* offset_ptr = pattern->offsets; *offset_ptr != -1; ++offset_ptr) { | |
| 8307 int offset = *offset_ptr; | |
| 8308 if (!offset || IsSamePage(pc, pc - offset)) { | |
| 8309 MSAN_MEMORY_IS_INITIALIZED(pc - offset, pattern->bytes_count); | |
| 8310 if (!memcmp(pc - offset, pattern->bytes, pattern->bytes_count)) | |
| 8311 return true; | |
| 8312 } else { | |
| 8313 // It is not safe to examine bytes on another page as it might not be | |
| 8314 // allocated thus causing a SEGFAULT. | |
| 8315 // Check the pattern part that's on the same page and | |
| 8316 // pessimistically assume it could be the entire pattern match. | |
| 8317 MSAN_MEMORY_IS_INITIALIZED(pc, pattern->bytes_count - offset); | |
| 8318 if (!memcmp(pc, pattern->bytes + offset, pattern->bytes_count - offset)) | |
| 8319 return true; | |
| 8320 } | |
| 8321 } | |
| 8322 } | |
| 8323 return false; | |
| 8324 } | |
| 8325 | |
| 8326 } // namespace | |
| 8327 | |
| 8328 // | |
| 8329 // StackTracer implementation | |
| 8330 // | |
| 8331 DISABLE_ASAN void TickSample::Init(Isolate* v8_isolate, | |
|
alph
2016/06/28 22:09:01
Don't move that much logic into api.cc
Keep it in
lpy
2016/06/28 23:02:53
Done.
| |
| 8332 const RegisterState& regs, | |
| 8333 RecordCEntryFrame record_c_entry_frame, | |
| 8334 bool update_stats) { | |
| 8335 this->update_stats = update_stats; | |
| 8336 | |
| 8337 SampleInfo info; | |
| 8338 if (GetStackSample(v8_isolate, const_cast<RegisterState&>(regs), | |
| 8339 record_c_entry_frame, reinterpret_cast<void**>(&stack[0]), | |
| 8340 kMaxFramesCount, &info)) { | |
| 8341 state = info.vm_state; | |
| 8342 pc = regs.pc; | |
| 8343 frames_count = static_cast<unsigned>(info.frames_count); | |
| 8344 has_external_callback = info.external_callback_entry != nullptr; | |
| 8345 if (has_external_callback) { | |
| 8346 external_callback_entry = info.external_callback_entry; | |
| 8347 } else if (frames_count) { | |
| 8348 // sp register may point at an arbitrary place in memory, make | |
| 8349 // sure MSAN doesn't complain about it. | |
| 8350 MSAN_MEMORY_IS_INITIALIZED(regs.sp, sizeof(void*)); | |
| 8351 // Sample potential return address value for frameless invocation of | |
| 8352 // stubs (we'll figure out later, if this value makes sense). | |
| 8353 tos = i::Memory::Address_at(reinterpret_cast<i::Address>(regs.sp)); | |
| 8354 } else { | |
| 8355 tos = nullptr; | |
| 8356 } | |
| 8357 } else { | |
| 8358 // It is executing JS but failed to collect a stack trace. | |
| 8359 // Mark the sample as spoiled. | |
| 8360 pc = nullptr; | |
| 8361 } | |
| 8362 } | |
| 8363 | |
| 8364 bool TickSample::GetStackSample(Isolate* v8_isolate, const RegisterState& regs, | |
| 8365 RecordCEntryFrame record_c_entry_frame, | |
| 8366 void** frames, size_t frames_limit, | |
| 8367 v8::SampleInfo* sample_info) { | |
| 8368 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); | |
| 8369 sample_info->frames_count = 0; | |
| 8370 sample_info->vm_state = isolate->current_vm_state(); | |
| 8371 sample_info->external_callback_entry = nullptr; | |
| 8372 if (sample_info->vm_state == GC) return true; | |
| 8373 | |
| 8374 i::Address js_entry_sp = isolate->js_entry_sp(); | |
| 8375 if (js_entry_sp == nullptr) return true; // Not executing JS now. | |
| 8376 DCHECK(regs.sp); | |
| 8377 | |
| 8378 if (regs.pc && IsNoFrameRegion(static_cast<i::Address>(regs.pc))) { | |
| 8379 // Can't collect stack. | |
| 8380 return false; | |
| 8381 } | |
| 8382 | |
| 8383 i::ExternalCallbackScope* scope = isolate->external_callback_scope(); | |
| 8384 i::Address handler = i::Isolate::handler(isolate->thread_local_top()); | |
| 8385 // If there is a handler on top of the external callback scope then | |
| 8386 // we have already entrered JavaScript again and the external callback | |
| 8387 // is not the top function. | |
| 8388 if (scope && scope->scope_address() < handler) { | |
| 8389 sample_info->external_callback_entry = | |
| 8390 *scope->callback_entrypoint_address(); | |
| 8391 } | |
| 8392 | |
| 8393 i::SafeStackFrameIterator it(isolate, reinterpret_cast<i::Address>(regs.fp), | |
| 8394 reinterpret_cast<i::Address>(regs.sp), | |
| 8395 js_entry_sp); | |
| 8396 size_t i = 0; | |
| 8397 if (record_c_entry_frame == kIncludeCEntryFrame && !it.done() && | |
| 8398 it.top_frame_type() == i::StackFrame::EXIT) { | |
| 8399 frames[i++] = isolate->c_function(); | |
| 8400 } | |
| 8401 while (!it.done() && i < frames_limit) { | |
| 8402 if (it.frame()->is_interpreted()) { | |
| 8403 // For interpreted frames use the bytecode array pointer as the pc. | |
| 8404 i::InterpretedFrame* frame = | |
| 8405 static_cast<i::InterpretedFrame*>(it.frame()); | |
| 8406 // Since the sampler can interrupt execution at any point the | |
| 8407 // bytecode_array might be garbage, so don't dereference it. | |
| 8408 i::Address bytecode_array = | |
| 8409 reinterpret_cast<i::Address>(frame->GetBytecodeArray()) - | |
| 8410 i::kHeapObjectTag; | |
| 8411 frames[i++] = bytecode_array + i::BytecodeArray::kHeaderSize + | |
| 8412 frame->GetBytecodeOffset(); | |
| 8413 } else { | |
| 8414 frames[i++] = it.frame()->pc(); | |
| 8415 } | |
| 8416 it.Advance(); | |
| 8417 } | |
| 8418 sample_info->frames_count = i; | |
| 8419 return true; | |
| 8420 } | |
| 8262 | 8421 |
| 8263 Local<String> CpuProfileNode::GetFunctionName() const { | 8422 Local<String> CpuProfileNode::GetFunctionName() const { |
| 8264 const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this); | 8423 const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this); |
| 8265 i::Isolate* isolate = node->isolate(); | 8424 i::Isolate* isolate = node->isolate(); |
| 8266 const i::CodeEntry* entry = node->entry(); | 8425 const i::CodeEntry* entry = node->entry(); |
| 8267 i::Handle<i::String> name = | 8426 i::Handle<i::String> name = |
| 8268 isolate->factory()->InternalizeUtf8String(entry->name()); | 8427 isolate->factory()->InternalizeUtf8String(entry->name()); |
| 8269 if (!entry->has_name_prefix()) { | 8428 if (!entry->has_name_prefix()) { |
| 8270 return ToApiHandle<String>(name); | 8429 return ToApiHandle<String>(name); |
| 8271 } else { | 8430 } else { |
| (...skipping 652 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8924 Address callback_address = | 9083 Address callback_address = |
| 8925 reinterpret_cast<Address>(reinterpret_cast<intptr_t>(callback)); | 9084 reinterpret_cast<Address>(reinterpret_cast<intptr_t>(callback)); |
| 8926 VMState<EXTERNAL> state(isolate); | 9085 VMState<EXTERNAL> state(isolate); |
| 8927 ExternalCallbackScope call_scope(isolate, callback_address); | 9086 ExternalCallbackScope call_scope(isolate, callback_address); |
| 8928 callback(info); | 9087 callback(info); |
| 8929 } | 9088 } |
| 8930 | 9089 |
| 8931 | 9090 |
| 8932 } // namespace internal | 9091 } // namespace internal |
| 8933 } // namespace v8 | 9092 } // namespace v8 |
| OLD | NEW |