[turbofan] Check instruction input/output count limits in instruction selector.
BUG=chromium:625966 Review-Url: https://codereview.chromium.org/2390303002 Cr-Commit-Position: refs/heads/master@{#39970}
This commit is contained in:
parent
17cb51254c
commit
a974970cff
@ -41,11 +41,12 @@ InstructionSelector::InstructionSelector(
|
||||
virtual_register_rename_(zone),
|
||||
scheduler_(nullptr),
|
||||
enable_scheduling_(enable_scheduling),
|
||||
frame_(frame) {
|
||||
frame_(frame),
|
||||
instruction_selection_failed_(false) {
|
||||
instructions_.reserve(node_count);
|
||||
}
|
||||
|
||||
void InstructionSelector::SelectInstructions() {
|
||||
bool InstructionSelector::SelectInstructions() {
|
||||
// Mark the inputs of all phis in loop headers as used.
|
||||
BasicBlockVector* blocks = schedule()->rpo_order();
|
||||
for (auto const block : *blocks) {
|
||||
@ -64,6 +65,7 @@ void InstructionSelector::SelectInstructions() {
|
||||
// Visit each basic block in post order.
|
||||
for (auto i = blocks->rbegin(); i != blocks->rend(); ++i) {
|
||||
VisitBlock(*i);
|
||||
if (instruction_selection_failed()) return false;
|
||||
}
|
||||
|
||||
// Schedule the selected instructions.
|
||||
@ -90,6 +92,7 @@ void InstructionSelector::SelectInstructions() {
|
||||
#if DEBUG
|
||||
sequence()->ValidateSSA();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void InstructionSelector::StartBlock(RpoNumber rpo) {
|
||||
@ -208,6 +211,13 @@ Instruction* InstructionSelector::Emit(
|
||||
InstructionCode opcode, size_t output_count, InstructionOperand* outputs,
|
||||
size_t input_count, InstructionOperand* inputs, size_t temp_count,
|
||||
InstructionOperand* temps) {
|
||||
if (output_count >= Instruction::kMaxOutputCount ||
|
||||
input_count >= Instruction::kMaxInputCount ||
|
||||
temp_count >= Instruction::kMaxTempCount) {
|
||||
set_instruction_selection_failed();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Instruction* instr =
|
||||
Instruction::New(instruction_zone(), opcode, output_count, outputs,
|
||||
input_count, inputs, temp_count, temps);
|
||||
@ -767,7 +777,6 @@ void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitBlock(BasicBlock* block) {
|
||||
DCHECK(!current_block_);
|
||||
current_block_ = block;
|
||||
@ -804,6 +813,7 @@ void InstructionSelector::VisitBlock(BasicBlock* block) {
|
||||
// up".
|
||||
size_t current_node_end = instructions_.size();
|
||||
VisitNode(node);
|
||||
if (instruction_selection_failed()) return;
|
||||
std::reverse(instructions_.begin() + current_node_end, instructions_.end());
|
||||
if (instructions_.size() == current_node_end) continue;
|
||||
// Mark source position on first instruction emitted.
|
||||
@ -1843,9 +1853,11 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
|
||||
// Emit the call instruction.
|
||||
size_t const output_count = buffer.outputs.size();
|
||||
auto* outputs = output_count ? &buffer.outputs.front() : nullptr;
|
||||
Emit(opcode, output_count, outputs, buffer.instruction_args.size(),
|
||||
&buffer.instruction_args.front())
|
||||
->MarkAsCall();
|
||||
Instruction* call_instr =
|
||||
Emit(opcode, output_count, outputs, buffer.instruction_args.size(),
|
||||
&buffer.instruction_args.front());
|
||||
if (instruction_selection_failed()) return;
|
||||
call_instr->MarkAsCall();
|
||||
}
|
||||
|
||||
|
||||
@ -1951,9 +1963,11 @@ void InstructionSelector::VisitTailCall(Node* node) {
|
||||
// Emit the call instruction.
|
||||
size_t output_count = buffer.outputs.size();
|
||||
auto* outputs = &buffer.outputs.front();
|
||||
Emit(opcode, output_count, outputs, buffer.instruction_args.size(),
|
||||
&buffer.instruction_args.front())
|
||||
->MarkAsCall();
|
||||
Instruction* call_instr =
|
||||
Emit(opcode, output_count, outputs, buffer.instruction_args.size(),
|
||||
&buffer.instruction_args.front());
|
||||
if (instruction_selection_failed()) return;
|
||||
call_instr->MarkAsCall();
|
||||
Emit(kArchRet, 0, nullptr, output_count, outputs);
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ class InstructionSelector final {
|
||||
: kDisableScheduling);
|
||||
|
||||
// Visit code for the entire graph with the included schedule.
|
||||
void SelectInstructions();
|
||||
bool SelectInstructions();
|
||||
|
||||
void StartBlock(RpoNumber rpo);
|
||||
void EndBlock(RpoNumber rpo);
|
||||
@ -332,6 +332,11 @@ class InstructionSelector final {
|
||||
Zone* instruction_zone() const { return sequence()->zone(); }
|
||||
Zone* zone() const { return zone_; }
|
||||
|
||||
void set_instruction_selection_failed() {
|
||||
instruction_selection_failed_ = true;
|
||||
}
|
||||
bool instruction_selection_failed() { return instruction_selection_failed_; }
|
||||
|
||||
// ===========================================================================
|
||||
|
||||
Zone* const zone_;
|
||||
@ -351,6 +356,7 @@ class InstructionSelector final {
|
||||
InstructionScheduler* scheduler_;
|
||||
EnableScheduling enable_scheduling_;
|
||||
Frame* frame_;
|
||||
bool instruction_selection_failed_;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
|
@ -947,6 +947,14 @@ class Instruction final {
|
||||
void Print(const RegisterConfiguration* config) const;
|
||||
void Print() const;
|
||||
|
||||
typedef BitField<size_t, 0, 8> OutputCountField;
|
||||
typedef BitField<size_t, 8, 16> InputCountField;
|
||||
typedef BitField<size_t, 24, 6> TempCountField;
|
||||
|
||||
static const size_t kMaxOutputCount = OutputCountField::kMax;
|
||||
static const size_t kMaxInputCount = InputCountField::kMax;
|
||||
static const size_t kMaxTempCount = TempCountField::kMax;
|
||||
|
||||
private:
|
||||
explicit Instruction(InstructionCode opcode);
|
||||
|
||||
@ -955,9 +963,6 @@ class Instruction final {
|
||||
InstructionOperand* inputs, size_t temp_count,
|
||||
InstructionOperand* temps);
|
||||
|
||||
typedef BitField<size_t, 0, 8> OutputCountField;
|
||||
typedef BitField<size_t, 8, 16> InputCountField;
|
||||
typedef BitField<size_t, 24, 6> TempCountField;
|
||||
typedef BitField<bool, 30, 1> IsCallField;
|
||||
|
||||
InstructionCode opcode_;
|
||||
|
@ -1233,7 +1233,9 @@ struct InstructionSelectionPhase {
|
||||
data->info()->is_source_positions_enabled()
|
||||
? InstructionSelector::kAllSourcePositions
|
||||
: InstructionSelector::kCallSourcePositions);
|
||||
selector.SelectInstructions();
|
||||
if (!selector.SelectInstructions()) {
|
||||
data->set_compilation_failed();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -1754,6 +1756,11 @@ bool PipelineImpl::ScheduleAndSelectInstructions(Linkage* linkage) {
|
||||
data->InitializeFrameData(call_descriptor);
|
||||
// Select and schedule instructions covering the scheduled graph.
|
||||
Run<InstructionSelectionPhase>(linkage);
|
||||
if (data->compilation_failed()) {
|
||||
info()->AbortOptimization(kCodeGenerationFailed);
|
||||
data->EndPhaseKind();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FLAG_trace_turbo && !data->MayHaveUnverifiableGraph()) {
|
||||
AllowHandleDereference allow_deref;
|
||||
|
10
test/mjsunit/compiler/regress-625966.js
Normal file
10
test/mjsunit/compiler/regress-625966.js
Normal file
@ -0,0 +1,10 @@
|
||||
// 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.
|
||||
|
||||
"use strict";
|
||||
var s = "";
|
||||
for (var i = 0; i < 65535; i++) {
|
||||
s += ("var a" + i + ";");
|
||||
}
|
||||
eval(s);
|
Loading…
Reference in New Issue
Block a user