| Index: test/cctest/test-api.cc
|
| diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
|
| index 5edbda777cb49473185e3bcdedf28338be0be0eb..0ef1e65e3075ecbe371a9b7b2223ccbb924af92f 100644
|
| --- a/test/cctest/test-api.cc
|
| +++ b/test/cctest/test-api.cc
|
| @@ -3099,6 +3099,131 @@ THREADED_TEST(Global) {
|
| }
|
|
|
|
|
| +namespace {
|
| +
|
| +class TwoPassCallbackData;
|
| +void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
|
| +void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
|
| +
|
| +
|
| +class TwoPassCallbackData {
|
| + public:
|
| + TwoPassCallbackData(v8::Isolate* isolate, int* instance_counter)
|
| + : first_pass_called_(false),
|
| + second_pass_called_(false),
|
| + trigger_gc_(false),
|
| + instance_counter_(instance_counter) {
|
| + HandleScope scope(isolate);
|
| + i::ScopedVector<char> buffer(40);
|
| + i::SNPrintF(buffer, "%p", this);
|
| + auto string =
|
| + v8::String::NewFromUtf8(isolate, buffer.start(),
|
| + v8::NewStringType::kNormal).ToLocalChecked();
|
| + cell_.Reset(isolate, string);
|
| + (*instance_counter_)++;
|
| + }
|
| +
|
| + ~TwoPassCallbackData() {
|
| + CHECK(first_pass_called_);
|
| + CHECK(second_pass_called_);
|
| + CHECK(cell_.IsEmpty());
|
| + (*instance_counter_)--;
|
| + }
|
| +
|
| + void FirstPass() {
|
| + CHECK(!first_pass_called_);
|
| + CHECK(!second_pass_called_);
|
| + CHECK(!cell_.IsEmpty());
|
| + cell_.Reset();
|
| + first_pass_called_ = true;
|
| + }
|
| +
|
| + void SecondPass() {
|
| + CHECK(first_pass_called_);
|
| + CHECK(!second_pass_called_);
|
| + CHECK(cell_.IsEmpty());
|
| + second_pass_called_ = true;
|
| + delete this;
|
| + }
|
| +
|
| + void SetWeak() {
|
| + cell_.SetWeak(this, FirstPassCallback, v8::WeakCallbackType::kParameter);
|
| + }
|
| +
|
| + void MarkTriggerGc() { trigger_gc_ = true; }
|
| + bool trigger_gc() { return trigger_gc_; }
|
| +
|
| + int* instance_counter() { return instance_counter_; }
|
| +
|
| + private:
|
| + bool first_pass_called_;
|
| + bool second_pass_called_;
|
| + bool trigger_gc_;
|
| + v8::Global<v8::String> cell_;
|
| + int* instance_counter_;
|
| +};
|
| +
|
| +
|
| +void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
|
| + ApiTestFuzzer::Fuzz();
|
| + bool trigger_gc = data.GetParameter()->trigger_gc();
|
| + int* instance_counter = data.GetParameter()->instance_counter();
|
| + data.GetParameter()->SecondPass();
|
| + if (!trigger_gc) return;
|
| + auto data_2 = new TwoPassCallbackData(data.GetIsolate(), instance_counter);
|
| + data_2->SetWeak();
|
| + CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
|
| +}
|
| +
|
| +
|
| +void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
|
| + data.GetParameter()->FirstPass();
|
| + data.SetSecondPassCallback(SecondPassCallback);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +
|
| +THREADED_TEST(TwoPassPhantomCallbacks) {
|
| + auto isolate = CcTest::isolate();
|
| + const size_t kLength = 20;
|
| + auto global_handles =
|
| + reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
|
| + int instance_counter = 0;
|
| + int initial_handle_count = global_handles->global_handles_count();
|
| + for (size_t i = 0; i < kLength; ++i) {
|
| + auto data = new TwoPassCallbackData(isolate, &instance_counter);
|
| + data->SetWeak();
|
| + }
|
| + CHECK_EQ(static_cast<int>(kLength), instance_counter);
|
| + CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
|
| + CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
|
| + CHECK_EQ(0, instance_counter);
|
| +}
|
| +
|
| +
|
| +THREADED_TEST(TwoPassPhantomCallbacksNestedGc) {
|
| + auto isolate = CcTest::isolate();
|
| + const size_t kLength = 20;
|
| + TwoPassCallbackData* array[kLength];
|
| + v8::internal::GlobalHandles* global_handles =
|
| + reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
|
| + int instance_counter = 0;
|
| + int initial_handle_count = global_handles->global_handles_count();
|
| + for (size_t i = 0; i < kLength; ++i) {
|
| + array[i] = new TwoPassCallbackData(isolate, &instance_counter);
|
| + array[i]->SetWeak();
|
| + }
|
| + array[5]->MarkTriggerGc();
|
| + array[10]->MarkTriggerGc();
|
| + array[15]->MarkTriggerGc();
|
| + CHECK_EQ(static_cast<int>(kLength), instance_counter);
|
| + CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
|
| + CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
|
| + CHECK_EQ(0, instance_counter);
|
| +}
|
| +
|
| +
|
| template <typename K, typename V>
|
| class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
|
| public:
|
| @@ -3242,6 +3367,7 @@ class PhantomStdMapTraits : public v8::StdMapTraits<K, V> {
|
| v8::Isolate* isolate,
|
| const v8::WeakCallbackInfo<WeakCallbackDataType>& info, K key) {
|
| CHECK_EQ(IntKeyToVoidPointer(key), info.GetInternalField(0));
|
| + DisposeCallbackData(info.GetParameter());
|
| }
|
| };
|
| }
|
|
|