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