No longer desugar the exponentiation (**) operator.
Prior to this change, the exponentiation operator was rewritten by the parser to a call of the Math.pow builtin. However, Math.pow does not accept BigInt arguments, while the exponentiation operator must accept them. This CL - removes the parser's special treatment of ** and **=, treating them like any other binary op instead. - adds a TFC builtin Exponentiate that does the right thing for all inputs. - adds interpreter bytecodes Exp and ExpSmi whose handlers call the Exponentiate builtin. For simplicity, they currently always collect kAny feedback. - adds a Turbofan operator JSExponentiate with a typed-lowering to the existing NumberPow and a generic-lowering to the Exponentiate builtin. There is currently no speculative lowering. Note that exponentiation for BigInts is actually not implemented yet, so we can't yet test it. Bug: v8:6791 Change-Id: Id90914c9c3fce310ce01e715c09eaa9f294f4f8a Reviewed-on: https://chromium-review.googlesource.com/785694 Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org> Reviewed-by: Yang Guo <yangguo@chromium.org> Reviewed-by: Mythri Alle <mythria@chromium.org> Reviewed-by: Jaroslav Sevcik <jarin@chromium.org> Commit-Queue: Georg Neis <neis@chromium.org> Cr-Commit-Position: refs/heads/master@{#49696}
This commit is contained in:
parent
9fb39c6b91
commit
b97567a976
1
BUILD.gn
1
BUILD.gn
@ -1022,6 +1022,7 @@ v8_source_set("v8_initializers") {
|
|||||||
"src/builtins/builtins-iterator-gen.cc",
|
"src/builtins/builtins-iterator-gen.cc",
|
||||||
"src/builtins/builtins-iterator-gen.h",
|
"src/builtins/builtins-iterator-gen.h",
|
||||||
"src/builtins/builtins-math-gen.cc",
|
"src/builtins/builtins-math-gen.cc",
|
||||||
|
"src/builtins/builtins-math-gen.h",
|
||||||
"src/builtins/builtins-number-gen.cc",
|
"src/builtins/builtins-number-gen.cc",
|
||||||
"src/builtins/builtins-object-gen.cc",
|
"src/builtins/builtins-object-gen.cc",
|
||||||
"src/builtins/builtins-promise-gen.cc",
|
"src/builtins/builtins-promise-gen.cc",
|
||||||
|
@ -688,6 +688,7 @@ namespace internal {
|
|||||||
TFC(Multiply, BinaryOp, 1) \
|
TFC(Multiply, BinaryOp, 1) \
|
||||||
TFC(Divide, BinaryOp, 1) \
|
TFC(Divide, BinaryOp, 1) \
|
||||||
TFC(Modulus, BinaryOp, 1) \
|
TFC(Modulus, BinaryOp, 1) \
|
||||||
|
TFC(Exponentiate, BinaryOp, 1) \
|
||||||
TFC(BitwiseAnd, BinaryOp, 1) \
|
TFC(BitwiseAnd, BinaryOp, 1) \
|
||||||
TFC(BitwiseOr, BinaryOp, 1) \
|
TFC(BitwiseOr, BinaryOp, 1) \
|
||||||
TFC(BitwiseXor, BinaryOp, 1) \
|
TFC(BitwiseXor, BinaryOp, 1) \
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "src/builtins/builtins-math-gen.h"
|
||||||
|
|
||||||
#include "src/builtins/builtins-utils-gen.h"
|
#include "src/builtins/builtins-utils-gen.h"
|
||||||
#include "src/builtins/builtins.h"
|
#include "src/builtins/builtins.h"
|
||||||
#include "src/code-factory.h"
|
#include "src/code-factory.h"
|
||||||
@ -14,24 +16,6 @@ namespace internal {
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// ES6 section 20.2.2 Function Properties of the Math Object
|
// 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,
|
|
||||||
TNode<Float64T> (CodeStubAssembler::*float64op)(SloppyTNode<Float64T>));
|
|
||||||
void MathUnaryOperation(
|
|
||||||
Node* context, Node* x,
|
|
||||||
TNode<Float64T> (CodeStubAssembler::*float64op)(SloppyTNode<Float64T>));
|
|
||||||
void MathMaxMin(Node* context, Node* argc,
|
|
||||||
TNode<Float64T> (CodeStubAssembler::*float64op)(
|
|
||||||
SloppyTNode<Float64T>, SloppyTNode<Float64T>),
|
|
||||||
double default_val);
|
|
||||||
};
|
|
||||||
|
|
||||||
// ES6 #sec-math.abs
|
// ES6 #sec-math.abs
|
||||||
TF_BUILTIN(MathAbs, CodeStubAssembler) {
|
TF_BUILTIN(MathAbs, CodeStubAssembler) {
|
||||||
Node* context = Parameter(Descriptor::kContext);
|
Node* context = Parameter(Descriptor::kContext);
|
||||||
@ -405,16 +389,19 @@ TF_BUILTIN(MathLog2, MathBuiltinsAssembler) {
|
|||||||
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Log2);
|
MathUnaryOperation(context, x, &CodeStubAssembler::Float64Log2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CodeStubAssembler::Node* MathBuiltinsAssembler::MathPow(Node* context,
|
||||||
|
Node* base,
|
||||||
|
Node* exponent) {
|
||||||
|
Node* base_value = TruncateTaggedToFloat64(context, base);
|
||||||
|
Node* exponent_value = TruncateTaggedToFloat64(context, exponent);
|
||||||
|
Node* value = Float64Pow(base_value, exponent_value);
|
||||||
|
return ChangeFloat64ToTagged(value);
|
||||||
|
}
|
||||||
|
|
||||||
// ES6 #sec-math.pow
|
// ES6 #sec-math.pow
|
||||||
TF_BUILTIN(MathPow, CodeStubAssembler) {
|
TF_BUILTIN(MathPow, MathBuiltinsAssembler) {
|
||||||
Node* context = Parameter(Descriptor::kContext);
|
Return(MathPow(Parameter(Descriptor::kContext), Parameter(Descriptor::kBase),
|
||||||
Node* x = Parameter(Descriptor::kBase);
|
Parameter(Descriptor::kExponent)));
|
||||||
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
|
// ES6 #sec-math.random
|
||||||
|
36
src/builtins/builtins-math-gen.h
Normal file
36
src/builtins/builtins-math-gen.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#ifndef V8_BUILTINS_BUILTINS_MATH_GEN_H_
|
||||||
|
#define V8_BUILTINS_BUILTINS_MATH_GEN_H_
|
||||||
|
|
||||||
|
#include "src/code-stub-assembler.h"
|
||||||
|
|
||||||
|
namespace v8 {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class MathBuiltinsAssembler : public CodeStubAssembler {
|
||||||
|
public:
|
||||||
|
explicit MathBuiltinsAssembler(compiler::CodeAssemblerState* state)
|
||||||
|
: CodeStubAssembler(state) {}
|
||||||
|
|
||||||
|
Node* MathPow(Node* context, Node* base, Node* exponent);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void MathRoundingOperation(
|
||||||
|
Node* context, Node* x,
|
||||||
|
TNode<Float64T> (CodeStubAssembler::*float64op)(SloppyTNode<Float64T>));
|
||||||
|
void MathUnaryOperation(
|
||||||
|
Node* context, Node* x,
|
||||||
|
TNode<Float64T> (CodeStubAssembler::*float64op)(SloppyTNode<Float64T>));
|
||||||
|
void MathMaxMin(Node* context, Node* argc,
|
||||||
|
TNode<Float64T> (CodeStubAssembler::*float64op)(
|
||||||
|
SloppyTNode<Float64T>, SloppyTNode<Float64T>),
|
||||||
|
double default_val);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace v8
|
||||||
|
|
||||||
|
#endif // V8_BUILTINS_BUILTINS_MATH_GEN_H_
|
@ -2,6 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "src/builtins/builtins-math-gen.h"
|
||||||
#include "src/builtins/builtins-utils-gen.h"
|
#include "src/builtins/builtins-utils-gen.h"
|
||||||
#include "src/builtins/builtins.h"
|
#include "src/builtins/builtins.h"
|
||||||
#include "src/code-stub-assembler.h"
|
#include "src/code-stub-assembler.h"
|
||||||
@ -636,8 +637,11 @@ void NumberBuiltinsAssembler::BinaryOp(Label* smis, Variable* var_left,
|
|||||||
Label* bigints) {
|
Label* bigints) {
|
||||||
DCHECK_EQ(var_left->rep(), MachineRepresentation::kTagged);
|
DCHECK_EQ(var_left->rep(), MachineRepresentation::kTagged);
|
||||||
DCHECK_EQ(var_right->rep(), MachineRepresentation::kTagged);
|
DCHECK_EQ(var_right->rep(), MachineRepresentation::kTagged);
|
||||||
DCHECK_EQ(var_left_double->rep(), MachineRepresentation::kFloat64);
|
DCHECK_IMPLIES(var_left_double != nullptr,
|
||||||
DCHECK_EQ(var_right_double->rep(), MachineRepresentation::kFloat64);
|
var_left_double->rep() == MachineRepresentation::kFloat64);
|
||||||
|
DCHECK_IMPLIES(var_right_double != nullptr,
|
||||||
|
var_right_double->rep() == MachineRepresentation::kFloat64);
|
||||||
|
DCHECK_EQ(var_left_double == nullptr, var_right_double == nullptr);
|
||||||
|
|
||||||
Node* context = Parameter(Descriptor::kContext);
|
Node* context = Parameter(Descriptor::kContext);
|
||||||
var_left->Bind(Parameter(Descriptor::kLeft));
|
var_left->Bind(Parameter(Descriptor::kLeft));
|
||||||
@ -655,8 +659,10 @@ void NumberBuiltinsAssembler::BinaryOp(Label* smis, Variable* var_left,
|
|||||||
|
|
||||||
// At this point, var_left is a Smi but var_right is not.
|
// At this point, var_left is a Smi but var_right is not.
|
||||||
GotoIfNot(IsHeapNumber(var_right->value()), &right_not_number);
|
GotoIfNot(IsHeapNumber(var_right->value()), &right_not_number);
|
||||||
var_left_double->Bind(SmiToFloat64(var_left->value()));
|
if (var_left_double != nullptr) {
|
||||||
var_right_double->Bind(LoadHeapNumberValue(var_right->value()));
|
var_left_double->Bind(SmiToFloat64(var_left->value()));
|
||||||
|
var_right_double->Bind(LoadHeapNumberValue(var_right->value()));
|
||||||
|
}
|
||||||
Goto(doubles);
|
Goto(doubles);
|
||||||
|
|
||||||
BIND(&left_not_smi);
|
BIND(&left_not_smi);
|
||||||
@ -665,16 +671,20 @@ void NumberBuiltinsAssembler::BinaryOp(Label* smis, Variable* var_left,
|
|||||||
GotoIfNot(TaggedIsSmi(var_right->value()), &right_not_smi);
|
GotoIfNot(TaggedIsSmi(var_right->value()), &right_not_smi);
|
||||||
|
|
||||||
// At this point, var_left is a HeapNumber and var_right is a Smi.
|
// At this point, var_left is a HeapNumber and var_right is a Smi.
|
||||||
var_left_double->Bind(LoadHeapNumberValue(var_left->value()));
|
if (var_left_double != nullptr) {
|
||||||
var_right_double->Bind(SmiToFloat64(var_right->value()));
|
var_left_double->Bind(LoadHeapNumberValue(var_left->value()));
|
||||||
|
var_right_double->Bind(SmiToFloat64(var_right->value()));
|
||||||
|
}
|
||||||
Goto(doubles);
|
Goto(doubles);
|
||||||
}
|
}
|
||||||
|
|
||||||
BIND(&right_not_smi);
|
BIND(&right_not_smi);
|
||||||
{
|
{
|
||||||
GotoIfNot(IsHeapNumber(var_right->value()), &right_not_number);
|
GotoIfNot(IsHeapNumber(var_right->value()), &right_not_number);
|
||||||
var_left_double->Bind(LoadHeapNumberValue(var_left->value()));
|
if (var_left_double != nullptr) {
|
||||||
var_right_double->Bind(LoadHeapNumberValue(var_right->value()));
|
var_left_double->Bind(LoadHeapNumberValue(var_left->value()));
|
||||||
|
var_right_double->Bind(LoadHeapNumberValue(var_right->value()));
|
||||||
|
}
|
||||||
Goto(doubles);
|
Goto(doubles);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -970,6 +980,26 @@ TF_BUILTIN(Modulus, NumberBuiltinsAssembler) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TF_BUILTIN(Exponentiate, NumberBuiltinsAssembler) {
|
||||||
|
VARIABLE(var_left, MachineRepresentation::kTagged);
|
||||||
|
VARIABLE(var_right, MachineRepresentation::kTagged);
|
||||||
|
Label do_number_exp(this), do_bigint_exp(this);
|
||||||
|
Node* context = Parameter(Descriptor::kContext);
|
||||||
|
|
||||||
|
BinaryOp<Descriptor>(&do_number_exp, &var_left, &var_right, &do_number_exp,
|
||||||
|
nullptr, nullptr, &do_bigint_exp);
|
||||||
|
|
||||||
|
BIND(&do_number_exp);
|
||||||
|
{
|
||||||
|
MathBuiltinsAssembler math_asm(state());
|
||||||
|
Return(math_asm.MathPow(context, var_left.value(), var_right.value()));
|
||||||
|
}
|
||||||
|
|
||||||
|
BIND(&do_bigint_exp);
|
||||||
|
Return(CallRuntime(Runtime::kBigIntBinaryOp, context, var_left.value(),
|
||||||
|
var_right.value(), SmiConstant(Operation::kExponentiate)));
|
||||||
|
}
|
||||||
|
|
||||||
TF_BUILTIN(ShiftLeft, NumberBuiltinsAssembler) {
|
TF_BUILTIN(ShiftLeft, NumberBuiltinsAssembler) {
|
||||||
EmitBitwiseOp<Descriptor>(Operation::kShiftLeft);
|
EmitBitwiseOp<Descriptor>(Operation::kShiftLeft);
|
||||||
}
|
}
|
||||||
|
@ -2139,6 +2139,10 @@ void BytecodeGraphBuilder::VisitMod() {
|
|||||||
BuildBinaryOp(javascript()->Modulus());
|
BuildBinaryOp(javascript()->Modulus());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BytecodeGraphBuilder::VisitExp() {
|
||||||
|
BuildBinaryOp(javascript()->Exponentiate());
|
||||||
|
}
|
||||||
|
|
||||||
void BytecodeGraphBuilder::VisitBitwiseOr() {
|
void BytecodeGraphBuilder::VisitBitwiseOr() {
|
||||||
BuildBinaryOp(javascript()->BitwiseOr());
|
BuildBinaryOp(javascript()->BitwiseOr());
|
||||||
}
|
}
|
||||||
@ -2205,6 +2209,10 @@ void BytecodeGraphBuilder::VisitModSmi() {
|
|||||||
BuildBinaryOpWithImmediate(javascript()->Modulus());
|
BuildBinaryOpWithImmediate(javascript()->Modulus());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BytecodeGraphBuilder::VisitExpSmi() {
|
||||||
|
BuildBinaryOpWithImmediate(javascript()->Exponentiate());
|
||||||
|
}
|
||||||
|
|
||||||
void BytecodeGraphBuilder::VisitBitwiseOrSmi() {
|
void BytecodeGraphBuilder::VisitBitwiseOrSmi() {
|
||||||
BuildBinaryOpWithImmediate(javascript()->BitwiseOr());
|
BuildBinaryOpWithImmediate(javascript()->BitwiseOr());
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,7 @@ REPLACE_STUB_CALL(Subtract)
|
|||||||
REPLACE_STUB_CALL(Multiply)
|
REPLACE_STUB_CALL(Multiply)
|
||||||
REPLACE_STUB_CALL(Divide)
|
REPLACE_STUB_CALL(Divide)
|
||||||
REPLACE_STUB_CALL(Modulus)
|
REPLACE_STUB_CALL(Modulus)
|
||||||
|
REPLACE_STUB_CALL(Exponentiate)
|
||||||
REPLACE_STUB_CALL(BitwiseAnd)
|
REPLACE_STUB_CALL(BitwiseAnd)
|
||||||
REPLACE_STUB_CALL(BitwiseOr)
|
REPLACE_STUB_CALL(BitwiseOr)
|
||||||
REPLACE_STUB_CALL(BitwiseXor)
|
REPLACE_STUB_CALL(BitwiseXor)
|
||||||
|
@ -577,6 +577,7 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
|
|||||||
V(Multiply, Operator::kNoProperties, 2, 1) \
|
V(Multiply, Operator::kNoProperties, 2, 1) \
|
||||||
V(Divide, Operator::kNoProperties, 2, 1) \
|
V(Divide, Operator::kNoProperties, 2, 1) \
|
||||||
V(Modulus, Operator::kNoProperties, 2, 1) \
|
V(Modulus, Operator::kNoProperties, 2, 1) \
|
||||||
|
V(Exponentiate, Operator::kNoProperties, 2, 1) \
|
||||||
V(BitwiseNot, Operator::kNoProperties, 1, 1) \
|
V(BitwiseNot, Operator::kNoProperties, 1, 1) \
|
||||||
V(Decrement, Operator::kNoProperties, 1, 1) \
|
V(Decrement, Operator::kNoProperties, 1, 1) \
|
||||||
V(Increment, Operator::kNoProperties, 1, 1) \
|
V(Increment, Operator::kNoProperties, 1, 1) \
|
||||||
|
@ -651,6 +651,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
|
|||||||
const Operator* Multiply();
|
const Operator* Multiply();
|
||||||
const Operator* Divide();
|
const Operator* Divide();
|
||||||
const Operator* Modulus();
|
const Operator* Modulus();
|
||||||
|
const Operator* Exponentiate();
|
||||||
|
|
||||||
const Operator* BitwiseNot();
|
const Operator* BitwiseNot();
|
||||||
const Operator* Decrement();
|
const Operator* Decrement();
|
||||||
|
@ -344,6 +344,10 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case IrOpcode::kJSExponentiate: {
|
||||||
|
// TODO(neis): Introduce a SpeculativeNumberPow operator?
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
|
@ -279,6 +279,8 @@ class JSBinopReduction final {
|
|||||||
return simplified()->NumberDivide();
|
return simplified()->NumberDivide();
|
||||||
case IrOpcode::kJSModulus:
|
case IrOpcode::kJSModulus:
|
||||||
return simplified()->NumberModulus();
|
return simplified()->NumberModulus();
|
||||||
|
case IrOpcode::kJSExponentiate:
|
||||||
|
return simplified()->NumberPow();
|
||||||
case IrOpcode::kJSBitwiseAnd:
|
case IrOpcode::kJSBitwiseAnd:
|
||||||
return simplified()->NumberBitwiseAnd();
|
return simplified()->NumberBitwiseAnd();
|
||||||
case IrOpcode::kJSBitwiseOr:
|
case IrOpcode::kJSBitwiseOr:
|
||||||
@ -2123,6 +2125,7 @@ Reduction JSTypedLowering::Reduce(Node* node) {
|
|||||||
case IrOpcode::kJSMultiply:
|
case IrOpcode::kJSMultiply:
|
||||||
case IrOpcode::kJSDivide:
|
case IrOpcode::kJSDivide:
|
||||||
case IrOpcode::kJSModulus:
|
case IrOpcode::kJSModulus:
|
||||||
|
case IrOpcode::kJSExponentiate:
|
||||||
return ReduceNumberBinop(node);
|
return ReduceNumberBinop(node);
|
||||||
case IrOpcode::kJSBitwiseNot:
|
case IrOpcode::kJSBitwiseNot:
|
||||||
return ReduceJSBitwiseNot(node);
|
return ReduceJSBitwiseNot(node);
|
||||||
|
@ -105,7 +105,8 @@
|
|||||||
V(JSSubtract) \
|
V(JSSubtract) \
|
||||||
V(JSMultiply) \
|
V(JSMultiply) \
|
||||||
V(JSDivide) \
|
V(JSDivide) \
|
||||||
V(JSModulus)
|
V(JSModulus) \
|
||||||
|
V(JSExponentiate)
|
||||||
|
|
||||||
#define JS_SIMPLE_BINOP_LIST(V) \
|
#define JS_SIMPLE_BINOP_LIST(V) \
|
||||||
JS_COMPARE_BINOP_LIST(V) \
|
JS_COMPARE_BINOP_LIST(V) \
|
||||||
|
@ -44,6 +44,7 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
|
|||||||
case IrOpcode::kJSMultiply:
|
case IrOpcode::kJSMultiply:
|
||||||
case IrOpcode::kJSDivide:
|
case IrOpcode::kJSDivide:
|
||||||
case IrOpcode::kJSModulus:
|
case IrOpcode::kJSModulus:
|
||||||
|
case IrOpcode::kJSExponentiate:
|
||||||
|
|
||||||
// Bitwise operations
|
// Bitwise operations
|
||||||
case IrOpcode::kJSBitwiseOr:
|
case IrOpcode::kJSBitwiseOr:
|
||||||
|
@ -1103,6 +1103,12 @@ Type* Typer::Visitor::JSModulusTyper(Type* lhs, Type* rhs, Typer* t) {
|
|||||||
return NumberModulus(ToNumber(lhs, t), ToNumber(rhs, t), t);
|
return NumberModulus(ToNumber(lhs, t), ToNumber(rhs, t), t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(neis): Adapt all these for bigints. Why does this even work in the
|
||||||
|
// bigint tests?
|
||||||
|
|
||||||
|
Type* Typer::Visitor::JSExponentiateTyper(Type* lhs, Type* rhs, Typer* t) {
|
||||||
|
return Type::Number();
|
||||||
|
}
|
||||||
|
|
||||||
// JS unary operators.
|
// JS unary operators.
|
||||||
|
|
||||||
|
@ -608,7 +608,9 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
|
|||||||
case IrOpcode::kJSMultiply:
|
case IrOpcode::kJSMultiply:
|
||||||
case IrOpcode::kJSDivide:
|
case IrOpcode::kJSDivide:
|
||||||
case IrOpcode::kJSModulus:
|
case IrOpcode::kJSModulus:
|
||||||
|
case IrOpcode::kJSExponentiate:
|
||||||
// Type is Number.
|
// Type is Number.
|
||||||
|
// TODO(neis): Adapt for bigints.
|
||||||
CheckTypeIs(node, Type::Number());
|
CheckTypeIs(node, Type::Number());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -382,6 +382,8 @@ bool BytecodeHasNoSideEffect(interpreter::Bytecode bytecode) {
|
|||||||
case Bytecode::kDivSmi:
|
case Bytecode::kDivSmi:
|
||||||
case Bytecode::kMod:
|
case Bytecode::kMod:
|
||||||
case Bytecode::kModSmi:
|
case Bytecode::kModSmi:
|
||||||
|
case Bytecode::kExp:
|
||||||
|
case Bytecode::kExpSmi:
|
||||||
case Bytecode::kNegate:
|
case Bytecode::kNegate:
|
||||||
case Bytecode::kBitwiseAnd:
|
case Bytecode::kBitwiseAnd:
|
||||||
case Bytecode::kBitwiseAndSmi:
|
case Bytecode::kBitwiseAndSmi:
|
||||||
|
@ -1305,6 +1305,7 @@ enum class Operation {
|
|||||||
kMultiply,
|
kMultiply,
|
||||||
kDivide,
|
kDivide,
|
||||||
kModulus,
|
kModulus,
|
||||||
|
kExponentiate,
|
||||||
kBitwiseAnd,
|
kBitwiseAnd,
|
||||||
kBitwiseOr,
|
kBitwiseOr,
|
||||||
kBitwiseXor,
|
kBitwiseXor,
|
||||||
|
@ -529,5 +529,14 @@ Node* BinaryOpAssembler::Generate_ModulusWithFeedback(
|
|||||||
floatFunction, Operation::kModulus, rhs_is_smi);
|
floatFunction, Operation::kModulus, rhs_is_smi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Node* BinaryOpAssembler::Generate_ExponentiateWithFeedback(
|
||||||
|
Node* context, Node* base, Node* exponent, Node* slot_id,
|
||||||
|
Node* feedback_vector, bool rhs_is_smi) {
|
||||||
|
// We currently don't optimize exponentiation based on feedback.
|
||||||
|
Node* dummy_feedback = SmiConstant(BinaryOperationFeedback::kAny);
|
||||||
|
UpdateFeedback(dummy_feedback, feedback_vector, slot_id);
|
||||||
|
return CallBuiltin(Builtins::kExponentiate, context, base, exponent);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -42,6 +42,11 @@ class BinaryOpAssembler : public CodeStubAssembler {
|
|||||||
Node* divisor, Node* slot_id,
|
Node* divisor, Node* slot_id,
|
||||||
Node* feedback_vector, bool rhs_is_smi);
|
Node* feedback_vector, bool rhs_is_smi);
|
||||||
|
|
||||||
|
Node* Generate_ExponentiateWithFeedback(Node* context, Node* dividend,
|
||||||
|
Node* divisor, Node* slot_id,
|
||||||
|
Node* feedback_vector,
|
||||||
|
bool rhs_is_smi);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::function<Node*(Node*, Node*, Variable*)> SmiOperation;
|
typedef std::function<Node*(Node*, Node*, Variable*)> SmiOperation;
|
||||||
typedef std::function<Node*(Node*, Node*)> FloatOperation;
|
typedef std::function<Node*(Node*, Node*)> FloatOperation;
|
||||||
|
@ -362,6 +362,9 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op,
|
|||||||
case Token::Value::MOD:
|
case Token::Value::MOD:
|
||||||
OutputMod(reg, feedback_slot);
|
OutputMod(reg, feedback_slot);
|
||||||
break;
|
break;
|
||||||
|
case Token::Value::EXP:
|
||||||
|
OutputExp(reg, feedback_slot);
|
||||||
|
break;
|
||||||
case Token::Value::BIT_OR:
|
case Token::Value::BIT_OR:
|
||||||
OutputBitwiseOr(reg, feedback_slot);
|
OutputBitwiseOr(reg, feedback_slot);
|
||||||
break;
|
break;
|
||||||
@ -404,6 +407,9 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperationSmiLiteral(
|
|||||||
case Token::Value::MOD:
|
case Token::Value::MOD:
|
||||||
OutputModSmi(literal->value(), feedback_slot);
|
OutputModSmi(literal->value(), feedback_slot);
|
||||||
break;
|
break;
|
||||||
|
case Token::Value::EXP:
|
||||||
|
OutputExpSmi(literal->value(), feedback_slot);
|
||||||
|
break;
|
||||||
case Token::Value::BIT_OR:
|
case Token::Value::BIT_OR:
|
||||||
OutputBitwiseOrSmi(literal->value(), feedback_slot);
|
OutputBitwiseOrSmi(literal->value(), feedback_slot);
|
||||||
break;
|
break;
|
||||||
|
@ -110,6 +110,7 @@ namespace interpreter {
|
|||||||
V(Mul, AccumulatorUse::kReadWrite, OperandType::kReg, OperandType::kIdx) \
|
V(Mul, AccumulatorUse::kReadWrite, OperandType::kReg, OperandType::kIdx) \
|
||||||
V(Div, AccumulatorUse::kReadWrite, OperandType::kReg, OperandType::kIdx) \
|
V(Div, AccumulatorUse::kReadWrite, OperandType::kReg, OperandType::kIdx) \
|
||||||
V(Mod, AccumulatorUse::kReadWrite, OperandType::kReg, OperandType::kIdx) \
|
V(Mod, AccumulatorUse::kReadWrite, OperandType::kReg, OperandType::kIdx) \
|
||||||
|
V(Exp, AccumulatorUse::kReadWrite, OperandType::kReg, OperandType::kIdx) \
|
||||||
V(BitwiseOr, AccumulatorUse::kReadWrite, OperandType::kReg, \
|
V(BitwiseOr, AccumulatorUse::kReadWrite, OperandType::kReg, \
|
||||||
OperandType::kIdx) \
|
OperandType::kIdx) \
|
||||||
V(BitwiseXor, AccumulatorUse::kReadWrite, OperandType::kReg, \
|
V(BitwiseXor, AccumulatorUse::kReadWrite, OperandType::kReg, \
|
||||||
@ -129,6 +130,7 @@ namespace interpreter {
|
|||||||
V(MulSmi, AccumulatorUse::kReadWrite, OperandType::kImm, OperandType::kIdx) \
|
V(MulSmi, AccumulatorUse::kReadWrite, OperandType::kImm, OperandType::kIdx) \
|
||||||
V(DivSmi, AccumulatorUse::kReadWrite, OperandType::kImm, OperandType::kIdx) \
|
V(DivSmi, AccumulatorUse::kReadWrite, OperandType::kImm, OperandType::kIdx) \
|
||||||
V(ModSmi, AccumulatorUse::kReadWrite, OperandType::kImm, OperandType::kIdx) \
|
V(ModSmi, AccumulatorUse::kReadWrite, OperandType::kImm, OperandType::kIdx) \
|
||||||
|
V(ExpSmi, AccumulatorUse::kReadWrite, OperandType::kImm, OperandType::kIdx) \
|
||||||
V(BitwiseOrSmi, AccumulatorUse::kReadWrite, OperandType::kImm, \
|
V(BitwiseOrSmi, AccumulatorUse::kReadWrite, OperandType::kImm, \
|
||||||
OperandType::kIdx) \
|
OperandType::kIdx) \
|
||||||
V(BitwiseXorSmi, AccumulatorUse::kReadWrite, OperandType::kImm, \
|
V(BitwiseXorSmi, AccumulatorUse::kReadWrite, OperandType::kImm, \
|
||||||
|
@ -910,6 +910,13 @@ IGNITION_HANDLER(Mod, InterpreterBinaryOpAssembler) {
|
|||||||
BinaryOpWithFeedback(&BinaryOpAssembler::Generate_ModulusWithFeedback);
|
BinaryOpWithFeedback(&BinaryOpAssembler::Generate_ModulusWithFeedback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exp <src>
|
||||||
|
//
|
||||||
|
// Exponentiate register <src> (base) with accumulator (exponent).
|
||||||
|
IGNITION_HANDLER(Exp, InterpreterBinaryOpAssembler) {
|
||||||
|
BinaryOpWithFeedback(&BinaryOpAssembler::Generate_ExponentiateWithFeedback);
|
||||||
|
}
|
||||||
|
|
||||||
// AddSmi <imm>
|
// AddSmi <imm>
|
||||||
//
|
//
|
||||||
// Adds an immediate value <imm> to the value in the accumulator.
|
// Adds an immediate value <imm> to the value in the accumulator.
|
||||||
@ -945,6 +952,14 @@ IGNITION_HANDLER(ModSmi, InterpreterBinaryOpAssembler) {
|
|||||||
BinaryOpSmiWithFeedback(&BinaryOpAssembler::Generate_ModulusWithFeedback);
|
BinaryOpSmiWithFeedback(&BinaryOpAssembler::Generate_ModulusWithFeedback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExpSmi <imm>
|
||||||
|
//
|
||||||
|
// Exponentiate accumulator (base) with immediate value <imm> (exponent).
|
||||||
|
IGNITION_HANDLER(ExpSmi, InterpreterBinaryOpAssembler) {
|
||||||
|
BinaryOpSmiWithFeedback(
|
||||||
|
&BinaryOpAssembler::Generate_ExponentiateWithFeedback);
|
||||||
|
}
|
||||||
|
|
||||||
class InterpreterBitwiseBinaryOpAssembler : public InterpreterAssembler {
|
class InterpreterBitwiseBinaryOpAssembler : public InterpreterAssembler {
|
||||||
public:
|
public:
|
||||||
InterpreterBitwiseBinaryOpAssembler(CodeAssemblerState* state,
|
InterpreterBitwiseBinaryOpAssembler(CodeAssemblerState* state,
|
||||||
|
@ -2973,15 +2973,11 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
|
|||||||
impl()->SetFunctionNameFromIdentifierRef(right, expression);
|
impl()->SetFunctionNameFromIdentifierRef(right, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op == Token::ASSIGN_EXP) {
|
|
||||||
DCHECK(!is_destructuring_assignment);
|
|
||||||
return impl()->RewriteAssignExponentiation(expression, right, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
DCHECK_NE(op, Token::INIT);
|
DCHECK_NE(op, Token::INIT);
|
||||||
ExpressionT result = factory()->NewAssignment(op, expression, right, pos);
|
ExpressionT result = factory()->NewAssignment(op, expression, right, pos);
|
||||||
|
|
||||||
if (is_destructuring_assignment) {
|
if (is_destructuring_assignment) {
|
||||||
|
DCHECK_NE(op, Token::ASSIGN_EXP);
|
||||||
auto rewritable = factory()->NewRewritableExpression(result, scope());
|
auto rewritable = factory()->NewRewritableExpression(result, scope());
|
||||||
impl()->QueueDestructuringAssignmentForRewriting(rewritable);
|
impl()->QueueDestructuringAssignmentForRewriting(rewritable);
|
||||||
result = rewritable;
|
result = rewritable;
|
||||||
@ -3131,8 +3127,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression(
|
|||||||
// The comparison was negated - add a NOT.
|
// The comparison was negated - add a NOT.
|
||||||
x = factory()->NewUnaryOperation(Token::NOT, x, pos);
|
x = factory()->NewUnaryOperation(Token::NOT, x, pos);
|
||||||
}
|
}
|
||||||
} else if (op == Token::EXP) {
|
|
||||||
x = impl()->RewriteExponentiation(x, y, pos);
|
|
||||||
} else if (impl()->CollapseNaryExpression(&x, y, op, pos, right_range)) {
|
} else if (impl()->CollapseNaryExpression(&x, y, op, pos, right_range)) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
|
@ -3845,58 +3845,6 @@ void Parser::RewriteDestructuringAssignments() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression* Parser::RewriteExponentiation(Expression* left, Expression* right,
|
|
||||||
int pos) {
|
|
||||||
ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone());
|
|
||||||
args->Add(left, zone());
|
|
||||||
args->Add(right, zone());
|
|
||||||
return factory()->NewCallRuntime(Context::MATH_POW_INDEX, args, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
Expression* Parser::RewriteAssignExponentiation(Expression* left,
|
|
||||||
Expression* right, int pos) {
|
|
||||||
ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone());
|
|
||||||
if (left->IsVariableProxy()) {
|
|
||||||
VariableProxy* lhs = left->AsVariableProxy();
|
|
||||||
|
|
||||||
Expression* result;
|
|
||||||
DCHECK_NOT_NULL(lhs->raw_name());
|
|
||||||
result = ExpressionFromIdentifier(lhs->raw_name(), lhs->position());
|
|
||||||
args->Add(left, zone());
|
|
||||||
args->Add(right, zone());
|
|
||||||
Expression* call =
|
|
||||||
factory()->NewCallRuntime(Context::MATH_POW_INDEX, args, pos);
|
|
||||||
return factory()->NewAssignment(Token::ASSIGN, result, call, pos);
|
|
||||||
} else if (left->IsProperty()) {
|
|
||||||
Property* prop = left->AsProperty();
|
|
||||||
auto temp_obj = NewTemporary(ast_value_factory()->empty_string());
|
|
||||||
auto temp_key = NewTemporary(ast_value_factory()->empty_string());
|
|
||||||
Expression* assign_obj = factory()->NewAssignment(
|
|
||||||
Token::ASSIGN, factory()->NewVariableProxy(temp_obj), prop->obj(),
|
|
||||||
kNoSourcePosition);
|
|
||||||
Expression* assign_key = factory()->NewAssignment(
|
|
||||||
Token::ASSIGN, factory()->NewVariableProxy(temp_key), prop->key(),
|
|
||||||
kNoSourcePosition);
|
|
||||||
args->Add(factory()->NewProperty(factory()->NewVariableProxy(temp_obj),
|
|
||||||
factory()->NewVariableProxy(temp_key),
|
|
||||||
left->position()),
|
|
||||||
zone());
|
|
||||||
args->Add(right, zone());
|
|
||||||
Expression* call =
|
|
||||||
factory()->NewCallRuntime(Context::MATH_POW_INDEX, args, pos);
|
|
||||||
Expression* target = factory()->NewProperty(
|
|
||||||
factory()->NewVariableProxy(temp_obj),
|
|
||||||
factory()->NewVariableProxy(temp_key), kNoSourcePosition);
|
|
||||||
Expression* assign =
|
|
||||||
factory()->NewAssignment(Token::ASSIGN, target, call, pos);
|
|
||||||
return factory()->NewBinaryOperation(
|
|
||||||
Token::COMMA, assign_obj,
|
|
||||||
factory()->NewBinaryOperation(Token::COMMA, assign_key, assign, pos),
|
|
||||||
pos);
|
|
||||||
}
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
Expression* Parser::RewriteSpreads(ArrayLiteral* lit) {
|
Expression* Parser::RewriteSpreads(ArrayLiteral* lit) {
|
||||||
// Array literals containing spreads are rewritten using do expressions, e.g.
|
// Array literals containing spreads are rewritten using do expressions, e.g.
|
||||||
// [1, 2, 3, ...x, 4, ...y, 5]
|
// [1, 2, 3, ...x, 4, ...y, 5]
|
||||||
|
@ -551,11 +551,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
|
|||||||
// Rewrite all DestructuringAssignments in the current FunctionState.
|
// Rewrite all DestructuringAssignments in the current FunctionState.
|
||||||
V8_INLINE void RewriteDestructuringAssignments();
|
V8_INLINE void RewriteDestructuringAssignments();
|
||||||
|
|
||||||
V8_INLINE Expression* RewriteExponentiation(Expression* left,
|
|
||||||
Expression* right, int pos);
|
|
||||||
V8_INLINE Expression* RewriteAssignExponentiation(Expression* left,
|
|
||||||
Expression* right, int pos);
|
|
||||||
|
|
||||||
Expression* RewriteSpreads(ArrayLiteral* lit);
|
Expression* RewriteSpreads(ArrayLiteral* lit);
|
||||||
|
|
||||||
// Rewrite expressions that are not used as patterns
|
// Rewrite expressions that are not used as patterns
|
||||||
|
@ -995,17 +995,6 @@ class PreParser : public ParserBase<PreParser> {
|
|||||||
|
|
||||||
V8_INLINE void RewriteDestructuringAssignments() {}
|
V8_INLINE void RewriteDestructuringAssignments() {}
|
||||||
|
|
||||||
V8_INLINE PreParserExpression
|
|
||||||
RewriteExponentiation(const PreParserExpression& left,
|
|
||||||
const PreParserExpression& right, int pos) {
|
|
||||||
return left;
|
|
||||||
}
|
|
||||||
V8_INLINE PreParserExpression
|
|
||||||
RewriteAssignExponentiation(const PreParserExpression& left,
|
|
||||||
const PreParserExpression& right, int pos) {
|
|
||||||
return left;
|
|
||||||
}
|
|
||||||
|
|
||||||
V8_INLINE void PrepareGeneratorVariables() {}
|
V8_INLINE void PrepareGeneratorVariables() {}
|
||||||
V8_INLINE void RewriteAsyncFunctionBody(
|
V8_INLINE void RewriteAsyncFunctionBody(
|
||||||
PreParserStatementList body, PreParserStatement block,
|
PreParserStatementList body, PreParserStatement block,
|
||||||
|
@ -284,6 +284,8 @@ class Token {
|
|||||||
return Token::DIV;
|
return Token::DIV;
|
||||||
case Token::ASSIGN_MOD:
|
case Token::ASSIGN_MOD:
|
||||||
return Token::MOD;
|
return Token::MOD;
|
||||||
|
case Token::ASSIGN_EXP:
|
||||||
|
return Token::EXP;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -107,6 +107,9 @@ RUNTIME_FUNCTION(Runtime_BigIntBinaryOp) {
|
|||||||
case Operation::kModulus:
|
case Operation::kModulus:
|
||||||
result = BigInt::Remainder(left, right);
|
result = BigInt::Remainder(left, right);
|
||||||
break;
|
break;
|
||||||
|
case Operation::kExponentiate:
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
break;
|
||||||
case Operation::kBitwiseAnd:
|
case Operation::kBitwiseAnd:
|
||||||
result = BigInt::BitwiseAnd(left, right);
|
result = BigInt::BitwiseAnd(left, right);
|
||||||
break;
|
break;
|
||||||
|
@ -200,6 +200,7 @@
|
|||||||
'builtins/builtins-iterator-gen.h',
|
'builtins/builtins-iterator-gen.h',
|
||||||
'builtins/builtins-iterator-gen.cc',
|
'builtins/builtins-iterator-gen.cc',
|
||||||
'builtins/builtins-math-gen.cc',
|
'builtins/builtins-math-gen.cc',
|
||||||
|
'builtins/builtins-math-gen.h',
|
||||||
'builtins/builtins-number-gen.cc',
|
'builtins/builtins-number-gen.cc',
|
||||||
'builtins/builtins-object-gen.cc',
|
'builtins/builtins-object-gen.cc',
|
||||||
'builtins/builtins-promise-gen.cc',
|
'builtins/builtins-promise-gen.cc',
|
||||||
|
@ -199,7 +199,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
|||||||
.BinaryOperation(Token::Value::SUB, reg, 2)
|
.BinaryOperation(Token::Value::SUB, reg, 2)
|
||||||
.BinaryOperation(Token::Value::MUL, reg, 3)
|
.BinaryOperation(Token::Value::MUL, reg, 3)
|
||||||
.BinaryOperation(Token::Value::DIV, reg, 4)
|
.BinaryOperation(Token::Value::DIV, reg, 4)
|
||||||
.BinaryOperation(Token::Value::MOD, reg, 5);
|
.BinaryOperation(Token::Value::MOD, reg, 5)
|
||||||
|
.BinaryOperation(Token::Value::EXP, reg, 6);
|
||||||
|
|
||||||
// Emit bitwise operator invocations
|
// Emit bitwise operator invocations
|
||||||
builder.BinaryOperation(Token::Value::BIT_OR, reg, 6)
|
builder.BinaryOperation(Token::Value::BIT_OR, reg, 6)
|
||||||
@ -217,6 +218,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
|||||||
.BinaryOperationSmiLiteral(Token::Value::MUL, Smi::FromInt(42), 2)
|
.BinaryOperationSmiLiteral(Token::Value::MUL, Smi::FromInt(42), 2)
|
||||||
.BinaryOperationSmiLiteral(Token::Value::DIV, Smi::FromInt(42), 2)
|
.BinaryOperationSmiLiteral(Token::Value::DIV, Smi::FromInt(42), 2)
|
||||||
.BinaryOperationSmiLiteral(Token::Value::MOD, Smi::FromInt(42), 2)
|
.BinaryOperationSmiLiteral(Token::Value::MOD, Smi::FromInt(42), 2)
|
||||||
|
.BinaryOperationSmiLiteral(Token::Value::EXP, Smi::FromInt(42), 2)
|
||||||
.BinaryOperationSmiLiteral(Token::Value::BIT_OR, Smi::FromInt(42), 2)
|
.BinaryOperationSmiLiteral(Token::Value::BIT_OR, Smi::FromInt(42), 2)
|
||||||
.BinaryOperationSmiLiteral(Token::Value::BIT_XOR, Smi::FromInt(42), 2)
|
.BinaryOperationSmiLiteral(Token::Value::BIT_XOR, Smi::FromInt(42), 2)
|
||||||
.BinaryOperationSmiLiteral(Token::Value::BIT_AND, Smi::FromInt(42), 2)
|
.BinaryOperationSmiLiteral(Token::Value::BIT_AND, Smi::FromInt(42), 2)
|
||||||
|
Loading…
Reference in New Issue
Block a user