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