[email protected] | 41fba0e | 2014-01-16 18:19:42 | [diff] [blame] | 1 | // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
danakj | 89f4708 | 2020-09-02 17:53:43 | [diff] [blame] | 5 | #include "content/web_test/renderer/gc_controller.h" |
[email protected] | 41fba0e | 2014-01-16 18:19:42 | [diff] [blame] | 6 | |
Sebastien Marchand | f8cbfab | 2019-01-25 16:02:30 | [diff] [blame] | 7 | #include "base/bind.h" |
Peter Boström | 2e6be14 | 2021-11-13 01:28:25 | [diff] [blame] | 8 | #include "base/ignore_result.h" |
[email protected] | 41fba0e | 2014-01-16 18:19:42 | [diff] [blame] | 9 | #include "gin/arguments.h" |
| 10 | #include "gin/handle.h" |
| 11 | #include "gin/object_template_builder.h" |
Blink Reformat | a30d423 | 2018-04-07 15:31:06 | [diff] [blame] | 12 | #include "third_party/blink/public/web/blink.h" |
| 13 | #include "third_party/blink/public/web/web_local_frame.h" |
[email protected] | 41fba0e | 2014-01-16 18:19:42 | [diff] [blame] | 14 | #include "v8/include/v8.h" |
| 15 | |
danakj | 741848a | 2020-04-07 22:48:06 | [diff] [blame] | 16 | namespace content { |
[email protected] | 41fba0e | 2014-01-16 18:19:42 | [diff] [blame] | 17 | |
| 18 | gin::WrapperInfo GCController::kWrapperInfo = {gin::kEmbedderNativeGin}; |
| 19 | |
| 20 | // static |
danakj | c989ac7 | 2020-04-15 20:31:23 | [diff] [blame] | 21 | void GCController::Install(blink::WebLocalFrame* frame) { |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 22 | v8::Isolate* isolate = blink::MainThreadIsolate(); |
[email protected] | 41fba0e | 2014-01-16 18:19:42 | [diff] [blame] | 23 | v8::HandleScope handle_scope(isolate); |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 24 | v8::Local<v8::Context> context = frame->MainWorldScriptContext(); |
[email protected] | 41fba0e | 2014-01-16 18:19:42 | [diff] [blame] | 25 | if (context.IsEmpty()) |
| 26 | return; |
| 27 | |
| 28 | v8::Context::Scope context_scope(context); |
| 29 | |
| 30 | gin::Handle<GCController> controller = |
danakj | c989ac7 | 2020-04-15 20:31:23 | [diff] [blame] | 31 | gin::CreateHandle(isolate, new GCController(frame)); |
[email protected] | ad4d203 | 2014-04-28 13:50:59 | [diff] [blame] | 32 | if (controller.IsEmpty()) |
| 33 | return; |
deepak.s | 750d68f | 2015-04-30 07:32:41 | [diff] [blame] | 34 | v8::Local<v8::Object> global = context->Global(); |
Dan Elphick | a83be51 | 2019-02-05 15:57:23 | [diff] [blame] | 35 | global |
| 36 | ->Set(context, gin::StringToV8(isolate, "GCController"), |
| 37 | controller.ToV8()) |
| 38 | .Check(); |
[email protected] | 41fba0e | 2014-01-16 18:19:42 | [diff] [blame] | 39 | } |
| 40 | |
danakj | c989ac7 | 2020-04-15 20:31:23 | [diff] [blame] | 41 | GCController::GCController(blink::WebLocalFrame* frame) : frame_(frame) {} |
[email protected] | 41fba0e | 2014-01-16 18:19:42 | [diff] [blame] | 42 | |
Michael Lippautz | 5b64e89 | 2018-09-24 11:10:00 | [diff] [blame] | 43 | GCController::~GCController() = default; |
[email protected] | 41fba0e | 2014-01-16 18:19:42 | [diff] [blame] | 44 | |
| 45 | gin::ObjectTemplateBuilder GCController::GetObjectTemplateBuilder( |
| 46 | v8::Isolate* isolate) { |
| 47 | return gin::Wrappable<GCController>::GetObjectTemplateBuilder(isolate) |
| 48 | .SetMethod("collect", &GCController::Collect) |
[email protected] | c7d9004 | 2014-02-05 08:25:15 | [diff] [blame] | 49 | .SetMethod("collectAll", &GCController::CollectAll) |
Michael Lippautz | 5b64e89 | 2018-09-24 11:10:00 | [diff] [blame] | 50 | .SetMethod("minorCollect", &GCController::MinorCollect) |
| 51 | .SetMethod("asyncCollectAll", &GCController::AsyncCollectAll); |
[email protected] | 41fba0e | 2014-01-16 18:19:42 | [diff] [blame] | 52 | } |
| 53 | |
| 54 | void GCController::Collect(const gin::Arguments& args) { |
| 55 | args.isolate()->RequestGarbageCollectionForTesting( |
| 56 | v8::Isolate::kFullGarbageCollection); |
| 57 | } |
| 58 | |
[email protected] | c7d9004 | 2014-02-05 08:25:15 | [diff] [blame] | 59 | void GCController::CollectAll(const gin::Arguments& args) { |
Michael Lippautz | 5b64e89 | 2018-09-24 11:10:00 | [diff] [blame] | 60 | for (int i = 0; i < kNumberOfGCsForFullCollection; i++) { |
[email protected] | c7d9004 | 2014-02-05 08:25:15 | [diff] [blame] | 61 | args.isolate()->RequestGarbageCollectionForTesting( |
| 62 | v8::Isolate::kFullGarbageCollection); |
| 63 | } |
| 64 | } |
| 65 | |
Michael Lippautz | 5b64e89 | 2018-09-24 11:10:00 | [diff] [blame] | 66 | void GCController::AsyncCollectAll(const gin::Arguments& args) { |
Michael Lippautz | 584c69a8 | 2018-09-25 15:22:51 | [diff] [blame] | 67 | v8::HandleScope scope(args.isolate()); |
| 68 | |
| 69 | if (args.PeekNext().IsEmpty() || !args.PeekNext()->IsFunction()) { |
| 70 | args.ThrowTypeError( |
| 71 | "asyncCollectAll should be called with a callback argument being a " |
| 72 | "v8::Function."); |
| 73 | return; |
Michael Lippautz | 5b64e89 | 2018-09-24 11:10:00 | [diff] [blame] | 74 | } |
danakj | c989ac7 | 2020-04-15 20:31:23 | [diff] [blame] | 75 | v8::UniquePersistent<v8::Function> js_callback( |
Michael Lippautz | 5b64e89 | 2018-09-24 11:10:00 | [diff] [blame] | 76 | args.isolate(), v8::Local<v8::Function>::Cast(args.PeekNext())); |
| 77 | |
danakj | c989ac7 | 2020-04-15 20:31:23 | [diff] [blame] | 78 | // Bind the js callback into a OnceClosure that will be run asynchronously in |
| 79 | // a fresh call stack. |
| 80 | base::OnceClosure run_async = |
Michael Lippautz | 5b64e89 | 2018-09-24 11:10:00 | [diff] [blame] | 81 | base::BindOnce(&GCController::AsyncCollectAllWithEmptyStack, |
danakj | c989ac7 | 2020-04-15 20:31:23 | [diff] [blame] | 82 | weak_ptr_factory_.GetWeakPtr(), std::move(js_callback)); |
| 83 | frame_->GetTaskRunner(blink::TaskType::kInternalTest) |
| 84 | ->PostTask(FROM_HERE, std::move(run_async)); |
Michael Lippautz | 5b64e89 | 2018-09-24 11:10:00 | [diff] [blame] | 85 | } |
| 86 | |
| 87 | void GCController::AsyncCollectAllWithEmptyStack( |
| 88 | v8::UniquePersistent<v8::Function> callback) { |
| 89 | v8::Isolate* const isolate = blink::MainThreadIsolate(); |
| 90 | |
| 91 | for (int i = 0; i < kNumberOfGCsForFullCollection; i++) { |
Omer Katz | b65361a4 | 2021-11-22 21:46:49 | [diff] [blame] | 92 | isolate->RequestGarbageCollectionForTesting( |
| 93 | v8::Isolate::kFullGarbageCollection, |
Michael Lippautz | ac8bee7 | 2020-12-14 11:31:42 | [diff] [blame] | 94 | v8::EmbedderHeapTracer::EmbedderStackState::kNoHeapPointers); |
Michael Lippautz | 5b64e89 | 2018-09-24 11:10:00 | [diff] [blame] | 95 | } |
| 96 | |
| 97 | v8::HandleScope scope(isolate); |
| 98 | v8::Local<v8::Function> func = callback.Get(isolate); |
| 99 | v8::Local<v8::Context> context = func->CreationContext(); |
| 100 | v8::Context::Scope context_scope(context); |
Michael Lippautz | 54f67af2 | 2019-01-08 15:41:57 | [diff] [blame] | 101 | v8::TryCatch try_catch(isolate); |
Jochen Eisinger | 68f33286 | 2021-04-29 08:19:20 | [diff] [blame] | 102 | v8::MicrotasksScope microtasks_scope( |
| 103 | isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); |
Michael Lippautz | 54f67af2 | 2019-01-08 15:41:57 | [diff] [blame] | 104 | auto result = func->Call(context, context->Global(), 0, nullptr); |
| 105 | // Swallow potential exception. |
| 106 | ignore_result(result); |
Michael Lippautz | 5b64e89 | 2018-09-24 11:10:00 | [diff] [blame] | 107 | } |
| 108 | |
[email protected] | 41fba0e | 2014-01-16 18:19:42 | [diff] [blame] | 109 | void GCController::MinorCollect(const gin::Arguments& args) { |
| 110 | args.isolate()->RequestGarbageCollectionForTesting( |
| 111 | v8::Isolate::kMinorGarbageCollection); |
| 112 | } |
| 113 | |
danakj | 741848a | 2020-04-07 22:48:06 | [diff] [blame] | 114 | } // namespace content |