blob: 632395fecba37b84ce75e005b0c334affdc552a6 [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2014 The Chromium Authors
[email protected]41fba0e2014-01-16 18:19:422// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
danakj89f47082020-09-02 17:53:435#include "content/web_test/renderer/gc_controller.h"
[email protected]41fba0e2014-01-16 18:19:426
Avi Drissman5d5d48d62022-01-07 20:23:587#include <tuple>
8
Avi Drissmanadac21992023-01-11 23:46:399#include "base/functional/bind.h"
Sean Mahere672a662023-01-09 21:42:2810#include "base/task/single_thread_task_runner.h"
[email protected]41fba0e2014-01-16 18:19:4211#include "gin/arguments.h"
12#include "gin/handle.h"
13#include "gin/object_template_builder.h"
Dave Tapuskad1aaf8a2023-09-12 14:50:3414#include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
Blink Reformata30d4232018-04-07 15:31:0615#include "third_party/blink/public/web/web_local_frame.h"
[email protected]41fba0e2014-01-16 18:19:4216#include "v8/include/v8.h"
17
danakj741848a2020-04-07 22:48:0618namespace content {
[email protected]41fba0e2014-01-16 18:19:4219
20gin::WrapperInfo GCController::kWrapperInfo = {gin::kEmbedderNativeGin};
21
22// static
danakjc989ac72020-04-15 20:31:2323void GCController::Install(blink::WebLocalFrame* frame) {
Dave Tapuskad1aaf8a2023-09-12 14:50:3424 v8::Isolate* isolate = frame->GetAgentGroupScheduler()->Isolate();
[email protected]41fba0e2014-01-16 18:19:4225 v8::HandleScope handle_scope(isolate);
Blink Reformat1c4d759e2017-04-09 16:34:5426 v8::Local<v8::Context> context = frame->MainWorldScriptContext();
[email protected]41fba0e2014-01-16 18:19:4227 if (context.IsEmpty())
28 return;
29
30 v8::Context::Scope context_scope(context);
31
32 gin::Handle<GCController> controller =
danakjc989ac72020-04-15 20:31:2333 gin::CreateHandle(isolate, new GCController(frame));
[email protected]ad4d2032014-04-28 13:50:5934 if (controller.IsEmpty())
35 return;
deepak.s750d68f2015-04-30 07:32:4136 v8::Local<v8::Object> global = context->Global();
Dan Elphicka83be512019-02-05 15:57:2337 global
38 ->Set(context, gin::StringToV8(isolate, "GCController"),
39 controller.ToV8())
40 .Check();
[email protected]41fba0e2014-01-16 18:19:4241}
42
danakjc989ac72020-04-15 20:31:2343GCController::GCController(blink::WebLocalFrame* frame) : frame_(frame) {}
[email protected]41fba0e2014-01-16 18:19:4244
Michael Lippautz5b64e892018-09-24 11:10:0045GCController::~GCController() = default;
[email protected]41fba0e2014-01-16 18:19:4246
47gin::ObjectTemplateBuilder GCController::GetObjectTemplateBuilder(
48 v8::Isolate* isolate) {
49 return gin::Wrappable<GCController>::GetObjectTemplateBuilder(isolate)
50 .SetMethod("collect", &GCController::Collect)
[email protected]c7d90042014-02-05 08:25:1551 .SetMethod("collectAll", &GCController::CollectAll)
Michael Lippautz5b64e892018-09-24 11:10:0052 .SetMethod("minorCollect", &GCController::MinorCollect)
53 .SetMethod("asyncCollectAll", &GCController::AsyncCollectAll);
[email protected]41fba0e2014-01-16 18:19:4254}
55
56void GCController::Collect(const gin::Arguments& args) {
57 args.isolate()->RequestGarbageCollectionForTesting(
58 v8::Isolate::kFullGarbageCollection);
59}
60
[email protected]c7d90042014-02-05 08:25:1561void GCController::CollectAll(const gin::Arguments& args) {
Michael Lippautz5b64e892018-09-24 11:10:0062 for (int i = 0; i < kNumberOfGCsForFullCollection; i++) {
[email protected]c7d90042014-02-05 08:25:1563 args.isolate()->RequestGarbageCollectionForTesting(
64 v8::Isolate::kFullGarbageCollection);
65 }
66}
67
Michael Lippautz5b64e892018-09-24 11:10:0068void GCController::AsyncCollectAll(const gin::Arguments& args) {
Michael Lippautz584c69a82018-09-25 15:22:5169 v8::HandleScope scope(args.isolate());
70
71 if (args.PeekNext().IsEmpty() || !args.PeekNext()->IsFunction()) {
72 args.ThrowTypeError(
73 "asyncCollectAll should be called with a callback argument being a "
74 "v8::Function.");
75 return;
Michael Lippautz5b64e892018-09-24 11:10:0076 }
danakjc989ac72020-04-15 20:31:2377 v8::UniquePersistent<v8::Function> js_callback(
Michael Lippautz5b64e892018-09-24 11:10:0078 args.isolate(), v8::Local<v8::Function>::Cast(args.PeekNext()));
79
danakjc989ac72020-04-15 20:31:2380 // Bind the js callback into a OnceClosure that will be run asynchronously in
81 // a fresh call stack.
82 base::OnceClosure run_async =
Michael Lippautz5b64e892018-09-24 11:10:0083 base::BindOnce(&GCController::AsyncCollectAllWithEmptyStack,
danakjc989ac72020-04-15 20:31:2384 weak_ptr_factory_.GetWeakPtr(), std::move(js_callback));
85 frame_->GetTaskRunner(blink::TaskType::kInternalTest)
86 ->PostTask(FROM_HERE, std::move(run_async));
Michael Lippautz5b64e892018-09-24 11:10:0087}
88
89void GCController::AsyncCollectAllWithEmptyStack(
90 v8::UniquePersistent<v8::Function> callback) {
Dave Tapuskad1aaf8a2023-09-12 14:50:3491 v8::Isolate* const isolate = frame_->GetAgentGroupScheduler()->Isolate();
Michael Lippautz5b64e892018-09-24 11:10:0092
93 for (int i = 0; i < kNumberOfGCsForFullCollection; i++) {
Omer Katzb65361a42021-11-22 21:46:4994 isolate->RequestGarbageCollectionForTesting(
95 v8::Isolate::kFullGarbageCollection,
Nico Weber2922f3692022-11-29 17:03:4696 cppgc::EmbedderStackState::kNoHeapPointers);
Michael Lippautz5b64e892018-09-24 11:10:0097 }
98
99 v8::HandleScope scope(isolate);
100 v8::Local<v8::Function> func = callback.Get(isolate);
Dominik Inführ3af929c2024-10-08 05:53:19101 v8::Local<v8::Context> context = func->GetCreationContextChecked(isolate);
Michael Lippautz5b64e892018-09-24 11:10:00102 v8::Context::Scope context_scope(context);
Michael Lippautz54f67af22019-01-08 15:41:57103 v8::TryCatch try_catch(isolate);
Jochen Eisinger68f332862021-04-29 08:19:20104 v8::MicrotasksScope microtasks_scope(
Dave Tapuska7ba87502022-10-14 19:52:27105 isolate, context->GetMicrotaskQueue(),
106 v8::MicrotasksScope::kDoNotRunMicrotasks);
Michael Lippautz54f67af22019-01-08 15:41:57107 auto result = func->Call(context, context->Global(), 0, nullptr);
108 // Swallow potential exception.
Avi Drissman5d5d48d62022-01-07 20:23:58109 std::ignore = result;
Michael Lippautz5b64e892018-09-24 11:10:00110}
111
[email protected]41fba0e2014-01-16 18:19:42112void GCController::MinorCollect(const gin::Arguments& args) {
113 args.isolate()->RequestGarbageCollectionForTesting(
114 v8::Isolate::kMinorGarbageCollection);
115}
116
danakj741848a2020-04-07 22:48:06117} // namespace content