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 90 : 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 90 : main_graph_.SetStart(main_graph_.NewNode(common()->Start(0)));
40 90 : main_graph_.SetEnd(
41 : 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 : Factory* factory() { return main_isolate()->factory(); }
50 : };
51 :
52 :
53 26644 : 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 26644 : TEST(MinusZeroConstant) {
69 5 : JSConstantCacheTester T;
70 :
71 5 : Node* minus_zero = T.Constant(-0.0);
72 5 : 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 26644 : 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 26644 : 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 26644 : 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 26644 : 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 26644 : 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 105 : for (size_t i = 0; i < arraysize(nodes); i++) {
159 1050 : 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 26644 : TEST(CanonicalizingNumbers) {
167 5 : JSConstantCacheTester T;
168 :
169 495 : FOR_FLOAT64_INPUTS(i) {
170 245 : Node* node = T.Constant(i);
171 2695 : for (int j = 0; j < 5; j++) {
172 1225 : CHECK_EQ(node, T.Constant(i));
173 : }
174 : }
175 5 : }
176 :
177 :
178 26644 : TEST(HeapNumbers) {
179 5 : JSConstantCacheTester T;
180 :
181 495 : FOR_FLOAT64_INPUTS(value) {
182 245 : Handle<Object> num = T.factory()->NewNumber(value);
183 245 : Handle<HeapNumber> heap = T.factory()->NewHeapNumber(value);
184 245 : Node* node1 = T.Constant(value);
185 245 : Node* node2 = T.Constant(num);
186 245 : Node* node3 = T.Constant(heap);
187 245 : CHECK_EQ(node1, node2);
188 245 : CHECK_EQ(node1, node3);
189 : }
190 5 : }
191 :
192 :
193 26644 : TEST(OddballHandle) {
194 5 : JSConstantCacheTester T;
195 :
196 5 : CHECK_EQ(T.UndefinedConstant(), T.Constant(T.factory()->undefined_value()));
197 5 : CHECK_EQ(T.TheHoleConstant(), T.Constant(T.factory()->the_hole_value()));
198 5 : CHECK_EQ(T.TrueConstant(), T.Constant(T.factory()->true_value()));
199 5 : CHECK_EQ(T.FalseConstant(), T.Constant(T.factory()->false_value()));
200 5 : CHECK_EQ(T.NullConstant(), T.Constant(T.factory()->null_value()));
201 5 : CHECK_EQ(T.NaNConstant(), T.Constant(T.factory()->nan_value()));
202 5 : }
203 :
204 :
205 26644 : TEST(OddballValues) {
206 5 : JSConstantCacheTester T;
207 :
208 10 : CHECK_EQ(*T.factory()->undefined_value(), *T.handle(T.UndefinedConstant()));
209 10 : CHECK_EQ(*T.factory()->the_hole_value(), *T.handle(T.TheHoleConstant()));
210 10 : CHECK_EQ(*T.factory()->true_value(), *T.handle(T.TrueConstant()));
211 10 : CHECK_EQ(*T.factory()->false_value(), *T.handle(T.FalseConstant()));
212 10 : CHECK_EQ(*T.factory()->null_value(), *T.handle(T.NullConstant()));
213 5 : }
214 :
215 :
216 26644 : TEST(ExternalReferences) {
217 : // TODO(titzer): test canonicalization of external references.
218 5 : }
219 :
220 :
221 915 : static bool Contains(NodeVector* nodes, Node* n) {
222 11589 : for (size_t i = 0; i < nodes->size(); i++) {
223 6252 : if (nodes->at(i) == n) return true;
224 : }
225 : return false;
226 : }
227 :
228 :
229 645 : static void CheckGetCachedNodesContains(JSConstantCacheTester* T, Node* n) {
230 : NodeVector nodes(T->main_zone());
231 645 : T->GetCachedNodes(&nodes);
232 645 : CHECK(Contains(&nodes, n));
233 645 : }
234 :
235 :
236 26644 : TEST(JSGraph_GetCachedNodes1) {
237 5 : JSConstantCacheTester T;
238 5 : CheckGetCachedNodesContains(&T, T.TrueConstant());
239 5 : CheckGetCachedNodesContains(&T, T.UndefinedConstant());
240 5 : CheckGetCachedNodesContains(&T, T.TheHoleConstant());
241 5 : CheckGetCachedNodesContains(&T, T.TrueConstant());
242 5 : CheckGetCachedNodesContains(&T, T.FalseConstant());
243 5 : CheckGetCachedNodesContains(&T, T.NullConstant());
244 5 : CheckGetCachedNodesContains(&T, T.ZeroConstant());
245 5 : CheckGetCachedNodesContains(&T, T.OneConstant());
246 5 : CheckGetCachedNodesContains(&T, T.NaNConstant());
247 5 : }
248 :
249 :
250 26644 : TEST(JSGraph_GetCachedNodes_int32) {
251 5 : JSConstantCacheTester T;
252 :
253 : int32_t constants[] = {0, 1, 1, 1, 1, 2, 3, 4, 11, 12, 13,
254 : 14, 55, -55, -44, -33, -22, -11, 16, 16, 17, 17,
255 : 18, 18, 19, 19, 20, 20, 21, 21, 22, 23, 24,
256 5 : 25, 15, 30, 31, 45, 46, 47, 48};
257 :
258 415 : for (size_t i = 0; i < arraysize(constants); i++) {
259 : size_t count_before = T.graph()->NodeCount();
260 : NodeVector nodes_before(T.main_zone());
261 205 : T.GetCachedNodes(&nodes_before);
262 205 : Node* n = T.Int32Constant(constants[i]);
263 205 : if (n->id() < count_before) {
264 : // An old ID indicates a cached node. It should have been in the set.
265 45 : CHECK(Contains(&nodes_before, n));
266 : }
267 : // Old or new, it should be in the cached set afterwards.
268 205 : CheckGetCachedNodesContains(&T, n);
269 : }
270 5 : }
271 :
272 :
273 26644 : TEST(JSGraph_GetCachedNodes_float64) {
274 5 : JSConstantCacheTester T;
275 :
276 : double constants[] = {0, 11.1, 12.2, 13, 14, 55.5, -55.5, -44.4,
277 : -33, -22, -11, 0, 11.1, 11.1, 12.3, 12.3,
278 5 : 11, 11, -33.3, -33.3, -22, -11};
279 :
280 225 : for (size_t i = 0; i < arraysize(constants); i++) {
281 : size_t count_before = T.graph()->NodeCount();
282 : NodeVector nodes_before(T.main_zone());
283 110 : T.GetCachedNodes(&nodes_before);
284 110 : Node* n = T.Float64Constant(constants[i]);
285 110 : if (n->id() < count_before) {
286 : // An old ID indicates a cached node. It should have been in the set.
287 40 : CHECK(Contains(&nodes_before, n));
288 : }
289 : // Old or new, it should be in the cached set afterwards.
290 110 : CheckGetCachedNodesContains(&T, n);
291 : }
292 5 : }
293 :
294 :
295 26644 : TEST(JSGraph_GetCachedNodes_int64) {
296 5 : JSConstantCacheTester T;
297 :
298 : int32_t constants[] = {0, 11, 12, 13, 14, 55, -55, -44, -33,
299 : -22, -11, 16, 16, 17, 17, 18, 18, 19,
300 5 : 19, 20, 20, 21, 21, 22, 23, 24, 25};
301 :
302 275 : for (size_t i = 0; i < arraysize(constants); i++) {
303 : size_t count_before = T.graph()->NodeCount();
304 : NodeVector nodes_before(T.main_zone());
305 135 : T.GetCachedNodes(&nodes_before);
306 135 : Node* n = T.Int64Constant(constants[i]);
307 135 : if (n->id() < count_before) {
308 : // An old ID indicates a cached node. It should have been in the set.
309 30 : CHECK(Contains(&nodes_before, n));
310 : }
311 : // Old or new, it should be in the cached set afterwards.
312 135 : CheckGetCachedNodesContains(&T, n);
313 : }
314 5 : }
315 :
316 :
317 26644 : TEST(JSGraph_GetCachedNodes_number) {
318 5 : JSConstantCacheTester T;
319 :
320 : double constants[] = {0, 11.1, 12.2, 13, 14, 55.5, -55.5, -44.4,
321 : -33, -22, -11, 0, 11.1, 11.1, 12.3, 12.3,
322 5 : 11, 11, -33.3, -33.3, -22, -11};
323 :
324 225 : for (size_t i = 0; i < arraysize(constants); i++) {
325 : size_t count_before = T.graph()->NodeCount();
326 : NodeVector nodes_before(T.main_zone());
327 110 : T.GetCachedNodes(&nodes_before);
328 110 : Node* n = T.Constant(constants[i]);
329 110 : if (n->id() < count_before) {
330 : // An old ID indicates a cached node. It should have been in the set.
331 40 : CHECK(Contains(&nodes_before, n));
332 : }
333 : // Old or new, it should be in the cached set afterwards.
334 110 : CheckGetCachedNodesContains(&T, n);
335 : }
336 5 : }
337 :
338 :
339 26644 : TEST(JSGraph_GetCachedNodes_external) {
340 5 : JSConstantCacheTester T;
341 :
342 : ExternalReference constants[] = {ExternalReference::address_of_min_int(),
343 : ExternalReference::address_of_min_int(),
344 : ExternalReference::address_of_min_int(),
345 : ExternalReference::address_of_one_half(),
346 : ExternalReference::address_of_one_half(),
347 : ExternalReference::address_of_min_int(),
348 : ExternalReference::address_of_the_hole_nan(),
349 5 : ExternalReference::address_of_one_half()};
350 :
351 85 : for (size_t i = 0; i < arraysize(constants); i++) {
352 : size_t count_before = T.graph()->NodeCount();
353 : NodeVector nodes_before(T.main_zone());
354 40 : T.GetCachedNodes(&nodes_before);
355 40 : Node* n = T.ExternalConstant(constants[i]);
356 40 : if (n->id() < count_before) {
357 : // An old ID indicates a cached node. It should have been in the set.
358 25 : CHECK(Contains(&nodes_before, n));
359 : }
360 : // Old or new, it should be in the cached set afterwards.
361 40 : CheckGetCachedNodesContains(&T, n);
362 : }
363 5 : }
364 :
365 :
366 26644 : TEST(JSGraph_GetCachedNodes_together) {
367 5 : JSConstantCacheTester T;
368 :
369 : Node* constants[] = {
370 5 : T.TrueConstant(),
371 5 : T.UndefinedConstant(),
372 5 : T.TheHoleConstant(),
373 5 : T.TrueConstant(),
374 5 : T.FalseConstant(),
375 5 : T.NullConstant(),
376 5 : T.ZeroConstant(),
377 5 : T.OneConstant(),
378 5 : T.NaNConstant(),
379 5 : T.Int32Constant(0),
380 5 : T.Int32Constant(1),
381 5 : T.Int64Constant(-2),
382 5 : T.Int64Constant(-4),
383 5 : T.Float64Constant(0.9),
384 5 : T.Float64Constant(V8_INFINITY),
385 5 : T.Constant(0.99),
386 5 : T.Constant(1.11),
387 85 : T.ExternalConstant(ExternalReference::address_of_one_half())};
388 :
389 : NodeVector nodes(T.main_zone());
390 5 : T.GetCachedNodes(&nodes);
391 :
392 185 : for (size_t i = 0; i < arraysize(constants); i++) {
393 90 : CHECK(Contains(&nodes, constants[i]));
394 : }
395 5 : }
396 :
397 : } // namespace compiler
398 : } // namespace internal
399 79917 : } // namespace v8
|