Commit dbb52a1c authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[bigint,compiler] Fully implement ToNumeric bytecode.

TBR: rmcilroy@chromium.org
Bug: v8:6791
Change-Id: I4ac2bdce353d987a2fe45149d8556b6591569a01
Reviewed-on: https://chromium-review.googlesource.com/771191
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49528}
parent a8152658
......@@ -2521,9 +2521,25 @@ void BytecodeGraphBuilder::VisitToNumber() {
}
void BytecodeGraphBuilder::VisitToNumeric() {
// TODO(neis): This is currently only correct in the absence of bigints.
DCHECK(!FLAG_harmony_bigint);
VisitToNumber();
PrepareEagerCheckpoint();
Node* object = environment()->LookupAccumulator();
// If we have some kind of Number feedback, we do the same lowering as for
// ToNumber.
FeedbackSlot slot =
feedback_vector()->ToSlot(bytecode_iterator().GetIndexOperand(0));
JSTypeHintLowering::LoweringResult lowering =
TryBuildSimplifiedToNumber(object, slot);
Node* node = nullptr;
if (lowering.IsSideEffectFree()) {
node = lowering.value();
} else {
DCHECK(!lowering.Changed());
node = NewNode(javascript()->ToNumeric(), object);
}
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitJump() { BuildJump(); }
......
......@@ -63,6 +63,7 @@ bool CanBeNullOrUndefined(Node* node) {
case IrOpcode::kJSToLength:
case IrOpcode::kJSToName:
case IrOpcode::kJSToNumber:
case IrOpcode::kJSToNumeric:
case IrOpcode::kJSToString:
return false;
case IrOpcode::kHeapConstant: {
......
......@@ -75,6 +75,7 @@ REPLACE_STUB_CALL(Equal)
REPLACE_STUB_CALL(ToInteger)
REPLACE_STUB_CALL(ToLength)
REPLACE_STUB_CALL(ToNumber)
REPLACE_STUB_CALL(ToNumeric)
REPLACE_STUB_CALL(ToName)
REPLACE_STUB_CALL(ToObject)
REPLACE_STUB_CALL(ToString)
......
......@@ -581,6 +581,7 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
V(ToLength, Operator::kNoProperties, 1, 1) \
V(ToName, Operator::kNoProperties, 1, 1) \
V(ToNumber, Operator::kNoProperties, 1, 1) \
V(ToNumeric, Operator::kNoProperties, 1, 1) \
V(ToObject, Operator::kFoldable, 1, 1) \
V(ToString, Operator::kNoProperties, 1, 1) \
V(Create, Operator::kNoProperties, 2, 1) \
......
......@@ -656,6 +656,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* ToLength();
const Operator* ToName();
const Operator* ToNumber();
const Operator* ToNumeric();
const Operator* ToObject();
const Operator* ToString();
......
......@@ -364,7 +364,7 @@ class JSBinopReduction final {
Node* ConvertPlainPrimitiveToNumber(Node* node) {
DCHECK(NodeProperties::GetType(node)->Is(Type::PlainPrimitive()));
// Avoid inserting too many eager ToNumber() operations.
Reduction const reduction = lowering_->ReduceJSToNumberInput(node);
Reduction const reduction = lowering_->ReduceJSToNumberOrNumericInput(node);
if (reduction.Changed()) return reduction.replacement();
if (NodeProperties::GetType(node)->Is(Type::Number())) {
return node;
......@@ -900,8 +900,9 @@ Reduction JSTypedLowering::ReduceJSToLength(Node* node) {
return NoChange();
}
Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
// Try constant-folding of JSToNumber with constant inputs.
Reduction JSTypedLowering::ReduceJSToNumberOrNumericInput(Node* input) {
// Try constant-folding of JSToNumber/JSToNumeric with constant inputs. Here
// we only cover cases where ToNumber and ToNumeric coincide.
Type* input_type = NodeProperties::GetType(input);
if (input_type->Is(Type::String())) {
HeapObjectMatcher m(input);
......@@ -933,10 +934,10 @@ Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
return NoChange();
}
Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
Reduction JSTypedLowering::ReduceJSToNumberOrNumeric(Node* node) {
// Try to reduce the input first.
Node* const input = node->InputAt(0);
Reduction reduction = ReduceJSToNumberInput(input);
Reduction reduction = ReduceJSToNumberOrNumericInput(input);
if (reduction.Changed()) {
ReplaceWithValue(node, reduction.replacement());
return reduction;
......@@ -945,6 +946,10 @@ Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
if (input_type->Is(Type::PlainPrimitive())) {
RelaxEffectsAndControls(node);
node->TrimInputCount(1);
// For a PlainPrimitive, ToNumeric is the same as ToNumber.
Type* node_type = NodeProperties::GetType(node);
NodeProperties::SetType(
node, Type::Intersect(node_type, Type::Number(), graph()->zone()));
NodeProperties::ChangeOp(node, simplified()->PlainPrimitiveToNumber());
return Changed(node);
}
......@@ -2070,7 +2075,8 @@ Reduction JSTypedLowering::Reduce(Node* node) {
case IrOpcode::kJSToName:
return ReduceJSToName(node);
case IrOpcode::kJSToNumber:
return ReduceJSToNumber(node);
case IrOpcode::kJSToNumeric:
return ReduceJSToNumberOrNumeric(node);
case IrOpcode::kJSToString:
return ReduceJSToString(node);
case IrOpcode::kJSToObject:
......
......@@ -53,8 +53,8 @@ class V8_EXPORT_PRIVATE JSTypedLowering final
Reduction ReduceJSToInteger(Node* node);
Reduction ReduceJSToLength(Node* node);
Reduction ReduceJSToName(Node* node);
Reduction ReduceJSToNumberInput(Node* input);
Reduction ReduceJSToNumber(Node* node);
Reduction ReduceJSToNumberOrNumericInput(Node* input);
Reduction ReduceJSToNumberOrNumeric(Node* node);
Reduction ReduceJSToStringInput(Node* input);
Reduction ReduceJSToString(Node* node);
Reduction ReduceJSToObject(Node* node);
......
......@@ -318,6 +318,7 @@ InductionVariable* LoopVariableOptimizer::TryGetInductionVariable(Node* phi) {
}
// TODO(jarin) Support both sides.
// XXX
if (arith->InputAt(0) != phi) {
if ((arith->InputAt(0)->opcode() != IrOpcode::kJSToNumber &&
arith->InputAt(0)->opcode() != IrOpcode::kSpeculativeToNumber) ||
......
......@@ -120,6 +120,7 @@
V(JSToLength) \
V(JSToName) \
V(JSToNumber) \
V(JSToNumeric) \
V(JSToObject) \
V(JSToString)
......
......@@ -245,7 +245,7 @@ Type* OperationTyper::ConvertReceiver(Type* type) {
return type;
}
Type* OperationTyper::ToNumber(Type* type) {
Type* OperationTyper::ToNumberOrNumeric(Object::Conversion mode, Type* type) {
if (type->Is(Type::Number())) return type;
if (type->Is(Type::NullOrUndefined())) {
if (type->Is(Type::Null())) return cache_.kSingletonZero;
......@@ -269,7 +269,19 @@ Type* OperationTyper::ToNumber(Type* type) {
}
return Type::Intersect(type, Type::Number(), zone());
}
return Type::Number();
if (type->Is(Type::BigInt())) {
return mode == Object::Conversion::kToNumber ? Type::None() : type;
}
return mode == Object::Conversion::kToNumber ? Type::Number()
: Type::Numeric();
}
Type* OperationTyper::ToNumber(Type* type) {
return ToNumberOrNumeric(Object::Conversion::kToNumber, type);
}
Type* OperationTyper::ToNumeric(Type* type) {
return ToNumberOrNumeric(Object::Conversion::kToNumeric, type);
}
Type* OperationTyper::NumberAbs(Type* type) {
......
......@@ -7,6 +7,7 @@
#include "src/base/flags.h"
#include "src/compiler/opcodes.h"
#include "src/objects.h"
namespace v8 {
namespace internal {
......@@ -31,9 +32,9 @@ class V8_EXPORT_PRIVATE OperationTyper {
Type* Merge(Type* left, Type* right);
Type* ToPrimitive(Type* type);
// Helpers for number operation typing.
Type* ToNumber(Type* type);
Type* ToNumeric(Type* type);
Type* WeakenRange(Type* current_range, Type* previous_range);
// Number unary operators.
......@@ -73,6 +74,8 @@ class V8_EXPORT_PRIVATE OperationTyper {
private:
typedef base::Flags<ComparisonOutcomeFlags> ComparisonOutcome;
Type* ToNumberOrNumeric(Object::Conversion mode, Type* type);
ComparisonOutcome Invert(ComparisonOutcome);
Type* Invert(Type*);
Type* FalsifyUndefined(ComparisonOutcome);
......
......@@ -93,6 +93,7 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
case IrOpcode::kJSToLength:
case IrOpcode::kJSToName:
case IrOpcode::kJSToNumber:
case IrOpcode::kJSToNumeric:
case IrOpcode::kJSToObject:
case IrOpcode::kJSToString:
......
......@@ -1558,15 +1558,18 @@ class RepresentationSelector {
}
return;
}
case IrOpcode::kJSToNumber: {
case IrOpcode::kJSToNumber:
case IrOpcode::kJSToNumeric: {
VisitInputs(node);
// TODO(bmeurer): Optimize somewhat based on input type?
if (truncation.IsUsedAsWord32()) {
SetOutput(node, MachineRepresentation::kWord32);
if (lower()) lowering->DoJSToNumberTruncatesToWord32(node, this);
if (lower())
lowering->DoJSToNumberOrNumericTruncatesToWord32(node, this);
} else if (truncation.IsUsedAsFloat64()) {
SetOutput(node, MachineRepresentation::kFloat64);
if (lower()) lowering->DoJSToNumberTruncatesToFloat64(node, this);
if (lower())
lowering->DoJSToNumberOrNumericTruncatesToFloat64(node, this);
} else {
SetOutput(node, MachineRepresentation::kTagged);
}
......@@ -3181,9 +3184,10 @@ void SimplifiedLowering::LowerAllNodes() {
selector.Run(this);
}
void SimplifiedLowering::DoJSToNumberTruncatesToFloat64(
void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToFloat64(
Node* node, RepresentationSelector* selector) {
DCHECK_EQ(IrOpcode::kJSToNumber, node->opcode());
DCHECK(node->opcode() == IrOpcode::kJSToNumber ||
node->opcode() == IrOpcode::kJSToNumeric);
Node* value = node->InputAt(0);
Node* context = node->InputAt(1);
Node* frame_state = node->InputAt(2);
......@@ -3206,12 +3210,16 @@ void SimplifiedLowering::DoJSToNumberTruncatesToFloat64(
Node* efalse0 = effect;
Node* vfalse0;
{
vfalse0 = efalse0 = if_false0 =
graph()->NewNode(ToNumberOperator(), ToNumberCode(), value, context,
frame_state, efalse0, if_false0);
Operator const* op = node->opcode() == IrOpcode::kJSToNumber
? ToNumberOperator()
: ToNumericOperator();
Node* code = node->opcode() == IrOpcode::kJSToNumber ? ToNumberCode()
: ToNumericCode();
vfalse0 = efalse0 = if_false0 = graph()->NewNode(
op, code, value, context, frame_state, efalse0, if_false0);
// Update potential {IfException} uses of {node} to point to the above
// {ToNumber} stub call node instead.
// stub call node instead.
Node* on_exception = nullptr;
if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
NodeProperties::ReplaceControlInput(on_exception, vfalse0);
......@@ -3271,9 +3279,10 @@ void SimplifiedLowering::DoJSToNumberTruncatesToFloat64(
selector->DeferReplacement(node, value);
}
void SimplifiedLowering::DoJSToNumberTruncatesToWord32(
void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToWord32(
Node* node, RepresentationSelector* selector) {
DCHECK_EQ(IrOpcode::kJSToNumber, node->opcode());
DCHECK(node->opcode() == IrOpcode::kJSToNumber ||
node->opcode() == IrOpcode::kJSToNumeric);
Node* value = node->InputAt(0);
Node* context = node->InputAt(1);
Node* frame_state = node->InputAt(2);
......@@ -3293,12 +3302,16 @@ void SimplifiedLowering::DoJSToNumberTruncatesToWord32(
Node* efalse0 = effect;
Node* vfalse0;
{
vfalse0 = efalse0 = if_false0 =
graph()->NewNode(ToNumberOperator(), ToNumberCode(), value, context,
frame_state, efalse0, if_false0);
Operator const* op = node->opcode() == IrOpcode::kJSToNumber
? ToNumberOperator()
: ToNumericOperator();
Node* code = node->opcode() == IrOpcode::kJSToNumber ? ToNumberCode()
: ToNumericCode();
vfalse0 = efalse0 = if_false0 = graph()->NewNode(
op, code, value, context, frame_state, efalse0, if_false0);
// Update potential {IfException} uses of {node} to point to the above
// {ToNumber} stub call node instead.
// stub call node instead.
Node* on_exception = nullptr;
if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
NodeProperties::ReplaceControlInput(on_exception, vfalse0);
......@@ -3798,6 +3811,14 @@ Node* SimplifiedLowering::ToNumberCode() {
return to_number_code_.get();
}
Node* SimplifiedLowering::ToNumericCode() {
if (!to_numeric_code_.is_set()) {
Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumeric);
to_number_code_.set(jsgraph()->HeapConstant(callable.code()));
}
return to_numeric_code_.get();
}
Operator const* SimplifiedLowering::ToNumberOperator() {
if (!to_number_operator_.is_set()) {
Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumber);
......@@ -3810,6 +3831,18 @@ Operator const* SimplifiedLowering::ToNumberOperator() {
return to_number_operator_.get();
}
Operator const* SimplifiedLowering::ToNumericOperator() {
if (!to_numeric_operator_.is_set()) {
Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumeric);
CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), callable.descriptor(), 0, flags,
Operator::kNoProperties);
to_numeric_operator_.set(common()->Call(desc));
}
return to_numeric_operator_.get();
}
#undef TRACE
} // namespace compiler
......
......@@ -30,10 +30,10 @@ class SimplifiedLowering final {
void DoMax(Node* node, Operator const* op, MachineRepresentation rep);
void DoMin(Node* node, Operator const* op, MachineRepresentation rep);
void DoJSToNumberTruncatesToFloat64(Node* node,
RepresentationSelector* selector);
void DoJSToNumberTruncatesToWord32(Node* node,
RepresentationSelector* selector);
void DoJSToNumberOrNumericTruncatesToFloat64(
Node* node, RepresentationSelector* selector);
void DoJSToNumberOrNumericTruncatesToWord32(Node* node,
RepresentationSelector* selector);
void DoShift(Node* node, Operator const* op, Type* rhs_type);
void DoIntegral32ToBit(Node* node);
void DoOrderedNumberToBit(Node* node);
......@@ -48,7 +48,9 @@ class SimplifiedLowering final {
Zone* const zone_;
TypeCache const& type_cache_;
SetOncePointer<Node> to_number_code_;
SetOncePointer<Node> to_numeric_code_;
SetOncePointer<Operator const> to_number_operator_;
SetOncePointer<Operator const> to_numeric_operator_;
// TODO(danno): SimplifiedLowering shouldn't know anything about the source
// positions table, but must for now since there currently is no other way to
......@@ -67,7 +69,9 @@ class SimplifiedLowering final {
Node* Uint32Mod(Node* const node);
Node* ToNumberCode();
Node* ToNumericCode();
Operator const* ToNumberOperator();
Operator const* ToNumericOperator();
friend class RepresentationSelector;
......
......@@ -270,6 +270,7 @@ class Typer::Visitor : public Reducer {
static Type* ToLength(Type*, Typer*);
static Type* ToName(Type*, Typer*);
static Type* ToNumber(Type*, Typer*);
static Type* ToNumeric(Type*, Typer*);
static Type* ToObject(Type*, Typer*);
static Type* ToString(Type*, Typer*);
#define DECLARE_METHOD(Name) \
......@@ -492,6 +493,10 @@ Type* Typer::Visitor::ToNumber(Type* type, Typer* t) {
return t->operation_typer_.ToNumber(type);
}
// static
Type* Typer::Visitor::ToNumeric(Type* type, Typer* t) {
return t->operation_typer_.ToNumeric(type);
}
// static
Type* Typer::Visitor::ToObject(Type* type, Typer* t) {
......@@ -1095,6 +1100,10 @@ Type* Typer::Visitor::TypeJSToNumber(Node* node) {
return TypeUnaryOp(node, ToNumber);
}
Type* Typer::Visitor::TypeJSToNumeric(Node* node) {
return TypeUnaryOp(node, ToNumeric);
}
Type* Typer::Visitor::TypeJSToObject(Node* node) {
return TypeUnaryOp(node, ToObject);
}
......
......@@ -631,6 +631,10 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
// Type is Number.
CheckTypeIs(node, Type::Number());
break;
case IrOpcode::kJSToNumeric:
// Type is Numeric.
CheckTypeIs(node, Type::Numeric());
break;
case IrOpcode::kJSToString:
// Type is String.
CheckTypeIs(node, Type::String());
......
......@@ -3719,7 +3719,7 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
old_value = register_allocator()->NewRegister();
// Convert old value into a number before saving it.
// TODO(ignition): Think about adding proper PostInc/PostDec bytecodes
// instead of this ToNumber + Inc/Dec dance.
// instead of this ToNumeric + Inc/Dec dance.
builder()
->ToNumeric(feedback_index(count_slot))
.StoreAccumulatorInRegister(old_value);
......
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