| // 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 <stdlib.h> |
| |
| #include "src/v8.h" |
| |
| #include "src/crankshaft/unique.h" |
| #include "src/factory.h" |
| #include "src/global-handles.h" |
| #include "test/cctest/cctest.h" |
| |
| using namespace v8::internal; |
| |
| #define MAKE_HANDLES_AND_DISALLOW_ALLOCATION \ |
| Isolate* isolate = CcTest::i_isolate(); \ |
| Factory* factory = isolate->factory(); \ |
| HandleScope sc(isolate); \ |
| Handle<String> handles[] = { \ |
| factory->InternalizeUtf8String("A"), \ |
| factory->InternalizeUtf8String("B"), \ |
| factory->InternalizeUtf8String("C"), \ |
| factory->InternalizeUtf8String("D"), \ |
| factory->InternalizeUtf8String("E"), \ |
| factory->InternalizeUtf8String("F"), \ |
| factory->InternalizeUtf8String("G") \ |
| }; \ |
| DisallowHeapAllocation _disable |
| |
| #define MAKE_UNIQUES_A_B_C \ |
| Unique<String> A(handles[0]); \ |
| Unique<String> B(handles[1]); \ |
| Unique<String> C(handles[2]) |
| |
| #define MAKE_UNIQUES_A_B_C_D_E_F_G \ |
| Unique<String> A(handles[0]); \ |
| Unique<String> B(handles[1]); \ |
| Unique<String> C(handles[2]); \ |
| Unique<String> D(handles[3]); \ |
| Unique<String> E(handles[4]); \ |
| Unique<String> F(handles[5]); \ |
| Unique<String> G(handles[6]) |
| |
| template <class T, class U> |
| void CheckHashCodeEqual(Unique<T> a, Unique<U> b) { |
| int64_t hasha = static_cast<int64_t>(a.Hashcode()); |
| int64_t hashb = static_cast<int64_t>(b.Hashcode()); |
| CHECK_NE(static_cast<int64_t>(0), hasha); |
| CHECK_NE(static_cast<int64_t>(0), hashb); |
| CHECK_EQ(hasha, hashb); |
| } |
| |
| |
| template <class T, class U> |
| void CheckHashCodeNotEqual(Unique<T> a, Unique<U> b) { |
| int64_t hasha = static_cast<int64_t>(a.Hashcode()); |
| int64_t hashb = static_cast<int64_t>(b.Hashcode()); |
| CHECK_NE(static_cast<int64_t>(0), hasha); |
| CHECK_NE(static_cast<int64_t>(0), hashb); |
| CHECK_NE(hasha, hashb); |
| } |
| |
| |
| TEST(UniqueCreate) { |
| CcTest::InitializeVM(); |
| MAKE_HANDLES_AND_DISALLOW_ALLOCATION; |
| Handle<String> A = handles[0], B = handles[1]; |
| |
| Unique<String> HA(A); |
| |
| CHECK(*HA.handle() == *A); |
| CHECK_EQ(*A, *HA.handle()); |
| |
| Unique<String> HA2(A); |
| |
| CheckHashCodeEqual(HA, HA2); |
| CHECK(HA == HA2); |
| CHECK_EQ(*HA.handle(), *HA2.handle()); |
| |
| CHECK(HA2 == HA); |
| CHECK_EQ(*HA2.handle(), *HA.handle()); |
| |
| Unique<String> HB(B); |
| |
| CheckHashCodeNotEqual(HA, HB); |
| CHECK(HA != HB); |
| CHECK_NE(*HA.handle(), *HB.handle()); |
| |
| CHECK(HB != HA); |
| CHECK_NE(*HB.handle(), *HA.handle()); |
| |
| // TODO(titzer): check that Unique properly survives a GC. |
| } |
| |
| |
| TEST(UniqueSubsume) { |
| CcTest::InitializeVM(); |
| MAKE_HANDLES_AND_DISALLOW_ALLOCATION; |
| Handle<String> A = handles[0]; |
| |
| Unique<String> HA(A); |
| |
| CHECK(*HA.handle() == *A); |
| CHECK_EQ(*A, *HA.handle()); |
| |
| Unique<Object> HO = HA; // Here comes the subsumption, boys. |
| |
| CheckHashCodeEqual(HA, HO); |
| CHECK(HA == HO); |
| CHECK_EQ(*HA.handle(), *HO.handle()); |
| |
| CHECK(HO == HA); |
| CHECK_EQ(*HO.handle(), *HA.handle()); |
| } |
| |
| |
| TEST(UniqueSet_Add) { |
| CcTest::InitializeVM(); |
| MAKE_HANDLES_AND_DISALLOW_ALLOCATION; |
| MAKE_UNIQUES_A_B_C; |
| |
| Zone zone(CcTest::i_isolate()->allocator()); |
| |
| UniqueSet<String>* set = new(&zone) UniqueSet<String>(); |
| |
| CHECK_EQ(0, set->size()); |
| set->Add(A, &zone); |
| CHECK_EQ(1, set->size()); |
| set->Add(A, &zone); |
| CHECK_EQ(1, set->size()); |
| set->Add(B, &zone); |
| CHECK_EQ(2, set->size()); |
| set->Add(C, &zone); |
| CHECK_EQ(3, set->size()); |
| set->Add(C, &zone); |
| CHECK_EQ(3, set->size()); |
| set->Add(B, &zone); |
| CHECK_EQ(3, set->size()); |
| set->Add(A, &zone); |
| CHECK_EQ(3, set->size()); |
| } |
| |
| |
| TEST(UniqueSet_Remove) { |
| CcTest::InitializeVM(); |
| MAKE_HANDLES_AND_DISALLOW_ALLOCATION; |
| MAKE_UNIQUES_A_B_C; |
| |
| Zone zone(CcTest::i_isolate()->allocator()); |
| |
| UniqueSet<String>* set = new(&zone) UniqueSet<String>(); |
| |
| set->Add(A, &zone); |
| set->Add(B, &zone); |
| set->Add(C, &zone); |
| CHECK_EQ(3, set->size()); |
| |
| set->Remove(A); |
| CHECK_EQ(2, set->size()); |
| CHECK(!set->Contains(A)); |
| CHECK(set->Contains(B)); |
| CHECK(set->Contains(C)); |
| |
| set->Remove(A); |
| CHECK_EQ(2, set->size()); |
| CHECK(!set->Contains(A)); |
| CHECK(set->Contains(B)); |
| CHECK(set->Contains(C)); |
| |
| set->Remove(B); |
| CHECK_EQ(1, set->size()); |
| CHECK(!set->Contains(A)); |
| CHECK(!set->Contains(B)); |
| CHECK(set->Contains(C)); |
| |
| set->Remove(C); |
| CHECK_EQ(0, set->size()); |
| CHECK(!set->Contains(A)); |
| CHECK(!set->Contains(B)); |
| CHECK(!set->Contains(C)); |
| } |
| |
| |
| TEST(UniqueSet_Contains) { |
| CcTest::InitializeVM(); |
| MAKE_HANDLES_AND_DISALLOW_ALLOCATION; |
| MAKE_UNIQUES_A_B_C; |
| |
| Zone zone(CcTest::i_isolate()->allocator()); |
| |
| UniqueSet<String>* set = new(&zone) UniqueSet<String>(); |
| |
| CHECK_EQ(0, set->size()); |
| set->Add(A, &zone); |
| CHECK(set->Contains(A)); |
| CHECK(!set->Contains(B)); |
| CHECK(!set->Contains(C)); |
| |
| set->Add(A, &zone); |
| CHECK(set->Contains(A)); |
| CHECK(!set->Contains(B)); |
| CHECK(!set->Contains(C)); |
| |
| set->Add(B, &zone); |
| CHECK(set->Contains(A)); |
| CHECK(set->Contains(B)); |
| |
| set->Add(C, &zone); |
| CHECK(set->Contains(A)); |
| CHECK(set->Contains(B)); |
| CHECK(set->Contains(C)); |
| } |
| |
| |
| TEST(UniqueSet_At) { |
| CcTest::InitializeVM(); |
| MAKE_HANDLES_AND_DISALLOW_ALLOCATION; |
| MAKE_UNIQUES_A_B_C; |
| |
| Zone zone(CcTest::i_isolate()->allocator()); |
| |
| UniqueSet<String>* set = new(&zone) UniqueSet<String>(); |
| |
| CHECK_EQ(0, set->size()); |
| set->Add(A, &zone); |
| CHECK(A == set->at(0)); |
| |
| set->Add(A, &zone); |
| CHECK(A == set->at(0)); |
| |
| set->Add(B, &zone); |
| CHECK(A == set->at(0) || B == set->at(0)); |
| CHECK(A == set->at(1) || B == set->at(1)); |
| |
| set->Add(C, &zone); |
| CHECK(A == set->at(0) || B == set->at(0) || C == set->at(0)); |
| CHECK(A == set->at(1) || B == set->at(1) || C == set->at(1)); |
| CHECK(A == set->at(2) || B == set->at(2) || C == set->at(2)); |
| } |
| |
| |
| template <class T> |
| static void CHECK_SETS( |
| UniqueSet<T>* set1, UniqueSet<T>* set2, bool expected) { |
| CHECK(set1->Equals(set1)); |
| CHECK(set2->Equals(set2)); |
| CHECK(expected == set1->Equals(set2)); |
| CHECK(expected == set2->Equals(set1)); |
| } |
| |
| |
| TEST(UniqueSet_Equals) { |
| CcTest::InitializeVM(); |
| MAKE_HANDLES_AND_DISALLOW_ALLOCATION; |
| MAKE_UNIQUES_A_B_C; |
| |
| Zone zone(CcTest::i_isolate()->allocator()); |
| |
| UniqueSet<String>* set1 = new(&zone) UniqueSet<String>(); |
| UniqueSet<String>* set2 = new(&zone) UniqueSet<String>(); |
| |
| CHECK_SETS(set1, set2, true); |
| |
| set1->Add(A, &zone); |
| |
| CHECK_SETS(set1, set2, false); |
| |
| set2->Add(A, &zone); |
| |
| CHECK_SETS(set1, set2, true); |
| |
| set1->Add(B, &zone); |
| |
| CHECK_SETS(set1, set2, false); |
| |
| set2->Add(C, &zone); |
| |
| CHECK_SETS(set1, set2, false); |
| |
| set1->Add(C, &zone); |
| |
| CHECK_SETS(set1, set2, false); |
| |
| set2->Add(B, &zone); |
| |
| CHECK_SETS(set1, set2, true); |
| } |
| |
| |
| TEST(UniqueSet_IsSubset1) { |
| CcTest::InitializeVM(); |
| MAKE_HANDLES_AND_DISALLOW_ALLOCATION; |
| MAKE_UNIQUES_A_B_C; |
| |
| Zone zone(CcTest::i_isolate()->allocator()); |
| |
| UniqueSet<String>* set1 = new(&zone) UniqueSet<String>(); |
| UniqueSet<String>* set2 = new(&zone) UniqueSet<String>(); |
| |
| CHECK(set1->IsSubset(set2)); |
| CHECK(set2->IsSubset(set1)); |
| |
| set1->Add(A, &zone); |
| |
| CHECK(!set1->IsSubset(set2)); |
| CHECK(set2->IsSubset(set1)); |
| |
| set2->Add(B, &zone); |
| |
| CHECK(!set1->IsSubset(set2)); |
| CHECK(!set2->IsSubset(set1)); |
| |
| set2->Add(A, &zone); |
| |
| CHECK(set1->IsSubset(set2)); |
| CHECK(!set2->IsSubset(set1)); |
| |
| set1->Add(B, &zone); |
| |
| CHECK(set1->IsSubset(set2)); |
| CHECK(set2->IsSubset(set1)); |
| } |
| |
| |
| TEST(UniqueSet_IsSubset2) { |
| CcTest::InitializeVM(); |
| MAKE_HANDLES_AND_DISALLOW_ALLOCATION; |
| MAKE_UNIQUES_A_B_C_D_E_F_G; |
| |
| Zone zone(CcTest::i_isolate()->allocator()); |
| |
| UniqueSet<String>* set1 = new(&zone) UniqueSet<String>(); |
| UniqueSet<String>* set2 = new(&zone) UniqueSet<String>(); |
| |
| set1->Add(A, &zone); |
| set1->Add(C, &zone); |
| set1->Add(E, &zone); |
| |
| set2->Add(A, &zone); |
| set2->Add(B, &zone); |
| set2->Add(C, &zone); |
| set2->Add(D, &zone); |
| set2->Add(E, &zone); |
| set2->Add(F, &zone); |
| |
| CHECK(set1->IsSubset(set2)); |
| CHECK(!set2->IsSubset(set1)); |
| |
| set1->Add(G, &zone); |
| |
| CHECK(!set1->IsSubset(set2)); |
| CHECK(!set2->IsSubset(set1)); |
| } |
| |
| |
| template <class T> |
| static UniqueSet<T>* MakeSet(Zone* zone, int which, Unique<T>* elements) { |
| UniqueSet<T>* set = new(zone) UniqueSet<T>(); |
| for (int i = 0; i < 32; i++) { |
| if ((which & (1 << i)) != 0) set->Add(elements[i], zone); |
| } |
| return set; |
| } |
| |
| |
| TEST(UniqueSet_IsSubsetExhaustive) { |
| const int kSetSize = 6; |
| |
| CcTest::InitializeVM(); |
| MAKE_HANDLES_AND_DISALLOW_ALLOCATION; |
| MAKE_UNIQUES_A_B_C_D_E_F_G; |
| |
| Zone zone(CcTest::i_isolate()->allocator()); |
| |
| Unique<String> elements[] = { |
| A, B, C, D, E, F, G |
| }; |
| |
| // Exhaustively test all sets with <= 6 elements. |
| for (int i = 0; i < (1 << kSetSize); i++) { |
| for (int j = 0; j < (1 << kSetSize); j++) { |
| UniqueSet<String>* set1 = MakeSet(&zone, i, elements); |
| UniqueSet<String>* set2 = MakeSet(&zone, j, elements); |
| |
| CHECK(((i & j) == i) == set1->IsSubset(set2)); |
| } |
| } |
| } |
| |
| |
| TEST(UniqueSet_Intersect1) { |
| CcTest::InitializeVM(); |
| MAKE_HANDLES_AND_DISALLOW_ALLOCATION; |
| MAKE_UNIQUES_A_B_C; |
| |
| Zone zone(CcTest::i_isolate()->allocator()); |
| |
| UniqueSet<String>* set1 = new(&zone) UniqueSet<String>(); |
| UniqueSet<String>* set2 = new(&zone) UniqueSet<String>(); |
| UniqueSet<String>* result; |
| |
| CHECK(set1->IsSubset(set2)); |
| CHECK(set2->IsSubset(set1)); |
| |
| set1->Add(A, &zone); |
| |
| result = set1->Intersect(set2, &zone); |
| |
| CHECK_EQ(0, result->size()); |
| CHECK(set2->Equals(result)); |
| |
| set2->Add(A, &zone); |
| |
| result = set1->Intersect(set2, &zone); |
| |
| CHECK_EQ(1, result->size()); |
| CHECK(set1->Equals(result)); |
| CHECK(set2->Equals(result)); |
| |
| set2->Add(B, &zone); |
| set2->Add(C, &zone); |
| |
| result = set1->Intersect(set2, &zone); |
| |
| CHECK_EQ(1, result->size()); |
| CHECK(set1->Equals(result)); |
| } |
| |
| |
| TEST(UniqueSet_IntersectExhaustive) { |
| const int kSetSize = 6; |
| |
| CcTest::InitializeVM(); |
| MAKE_HANDLES_AND_DISALLOW_ALLOCATION; |
| MAKE_UNIQUES_A_B_C_D_E_F_G; |
| |
| Zone zone(CcTest::i_isolate()->allocator()); |
| |
| Unique<String> elements[] = { |
| A, B, C, D, E, F, G |
| }; |
| |
| // Exhaustively test all sets with <= 6 elements. |
| for (int i = 0; i < (1 << kSetSize); i++) { |
| for (int j = 0; j < (1 << kSetSize); j++) { |
| UniqueSet<String>* set1 = MakeSet(&zone, i, elements); |
| UniqueSet<String>* set2 = MakeSet(&zone, j, elements); |
| |
| UniqueSet<String>* result = set1->Intersect(set2, &zone); |
| UniqueSet<String>* expected = MakeSet(&zone, i & j, elements); |
| |
| CHECK(result->Equals(expected)); |
| CHECK(expected->Equals(result)); |
| } |
| } |
| } |
| |
| |
| TEST(UniqueSet_Union1) { |
| CcTest::InitializeVM(); |
| MAKE_HANDLES_AND_DISALLOW_ALLOCATION; |
| MAKE_UNIQUES_A_B_C; |
| |
| Zone zone(CcTest::i_isolate()->allocator()); |
| |
| UniqueSet<String>* set1 = new(&zone) UniqueSet<String>(); |
| UniqueSet<String>* set2 = new(&zone) UniqueSet<String>(); |
| UniqueSet<String>* result; |
| |
| CHECK(set1->IsSubset(set2)); |
| CHECK(set2->IsSubset(set1)); |
| |
| set1->Add(A, &zone); |
| |
| result = set1->Union(set2, &zone); |
| |
| CHECK_EQ(1, result->size()); |
| CHECK(set1->Equals(result)); |
| |
| set2->Add(A, &zone); |
| |
| result = set1->Union(set2, &zone); |
| |
| CHECK_EQ(1, result->size()); |
| CHECK(set1->Equals(result)); |
| CHECK(set2->Equals(result)); |
| |
| set2->Add(B, &zone); |
| set2->Add(C, &zone); |
| |
| result = set1->Union(set2, &zone); |
| |
| CHECK_EQ(3, result->size()); |
| CHECK(set2->Equals(result)); |
| } |
| |
| |
| TEST(UniqueSet_UnionExhaustive) { |
| const int kSetSize = 6; |
| |
| CcTest::InitializeVM(); |
| MAKE_HANDLES_AND_DISALLOW_ALLOCATION; |
| MAKE_UNIQUES_A_B_C_D_E_F_G; |
| |
| Zone zone(CcTest::i_isolate()->allocator()); |
| |
| Unique<String> elements[] = { |
| A, B, C, D, E, F, G |
| }; |
| |
| // Exhaustively test all sets with <= 6 elements. |
| for (int i = 0; i < (1 << kSetSize); i++) { |
| for (int j = 0; j < (1 << kSetSize); j++) { |
| UniqueSet<String>* set1 = MakeSet(&zone, i, elements); |
| UniqueSet<String>* set2 = MakeSet(&zone, j, elements); |
| |
| UniqueSet<String>* result = set1->Union(set2, &zone); |
| UniqueSet<String>* expected = MakeSet(&zone, i | j, elements); |
| |
| CHECK(result->Equals(expected)); |
| CHECK(expected->Equals(result)); |
| } |
| } |
| } |