// Copyright 2013 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (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/api.h" #include "src/factory.h" #include "src/global-handles.h" #include "src/isolate.h" #include "src/objects-inl.h" #include "src/objects.h" #include "test/cctest/cctest.h" using namespace v8::internal; TEST(EternalHandles) { CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); v8::Isolate* v8_isolate = reinterpret_cast(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; int indices[kArrayLength]; v8::Eternal eternals[kArrayLength]; CHECK_EQ(0, eternal_handles->NumberOfHandles()); for (int i = 0; i < kArrayLength; i++) { indices[i] = -1; HandleScope scope(isolate); v8::Local object = v8::Object::New(v8_isolate); 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]); // Create with external api CHECK(eternals[i].IsEmpty()); eternals[i].Set(v8_isolate, object); CHECK(!eternals[i].IsEmpty()); } CcTest::CollectAllAvailableGarbage(); for (int i = 0; i < kArrayLength; i++) { for (int j = 0; j < 2; j++) { HandleScope scope(isolate); v8::Local local; if (j == 0) { // Test internal api local = v8::Utils::ToLocal(eternal_handles->Get(indices[i])); } else { // Test external api local = eternals[i].Get(v8_isolate); } v8::Local object = v8::Local::Cast(local); v8::Local value = object->Get(v8_isolate->GetCurrentContext(), i).ToLocalChecked(); CHECK(value->IsInt32()); CHECK_EQ(i, value->Int32Value(v8_isolate->GetCurrentContext()).FromJust()); } } CHECK_EQ(2*kArrayLength, eternal_handles->NumberOfHandles()); // Create an eternal via the constructor { HandleScope scope(isolate); v8::Local object = v8::Object::New(v8_isolate); v8::Eternal eternal(v8_isolate, object); CHECK(!eternal.IsEmpty()); CHECK(object == eternal.Get(v8_isolate)); } CHECK_EQ(2*kArrayLength + 1, eternal_handles->NumberOfHandles()); } TEST(PersistentBaseGetLocal) { CcTest::InitializeVM(); v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); v8::Local o = v8::Object::New(isolate); CHECK(!o.IsEmpty()); v8::Persistent p(isolate, o); CHECK(o == p.Get(isolate)); CHECK(v8::Local::New(isolate, p) == p.Get(isolate)); v8::Global g(isolate, o); CHECK(o == g.Get(isolate)); CHECK(v8::Local::New(isolate, g) == g.Get(isolate)); } void WeakCallback(const v8::WeakCallbackInfo& data) {} TEST(WeakPersistentSmi) { CcTest::InitializeVM(); v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); v8::Local n = v8::Number::New(isolate, 0); v8::Global g(isolate, n); // Should not crash. g.SetWeak(nullptr, &WeakCallback, v8::WeakCallbackType::kParameter); } void finalizer(const v8::WeakCallbackInfo>& data) { data.GetParameter()->ClearWeak(); v8::Local o = v8::Local::New(data.GetIsolate(), *data.GetParameter()); o->Set(data.GetIsolate()->GetCurrentContext(), v8_str("finalizer"), v8_str("was here")) .FromJust(); } TEST(FinalizerWeakness) { CcTest::InitializeVM(); v8::Isolate* isolate = CcTest::isolate(); v8::Global g; int identity; { v8::HandleScope scope(isolate); v8::Local o = v8::Object::New(isolate); identity = o->GetIdentityHash(); g.Reset(isolate, o); g.SetWeak(&g, finalizer, v8::WeakCallbackType::kFinalizer); } CcTest::CollectAllAvailableGarbage(); CHECK(!g.IsEmpty()); v8::HandleScope scope(isolate); v8::Local o = v8::Local::New(isolate, g); CHECK_EQ(identity, o->GetIdentityHash()); CHECK(o->Has(isolate->GetCurrentContext(), v8_str("finalizer")).FromJust()); } TEST(PhatomHandlesWithoutCallbacks) { CcTest::InitializeVM(); v8::Isolate* isolate = CcTest::isolate(); v8::Global g1, g2; { v8::HandleScope scope(isolate); g1.Reset(isolate, v8::Object::New(isolate)); g1.SetWeak(); g2.Reset(isolate, v8::Object::New(isolate)); g2.SetWeak(); } CHECK_EQ(0u, isolate->NumberOfPhantomHandleResetsSinceLastCall()); CcTest::CollectAllAvailableGarbage(); CHECK_EQ(2u, isolate->NumberOfPhantomHandleResetsSinceLastCall()); CHECK_EQ(0u, isolate->NumberOfPhantomHandleResetsSinceLastCall()); }