• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
JSCacheTesterHelper(Isolate * isolate,Zone * zone)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:
JSConstantCacheTester()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 
TypeOf(Node * node)48   Type* TypeOf(Node* node) { return NodeProperties::GetType(node); }
49 
handle(Node * node)50   Handle<HeapObject> handle(Node* node) {
51     CHECK_EQ(IrOpcode::kHeapConstant, node->opcode());
52     return OpParameter<Handle<HeapObject>>(node);
53   }
54 
factory()55   Factory* factory() { return main_isolate()->factory(); }
56 };
57 
58 
TEST(ZeroConstant1)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 
TEST(MinusZeroConstant)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 
TEST(ZeroConstant2)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 
TEST(OneConstant1)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 
TEST(OneConstant2)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 
TEST(Canonicalizations)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 
TEST(NoAliasing)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 
TEST(CanonicalizingNumbers)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 
TEST(NumberTypes)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 
TEST(HeapNumbers)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 
TEST(OddballHandle)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 
TEST(OddballValues)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 
TEST(OddballTypes)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 
TEST(ExternalReferences)295 TEST(ExternalReferences) {
296   // TODO(titzer): test canonicalization of external references.
297 }
298 
299 
Contains(NodeVector * nodes,Node * n)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 
CheckGetCachedNodesContains(JSConstantCacheTester * T,Node * n)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 
TEST(JSGraph_GetCachedNodes1)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 
TEST(JSGraph_GetCachedNodes_int32)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 
TEST(JSGraph_GetCachedNodes_float64)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 
TEST(JSGraph_GetCachedNodes_int64)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 
TEST(JSGraph_GetCachedNodes_number)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 
TEST(JSGraph_GetCachedNodes_external)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 
TEST(JSGraph_GetCachedNodes_together)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