Commit a81d19d5 authored by jarin's avatar jarin Committed by Commit bot

[turbofan] Handle impossible types (Type::None()) in the backend.

BUG=chromium:630611

Review-Url: https://codereview.chromium.org/2177483002
Cr-Commit-Position: refs/heads/master@{#37994}
parent 7ede61ed
......@@ -266,7 +266,9 @@ namespace internal {
V(kWrongArgumentCountForInvokeIntrinsic, \
"Wrong number of arguments for intrinsic") \
V(kShouldNotDirectlyEnterOsrFunction, \
"Should not directly enter OSR-compiled function")
"Should not directly enter OSR-compiled function") \
V(kConversionFromImpossibleValue, \
"Reached conversion from value with empty type (i.e., impossible type)")
#define ERROR_MESSAGES_CONSTANTS(C, T) C,
enum BailoutReason {
......
......@@ -696,6 +696,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kArchDebugBreak:
__ stop("kArchDebugBreak");
break;
case kArchImpossible:
__ Abort(kConversionFromImpossibleValue);
break;
case kArchComment: {
Address comment_string = i.InputExternalReference(0).address();
__ RecordComment(reinterpret_cast<const char*>(comment_string));
......
......@@ -766,6 +766,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kArchDebugBreak:
__ Debug("kArchDebugBreak", 0, BREAK);
break;
case kArchImpossible:
__ Abort(kConversionFromImpossibleValue);
break;
case kArchComment: {
Address comment_string = i.InputExternalReference(0).address();
__ RecordComment(reinterpret_cast<const char*>(comment_string));
......
......@@ -865,7 +865,11 @@ void CodeGenerator::AddTranslationForOperand(Translation* translation,
switch (constant.type()) {
case Constant::kInt32:
DCHECK(type == MachineType::Int32() || type == MachineType::Uint32() ||
type.representation() == MachineRepresentation::kBit);
type.representation() == MachineRepresentation::kBit ||
type.representation() == MachineRepresentation::kNone);
DCHECK(type.representation() != MachineRepresentation::kNone ||
constant.ToInt32() == FrameStateDescriptor::kImpossibleValue);
constant_object =
isolate()->factory()->NewNumberFromInt(constant.ToInt32());
break;
......
......@@ -621,6 +621,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kArchDebugBreak:
__ int3();
break;
case kArchImpossible:
__ Abort(kConversionFromImpossibleValue);
break;
case kArchNop:
case kArchThrowTerminator:
// don't emit code for nops.
......
......@@ -57,6 +57,7 @@ enum class RecordWriteMode { kValueIsMap, kValueIsPointer, kValueIsAny };
V(ArchTableSwitch) \
V(ArchNop) \
V(ArchDebugBreak) \
V(ArchImpossible) \
V(ArchComment) \
V(ArchThrowTerminator) \
V(ArchDeoptimize) \
......
......@@ -223,6 +223,7 @@ int InstructionScheduler::GetInstructionFlags(const Instruction* instr) const {
case kArchTruncateDoubleToI:
case kArchStackSlot:
case kArchDebugBreak:
case kArchImpossible:
case kArchComment:
case kIeee754Float64Acos:
case kIeee754Float64Acosh:
......
......@@ -62,9 +62,13 @@ class OperandGenerator {
}
InstructionOperand DefineAsConstant(Node* node) {
return DefineAsConstant(node, ToConstant(node));
}
InstructionOperand DefineAsConstant(Node* node, Constant constant) {
selector()->MarkAsDefined(node);
int virtual_register = GetVReg(node);
sequence()->AddConstant(virtual_register, ToConstant(node));
sequence()->AddConstant(virtual_register, constant);
return ConstantOperand(virtual_register);
}
......
......@@ -344,9 +344,9 @@ namespace {
enum class FrameStateInputKind { kAny, kStackSlot };
InstructionOperand OperandForDeopt(OperandGenerator* g, Node* input,
FrameStateInputKind kind) {
FrameStateInputKind kind,
MachineRepresentation rep) {
switch (input->opcode()) {
case IrOpcode::kInt32Constant:
case IrOpcode::kNumberConstant:
......@@ -358,11 +358,15 @@ InstructionOperand OperandForDeopt(OperandGenerator* g, Node* input,
UNREACHABLE();
break;
default:
switch (kind) {
case FrameStateInputKind::kStackSlot:
return g->UseUniqueSlot(input);
case FrameStateInputKind::kAny:
return g->UseAny(input);
if (rep == MachineRepresentation::kNone) {
return g->TempImmediate(FrameStateDescriptor::kImpossibleValue);
} else {
switch (kind) {
case FrameStateInputKind::kStackSlot:
return g->UseUniqueSlot(input);
case FrameStateInputKind::kAny:
return g->UseAny(input);
}
}
}
UNREACHABLE();
......@@ -428,7 +432,7 @@ size_t AddOperandToStateValueDescriptor(StateValueDescriptor* descriptor,
break;
}
default: {
inputs->push_back(OperandForDeopt(g, input, kind));
inputs->push_back(OperandForDeopt(g, input, kind, type.representation()));
descriptor->fields().push_back(StateValueDescriptor::Plain(zone, type));
return 1;
}
......@@ -886,6 +890,7 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsReference(node), VisitOsrValue(node);
case IrOpcode::kPhi: {
MachineRepresentation rep = PhiRepresentationOf(node->op());
if (rep == MachineRepresentation::kNone) return;
MarkAsRepresentation(rep, node);
return VisitPhi(node);
}
......@@ -1049,6 +1054,19 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsWord32(node), VisitChangeFloat64ToInt32(node);
case IrOpcode::kChangeFloat64ToUint32:
return MarkAsWord32(node), VisitChangeFloat64ToUint32(node);
case IrOpcode::kImpossibleToWord32:
return MarkAsWord32(node), VisitImpossibleToWord32(node);
case IrOpcode::kImpossibleToWord64:
return MarkAsWord64(node), VisitImpossibleToWord64(node);
case IrOpcode::kImpossibleToFloat32:
return MarkAsFloat32(node), VisitImpossibleToFloat32(node);
case IrOpcode::kImpossibleToFloat64:
return MarkAsFloat64(node), VisitImpossibleToFloat64(node);
case IrOpcode::kImpossibleToTagged:
MarkAsRepresentation(MachineType::PointerRepresentation(), node);
return VisitImpossibleToTagged(node);
case IrOpcode::kImpossibleToBit:
return MarkAsWord32(node), VisitImpossibleToBit(node);
case IrOpcode::kFloat64SilenceNaN:
MarkAsFloat64(node);
if (CanProduceSignalingNaN(node->InputAt(0))) {
......@@ -1282,13 +1300,47 @@ void InstructionSelector::VisitNode(Node* node) {
}
}
void InstructionSelector::VisitImpossibleToWord32(Node* node) {
OperandGenerator g(this);
Emit(kArchImpossible, g.DefineAsConstant(node, Constant(0)));
}
void InstructionSelector::VisitImpossibleToWord64(Node* node) {
OperandGenerator g(this);
Emit(kArchImpossible,
g.DefineAsConstant(node, Constant(static_cast<int64_t>(0))));
}
void InstructionSelector::VisitImpossibleToFloat32(Node* node) {
OperandGenerator g(this);
Emit(kArchImpossible, g.DefineAsConstant(node, Constant(0.0f)));
}
void InstructionSelector::VisitImpossibleToFloat64(Node* node) {
OperandGenerator g(this);
Emit(kArchImpossible, g.DefineAsConstant(node, Constant(0.0)));
}
void InstructionSelector::VisitImpossibleToBit(Node* node) {
OperandGenerator g(this);
Emit(kArchImpossible, g.DefineAsConstant(node, Constant(0)));
}
void InstructionSelector::VisitImpossibleToTagged(Node* node) {
OperandGenerator g(this);
#if V8_TARGET_ARCH_64_BIT
Emit(kArchImpossible,
g.DefineAsConstant(node, Constant(static_cast<int64_t>(0))));
#else // V8_TARGET_ARCH_64_BIT
Emit(kArchImpossible, g.DefineAsConstant(node, Constant(0)));
#endif // V8_TARGET_ARCH_64_BIT
}
void InstructionSelector::VisitLoadStackPointer(Node* node) {
OperandGenerator g(this);
Emit(kArchStackPointer, g.DefineAsRegister(node));
}
void InstructionSelector::VisitLoadFramePointer(Node* node) {
OperandGenerator g(this);
Emit(kArchFramePointer, g.DefineAsRegister(node));
......
......@@ -1149,6 +1149,8 @@ class FrameStateDescriptor : public ZoneObject {
}
StateValueDescriptor* GetStateValueDescriptor() { return &values_; }
static const int kImpossibleValue = 0xdead;
private:
FrameStateType type_;
BailoutId bailout_id_;
......
......@@ -145,6 +145,12 @@ MachineRepresentation AtomicStoreRepresentationOf(Operator const* op) {
V(ChangeInt32ToInt64, Operator::kNoProperties, 1, 0, 1) \
V(ChangeUint32ToFloat64, Operator::kNoProperties, 1, 0, 1) \
V(ChangeUint32ToUint64, Operator::kNoProperties, 1, 0, 1) \
V(ImpossibleToWord32, Operator::kNoProperties, 1, 0, 1) \
V(ImpossibleToWord64, Operator::kNoProperties, 1, 0, 1) \
V(ImpossibleToFloat32, Operator::kNoProperties, 1, 0, 1) \
V(ImpossibleToFloat64, Operator::kNoProperties, 1, 0, 1) \
V(ImpossibleToTagged, Operator::kNoProperties, 1, 0, 1) \
V(ImpossibleToBit, Operator::kNoProperties, 1, 0, 1) \
V(TruncateFloat64ToFloat32, Operator::kNoProperties, 1, 0, 1) \
V(TruncateInt64ToInt32, Operator::kNoProperties, 1, 0, 1) \
V(BitcastFloat32ToInt32, Operator::kNoProperties, 1, 0, 1) \
......
......@@ -305,6 +305,16 @@ class MachineOperatorBuilder final : public ZoneObject {
const Operator* ChangeUint32ToFloat64();
const Operator* ChangeUint32ToUint64();
// These are changes from impossible values (for example a smi-checked
// string). They can safely emit an abort instruction, which should
// never be reached.
const Operator* ImpossibleToWord32();
const Operator* ImpossibleToWord64();
const Operator* ImpossibleToFloat32();
const Operator* ImpossibleToFloat64();
const Operator* ImpossibleToTagged();
const Operator* ImpossibleToBit();
// These operators truncate or round numbers, both changing the representation
// of the number and mapping multiple input values onto the same output value.
const Operator* TruncateFloat64ToFloat32();
......
......@@ -693,6 +693,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kArchDebugBreak:
__ stop("kArchDebugBreak");
break;
case kArchImpossible:
__ Abort(kConversionFromImpossibleValue);
break;
case kArchComment: {
Address comment_string = i.InputExternalReference(0).address();
__ RecordComment(reinterpret_cast<const char*>(comment_string));
......
......@@ -702,6 +702,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kArchDebugBreak:
__ stop("kArchDebugBreak");
break;
case kArchImpossible:
__ Abort(kConversionFromImpossibleValue);
break;
case kArchComment: {
Address comment_string = i.InputExternalReference(0).address();
__ RecordComment(reinterpret_cast<const char*>(comment_string));
......
......@@ -378,6 +378,12 @@
V(ChangeInt32ToInt64) \
V(ChangeUint32ToFloat64) \
V(ChangeUint32ToUint64) \
V(ImpossibleToBit) \
V(ImpossibleToWord32) \
V(ImpossibleToWord64) \
V(ImpossibleToFloat32) \
V(ImpossibleToFloat64) \
V(ImpossibleToTagged) \
V(TruncateFloat64ToFloat32) \
V(TruncateInt64ToInt32) \
V(RoundFloat64ToInt32) \
......
......@@ -1077,6 +1077,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kArchDebugBreak:
__ stop("kArchDebugBreak");
break;
case kArchImpossible:
__ Abort(kConversionFromImpossibleValue);
break;
case kArchNop:
case kArchThrowTerminator:
// don't emit code for nops.
......
......@@ -117,8 +117,10 @@ bool IsWord(MachineRepresentation rep) {
Node* RepresentationChanger::GetRepresentationFor(
Node* node, MachineRepresentation output_rep, Type* output_type,
Node* use_node, UseInfo use_info) {
if (output_rep == MachineRepresentation::kNone) {
// The output representation should be set.
if (output_rep == MachineRepresentation::kNone &&
output_type->IsInhabited()) {
// The output representation should be set if the type is inhabited (i.e.,
// if the value is possible).
return TypeError(node, output_rep, output_type, use_info.representation());
}
......@@ -200,7 +202,11 @@ Node* RepresentationChanger::GetTaggedRepresentationFor(
}
// Select the correct X -> Tagged operator.
const Operator* op;
if (output_rep == MachineRepresentation::kBit) {
if (output_rep == MachineRepresentation::kNone) {
// We should only asisgn this representation if the type is empty.
CHECK(!output_type->IsInhabited());
op = machine()->ImpossibleToTagged();
} else if (output_rep == MachineRepresentation::kBit) {
if (output_type->Is(Type::Boolean())) {
op = simplified()->ChangeBitToTagged();
} else {
......@@ -271,7 +277,11 @@ Node* RepresentationChanger::GetFloat32RepresentationFor(
}
// Select the correct X -> Float32 operator.
const Operator* op = nullptr;
if (IsWord(output_rep)) {
if (output_rep == MachineRepresentation::kNone) {
// We should only use kNone representation if the type is empty.
CHECK(!output_type->IsInhabited());
op = machine()->ImpossibleToFloat32();
} else if (IsWord(output_rep)) {
if (output_type->Is(Type::Signed32())) {
// int32 -> float64 -> float32
op = machine()->ChangeInt32ToFloat64();
......@@ -336,7 +346,11 @@ Node* RepresentationChanger::GetFloat64RepresentationFor(
}
// Select the correct X -> Float64 operator.
const Operator* op = nullptr;
if (IsWord(output_rep)) {
if (output_rep == MachineRepresentation::kNone) {
// We should only use kNone representation if the type is empty.
CHECK(!output_type->IsInhabited());
op = machine()->ImpossibleToFloat64();
} else if (IsWord(output_rep)) {
if (output_type->Is(Type::Signed32())) {
op = machine()->ChangeInt32ToFloat64();
} else if (output_type->Is(Type::Unsigned32()) ||
......@@ -408,7 +422,11 @@ Node* RepresentationChanger::GetWord32RepresentationFor(
// Select the correct X -> Word32 operator.
const Operator* op = nullptr;
if (output_rep == MachineRepresentation::kBit) {
if (output_rep == MachineRepresentation::kNone) {
// We should only use kNone representation if the type is empty.
CHECK(!output_type->IsInhabited());
op = machine()->ImpossibleToWord32();
} else if (output_rep == MachineRepresentation::kBit) {
return node; // Sloppy comparison -> word32
} else if (output_rep == MachineRepresentation::kFloat64) {
if (output_type->Is(Type::Unsigned32())) {
......@@ -497,7 +515,11 @@ Node* RepresentationChanger::GetBitRepresentationFor(
}
// Select the correct X -> Bit operator.
const Operator* op;
if (output_rep == MachineRepresentation::kTagged) {
if (output_rep == MachineRepresentation::kNone) {
// We should only use kNone representation if the type is empty.
CHECK(!output_type->IsInhabited());
op = machine()->ImpossibleToBit();
} else if (output_rep == MachineRepresentation::kTagged) {
op = simplified()->ChangeTaggedToBit();
} else {
return TypeError(node, output_rep, output_type,
......@@ -508,7 +530,11 @@ Node* RepresentationChanger::GetBitRepresentationFor(
Node* RepresentationChanger::GetWord64RepresentationFor(
Node* node, MachineRepresentation output_rep, Type* output_type) {
if (output_rep == MachineRepresentation::kBit) {
if (output_rep == MachineRepresentation::kNone) {
// We should only use kNone representation if the type is empty.
CHECK(!output_type->IsInhabited());
return jsgraph()->graph()->NewNode(machine()->ImpossibleToFloat64(), node);
} else if (output_rep == MachineRepresentation::kBit) {
return node; // Sloppy comparison -> word64
}
// Can't really convert Word64 to anything else. Purported to be internal.
......@@ -532,7 +558,11 @@ Node* RepresentationChanger::GetCheckedWord32RepresentationFor(
// Select the correct X -> Word32 operator.
const Operator* op = nullptr;
if (output_rep == MachineRepresentation::kWord32) {
if (output_rep == MachineRepresentation::kNone) {
// We should only use kNone representation if the type is empty.
CHECK(!output_type->IsInhabited());
op = machine()->ImpossibleToWord32();
} else if (output_rep == MachineRepresentation::kWord32) {
if (output_type->Is(Type::Unsigned32())) {
op = simplified()->CheckedUint32ToInt32();
}
......
......@@ -913,6 +913,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kArchDebugBreak:
__ stop("kArchDebugBreak");
break;
case kArchImpossible:
__ Abort(kConversionFromImpossibleValue);
break;
case kArchNop:
case kArchThrowTerminator:
// don't emit code for nops.
......
......@@ -568,7 +568,8 @@ class RepresentationSelector {
NodeInfo* info = GetInfo(node);
queue_.pop();
info->set_visited();
TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
TRACE(" visit #%d: %s (trunc: %s)\n", node->id(), node->op()->mnemonic(),
info->truncation().description());
VisitNode(node, info->truncation(), nullptr);
TRACE(" ==> output ");
PrintOutputInfo(info);
......@@ -635,12 +636,12 @@ class RepresentationSelector {
info->set_queued();
nodes_.push_back(node);
queue_.push(node);
TRACE(" initial: ");
TRACE(" initial #%i: ", node->id());
info->AddUse(use_info);
PrintTruncation(info->truncation());
return;
}
TRACE(" queue?: ");
TRACE(" queue #%i?: ", node->id());
PrintTruncation(info->truncation());
if (info->AddUse(use_info)) {
// New usage information for the node is available.
......
......@@ -2230,16 +2230,35 @@ Type* Typer::Visitor::TypeChangeInt32ToInt64(Node* node) {
return Type::Internal();
}
Type* Typer::Visitor::TypeChangeUint32ToFloat64(Node* node) {
return Type::Intersect(Type::Unsigned32(), Type::UntaggedFloat64(), zone());
}
Type* Typer::Visitor::TypeChangeUint32ToUint64(Node* node) {
return Type::Internal();
}
Type* Typer::Visitor::TypeImpossibleToWord32(Node* node) {
return Type::None();
}
Type* Typer::Visitor::TypeImpossibleToWord64(Node* node) {
return Type::None();
}
Type* Typer::Visitor::TypeImpossibleToFloat32(Node* node) {
return Type::None();
}
Type* Typer::Visitor::TypeImpossibleToFloat64(Node* node) {
return Type::None();
}
Type* Typer::Visitor::TypeImpossibleToTagged(Node* node) {
return Type::None();
}
Type* Typer::Visitor::TypeImpossibleToBit(Node* node) { return Type::None(); }
Type* Typer::Visitor::TypeTruncateFloat64ToFloat32(Node* node) {
return Type::Intersect(Type::Number(), Type::UntaggedFloat32(), zone());
......@@ -2250,7 +2269,6 @@ Type* Typer::Visitor::TypeTruncateFloat64ToWord32(Node* node) {
zone());
}
Type* Typer::Visitor::TypeTruncateInt64ToInt32(Node* node) {
return Type::Intersect(Type::Signed32(), Type::UntaggedIntegral32(), zone());
}
......
......@@ -948,6 +948,13 @@ void Verifier::Visitor::Check(Node* node) {
// CheckUpperIs(node, to));
break;
}
case IrOpcode::kImpossibleToWord32:
case IrOpcode::kImpossibleToWord64:
case IrOpcode::kImpossibleToFloat32:
case IrOpcode::kImpossibleToFloat64:
case IrOpcode::kImpossibleToTagged:
case IrOpcode::kImpossibleToBit:
break;
case IrOpcode::kCheckBounds:
CheckValueInputIs(node, 0, Type::Any());
......
......@@ -851,6 +851,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kArchDebugBreak:
__ int3();
break;
case kArchImpossible:
__ Abort(kConversionFromImpossibleValue);
break;
case kArchNop:
case kArchThrowTerminator:
// don't emit code for nops.
......
......@@ -704,6 +704,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kArchDebugBreak:
__ int3();
break;
case kArchImpossible:
__ Abort(kConversionFromImpossibleValue);
break;
case kArchNop:
case kArchThrowTerminator:
// don't emit code for nops.
......
// Copyright 2016 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.
var global = 1;
global = 2;
function f() {
var o = { a : 1 };
global = "a";
for (var i = global; i < 2; i++) {
delete o[i];
}
}
f();
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