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