2850bdd727
Change-Id: I224ea998eccf8fa18766b71962d487bb02768c78 Reviewed-on: https://chromium-review.googlesource.com/518146 Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Mythri Alle <mythria@chromium.org> Commit-Queue: Camillo Bruni <cbruni@chromium.org> Cr-Commit-Position: refs/heads/master@{#45980}
533 lines
17 KiB
C++
533 lines
17 KiB
C++
// Copyright 2017 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "src/builtins/builtins-utils-gen.h"
|
|
#include "src/builtins/builtins.h"
|
|
#include "src/code-factory.h"
|
|
#include "src/code-stub-assembler.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// ES6 section 20.2.2 Function Properties of the Math Object
|
|
|
|
class MathBuiltinsAssembler : public CodeStubAssembler {
|
|
public:
|
|
explicit MathBuiltinsAssembler(compiler::CodeAssemblerState* state)
|
|
: CodeStubAssembler(state) {}
|
|
|
|
protected:
|
|
void MathRoundingOperation(Node* context, Node* x,
|
|
Node* (CodeStubAssembler::*float64op)(Node*));
|
|
void MathUnaryOperation(Node* context, Node* x,
|
|
Node* (CodeStubAssembler::*float64op)(Node*));
|
|
void MathMaxMin(Node* context, Node* argc,
|
|
Node* (CodeStubAssembler::*float64op)(Node*, Node*),
|
|
double default_val);
|
|
};
|
|
|
|
// ES6 #sec-math.abs
|
|
TF_BUILTIN(MathAbs, CodeStubAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
|
|
// We might need to loop once for ToNumber conversion.
|
|
VARIABLE(var_x, MachineRepresentation::kTagged);
|
|
Label loop(this, &var_x);
|
|
var_x.Bind(Parameter(Descriptor::kX));
|
|
Goto(&loop);
|
|
BIND(&loop);
|
|
{
|
|
// Load the current {x} value.
|
|
Node* x = var_x.value();
|
|
|
|
// Check if {x} is a Smi or a HeapObject.
|
|
Label if_xissmi(this), if_xisnotsmi(this);
|
|
Branch(TaggedIsSmi(x), &if_xissmi, &if_xisnotsmi);
|
|
|
|
BIND(&if_xissmi);
|
|
{
|
|
Label if_overflow(this, Label::kDeferred), if_notoverflow(this);
|
|
Node* pair = NULL;
|
|
|
|
// check if support abs function
|
|
if (IsIntPtrAbsWithOverflowSupported()) {
|
|
pair = IntPtrAbsWithOverflow(x);
|
|
Node* overflow = Projection(1, pair);
|
|
Branch(overflow, &if_overflow, &if_notoverflow);
|
|
} else {
|
|
// Check if {x} is already positive.
|
|
Label if_xispositive(this), if_xisnotpositive(this);
|
|
BranchIfSmiLessThanOrEqual(SmiConstant(Smi::FromInt(0)), x,
|
|
&if_xispositive, &if_xisnotpositive);
|
|
|
|
BIND(&if_xispositive);
|
|
{
|
|
// Just return the input {x}.
|
|
Return(x);
|
|
}
|
|
|
|
BIND(&if_xisnotpositive);
|
|
{
|
|
// Try to negate the {x} value.
|
|
pair =
|
|
IntPtrSubWithOverflow(IntPtrConstant(0), BitcastTaggedToWord(x));
|
|
Node* overflow = Projection(1, pair);
|
|
Branch(overflow, &if_overflow, &if_notoverflow);
|
|
}
|
|
}
|
|
|
|
BIND(&if_notoverflow);
|
|
{
|
|
// There is a Smi representation for negated {x}.
|
|
Node* result = Projection(0, pair);
|
|
Return(BitcastWordToTagged(result));
|
|
}
|
|
|
|
BIND(&if_overflow);
|
|
{ Return(NumberConstant(0.0 - Smi::kMinValue)); }
|
|
}
|
|
|
|
BIND(&if_xisnotsmi);
|
|
{
|
|
// Check if {x} is a HeapNumber.
|
|
Label if_xisheapnumber(this), if_xisnotheapnumber(this, Label::kDeferred);
|
|
Branch(IsHeapNumber(x), &if_xisheapnumber, &if_xisnotheapnumber);
|
|
|
|
BIND(&if_xisheapnumber);
|
|
{
|
|
Node* x_value = LoadHeapNumberValue(x);
|
|
Node* value = Float64Abs(x_value);
|
|
Node* result = AllocateHeapNumberWithValue(value);
|
|
Return(result);
|
|
}
|
|
|
|
BIND(&if_xisnotheapnumber);
|
|
{
|
|
// Need to convert {x} to a Number first.
|
|
var_x.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, x));
|
|
Goto(&loop);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MathBuiltinsAssembler::MathRoundingOperation(
|
|
Node* context, Node* x, Node* (CodeStubAssembler::*float64op)(Node*)) {
|
|
// We might need to loop once for ToNumber conversion.
|
|
VARIABLE(var_x, MachineRepresentation::kTagged, x);
|
|
Label loop(this, &var_x);
|
|
Goto(&loop);
|
|
BIND(&loop);
|
|
{
|
|
// Load the current {x} value.
|
|
Node* x = var_x.value();
|
|
|
|
// Check if {x} is a Smi or a HeapObject.
|
|
Label if_xissmi(this), if_xisnotsmi(this);
|
|
Branch(TaggedIsSmi(x), &if_xissmi, &if_xisnotsmi);
|
|
|
|
BIND(&if_xissmi);
|
|
{
|
|
// Nothing to do when {x} is a Smi.
|
|
Return(x);
|
|
}
|
|
|
|
BIND(&if_xisnotsmi);
|
|
{
|
|
// Check if {x} is a HeapNumber.
|
|
Label if_xisheapnumber(this), if_xisnotheapnumber(this, Label::kDeferred);
|
|
Branch(IsHeapNumber(x), &if_xisheapnumber, &if_xisnotheapnumber);
|
|
|
|
BIND(&if_xisheapnumber);
|
|
{
|
|
Node* x_value = LoadHeapNumberValue(x);
|
|
Node* value = (this->*float64op)(x_value);
|
|
Node* result = ChangeFloat64ToTagged(value);
|
|
Return(result);
|
|
}
|
|
|
|
BIND(&if_xisnotheapnumber);
|
|
{
|
|
// Need to convert {x} to a Number first.
|
|
var_x.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, x));
|
|
Goto(&loop);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MathBuiltinsAssembler::MathUnaryOperation(
|
|
Node* context, Node* x, Node* (CodeStubAssembler::*float64op)(Node*)) {
|
|
Node* x_value = TruncateTaggedToFloat64(context, x);
|
|
Node* value = (this->*float64op)(x_value);
|
|
Node* result = AllocateHeapNumberWithValue(value);
|
|
Return(result);
|
|
}
|
|
|
|
void MathBuiltinsAssembler::MathMaxMin(
|
|
Node* context, Node* argc,
|
|
Node* (CodeStubAssembler::*float64op)(Node*, Node*), double default_val) {
|
|
CodeStubArguments arguments(this, ChangeInt32ToIntPtr(argc));
|
|
argc = arguments.GetLength();
|
|
|
|
VARIABLE(result, MachineRepresentation::kFloat64);
|
|
result.Bind(Float64Constant(default_val));
|
|
|
|
CodeStubAssembler::VariableList vars({&result}, zone());
|
|
arguments.ForEach(vars, [=, &result](Node* arg) {
|
|
Node* float_value = TruncateTaggedToFloat64(context, arg);
|
|
result.Bind((this->*float64op)(result.value(), float_value));
|
|
});
|
|
|
|
arguments.PopAndReturn(ChangeFloat64ToTagged(result.value()));
|
|
}
|
|
|
|
// ES6 #sec-math.acos
|
|
TF_BUILTIN(MathAcos, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Acos);
|
|
}
|
|
|
|
// ES6 #sec-math.acosh
|
|
TF_BUILTIN(MathAcosh, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Acosh);
|
|
}
|
|
|
|
// ES6 #sec-math.asin
|
|
TF_BUILTIN(MathAsin, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Asin);
|
|
}
|
|
|
|
// ES6 #sec-math.asinh
|
|
TF_BUILTIN(MathAsinh, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Asinh);
|
|
}
|
|
|
|
// ES6 #sec-math.atan
|
|
TF_BUILTIN(MathAtan, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Atan);
|
|
}
|
|
|
|
// ES6 #sec-math.atanh
|
|
TF_BUILTIN(MathAtanh, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Atanh);
|
|
}
|
|
|
|
// ES6 #sec-math.atan2
|
|
TF_BUILTIN(MathAtan2, CodeStubAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* y = Parameter(Descriptor::kY);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
|
|
Node* y_value = TruncateTaggedToFloat64(context, y);
|
|
Node* x_value = TruncateTaggedToFloat64(context, x);
|
|
Node* value = Float64Atan2(y_value, x_value);
|
|
Node* result = AllocateHeapNumberWithValue(value);
|
|
Return(result);
|
|
}
|
|
|
|
// ES6 #sec-math.ceil
|
|
TF_BUILTIN(MathCeil, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathRoundingOperation(context, x, &CodeStubAssembler::Float64Ceil);
|
|
}
|
|
|
|
// ES6 #sec-math.cbrt
|
|
TF_BUILTIN(MathCbrt, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Cbrt);
|
|
}
|
|
|
|
// ES6 #sec-math.clz32
|
|
TF_BUILTIN(MathClz32, CodeStubAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
|
|
// Shared entry point for the clz32 operation.
|
|
VARIABLE(var_clz32_x, MachineRepresentation::kWord32);
|
|
Label do_clz32(this);
|
|
|
|
// We might need to loop once for ToNumber conversion.
|
|
VARIABLE(var_x, MachineRepresentation::kTagged);
|
|
Label loop(this, &var_x);
|
|
var_x.Bind(Parameter(Descriptor::kX));
|
|
Goto(&loop);
|
|
BIND(&loop);
|
|
{
|
|
// Load the current {x} value.
|
|
Node* x = var_x.value();
|
|
|
|
// Check if {x} is a Smi or a HeapObject.
|
|
Label if_xissmi(this), if_xisnotsmi(this);
|
|
Branch(TaggedIsSmi(x), &if_xissmi, &if_xisnotsmi);
|
|
|
|
BIND(&if_xissmi);
|
|
{
|
|
var_clz32_x.Bind(SmiToWord32(x));
|
|
Goto(&do_clz32);
|
|
}
|
|
|
|
BIND(&if_xisnotsmi);
|
|
{
|
|
// Check if {x} is a HeapNumber.
|
|
Label if_xisheapnumber(this), if_xisnotheapnumber(this, Label::kDeferred);
|
|
Branch(IsHeapNumber(x), &if_xisheapnumber, &if_xisnotheapnumber);
|
|
|
|
BIND(&if_xisheapnumber);
|
|
{
|
|
var_clz32_x.Bind(TruncateHeapNumberValueToWord32(x));
|
|
Goto(&do_clz32);
|
|
}
|
|
|
|
BIND(&if_xisnotheapnumber);
|
|
{
|
|
// Need to convert {x} to a Number first.
|
|
var_x.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, x));
|
|
Goto(&loop);
|
|
}
|
|
}
|
|
}
|
|
|
|
BIND(&do_clz32);
|
|
{
|
|
Node* x_value = var_clz32_x.value();
|
|
Node* value = Word32Clz(x_value);
|
|
Node* result = ChangeInt32ToTagged(value);
|
|
Return(result);
|
|
}
|
|
}
|
|
|
|
// ES6 #sec-math.cos
|
|
TF_BUILTIN(MathCos, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Cos);
|
|
}
|
|
|
|
// ES6 #sec-math.cosh
|
|
TF_BUILTIN(MathCosh, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Cosh);
|
|
}
|
|
|
|
// ES6 #sec-math.exp
|
|
TF_BUILTIN(MathExp, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Exp);
|
|
}
|
|
|
|
// ES6 #sec-math.expm1
|
|
TF_BUILTIN(MathExpm1, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Expm1);
|
|
}
|
|
|
|
// ES6 #sec-math.floor
|
|
TF_BUILTIN(MathFloor, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathRoundingOperation(context, x, &CodeStubAssembler::Float64Floor);
|
|
}
|
|
|
|
// ES6 #sec-math.fround
|
|
TF_BUILTIN(MathFround, CodeStubAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
Node* x_value = TruncateTaggedToFloat64(context, x);
|
|
Node* value32 = TruncateFloat64ToFloat32(x_value);
|
|
Node* value = ChangeFloat32ToFloat64(value32);
|
|
Node* result = AllocateHeapNumberWithValue(value);
|
|
Return(result);
|
|
}
|
|
|
|
// ES6 #sec-math.imul
|
|
TF_BUILTIN(MathImul, CodeStubAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
Node* y = Parameter(Descriptor::kY);
|
|
Node* x_value = TruncateTaggedToWord32(context, x);
|
|
Node* y_value = TruncateTaggedToWord32(context, y);
|
|
Node* value = Int32Mul(x_value, y_value);
|
|
Node* result = ChangeInt32ToTagged(value);
|
|
Return(result);
|
|
}
|
|
|
|
// ES6 #sec-math.log
|
|
TF_BUILTIN(MathLog, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Log);
|
|
}
|
|
|
|
// ES6 #sec-math.log1p
|
|
TF_BUILTIN(MathLog1p, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Log1p);
|
|
}
|
|
|
|
// ES6 #sec-math.log10
|
|
TF_BUILTIN(MathLog10, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Log10);
|
|
}
|
|
|
|
// ES6 #sec-math.log2
|
|
TF_BUILTIN(MathLog2, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Log2);
|
|
}
|
|
|
|
// ES6 #sec-math.pow
|
|
TF_BUILTIN(MathPow, CodeStubAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kBase);
|
|
Node* y = Parameter(Descriptor::kExponent);
|
|
Node* x_value = TruncateTaggedToFloat64(context, x);
|
|
Node* y_value = TruncateTaggedToFloat64(context, y);
|
|
Node* value = Float64Pow(x_value, y_value);
|
|
Node* result = ChangeFloat64ToTagged(value);
|
|
Return(result);
|
|
}
|
|
|
|
// ES6 #sec-math.random
|
|
TF_BUILTIN(MathRandom, CodeStubAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* native_context = LoadNativeContext(context);
|
|
|
|
// Load cache index.
|
|
VARIABLE(smi_index, MachineRepresentation::kTagged);
|
|
smi_index.Bind(
|
|
LoadContextElement(native_context, Context::MATH_RANDOM_INDEX_INDEX));
|
|
|
|
// Cached random numbers are exhausted if index is 0. Go to slow path.
|
|
Label if_cached(this);
|
|
GotoIf(SmiAbove(smi_index.value(), SmiConstant(Smi::kZero)), &if_cached);
|
|
|
|
// Cache exhausted, populate the cache. Return value is the new index.
|
|
smi_index.Bind(CallRuntime(Runtime::kGenerateRandomNumbers, context));
|
|
Goto(&if_cached);
|
|
|
|
// Compute next index by decrement.
|
|
BIND(&if_cached);
|
|
Node* new_smi_index = SmiSub(smi_index.value(), SmiConstant(Smi::FromInt(1)));
|
|
StoreContextElement(native_context, Context::MATH_RANDOM_INDEX_INDEX,
|
|
new_smi_index);
|
|
|
|
// Load and return next cached random number.
|
|
Node* array =
|
|
LoadContextElement(native_context, Context::MATH_RANDOM_CACHE_INDEX);
|
|
Node* random = LoadFixedDoubleArrayElement(
|
|
array, new_smi_index, MachineType::Float64(), 0, SMI_PARAMETERS);
|
|
Return(AllocateHeapNumberWithValue(random));
|
|
}
|
|
|
|
// ES6 #sec-math.round
|
|
TF_BUILTIN(MathRound, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathRoundingOperation(context, x, &CodeStubAssembler::Float64Round);
|
|
}
|
|
|
|
// ES6 #sec-math.sign
|
|
TF_BUILTIN(MathSign, CodeStubAssembler) {
|
|
// Convert the {x} value to a Number.
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
Node* x_value = TruncateTaggedToFloat64(context, x);
|
|
|
|
// Return -1 if {x} is negative, 1 if {x} is positive, or {x} itself.
|
|
Label if_xisnegative(this), if_xispositive(this);
|
|
GotoIf(Float64LessThan(x_value, Float64Constant(0.0)), &if_xisnegative);
|
|
GotoIf(Float64LessThan(Float64Constant(0.0), x_value), &if_xispositive);
|
|
Return(ChangeFloat64ToTagged(x_value));
|
|
|
|
BIND(&if_xisnegative);
|
|
Return(SmiConstant(Smi::FromInt(-1)));
|
|
|
|
BIND(&if_xispositive);
|
|
Return(SmiConstant(Smi::FromInt(1)));
|
|
}
|
|
|
|
// ES6 #sec-math.sin
|
|
TF_BUILTIN(MathSin, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Sin);
|
|
}
|
|
|
|
// ES6 #sec-math.sinh
|
|
TF_BUILTIN(MathSinh, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Sinh);
|
|
}
|
|
|
|
// ES6 #sec-math.sqrt
|
|
TF_BUILTIN(MathSqrt, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Sqrt);
|
|
}
|
|
|
|
// ES6 #sec-math.tan
|
|
TF_BUILTIN(MathTan, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Tan);
|
|
}
|
|
|
|
// ES6 #sec-math.tanh
|
|
TF_BUILTIN(MathTanh, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Tanh);
|
|
}
|
|
|
|
// ES6 #sec-math.trunc
|
|
TF_BUILTIN(MathTrunc, MathBuiltinsAssembler) {
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
Node* x = Parameter(Descriptor::kX);
|
|
MathRoundingOperation(context, x, &CodeStubAssembler::Float64Trunc);
|
|
}
|
|
|
|
// ES6 #sec-math.max
|
|
TF_BUILTIN(MathMax, MathBuiltinsAssembler) {
|
|
// TODO(ishell): use constants from Descriptor once the JSFunction linkage
|
|
// arguments are reordered.
|
|
Node* context = Parameter(BuiltinDescriptor::kContext);
|
|
Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
|
|
MathMaxMin(context, argc, &CodeStubAssembler::Float64Max, -1.0 * V8_INFINITY);
|
|
}
|
|
|
|
// ES6 #sec-math.min
|
|
TF_BUILTIN(MathMin, MathBuiltinsAssembler) {
|
|
// TODO(ishell): use constants from Descriptor once the JSFunction linkage
|
|
// arguments are reordered.
|
|
Node* context = Parameter(BuiltinDescriptor::kContext);
|
|
Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
|
|
MathMaxMin(context, argc, &CodeStubAssembler::Float64Min, V8_INFINITY);
|
|
}
|
|
|
|
} // namespace internal
|
|
} // namespace v8
|