|  | // 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" | 
|  |  | 
|  | namespace v8 { | 
|  | namespace internal { | 
|  |  | 
|  | TEST(EternalHandles) { | 
|  | CcTest::InitializeVM(); | 
|  | Isolate* isolate = CcTest::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; | 
|  | int indices[kArrayLength]; | 
|  | v8::Eternal<v8::Value> eternals[kArrayLength]; | 
|  |  | 
|  | CHECK_EQ(0, eternal_handles->NumberOfHandles()); | 
|  | for (int i = 0; i < kArrayLength; i++) { | 
|  | 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)) | 
|  | .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<v8::Value> 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<v8::Object> object = v8::Local<v8::Object>::Cast(local); | 
|  | v8::Local<v8::Value> 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<v8::Object> object = v8::Object::New(v8_isolate); | 
|  | v8::Eternal<v8::Object> 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<v8::Object> o = v8::Object::New(isolate); | 
|  | CHECK(!o.IsEmpty()); | 
|  | v8::Persistent<v8::Object> p(isolate, o); | 
|  | CHECK(o == p.Get(isolate)); | 
|  | CHECK(v8::Local<v8::Object>::New(isolate, p) == p.Get(isolate)); | 
|  |  | 
|  | v8::Global<v8::Object> g(isolate, o); | 
|  | CHECK(o == g.Get(isolate)); | 
|  | CHECK(v8::Local<v8::Object>::New(isolate, g) == g.Get(isolate)); | 
|  | } | 
|  |  | 
|  |  | 
|  | void WeakCallback(const v8::WeakCallbackInfo<void>& data) {} | 
|  |  | 
|  |  | 
|  | TEST(WeakPersistentSmi) { | 
|  | CcTest::InitializeVM(); | 
|  | v8::Isolate* isolate = CcTest::isolate(); | 
|  |  | 
|  | v8::HandleScope scope(isolate); | 
|  | v8::Local<v8::Number> n = v8::Number::New(isolate, 0); | 
|  | v8::Global<v8::Number> g(isolate, n); | 
|  |  | 
|  | // Should not crash. | 
|  | g.SetWeak<void>(nullptr, &WeakCallback, v8::WeakCallbackType::kParameter); | 
|  | } | 
|  |  | 
|  | void finalizer(const v8::WeakCallbackInfo<v8::Global<v8::Object>>& data) { | 
|  | data.GetParameter()->ClearWeak(); | 
|  | v8::Local<v8::Object> o = | 
|  | v8::Local<v8::Object>::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<v8::Object> g; | 
|  | int identity; | 
|  |  | 
|  | { | 
|  | v8::HandleScope scope(isolate); | 
|  | v8::Local<v8::Object> 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<v8::Object> o = v8::Local<v8::Object>::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<v8::Object> 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()); | 
|  | } | 
|  |  | 
|  | }  // namespace internal | 
|  | }  // namespace v8 |