1 // Copyright 2018 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 <cctype>
6
7 #include "src/codegen/tick-counter.h"
8 #include "src/compiler/compilation-dependencies.h"
9 #include "src/compiler/feedback-source.h"
10 #include "src/compiler/js-call-reducer.h"
11 #include "src/compiler/js-graph.h"
12 #include "src/compiler/simplified-operator.h"
13 #include "src/execution/isolate.h"
14 #include "src/execution/protectors.h"
15 #include "src/heap/factory.h"
16 #include "src/objects/feedback-vector.h"
17 #include "test/unittests/compiler/graph-unittest.h"
18 #include "test/unittests/compiler/node-test-utils.h"
19
20 namespace v8 {
21 namespace internal {
22 namespace compiler {
23
24 class JSCallReducerTest : public TypedGraphTest {
25 public:
JSCallReducerTest()26 JSCallReducerTest()
27 : TypedGraphTest(3), javascript_(zone()), deps_(broker(), zone()) {
28 }
29 ~JSCallReducerTest() override = default;
30
31 protected:
Reduce(Node * node)32 Reduction Reduce(Node* node) {
33 MachineOperatorBuilder machine(zone());
34 SimplifiedOperatorBuilder simplified(zone());
35 JSGraph jsgraph(isolate(), graph(), common(), javascript(), &simplified,
36 &machine);
37 GraphReducer graph_reducer(zone(), graph(), tick_counter(), broker());
38 JSCallReducer reducer(&graph_reducer, &jsgraph, broker(), zone(),
39 JSCallReducer::kNoFlags);
40 return reducer.Reduce(node);
41 }
42
javascript()43 JSOperatorBuilder* javascript() { return &javascript_; }
44
GlobalFunction(const char * name)45 Node* GlobalFunction(const char* name) {
46 Handle<JSFunction> f = Handle<JSFunction>::cast(
47 Object::GetProperty(
48 isolate(), isolate()->global_object(),
49 isolate()->factory()->NewStringFromAsciiChecked(name))
50 .ToHandleChecked());
51 return HeapConstant(f);
52 }
53
MathFunction(const std::string & name)54 Node* MathFunction(const std::string& name) {
55 Handle<Object> m =
56 JSObject::GetProperty(
57 isolate(), isolate()->global_object(),
58 isolate()->factory()->NewStringFromAsciiChecked("Math"))
59 .ToHandleChecked();
60 Handle<JSFunction> f = Handle<JSFunction>::cast(
61 Object::GetProperty(
62 isolate(), m,
63 isolate()->factory()->NewStringFromAsciiChecked(name.c_str()))
64 .ToHandleChecked());
65 return HeapConstant(f);
66 }
67
StringFunction(const char * name)68 Node* StringFunction(const char* name) {
69 Handle<Object> m =
70 JSObject::GetProperty(
71 isolate(), isolate()->global_object(),
72 isolate()->factory()->NewStringFromAsciiChecked("String"))
73 .ToHandleChecked();
74 Handle<JSFunction> f = Handle<JSFunction>::cast(
75 Object::GetProperty(
76 isolate(), m, isolate()->factory()->NewStringFromAsciiChecked(name))
77 .ToHandleChecked());
78 return HeapConstant(f);
79 }
80
NumberFunction(const char * name)81 Node* NumberFunction(const char* name) {
82 Handle<Object> m =
83 JSObject::GetProperty(
84 isolate(), isolate()->global_object(),
85 isolate()->factory()->NewStringFromAsciiChecked("Number"))
86 .ToHandleChecked();
87 Handle<JSFunction> f = Handle<JSFunction>::cast(
88 Object::GetProperty(
89 isolate(), m, isolate()->factory()->NewStringFromAsciiChecked(name))
90 .ToHandleChecked());
91 return HeapConstant(f);
92 }
93
op_name_for(const char * fnc)94 std::string op_name_for(const char* fnc) {
95 std::string string_fnc(fnc);
96 char initial = std::toupper(fnc[0]);
97 return std::string("Number") + initial +
98 string_fnc.substr(1, std::string::npos);
99 }
100
Call(int arity)101 const Operator* Call(int arity) {
102 FeedbackVectorSpec spec(zone());
103 spec.AddCallICSlot();
104 Handle<FeedbackMetadata> metadata = FeedbackMetadata::New(isolate(), &spec);
105 Handle<SharedFunctionInfo> shared =
106 isolate()->factory()->NewSharedFunctionInfoForBuiltin(
107 isolate()->factory()->empty_string(), Builtin::kIllegal);
108 // Set the raw feedback metadata to circumvent checks that we are not
109 // overwriting existing metadata.
110 shared->set_raw_outer_scope_info_or_feedback_metadata(*metadata);
111 Handle<ClosureFeedbackCellArray> closure_feedback_cell_array =
112 ClosureFeedbackCellArray::New(isolate(), shared);
113 IsCompiledScope is_compiled_scope(shared->is_compiled_scope(isolate()));
114 Handle<FeedbackVector> vector = FeedbackVector::New(
115 isolate(), shared, closure_feedback_cell_array, &is_compiled_scope);
116 FeedbackSource feedback(vector, FeedbackSlot(0));
117 return javascript()->Call(JSCallNode::ArityForArgc(arity), CallFrequency(),
118 feedback, ConvertReceiverMode::kAny,
119 SpeculationMode::kAllowSpeculation,
120 CallFeedbackRelation::kTarget);
121 }
122
DummyFrameState()123 Node* DummyFrameState() {
124 return graph()->NewNode(
125 common()->FrameState(BytecodeOffset{42},
126 OutputFrameStateCombine::Ignore(), nullptr),
127 graph()->start(), graph()->start(), graph()->start(), graph()->start(),
128 graph()->start(), graph()->start());
129 }
130
131 private:
132 JSOperatorBuilder javascript_;
133 CompilationDependencies deps_;
134 };
135
TEST_F(JSCallReducerTest,PromiseConstructorNoArgs)136 TEST_F(JSCallReducerTest, PromiseConstructorNoArgs) {
137 Node* promise =
138 HeapConstant(handle(native_context()->promise_function(), isolate()));
139 Node* effect = graph()->start();
140 Node* control = graph()->start();
141 Node* context = UndefinedConstant();
142 Node* frame_state = DummyFrameState();
143 Node* feedback = UndefinedConstant();
144
145 Node* construct = graph()->NewNode(
146 javascript()->Construct(JSConstructNode::ArityForArgc(0)), promise,
147 promise, feedback, context, frame_state, effect, control);
148
149 Reduction r = Reduce(construct);
150
151 ASSERT_FALSE(r.Changed());
152 }
153
TEST_F(JSCallReducerTest,PromiseConstructorSubclass)154 TEST_F(JSCallReducerTest, PromiseConstructorSubclass) {
155 Node* promise =
156 HeapConstant(handle(native_context()->promise_function(), isolate()));
157 Node* new_target =
158 HeapConstant(handle(native_context()->array_function(), isolate()));
159 Node* effect = graph()->start();
160 Node* control = graph()->start();
161 Node* context = UndefinedConstant();
162 Node* frame_state = DummyFrameState();
163 Node* feedback = UndefinedConstant();
164
165 Node* executor = UndefinedConstant();
166 Node* construct = graph()->NewNode(
167 javascript()->Construct(JSConstructNode::ArityForArgc(1)), promise,
168 new_target, executor, feedback, context, frame_state, effect, control);
169
170 Reduction r = Reduce(construct);
171
172 ASSERT_FALSE(r.Changed());
173 }
174
TEST_F(JSCallReducerTest,PromiseConstructorBasic)175 TEST_F(JSCallReducerTest, PromiseConstructorBasic) {
176 Node* promise =
177 HeapConstant(handle(native_context()->promise_function(), isolate()));
178 Node* effect = graph()->start();
179 Node* control = graph()->start();
180 Node* context = UndefinedConstant();
181 Node* frame_state = DummyFrameState();
182 Node* feedback = UndefinedConstant();
183
184 Node* executor = UndefinedConstant();
185 Node* construct = graph()->NewNode(
186 javascript()->Construct(JSConstructNode::ArityForArgc(1)), promise,
187 promise, executor, feedback, context, frame_state, effect, control);
188
189 Reduction r = Reduce(construct);
190 ASSERT_TRUE(r.Changed());
191 }
192
193 // Exactly the same as PromiseConstructorBasic which expects a reduction,
194 // except that we invalidate the protector cell.
TEST_F(JSCallReducerTest,PromiseConstructorWithHook)195 TEST_F(JSCallReducerTest, PromiseConstructorWithHook) {
196 Node* promise =
197 HeapConstant(handle(native_context()->promise_function(), isolate()));
198 Node* effect = graph()->start();
199 Node* control = graph()->start();
200 Node* context = UndefinedConstant();
201 Node* frame_state = DummyFrameState();
202 Node* feedback = UndefinedConstant();
203
204 Node* executor = UndefinedConstant();
205 Node* construct = graph()->NewNode(
206 javascript()->Construct(JSConstructNode::ArityForArgc(1)), promise,
207 promise, executor, feedback, context, frame_state, effect, control);
208
209 Protectors::InvalidatePromiseHook(isolate());
210
211 Reduction r = Reduce(construct);
212
213 ASSERT_FALSE(r.Changed());
214 }
215
216 // -----------------------------------------------------------------------------
217 // Math unaries
218
219 namespace {
220
221 const char* kMathUnaries[] = {
222 "abs", "acos", "acosh", "asin", "asinh", "atan", "cbrt",
223 "ceil", "cos", "cosh", "exp", "expm1", "floor", "fround",
224 "log", "log1p", "log10", "log2", "round", "sign", "sin",
225 "sinh", "sqrt", "tan", "tanh", "trunc"};
226
227 } // namespace
228
TEST_F(JSCallReducerTest,MathUnaryWithNumber)229 TEST_F(JSCallReducerTest, MathUnaryWithNumber) {
230 TRACED_FOREACH(const char*, fnc, kMathUnaries) {
231 Node* effect = graph()->start();
232 Node* control = graph()->start();
233 Node* context = UndefinedConstant();
234 Node* frame_state = DummyFrameState();
235 Node* jsfunction = MathFunction(fnc);
236 Node* p0 = Parameter(Type::Any(), 0);
237 Node* feedback = UndefinedConstant();
238 Node* call =
239 graph()->NewNode(Call(1), jsfunction, UndefinedConstant(), p0, feedback,
240 context, frame_state, effect, control);
241 Reduction r = Reduce(call);
242 ASSERT_TRUE(r.Changed());
243 EXPECT_THAT(std::string(IrOpcode::Mnemonic(r.replacement()->opcode())),
244 op_name_for(fnc));
245 }
246 }
247
248 // -----------------------------------------------------------------------------
249 // Math binaries
250
251 namespace {
252
253 const char* kMathBinaries[] = {"atan2", "pow"};
254
255 } // namespace
256
TEST_F(JSCallReducerTest,MathBinaryWithNumber)257 TEST_F(JSCallReducerTest, MathBinaryWithNumber) {
258 TRACED_FOREACH(const char*, fnc, kMathBinaries) {
259 Node* jsfunction = MathFunction(fnc);
260
261 Node* effect = graph()->start();
262 Node* control = graph()->start();
263 Node* context = UndefinedConstant();
264 Node* frame_state = DummyFrameState();
265 Node* p0 = Parameter(Type::Any(), 0);
266 Node* p1 = Parameter(Type::Any(), 0);
267 Node* feedback = UndefinedConstant();
268 Node* call =
269 graph()->NewNode(Call(2), jsfunction, UndefinedConstant(), p0, p1,
270 feedback, context, frame_state, effect, control);
271 Reduction r = Reduce(call);
272
273 ASSERT_TRUE(r.Changed());
274 EXPECT_THAT(std::string(IrOpcode::Mnemonic(r.replacement()->opcode())),
275 op_name_for(fnc));
276 }
277 }
278
279 // -----------------------------------------------------------------------------
280 // Math.clz32
281
TEST_F(JSCallReducerTest,MathClz32WithUnsigned32)282 TEST_F(JSCallReducerTest, MathClz32WithUnsigned32) {
283 Node* jsfunction = MathFunction("clz32");
284 Node* effect = graph()->start();
285 Node* control = graph()->start();
286 Node* context = UndefinedConstant();
287 Node* frame_state = DummyFrameState();
288
289 Node* p0 = Parameter(Type::Unsigned32(), 0);
290 Node* feedback = UndefinedConstant();
291 Node* call =
292 graph()->NewNode(Call(1), jsfunction, UndefinedConstant(), p0, feedback,
293 context, frame_state, effect, control);
294 Reduction r = Reduce(call);
295
296 ASSERT_TRUE(r.Changed());
297 EXPECT_THAT(r.replacement(),
298 IsNumberClz32(IsNumberToUint32(IsSpeculativeToNumber(p0))));
299 }
300
TEST_F(JSCallReducerTest,MathClz32WithUnsigned32NoArg)301 TEST_F(JSCallReducerTest, MathClz32WithUnsigned32NoArg) {
302 Node* jsfunction = MathFunction("clz32");
303 Node* effect = graph()->start();
304 Node* control = graph()->start();
305 Node* context = UndefinedConstant();
306 Node* frame_state = DummyFrameState();
307
308 Node* feedback = UndefinedConstant();
309 Node* call =
310 graph()->NewNode(Call(0), jsfunction, UndefinedConstant(), feedback,
311 context, frame_state, effect, control);
312 Reduction r = Reduce(call);
313
314 ASSERT_TRUE(r.Changed());
315 EXPECT_THAT(r.replacement(), IsNumberConstant(32));
316 }
317
318 // -----------------------------------------------------------------------------
319 // Math.imul
320
TEST_F(JSCallReducerTest,MathImulWithUnsigned32)321 TEST_F(JSCallReducerTest, MathImulWithUnsigned32) {
322 Node* jsfunction = MathFunction("imul");
323
324 Node* effect = graph()->start();
325 Node* control = graph()->start();
326 Node* context = UndefinedConstant();
327 Node* frame_state = DummyFrameState();
328 Node* p0 = Parameter(Type::Unsigned32(), 0);
329 Node* p1 = Parameter(Type::Unsigned32(), 1);
330 Node* feedback = UndefinedConstant();
331 Node* call =
332 graph()->NewNode(Call(2), jsfunction, UndefinedConstant(), p0, p1,
333 feedback, context, frame_state, effect, control);
334 Reduction r = Reduce(call);
335
336 ASSERT_TRUE(r.Changed());
337 EXPECT_THAT(std::string(IrOpcode::Mnemonic(r.replacement()->opcode())),
338 op_name_for("imul"));
339 }
340
341 // -----------------------------------------------------------------------------
342 // Math.min
343
TEST_F(JSCallReducerTest,MathMinWithNoArguments)344 TEST_F(JSCallReducerTest, MathMinWithNoArguments) {
345 Node* jsfunction = MathFunction("min");
346 Node* effect = graph()->start();
347 Node* control = graph()->start();
348 Node* context = UndefinedConstant();
349 Node* frame_state = DummyFrameState();
350 Node* feedback = UndefinedConstant();
351 Node* call =
352 graph()->NewNode(Call(0), jsfunction, UndefinedConstant(), feedback,
353 context, frame_state, effect, control);
354 Reduction r = Reduce(call);
355
356 ASSERT_TRUE(r.Changed());
357 EXPECT_THAT(r.replacement(), IsNumberConstant(V8_INFINITY));
358 }
359
TEST_F(JSCallReducerTest,MathMinWithNumber)360 TEST_F(JSCallReducerTest, MathMinWithNumber) {
361 Node* jsfunction = MathFunction("min");
362 Node* effect = graph()->start();
363 Node* control = graph()->start();
364 Node* context = UndefinedConstant();
365 Node* frame_state = DummyFrameState();
366 Node* p0 = Parameter(Type::Any(), 0);
367 Node* feedback = UndefinedConstant();
368 Node* call =
369 graph()->NewNode(Call(1), jsfunction, UndefinedConstant(), p0, feedback,
370 context, frame_state, effect, control);
371 Reduction r = Reduce(call);
372
373 ASSERT_TRUE(r.Changed());
374 EXPECT_THAT(r.replacement(), IsSpeculativeToNumber(p0));
375 }
376
TEST_F(JSCallReducerTest,MathMinWithTwoArguments)377 TEST_F(JSCallReducerTest, MathMinWithTwoArguments) {
378 Node* jsfunction = MathFunction("min");
379 Node* effect = graph()->start();
380 Node* control = graph()->start();
381 Node* context = UndefinedConstant();
382 Node* frame_state = DummyFrameState();
383 Node* p0 = Parameter(Type::Any(), 0);
384 Node* p1 = Parameter(Type::Any(), 1);
385 Node* feedback = UndefinedConstant();
386 Node* call =
387 graph()->NewNode(Call(2), jsfunction, UndefinedConstant(), p0, p1,
388 feedback, context, frame_state, effect, control);
389 Reduction r = Reduce(call);
390
391 ASSERT_TRUE(r.Changed());
392 EXPECT_THAT(r.replacement(), IsNumberMin(IsSpeculativeToNumber(p0),
393 IsSpeculativeToNumber(p1)));
394 }
395
396 // -----------------------------------------------------------------------------
397 // Math.max
398
TEST_F(JSCallReducerTest,MathMaxWithNoArguments)399 TEST_F(JSCallReducerTest, MathMaxWithNoArguments) {
400 Node* jsfunction = MathFunction("max");
401
402 Node* effect = graph()->start();
403 Node* control = graph()->start();
404 Node* context = UndefinedConstant();
405 Node* frame_state = DummyFrameState();
406 Node* feedback = UndefinedConstant();
407 Node* call =
408 graph()->NewNode(Call(0), jsfunction, UndefinedConstant(), feedback,
409 context, frame_state, effect, control);
410 Reduction r = Reduce(call);
411
412 ASSERT_TRUE(r.Changed());
413 EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY));
414 }
415
TEST_F(JSCallReducerTest,MathMaxWithNumber)416 TEST_F(JSCallReducerTest, MathMaxWithNumber) {
417 Node* jsfunction = MathFunction("max");
418 Node* effect = graph()->start();
419 Node* control = graph()->start();
420 Node* context = UndefinedConstant();
421 Node* frame_state = DummyFrameState();
422 Node* p0 = Parameter(Type::Any(), 0);
423 Node* feedback = UndefinedConstant();
424 Node* call =
425 graph()->NewNode(Call(1), jsfunction, UndefinedConstant(), p0, feedback,
426 context, frame_state, effect, control);
427 Reduction r = Reduce(call);
428
429 ASSERT_TRUE(r.Changed());
430 EXPECT_THAT(r.replacement(), IsSpeculativeToNumber(p0));
431 }
432
TEST_F(JSCallReducerTest,MathMaxWithTwoArguments)433 TEST_F(JSCallReducerTest, MathMaxWithTwoArguments) {
434 Node* jsfunction = MathFunction("max");
435
436 Node* effect = graph()->start();
437 Node* control = graph()->start();
438 Node* context = UndefinedConstant();
439 Node* frame_state = DummyFrameState();
440 Node* p0 = Parameter(Type::Any(), 0);
441 Node* p1 = Parameter(Type::Any(), 1);
442 Node* feedback = UndefinedConstant();
443 Node* call =
444 graph()->NewNode(Call(2), jsfunction, UndefinedConstant(), p0, p1,
445 feedback, context, frame_state, effect, control);
446 Reduction r = Reduce(call);
447
448 ASSERT_TRUE(r.Changed());
449 EXPECT_THAT(r.replacement(), IsNumberMax(IsSpeculativeToNumber(p0),
450 IsSpeculativeToNumber(p1)));
451 }
452
453 // -----------------------------------------------------------------------------
454 // String.fromCharCode
455
TEST_F(JSCallReducerTest,StringFromSingleCharCodeWithNumber)456 TEST_F(JSCallReducerTest, StringFromSingleCharCodeWithNumber) {
457 Node* function = StringFunction("fromCharCode");
458
459 Node* effect = graph()->start();
460 Node* control = graph()->start();
461 Node* context = UndefinedConstant();
462 Node* frame_state = DummyFrameState();
463 Node* p0 = Parameter(Type::Any(), 0);
464 Node* feedback = UndefinedConstant();
465 Node* call =
466 graph()->NewNode(Call(1), function, UndefinedConstant(), p0, feedback,
467 context, frame_state, effect, control);
468 Reduction r = Reduce(call);
469
470 ASSERT_TRUE(r.Changed());
471 EXPECT_THAT(r.replacement(),
472 IsStringFromSingleCharCode(IsSpeculativeToNumber(p0)));
473 }
474
TEST_F(JSCallReducerTest,StringFromSingleCharCodeWithPlainPrimitive)475 TEST_F(JSCallReducerTest, StringFromSingleCharCodeWithPlainPrimitive) {
476 Node* function = StringFunction("fromCharCode");
477
478 Node* effect = graph()->start();
479 Node* control = graph()->start();
480 Node* context = UndefinedConstant();
481 Node* frame_state = DummyFrameState();
482 Node* p0 = Parameter(Type::PlainPrimitive(), 0);
483 Node* feedback = UndefinedConstant();
484 Node* call =
485 graph()->NewNode(Call(1), function, UndefinedConstant(), p0, feedback,
486 context, frame_state, effect, control);
487 Reduction r = Reduce(call);
488
489 ASSERT_TRUE(r.Changed());
490 EXPECT_THAT(r.replacement(),
491 IsStringFromSingleCharCode(IsSpeculativeToNumber(p0)));
492 }
493
494 // -----------------------------------------------------------------------------
495 // Number.isFinite
496
TEST_F(JSCallReducerTest,NumberIsFinite)497 TEST_F(JSCallReducerTest, NumberIsFinite) {
498 Node* function = NumberFunction("isFinite");
499
500 Node* effect = graph()->start();
501 Node* control = graph()->start();
502 Node* context = UndefinedConstant();
503 Node* frame_state = DummyFrameState();
504 Node* p0 = Parameter(Type::Any(), 0);
505 Node* feedback = UndefinedConstant();
506 Node* call =
507 graph()->NewNode(Call(1), function, UndefinedConstant(), p0, feedback,
508 context, frame_state, effect, control);
509 Reduction r = Reduce(call);
510
511 ASSERT_TRUE(r.Changed());
512 EXPECT_THAT(r.replacement(), IsObjectIsFiniteNumber(p0));
513 }
514
515 // -----------------------------------------------------------------------------
516 // Number.isInteger
517
TEST_F(JSCallReducerTest,NumberIsIntegerWithNumber)518 TEST_F(JSCallReducerTest, NumberIsIntegerWithNumber) {
519 Node* function = NumberFunction("isInteger");
520
521 Node* effect = graph()->start();
522 Node* control = graph()->start();
523 Node* context = UndefinedConstant();
524 Node* frame_state = DummyFrameState();
525 Node* p0 = Parameter(Type::Any(), 0);
526 Node* feedback = UndefinedConstant();
527 Node* call =
528 graph()->NewNode(Call(1), function, UndefinedConstant(), p0, feedback,
529 context, frame_state, effect, control);
530 Reduction r = Reduce(call);
531
532 ASSERT_TRUE(r.Changed());
533 EXPECT_THAT(r.replacement(), IsObjectIsInteger(p0));
534 }
535
536 // -----------------------------------------------------------------------------
537 // Number.isNaN
538
TEST_F(JSCallReducerTest,NumberIsNaNWithNumber)539 TEST_F(JSCallReducerTest, NumberIsNaNWithNumber) {
540 Node* function = NumberFunction("isNaN");
541
542 Node* effect = graph()->start();
543 Node* control = graph()->start();
544 Node* context = UndefinedConstant();
545 Node* frame_state = DummyFrameState();
546 Node* p0 = Parameter(Type::Any(), 0);
547 Node* feedback = UndefinedConstant();
548 Node* call =
549 graph()->NewNode(Call(1), function, UndefinedConstant(), p0, feedback,
550 context, frame_state, effect, control);
551 Reduction r = Reduce(call);
552
553 ASSERT_TRUE(r.Changed());
554 EXPECT_THAT(r.replacement(), IsObjectIsNaN(p0));
555 }
556
557 // -----------------------------------------------------------------------------
558 // Number.isSafeInteger
559
TEST_F(JSCallReducerTest,NumberIsSafeIntegerWithIntegral32)560 TEST_F(JSCallReducerTest, NumberIsSafeIntegerWithIntegral32) {
561 Node* function = NumberFunction("isSafeInteger");
562
563 Node* effect = graph()->start();
564 Node* control = graph()->start();
565 Node* context = UndefinedConstant();
566 Node* frame_state = DummyFrameState();
567 Node* p0 = Parameter(Type::Any(), 0);
568 Node* feedback = UndefinedConstant();
569 Node* call =
570 graph()->NewNode(Call(1), function, UndefinedConstant(), p0, feedback,
571 context, frame_state, effect, control);
572 Reduction r = Reduce(call);
573
574 ASSERT_TRUE(r.Changed());
575 EXPECT_THAT(r.replacement(), IsObjectIsSafeInteger(p0));
576 }
577
578 // -----------------------------------------------------------------------------
579 // isFinite
580
TEST_F(JSCallReducerTest,GlobalIsFiniteWithNumber)581 TEST_F(JSCallReducerTest, GlobalIsFiniteWithNumber) {
582 Node* function = GlobalFunction("isFinite");
583
584 Node* effect = graph()->start();
585 Node* control = graph()->start();
586 Node* context = UndefinedConstant();
587 Node* frame_state = DummyFrameState();
588 Node* p0 = Parameter(Type::Any(), 0);
589 Node* feedback = UndefinedConstant();
590 Node* call =
591 graph()->NewNode(Call(1), function, UndefinedConstant(), p0, feedback,
592 context, frame_state, effect, control);
593 Reduction r = Reduce(call);
594
595 ASSERT_TRUE(r.Changed());
596 EXPECT_THAT(r.replacement(), IsNumberIsFinite(IsSpeculativeToNumber(p0)));
597 }
598
599 // -----------------------------------------------------------------------------
600 // isNaN
601
TEST_F(JSCallReducerTest,GlobalIsNaN)602 TEST_F(JSCallReducerTest, GlobalIsNaN) {
603 Node* function = GlobalFunction("isNaN");
604
605 Node* effect = graph()->start();
606 Node* control = graph()->start();
607 Node* context = UndefinedConstant();
608 Node* frame_state = DummyFrameState();
609 Node* p0 = Parameter(Type::Any(), 0);
610 Node* feedback = UndefinedConstant();
611 Node* call =
612 graph()->NewNode(Call(1), function, UndefinedConstant(), p0, feedback,
613 context, frame_state, effect, control);
614 Reduction r = Reduce(call);
615
616 ASSERT_TRUE(r.Changed());
617 EXPECT_THAT(r.replacement(), IsNumberIsNaN(IsSpeculativeToNumber(p0)));
618 }
619
620 // -----------------------------------------------------------------------------
621 // Number.parseInt
622
TEST_F(JSCallReducerTest,NumberParseInt)623 TEST_F(JSCallReducerTest, NumberParseInt) {
624 Node* function = NumberFunction("parseInt");
625
626 Node* effect = graph()->start();
627 Node* control = graph()->start();
628 Node* context = UndefinedConstant();
629 Node* frame_state = DummyFrameState();
630 Node* p0 = Parameter(Type::Any(), 0);
631 Node* p1 = Parameter(Type::Any(), 1);
632 Node* feedback = UndefinedConstant();
633 Node* call =
634 graph()->NewNode(Call(2), function, UndefinedConstant(), p0, p1, feedback,
635 context, frame_state, effect, control);
636 Reduction r = Reduce(call);
637
638 ASSERT_TRUE(r.Changed());
639 EXPECT_THAT(r.replacement(), IsJSParseInt(p0, p1));
640 }
641
642 } // namespace compiler
643 } // namespace internal
644 } // namespace v8
645