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