diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/v8/src/execution/isolate.cc | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-85-based.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/v8/src/execution/isolate.cc')
-rw-r--r-- | chromium/v8/src/execution/isolate.cc | 315 |
1 files changed, 195 insertions, 120 deletions
diff --git a/chromium/v8/src/execution/isolate.cc b/chromium/v8/src/execution/isolate.cc index bea08a16b83..98b98d5bea7 100644 --- a/chromium/v8/src/execution/isolate.cc +++ b/chromium/v8/src/execution/isolate.cc @@ -32,6 +32,7 @@ #include "src/debug/debug-frames.h" #include "src/debug/debug.h" #include "src/deoptimizer/deoptimizer.h" +#include "src/diagnostics/basic-block-profiler.h" #include "src/diagnostics/compilation-statistics.h" #include "src/execution/frames-inl.h" #include "src/execution/isolate-inl.h" @@ -588,21 +589,28 @@ class FrameArrayBuilder { offset, flags, parameters); } - void AppendPromiseAllFrame(Handle<Context> context, int offset) { + void AppendPromiseCombinatorFrame(Handle<JSFunction> element_function, + Handle<JSFunction> combinator, + FrameArray::Flag combinator_flag, + Handle<Context> context) { if (full()) return; - int flags = FrameArray::kIsAsync | FrameArray::kIsPromiseAll; + int flags = FrameArray::kIsAsync | combinator_flag; Handle<Context> native_context(context->native_context(), isolate_); - Handle<JSFunction> function(native_context->promise_all(), isolate_); - if (!IsVisibleInStackTrace(function)) return; + if (!IsVisibleInStackTrace(combinator)) return; Handle<Object> receiver(native_context->promise_function(), isolate_); - Handle<AbstractCode> code(AbstractCode::cast(function->code()), isolate_); + Handle<AbstractCode> code(AbstractCode::cast(combinator->code()), isolate_); - // TODO(mmarchini) save Promises list from Promise.all() + // TODO(mmarchini) save Promises list from the Promise combinator Handle<FixedArray> parameters = isolate_->factory()->empty_fixed_array(); - elements_ = FrameArray::AppendJSFrame(elements_, receiver, function, code, + // We store the offset of the promise into the element function's + // hash field for element callbacks. + int const offset = + Smi::ToInt(Smi::cast(element_function->GetIdentityHash())) - 1; + + elements_ = FrameArray::AppendJSFrame(elements_, receiver, combinator, code, offset, flags, parameters); } @@ -861,11 +869,10 @@ void CaptureAsyncStackTrace(Isolate* isolate, Handle<JSPromise> promise, Handle<JSFunction> function(JSFunction::cast(reaction->fulfill_handler()), isolate); Handle<Context> context(function->context(), isolate); - - // We store the offset of the promise into the {function}'s - // hash field for promise resolve element callbacks. - int const offset = Smi::ToInt(Smi::cast(function->GetIdentityHash())) - 1; - builder->AppendPromiseAllFrame(context, offset); + Handle<JSFunction> combinator(context->native_context().promise_all(), + isolate); + builder->AppendPromiseCombinatorFrame(function, combinator, + FrameArray::kIsPromiseAll, context); // Now peak into the Promise.all() resolve element context to // find the promise capability that's being resolved when all @@ -876,6 +883,24 @@ void CaptureAsyncStackTrace(Isolate* isolate, Handle<JSPromise> promise, PromiseCapability::cast(context->get(index)), isolate); if (!capability->promise().IsJSPromise()) return; promise = handle(JSPromise::cast(capability->promise()), isolate); + } else if (IsBuiltinFunction(isolate, reaction->reject_handler(), + Builtins::kPromiseAnyRejectElementClosure)) { + Handle<JSFunction> function(JSFunction::cast(reaction->reject_handler()), + isolate); + Handle<Context> context(function->context(), isolate); + Handle<JSFunction> combinator(context->native_context().promise_any(), + isolate); + builder->AppendPromiseCombinatorFrame(function, combinator, + FrameArray::kIsPromiseAny, context); + + // Now peak into the Promise.any() reject element context to + // find the promise capability that's being resolved when any of + // the concurrent promises resolve. + int const index = PromiseBuiltins::kPromiseAnyRejectElementCapabilitySlot; + Handle<PromiseCapability> capability( + PromiseCapability::cast(context->get(index)), isolate); + if (!capability->promise().IsJSPromise()) return; + promise = handle(JSPromise::cast(capability->promise()), isolate); } else if (IsBuiltinFunction(isolate, reaction->fulfill_handler(), Builtins::kPromiseCapabilityDefaultResolve)) { Handle<JSFunction> function(JSFunction::cast(reaction->fulfill_handler()), @@ -2491,6 +2516,10 @@ void Isolate::SetCaptureStackTraceForUncaughtExceptions( stack_trace_for_uncaught_exceptions_options_ = options; } +bool Isolate::get_capture_stack_trace_for_uncaught_exceptions() const { + return capture_stack_trace_for_uncaught_exceptions_; +} + void Isolate::SetAbortOnUncaughtExceptionCallback( v8::Isolate::AbortOnUncaughtExceptionCallback callback) { abort_on_uncaught_exception_callback_ = callback; @@ -2632,77 +2661,110 @@ void Isolate::ThreadDataTable::RemoveAllThreads() { table_.clear(); } -class VerboseAccountingAllocator : public AccountingAllocator { +class TracingAccountingAllocator : public AccountingAllocator { public: - VerboseAccountingAllocator(Heap* heap, size_t allocation_sample_bytes) - : heap_(heap), allocation_sample_bytes_(allocation_sample_bytes) {} + explicit TracingAccountingAllocator(Isolate* isolate) : isolate_(isolate) {} - v8::internal::Segment* AllocateSegment(size_t size) override { - v8::internal::Segment* memory = AccountingAllocator::AllocateSegment(size); - if (!memory) return nullptr; - size_t malloced_current = GetCurrentMemoryUsage(); + protected: + void TraceAllocateSegmentImpl(v8::internal::Segment* segment) override { + base::MutexGuard lock(&mutex_); + UpdateMemoryTrafficAndReportMemoryUsage(segment->total_size()); + } - if (last_memory_usage_ + allocation_sample_bytes_ < malloced_current) { - PrintMemoryJSON(malloced_current); - last_memory_usage_ = malloced_current; - } - return memory; + void TraceZoneCreationImpl(const Zone* zone) override { + base::MutexGuard lock(&mutex_); + active_zones_.insert(zone); + nesting_depth_++; } - void ReturnSegment(v8::internal::Segment* memory) override { - AccountingAllocator::ReturnSegment(memory); - size_t malloced_current = GetCurrentMemoryUsage(); + void TraceZoneDestructionImpl(const Zone* zone) override { + base::MutexGuard lock(&mutex_); + UpdateMemoryTrafficAndReportMemoryUsage(zone->segment_bytes_allocated()); + active_zones_.erase(zone); + nesting_depth_--; + } - if (malloced_current + allocation_sample_bytes_ < last_memory_usage_) { - PrintMemoryJSON(malloced_current); - last_memory_usage_ = malloced_current; + private: + void UpdateMemoryTrafficAndReportMemoryUsage(size_t memory_traffic_delta) { + memory_traffic_since_last_report_ += memory_traffic_delta; + if (memory_traffic_since_last_report_ < FLAG_zone_stats_tolerance) return; + memory_traffic_since_last_report_ = 0; + + Dump(buffer_, true); + + { + std::string trace_str = buffer_.str(); + + if (FLAG_trace_zone_stats) { + PrintF( + "{" + "\"type\": \"v8-zone-trace\", " + "\"stats\": %s" + "}\n", + trace_str.c_str()); + } + if (V8_UNLIKELY( + TracingFlags::zone_stats.load(std::memory_order_relaxed) & + v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) { + TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.zone_stats"), + "V8.Zone_Stats", TRACE_EVENT_SCOPE_THREAD, "stats", + TRACE_STR_COPY(trace_str.c_str())); + } } - } - void ZoneCreation(const Zone* zone) override { - PrintZoneModificationSample(zone, "zonecreation"); - nesting_deepth_++; + // Clear the buffer. + buffer_.str(std::string()); } - void ZoneDestruction(const Zone* zone) override { - nesting_deepth_--; - PrintZoneModificationSample(zone, "zonedestruction"); + void Dump(std::ostringstream& out, bool dump_details) { + // Note: Neither isolate nor zones are locked, so be careful with accesses + // as the allocator is potentially used on a concurrent thread. + double time = isolate_->time_millis_since_init(); + out << "{" + << "\"isolate\": \"" << reinterpret_cast<void*>(isolate_) << "\", " + << "\"time\": " << time << ", "; + size_t total_segment_bytes_allocated = 0; + size_t total_zone_allocation_size = 0; + + if (dump_details) { + // Print detailed zone stats if memory usage changes direction. + out << "\"zones\": ["; + bool first = true; + for (const Zone* zone : active_zones_) { + size_t zone_segment_bytes_allocated = zone->segment_bytes_allocated(); + size_t zone_allocation_size = zone->allocation_size_for_tracing(); + if (first) { + first = false; + } else { + out << ", "; + } + out << "{" + << "\"name\": \"" << zone->name() << "\", " + << "\"allocated\": " << zone_segment_bytes_allocated << ", " + << "\"used\": " << zone_allocation_size << "}"; + total_segment_bytes_allocated += zone_segment_bytes_allocated; + total_zone_allocation_size += zone_allocation_size; + } + out << "], "; + } else { + // Just calculate total allocated/used memory values. + for (const Zone* zone : active_zones_) { + total_segment_bytes_allocated += zone->segment_bytes_allocated(); + total_zone_allocation_size += zone->allocation_size_for_tracing(); + } + } + out << "\"allocated\": " << total_segment_bytes_allocated << ", " + << "\"used\": " << total_zone_allocation_size << "}"; } - private: - void PrintZoneModificationSample(const Zone* zone, const char* type) { - PrintF( - "{" - "\"type\": \"%s\", " - "\"isolate\": \"%p\", " - "\"time\": %f, " - "\"ptr\": \"%p\", " - "\"name\": \"%s\", " - "\"size\": %zu," - "\"nesting\": %zu}\n", - type, reinterpret_cast<void*>(heap_->isolate()), - heap_->isolate()->time_millis_since_init(), - reinterpret_cast<const void*>(zone), zone->name(), - zone->allocation_size(), nesting_deepth_.load()); - } - - void PrintMemoryJSON(size_t malloced) { - // Note: Neither isolate, nor heap is locked, so be careful with accesses - // as the allocator is potentially used on a concurrent thread. - double time = heap_->isolate()->time_millis_since_init(); - PrintF( - "{" - "\"type\": \"zone\", " - "\"isolate\": \"%p\", " - "\"time\": %f, " - "\"allocated\": %zu}\n", - reinterpret_cast<void*>(heap_->isolate()), time, malloced); - } - - Heap* heap_; - std::atomic<size_t> last_memory_usage_{0}; - std::atomic<size_t> nesting_deepth_{0}; - size_t allocation_sample_bytes_; + Isolate* const isolate_; + std::atomic<size_t> nesting_depth_{0}; + + base::Mutex mutex_; + std::unordered_set<const Zone*> active_zones_; + std::ostringstream buffer_; + // This value is increased on both allocations and deallocations. + size_t memory_traffic_since_last_report_ = 0; }; #ifdef DEBUG @@ -2781,9 +2843,7 @@ Isolate::Isolate(std::unique_ptr<i::IsolateAllocator> isolate_allocator) : isolate_data_(this), isolate_allocator_(std::move(isolate_allocator)), id_(isolate_counter.fetch_add(1, std::memory_order_relaxed)), - allocator_(FLAG_trace_zone_stats - ? new VerboseAccountingAllocator(&heap_, 256 * KB) - : new AccountingAllocator()), + allocator_(new TracingAccountingAllocator(this)), builtins_(this), rail_mode_(PERFORMANCE_ANIMATION), code_event_dispatcher_(new CodeEventDispatcher()), @@ -3235,15 +3295,15 @@ void Isolate::AddCrashKeysForIsolateAndHeapPointers() { AddressToString(isolate_address)); const uintptr_t ro_space_firstpage_address = - reinterpret_cast<uintptr_t>(heap()->read_only_space()->first_page()); + heap()->read_only_space()->FirstPageAddress(); add_crash_key_callback_(v8::CrashKeyId::kReadonlySpaceFirstPageAddress, AddressToString(ro_space_firstpage_address)); const uintptr_t map_space_firstpage_address = - reinterpret_cast<uintptr_t>(heap()->map_space()->first_page()); + heap()->map_space()->FirstPageAddress(); add_crash_key_callback_(v8::CrashKeyId::kMapSpaceFirstPageAddress, AddressToString(map_space_firstpage_address)); const uintptr_t code_space_firstpage_address = - reinterpret_cast<uintptr_t>(heap()->code_space()->first_page()); + heap()->code_space()->FirstPageAddress(); add_crash_key_callback_(v8::CrashKeyId::kCodeSpaceFirstPageAddress, AddressToString(code_space_firstpage_address)); } @@ -3616,6 +3676,11 @@ void Isolate::DumpAndResetStats() { counters()->runtime_call_stats()->Print(); counters()->runtime_call_stats()->Reset(); } + if (BasicBlockProfiler::Get()->HasData(this)) { + StdoutStream out; + BasicBlockProfiler::Get()->Print(out, this); + BasicBlockProfiler::Get()->ResetCounts(this); + } } void Isolate::AbortConcurrentOptimization(BlockingBehavior behavior) { @@ -4081,54 +4146,57 @@ void Isolate::RunPromiseHook(PromiseHookType type, Handle<JSPromise> promise, void Isolate::RunPromiseHookForAsyncEventDelegate(PromiseHookType type, Handle<JSPromise> promise) { if (!async_event_delegate_) return; - if (type == PromiseHookType::kResolve) return; - - if (type == PromiseHookType::kBefore) { - if (!promise->async_task_id()) return; - async_event_delegate_->AsyncEventOccurred(debug::kDebugWillHandle, - promise->async_task_id(), false); - } else if (type == PromiseHookType::kAfter) { - if (!promise->async_task_id()) return; - async_event_delegate_->AsyncEventOccurred(debug::kDebugDidHandle, - promise->async_task_id(), false); - } else { - DCHECK(type == PromiseHookType::kInit); - debug::DebugAsyncActionType type = debug::kDebugPromiseThen; - bool last_frame_was_promise_builtin = false; - JavaScriptFrameIterator it(this); - while (!it.done()) { - std::vector<Handle<SharedFunctionInfo>> infos; - it.frame()->GetFunctions(&infos); - for (size_t i = 1; i <= infos.size(); ++i) { - Handle<SharedFunctionInfo> info = infos[infos.size() - i]; - if (info->IsUserJavaScript()) { - // We should not report PromiseThen and PromiseCatch which is called - // indirectly, e.g. Promise.all calls Promise.then internally. - if (last_frame_was_promise_builtin) { - if (!promise->async_task_id()) { - promise->set_async_task_id(++async_task_count_); + switch (type) { + case PromiseHookType::kResolve: + return; + case PromiseHookType::kBefore: + if (!promise->async_task_id()) return; + async_event_delegate_->AsyncEventOccurred( + debug::kDebugWillHandle, promise->async_task_id(), false); + break; + case PromiseHookType::kAfter: + if (!promise->async_task_id()) return; + async_event_delegate_->AsyncEventOccurred( + debug::kDebugDidHandle, promise->async_task_id(), false); + break; + case PromiseHookType::kInit: + debug::DebugAsyncActionType type = debug::kDebugPromiseThen; + bool last_frame_was_promise_builtin = false; + JavaScriptFrameIterator it(this); + while (!it.done()) { + std::vector<Handle<SharedFunctionInfo>> infos; + it.frame()->GetFunctions(&infos); + for (size_t i = 1; i <= infos.size(); ++i) { + Handle<SharedFunctionInfo> info = infos[infos.size() - i]; + if (info->IsUserJavaScript()) { + // We should not report PromiseThen and PromiseCatch which is called + // indirectly, e.g. Promise.all calls Promise.then internally. + if (last_frame_was_promise_builtin) { + if (!promise->async_task_id()) { + promise->set_async_task_id(++async_task_count_); + } + async_event_delegate_->AsyncEventOccurred( + type, promise->async_task_id(), debug()->IsBlackboxed(info)); } - async_event_delegate_->AsyncEventOccurred( - type, promise->async_task_id(), debug()->IsBlackboxed(info)); + return; } - return; - } - last_frame_was_promise_builtin = false; - if (info->HasBuiltinId()) { - if (info->builtin_id() == Builtins::kPromisePrototypeThen) { - type = debug::kDebugPromiseThen; - last_frame_was_promise_builtin = true; - } else if (info->builtin_id() == Builtins::kPromisePrototypeCatch) { - type = debug::kDebugPromiseCatch; - last_frame_was_promise_builtin = true; - } else if (info->builtin_id() == Builtins::kPromisePrototypeFinally) { - type = debug::kDebugPromiseFinally; - last_frame_was_promise_builtin = true; + last_frame_was_promise_builtin = false; + if (info->HasBuiltinId()) { + if (info->builtin_id() == Builtins::kPromisePrototypeThen) { + type = debug::kDebugPromiseThen; + last_frame_was_promise_builtin = true; + } else if (info->builtin_id() == Builtins::kPromisePrototypeCatch) { + type = debug::kDebugPromiseCatch; + last_frame_was_promise_builtin = true; + } else if (info->builtin_id() == + Builtins::kPromisePrototypeFinally) { + type = debug::kDebugPromiseFinally; + last_frame_was_promise_builtin = true; + } } } + it.Advance(); } - it.Advance(); - } } } @@ -4180,6 +4248,13 @@ void Isolate::CountUsage(v8::Isolate::UseCounterFeature feature) { int Isolate::GetNextScriptId() { return heap()->NextScriptId(); } +int Isolate::GetNextStackFrameInfoId() { + int id = last_stack_frame_info_id(); + int next_id = id == Smi::kMaxValue ? 0 : (id + 1); + set_last_stack_frame_info_id(next_id); + return next_id; +} + // static std::string Isolate::GetTurboCfgFileName(Isolate* isolate) { if (FLAG_trace_turbo_cfg_file == nullptr) { |