26enum class GCType { kMinor, kMajor, kMajorWithSnapshot };
27enum class ExecutionType {
kAsync, kSync };
31 static GCOptions GetDefault() {
32 return {GCType::kMajor, ExecutionType::kSync, Flavor::kRegular,
35 static GCOptions GetDefaultForTruthyWithoutOptionsBag() {
36 return {GCType::kMinor, ExecutionType::kSync, Flavor::kRegular,
41 GCOptions() =
default;
44 ExecutionType execution;
49 GCOptions(
GCType type, ExecutionType execution, Flavor flavor,
54MaybeLocal<v8::String> ReadProperty(
v8::Isolate* isolate,
59 auto maybe_property =
object->Get(ctx, k);
61 if (!maybe_property.ToLocal(&property) || !property->IsString()) {
64 return MaybeLocal<v8::String>(property.As<
v8::String>());
67void ParseType(
v8::Isolate* isolate, MaybeLocal<v8::String> maybe_type,
68 GCOptions* options,
bool* found_options_object) {
69 if (maybe_type.IsEmpty())
return;
71 auto type = maybe_type.ToLocalChecked();
72 if (type->StrictEquals(
74 *found_options_object =
true;
75 options->type = GCType::kMinor;
76 }
else if (type->StrictEquals(
78 *found_options_object =
true;
79 options->type = GCType::kMajor;
80 }
else if (type->StrictEquals(
83 *found_options_object =
true;
84 options->type = GCType::kMajorWithSnapshot;
89 MaybeLocal<v8::String> maybe_execution, GCOptions* options,
90 bool* found_options_object) {
91 if (maybe_execution.IsEmpty())
return;
93 auto type = maybe_execution.ToLocalChecked();
94 if (type->StrictEquals(
96 *found_options_object =
true;
97 options->execution = ExecutionType::kAsync;
98 }
else if (type->StrictEquals(
100 *found_options_object =
true;
101 options->execution = ExecutionType::kSync;
105void ParseFlavor(
v8::Isolate* isolate, MaybeLocal<v8::String> maybe_execution,
106 GCOptions* options,
bool* found_options_object) {
107 if (maybe_execution.IsEmpty())
return;
109 auto type = maybe_execution.ToLocalChecked();
110 if (type->StrictEquals(
112 *found_options_object =
true;
113 options->flavor = Flavor::kRegular;
115 .ToLocalChecked())) {
116 *found_options_object =
true;
117 options->flavor = Flavor::kLastResort;
127 auto options = GCOptions::GetDefault();
130 bool found_options_object =
false;
134 auto ctx = isolate->GetCurrentContext();
138 ParseType(isolate, ReadProperty(isolate, ctx, param,
"type"), &options,
139 &found_options_object);
140 if (catch_block.HasCaught()) {
141 catch_block.ReThrow();
144 ParseExecution(isolate, ReadProperty(isolate, ctx, param,
"execution"),
145 &options, &found_options_object);
146 if (catch_block.HasCaught()) {
147 catch_block.ReThrow();
150 ParseFlavor(isolate, ReadProperty(isolate, ctx, param,
"flavor"), &options,
151 &found_options_object);
152 if (catch_block.HasCaught()) {
153 catch_block.ReThrow();
157 if (options.type == GCType::kMajorWithSnapshot) {
158 auto maybe_filename = ReadProperty(isolate, ctx, param,
"filename");
159 if (catch_block.HasCaught()) {
160 catch_block.ReThrow();
164 if (maybe_filename.ToLocal(&
filename)) {
165 size_t buffer_size =
filename->Utf8LengthV2(isolate) + 1;
166 std::unique_ptr<char[]> buffer(
new char[buffer_size]);
167 filename->WriteUtf8V2(isolate, buffer.get(), buffer_size,
169 options.filename = std::string(buffer.get());
172 CHECK(found_options_object);
179 if (!found_options_object) {
180 return Just<GCOptions>(GCOptions::GetDefaultForTruthyWithoutOptionsBag());
186void InvokeGC(
v8::Isolate* isolate,
const GCOptions gc_options) {
188 EmbedderStackStateScope stack_scope(
190 gc_options.execution == ExecutionType::kAsync
193 gc_options.execution == ExecutionType::kAsync
194 ? StackState::kNoHeapPointers
195 : StackState::kMayContainHeapPointers);
196 switch (gc_options.type) {
202 switch (gc_options.flavor) {
203 case Flavor::kRegular:
204 heap->PreciseCollectAllGarbage(i::GCFlag::kNoFlags,
205 i::GarbageCollectionReason::kTesting,
208 case Flavor::kLastResort:
209 heap->CollectAllAvailableGarbage(
210 i::GarbageCollectionReason::kTesting);
215 case GCType::kMajorWithSnapshot:
216 heap->PreciseCollectAllGarbage(i::GCFlag::kNoFlags,
217 i::GarbageCollectionReason::kTesting,
219 HeapProfiler* heap_profiler =
heap->heap_profiler();
225 options.snapshot_mode =
227 heap_profiler->TakeSnapshotToFile(options, gc_options.filename);
232class AsyncGC final :
public CancelableTask {
234 ~AsyncGC() final = default;
236 AsyncGC(
v8::Isolate* isolate,
v8::Local<
v8::Promise::Resolver> resolver,
238 : CancelableTask(reinterpret_cast<Isolate*>(isolate)),
240 ctx_(isolate, isolate->GetCurrentContext()),
241 resolver_(isolate, resolver),
243 AsyncGC(
const AsyncGC&) =
delete;
244 AsyncGC& operator=(
const AsyncGC&) =
delete;
246 void RunInternal() final {
248 InvokeGC(isolate_, options_);
275 if (info.Length() == 0) {
276 InvokeGC(isolate, GCOptions::GetDefault());
281 if (!Parse(isolate, info).To(&options)) {
285 switch (options.execution) {
286 case ExecutionType::kSync:
287 InvokeGC(isolate, options);
289 case ExecutionType::kAsync: {
293 info.GetReturnValue().Set(resolver->GetPromise());
296 CHECK(task_runner->NonNestableTasksEnabled());
297 task_runner->PostNonNestableTask(
298 std::make_unique<AsyncGC>(isolate, resolver, options));
static Local< FunctionTemplate > New(Isolate *isolate, FunctionCallback callback=nullptr, Local< Value > data=Local< Value >(), Local< Signature > signature=Local< Signature >(), int length=0, ConstructorBehavior behavior=ConstructorBehavior::kAllow, SideEffectType side_effect_type=SideEffectType::kHasSideEffect, const CFunction *c_function=nullptr, uint16_t instance_type=0, uint16_t allowed_receiver_instance_type_range_start=0, uint16_t allowed_receiver_instance_type_range_end=0)
static V8_INLINE Local< T > Cast(Local< S > that)
static V8_INLINE Local< T > New(Isolate *isolate, Local< T > that)
static V8_WARN_UNUSED_RESULT MaybeLocal< Resolver > New(Local< Context > context)
static V8_WARN_UNUSED_RESULT MaybeLocal< String > NewFromUtf8(Isolate *isolate, const char *data, NewStringType type=NewStringType::kNormal, int length=-1)
static void GC(const v8::FunctionCallbackInfo< v8::Value > &info)
v8::Local< v8::FunctionTemplate > GetNativeFunctionTemplate(v8::Isolate *isolate, v8::Local< v8::String > name) override
static V8_EXPORT_PRIVATE v8::Platform * GetCurrentPlatform()
v8::Global< v8::Promise::Resolver > resolver_
v8::Global< v8::Context > ctx_
DirectHandle< JSReceiver > options
bool V8_EXPORT ValidateCallbackInfo(const FunctionCallbackInfo< void > &info)
V8_INLINE constexpr bool IsObject(TaggedImpl< kRefType, StorageType > obj)
V8_INLINE Local< Primitive > Undefined(Isolate *isolate)
Maybe< T > Just(const T &t)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
NumericsMode numerics_mode