[bigint,compiler] Support bigints in increment (++) and decrement (--).
... in the same style as the previous CLs for negation and bitwise-not. R=jarin@chromium.org Bug: v8:6791 Change-Id: I0aa96a72421e90c8c82a39dd4264fdcf00967504 Reviewed-on: https://chromium-review.googlesource.com/779141 Commit-Queue: Georg Neis <neis@chromium.org> Reviewed-by: Jaroslav Sevcik <jarin@chromium.org> Cr-Commit-Position: refs/heads/master@{#49658}
This commit is contained in:
parent
a70344c63a
commit
9bf0002176
@ -702,6 +702,8 @@ namespace internal {
|
||||
TFC(SameValue, Compare, 1) \
|
||||
TFC(StrictEqual, Compare, 1) \
|
||||
TFS(BitwiseNot, kValue) \
|
||||
TFS(Decrement, kValue) \
|
||||
TFS(Increment, kValue) \
|
||||
TFS(Negate, kValue) \
|
||||
\
|
||||
/* Object */ \
|
||||
|
@ -771,6 +771,45 @@ TF_BUILTIN(BitwiseNot, NumberBuiltinsAssembler) {
|
||||
}
|
||||
}
|
||||
|
||||
TF_BUILTIN(Decrement, NumberBuiltinsAssembler) {
|
||||
Node* context = Parameter(Descriptor::kContext);
|
||||
VARIABLE(var_input, MachineRepresentation::kTagged);
|
||||
Label do_number(this), do_bigint(this);
|
||||
|
||||
UnaryOp<Descriptor>(&var_input, &do_number, &do_number, nullptr, &do_bigint);
|
||||
|
||||
BIND(&do_number);
|
||||
{
|
||||
TailCallBuiltin(Builtins::kSubtract, context, var_input.value(),
|
||||
SmiConstant(1));
|
||||
}
|
||||
|
||||
BIND(&do_bigint);
|
||||
{
|
||||
Return(CallRuntime(Runtime::kBigIntUnaryOp, context, var_input.value(),
|
||||
SmiConstant(Operation::kDecrement)));
|
||||
}
|
||||
}
|
||||
|
||||
TF_BUILTIN(Increment, NumberBuiltinsAssembler) {
|
||||
Node* context = Parameter(Descriptor::kContext);
|
||||
VARIABLE(var_input, MachineRepresentation::kTagged);
|
||||
Label do_number(this), do_bigint(this);
|
||||
|
||||
UnaryOp<Descriptor>(&var_input, &do_number, &do_number, nullptr, &do_bigint);
|
||||
|
||||
BIND(&do_number);
|
||||
{
|
||||
TailCallBuiltin(Builtins::kAdd, context, var_input.value(), SmiConstant(1));
|
||||
}
|
||||
|
||||
BIND(&do_bigint);
|
||||
{
|
||||
Return(CallRuntime(Runtime::kBigIntUnaryOp, context, var_input.value(),
|
||||
SmiConstant(Operation::kIncrement)));
|
||||
}
|
||||
}
|
||||
|
||||
TF_BUILTIN(Negate, NumberBuiltinsAssembler) {
|
||||
VARIABLE(var_input, MachineRepresentation::kTagged);
|
||||
VARIABLE(var_input_double, MachineRepresentation::kFloat64);
|
||||
|
@ -2015,6 +2015,27 @@ void BytecodeGraphBuilder::VisitThrowSuperAlreadyCalledIfNotHole() {
|
||||
Runtime::kThrowSuperAlreadyCalledError);
|
||||
}
|
||||
|
||||
void BytecodeGraphBuilder::BuildUnaryOp(const Operator* op) {
|
||||
PrepareEagerCheckpoint();
|
||||
Node* operand = environment()->LookupAccumulator();
|
||||
|
||||
FeedbackSlot slot = feedback_vector()->ToSlot(
|
||||
bytecode_iterator().GetIndexOperand(kUnaryOperationHintIndex));
|
||||
JSTypeHintLowering::LoweringResult lowering =
|
||||
TryBuildSimplifiedUnaryOp(op, operand, slot);
|
||||
if (lowering.IsExit()) return;
|
||||
|
||||
Node* node = nullptr;
|
||||
if (lowering.IsSideEffectFree()) {
|
||||
node = lowering.value();
|
||||
} else {
|
||||
DCHECK(!lowering.Changed());
|
||||
node = NewNode(op, operand);
|
||||
}
|
||||
|
||||
environment()->BindAccumulator(node, Environment::kAttachFrameState);
|
||||
}
|
||||
|
||||
void BytecodeGraphBuilder::BuildBinaryOp(const Operator* op) {
|
||||
PrepareEagerCheckpoint();
|
||||
Node* left =
|
||||
@ -2084,48 +2105,19 @@ CallFrequency BytecodeGraphBuilder::ComputeCallFrequency(int slot_id) const {
|
||||
}
|
||||
|
||||
void BytecodeGraphBuilder::VisitBitwiseNot() {
|
||||
// TODO(neis): Define a BuildUnaryOp helper function.
|
||||
PrepareEagerCheckpoint();
|
||||
|
||||
FeedbackSlot slot = feedback_vector()->ToSlot(
|
||||
bytecode_iterator().GetIndexOperand(kUnaryOperationHintIndex));
|
||||
const Operator* op = javascript()->BitwiseNot();
|
||||
Node* operand = environment()->LookupAccumulator();
|
||||
|
||||
JSTypeHintLowering::LoweringResult lowering =
|
||||
TryBuildSimplifiedUnaryOp(op, operand, slot);
|
||||
if (lowering.IsExit()) return;
|
||||
Node* node = nullptr;
|
||||
if (lowering.IsSideEffectFree()) {
|
||||
node = lowering.value();
|
||||
} else {
|
||||
DCHECK(!lowering.Changed());
|
||||
node = NewNode(op, operand);
|
||||
BuildUnaryOp(javascript()->BitwiseNot());
|
||||
}
|
||||
|
||||
environment()->BindAccumulator(node, Environment::kAttachFrameState);
|
||||
void BytecodeGraphBuilder::VisitDec() {
|
||||
BuildUnaryOp(javascript()->Decrement());
|
||||
}
|
||||
|
||||
void BytecodeGraphBuilder::VisitInc() {
|
||||
BuildUnaryOp(javascript()->Increment());
|
||||
}
|
||||
|
||||
void BytecodeGraphBuilder::VisitNegate() {
|
||||
PrepareEagerCheckpoint();
|
||||
|
||||
FeedbackSlot slot = feedback_vector()->ToSlot(
|
||||
bytecode_iterator().GetIndexOperand(kUnaryOperationHintIndex));
|
||||
const Operator* op = javascript()->Negate();
|
||||
Node* operand = environment()->LookupAccumulator();
|
||||
|
||||
JSTypeHintLowering::LoweringResult lowering =
|
||||
TryBuildSimplifiedUnaryOp(op, operand, slot);
|
||||
if (lowering.IsExit()) return;
|
||||
Node* node = nullptr;
|
||||
if (lowering.IsSideEffectFree()) {
|
||||
node = lowering.value();
|
||||
} else {
|
||||
DCHECK(!lowering.Changed());
|
||||
node = NewNode(op, operand);
|
||||
}
|
||||
|
||||
environment()->BindAccumulator(node, Environment::kAttachFrameState);
|
||||
BuildUnaryOp(javascript()->Negate());
|
||||
}
|
||||
|
||||
void BytecodeGraphBuilder::VisitAdd() {
|
||||
@ -2237,52 +2229,6 @@ void BytecodeGraphBuilder::VisitShiftRightLogicalSmi() {
|
||||
BuildBinaryOpWithImmediate(javascript()->ShiftRightLogical());
|
||||
}
|
||||
|
||||
void BytecodeGraphBuilder::VisitInc() {
|
||||
PrepareEagerCheckpoint();
|
||||
// Note: Use subtract -1 here instead of add 1 to ensure we always convert to
|
||||
// a number, not a string.
|
||||
Node* left = environment()->LookupAccumulator();
|
||||
Node* right = jsgraph()->Constant(-1);
|
||||
const Operator* op = javascript()->Subtract();
|
||||
|
||||
FeedbackSlot slot = feedback_vector()->ToSlot(
|
||||
bytecode_iterator().GetIndexOperand(kCountOperationHintIndex));
|
||||
JSTypeHintLowering::LoweringResult lowering =
|
||||
TryBuildSimplifiedBinaryOp(op, left, right, slot);
|
||||
if (lowering.IsExit()) return;
|
||||
|
||||
Node* node = nullptr;
|
||||
if (lowering.IsSideEffectFree()) {
|
||||
node = lowering.value();
|
||||
} else {
|
||||
DCHECK(!lowering.Changed());
|
||||
node = NewNode(op, left, right);
|
||||
}
|
||||
environment()->BindAccumulator(node, Environment::kAttachFrameState);
|
||||
}
|
||||
|
||||
void BytecodeGraphBuilder::VisitDec() {
|
||||
PrepareEagerCheckpoint();
|
||||
Node* left = environment()->LookupAccumulator();
|
||||
Node* right = jsgraph()->OneConstant();
|
||||
const Operator* op = javascript()->Subtract();
|
||||
|
||||
FeedbackSlot slot = feedback_vector()->ToSlot(
|
||||
bytecode_iterator().GetIndexOperand(kCountOperationHintIndex));
|
||||
JSTypeHintLowering::LoweringResult lowering =
|
||||
TryBuildSimplifiedBinaryOp(op, left, right, slot);
|
||||
if (lowering.IsExit()) return;
|
||||
|
||||
Node* node = nullptr;
|
||||
if (lowering.IsSideEffectFree()) {
|
||||
node = lowering.value();
|
||||
} else {
|
||||
DCHECK(!lowering.Changed());
|
||||
node = NewNode(op, left, right);
|
||||
}
|
||||
environment()->BindAccumulator(node, Environment::kAttachFrameState);
|
||||
}
|
||||
|
||||
void BytecodeGraphBuilder::VisitLogicalNot() {
|
||||
Node* value = environment()->LookupAccumulator();
|
||||
Node* node = NewNode(simplified()->BooleanNot(), value);
|
||||
|
@ -171,6 +171,7 @@ class BytecodeGraphBuilder {
|
||||
std::initializer_list<Node*> args, int slot_id) {
|
||||
BuildCall(receiver_mode, args.begin(), args.size(), slot_id);
|
||||
}
|
||||
void BuildUnaryOp(const Operator* op);
|
||||
void BuildBinaryOp(const Operator* op);
|
||||
void BuildBinaryOpWithImmediate(const Operator* op);
|
||||
void BuildCompareOp(const Operator* op);
|
||||
|
@ -71,6 +71,8 @@ REPLACE_STUB_CALL(LessThanOrEqual)
|
||||
REPLACE_STUB_CALL(GreaterThan)
|
||||
REPLACE_STUB_CALL(GreaterThanOrEqual)
|
||||
REPLACE_STUB_CALL(BitwiseNot)
|
||||
REPLACE_STUB_CALL(Decrement)
|
||||
REPLACE_STUB_CALL(Increment)
|
||||
REPLACE_STUB_CALL(Negate)
|
||||
REPLACE_STUB_CALL(HasProperty)
|
||||
REPLACE_STUB_CALL(Equal)
|
||||
|
@ -578,6 +578,8 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
|
||||
V(Divide, Operator::kNoProperties, 2, 1) \
|
||||
V(Modulus, Operator::kNoProperties, 2, 1) \
|
||||
V(BitwiseNot, Operator::kNoProperties, 1, 1) \
|
||||
V(Decrement, Operator::kNoProperties, 1, 1) \
|
||||
V(Increment, Operator::kNoProperties, 1, 1) \
|
||||
V(Negate, Operator::kNoProperties, 1, 1) \
|
||||
V(ToInteger, Operator::kNoProperties, 1, 1) \
|
||||
V(ToLength, Operator::kNoProperties, 1, 1) \
|
||||
|
@ -653,6 +653,8 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
|
||||
const Operator* Modulus();
|
||||
|
||||
const Operator* BitwiseNot();
|
||||
const Operator* Decrement();
|
||||
const Operator* Increment();
|
||||
const Operator* Negate();
|
||||
|
||||
const Operator* ToInteger();
|
||||
|
@ -234,6 +234,25 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceUnaryOperation(
|
||||
node = b.TryBuildNumberBinop();
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kJSDecrement: {
|
||||
// Lower to a speculative subtraction of 1 if we have some kind of Number
|
||||
// feedback.
|
||||
JSSpeculativeBinopBuilder b(this, jsgraph()->javascript()->Subtract(),
|
||||
operand, jsgraph()->SmiConstant(1), effect,
|
||||
control, slot);
|
||||
node = b.TryBuildNumberBinop();
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kJSIncrement: {
|
||||
// Lower to a speculative addition of 1 if we have some kind of Number
|
||||
// feedback.
|
||||
BinaryOperationHint hint = BinaryOperationHint::kAny; // Dummy.
|
||||
JSSpeculativeBinopBuilder b(this, jsgraph()->javascript()->Add(hint),
|
||||
operand, jsgraph()->SmiConstant(1), effect,
|
||||
control, slot);
|
||||
node = b.TryBuildNumberBinop();
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kJSNegate: {
|
||||
// Lower to a speculative multiplication with -1 if we have some kind of
|
||||
// Number feedback.
|
||||
|
@ -441,6 +441,37 @@ Reduction JSTypedLowering::ReduceJSBitwiseNot(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction JSTypedLowering::ReduceJSDecrement(Node* node) {
|
||||
Node* input = NodeProperties::GetValueInput(node, 0);
|
||||
Type* input_type = NodeProperties::GetType(input);
|
||||
if (input_type->Is(Type::PlainPrimitive())) {
|
||||
// JSDecrement(x) => NumberSubtract(ToNumber(x), 1)
|
||||
node->InsertInput(graph()->zone(), 1, jsgraph()->OneConstant());
|
||||
NodeProperties::ChangeOp(node, javascript()->Subtract());
|
||||
JSBinopReduction r(this, node);
|
||||
r.ConvertInputsToNumber();
|
||||
DCHECK_EQ(simplified()->NumberSubtract(), r.NumberOp());
|
||||
return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction JSTypedLowering::ReduceJSIncrement(Node* node) {
|
||||
Node* input = NodeProperties::GetValueInput(node, 0);
|
||||
Type* input_type = NodeProperties::GetType(input);
|
||||
if (input_type->Is(Type::PlainPrimitive())) {
|
||||
// JSIncrement(x) => NumberAdd(ToNumber(x), 1)
|
||||
node->InsertInput(graph()->zone(), 1, jsgraph()->OneConstant());
|
||||
BinaryOperationHint hint = BinaryOperationHint::kAny; // Dummy.
|
||||
NodeProperties::ChangeOp(node, javascript()->Add(hint));
|
||||
JSBinopReduction r(this, node);
|
||||
r.ConvertInputsToNumber();
|
||||
DCHECK_EQ(simplified()->NumberAdd(), r.NumberOp());
|
||||
return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction JSTypedLowering::ReduceJSNegate(Node* node) {
|
||||
Node* input = NodeProperties::GetValueInput(node, 0);
|
||||
Type* input_type = NodeProperties::GetType(input);
|
||||
@ -2095,6 +2126,10 @@ Reduction JSTypedLowering::Reduce(Node* node) {
|
||||
return ReduceNumberBinop(node);
|
||||
case IrOpcode::kJSBitwiseNot:
|
||||
return ReduceJSBitwiseNot(node);
|
||||
case IrOpcode::kJSDecrement:
|
||||
return ReduceJSDecrement(node);
|
||||
case IrOpcode::kJSIncrement:
|
||||
return ReduceJSIncrement(node);
|
||||
case IrOpcode::kJSNegate:
|
||||
return ReduceJSNegate(node);
|
||||
case IrOpcode::kJSHasInPrototypeChain:
|
||||
|
@ -41,6 +41,8 @@ class V8_EXPORT_PRIVATE JSTypedLowering final
|
||||
|
||||
Reduction ReduceJSAdd(Node* node);
|
||||
Reduction ReduceJSBitwiseNot(Node* node);
|
||||
Reduction ReduceJSDecrement(Node* node);
|
||||
Reduction ReduceJSIncrement(Node* node);
|
||||
Reduction ReduceJSNegate(Node* node);
|
||||
Reduction ReduceJSComparison(Node* node);
|
||||
Reduction ReduceJSLoadNamed(Node* node);
|
||||
|
@ -127,6 +127,8 @@
|
||||
#define JS_SIMPLE_UNOP_LIST(V) \
|
||||
JS_CONVERSION_UNOP_LIST(V) \
|
||||
V(JSBitwiseNot) \
|
||||
V(JSDecrement) \
|
||||
V(JSIncrement) \
|
||||
V(JSNegate)
|
||||
|
||||
#define JS_OBJECT_OP_LIST(V) \
|
||||
|
@ -111,6 +111,8 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
|
||||
case IrOpcode::kJSDebugger:
|
||||
case IrOpcode::kJSGetSuperConstructor:
|
||||
case IrOpcode::kJSBitwiseNot:
|
||||
case IrOpcode::kJSDecrement:
|
||||
case IrOpcode::kJSIncrement:
|
||||
case IrOpcode::kJSNegate:
|
||||
return true;
|
||||
|
||||
|
@ -3046,6 +3046,8 @@ class RepresentationSelector {
|
||||
JS_OTHER_OP_LIST(OPCODE_CASE)
|
||||
#undef OPCODE_CASE
|
||||
case IrOpcode::kJSBitwiseNot:
|
||||
case IrOpcode::kJSDecrement:
|
||||
case IrOpcode::kJSIncrement:
|
||||
case IrOpcode::kJSNegate:
|
||||
case IrOpcode::kJSToInteger:
|
||||
case IrOpcode::kJSToLength:
|
||||
|
@ -265,6 +265,8 @@ class Typer::Visitor : public Reducer {
|
||||
static Type* FalsifyUndefined(ComparisonOutcome, Typer*);
|
||||
|
||||
static Type* BitwiseNot(Type*, Typer*);
|
||||
static Type* Decrement(Type*, Typer*);
|
||||
static Type* Increment(Type*, Typer*);
|
||||
static Type* Negate(Type*, Typer*);
|
||||
|
||||
static Type* ToPrimitive(Type*, Typer*);
|
||||
@ -435,6 +437,22 @@ Type* Typer::Visitor::BitwiseNot(Type* type, Typer* t) {
|
||||
return Type::Numeric();
|
||||
}
|
||||
|
||||
Type* Typer::Visitor::Decrement(Type* type, Typer* t) {
|
||||
type = ToNumeric(type, t);
|
||||
if (type->Is(Type::Number())) {
|
||||
return NumberSubtract(type, t->cache_.kSingletonOne, t);
|
||||
}
|
||||
return Type::Numeric();
|
||||
}
|
||||
|
||||
Type* Typer::Visitor::Increment(Type* type, Typer* t) {
|
||||
type = ToNumeric(type, t);
|
||||
if (type->Is(Type::Number())) {
|
||||
return NumberAdd(type, t->cache_.kSingletonOne, t);
|
||||
}
|
||||
return Type::Numeric();
|
||||
}
|
||||
|
||||
Type* Typer::Visitor::Negate(Type* type, Typer* t) {
|
||||
type = ToNumeric(type, t);
|
||||
if (type->Is(Type::Number())) {
|
||||
@ -1092,6 +1110,14 @@ Type* Typer::Visitor::TypeJSBitwiseNot(Node* node) {
|
||||
return TypeUnaryOp(node, BitwiseNot);
|
||||
}
|
||||
|
||||
Type* Typer::Visitor::TypeJSDecrement(Node* node) {
|
||||
return TypeUnaryOp(node, Decrement);
|
||||
}
|
||||
|
||||
Type* Typer::Visitor::TypeJSIncrement(Node* node) {
|
||||
return TypeUnaryOp(node, Increment);
|
||||
}
|
||||
|
||||
Type* Typer::Visitor::TypeJSNegate(Node* node) {
|
||||
return TypeUnaryOp(node, Negate);
|
||||
}
|
||||
|
@ -613,6 +613,8 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
|
||||
break;
|
||||
|
||||
case IrOpcode::kJSBitwiseNot:
|
||||
case IrOpcode::kJSDecrement:
|
||||
case IrOpcode::kJSIncrement:
|
||||
case IrOpcode::kJSNegate:
|
||||
// Type is Numeric.
|
||||
CheckTypeIs(node, Type::Numeric());
|
||||
|
Loading…
Reference in New Issue
Block a user