[test] Migrate cctest/test-global-handles to unittests/

Bug: v8:12781
Change-Id: If7681564f3e0c087e3347557a3f9169625b51607
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3817621
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82633}
This commit is contained in:
Feng Yu 2022-08-12 17:53:31 +08:00 committed by V8 LUCI CQ
parent ce9b1b2ab0
commit 3615ae691d
10 changed files with 223 additions and 206 deletions

View File

@ -182,7 +182,6 @@ v8_source_set("cctest_sources") {
"test-disasm-regex-helper.h",
"test-field-type-tracking.cc",
"test-func-name-inference.cc",
"test-global-handles.cc",
"test-heap-profiler.cc",
"test-icache.cc",
"test-ignition-statistics-extension.cc",

View File

@ -522,7 +522,6 @@
'test-bignum-dtoa/*': [SKIP],
'test-cpu-profiler/*': [SKIP],
'test-debug/*': [SKIP],
'test-global-handles/*': [SKIP],
'test-heap-profiler/*': [SKIP],
'test-heap/*': [SKIP],
'test-inobject-slack-tracking/*': [SKIP],
@ -977,13 +976,6 @@
'test-embedder-tracing/V8RegisteringEmbedderReference': [SKIP],
'test-external-string-tracker/ExternalString_ExternalBackingStoreSizeIncreasesAfterExternalization': [SKIP],
'test-external-string-tracker/ExternalString_ExternalBackingStoreSizeIncreasesMarkCompact': [SKIP],
'test-global-handles/FinalizerDiesAndKeepsPhantomAliveOnMarkCompact': [SKIP],
'test-global-handles/FinalizerWeakness': [SKIP],
'test-global-handles/GCFromWeakCallbacks': [SKIP],
'test-global-handles/PhantomHandlesWithoutCallbacks': [SKIP],
'test-global-handles/SecondPassPhantomCallbacks': [SKIP],
'test-global-handles/WeakHandleToUnmodifiedJSApiObjectDiesOnMarkCompact': [SKIP],
'test-global-handles/WeakHandleToUnmodifiedJSObjectDiesOnMarkCompact': [SKIP],
'test-heap-profiler/HeapSnapshotDeleteDuringTakeSnapshot': [SKIP],
'test-heap-profiler/HeapSnapshotObjectsStats': [SKIP],
'test-heap-profiler/SamplingHeapProfilerPretenuredInlineAllocations': [SKIP],

View File

@ -378,6 +378,7 @@ v8_source_set("unittests_sources") {
"heap/embedder-tracing-unittest.cc",
"heap/gc-idle-time-handler-unittest.cc",
"heap/gc-tracer-unittest.cc",
"heap/global-handles-unittest.cc",
"heap/global-safepoint-unittest.cc",
"heap/heap-controller-unittest.cc",
"heap/heap-unittest.cc",

View File

@ -39,9 +39,7 @@ class ApiWasmTest : public TestWithIsolate {
// value is irrelevant.
Local<Promise> promise =
Local<Promise>::Cast(RunJS("WebAssembly.compileStreaming(null)"));
while (platform::PumpMessageLoop(platform(), isolate())) {
}
EmptyMessageQueues();
CHECK_EQ(expected_state, promise->State());
}
};

View File

@ -498,23 +498,6 @@ void ConstructJSApiObject(v8::Isolate* isolate, v8::Local<v8::Context> context,
EXPECT_FALSE(global->IsEmpty());
}
namespace {
bool InCorrectGeneration(HeapObject object) {
return FLAG_single_generation ? !i::Heap::InYoungGeneration(object)
: i::Heap::InYoungGeneration(object);
}
template <typename GlobalOrPersistent>
bool InCorrectGeneration(v8::Isolate* isolate,
const GlobalOrPersistent& global) {
v8::HandleScope scope(isolate);
auto tmp = global.Get(isolate);
return InCorrectGeneration(*v8::Utils::OpenHandle(*tmp));
}
} // namespace
enum class SurvivalMode { kSurvives, kDies };
template <typename ModifierFunction, typename ConstructTracedReferenceFunction,
@ -532,7 +515,7 @@ void TracedReferenceTest(v8::Isolate* isolate,
const size_t initial_count = global_handles->handles_count();
auto handle = std::make_unique<v8::TracedReference<v8::Object>>();
construct_function(isolate, context, handle.get());
ASSERT_TRUE(InCorrectGeneration(isolate, *handle));
ASSERT_TRUE(IsNewObjectInCorrectGeneration(isolate, *handle));
modifier_function(*handle);
const size_t after_modification_count = global_handles->handles_count();
gc_function();
@ -983,7 +966,8 @@ V8_NOINLINE void StackToHeapTest(v8::Isolate* v8_isolate,
v8::HandleScope scope(v8_isolate);
v8::Local<v8::Object> to_object(ConstructTraceableJSApiObject(
v8_isolate->GetCurrentContext(), nullptr, nullptr));
EXPECT_TRUE(InCorrectGeneration(*v8::Utils::OpenHandle(*to_object)));
EXPECT_TRUE(
IsNewObjectInCorrectGeneration(*v8::Utils::OpenHandle(*to_object)));
if (!FLAG_single_generation &&
target_handling == TargetHandling::kInitializedOldGen) {
FullGC(v8_isolate);
@ -1034,7 +1018,8 @@ V8_NOINLINE void HeapToStackTest(v8::Isolate* v8_isolate,
v8::HandleScope scope(v8_isolate);
v8::Local<v8::Object> to_object(ConstructTraceableJSApiObject(
v8_isolate->GetCurrentContext(), nullptr, nullptr));
EXPECT_TRUE(InCorrectGeneration(*v8::Utils::OpenHandle(*to_object)));
EXPECT_TRUE(
IsNewObjectInCorrectGeneration(*v8::Utils::OpenHandle(*to_object)));
if (!FLAG_single_generation &&
target_handling == TargetHandling::kInitializedOldGen) {
FullGC(v8_isolate);
@ -1074,7 +1059,8 @@ V8_NOINLINE void StackToStackTest(v8::Isolate* v8_isolate,
v8::HandleScope scope(v8_isolate);
v8::Local<v8::Object> to_object(ConstructTraceableJSApiObject(
v8_isolate->GetCurrentContext(), nullptr, nullptr));
EXPECT_TRUE(InCorrectGeneration(*v8::Utils::OpenHandle(*to_object)));
EXPECT_TRUE(
IsNewObjectInCorrectGeneration(*v8::Utils::OpenHandle(*to_object)));
if (!FLAG_single_generation &&
target_handling == TargetHandling::kInitializedOldGen) {
FullGC(v8_isolate);

View File

@ -25,16 +25,17 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/handles/global-handles.h"
#include "include/v8-function.h"
#include "include/v8-locker.h"
#include "src/api/api-inl.h"
#include "src/execution/isolate.h"
#include "src/handles/global-handles.h"
#include "src/heap/factory.h"
#include "src/heap/heap-inl.h"
#include "src/objects/objects-inl.h"
#include "test/cctest/cctest.h"
#include "test/cctest/heap/heap-utils.h"
#include "test/unittests/heap/heap-utils.h"
#include "test/unittests/test-utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace v8 {
namespace internal {
@ -81,12 +82,9 @@ class NonRootingEmbedderHeapTracer final : public v8::EmbedderHeapTracer {
std::vector<TracedReferenceWrapper*> wrappers_;
};
void InvokeScavenge() { CcTest::CollectGarbage(i::NEW_SPACE); }
void InvokeMarkSweep() { CcTest::CollectAllGarbage(); }
void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
info.GetReturnValue().Set(v8_num(0));
v8::Isolate* isolate = info.GetIsolate();
info.GetReturnValue().Set(v8::Number::New(isolate, 0));
}
struct FlagAndGlobal {
@ -154,7 +152,7 @@ void WeakHandleTest(v8::Isolate* isolate, ConstructFunction construct_function,
FlagAndGlobal fp;
construct_function(isolate, context, &fp);
CHECK(heap::InCorrectGeneration(isolate, fp.handle));
CHECK(IsNewObjectInCorrectGeneration(isolate, fp.handle));
fp.handle.SetWeak(&fp, &ResetHandleAndSetFlag,
v8::WeakCallbackType::kParameter);
fp.flag = false;
@ -164,42 +162,44 @@ void WeakHandleTest(v8::Isolate* isolate, ConstructFunction construct_function,
CHECK_IMPLIES(survives == SurvivalMode::kDies, fp.flag);
}
template <typename ConstructFunction, typename ModifierFunction>
void TracedReferenceTestWithScavenge(v8::Isolate* isolate,
ConstructFunction construct_function,
ModifierFunction modifier_function,
SurvivalMode survives) {
v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
NonRootingEmbedderHeapTracer tracer;
heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
auto fp = std::make_unique<TracedReferenceWrapper>();
tracer.Register(fp.get());
construct_function(isolate, context, fp.get());
CHECK(heap::InCorrectGeneration(isolate, fp->handle));
modifier_function(fp.get());
InvokeScavenge();
// Scavenge clear properly resets the original handle, so we can check the
// handle directly here.
CHECK_IMPLIES(survives == SurvivalMode::kSurvives, !fp->handle.IsEmpty());
CHECK_IMPLIES(survives == SurvivalMode::kDies, fp->handle.IsEmpty());
}
void EmptyWeakCallback(const v8::WeakCallbackInfo<void>& data) {}
class GlobalHandlesTest : public TestWithContext {
protected:
template <typename ConstructFunction, typename ModifierFunction>
void TracedReferenceTestWithScavenge(ConstructFunction construct_function,
ModifierFunction modifier_function,
SurvivalMode survives) {
v8::Isolate* isolate = v8_isolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
NonRootingEmbedderHeapTracer tracer;
TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
auto fp = std::make_unique<TracedReferenceWrapper>();
tracer.Register(fp.get());
construct_function(isolate, context, fp.get());
CHECK(IsNewObjectInCorrectGeneration(isolate, fp->handle));
modifier_function(fp.get());
CollectGarbage(i::NEW_SPACE);
// Scavenge clear properly resets the original handle, so we can check the
// handle directly here.
CHECK_IMPLIES(survives == SurvivalMode::kSurvives, !fp->handle.IsEmpty());
CHECK_IMPLIES(survives == SurvivalMode::kDies, fp->handle.IsEmpty());
}
};
} // namespace
TEST(EternalHandles) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
TEST_F(GlobalHandlesTest, EternalHandles) {
Isolate* isolate = i_isolate();
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
EternalHandles* eternal_handles = isolate->eternal_handles();
// Create a number of handles that will not be on a block boundary
const int kArrayLength = 2048-1;
const int kArrayLength = 2048 - 1;
int indices[kArrayLength];
v8::Eternal<v8::Value> eternals[kArrayLength];
@ -208,19 +208,20 @@ TEST(EternalHandles) {
indices[i] = -1;
HandleScope scope(isolate);
v8::Local<v8::Object> object = v8::Object::New(v8_isolate);
object->Set(v8_isolate->GetCurrentContext(), i,
v8::Integer::New(v8_isolate, i))
object
->Set(v8_isolate->GetCurrentContext(), i,
v8::Integer::New(v8_isolate, i))
.FromJust();
// Create with internal api
eternal_handles->Create(
isolate, *v8::Utils::OpenHandle(*object), &indices[i]);
eternal_handles->Create(isolate, *v8::Utils::OpenHandle(*object),
&indices[i]);
// Create with external api
CHECK(eternals[i].IsEmpty());
eternals[i].Set(v8_isolate, object);
CHECK(!eternals[i].IsEmpty());
}
CcTest::CollectAllAvailableGarbage();
CollectAllAvailableGarbage();
for (int i = 0; i < kArrayLength; i++) {
for (int j = 0; j < 2; j++) {
@ -256,10 +257,8 @@ TEST(EternalHandles) {
CHECK_EQ(2 * kArrayLength + 1, eternal_handles->handles_count());
}
TEST(PersistentBaseGetLocal) {
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
TEST_F(GlobalHandlesTest, PersistentBaseGetLocal) {
v8::Isolate* isolate = v8_isolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Object> o = v8::Object::New(isolate);
@ -273,9 +272,8 @@ TEST(PersistentBaseGetLocal) {
CHECK(v8::Local<v8::Object>::New(isolate, g) == g.Get(isolate));
}
TEST(WeakPersistentSmi) {
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
TEST_F(GlobalHandlesTest, WeakPersistentSmi) {
v8::Isolate* isolate = v8_isolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Number> n = v8::Number::New(isolate, 0);
@ -288,9 +286,8 @@ TEST(WeakPersistentSmi) {
START_ALLOW_USE_DEPRECATED()
TEST(PhantomHandlesWithoutCallbacks) {
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
TEST_F(GlobalHandlesTest, PhantomHandlesWithoutCallbacks) {
v8::Isolate* isolate = v8_isolate();
v8::Global<v8::Object> g1, g2;
{
@ -302,129 +299,127 @@ TEST(PhantomHandlesWithoutCallbacks) {
}
CHECK(!g1.IsEmpty());
CHECK(!g2.IsEmpty());
CcTest::CollectAllAvailableGarbage();
CollectAllAvailableGarbage();
CHECK(g1.IsEmpty());
CHECK(g2.IsEmpty());
}
END_ALLOW_USE_DEPRECATED()
TEST(WeakHandleToUnmodifiedJSObjectDiesOnScavenge) {
TEST_F(GlobalHandlesTest, WeakHandleToUnmodifiedJSObjectDiesOnScavenge) {
if (FLAG_single_generation) return;
CcTest::InitializeVM();
WeakHandleTest(
CcTest::isolate(), &ConstructJSObject<FlagAndGlobal>,
[](FlagAndGlobal* fp) {}, []() { InvokeScavenge(); },
SurvivalMode::kDies);
v8_isolate(), &ConstructJSObject<FlagAndGlobal>, [](FlagAndGlobal* fp) {},
[this]() { CollectGarbage(i::NEW_SPACE); }, SurvivalMode::kDies);
}
TEST(TracedReferenceToUnmodifiedJSObjectSurvivesScavenge) {
TEST_F(GlobalHandlesTest, TracedReferenceToUnmodifiedJSObjectSurvivesScavenge) {
if (FLAG_single_generation) return;
ManualGCScope manual_gc;
CcTest::InitializeVM();
ManualGCScope manual_gc(i_isolate());
TracedReferenceTestWithScavenge(
CcTest::isolate(), &ConstructJSObject<TracedReferenceWrapper>,
&ConstructJSObject<TracedReferenceWrapper>,
[](TracedReferenceWrapper* fp) {}, SurvivalMode::kSurvives);
}
TEST(WeakHandleToUnmodifiedJSObjectDiesOnMarkCompact) {
CcTest::InitializeVM();
TEST_F(GlobalHandlesTest, WeakHandleToUnmodifiedJSObjectDiesOnMarkCompact) {
WeakHandleTest(
CcTest::isolate(), &ConstructJSObject<FlagAndGlobal>,
[](FlagAndGlobal* fp) {}, []() { InvokeMarkSweep(); },
SurvivalMode::kDies);
v8_isolate(), &ConstructJSObject<FlagAndGlobal>, [](FlagAndGlobal* fp) {},
[this]() { CollectAllGarbage(); }, SurvivalMode::kDies);
}
TEST(WeakHandleToUnmodifiedJSObjectSurvivesMarkCompactWhenInHandle) {
CcTest::InitializeVM();
TEST_F(GlobalHandlesTest,
WeakHandleToUnmodifiedJSObjectSurvivesMarkCompactWhenInHandle) {
WeakHandleTest(
CcTest::isolate(), &ConstructJSObject<FlagAndGlobal>,
[](FlagAndGlobal* fp) {
v8_isolate(), &ConstructJSObject<FlagAndGlobal>,
[this](FlagAndGlobal* fp) {
v8::Local<v8::Object> handle =
v8::Local<v8::Object>::New(CcTest::isolate(), fp->handle);
v8::Local<v8::Object>::New(v8_isolate(), fp->handle);
USE(handle);
},
[]() { InvokeMarkSweep(); }, SurvivalMode::kSurvives);
[this]() { CollectAllGarbage(); }, SurvivalMode::kSurvives);
}
TEST(WeakHandleToUnmodifiedJSApiObjectDiesOnScavenge) {
TEST_F(GlobalHandlesTest, WeakHandleToUnmodifiedJSApiObjectDiesOnScavenge) {
if (FLAG_single_generation) return;
CcTest::InitializeVM();
WeakHandleTest(
CcTest::isolate(), &ConstructJSApiObject<FlagAndGlobal>,
[](FlagAndGlobal* fp) {}, []() { InvokeScavenge(); },
v8_isolate(), &ConstructJSApiObject<FlagAndGlobal>,
[](FlagAndGlobal* fp) {}, [this]() { CollectGarbage(i::NEW_SPACE); },
SurvivalMode::kDies);
}
TEST(TracedReferenceToUnmodifiedJSApiObjectDiesOnScavenge) {
TEST_F(GlobalHandlesTest,
TracedReferenceToUnmodifiedJSApiObjectDiesOnScavenge) {
if (FLAG_single_generation) return;
ManualGCScope manual_gc;
CcTest::InitializeVM();
ManualGCScope manual_gc(i_isolate());
TracedReferenceTestWithScavenge(
CcTest::isolate(), &ConstructJSApiObject<TracedReferenceWrapper>,
&ConstructJSApiObject<TracedReferenceWrapper>,
[](TracedReferenceWrapper* fp) {}, SurvivalMode::kDies);
}
TEST(TracedReferenceToJSApiObjectWithIdentityHashSurvivesScavenge) {
TEST_F(GlobalHandlesTest,
TracedReferenceToJSApiObjectWithIdentityHashSurvivesScavenge) {
if (FLAG_single_generation) return;
ManualGCScope manual_gc;
CcTest::InitializeVM();
Isolate* i_isolate = CcTest::i_isolate();
HandleScope scope(i_isolate);
Handle<JSWeakMap> weakmap = i_isolate->factory()->NewJSWeakMap();
ManualGCScope manual_gc(i_isolate());
Isolate* isolate = i_isolate();
HandleScope scope(isolate);
Handle<JSWeakMap> weakmap = isolate->factory()->NewJSWeakMap();
TracedReferenceTestWithScavenge(
CcTest::isolate(), &ConstructJSApiObject<TracedReferenceWrapper>,
[&weakmap, i_isolate](TracedReferenceWrapper* fp) {
v8::HandleScope scope(CcTest::isolate());
&ConstructJSApiObject<TracedReferenceWrapper>,
[this, &weakmap, isolate](TracedReferenceWrapper* fp) {
v8::HandleScope scope(v8_isolate());
Handle<JSReceiver> key =
Utils::OpenHandle(*fp->handle.Get(CcTest::isolate()));
Handle<Smi> smi(Smi::FromInt(23), i_isolate);
int32_t hash = key->GetOrCreateHash(i_isolate).value();
Utils::OpenHandle(*fp->handle.Get(v8_isolate()));
Handle<Smi> smi(Smi::FromInt(23), isolate);
int32_t hash = key->GetOrCreateHash(isolate).value();
JSWeakCollection::Set(weakmap, key, smi, hash);
},
SurvivalMode::kSurvives);
}
TEST(WeakHandleToUnmodifiedJSApiObjectSurvivesScavengeWhenInHandle) {
TEST_F(GlobalHandlesTest,
WeakHandleToUnmodifiedJSApiObjectSurvivesScavengeWhenInHandle) {
if (FLAG_single_generation) return;
CcTest::InitializeVM();
WeakHandleTest(
CcTest::isolate(), &ConstructJSApiObject<FlagAndGlobal>,
[](FlagAndGlobal* fp) {
v8_isolate(), &ConstructJSApiObject<FlagAndGlobal>,
[this](FlagAndGlobal* fp) {
v8::Local<v8::Object> handle =
v8::Local<v8::Object>::New(CcTest::isolate(), fp->handle);
v8::Local<v8::Object>::New(v8_isolate(), fp->handle);
USE(handle);
},
[]() { InvokeScavenge(); }, SurvivalMode::kSurvives);
[this]() { CollectGarbage(i::NEW_SPACE); }, SurvivalMode::kSurvives);
}
TEST(WeakHandleToUnmodifiedJSApiObjectDiesOnMarkCompact) {
CcTest::InitializeVM();
TEST_F(GlobalHandlesTest, WeakHandleToUnmodifiedJSApiObjectDiesOnMarkCompact) {
WeakHandleTest(
CcTest::isolate(), &ConstructJSApiObject<FlagAndGlobal>,
[](FlagAndGlobal* fp) {}, []() { InvokeMarkSweep(); },
v8_isolate(), &ConstructJSApiObject<FlagAndGlobal>,
[](FlagAndGlobal* fp) {}, [this]() { CollectAllGarbage(); },
SurvivalMode::kDies);
}
TEST(WeakHandleToUnmodifiedJSApiObjectSurvivesMarkCompactWhenInHandle) {
CcTest::InitializeVM();
TEST_F(GlobalHandlesTest,
WeakHandleToUnmodifiedJSApiObjectSurvivesMarkCompactWhenInHandle) {
WeakHandleTest(
CcTest::isolate(), &ConstructJSApiObject<FlagAndGlobal>,
[](FlagAndGlobal* fp) {
v8_isolate(), &ConstructJSApiObject<FlagAndGlobal>,
[this](FlagAndGlobal* fp) {
v8::Local<v8::Object> handle =
v8::Local<v8::Object>::New(CcTest::isolate(), fp->handle);
v8::Local<v8::Object>::New(v8_isolate(), fp->handle);
USE(handle);
},
[]() { InvokeMarkSweep(); }, SurvivalMode::kSurvives);
[this]() { CollectAllGarbage(); }, SurvivalMode::kSurvives);
}
TEST(TracedReferenceToJSApiObjectWithModifiedMapSurvivesScavenge) {
TEST_F(GlobalHandlesTest,
TracedReferenceToJSApiObjectWithModifiedMapSurvivesScavenge) {
if (FLAG_single_generation) return;
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
LocalContext context;
v8::Isolate* isolate = v8_isolate();
TracedReference<v8::Object> handle;
{
@ -434,19 +429,19 @@ TEST(TracedReferenceToJSApiObjectWithModifiedMapSurvivesScavenge) {
auto instance_t = function_template->InstanceTemplate();
instance_t->Set(isolate, "a", v8::Number::New(isolate, 10));
auto function =
function_template->GetFunction(context.local()).ToLocalChecked();
auto i = function->NewInstance(context.local()).ToLocalChecked();
function_template->GetFunction(v8_context()).ToLocalChecked();
auto i = function->NewInstance(v8_context()).ToLocalChecked();
handle.Reset(isolate, i);
}
InvokeScavenge();
CollectGarbage(i::NEW_SPACE);
CHECK(!handle.IsEmpty());
}
TEST(TracedReferenceTOJsApiObjectWithElementsSurvivesScavenge) {
TEST_F(GlobalHandlesTest,
TracedReferenceTOJsApiObjectWithElementsSurvivesScavenge) {
if (FLAG_single_generation) return;
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
LocalContext context;
v8::Isolate* isolate = v8_isolate();
TracedReference<v8::Object> handle;
{
@ -458,11 +453,11 @@ TEST(TracedReferenceTOJsApiObjectWithElementsSurvivesScavenge) {
instance_t->Set(isolate, "1", v8::Number::New(isolate, 10));
instance_t->Set(isolate, "2", v8::Number::New(isolate, 10));
auto function =
function_template->GetFunction(context.local()).ToLocalChecked();
auto i = function->NewInstance(context.local()).ToLocalChecked();
function_template->GetFunction(v8_context()).ToLocalChecked();
auto i = function->NewInstance(v8_context()).ToLocalChecked();
handle.Reset(isolate, i);
}
InvokeScavenge();
CollectGarbage(i::NEW_SPACE);
CHECK(!handle.IsEmpty());
}
@ -470,7 +465,7 @@ namespace {
void ForceScavenge2(const v8::WeakCallbackInfo<FlagAndGlobal>& data) {
data.GetParameter()->flag = true;
InvokeScavenge();
YoungGC(data.GetIsolate());
}
void ForceScavenge1(const v8::WeakCallbackInfo<FlagAndGlobal>& data) {
@ -480,7 +475,7 @@ void ForceScavenge1(const v8::WeakCallbackInfo<FlagAndGlobal>& data) {
void ForceMarkSweep2(const v8::WeakCallbackInfo<FlagAndGlobal>& data) {
data.GetParameter()->flag = true;
InvokeMarkSweep();
FullGC(data.GetIsolate());
}
void ForceMarkSweep1(const v8::WeakCallbackInfo<FlagAndGlobal>& data) {
@ -490,9 +485,8 @@ void ForceMarkSweep1(const v8::WeakCallbackInfo<FlagAndGlobal>& data) {
} // namespace
TEST(GCFromWeakCallbacks) {
v8::Isolate* isolate = CcTest::isolate();
v8::Locker locker(CcTest::isolate());
TEST_F(GlobalHandlesTest, GCFromWeakCallbacks) {
v8::Isolate* isolate = v8_isolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
@ -500,11 +494,11 @@ TEST(GCFromWeakCallbacks) {
if (FLAG_single_generation) {
FlagAndGlobal fp;
ConstructJSApiObject(isolate, context, &fp);
CHECK(!heap::InYoungGeneration(isolate, fp.handle));
CHECK(!InYoungGeneration(isolate, fp.handle));
fp.flag = false;
fp.handle.SetWeak(&fp, &ForceMarkSweep1, v8::WeakCallbackType::kParameter);
InvokeMarkSweep();
EmptyMessageQueues(isolate);
CollectAllGarbage();
EmptyMessageQueues();
CHECK(fp.flag);
return;
}
@ -514,19 +508,21 @@ TEST(GCFromWeakCallbacks) {
Callback gc_forcing_callback[kNumberOfGCTypes] = {&ForceScavenge1,
&ForceMarkSweep1};
using GCInvoker = void (*)();
GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
using GCInvoker = std::function<void(void)>;
GCInvoker invoke_gc[kNumberOfGCTypes] = {
[this]() { CollectGarbage(i::NEW_SPACE); },
[this]() { CollectAllGarbage(); }};
for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
FlagAndGlobal fp;
ConstructJSApiObject(isolate, context, &fp);
CHECK(heap::InYoungGeneration(isolate, fp.handle));
CHECK(InYoungGeneration(isolate, fp.handle));
fp.flag = false;
fp.handle.SetWeak(&fp, gc_forcing_callback[inner_gc],
v8::WeakCallbackType::kParameter);
invoke_gc[outer_gc]();
EmptyMessageQueues(isolate);
EmptyMessageQueues();
CHECK(fp.flag);
}
}
@ -545,9 +541,8 @@ void FirstPassCallback(const v8::WeakCallbackInfo<FlagAndGlobal>& data) {
} // namespace
TEST(SecondPassPhantomCallbacks) {
v8::Isolate* isolate = CcTest::isolate();
v8::Locker locker(CcTest::isolate());
TEST_F(GlobalHandlesTest, SecondPassPhantomCallbacks) {
v8::Isolate* isolate = v8_isolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
@ -556,72 +551,65 @@ TEST(SecondPassPhantomCallbacks) {
fp.flag = false;
fp.handle.SetWeak(&fp, FirstPassCallback, v8::WeakCallbackType::kParameter);
CHECK(!fp.flag);
InvokeMarkSweep();
InvokeMarkSweep();
CollectAllGarbage();
CollectAllGarbage();
CHECK(fp.flag);
}
TEST(MoveStrongGlobal) {
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
TEST_F(GlobalHandlesTest, MoveStrongGlobal) {
v8::Isolate* isolate = v8_isolate();
v8::HandleScope scope(isolate);
v8::Global<v8::Object>* global = new Global<v8::Object>();
ConstructJSObject(isolate, global);
InvokeMarkSweep();
CollectAllGarbage();
v8::Global<v8::Object> global2(std::move(*global));
delete global;
InvokeMarkSweep();
CollectAllGarbage();
}
TEST(MoveWeakGlobal) {
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
TEST_F(GlobalHandlesTest, MoveWeakGlobal) {
v8::Isolate* isolate = v8_isolate();
v8::HandleScope scope(isolate);
v8::Global<v8::Object>* global = new Global<v8::Object>();
ConstructJSObject(isolate, global);
InvokeMarkSweep();
CollectAllGarbage();
global->SetWeak();
v8::Global<v8::Object> global2(std::move(*global));
delete global;
InvokeMarkSweep();
CollectAllGarbage();
}
TEST(TotalSizeRegularNode) {
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
Isolate* i_isolate = CcTest::i_isolate();
TEST_F(GlobalHandlesTest, TotalSizeRegularNode) {
v8::Isolate* isolate = v8_isolate();
v8::HandleScope scope(isolate);
v8::Global<v8::Object>* global = new Global<v8::Object>();
CHECK_EQ(i_isolate->global_handles()->TotalSize(), 0);
CHECK_EQ(i_isolate->global_handles()->UsedSize(), 0);
CHECK_EQ(i_isolate()->global_handles()->TotalSize(), 0);
CHECK_EQ(i_isolate()->global_handles()->UsedSize(), 0);
ConstructJSObject(isolate, global);
CHECK_GT(i_isolate->global_handles()->TotalSize(), 0);
CHECK_GT(i_isolate->global_handles()->UsedSize(), 0);
CHECK_GT(i_isolate()->global_handles()->TotalSize(), 0);
CHECK_GT(i_isolate()->global_handles()->UsedSize(), 0);
delete global;
CHECK_GT(i_isolate->global_handles()->TotalSize(), 0);
CHECK_EQ(i_isolate->global_handles()->UsedSize(), 0);
CHECK_GT(i_isolate()->global_handles()->TotalSize(), 0);
CHECK_EQ(i_isolate()->global_handles()->UsedSize(), 0);
}
TEST(TotalSizeTracedNode) {
ManualGCScope manual_gc;
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
Isolate* i_isolate = CcTest::i_isolate();
TEST_F(GlobalHandlesTest, TotalSizeTracedNode) {
v8::Isolate* isolate = v8_isolate();
v8::HandleScope scope(isolate);
v8::TracedReference<v8::Object>* handle = new TracedReference<v8::Object>();
CHECK_EQ(i_isolate->global_handles()->TotalSize(), 0);
CHECK_EQ(i_isolate->global_handles()->UsedSize(), 0);
CHECK_EQ(i_isolate()->global_handles()->TotalSize(), 0);
CHECK_EQ(i_isolate()->global_handles()->UsedSize(), 0);
ConstructJSObject(isolate, handle);
CHECK_GT(i_isolate->global_handles()->TotalSize(), 0);
CHECK_GT(i_isolate->global_handles()->UsedSize(), 0);
CHECK_GT(i_isolate()->global_handles()->TotalSize(), 0);
CHECK_GT(i_isolate()->global_handles()->UsedSize(), 0);
delete handle;
InvokeMarkSweep();
CHECK_GT(i_isolate->global_handles()->TotalSize(), 0);
CHECK_EQ(i_isolate->global_handles()->UsedSize(), 0);
CollectAllGarbage();
CHECK_GT(i_isolate()->global_handles()->TotalSize(), 0);
CHECK_EQ(i_isolate()->global_handles()->UsedSize(), 0);
}
} // namespace internal

View File

@ -220,5 +220,10 @@ std::vector<Handle<FixedArray>> HeapInternalsBase::CreatePadding(
return handles;
}
bool IsNewObjectInCorrectGeneration(HeapObject object) {
return FLAG_single_generation ? !i::Heap::InYoungGeneration(object)
: i::Heap::InYoungGeneration(object);
}
} // namespace internal
} // namespace v8

View File

@ -99,6 +99,22 @@ class WithHeapInternals : public TMixin, HeapInternalsBase {
}
};
class V8_NODISCARD TemporaryEmbedderHeapTracerScope {
public:
TemporaryEmbedderHeapTracerScope(v8::Isolate* isolate,
v8::EmbedderHeapTracer* tracer)
: isolate_(isolate) {
isolate_->SetEmbedderHeapTracer(tracer);
}
~TemporaryEmbedderHeapTracerScope() {
isolate_->SetEmbedderHeapTracer(nullptr);
}
private:
v8::Isolate* const isolate_;
};
using TestWithHeapInternals = //
WithHeapInternals< //
WithInternalIsolateMixin< //
@ -121,6 +137,24 @@ inline void YoungGC(v8::Isolate* isolate) {
i::NEW_SPACE, i::GarbageCollectionReason::kTesting);
}
template <typename GlobalOrPersistent>
bool InYoungGeneration(v8::Isolate* isolate, const GlobalOrPersistent& global) {
CHECK(!FLAG_single_generation);
v8::HandleScope scope(isolate);
auto tmp = global.Get(isolate);
return i::Heap::InYoungGeneration(*v8::Utils::OpenHandle(*tmp));
}
bool IsNewObjectInCorrectGeneration(HeapObject object);
template <typename GlobalOrPersistent>
bool IsNewObjectInCorrectGeneration(v8::Isolate* isolate,
const GlobalOrPersistent& global) {
v8::HandleScope scope(isolate);
auto tmp = global.Get(isolate);
return IsNewObjectInCorrectGeneration(*v8::Utils::OpenHandle(*tmp));
}
} // namespace internal
} // namespace v8

View File

@ -211,6 +211,12 @@ class WithIsolateScopeMixin : public TMixin {
return v8::String::NewFromUtf8(this->v8_isolate(), string).ToLocalChecked();
}
void EmptyMessageQueues() {
while (v8::platform::PumpMessageLoop(internal::V8::GetCurrentPlatform(),
this->v8_isolate())) {
}
}
private:
Local<Value> RunJS(Local<String> source) {
return TryRunJS(source).ToLocalChecked();

View File

@ -203,6 +203,13 @@
# Performs GC
'APIExceptionTest.ExceptionMessageDoesNotKeepContextAlive': [SKIP],
'GlobalHandlesTest.FinalizerDiesAndKeepsPhantomAliveOnMarkCompact': [SKIP],
'GlobalHandlesTest.FinalizerWeakness': [SKIP],
'GlobalHandlesTest.GCFromWeakCallbacks': [SKIP],
'GlobalHandlesTest.PhantomHandlesWithoutCallbacks': [SKIP],
'GlobalHandlesTest.SecondPassPhantomCallbacks': [SKIP],
'GlobalHandlesTest.WeakHandleToUnmodifiedJSApiObjectDiesOnMarkCompact': [SKIP],
'GlobalHandlesTest.WeakHandleToUnmodifiedJSObjectDiesOnMarkCompact': [SKIP],
'LocalHeapTest.GCEpilogue': [SKIP],
'UnifiedHeapDetachedTest.AllocationBeforeConfigureHeap': [SKIP],
'UnifiedHeapTest.FindingV8ToBlinkReference': [SKIP],
@ -283,6 +290,7 @@
'BignumDtoaTest.*': [SKIP],
'DtoaTest.*': [SKIP],
'DeclsTest.*': [SKIP],
'GlobalHandlesTest.*': [SKIP],
}], # variant == no_wasm_traps
##############################################################################