1 // Copyright 2017 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/builtins/builtins-math-gen.h"
6 
7 #include "src/builtins/builtins-utils-gen.h"
8 #include "src/builtins/builtins.h"
9 #include "src/code-factory.h"
10 #include "src/code-stub-assembler.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 // -----------------------------------------------------------------------------
16 // ES6 section 20.2.2 Function Properties of the Math Object
17 
18 // ES6 #sec-math.abs
TF_BUILTIN(MathAbs,CodeStubAssembler)19 TF_BUILTIN(MathAbs, CodeStubAssembler) {
20   Node* context = Parameter(Descriptor::kContext);
21 
22   // We might need to loop once for ToNumber conversion.
23   VARIABLE(var_x, MachineRepresentation::kTagged);
24   Label loop(this, &var_x);
25   var_x.Bind(Parameter(Descriptor::kX));
26   Goto(&loop);
27   BIND(&loop);
28   {
29     // Load the current {x} value.
30     Node* x = var_x.value();
31 
32     // Check if {x} is a Smi or a HeapObject.
33     Label if_xissmi(this), if_xisnotsmi(this);
34     Branch(TaggedIsSmi(x), &if_xissmi, &if_xisnotsmi);
35 
36     BIND(&if_xissmi);
37     {
38       Label if_overflow(this, Label::kDeferred);
39 
40       // check if support abs function
41       if (IsIntPtrAbsWithOverflowSupported()) {
42         Node* pair = IntPtrAbsWithOverflow(x);
43         Node* overflow = Projection(1, pair);
44         GotoIf(overflow, &if_overflow);
45 
46         // There is a Smi representation for negated {x}.
47         Node* result = Projection(0, pair);
48         Return(BitcastWordToTagged(result));
49 
50       } else {
51         // Check if {x} is already positive.
52         Label if_xispositive(this), if_xisnotpositive(this);
53         BranchIfSmiLessThanOrEqual(SmiConstant(0), CAST(x), &if_xispositive,
54                                    &if_xisnotpositive);
55 
56         BIND(&if_xispositive);
57         {
58           // Just return the input {x}.
59           Return(x);
60         }
61 
62         BIND(&if_xisnotpositive);
63         {
64           // Try to negate the {x} value.
65           TNode<Smi> result = TrySmiSub(SmiConstant(0), CAST(x), &if_overflow);
66           Return(result);
67         }
68       }
69 
70       BIND(&if_overflow);
71       { Return(NumberConstant(0.0 - Smi::kMinValue)); }
72     }
73 
74     BIND(&if_xisnotsmi);
75     {
76       // Check if {x} is a HeapNumber.
77       Label if_xisheapnumber(this), if_xisnotheapnumber(this, Label::kDeferred);
78       Branch(IsHeapNumber(x), &if_xisheapnumber, &if_xisnotheapnumber);
79 
80       BIND(&if_xisheapnumber);
81       {
82         Node* x_value = LoadHeapNumberValue(x);
83         Node* value = Float64Abs(x_value);
84         Node* result = AllocateHeapNumberWithValue(value);
85         Return(result);
86       }
87 
88       BIND(&if_xisnotheapnumber);
89       {
90         // Need to convert {x} to a Number first.
91         var_x.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, x));
92         Goto(&loop);
93       }
94     }
95   }
96 }
97 
MathRoundingOperation(Node * context,Node * x,TNode<Float64T> (CodeStubAssembler::* float64op)(SloppyTNode<Float64T>))98 void MathBuiltinsAssembler::MathRoundingOperation(
99     Node* context, Node* x,
100     TNode<Float64T> (CodeStubAssembler::*float64op)(SloppyTNode<Float64T>)) {
101   // We might need to loop once for ToNumber conversion.
102   VARIABLE(var_x, MachineRepresentation::kTagged, x);
103   Label loop(this, &var_x);
104   Goto(&loop);
105   BIND(&loop);
106   {
107     // Load the current {x} value.
108     Node* x = var_x.value();
109 
110     // Check if {x} is a Smi or a HeapObject.
111     Label if_xissmi(this), if_xisnotsmi(this);
112     Branch(TaggedIsSmi(x), &if_xissmi, &if_xisnotsmi);
113 
114     BIND(&if_xissmi);
115     {
116       // Nothing to do when {x} is a Smi.
117       Return(x);
118     }
119 
120     BIND(&if_xisnotsmi);
121     {
122       // Check if {x} is a HeapNumber.
123       Label if_xisheapnumber(this), if_xisnotheapnumber(this, Label::kDeferred);
124       Branch(IsHeapNumber(x), &if_xisheapnumber, &if_xisnotheapnumber);
125 
126       BIND(&if_xisheapnumber);
127       {
128         Node* x_value = LoadHeapNumberValue(x);
129         Node* value = (this->*float64op)(x_value);
130         Node* result = ChangeFloat64ToTagged(value);
131         Return(result);
132       }
133 
134       BIND(&if_xisnotheapnumber);
135       {
136         // Need to convert {x} to a Number first.
137         var_x.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, x));
138         Goto(&loop);
139       }
140     }
141   }
142 }
143 
MathUnaryOperation(Node * context,Node * x,TNode<Float64T> (CodeStubAssembler::* float64op)(SloppyTNode<Float64T>))144 void MathBuiltinsAssembler::MathUnaryOperation(
145     Node* context, Node* x,
146     TNode<Float64T> (CodeStubAssembler::*float64op)(SloppyTNode<Float64T>)) {
147   Node* x_value = TruncateTaggedToFloat64(context, x);
148   Node* value = (this->*float64op)(x_value);
149   Node* result = AllocateHeapNumberWithValue(value);
150   Return(result);
151 }
152 
MathMaxMin(Node * context,Node * argc,TNode<Float64T> (CodeStubAssembler::* float64op)(SloppyTNode<Float64T>,SloppyTNode<Float64T>),double default_val)153 void MathBuiltinsAssembler::MathMaxMin(
154     Node* context, Node* argc,
155     TNode<Float64T> (CodeStubAssembler::*float64op)(SloppyTNode<Float64T>,
156                                                     SloppyTNode<Float64T>),
157     double default_val) {
158   CodeStubArguments arguments(this, ChangeInt32ToIntPtr(argc));
159   argc = arguments.GetLength(INTPTR_PARAMETERS);
160 
161   VARIABLE(result, MachineRepresentation::kFloat64);
162   result.Bind(Float64Constant(default_val));
163 
164   CodeStubAssembler::VariableList vars({&result}, zone());
165   arguments.ForEach(vars, [=, &result](Node* arg) {
166     Node* float_value = TruncateTaggedToFloat64(context, arg);
167     result.Bind((this->*float64op)(result.value(), float_value));
168   });
169 
170   arguments.PopAndReturn(ChangeFloat64ToTagged(result.value()));
171 }
172 
173 // ES6 #sec-math.acos
TF_BUILTIN(MathAcos,MathBuiltinsAssembler)174 TF_BUILTIN(MathAcos, MathBuiltinsAssembler) {
175   Node* context = Parameter(Descriptor::kContext);
176   Node* x = Parameter(Descriptor::kX);
177   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Acos);
178 }
179 
180 // ES6 #sec-math.acosh
TF_BUILTIN(MathAcosh,MathBuiltinsAssembler)181 TF_BUILTIN(MathAcosh, MathBuiltinsAssembler) {
182   Node* context = Parameter(Descriptor::kContext);
183   Node* x = Parameter(Descriptor::kX);
184   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Acosh);
185 }
186 
187 // ES6 #sec-math.asin
TF_BUILTIN(MathAsin,MathBuiltinsAssembler)188 TF_BUILTIN(MathAsin, MathBuiltinsAssembler) {
189   Node* context = Parameter(Descriptor::kContext);
190   Node* x = Parameter(Descriptor::kX);
191   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Asin);
192 }
193 
194 // ES6 #sec-math.asinh
TF_BUILTIN(MathAsinh,MathBuiltinsAssembler)195 TF_BUILTIN(MathAsinh, MathBuiltinsAssembler) {
196   Node* context = Parameter(Descriptor::kContext);
197   Node* x = Parameter(Descriptor::kX);
198   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Asinh);
199 }
200 
201 // ES6 #sec-math.atan
TF_BUILTIN(MathAtan,MathBuiltinsAssembler)202 TF_BUILTIN(MathAtan, MathBuiltinsAssembler) {
203   Node* context = Parameter(Descriptor::kContext);
204   Node* x = Parameter(Descriptor::kX);
205   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Atan);
206 }
207 
208 // ES6 #sec-math.atanh
TF_BUILTIN(MathAtanh,MathBuiltinsAssembler)209 TF_BUILTIN(MathAtanh, MathBuiltinsAssembler) {
210   Node* context = Parameter(Descriptor::kContext);
211   Node* x = Parameter(Descriptor::kX);
212   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Atanh);
213 }
214 
215 // ES6 #sec-math.atan2
TF_BUILTIN(MathAtan2,CodeStubAssembler)216 TF_BUILTIN(MathAtan2, CodeStubAssembler) {
217   Node* context = Parameter(Descriptor::kContext);
218   Node* y = Parameter(Descriptor::kY);
219   Node* x = Parameter(Descriptor::kX);
220 
221   Node* y_value = TruncateTaggedToFloat64(context, y);
222   Node* x_value = TruncateTaggedToFloat64(context, x);
223   Node* value = Float64Atan2(y_value, x_value);
224   Node* result = AllocateHeapNumberWithValue(value);
225   Return(result);
226 }
227 
228 // ES6 #sec-math.ceil
TF_BUILTIN(MathCeil,MathBuiltinsAssembler)229 TF_BUILTIN(MathCeil, MathBuiltinsAssembler) {
230   Node* context = Parameter(Descriptor::kContext);
231   Node* x = Parameter(Descriptor::kX);
232   MathRoundingOperation(context, x, &CodeStubAssembler::Float64Ceil);
233 }
234 
235 // ES6 #sec-math.cbrt
TF_BUILTIN(MathCbrt,MathBuiltinsAssembler)236 TF_BUILTIN(MathCbrt, MathBuiltinsAssembler) {
237   Node* context = Parameter(Descriptor::kContext);
238   Node* x = Parameter(Descriptor::kX);
239   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Cbrt);
240 }
241 
242 // ES6 #sec-math.clz32
TF_BUILTIN(MathClz32,CodeStubAssembler)243 TF_BUILTIN(MathClz32, CodeStubAssembler) {
244   Node* context = Parameter(Descriptor::kContext);
245 
246   // Shared entry point for the clz32 operation.
247   VARIABLE(var_clz32_x, MachineRepresentation::kWord32);
248   Label do_clz32(this);
249 
250   // We might need to loop once for ToNumber conversion.
251   VARIABLE(var_x, MachineRepresentation::kTagged);
252   Label loop(this, &var_x);
253   var_x.Bind(Parameter(Descriptor::kX));
254   Goto(&loop);
255   BIND(&loop);
256   {
257     // Load the current {x} value.
258     Node* x = var_x.value();
259 
260     // Check if {x} is a Smi or a HeapObject.
261     Label if_xissmi(this), if_xisnotsmi(this);
262     Branch(TaggedIsSmi(x), &if_xissmi, &if_xisnotsmi);
263 
264     BIND(&if_xissmi);
265     {
266       var_clz32_x.Bind(SmiToInt32(x));
267       Goto(&do_clz32);
268     }
269 
270     BIND(&if_xisnotsmi);
271     {
272       // Check if {x} is a HeapNumber.
273       Label if_xisheapnumber(this), if_xisnotheapnumber(this, Label::kDeferred);
274       Branch(IsHeapNumber(x), &if_xisheapnumber, &if_xisnotheapnumber);
275 
276       BIND(&if_xisheapnumber);
277       {
278         var_clz32_x.Bind(TruncateHeapNumberValueToWord32(x));
279         Goto(&do_clz32);
280       }
281 
282       BIND(&if_xisnotheapnumber);
283       {
284         // Need to convert {x} to a Number first.
285         var_x.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, x));
286         Goto(&loop);
287       }
288     }
289   }
290 
291   BIND(&do_clz32);
292   {
293     Node* x_value = var_clz32_x.value();
294     Node* value = Word32Clz(x_value);
295     Node* result = ChangeInt32ToTagged(value);
296     Return(result);
297   }
298 }
299 
300 // ES6 #sec-math.cos
TF_BUILTIN(MathCos,MathBuiltinsAssembler)301 TF_BUILTIN(MathCos, MathBuiltinsAssembler) {
302   Node* context = Parameter(Descriptor::kContext);
303   Node* x = Parameter(Descriptor::kX);
304   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Cos);
305 }
306 
307 // ES6 #sec-math.cosh
TF_BUILTIN(MathCosh,MathBuiltinsAssembler)308 TF_BUILTIN(MathCosh, MathBuiltinsAssembler) {
309   Node* context = Parameter(Descriptor::kContext);
310   Node* x = Parameter(Descriptor::kX);
311   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Cosh);
312 }
313 
314 // ES6 #sec-math.exp
TF_BUILTIN(MathExp,MathBuiltinsAssembler)315 TF_BUILTIN(MathExp, MathBuiltinsAssembler) {
316   Node* context = Parameter(Descriptor::kContext);
317   Node* x = Parameter(Descriptor::kX);
318   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Exp);
319 }
320 
321 // ES6 #sec-math.expm1
TF_BUILTIN(MathExpm1,MathBuiltinsAssembler)322 TF_BUILTIN(MathExpm1, MathBuiltinsAssembler) {
323   Node* context = Parameter(Descriptor::kContext);
324   Node* x = Parameter(Descriptor::kX);
325   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Expm1);
326 }
327 
328 // ES6 #sec-math.floor
TF_BUILTIN(MathFloor,MathBuiltinsAssembler)329 TF_BUILTIN(MathFloor, MathBuiltinsAssembler) {
330   Node* context = Parameter(Descriptor::kContext);
331   Node* x = Parameter(Descriptor::kX);
332   MathRoundingOperation(context, x, &CodeStubAssembler::Float64Floor);
333 }
334 
335 // ES6 #sec-math.fround
TF_BUILTIN(MathFround,CodeStubAssembler)336 TF_BUILTIN(MathFround, CodeStubAssembler) {
337   Node* context = Parameter(Descriptor::kContext);
338   Node* x = Parameter(Descriptor::kX);
339   Node* x_value = TruncateTaggedToFloat64(context, x);
340   Node* value32 = TruncateFloat64ToFloat32(x_value);
341   Node* value = ChangeFloat32ToFloat64(value32);
342   Node* result = AllocateHeapNumberWithValue(value);
343   Return(result);
344 }
345 
346 // ES6 #sec-math.imul
TF_BUILTIN(MathImul,CodeStubAssembler)347 TF_BUILTIN(MathImul, CodeStubAssembler) {
348   Node* context = Parameter(Descriptor::kContext);
349   Node* x = Parameter(Descriptor::kX);
350   Node* y = Parameter(Descriptor::kY);
351   Node* x_value = TruncateTaggedToWord32(context, x);
352   Node* y_value = TruncateTaggedToWord32(context, y);
353   Node* value = Int32Mul(x_value, y_value);
354   Node* result = ChangeInt32ToTagged(value);
355   Return(result);
356 }
357 
358 // ES6 #sec-math.log
TF_BUILTIN(MathLog,MathBuiltinsAssembler)359 TF_BUILTIN(MathLog, MathBuiltinsAssembler) {
360   Node* context = Parameter(Descriptor::kContext);
361   Node* x = Parameter(Descriptor::kX);
362   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Log);
363 }
364 
365 // ES6 #sec-math.log1p
TF_BUILTIN(MathLog1p,MathBuiltinsAssembler)366 TF_BUILTIN(MathLog1p, MathBuiltinsAssembler) {
367   Node* context = Parameter(Descriptor::kContext);
368   Node* x = Parameter(Descriptor::kX);
369   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Log1p);
370 }
371 
372 // ES6 #sec-math.log10
TF_BUILTIN(MathLog10,MathBuiltinsAssembler)373 TF_BUILTIN(MathLog10, MathBuiltinsAssembler) {
374   Node* context = Parameter(Descriptor::kContext);
375   Node* x = Parameter(Descriptor::kX);
376   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Log10);
377 }
378 
379 // ES6 #sec-math.log2
TF_BUILTIN(MathLog2,MathBuiltinsAssembler)380 TF_BUILTIN(MathLog2, MathBuiltinsAssembler) {
381   Node* context = Parameter(Descriptor::kContext);
382   Node* x = Parameter(Descriptor::kX);
383   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Log2);
384 }
385 
MathPow(Node * context,Node * base,Node * exponent)386 CodeStubAssembler::Node* MathBuiltinsAssembler::MathPow(Node* context,
387                                                         Node* base,
388                                                         Node* exponent) {
389   Node* base_value = TruncateTaggedToFloat64(context, base);
390   Node* exponent_value = TruncateTaggedToFloat64(context, exponent);
391   Node* value = Float64Pow(base_value, exponent_value);
392   return ChangeFloat64ToTagged(value);
393 }
394 
395 // ES6 #sec-math.pow
TF_BUILTIN(MathPow,MathBuiltinsAssembler)396 TF_BUILTIN(MathPow, MathBuiltinsAssembler) {
397   Return(MathPow(Parameter(Descriptor::kContext), Parameter(Descriptor::kBase),
398                  Parameter(Descriptor::kExponent)));
399 }
400 
401 // ES6 #sec-math.random
TF_BUILTIN(MathRandom,CodeStubAssembler)402 TF_BUILTIN(MathRandom, CodeStubAssembler) {
403   Node* context = Parameter(Descriptor::kContext);
404   Node* native_context = LoadNativeContext(context);
405 
406   // Load cache index.
407   TVARIABLE(Smi, smi_index);
408   smi_index = CAST(
409       LoadContextElement(native_context, Context::MATH_RANDOM_INDEX_INDEX));
410 
411   // Cached random numbers are exhausted if index is 0. Go to slow path.
412   Label if_cached(this);
413   GotoIf(SmiAbove(smi_index.value(), SmiConstant(0)), &if_cached);
414 
415   // Cache exhausted, populate the cache. Return value is the new index.
416   smi_index = CAST(CallRuntime(Runtime::kGenerateRandomNumbers, context));
417   Goto(&if_cached);
418 
419   // Compute next index by decrement.
420   BIND(&if_cached);
421   TNode<Smi> new_smi_index = SmiSub(smi_index.value(), SmiConstant(1));
422   StoreContextElement(native_context, Context::MATH_RANDOM_INDEX_INDEX,
423                       new_smi_index);
424 
425   // Load and return next cached random number.
426   Node* array =
427       LoadContextElement(native_context, Context::MATH_RANDOM_CACHE_INDEX);
428   Node* random = LoadFixedDoubleArrayElement(
429       array, new_smi_index, MachineType::Float64(), 0, SMI_PARAMETERS);
430   Return(AllocateHeapNumberWithValue(random));
431 }
432 
433 // ES6 #sec-math.round
TF_BUILTIN(MathRound,MathBuiltinsAssembler)434 TF_BUILTIN(MathRound, MathBuiltinsAssembler) {
435   Node* context = Parameter(Descriptor::kContext);
436   Node* x = Parameter(Descriptor::kX);
437   MathRoundingOperation(context, x, &CodeStubAssembler::Float64Round);
438 }
439 
440 // ES6 #sec-math.sign
TF_BUILTIN(MathSign,CodeStubAssembler)441 TF_BUILTIN(MathSign, CodeStubAssembler) {
442   // Convert the {x} value to a Number.
443   Node* context = Parameter(Descriptor::kContext);
444   Node* x = Parameter(Descriptor::kX);
445   Node* x_value = TruncateTaggedToFloat64(context, x);
446 
447   // Return -1 if {x} is negative, 1 if {x} is positive, or {x} itself.
448   Label if_xisnegative(this), if_xispositive(this);
449   GotoIf(Float64LessThan(x_value, Float64Constant(0.0)), &if_xisnegative);
450   GotoIf(Float64LessThan(Float64Constant(0.0), x_value), &if_xispositive);
451   Return(ChangeFloat64ToTagged(x_value));
452 
453   BIND(&if_xisnegative);
454   Return(SmiConstant(-1));
455 
456   BIND(&if_xispositive);
457   Return(SmiConstant(1));
458 }
459 
460 // ES6 #sec-math.sin
TF_BUILTIN(MathSin,MathBuiltinsAssembler)461 TF_BUILTIN(MathSin, MathBuiltinsAssembler) {
462   Node* context = Parameter(Descriptor::kContext);
463   Node* x = Parameter(Descriptor::kX);
464   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Sin);
465 }
466 
467 // ES6 #sec-math.sinh
TF_BUILTIN(MathSinh,MathBuiltinsAssembler)468 TF_BUILTIN(MathSinh, MathBuiltinsAssembler) {
469   Node* context = Parameter(Descriptor::kContext);
470   Node* x = Parameter(Descriptor::kX);
471   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Sinh);
472 }
473 
474 // ES6 #sec-math.sqrt
TF_BUILTIN(MathSqrt,MathBuiltinsAssembler)475 TF_BUILTIN(MathSqrt, MathBuiltinsAssembler) {
476   Node* context = Parameter(Descriptor::kContext);
477   Node* x = Parameter(Descriptor::kX);
478   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Sqrt);
479 }
480 
481 // ES6 #sec-math.tan
TF_BUILTIN(MathTan,MathBuiltinsAssembler)482 TF_BUILTIN(MathTan, MathBuiltinsAssembler) {
483   Node* context = Parameter(Descriptor::kContext);
484   Node* x = Parameter(Descriptor::kX);
485   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Tan);
486 }
487 
488 // ES6 #sec-math.tanh
TF_BUILTIN(MathTanh,MathBuiltinsAssembler)489 TF_BUILTIN(MathTanh, MathBuiltinsAssembler) {
490   Node* context = Parameter(Descriptor::kContext);
491   Node* x = Parameter(Descriptor::kX);
492   MathUnaryOperation(context, x, &CodeStubAssembler::Float64Tanh);
493 }
494 
495 // ES6 #sec-math.trunc
TF_BUILTIN(MathTrunc,MathBuiltinsAssembler)496 TF_BUILTIN(MathTrunc, MathBuiltinsAssembler) {
497   Node* context = Parameter(Descriptor::kContext);
498   Node* x = Parameter(Descriptor::kX);
499   MathRoundingOperation(context, x, &CodeStubAssembler::Float64Trunc);
500 }
501 
502 // ES6 #sec-math.max
TF_BUILTIN(MathMax,MathBuiltinsAssembler)503 TF_BUILTIN(MathMax, MathBuiltinsAssembler) {
504   // TODO(ishell): use constants from Descriptor once the JSFunction linkage
505   // arguments are reordered.
506   Node* context = Parameter(BuiltinDescriptor::kContext);
507   Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
508   MathMaxMin(context, argc, &CodeStubAssembler::Float64Max, -1.0 * V8_INFINITY);
509 }
510 
511 // ES6 #sec-math.min
TF_BUILTIN(MathMin,MathBuiltinsAssembler)512 TF_BUILTIN(MathMin, MathBuiltinsAssembler) {
513   // TODO(ishell): use constants from Descriptor once the JSFunction linkage
514   // arguments are reordered.
515   Node* context = Parameter(BuiltinDescriptor::kContext);
516   Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
517   MathMaxMin(context, argc, &CodeStubAssembler::Float64Min, V8_INFINITY);
518 }
519 
520 }  // namespace internal
521 }  // namespace v8
522