summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/timing/measure_memory
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/core/timing/measure_memory')
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/OWNERS1
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory.idl11
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_breakdown.idl12
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc288
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h39
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.cc286
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.h42
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/memory_attribution.idl12
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/memory_attribution_container.idl11
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/memory_breakdown_entry.idl12
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/memory_measurement.idl11
11 files changed, 267 insertions, 458 deletions
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/OWNERS b/chromium/third_party/blink/renderer/core/timing/measure_memory/OWNERS
new file mode 100644
index 00000000000..ccae9082083
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/timing/measure_memory/OWNERS
@@ -0,0 +1 @@
+ulan@chromium.org
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory.idl b/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory.idl
deleted file mode 100644
index d319cef8df4..00000000000
--- a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory.idl
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://github.com/WICG/performance-measure-memory
-
-// The result of performance.measureMemory().
-dictionary MeasureMemory {
- required unsigned long long bytes;
- required sequence<MeasureMemoryBreakdown> breakdown;
-};
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_breakdown.idl b/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_breakdown.idl
deleted file mode 100644
index e90820e6bda..00000000000
--- a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_breakdown.idl
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://github.com/ulan/performance-measure-memory.
-
-// A single entry of performance.measureMemory() result.
-dictionary MeasureMemoryBreakdown {
- unsigned long long bytes;
- sequence<DOMString> attribution;
- sequence<DOMString> userAgentSpecificTypes;
-};
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc b/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc
index 1a0aab598a2..3759664a803 100644
--- a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc
+++ b/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc
@@ -4,38 +4,56 @@
#include "third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h"
-#include "third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.h"
-
+#include <algorithm>
+#include "base/rand_util.h"
+#include "components/performance_manager/public/mojom/coordination_unit.mojom-blink.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_measure_memory.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_measure_memory_breakdown.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_memory_attribution.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_memory_attribution_container.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_memory_breakdown_entry.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_memory_measurement.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "v8/include/v8.h"
+using performance_manager::mojom::blink::WebMemoryAttribution;
+using performance_manager::mojom::blink::WebMemoryAttributionPtr;
+using performance_manager::mojom::blink::WebMemoryBreakdownEntryPtr;
+using performance_manager::mojom::blink::WebMemoryMeasurement;
+using performance_manager::mojom::blink::WebMemoryMeasurementPtr;
+using performance_manager::mojom::blink::WebMemoryUsagePtr;
+
namespace blink {
-static MeasureMemoryController::V8MemoryReporter*
- g_dedicated_worker_memory_reporter_ = nullptr;
+namespace {
-void MeasureMemoryController::SetDedicatedWorkerMemoryReporter(
- V8MemoryReporter* reporter) {
- g_dedicated_worker_memory_reporter_ = reporter;
-}
+// String constants used for building the result.
+constexpr const char* kCrossOriginUrl = "cross-origin-url";
+constexpr const char* kMemoryTypeDom = "DOM";
+constexpr const char* kMemoryTypeJavaScript = "JavaScript";
+constexpr const char* kMemoryTypeShared = "Shared";
+constexpr const char* kScopeCrossOriginAggregated = "cross-origin-aggregated";
+constexpr const char* kScopeDedicatedWorker = "DedicatedWorker";
+constexpr const char* kScopeWindow = "Window";
+
+} // anonymous namespace
MeasureMemoryController::MeasureMemoryController(
- util::PassKey<MeasureMemoryController>,
+ base::PassKey<MeasureMemoryController>,
v8::Isolate* isolate,
v8::Local<v8::Context> context,
v8::Local<v8::Promise::Resolver> promise_resolver)
@@ -51,17 +69,77 @@ MeasureMemoryController::MeasureMemoryController(
void MeasureMemoryController::Trace(Visitor* visitor) const {
visitor->Trace(promise_resolver_);
- visitor->Trace(main_result_);
- visitor->Trace(worker_result_);
}
+namespace {
+
+enum class ApiStatus {
+ kAvailable,
+ kNotAvailableDueToFlag,
+ kNotAvailableDueToDetachedContext,
+ kNotAvailableDueToCrossOriginContext,
+ kNotAvailableDueToCrossOriginIsolation,
+ kNotAvailableDueToResourceCoordinator,
+};
+
+ApiStatus CheckMeasureMemoryAvailability(LocalDOMWindow* window) {
+ if (!base::FeatureList::IsEnabled(
+ features::kWebMeasureMemoryViaPerformanceManager)) {
+ return ApiStatus::kNotAvailableDueToFlag;
+ }
+ if (!window) {
+ return ApiStatus::kNotAvailableDueToDetachedContext;
+ }
+ LocalFrame* local_frame = window->GetFrame();
+ if (!local_frame) {
+ return ApiStatus::kNotAvailableDueToDetachedContext;
+ }
+ if (!window->CrossOriginIsolatedCapability() &&
+ local_frame->GetSettings()->GetWebSecurityEnabled()) {
+ return ApiStatus::kNotAvailableDueToCrossOriginIsolation;
+ }
+
+ // We need DocumentResourceCoordinator to query PerformanceManager.
+ if (!window->document()) {
+ return ApiStatus::kNotAvailableDueToDetachedContext;
+ }
+
+ if (!window->document()->GetResourceCoordinator()) {
+ return ApiStatus::kNotAvailableDueToResourceCoordinator;
+ }
+
+ return ApiStatus::kAvailable;
+}
+
+} // anonymous namespace
+
ScriptPromise MeasureMemoryController::StartMeasurement(
ScriptState* script_state,
ExceptionState& exception_state) {
- if (!IsMeasureMemoryAvailable(LocalDOMWindow::From(script_state))) {
- exception_state.ThrowSecurityError(
- "performance.measureMemory is not available in this context");
- return ScriptPromise();
+ switch (auto status = CheckMeasureMemoryAvailability(
+ LocalDOMWindow::From(script_state))) {
+ case ApiStatus::kAvailable:
+ break;
+ case ApiStatus::kNotAvailableDueToFlag:
+ case ApiStatus::kNotAvailableDueToResourceCoordinator:
+ exception_state.ThrowSecurityError(
+ "performance.measureUserAgentSpecificMemory is not available.");
+ return ScriptPromise();
+ case ApiStatus::kNotAvailableDueToDetachedContext:
+ exception_state.ThrowSecurityError(
+ "performance.measureUserAgentSpecificMemory is not supported"
+ " in detached iframes.");
+ return ScriptPromise();
+ case ApiStatus::kNotAvailableDueToCrossOriginContext:
+ exception_state.ThrowSecurityError(
+ "performance.measureUserAgentSpecificMemory is not supported"
+ " in cross-origin iframes.");
+ return ScriptPromise();
+ case ApiStatus::kNotAvailableDueToCrossOriginIsolation:
+ exception_state.ThrowSecurityError(
+ "performance.measureUserAgentSpecificMemory requires"
+ " cross-origin isolation.");
+ return ScriptPromise();
}
v8::Isolate* isolate = script_state->GetIsolate();
v8::TryCatch try_catch(isolate);
@@ -71,73 +149,143 @@ ScriptPromise MeasureMemoryController::StartMeasurement(
exception_state.RethrowV8Exception(try_catch.Exception());
return ScriptPromise();
}
- v8::MeasureMemoryExecution execution =
+ auto measurement_mode =
RuntimeEnabledFeatures::ForceEagerMeasureMemoryEnabled(
ExecutionContext::From(script_state))
- ? v8::MeasureMemoryExecution::kEager
- : v8::MeasureMemoryExecution::kDefault;
+ ? WebMemoryMeasurement::Mode::kEager
+ : WebMemoryMeasurement::Mode::kDefault;
auto* impl = MakeGarbageCollected<MeasureMemoryController>(
- util::PassKey<MeasureMemoryController>(), isolate, context,
+ base::PassKey<MeasureMemoryController>(), isolate, context,
promise_resolver);
+ Document* document = LocalDOMWindow::From(script_state)->document();
+ document->GetResourceCoordinator()->OnWebMemoryMeasurementRequested(
+ measurement_mode, WTF::Bind(&MeasureMemoryController::MeasurementComplete,
+ WrapPersistent(impl)));
- isolate->MeasureMemory(
- std::make_unique<MeasureMemoryDelegate>(
- isolate, context,
- WTF::Bind(&MeasureMemoryController::MainMeasurementComplete,
- WrapPersistent(impl))),
- execution);
- if (g_dedicated_worker_memory_reporter_) {
- g_dedicated_worker_memory_reporter_->GetMemoryUsage(
- WTF::Bind(&MeasureMemoryController::WorkerMeasurementComplete,
- WrapPersistent(impl)),
-
- execution);
- } else {
- HeapVector<Member<MeasureMemoryBreakdown>> result;
- impl->WorkerMeasurementComplete(result);
- }
return ScriptPromise(script_state, promise_resolver->GetPromise());
}
-bool MeasureMemoryController::IsMeasureMemoryAvailable(LocalDOMWindow* window) {
- // TODO(ulan): We should check for window.crossOriginIsolated when it ships.
- // Until then we enable the API only for processes locked to a site
- // similar to the precise mode of the legacy performance.memory API.
- if (!Platform::Current()->IsLockedToSite()) {
- return false;
+
+namespace {
+
+// Satisfies the requirements of UniformRandomBitGenerator from C++ standard.
+// It is used in std::shuffle calls below.
+struct RandomBitGenerator {
+ using result_type = size_t;
+ static constexpr size_t min() { return 0; }
+ static constexpr size_t max() {
+ return static_cast<size_t>(std::numeric_limits<int>::max());
+ }
+ size_t operator()() {
+ return static_cast<size_t>(base::RandInt(min(), max()));
+ }
+};
+
+// These functions convert WebMemory* mojo structs to IDL and JS values.
+WTF::AtomicString ConvertScope(WebMemoryAttribution::Scope scope) {
+ using Scope = WebMemoryAttribution::Scope;
+ switch (scope) {
+ case Scope::kDedicatedWorker:
+ return kScopeDedicatedWorker;
+ case Scope::kWindow:
+ return kScopeWindow;
+ case Scope::kCrossOriginAggregated:
+ return kScopeCrossOriginAggregated;
+ }
+}
+
+MemoryAttributionContainer* ConvertContainer(
+ const WebMemoryAttributionPtr& attribution) {
+ if (!attribution->src && !attribution->id) {
+ return nullptr;
}
- // The window.crossOriginIsolated will be true only for the top-level frame.
- // Until the flag is available we check for the top-level condition manually.
- if (!window) {
- return false;
+ auto* result = MemoryAttributionContainer::Create();
+ result->setSrc(attribution->src);
+ result->setId(attribution->id);
+ return result;
+}
+
+MemoryAttribution* ConvertAttribution(
+ const WebMemoryAttributionPtr& attribution) {
+ auto* result = MemoryAttribution::Create();
+ if (attribution->url) {
+ result->setUrl(attribution->url);
+ } else {
+ result->setUrl(kCrossOriginUrl);
}
- LocalFrame* local_frame = window->GetFrame();
- if (!local_frame || !local_frame->IsMainFrame()) {
- return false;
+ result->setScope(ConvertScope(attribution->scope));
+ result->setContainer(ConvertContainer(attribution));
+ return result;
+}
+
+MemoryBreakdownEntry* ConvertBreakdown(
+ const WebMemoryBreakdownEntryPtr& breakdown_entry) {
+ auto* result = MemoryBreakdownEntry::Create();
+ DCHECK(breakdown_entry->memory);
+ result->setBytes(breakdown_entry->memory->bytes);
+ HeapVector<Member<MemoryAttribution>> attribution;
+ for (const auto& entry : breakdown_entry->attribution) {
+ attribution.push_back(ConvertAttribution(entry));
}
- return true;
+ result->setAttribution(attribution);
+ result->setTypes({WTF::AtomicString(kMemoryTypeJavaScript)});
+ return result;
}
-void MeasureMemoryController::MainMeasurementComplete(Result result) {
- DCHECK(!main_measurement_completed_);
- main_result_ = result;
- main_measurement_completed_ = true;
- MaybeResolvePromise();
+MemoryBreakdownEntry* CreateUnattributedBreakdown(
+ const WebMemoryUsagePtr& memory,
+ const WTF::String& memory_type) {
+ auto* result = MemoryBreakdownEntry::Create();
+ DCHECK(memory);
+ result->setBytes(memory->bytes);
+ result->setAttribution({});
+ Vector<String> types;
+ types.push_back(memory_type);
+ result->setTypes(types);
+ return result;
}
-void MeasureMemoryController::WorkerMeasurementComplete(Result result) {
- DCHECK(!worker_measurement_completed_);
- worker_result_ = result;
- worker_measurement_completed_ = true;
- MaybeResolvePromise();
+MemoryBreakdownEntry* EmptyBreakdown() {
+ auto* result = MemoryBreakdownEntry::Create();
+ result->setBytes(0);
+ result->setAttribution({});
+ result->setTypes({});
+ return result;
}
-void MeasureMemoryController::MaybeResolvePromise() {
- if (!main_measurement_completed_ || !worker_measurement_completed_) {
- // Wait until we have all results.
- return;
+MemoryMeasurement* ConvertResult(const WebMemoryMeasurementPtr& measurement) {
+ HeapVector<Member<MemoryBreakdownEntry>> breakdown;
+ for (const auto& entry : measurement->breakdown) {
+ // Skip breakdowns that didn't get a measurement.
+ if (entry->memory)
+ breakdown.push_back(ConvertBreakdown(entry));
}
+ // Add breakdowns for memory that isn't attributed to an execution context.
+ breakdown.push_back(CreateUnattributedBreakdown(measurement->shared_memory,
+ kMemoryTypeShared));
+ breakdown.push_back(
+ CreateUnattributedBreakdown(measurement->blink_memory, kMemoryTypeDom));
+ // TODO(1085129): Report memory usage of detached frames once implemented.
+ // Add an empty breakdown entry as required by the spec.
+ // See https://github.com/WICG/performance-measure-memory/issues/10.
+ breakdown.push_back(EmptyBreakdown());
+ // Randomize the order of the entries as required by the spec.
+ std::shuffle(breakdown.begin(), breakdown.end(), RandomBitGenerator{});
+ size_t bytes = 0;
+ for (auto entry : breakdown) {
+ bytes += entry->bytes();
+ }
+ auto* result = MemoryMeasurement::Create();
+ result->setBreakdown(breakdown);
+ result->setBytes(bytes);
+ return result;
+}
+
+} // anonymous namespace
+
+void MeasureMemoryController::MeasurementComplete(
+ WebMemoryMeasurementPtr measurement) {
if (context_.IsEmpty()) {
// The context was garbage collected in the meantime.
return;
@@ -145,15 +293,7 @@ void MeasureMemoryController::MaybeResolvePromise() {
v8::HandleScope handle_scope(isolate_);
v8::Local<v8::Context> context = context_.NewLocal(isolate_);
v8::Context::Scope context_scope(context);
- MeasureMemory* result = MeasureMemory::Create();
- auto breakdown = main_result_;
- breakdown.AppendVector(worker_result_);
- size_t total_size = 0;
- for (auto entry : breakdown) {
- total_size += entry->bytes();
- }
- result->setBytes(total_size);
- result->setBreakdown(breakdown);
+ auto* result = ConvertResult(measurement);
v8::Local<v8::Promise::Resolver> promise_resolver =
promise_resolver_.NewLocal(isolate_);
promise_resolver->Resolve(context, ToV8(result, promise_resolver, isolate_))
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h b/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h
index 6a59e0c99b3..b20ab9ed6ff 100644
--- a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h
+++ b/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h
@@ -5,7 +5,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_MEASURE_MEMORY_MEASURE_MEMORY_CONTROLLER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_MEASURE_MEMORY_MEASURE_MEMORY_CONTROLLER_H_
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
+#include "components/performance_manager/public/mojom/coordination_unit.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
@@ -16,12 +17,10 @@
namespace blink {
-class LocalDOMWindow;
-class MeasureMemoryBreakdown;
class ScriptState;
class ExceptionState;
-// The implementation of Performance.measureMemory() Web API.
+// The implementation of performance.measureUserAgentSpecificMemory() Web API.
// It is responsible for:
// 1. Starting an asynchronous memory measurement of the main V8 isolate.
// 2. Starting an asynchronous memory measurement of dedicated workers.
@@ -30,24 +29,9 @@ class ExceptionState;
class MeasureMemoryController final
: public GarbageCollected<MeasureMemoryController> {
public:
- using Result = HeapVector<Member<MeasureMemoryBreakdown>>;
- using ResultCallback = base::OnceCallback<void(Result)>;
-
- // PerformanceManager in blink/renderer/controller uses this interface
- // to provide an implementation of memory measurement for dedicated workers.
- //
- // It will be removed in the future when performance.measureMemory switches
- // to a mojo-based implementation that queries PerformanceManager in the
- // browser process.
- class V8MemoryReporter {
- public:
- virtual void GetMemoryUsage(MeasureMemoryController::ResultCallback,
- v8::MeasureMemoryExecution) = 0;
- };
-
// Private constructor guarded by PassKey. Use the StartMeasurement() wrapper
// to construct the object and start the measurement.
- MeasureMemoryController(util::PassKey<MeasureMemoryController>,
+ MeasureMemoryController(base::PassKey<MeasureMemoryController>,
v8::Isolate*,
v8::Local<v8::Context>,
v8::Local<v8::Promise::Resolver>);
@@ -58,25 +42,14 @@ class MeasureMemoryController final
void Trace(Visitor* visitor) const;
- // The entry point for injecting dependency on PerformanceManager.
- CORE_EXPORT static void SetDedicatedWorkerMemoryReporter(V8MemoryReporter*);
-
private:
- static bool IsMeasureMemoryAvailable(LocalDOMWindow* window);
// Invoked when the memory of the main V8 isolate is measured.
- void MainMeasurementComplete(Result);
- // Invoked when the memory of all dedicated workers is measured.
- void WorkerMeasurementComplete(Result);
- // Resolves the JS promise if both pending measurements are done.
- void MaybeResolvePromise();
+ void MeasurementComplete(
+ performance_manager::mojom::blink::WebMemoryMeasurementPtr);
v8::Isolate* isolate_;
ScopedPersistent<v8::Context> context_;
TraceWrapperV8Reference<v8::Promise::Resolver> promise_resolver_;
- Result main_result_;
- Result worker_result_;
- bool main_measurement_completed_ = false;
- bool worker_measurement_completed_ = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.cc b/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.cc
deleted file mode 100644
index 28f6202d87e..00000000000
--- a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.cc
+++ /dev/null
@@ -1,286 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.h"
-
-#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_security_origin.h"
-#include "third_party/blink/public/web/web_frame.h"
-#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_measure_memory.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_measure_memory_breakdown.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/frame/frame.h"
-#include "third_party/blink/renderer/core/frame/frame_owner.h"
-#include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
-
-namespace blink {
-
-MeasureMemoryDelegate::MeasureMemoryDelegate(v8::Isolate* isolate,
- v8::Local<v8::Context> context,
- ResultCallback callback)
- : isolate_(isolate),
- context_(isolate, context),
- callback_(std::move(callback)) {
- context_.SetPhantom();
-}
-
-// Returns true if the given context should be included in the current memory
-// measurement. Currently it is very conservative and allows only the same
-// origin contexts that belong to the same JavaScript origin.
-// With COOP/COEP we will be able to relax this restriction for the contexts
-// that opt-in into memory measurement.
-bool MeasureMemoryDelegate::ShouldMeasure(v8::Local<v8::Context> context) {
- if (context_.IsEmpty()) {
- // The original context was garbage collected in the meantime.
- return false;
- }
- v8::Local<v8::Context> original_context = context_.NewLocal(isolate_);
- ExecutionContext* original_execution_context =
- ExecutionContext::From(original_context);
- ExecutionContext* execution_context = ExecutionContext::From(context);
- if (!original_execution_context || !execution_context) {
- // One of the contexts is detached or is created by DevTools.
- return false;
- }
- if (original_execution_context->GetAgent() != execution_context->GetAgent()) {
- // Context do not belong to the same JavaScript agent.
- return false;
- }
- if (ScriptState::From(context)->World().IsIsolatedWorld()) {
- // Context belongs to an extension. Skip it.
- return false;
- }
- const SecurityOrigin* original_security_origin =
- original_execution_context->GetSecurityContext().GetSecurityOrigin();
- const SecurityOrigin* security_origin =
- execution_context->GetSecurityContext().GetSecurityOrigin();
- if (!original_security_origin->IsSameOriginWith(security_origin)) {
- // TODO(ulan): Check for COOP/COEP and allow cross-origin contexts that
- // opted in for memory measurement.
- // Until then we allow cross-origin measurement only for site-isolated
- // web pages.
- return Platform::Current()->IsLockedToSite();
- }
- return true;
-}
-
-namespace {
-// Helper functions for constructing a memory measurement result.
-
-LocalFrame* GetLocalFrame(v8::Local<v8::Context> context) {
- LocalDOMWindow* window = ToLocalDOMWindow(context);
- if (!window) {
- // The context was detached. Ignore it.
- return nullptr;
- }
- return window->GetFrame();
-}
-
-// Returns true if all frames on the path from the main frame to
-// the given frame (excluding the given frame) have the same origin.
-bool AllAncestorsAndOpenersAreSameOrigin(const WebFrame* main_frame,
- const WebFrame* frame) {
- while (frame != main_frame) {
- frame = frame->Parent() ? frame->Parent() : frame->Opener();
- if (!main_frame->GetSecurityOrigin().CanAccess(frame->GetSecurityOrigin()))
- return false;
- }
- return true;
-}
-
-// Returns the URL corresponding to the given frame. It is:
-// - document's URL if the frame is a same-origin top frame.
-// - the src attribute of the owner iframe element if the frame is
-// an iframe.
-// - nullopt, otherwise.
-// Preconditions:
-// - If the frame is cross-origin, then all its ancestors/openers
-// must be of the same origin as the main frame.
-// - The frame must be attached to the DOM tree and the main frame
-// must be reachable via child => parent and openee => opener edges.
-String GetUrl(const WebFrame* main_frame, const WebFrame* frame) {
- DCHECK(AllAncestorsAndOpenersAreSameOrigin(main_frame, frame));
- if (!frame->Parent()) {
- // TODO(ulan): Turn this conditional into a DCHECK once the API
- // is gated behind COOP+COEP. Only same-origin frames can appear here.
- if (!main_frame->GetSecurityOrigin().CanAccess(frame->GetSecurityOrigin()))
- return {};
- // The frame must be local because it is in the same browsing context
- // group as the main frame and has the same origin.
- // Check to avoid memory corruption in the case if our invariant is off.
- CHECK(IsA<LocalFrame>(WebFrame::ToCoreFrame(*frame)));
- LocalFrame* local = To<LocalFrame>(WebFrame::ToCoreFrame(*frame));
- return local->GetDocument()->Url().GetString();
- }
- FrameOwner* frame_owner = WebFrame::ToCoreFrame(*frame)->Owner();
- // The frame owner must be local because the parent of the frame has
- // the same origin as the main frame. Also the frame cannot be provisional
- // here because it is attached and has a document.
- // Check to avoid of memory corruption in the case if our invariant is off.
- CHECK(IsA<HTMLFrameOwnerElement>(frame_owner));
- HTMLFrameOwnerElement* owner_element = To<HTMLFrameOwnerElement>(frame_owner);
- switch (owner_element->OwnerType()) {
- case mojom::blink::FrameOwnerElementType::kIframe:
- return owner_element->getAttribute(html_names::kSrcAttr);
- case mojom::blink::FrameOwnerElementType::kObject:
- case mojom::blink::FrameOwnerElementType::kEmbed:
- case mojom::blink::FrameOwnerElementType::kFrame:
- case mojom::blink::FrameOwnerElementType::kPortal:
- // TODO(ulan): return the data/src attribute after adding tests.
- return {};
- case mojom::blink::FrameOwnerElementType::kNone:
- // The main frame was handled as a local frame above.
- NOTREACHED();
- return {};
- }
-}
-
-// To avoid information leaks cross-origin iframes are considered opaque for
-// the purposes of attribution. This means the memory of all iframes nested
-// in a cross-origin iframe is attributed to the cross-origin iframe.
-// See https://github.com/WICG/performance-measure-memory for more details.
-//
-// Given the main frame and a frame, this function find the first cross-origin
-// frame in the path from the main frame to the given frame. Edges in the path
-// are parent/child and opener/openee edges.
-// If the path doesn't exist then it returns nullptr.
-// If there are no cross-origin frames, then it returns the given frame.
-//
-// Precondition: the frame must be attached to the DOM tree.
-const WebFrame* GetAttributionFrame(const WebFrame* main_frame,
- const WebFrame* frame) {
- WebSecurityOrigin main_security_origin = main_frame->GetSecurityOrigin();
- // Walk up the tree and the openers to find the first cross-origin frame
- // on the path from the main frame to the given frame.
- const WebFrame* result = frame;
- while (frame != main_frame) {
- if (frame->Parent()) {
- frame = frame->Parent();
- } else if (frame->Opener()) {
- frame = frame->Opener();
- } else {
- // The opener was reset. We cannot get the attribution.
- return nullptr;
- }
- if (!main_security_origin.CanAccess(frame->GetSecurityOrigin()))
- result = frame;
- }
- // The result frame must be attached because we started from an attached
- // frame (precondition) and followed the parent and opener references until
- // the main frame, which is also attached.
- DCHECK(WebFrame::ToCoreFrame(*result)->IsAttached());
- return result;
-}
-
-// Return per-frame sizes based on the given per-context size.
-// TODO(ulan): Revisit this after Origin Trial and see if the results
-// are precise enough or if we need to additionally group by JS agent.
-HashMap<const WebFrame*, size_t> GroupByFrame(
- const WebFrame* main_frame,
- const std::vector<std::pair<v8::Local<v8::Context>, size_t>>& context_sizes,
- size_t& detached_size,
- size_t& unknown_frame_size) {
- detached_size = 0;
- unknown_frame_size = 0;
- HashMap<const WebFrame*, size_t> per_frame;
- for (const auto& context_size : context_sizes) {
- const WebFrame* frame =
- WebFrame::FromFrame(GetLocalFrame(context_size.first));
- if (!frame) {
- detached_size += context_size.second;
- continue;
- }
- frame = GetAttributionFrame(main_frame, frame);
- if (!frame) {
- unknown_frame_size += context_size.second;
- continue;
- }
- auto it = per_frame.find(frame);
- if (it == per_frame.end()) {
- per_frame.insert(frame, context_size.second);
- } else {
- it->value += context_size.second;
- }
- }
- return per_frame;
-}
-
-MeasureMemoryBreakdown* CreateMeasureMemoryBreakdown(
- size_t bytes,
- const Vector<String>& types,
- const String& url) {
- MeasureMemoryBreakdown* result = MeasureMemoryBreakdown::Create();
- result->setBytes(bytes);
- result->setUserAgentSpecificTypes(types);
- result->setAttribution(url.length() ? Vector<String>{url} : Vector<String>());
- return result;
-}
-
-} // anonymous namespace
-
-// Constructs a memory measurement result based on the given list of (context,
-// size) pairs and resolves the promise.
-void MeasureMemoryDelegate::MeasurementComplete(
- const std::vector<std::pair<v8::Local<v8::Context>, size_t>>& context_sizes,
- size_t unattributed_size) {
- if (context_.IsEmpty()) {
- // The context was garbage collected in the meantime.
- return;
- }
- v8::Local<v8::Context> context = context_.NewLocal(isolate_);
- const WebFrame* main_frame = WebFrame::FromFrame(GetLocalFrame(context));
- if (!main_frame) {
- // The context was detached in the meantime.
- return;
- }
- DCHECK(!main_frame->Parent());
- v8::Context::Scope context_scope(context);
- size_t total_size = 0;
- for (const auto& context_size : context_sizes) {
- total_size += context_size.second;
- }
- HeapVector<Member<MeasureMemoryBreakdown>> breakdown;
- size_t detached_size;
- size_t unknown_frame_size;
- HashMap<const WebFrame*, size_t> per_frame(GroupByFrame(
- main_frame, context_sizes, detached_size, unknown_frame_size));
- size_t attributed_size = 0;
- const String kWindow("Window");
- const String kJS("JS");
- const Vector<String> js_window_types = {kWindow, kJS};
- for (const auto& it : per_frame) {
- String url = GetUrl(main_frame, it.key);
- if (url.IsNull()) {
- unknown_frame_size += it.value;
- continue;
- }
- attributed_size += it.value;
- breakdown.push_back(
- CreateMeasureMemoryBreakdown(it.value, js_window_types, url));
- }
- if (detached_size) {
- const String kDetached("Detached");
- breakdown.push_back(CreateMeasureMemoryBreakdown(
- detached_size, Vector<String>{kWindow, kJS, kDetached}, ""));
- }
- if (unattributed_size) {
- const String kShared("Shared");
- breakdown.push_back(CreateMeasureMemoryBreakdown(
- unattributed_size, Vector<String>{kWindow, kJS, kShared}, ""));
- }
- if (unknown_frame_size) {
- breakdown.push_back(CreateMeasureMemoryBreakdown(
- unknown_frame_size, Vector<String>{kWindow, kJS}, ""));
- }
- std::move(callback_).Run(breakdown);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.h b/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.h
deleted file mode 100644
index 23a1100784f..00000000000
--- a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_MEASURE_MEMORY_MEASURE_MEMORY_DELEGATE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_MEASURE_MEMORY_MEASURE_MEMORY_DELEGATE_H_
-
-#include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
-#include "third_party/blink/renderer/platform/heap/member.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-class MeasureMemoryBreakdown;
-
-// Specifies V8 contexts to be measured and invokes the given callback once V8
-// completes the memory measurement.
-class MeasureMemoryDelegate : public v8::MeasureMemoryDelegate {
- public:
- using ResultCallback =
- base::OnceCallback<void(HeapVector<Member<MeasureMemoryBreakdown>>)>;
-
- MeasureMemoryDelegate(v8::Isolate* isolate,
- v8::Local<v8::Context> context,
- ResultCallback callback);
-
- // v8::MeasureMemoryDelegate overrides.
- bool ShouldMeasure(v8::Local<v8::Context> context) override;
- void MeasurementComplete(
- const std::vector<std::pair<v8::Local<v8::Context>, size_t>>&
- context_sizes,
- size_t unattributed_size) override;
- private:
- v8::Isolate* isolate_;
- ScopedPersistent<v8::Context> context_;
- ResultCallback callback_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_MEASURE_MEMORY_MEASURE_MEMORY_DELEGATE_H_
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_attribution.idl b/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_attribution.idl
new file mode 100644
index 00000000000..5a8d9c27bb4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_attribution.idl
@@ -0,0 +1,12 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/performance-measure-memory/#dictdef-memoryattribution
+
+// Describes a context to which the memory was attributed.
+dictionary MemoryAttribution {
+ required USVString url;
+ MemoryAttributionContainer container;
+ required DOMString scope;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_attribution_container.idl b/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_attribution_container.idl
new file mode 100644
index 00000000000..bb47082f790
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_attribution_container.idl
@@ -0,0 +1,11 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/performance-measure-memory/#dictdef-memoryattribution
+
+// The attributes of the container iframe element.
+dictionary MemoryAttributionContainer {
+ DOMString id;
+ USVString src;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_breakdown_entry.idl b/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_breakdown_entry.idl
new file mode 100644
index 00000000000..e3461faef8e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_breakdown_entry.idl
@@ -0,0 +1,12 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/performance-measure-memory/#dictdef-memorybreakdownentry
+
+// A single entry of performance.measureUserAgentSpecificMemory() result.
+dictionary MemoryBreakdownEntry {
+ required unsigned long long bytes;
+ required sequence<MemoryAttribution> attribution;
+ required sequence<DOMString> types;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_measurement.idl b/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_measurement.idl
new file mode 100644
index 00000000000..0f8feeb5797
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_measurement.idl
@@ -0,0 +1,11 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/performance-measure-memory/#dictdef-memorymeasurement
+
+// The result of performance.measureUserAgentSpecificMemory().
+dictionary MemoryMeasurement {
+ required unsigned long long bytes;
+ required sequence<MemoryBreakdownEntry> breakdown;
+};