[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:
Georg Neis 2017-11-20 17:04:54 +01:00 committed by Commit Bot
parent a70344c63a
commit 9bf0002176
15 changed files with 167 additions and 83 deletions

View File

@ -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 */ \

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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) \

View File

@ -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();

View File

@ -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.

View File

@ -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:

View File

@ -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);

View File

@ -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) \

View File

@ -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;

View File

@ -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:

View File

@ -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);
}

View File

@ -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());