blob: 45d06ec14e267272f967b0d83b7d14ea2e6411e3 [file] [log] [blame]
// Copyright 2014 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 "content/shell/test_runner/gc_controller.h"
#include "content/shell/test_runner/test_interfaces.h"
#include "content/shell/test_runner/web_test_delegate.h"
#include "gin/arguments.h"
#include "gin/handle.h"
#include "gin/object_template_builder.h"
#include "third_party/blink/public/web/blink.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "v8/include/v8.h"
namespace test_runner {
gin::WrapperInfo GCController::kWrapperInfo = {gin::kEmbedderNativeGin};
// static
void GCController::Install(TestInterfaces* interfaces,
blink::WebLocalFrame* frame) {
v8::Isolate* isolate = blink::MainThreadIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = frame->MainWorldScriptContext();
if (context.IsEmpty())
return;
v8::Context::Scope context_scope(context);
gin::Handle<GCController> controller =
gin::CreateHandle(isolate, new GCController(interfaces));
if (controller.IsEmpty())
return;
v8::Local<v8::Object> global = context->Global();
global->Set(gin::StringToV8(isolate, "GCController"), controller.ToV8());
}
GCController::GCController(TestInterfaces* interfaces)
: interfaces_(interfaces) {}
GCController::~GCController() = default;
gin::ObjectTemplateBuilder GCController::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return gin::Wrappable<GCController>::GetObjectTemplateBuilder(isolate)
.SetMethod("collect", &GCController::Collect)
.SetMethod("collectAll", &GCController::CollectAll)
.SetMethod("minorCollect", &GCController::MinorCollect)
.SetMethod("asyncCollectAll", &GCController::AsyncCollectAll);
}
void GCController::Collect(const gin::Arguments& args) {
args.isolate()->RequestGarbageCollectionForTesting(
v8::Isolate::kFullGarbageCollection);
}
void GCController::CollectAll(const gin::Arguments& args) {
for (int i = 0; i < kNumberOfGCsForFullCollection; i++) {
args.isolate()->RequestGarbageCollectionForTesting(
v8::Isolate::kFullGarbageCollection);
}
}
void GCController::AsyncCollectAll(const gin::Arguments& args) {
v8::HandleScope scope(args.isolate());
if (args.PeekNext().IsEmpty() || !args.PeekNext()->IsFunction()) {
args.ThrowTypeError(
"asyncCollectAll should be called with a callback argument being a "
"v8::Function.");
return;
}
v8::UniquePersistent<v8::Function> func(
args.isolate(), v8::Local<v8::Function>::Cast(args.PeekNext()));
CHECK(interfaces_->GetDelegate());
CHECK(!func.IsEmpty());
interfaces_->GetDelegate()->PostTask(
base::BindOnce(&GCController::AsyncCollectAllWithEmptyStack,
base::Unretained(this), std::move(func)));
}
void GCController::AsyncCollectAllWithEmptyStack(
v8::UniquePersistent<v8::Function> callback) {
v8::Isolate* const isolate = blink::MainThreadIsolate();
for (int i = 0; i < kNumberOfGCsForFullCollection; i++) {
isolate->GetEmbedderHeapTracer()->GarbageCollectionForTesting(
v8::EmbedderHeapTracer::kEmpty);
}
v8::HandleScope scope(isolate);
v8::Local<v8::Function> func = callback.Get(isolate);
v8::Local<v8::Context> context = func->CreationContext();
v8::Context::Scope context_scope(context);
v8::TryCatch try_catch(isolate);
auto result = func->Call(context, context->Global(), 0, nullptr);
// Swallow potential exception.
ignore_result(result);
}
void GCController::MinorCollect(const gin::Arguments& args) {
args.isolate()->RequestGarbageCollectionForTesting(
v8::Isolate::kMinorGarbageCollection);
}
} // namespace test_runner