diff --git a/src/compiler/js-create-lowering.cc b/src/compiler/js-create-lowering.cc index 80105aebb42..f3ceb2b0c08 100644 --- a/src/compiler/js-create-lowering.cc +++ b/src/compiler/js-create-lowering.cc @@ -1097,7 +1097,17 @@ Node* JSCreateLowering::AllocateElements(Node* effect, Node* control, ElementAccess access = IsFastDoubleElementsKind(elements_kind) ? AccessBuilder::ForFixedDoubleArrayElement() : AccessBuilder::ForFixedArrayElement(); - Node* value = jsgraph()->TheHoleConstant(); + Node* value; + if (IsFastDoubleElementsKind(elements_kind)) { + // Load the hole NaN pattern from the canonical location. + value = effect = graph()->NewNode( + simplified()->LoadField(AccessBuilder::ForExternalDoubleValue()), + jsgraph()->ExternalConstant( + ExternalReference::address_of_the_hole_nan()), + effect, control); + } else { + value = jsgraph()->TheHoleConstant(); + } // Actually allocate the backing store. AllocationBuilder a(jsgraph(), effect, control); @@ -1245,9 +1255,18 @@ Node* JSCreateLowering::AllocateFastLiteralElements( if (elements_map->instance_type() == FIXED_DOUBLE_ARRAY_TYPE) { Handle elements = Handle::cast(boilerplate_elements); + Node* the_hole_value = nullptr; for (int i = 0; i < elements_length; ++i) { if (elements->is_the_hole(i)) { - elements_values[i] = jsgraph()->TheHoleConstant(); + if (the_hole_value == nullptr) { + // Load the hole NaN pattern from the canonical location. + the_hole_value = effect = graph()->NewNode( + simplified()->LoadField(AccessBuilder::ForExternalDoubleValue()), + jsgraph()->ExternalConstant( + ExternalReference::address_of_the_hole_nan()), + effect, control); + } + elements_values[i] = the_hole_value; } else { elements_values[i] = jsgraph()->Constant(elements->get_scalar(i)); } diff --git a/src/compiler/js-native-context-specialization.cc b/src/compiler/js-native-context-specialization.cc index 6272e11ede2..c32ee269a08 100644 --- a/src/compiler/js-native-context-specialization.cc +++ b/src/compiler/js-native-context-specialization.cc @@ -1990,12 +1990,10 @@ JSNativeContextSpecialization::BuildElementAccess( if (access_mode == AccessMode::kLoad) { // Compute the real element access type, which includes the hole in case // of holey backing stores. - if (IsHoleyElementsKind(elements_kind)) { - element_access.type = - Type::Union(element_type, Type::Hole(), graph()->zone()); - } if (elements_kind == FAST_HOLEY_ELEMENTS || elements_kind == FAST_HOLEY_SMI_ELEMENTS) { + element_access.type = + Type::Union(element_type, Type::Hole(), graph()->zone()); element_access.machine_type = MachineType::AnyTagged(); } // Perform the actual backing store access. diff --git a/src/compiler/operation-typer.cc b/src/compiler/operation-typer.cc index ae7813956a0..dfd4c4b6047 100644 --- a/src/compiler/operation-typer.cc +++ b/src/compiler/operation-typer.cc @@ -1009,19 +1009,6 @@ Type* OperationTyper::FalsifyUndefined(ComparisonOutcome outcome) { return singleton_true(); } -Type* OperationTyper::CheckFloat64Hole(Type* type) { - if (type->Maybe(Type::Hole())) { - // Turn "the hole" into undefined. - type = Type::Intersect(type, Type::Number(), zone()); - type = Type::Union(type, Type::Undefined(), zone()); - } - return type; -} - -Type* OperationTyper::CheckNumber(Type* type) { - return Type::Intersect(type, Type::Number(), zone()); -} - Type* OperationTyper::TypeTypeGuard(const Operator* sigma_op, Type* input) { return Type::Intersect(input, TypeGuardTypeOf(sigma_op), zone()); } diff --git a/src/compiler/operation-typer.h b/src/compiler/operation-typer.h index a9d0174664b..09f063c14e6 100644 --- a/src/compiler/operation-typer.h +++ b/src/compiler/operation-typer.h @@ -47,10 +47,6 @@ class OperationTyper { SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_METHOD) #undef DECLARE_METHOD - // Check operators. - Type* CheckFloat64Hole(Type* type); - Type* CheckNumber(Type* type); - Type* TypeTypeGuard(const Operator* sigma_op, Type* input); enum ComparisonOutcomeFlags { diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc index 82c4ef18fe3..4acc77f22f3 100644 --- a/src/compiler/simplified-lowering.cc +++ b/src/compiler/simplified-lowering.cc @@ -458,18 +458,6 @@ class RepresentationSelector { new_type = op_typer_.ToNumber(FeedbackTypeOf(node->InputAt(0))); break; - case IrOpcode::kCheckFloat64Hole: - new_type = Type::Intersect( - op_typer_.CheckFloat64Hole(FeedbackTypeOf(node->InputAt(0))), - info->restriction_type(), graph_zone()); - break; - - case IrOpcode::kCheckNumber: - new_type = Type::Intersect( - op_typer_.CheckNumber(FeedbackTypeOf(node->InputAt(0))), - info->restriction_type(), graph_zone()); - break; - case IrOpcode::kPhi: { new_type = TypePhi(node); if (type != nullptr) { @@ -821,15 +809,6 @@ class RepresentationSelector { if (lower()) Kill(node); } - // Helper for no-op node. - void VisitNoop(Node* node, Truncation truncation) { - if (truncation.IsUnused()) return VisitUnused(node); - MachineRepresentation representation = - GetOutputInfoForPhi(node, TypeOf(node), truncation); - VisitUnop(node, UseInfo(representation, truncation), representation); - if (lower()) DeferReplacement(node, node->InputAt(0)); - } - // Helper for binops of the R x L -> O variety. void VisitBinop(Node* node, UseInfo left_use, UseInfo right_use, MachineRepresentation output, @@ -2336,9 +2315,19 @@ class RepresentationSelector { return; } case IrOpcode::kCheckNumber: { - Type* const input_type = TypeOf(node->InputAt(0)); - if (input_type->Is(Type::Number())) { - VisitNoop(node, truncation); + if (InputIs(node, Type::Number())) { + if (truncation.IsUsedAsWord32()) { + VisitUnop(node, UseInfo::TruncatingWord32(), + MachineRepresentation::kWord32); + } else { + // TODO(jarin,bmeurer): We need to go to Tagged here, because + // otherwise we cannot distinguish the hole NaN (which might need to + // be treated as undefined). We should have a dedicated Type for + // that at some point, and maybe even a dedicated truncation. + VisitUnop(node, UseInfo::AnyTagged(), + MachineRepresentation::kTagged); + } + if (lower()) DeferReplacement(node, node->InputAt(0)); } else { VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged); } @@ -2592,32 +2581,13 @@ class RepresentationSelector { return; } case IrOpcode::kCheckFloat64Hole: { - Type* const input_type = TypeOf(node->InputAt(0)); - if (input_type->Is(Type::Number())) { - VisitNoop(node, truncation); - } else { - CheckFloat64HoleMode mode = CheckFloat64HoleModeOf(node->op()); - switch (mode) { - case CheckFloat64HoleMode::kAllowReturnHole: - if (truncation.IsUnused()) return VisitUnused(node); - if (truncation.IsUsedAsFloat64()) { - VisitUnop(node, UseInfo::TruncatingFloat64(), - MachineRepresentation::kFloat64); - if (lower()) DeferReplacement(node, node->InputAt(0)); - } else { - VisitUnop( - node, - UseInfo(MachineRepresentation::kFloat64, Truncation::Any()), - MachineRepresentation::kFloat64, Type::Number()); - } - break; - case CheckFloat64HoleMode::kNeverReturnHole: - VisitUnop( - node, - UseInfo(MachineRepresentation::kFloat64, Truncation::Any()), - MachineRepresentation::kFloat64, Type::Number()); - break; - } + CheckFloat64HoleMode mode = CheckFloat64HoleModeOf(node->op()); + ProcessInput(node, 0, UseInfo::TruncatingFloat64()); + ProcessRemainingInputs(node, 1); + SetOutput(node, MachineRepresentation::kFloat64); + if (truncation.IsUsedAsFloat64() && + mode == CheckFloat64HoleMode::kAllowReturnHole) { + if (lower()) DeferReplacement(node, node->InputAt(0)); } return; } diff --git a/src/compiler/typed-optimization.cc b/src/compiler/typed-optimization.cc index 7ef012658e5..e130a10e4eb 100644 --- a/src/compiler/typed-optimization.cc +++ b/src/compiler/typed-optimization.cc @@ -78,8 +78,6 @@ Reduction TypedOptimization::Reduce(Node* node) { return ReduceCheckHeapObject(node); case IrOpcode::kCheckMaps: return ReduceCheckMaps(node); - case IrOpcode::kCheckNumber: - return ReduceCheckNumber(node); case IrOpcode::kCheckString: return ReduceCheckString(node); case IrOpcode::kLoadField: @@ -152,16 +150,6 @@ Reduction TypedOptimization::ReduceCheckMaps(Node* node) { return NoChange(); } -Reduction TypedOptimization::ReduceCheckNumber(Node* node) { - Node* const input = NodeProperties::GetValueInput(node, 0); - Type* const input_type = NodeProperties::GetType(input); - if (input_type->Is(Type::Number())) { - ReplaceWithValue(node, input); - return Replace(input); - } - return NoChange(); -} - Reduction TypedOptimization::ReduceCheckString(Node* node) { Node* const input = NodeProperties::GetValueInput(node, 0); Type* const input_type = NodeProperties::GetType(input); diff --git a/src/compiler/typed-optimization.h b/src/compiler/typed-optimization.h index 59cb401b8d9..93de680d4f0 100644 --- a/src/compiler/typed-optimization.h +++ b/src/compiler/typed-optimization.h @@ -44,7 +44,6 @@ class V8_EXPORT_PRIVATE TypedOptimization final private: Reduction ReduceCheckHeapObject(Node* node); Reduction ReduceCheckMaps(Node* node); - Reduction ReduceCheckNumber(Node* node); Reduction ReduceCheckString(Node* node); Reduction ReduceLoadField(Node* node); Reduction ReduceNumberFloor(Node* node); diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index 80d8abd3c7a..ed1a04aa3b4 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -1804,7 +1804,8 @@ Type* Typer::Visitor::TypeCheckMaps(Node* node) { } Type* Typer::Visitor::TypeCheckNumber(Node* node) { - return typer_->operation_typer_.CheckNumber(Operand(node, 0)); + Type* arg = Operand(node, 0); + return Type::Intersect(arg, Type::Number(), zone()); } Type* Typer::Visitor::TypeCheckReceiver(Node* node) { @@ -1823,7 +1824,8 @@ Type* Typer::Visitor::TypeCheckString(Node* node) { } Type* Typer::Visitor::TypeCheckFloat64Hole(Node* node) { - return typer_->operation_typer_.CheckFloat64Hole(Operand(node, 0)); + Type* type = Operand(node, 0); + return type; } Type* Typer::Visitor::TypeCheckTaggedHole(Node* node) { diff --git a/src/compiler/types.h b/src/compiler/types.h index eef4a341fd5..9e55a0bc88c 100644 --- a/src/compiler/types.h +++ b/src/compiler/types.h @@ -155,7 +155,6 @@ namespace compiler { V(NullOrNumber, kNull | kNumber) \ V(NullOrUndefined, kNull | kUndefined) \ V(Undetectable, kNullOrUndefined | kOtherUndetectable) \ - V(NumberOrHole, kNumber | kHole) \ V(NumberOrOddball, kNumber | kNullOrUndefined | kBoolean | \ kHole) \ V(NumberOrString, kNumber | kString) \ diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc index 48326a86426..7f63ceb803b 100644 --- a/src/compiler/verifier.cc +++ b/src/compiler/verifier.cc @@ -1163,8 +1163,8 @@ void Verifier::Visitor::Check(Node* node) { break; case IrOpcode::kCheckFloat64Hole: - CheckValueInputIs(node, 0, Type::NumberOrHole()); - CheckTypeIs(node, Type::NumberOrUndefined()); + CheckValueInputIs(node, 0, Type::Number()); + CheckTypeIs(node, Type::Number()); break; case IrOpcode::kCheckTaggedHole: CheckValueInputIs(node, 0, Type::Any()); diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc index 0e2e2167aa4..8dfe0e181c6 100644 --- a/src/deoptimizer.cc +++ b/src/deoptimizer.cc @@ -3019,6 +3019,10 @@ void TranslatedValue::MaterializeSimple() { } case kDouble: { + if (double_value().is_hole_nan()) { + value_ = isolate()->factory()->hole_nan_value(); + return; + } double scalar_value = double_value().get_scalar(); value_ = Handle(isolate()->factory()->NewNumber(scalar_value)); return; @@ -3903,10 +3907,10 @@ Handle TranslatedState::MaterializeCapturedObjectAt( Handle::cast(object); for (int i = 0; i < length; ++i) { Handle value = materializer.FieldAt(value_index); - if (value.is_identical_to(isolate_->factory()->the_hole_value())) { + CHECK(value->IsNumber()); + if (value.is_identical_to(isolate_->factory()->hole_nan_value())) { double_array->set_the_hole(isolate_, i); } else { - CHECK(value->IsNumber()); double_array->set(i, value->Number()); } } diff --git a/src/objects-inl.h b/src/objects-inl.h index 1f13ca67708..3aa26c56016 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -1970,10 +1970,6 @@ void Oddball::set_to_number_raw(double value) { WRITE_DOUBLE_FIELD(this, kToNumberRawOffset, value); } -void Oddball::set_to_number_raw_as_bits(uint64_t bits) { - WRITE_UINT64_FIELD(this, kToNumberRawOffset, bits); -} - ACCESSORS(Oddball, to_string, String, kToStringOffset) ACCESSORS(Oddball, to_number, Object, kToNumberOffset) ACCESSORS(Oddball, type_of, String, kTypeOfOffset) diff --git a/src/objects.cc b/src/objects.cc index 7902738fc4e..9f9a628062b 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -12909,12 +12909,7 @@ void Oddball::Initialize(Isolate* isolate, Handle oddball, isolate->factory()->InternalizeUtf8String(to_string); Handle internalized_type_of = isolate->factory()->InternalizeUtf8String(type_of); - if (to_number->IsHeapNumber()) { - oddball->set_to_number_raw_as_bits( - Handle::cast(to_number)->value_as_bits()); - } else { - oddball->set_to_number_raw(to_number->Number()); - } + oddball->set_to_number_raw(to_number->Number()); oddball->set_to_number(*to_number); oddball->set_to_string(*internalized_to_string); oddball->set_type_of(*internalized_type_of); diff --git a/src/objects.h b/src/objects.h index ccf60550cac..04d3d384d13 100644 --- a/src/objects.h +++ b/src/objects.h @@ -10087,7 +10087,6 @@ class Oddball: public HeapObject { // [to_number_raw]: Cached raw to_number computed at startup. inline double to_number_raw() const; inline void set_to_number_raw(double value); - inline void set_to_number_raw_as_bits(uint64_t bits); // [to_string]: Cached to_string computed at startup. DECL_ACCESSORS(to_string, String) diff --git a/test/mjsunit/regress/regress-crbug-709753.js b/test/mjsunit/regress/regress-crbug-709753.js deleted file mode 100644 index e4d4d4ed37f..00000000000 --- a/test/mjsunit/regress/regress-crbug-709753.js +++ /dev/null @@ -1,13 +0,0 @@ -// 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. - -// Flags: --allow-natives-syntax - -function foo(a, i) { a[i].x; } - -var a = [,0.1]; -foo(a, 1); -foo(a, 1); -%OptimizeFunctionOnNextCall(foo); -assertThrows(() => foo(a, 0), TypeError);