Home | History | Annotate | Download | only in compiler
      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