| // 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 |