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/assembler.h" 6 #include "src/compiler/js-graph.h" 7 #include "src/compiler/node-properties.h" 8 #include "src/compiler/typer.h" 9 #include "src/types.h" 10 #include "test/cctest/cctest.h" 11 #include "test/cctest/compiler/value-helper.h" 12 13 namespace v8 { 14 namespace internal { 15 namespace compiler { 16 17 class JSCacheTesterHelper { 18 protected: 19 JSCacheTesterHelper(Isolate* isolate, Zone* zone) 20 : main_graph_(zone), 21 main_common_(zone), 22 main_javascript_(zone), 23 main_typer_(isolate, &main_graph_), 24 main_machine_(zone) {} 25 Graph main_graph_; 26 CommonOperatorBuilder main_common_; 27 JSOperatorBuilder main_javascript_; 28 Typer main_typer_; 29 MachineOperatorBuilder main_machine_; 30 }; 31 32 33 // TODO(dcarney): JSConstantCacheTester inherits from JSGraph??? 34 class JSConstantCacheTester : public HandleAndZoneScope, 35 public JSCacheTesterHelper, 36 public JSGraph { 37 public: 38 JSConstantCacheTester() 39 : JSCacheTesterHelper(main_isolate(), main_zone()), 40 JSGraph(main_isolate(), &main_graph_, &main_common_, &main_javascript_, 41 nullptr, &main_machine_) { 42 main_graph_.SetStart(main_graph_.NewNode(common()->Start(0))); 43 main_graph_.SetEnd( 44 main_graph_.NewNode(common()->End(1), main_graph_.start())); 45 main_typer_.Run(); 46 } 47 48 Type* TypeOf(Node* node) { return NodeProperties::GetType(node); } 49 50 Handle<HeapObject> handle(Node* node) { 51 CHECK_EQ(IrOpcode::kHeapConstant, node->opcode()); 52 return OpParameter<Handle<HeapObject>>(node); 53 } 54 55 Factory* factory() { return main_isolate()->factory(); } 56 }; 57 58 59 TEST(ZeroConstant1) { 60 JSConstantCacheTester T; 61 62 Node* zero = T.ZeroConstant(); 63 64 CHECK_EQ(IrOpcode::kNumberConstant, zero->opcode()); 65 CHECK_EQ(zero, T.Constant(0)); 66 CHECK_NE(zero, T.Constant(-0.0)); 67 CHECK_NE(zero, T.Constant(1.0)); 68 CHECK_NE(zero, T.Constant(std::numeric_limits<double>::quiet_NaN())); 69 CHECK_NE(zero, T.Float64Constant(0)); 70 CHECK_NE(zero, T.Int32Constant(0)); 71 72 Type* t = T.TypeOf(zero); 73 74 CHECK(t->Is(Type::Number())); 75 CHECK(t->Is(Type::Integral32())); 76 CHECK(t->Is(Type::Signed32())); 77 CHECK(t->Is(Type::Unsigned32())); 78 CHECK(t->Is(Type::SignedSmall())); 79 CHECK(t->Is(Type::UnsignedSmall())); 80 } 81 82 83 TEST(MinusZeroConstant) { 84 JSConstantCacheTester T; 85 86 Node* minus_zero = T.Constant(-0.0); 87 Node* zero = T.ZeroConstant(); 88 89 CHECK_EQ(IrOpcode::kNumberConstant, minus_zero->opcode()); 90 CHECK_EQ(minus_zero, T.Constant(-0.0)); 91 CHECK_NE(zero, minus_zero); 92 93 Type* t = T.TypeOf(minus_zero); 94 95 CHECK(t->Is(Type::Number())); 96 CHECK(t->Is(Type::MinusZero())); 97 CHECK(!t->Is(Type::Integral32())); 98 CHECK(!t->Is(Type::Signed32())); 99 CHECK(!t->Is(Type::Unsigned32())); 100 CHECK(!t->Is(Type::SignedSmall())); 101 CHECK(!t->Is(Type::UnsignedSmall())); 102 103 double zero_value = OpParameter<double>(zero); 104 double minus_zero_value = OpParameter<double>(minus_zero); 105 106 CHECK(bit_cast<uint64_t>(0.0) == bit_cast<uint64_t>(zero_value)); 107 CHECK(bit_cast<uint64_t>(-0.0) != bit_cast<uint64_t>(zero_value)); 108 CHECK(bit_cast<uint64_t>(0.0) != bit_cast<uint64_t>(minus_zero_value)); 109 CHECK(bit_cast<uint64_t>(-0.0) == bit_cast<uint64_t>(minus_zero_value)); 110 } 111 112 113 TEST(ZeroConstant2) { 114 JSConstantCacheTester T; 115 116 Node* zero = T.Constant(0); 117 118 CHECK_EQ(IrOpcode::kNumberConstant, zero->opcode()); 119 CHECK_EQ(zero, T.ZeroConstant()); 120 CHECK_NE(zero, T.Constant(-0.0)); 121 CHECK_NE(zero, T.Constant(1.0)); 122 CHECK_NE(zero, T.Constant(std::numeric_limits<double>::quiet_NaN())); 123 CHECK_NE(zero, T.Float64Constant(0)); 124 CHECK_NE(zero, T.Int32Constant(0)); 125 126 Type* t = T.TypeOf(zero); 127 128 CHECK(t->Is(Type::Number())); 129 CHECK(t->Is(Type::Integral32())); 130 CHECK(t->Is(Type::Signed32())); 131 CHECK(t->Is(Type::Unsigned32())); 132 CHECK(t->Is(Type::SignedSmall())); 133 CHECK(t->Is(Type::UnsignedSmall())); 134 } 135 136 137 TEST(OneConstant1) { 138 JSConstantCacheTester T; 139 140 Node* one = T.OneConstant(); 141 142 CHECK_EQ(IrOpcode::kNumberConstant, one->opcode()); 143 CHECK_EQ(one, T.Constant(1)); 144 CHECK_EQ(one, T.Constant(1.0)); 145 CHECK_NE(one, T.Constant(1.01)); 146 CHECK_NE(one, T.Constant(-1.01)); 147 CHECK_NE(one, T.Constant(std::numeric_limits<double>::quiet_NaN())); 148 CHECK_NE(one, T.Float64Constant(1.0)); 149 CHECK_NE(one, T.Int32Constant(1)); 150 151 Type* t = T.TypeOf(one); 152 153 CHECK(t->Is(Type::Number())); 154 CHECK(t->Is(Type::Integral32())); 155 CHECK(t->Is(Type::Signed32())); 156 CHECK(t->Is(Type::Unsigned32())); 157 CHECK(t->Is(Type::SignedSmall())); 158 CHECK(t->Is(Type::UnsignedSmall())); 159 } 160 161 162 TEST(OneConstant2) { 163 JSConstantCacheTester T; 164 165 Node* one = T.Constant(1); 166 167 CHECK_EQ(IrOpcode::kNumberConstant, one->opcode()); 168 CHECK_EQ(one, T.OneConstant()); 169 CHECK_EQ(one, T.Constant(1.0)); 170 CHECK_NE(one, T.Constant(1.01)); 171 CHECK_NE(one, T.Constant(-1.01)); 172 CHECK_NE(one, T.Constant(std::numeric_limits<double>::quiet_NaN())); 173 CHECK_NE(one, T.Float64Constant(1.0)); 174 CHECK_NE(one, T.Int32Constant(1)); 175 176 Type* t = T.TypeOf(one); 177 178 CHECK(t->Is(Type::Number())); 179 CHECK(t->Is(Type::Integral32())); 180 CHECK(t->Is(Type::Signed32())); 181 CHECK(t->Is(Type::Unsigned32())); 182 CHECK(t->Is(Type::SignedSmall())); 183 CHECK(t->Is(Type::UnsignedSmall())); 184 } 185 186 187 TEST(Canonicalizations) { 188 JSConstantCacheTester T; 189 190 CHECK_EQ(T.ZeroConstant(), T.ZeroConstant()); 191 CHECK_EQ(T.UndefinedConstant(), T.UndefinedConstant()); 192 CHECK_EQ(T.TheHoleConstant(), T.TheHoleConstant()); 193 CHECK_EQ(T.TrueConstant(), T.TrueConstant()); 194 CHECK_EQ(T.FalseConstant(), T.FalseConstant()); 195 CHECK_EQ(T.NullConstant(), T.NullConstant()); 196 CHECK_EQ(T.ZeroConstant(), T.ZeroConstant()); 197 CHECK_EQ(T.OneConstant(), T.OneConstant()); 198 CHECK_EQ(T.NaNConstant(), T.NaNConstant()); 199 } 200 201 202 TEST(NoAliasing) { 203 JSConstantCacheTester T; 204 205 Node* nodes[] = {T.UndefinedConstant(), T.TheHoleConstant(), T.TrueConstant(), 206 T.FalseConstant(), T.NullConstant(), T.ZeroConstant(), 207 T.OneConstant(), T.NaNConstant(), T.Constant(21), 208 T.Constant(22.2)}; 209 210 for (size_t i = 0; i < arraysize(nodes); i++) { 211 for (size_t j = 0; j < arraysize(nodes); j++) { 212 if (i != j) CHECK_NE(nodes[i], nodes[j]); 213 } 214 } 215 } 216 217 218 TEST(CanonicalizingNumbers) { 219 JSConstantCacheTester T; 220 221 FOR_FLOAT64_INPUTS(i) { 222 Node* node = T.Constant(*i); 223 for (int j = 0; j < 5; j++) { 224 CHECK_EQ(node, T.Constant(*i)); 225 } 226 } 227 } 228 229 230 TEST(NumberTypes) { 231 JSConstantCacheTester T; 232 233 FOR_FLOAT64_INPUTS(i) { 234 double value = *i; 235 Node* node = T.Constant(value); 236 CHECK(T.TypeOf(node)->Is(Type::Of(value, T.main_zone()))); 237 } 238 } 239 240 241 TEST(HeapNumbers) { 242 JSConstantCacheTester T; 243 244 FOR_FLOAT64_INPUTS(i) { 245 double value = *i; 246 Handle<Object> num = T.factory()->NewNumber(value); 247 Handle<HeapNumber> heap = T.factory()->NewHeapNumber(value); 248 Node* node1 = T.Constant(value); 249 Node* node2 = T.Constant(num); 250 Node* node3 = T.Constant(heap); 251 CHECK_EQ(node1, node2); 252 CHECK_EQ(node1, node3); 253 } 254 } 255 256 257 TEST(OddballHandle) { 258 JSConstantCacheTester T; 259 260 CHECK_EQ(T.UndefinedConstant(), T.Constant(T.factory()->undefined_value())); 261 CHECK_EQ(T.TheHoleConstant(), T.Constant(T.factory()->the_hole_value())); 262 CHECK_EQ(T.TrueConstant(), T.Constant(T.factory()->true_value())); 263 CHECK_EQ(T.FalseConstant(), T.Constant(T.factory()->false_value())); 264 CHECK_EQ(T.NullConstant(), T.Constant(T.factory()->null_value())); 265 CHECK_EQ(T.NaNConstant(), T.Constant(T.factory()->nan_value())); 266 } 267 268 269 TEST(OddballValues) { 270 JSConstantCacheTester T; 271 272 CHECK_EQ(*T.factory()->undefined_value(), *T.handle(T.UndefinedConstant())); 273 CHECK_EQ(*T.factory()->the_hole_value(), *T.handle(T.TheHoleConstant())); 274 CHECK_EQ(*T.factory()->true_value(), *T.handle(T.TrueConstant())); 275 CHECK_EQ(*T.factory()->false_value(), *T.handle(T.FalseConstant())); 276 CHECK_EQ(*T.factory()->null_value(), *T.handle(T.NullConstant())); 277 } 278 279 280 TEST(OddballTypes) { 281 JSConstantCacheTester T; 282 283 CHECK(T.TypeOf(T.UndefinedConstant())->Is(Type::Undefined())); 284 // TODO(dcarney): figure this out. 285 // CHECK(T.TypeOf(T.TheHoleConstant())->Is(Type::Internal())); 286 CHECK(T.TypeOf(T.TrueConstant())->Is(Type::Boolean())); 287 CHECK(T.TypeOf(T.FalseConstant())->Is(Type::Boolean())); 288 CHECK(T.TypeOf(T.NullConstant())->Is(Type::Null())); 289 CHECK(T.TypeOf(T.ZeroConstant())->Is(Type::Number())); 290 CHECK(T.TypeOf(T.OneConstant())->Is(Type::Number())); 291 CHECK(T.TypeOf(T.NaNConstant())->Is(Type::NaN())); 292 } 293 294 295 TEST(ExternalReferences) { 296 // TODO(titzer): test canonicalization of external references. 297 } 298 299 300 static bool Contains(NodeVector* nodes, Node* n) { 301 for (size_t i = 0; i < nodes->size(); i++) { 302 if (nodes->at(i) == n) return true; 303 } 304 return false; 305 } 306 307 308 static void CheckGetCachedNodesContains(JSConstantCacheTester* T, Node* n) { 309 NodeVector nodes(T->main_zone()); 310 T->GetCachedNodes(&nodes); 311 CHECK(Contains(&nodes, n)); 312 } 313 314 315 TEST(JSGraph_GetCachedNodes1) { 316 JSConstantCacheTester T; 317 CheckGetCachedNodesContains(&T, T.TrueConstant()); 318 CheckGetCachedNodesContains(&T, T.UndefinedConstant()); 319 CheckGetCachedNodesContains(&T, T.TheHoleConstant()); 320 CheckGetCachedNodesContains(&T, T.TrueConstant()); 321 CheckGetCachedNodesContains(&T, T.FalseConstant()); 322 CheckGetCachedNodesContains(&T, T.NullConstant()); 323 CheckGetCachedNodesContains(&T, T.ZeroConstant()); 324 CheckGetCachedNodesContains(&T, T.OneConstant()); 325 CheckGetCachedNodesContains(&T, T.NaNConstant()); 326 } 327 328 329 TEST(JSGraph_GetCachedNodes_int32) { 330 JSConstantCacheTester T; 331 332 int32_t constants[] = {0, 1, 1, 1, 1, 2, 3, 4, 11, 12, 13, 333 14, 55, -55, -44, -33, -22, -11, 16, 16, 17, 17, 334 18, 18, 19, 19, 20, 20, 21, 21, 22, 23, 24, 335 25, 15, 30, 31, 45, 46, 47, 48}; 336 337 for (size_t i = 0; i < arraysize(constants); i++) { 338 size_t count_before = T.graph()->NodeCount(); 339 NodeVector nodes_before(T.main_zone()); 340 T.GetCachedNodes(&nodes_before); 341 Node* n = T.Int32Constant(constants[i]); 342 if (n->id() < count_before) { 343 // An old ID indicates a cached node. It should have been in the set. 344 CHECK(Contains(&nodes_before, n)); 345 } 346 // Old or new, it should be in the cached set afterwards. 347 CheckGetCachedNodesContains(&T, n); 348 } 349 } 350 351 352 TEST(JSGraph_GetCachedNodes_float64) { 353 JSConstantCacheTester T; 354 355 double constants[] = {0, 11.1, 12.2, 13, 14, 55.5, -55.5, -44.4, 356 -33, -22, -11, 0, 11.1, 11.1, 12.3, 12.3, 357 11, 11, -33.3, -33.3, -22, -11}; 358 359 for (size_t i = 0; i < arraysize(constants); i++) { 360 size_t count_before = T.graph()->NodeCount(); 361 NodeVector nodes_before(T.main_zone()); 362 T.GetCachedNodes(&nodes_before); 363 Node* n = T.Float64Constant(constants[i]); 364 if (n->id() < count_before) { 365 // An old ID indicates a cached node. It should have been in the set. 366 CHECK(Contains(&nodes_before, n)); 367 } 368 // Old or new, it should be in the cached set afterwards. 369 CheckGetCachedNodesContains(&T, n); 370 } 371 } 372 373 374 TEST(JSGraph_GetCachedNodes_int64) { 375 JSConstantCacheTester T; 376 377 int32_t constants[] = {0, 11, 12, 13, 14, 55, -55, -44, -33, 378 -22, -11, 16, 16, 17, 17, 18, 18, 19, 379 19, 20, 20, 21, 21, 22, 23, 24, 25}; 380 381 for (size_t i = 0; i < arraysize(constants); i++) { 382 size_t count_before = T.graph()->NodeCount(); 383 NodeVector nodes_before(T.main_zone()); 384 T.GetCachedNodes(&nodes_before); 385 Node* n = T.Int64Constant(constants[i]); 386 if (n->id() < count_before) { 387 // An old ID indicates a cached node. It should have been in the set. 388 CHECK(Contains(&nodes_before, n)); 389 } 390 // Old or new, it should be in the cached set afterwards. 391 CheckGetCachedNodesContains(&T, n); 392 } 393 } 394 395 396 TEST(JSGraph_GetCachedNodes_number) { 397 JSConstantCacheTester T; 398 399 double constants[] = {0, 11.1, 12.2, 13, 14, 55.5, -55.5, -44.4, 400 -33, -22, -11, 0, 11.1, 11.1, 12.3, 12.3, 401 11, 11, -33.3, -33.3, -22, -11}; 402 403 for (size_t i = 0; i < arraysize(constants); i++) { 404 size_t count_before = T.graph()->NodeCount(); 405 NodeVector nodes_before(T.main_zone()); 406 T.GetCachedNodes(&nodes_before); 407 Node* n = T.Constant(constants[i]); 408 if (n->id() < count_before) { 409 // An old ID indicates a cached node. It should have been in the set. 410 CHECK(Contains(&nodes_before, n)); 411 } 412 // Old or new, it should be in the cached set afterwards. 413 CheckGetCachedNodesContains(&T, n); 414 } 415 } 416 417 418 TEST(JSGraph_GetCachedNodes_external) { 419 JSConstantCacheTester T; 420 421 ExternalReference constants[] = {ExternalReference::address_of_min_int(), 422 ExternalReference::address_of_min_int(), 423 ExternalReference::address_of_min_int(), 424 ExternalReference::address_of_one_half(), 425 ExternalReference::address_of_one_half(), 426 ExternalReference::address_of_min_int(), 427 ExternalReference::address_of_the_hole_nan(), 428 ExternalReference::address_of_one_half()}; 429 430 for (size_t i = 0; i < arraysize(constants); i++) { 431 size_t count_before = T.graph()->NodeCount(); 432 NodeVector nodes_before(T.main_zone()); 433 T.GetCachedNodes(&nodes_before); 434 Node* n = T.ExternalConstant(constants[i]); 435 if (n->id() < count_before) { 436 // An old ID indicates a cached node. It should have been in the set. 437 CHECK(Contains(&nodes_before, n)); 438 } 439 // Old or new, it should be in the cached set afterwards. 440 CheckGetCachedNodesContains(&T, n); 441 } 442 } 443 444 445 TEST(JSGraph_GetCachedNodes_together) { 446 JSConstantCacheTester T; 447 448 Node* constants[] = { 449 T.TrueConstant(), 450 T.UndefinedConstant(), 451 T.TheHoleConstant(), 452 T.TrueConstant(), 453 T.FalseConstant(), 454 T.NullConstant(), 455 T.ZeroConstant(), 456 T.OneConstant(), 457 T.NaNConstant(), 458 T.Int32Constant(0), 459 T.Int32Constant(1), 460 T.Int64Constant(-2), 461 T.Int64Constant(-4), 462 T.Float64Constant(0.9), 463 T.Float64Constant(V8_INFINITY), 464 T.Constant(0.99), 465 T.Constant(1.11), 466 T.ExternalConstant(ExternalReference::address_of_one_half())}; 467 468 NodeVector nodes(T.main_zone()); 469 T.GetCachedNodes(&nodes); 470 471 for (size_t i = 0; i < arraysize(constants); i++) { 472 CHECK(Contains(&nodes, constants[i])); 473 } 474 } 475 476 } // namespace compiler 477 } // namespace internal 478 } // namespace v8 479