OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "src/v8.h" |
| 6 |
| 7 #include "src/factory.h" |
| 8 #include "src/handles-inl.h" |
| 9 #include "src/interpreter/constant-array-builder.h" |
| 10 #include "src/isolate.h" |
| 11 #include "test/unittests/test-utils.h" |
| 12 |
| 13 namespace v8 { |
| 14 namespace internal { |
| 15 namespace interpreter { |
| 16 |
| 17 class ConstantArrayBuilderTest : public TestWithIsolateAndZone { |
| 18 public: |
| 19 ConstantArrayBuilderTest() {} |
| 20 ~ConstantArrayBuilderTest() override {} |
| 21 |
| 22 static const size_t kLowCapacity = ConstantArrayBuilder::kLowCapacity; |
| 23 static const size_t kMaxCapacity = ConstantArrayBuilder::kMaxCapacity; |
| 24 }; |
| 25 |
| 26 |
| 27 STATIC_CONST_MEMBER_DEFINITION const size_t |
| 28 ConstantArrayBuilderTest::kMaxCapacity; |
| 29 STATIC_CONST_MEMBER_DEFINITION const size_t |
| 30 ConstantArrayBuilderTest::kLowCapacity; |
| 31 |
| 32 |
| 33 TEST_F(ConstantArrayBuilderTest, AllocateAllEntries) { |
| 34 ConstantArrayBuilder builder(isolate(), zone()); |
| 35 for (size_t i = 0; i < kMaxCapacity; i++) { |
| 36 auto object = isolate()->factory()->NewNumberFromSize(i); |
| 37 builder.Insert(object); |
| 38 CHECK_EQ(builder.size(), i + 1); |
| 39 CHECK(builder.at(i)->SameValue(*object)); |
| 40 } |
| 41 |
| 42 for (size_t i = 0; i < kMaxCapacity; i++) { |
| 43 CHECK_EQ(Handle<Smi>::cast(builder.at(i))->value(), static_cast<double>(i)); |
| 44 } |
| 45 } |
| 46 |
| 47 |
| 48 TEST_F(ConstantArrayBuilderTest, AllocateEntriesWithIdx8Reservations) { |
| 49 for (size_t reserved = 1; reserved < kLowCapacity; reserved *= 3) { |
| 50 ConstantArrayBuilder builder(isolate(), zone()); |
| 51 |
| 52 for (size_t i = 0; i < reserved; i++) { |
| 53 auto token = builder.CreateReservedEntry(); |
| 54 CHECK(token == ConstantArrayBuilder::ReservationToken::kIdx8); |
| 55 } |
| 56 |
| 57 for (size_t i = 0; i < 2 * kLowCapacity; i++) { |
| 58 auto object = isolate()->factory()->NewNumberFromSize(i); |
| 59 builder.Insert(object); |
| 60 if (i + reserved < kLowCapacity) { |
| 61 CHECK_LE(builder.size(), kLowCapacity); |
| 62 CHECK_EQ(builder.size(), i + 1); |
| 63 CHECK(builder.at(i)->SameValue(*object)); |
| 64 } else { |
| 65 CHECK_GE(builder.size(), kLowCapacity); |
| 66 CHECK_EQ(builder.size(), i + reserved + 1); |
| 67 CHECK(builder.at(i + reserved)->SameValue(*object)); |
| 68 } |
| 69 } |
| 70 CHECK_EQ(builder.size(), 2 * kLowCapacity + reserved); |
| 71 |
| 72 // Check reserved values represented by the hole. |
| 73 for (size_t i = 0; i < reserved; i++) { |
| 74 auto empty = builder.at(kLowCapacity - reserved + i); |
| 75 CHECK(empty->SameValue(isolate()->heap()->the_hole_value())); |
| 76 } |
| 77 |
| 78 // Commmit reserved entries with duplicates and check size does not change. |
| 79 DCHECK_EQ(reserved + 2 * kLowCapacity, builder.size()); |
| 80 size_t duplicates_in_idx8_space = |
| 81 std::min(reserved, kLowCapacity - reserved); |
| 82 for (size_t i = 0; i < duplicates_in_idx8_space; i++) { |
| 83 builder.CommitReservedEntry(ConstantArrayBuilder::ReservationToken::kIdx8, |
| 84 isolate()->factory()->NewNumberFromSize(i)); |
| 85 DCHECK_EQ(reserved + 2 * kLowCapacity, builder.size()); |
| 86 } |
| 87 |
| 88 // Check all committed values match expected (holes where |
| 89 // duplicates_in_idx8_space allocated). |
| 90 for (size_t i = 0; i < kLowCapacity - reserved; i++) { |
| 91 Smi* smi = Smi::FromInt(static_cast<int>(i)); |
| 92 CHECK(Handle<Smi>::cast(builder.at(i))->SameValue(smi)); |
| 93 } |
| 94 for (size_t i = kLowCapacity; i < 2 * kLowCapacity + reserved; i++) { |
| 95 Smi* smi = Smi::FromInt(static_cast<int>(i - reserved)); |
| 96 CHECK(Handle<Smi>::cast(builder.at(i))->SameValue(smi)); |
| 97 } |
| 98 for (size_t i = 0; i < reserved; i++) { |
| 99 size_t index = kLowCapacity - reserved + i; |
| 100 CHECK(builder.at(index)->IsTheHole()); |
| 101 } |
| 102 |
| 103 // Now make reservations, and commit them with unique entries. |
| 104 for (size_t i = 0; i < duplicates_in_idx8_space; i++) { |
| 105 auto token = builder.CreateReservedEntry(); |
| 106 CHECK(token == ConstantArrayBuilder::ReservationToken::kIdx8); |
| 107 } |
| 108 for (size_t i = 0; i < duplicates_in_idx8_space; i++) { |
| 109 auto object = |
| 110 isolate()->factory()->NewNumberFromSize(2 * kLowCapacity + i); |
| 111 size_t index = builder.CommitReservedEntry( |
| 112 ConstantArrayBuilder::ReservationToken::kIdx8, object); |
| 113 CHECK_EQ(static_cast<int>(index), kLowCapacity - reserved + i); |
| 114 CHECK(builder.at(static_cast<int>(index))->SameValue(*object)); |
| 115 } |
| 116 CHECK_EQ(builder.size(), 2 * kLowCapacity + reserved); |
| 117 } |
| 118 } |
| 119 |
| 120 |
| 121 TEST_F(ConstantArrayBuilderTest, AllocateEntriesWithIdx16Reservations) { |
| 122 for (size_t reserved = 1; reserved < kLowCapacity; reserved *= 3) { |
| 123 ConstantArrayBuilder builder(isolate(), zone()); |
| 124 for (size_t i = 0; i < kLowCapacity; i++) { |
| 125 auto object = isolate()->factory()->NewNumberFromSize(i); |
| 126 builder.Insert(object); |
| 127 CHECK(builder.at(i)->SameValue(*object)); |
| 128 CHECK_EQ(builder.size(), i + 1); |
| 129 } |
| 130 for (size_t i = 0; i < reserved; i++) { |
| 131 auto token = builder.CreateReservedEntry(); |
| 132 CHECK(token == ConstantArrayBuilder::ReservationToken::kIdx16); |
| 133 CHECK_EQ(builder.size(), kLowCapacity); |
| 134 } |
| 135 for (size_t i = 0; i < reserved; i++) { |
| 136 builder.DiscardReservedEntry( |
| 137 ConstantArrayBuilder::ReservationToken::kIdx16); |
| 138 CHECK_EQ(builder.size(), kLowCapacity); |
| 139 } |
| 140 for (size_t i = 0; i < reserved; i++) { |
| 141 auto token = builder.CreateReservedEntry(); |
| 142 CHECK(token == ConstantArrayBuilder::ReservationToken::kIdx16); |
| 143 auto object = isolate()->factory()->NewNumberFromSize(i); |
| 144 builder.CommitReservedEntry(token, object); |
| 145 CHECK_EQ(builder.size(), kLowCapacity); |
| 146 } |
| 147 for (size_t i = kLowCapacity; i < kLowCapacity + reserved; i++) { |
| 148 auto token = builder.CreateReservedEntry(); |
| 149 CHECK(token == ConstantArrayBuilder::ReservationToken::kIdx16); |
| 150 auto object = isolate()->factory()->NewNumberFromSize(i); |
| 151 builder.CommitReservedEntry(token, object); |
| 152 CHECK_EQ(builder.size(), i + 1); |
| 153 } |
| 154 } |
| 155 } |
| 156 |
| 157 |
| 158 TEST_F(ConstantArrayBuilderTest, ToFixedArray) { |
| 159 ConstantArrayBuilder builder(isolate(), zone()); |
| 160 static const size_t kNumberOfElements = 37; |
| 161 for (size_t i = 0; i < kNumberOfElements; i++) { |
| 162 auto object = isolate()->factory()->NewNumberFromSize(i); |
| 163 builder.Insert(object); |
| 164 CHECK(builder.at(i)->SameValue(*object)); |
| 165 } |
| 166 |
| 167 Handle<FixedArray> constant_array = |
| 168 builder.ToFixedArray(isolate()->factory(), TENURED); |
| 169 CHECK_EQ(constant_array->length(), kNumberOfElements); |
| 170 for (size_t i = 0; i < kNumberOfElements; i++) { |
| 171 CHECK(constant_array->get(static_cast<int>(i))->SameValue(*builder.at(i))); |
| 172 } |
| 173 } |
| 174 |
| 175 |
| 176 TEST_F(ConstantArrayBuilderTest, GapFilledWhenLowReservationCommitted) { |
| 177 ConstantArrayBuilder builder(isolate(), zone()); |
| 178 for (size_t i = 0; i < 256; i++) { |
| 179 auto token = builder.CreateReservedEntry(); |
| 180 CHECK(ConstantArrayBuilder::ReservationToken::kIdx8 == token); |
| 181 CHECK_EQ(builder.size(), 0); |
| 182 } |
| 183 |
| 184 for (size_t i = 0; i < 256; i++) { |
| 185 auto object = isolate()->factory()->NewNumberFromSize(i); |
| 186 builder.Insert(object); |
| 187 CHECK_EQ(builder.size(), i + 257); |
| 188 } |
| 189 |
| 190 for (size_t i = 0; i < 256; i++) { |
| 191 builder.CommitReservedEntry(ConstantArrayBuilder::ReservationToken::kIdx8, |
| 192 builder.at(i + 256)); |
| 193 CHECK_EQ(builder.size(), 512); |
| 194 } |
| 195 |
| 196 for (size_t i = 0; i < 256; i++) { |
| 197 Handle<Object> original = builder.at(256 + i); |
| 198 Handle<Object> duplicate = builder.at(i); |
| 199 CHECK(original->SameValue(*duplicate)); |
| 200 auto reference = isolate()->factory()->NewNumberFromSize(i); |
| 201 CHECK(original->SameValue(*reference)); |
| 202 } |
| 203 } |
| 204 |
| 205 |
| 206 TEST_F(ConstantArrayBuilderTest, GapNotFilledWhenLowReservationDiscarded) { |
| 207 ConstantArrayBuilder builder(isolate(), zone()); |
| 208 for (size_t i = 0; i < 256; i++) { |
| 209 auto token = builder.CreateReservedEntry(); |
| 210 CHECK(ConstantArrayBuilder::ReservationToken::kIdx8 == token); |
| 211 CHECK_EQ(builder.size(), 0); |
| 212 } |
| 213 |
| 214 for (size_t i = 0; i < 256; i++) { |
| 215 auto object = isolate()->factory()->NewNumberFromSize(i); |
| 216 builder.Insert(object); |
| 217 CHECK_EQ(builder.size(), i + 257); |
| 218 } |
| 219 |
| 220 for (size_t i = 0; i < 256; i++) { |
| 221 builder.DiscardReservedEntry(ConstantArrayBuilder::ReservationToken::kIdx8); |
| 222 builder.Insert(builder.at(i + 256)); |
| 223 CHECK_EQ(builder.size(), 512); |
| 224 } |
| 225 |
| 226 for (size_t i = 0; i < 256; i++) { |
| 227 auto reference = isolate()->factory()->NewNumberFromSize(i); |
| 228 Handle<Object> original = builder.at(256 + i); |
| 229 CHECK(original->SameValue(*reference)); |
| 230 Handle<Object> duplicate = builder.at(i); |
| 231 CHECK(duplicate->SameValue(*isolate()->factory()->the_hole_value())); |
| 232 } |
| 233 } |
| 234 |
| 235 } // namespace interpreter |
| 236 } // namespace internal |
| 237 } // namespace v8 |
OLD | NEW |