Commit da5e4de1 authored by Victor Gomes's avatar Victor Gomes Committed by V8 LUCI CQ

[maglev] Support ToNumber and ToNumeric

Bug: v8:7700
Change-Id: I73eae4aa0b81c3a8ae53b64a0f750a0e7cced40e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3784589
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Auto-Submit: Victor Gomes <victorgomes@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82024}
parent 6c64338c
......@@ -1612,8 +1612,35 @@ void MaglevGraphBuilder::VisitTestInstanceOf() {
MAGLEV_UNIMPLEMENTED_BYTECODE(TestIn)
MAGLEV_UNIMPLEMENTED_BYTECODE(ToName)
MAGLEV_UNIMPLEMENTED_BYTECODE(ToNumber)
MAGLEV_UNIMPLEMENTED_BYTECODE(ToNumeric)
void MaglevGraphBuilder::BuildToNumberOrToNumeric(Object::Conversion mode) {
ValueNode* value = GetAccumulatorTagged();
FeedbackSlot slot = GetSlotOperand(0);
switch (broker()->GetFeedbackForBinaryOperation(
compiler::FeedbackSource(feedback(), slot))) {
case BinaryOperationHint::kSignedSmall:
AddNewNode<CheckSmi>({value});
break;
case BinaryOperationHint::kSignedSmallInputs:
UNREACHABLE();
case BinaryOperationHint::kNumber:
case BinaryOperationHint::kBigInt:
AddNewNode<CheckNumber>({value}, mode);
break;
default:
SetAccumulator(
AddNewNode<ToNumberOrNumeric>({GetContext(), value}, mode));
break;
}
}
void MaglevGraphBuilder::VisitToNumber() {
BuildToNumberOrToNumeric(Object::Conversion::kToNumber);
}
void MaglevGraphBuilder::VisitToNumeric() {
BuildToNumberOrToNumeric(Object::Conversion::kToNumeric);
}
MAGLEV_UNIMPLEMENTED_BYTECODE(ToObject)
MAGLEV_UNIMPLEMENTED_BYTECODE(ToString)
......
......@@ -738,6 +738,8 @@ class MaglevGraphBuilder {
void BuildBranchIfToBooleanTrue(ValueNode* node, int true_target,
int false_target);
void BuildToNumberOrToNumeric(Object::Conversion mode);
void CalculatePredecessorCounts() {
// Add 1 after the end of the bytecode so we can always write to the offset
// after the last bytecode.
......
......@@ -99,6 +99,7 @@ class MaglevGraphVerifier {
case Opcode::kCheckMaps:
case Opcode::kCheckMapsWithMigration:
case Opcode::kCheckSmi:
case Opcode::kCheckNumber:
case Opcode::kCheckString:
case Opcode::kCheckedInternalizedString:
// TODO(victorgomes): Can we check that the input is Boolean?
......@@ -152,6 +153,7 @@ class MaglevGraphVerifier {
// TODO(victorgomes): Can we check that second input is a Smi?
case Opcode::kStoreTaggedFieldWithWriteBarrier:
case Opcode::kLoadNamedGeneric:
case Opcode::kToNumberOrNumeric:
DCHECK_EQ(node->input_count(), 2);
CheckValueInputIs(node, 0, ValueRepresentation::kTagged);
CheckValueInputIs(node, 1, ValueRepresentation::kTagged);
......
......@@ -951,6 +951,30 @@ void CheckSmi::GenerateCode(MaglevCodeGenState* code_gen_state,
void CheckSmi::PrintParams(std::ostream& os,
MaglevGraphLabeller* graph_labeller) const {}
void CheckNumber::AllocateVreg(MaglevVregAllocationState* vreg_state) {
UseRegister(receiver_input());
}
void CheckNumber::GenerateCode(MaglevCodeGenState* code_gen_state,
const ProcessingState& state) {
Label done;
Register value = ToRegister(receiver_input());
// If {value} is a Smi or a HeapNumber, we're done.
__ JumpIfSmi(value, &done);
__ CompareRoot(FieldOperand(value, HeapObject::kMapOffset),
RootIndex::kHeapNumberMap);
if (mode() == Object::Conversion::kToNumeric) {
// Jump to done if it is a HeapNumber.
__ j(equal, &done);
// Check if it is a BigInt.
__ LoadMap(kScratchRegister, value);
__ cmpw(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
Immediate(BIGINT_TYPE));
}
EmitEagerDeoptIf(not_equal, code_gen_state, DeoptimizeReason::kNotANumber,
this);
__ bind(&done);
}
void CheckHeapObject::AllocateVreg(MaglevVregAllocationState* vreg_state) {
UseRegister(receiver_input());
}
......@@ -2141,6 +2165,25 @@ void TestTypeOf::GenerateCode(MaglevCodeGenState* code_gen_state,
__ bind(&done);
}
void ToNumberOrNumeric::AllocateVreg(MaglevVregAllocationState* vreg_state) {
using D = TypeConversionDescriptor;
UseFixed(context(), kContextRegister);
UseFixed(value_input(), D::GetRegisterParameter(D::kArgument));
DefineAsFixed(vreg_state, this, kReturnRegister0);
}
void ToNumberOrNumeric::GenerateCode(MaglevCodeGenState* code_gen_state,
const ProcessingState& state) {
switch (mode()) {
case Object::Conversion::kToNumber:
__ CallBuiltin(Builtin::kToNumber);
break;
case Object::Conversion::kToNumeric:
__ CallBuiltin(Builtin::kToNumeric);
break;
}
code_gen_state->DefineLazyDeoptPoint(lazy_deopt_info());
}
void ChangeInt32ToFloat64::AllocateVreg(MaglevVregAllocationState* vreg_state) {
UseRegister(input());
DefineAsRegister(vreg_state, this);
......
......@@ -153,6 +153,7 @@ class CompactInterpreterFrameState;
V(TestInstanceOf) \
V(TestUndetectable) \
V(TestTypeOf) \
V(ToNumberOrNumeric) \
CONSTANT_VALUE_NODE_LIST(V) \
INT32_OPERATIONS_NODE_LIST(V) \
FLOAT64_OPERATIONS_NODE_LIST(V) \
......@@ -166,6 +167,7 @@ class CompactInterpreterFrameState;
V(Abort) \
V(CheckMaps) \
V(CheckSmi) \
V(CheckNumber) \
V(CheckHeapObject) \
V(CheckString) \
V(CheckMapsWithMigration) \
......@@ -1648,6 +1650,28 @@ class TestTypeOf : public FixedInputValueNodeT<1, TestTypeOf> {
interpreter::TestTypeOfFlags::LiteralFlag literal_;
};
class ToNumberOrNumeric : public FixedInputValueNodeT<2, ToNumberOrNumeric> {
using Base = FixedInputValueNodeT<2, ToNumberOrNumeric>;
public:
explicit ToNumberOrNumeric(uint64_t bitfield, Object::Conversion mode)
: Base(bitfield), mode_(mode) {}
// The implementation currently calls runtime.
static constexpr OpProperties kProperties = OpProperties::JSCall();
Input& context() { return Node::input(0); }
Input& value_input() { return Node::input(1); }
Object::Conversion mode() const { return mode_; }
void AllocateVreg(MaglevVregAllocationState*);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
private:
const Object::Conversion mode_;
};
class InitialValue : public FixedInputValueNodeT<0, InitialValue> {
using Base = FixedInputValueNodeT<0, InitialValue>;
......@@ -2082,6 +2106,27 @@ class CheckSmi : public FixedInputNodeT<1, CheckSmi> {
void PrintParams(std::ostream&, MaglevGraphLabeller*) const;
};
class CheckNumber : public FixedInputNodeT<1, CheckNumber> {
using Base = FixedInputNodeT<1, CheckNumber>;
public:
explicit CheckNumber(uint64_t bitfield, Object::Conversion mode)
: Base(bitfield), mode_(mode) {}
static constexpr OpProperties kProperties = OpProperties::EagerDeopt();
static constexpr int kReceiverIndex = 0;
Input& receiver_input() { return input(kReceiverIndex); }
Object::Conversion mode() const { return mode_; }
void AllocateVreg(MaglevVregAllocationState*);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
private:
const Object::Conversion mode_;
};
class CheckHeapObject : public FixedInputNodeT<1, CheckHeapObject> {
using Base = FixedInputNodeT<1, CheckHeapObject>;
......
......@@ -1538,8 +1538,10 @@ void StraightForwardRegisterAllocator::MergeRegisterValues(ControlNode* control,
// different register.
// This maybe not be true for conversion nodes, as they can split and take
// over the liveness of the node they are converting.
DCHECK_IMPLIES(!IsInRegister(target_state, incoming),
incoming->properties().is_conversion());
// TODO(v8:7700): This DCHECK is overeager, {incoming} can be a Phi node
// containing conversion nodes.
// DCHECK_IMPLIES(!IsInRegister(target_state, incoming),
// incoming->properties().is_conversion());
return;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment