V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
builtins-math-gen.cc
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
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 
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 
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 
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 
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
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
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  Node* const refill_math_random =
417  ExternalConstant(ExternalReference::refill_math_random());
418  Node* const isolate_ptr =
419  ExternalConstant(ExternalReference::isolate_address(isolate()));
420  MachineType type_tagged = MachineType::AnyTagged();
421  MachineType type_ptr = MachineType::Pointer();
422 
423  smi_index =
424  CAST(CallCFunction2(type_tagged, type_ptr, type_tagged,
425  refill_math_random, isolate_ptr, native_context));
426  Goto(&if_cached);
427 
428  // Compute next index by decrement.
429  BIND(&if_cached);
430  TNode<Smi> new_smi_index = SmiSub(smi_index.value(), SmiConstant(1));
431  StoreContextElement(native_context, Context::MATH_RANDOM_INDEX_INDEX,
432  new_smi_index);
433 
434  // Load and return next cached random number.
435  Node* array =
436  LoadContextElement(native_context, Context::MATH_RANDOM_CACHE_INDEX);
437  Node* random = LoadFixedDoubleArrayElement(
438  array, new_smi_index, MachineType::Float64(), 0, SMI_PARAMETERS);
439  Return(AllocateHeapNumberWithValue(random));
440 }
441 
442 // ES6 #sec-math.round
443 TF_BUILTIN(MathRound, MathBuiltinsAssembler) {
444  Node* context = Parameter(Descriptor::kContext);
445  Node* x = Parameter(Descriptor::kX);
446  MathRoundingOperation(context, x, &CodeStubAssembler::Float64Round);
447 }
448 
449 // ES6 #sec-math.sign
450 TF_BUILTIN(MathSign, CodeStubAssembler) {
451  // Convert the {x} value to a Number.
452  Node* context = Parameter(Descriptor::kContext);
453  Node* x = Parameter(Descriptor::kX);
454  Node* x_value = TruncateTaggedToFloat64(context, x);
455 
456  // Return -1 if {x} is negative, 1 if {x} is positive, or {x} itself.
457  Label if_xisnegative(this), if_xispositive(this);
458  GotoIf(Float64LessThan(x_value, Float64Constant(0.0)), &if_xisnegative);
459  GotoIf(Float64LessThan(Float64Constant(0.0), x_value), &if_xispositive);
460  Return(ChangeFloat64ToTagged(x_value));
461 
462  BIND(&if_xisnegative);
463  Return(SmiConstant(-1));
464 
465  BIND(&if_xispositive);
466  Return(SmiConstant(1));
467 }
468 
469 // ES6 #sec-math.sin
470 TF_BUILTIN(MathSin, MathBuiltinsAssembler) {
471  Node* context = Parameter(Descriptor::kContext);
472  Node* x = Parameter(Descriptor::kX);
473  MathUnaryOperation(context, x, &CodeStubAssembler::Float64Sin);
474 }
475 
476 // ES6 #sec-math.sinh
477 TF_BUILTIN(MathSinh, MathBuiltinsAssembler) {
478  Node* context = Parameter(Descriptor::kContext);
479  Node* x = Parameter(Descriptor::kX);
480  MathUnaryOperation(context, x, &CodeStubAssembler::Float64Sinh);
481 }
482 
483 // ES6 #sec-math.sqrt
484 TF_BUILTIN(MathSqrt, MathBuiltinsAssembler) {
485  Node* context = Parameter(Descriptor::kContext);
486  Node* x = Parameter(Descriptor::kX);
487  MathUnaryOperation(context, x, &CodeStubAssembler::Float64Sqrt);
488 }
489 
490 // ES6 #sec-math.tan
491 TF_BUILTIN(MathTan, MathBuiltinsAssembler) {
492  Node* context = Parameter(Descriptor::kContext);
493  Node* x = Parameter(Descriptor::kX);
494  MathUnaryOperation(context, x, &CodeStubAssembler::Float64Tan);
495 }
496 
497 // ES6 #sec-math.tanh
498 TF_BUILTIN(MathTanh, MathBuiltinsAssembler) {
499  Node* context = Parameter(Descriptor::kContext);
500  Node* x = Parameter(Descriptor::kX);
501  MathUnaryOperation(context, x, &CodeStubAssembler::Float64Tanh);
502 }
503 
504 // ES6 #sec-math.trunc
505 TF_BUILTIN(MathTrunc, MathBuiltinsAssembler) {
506  Node* context = Parameter(Descriptor::kContext);
507  Node* x = Parameter(Descriptor::kX);
508  MathRoundingOperation(context, x, &CodeStubAssembler::Float64Trunc);
509 }
510 
511 // ES6 #sec-math.max
512 TF_BUILTIN(MathMax, MathBuiltinsAssembler) {
513  // TODO(ishell): use constants from Descriptor once the JSFunction linkage
514  // arguments are reordered.
515  Node* context = Parameter(Descriptor::kContext);
516  Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);
517  MathMaxMin(context, argc, &CodeStubAssembler::Float64Max, -1.0 * V8_INFINITY);
518 }
519 
520 // ES6 #sec-math.min
521 TF_BUILTIN(MathMin, MathBuiltinsAssembler) {
522  // TODO(ishell): use constants from Descriptor once the JSFunction linkage
523  // arguments are reordered.
524  Node* context = Parameter(Descriptor::kContext);
525  Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);
526  MathMaxMin(context, argc, &CodeStubAssembler::Float64Min, V8_INFINITY);
527 }
528 
529 } // namespace internal
530 } // namespace v8
Definition: libplatform.h:13