Commit 2778b460 authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

Reland "[turbofan] disable indirect jumps in Turbofan generated switches"

This is a reland of 957ac364.

To avoid a race condition TSAN found when accessing FLAG_turbo_disable_switch_jump_table
in the InstructionSelector, this now threads the flag through the CompilationInfo.

Original change's description:
> [turbofan] disable indirect jumps in Turbofan generated switches
>
> Bug:
> Change-Id: I326bf518f895e7c030376210e7797f3dd4a9ae1f
> Reviewed-on: https://chromium-review.googlesource.com/873643
> Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
> Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#50984}

Change-Id: I76c2804f140cc116e30881bfd05365a09240e605
Reviewed-on: https://chromium-review.googlesource.com/895643Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51014}
parent 1efdab82
...@@ -47,6 +47,7 @@ CompilationInfo::CompilationInfo(Zone* zone, Isolate* isolate, ...@@ -47,6 +47,7 @@ CompilationInfo::CompilationInfo(Zone* zone, Isolate* isolate,
if (FLAG_function_context_specialization) MarkAsFunctionContextSpecializing(); if (FLAG_function_context_specialization) MarkAsFunctionContextSpecializing();
if (FLAG_turbo_splitting) MarkAsSplittingEnabled(); if (FLAG_turbo_splitting) MarkAsSplittingEnabled();
if (!FLAG_turbo_disable_switch_jump_table) SetFlag(kSwitchJumpTableEnabled);
// Collect source positions for optimized code when profiling or if debugger // Collect source positions for optimized code when profiling or if debugger
// is active, to be able to get more precise source positions at the price of // is active, to be able to get more precise source positions at the price of
......
...@@ -51,6 +51,7 @@ class V8_EXPORT_PRIVATE CompilationInfo final { ...@@ -51,6 +51,7 @@ class V8_EXPORT_PRIVATE CompilationInfo final {
kBailoutOnUninitialized = 1 << 9, kBailoutOnUninitialized = 1 << 9,
kLoopPeelingEnabled = 1 << 10, kLoopPeelingEnabled = 1 << 10,
kUntrustedCodeMitigations = 1 << 11, kUntrustedCodeMitigations = 1 << 11,
kSwitchJumpTableEnabled = 1 << 12,
}; };
// TODO(mtrofin): investigate if this might be generalized outside wasm, with // TODO(mtrofin): investigate if this might be generalized outside wasm, with
...@@ -169,6 +170,10 @@ class V8_EXPORT_PRIVATE CompilationInfo final { ...@@ -169,6 +170,10 @@ class V8_EXPORT_PRIVATE CompilationInfo final {
return GetFlag(kUntrustedCodeMitigations); return GetFlag(kUntrustedCodeMitigations);
} }
bool switch_jump_table_enabled() const {
return GetFlag(kSwitchJumpTableEnabled);
}
// Code getters and setters. // Code getters and setters.
void SetCode(Handle<Code> code) { code_ = code; } void SetCode(Handle<Code> code) { code_ = code; }
......
...@@ -1980,6 +1980,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -1980,6 +1980,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
// Emit either ArchTableSwitch or ArchLookupSwitch. // Emit either ArchTableSwitch or ArchLookupSwitch.
if (enable_switch_jump_table_ == kEnableSwitchJumpTable) {
static const size_t kMaxTableSwitchValueRange = 2 << 16; static const size_t kMaxTableSwitchValueRange = 2 << 16;
size_t table_space_cost = 4 + sw.value_range; size_t table_space_cost = 4 + sw.value_range;
size_t table_time_cost = 3; size_t table_time_cost = 3;
...@@ -1999,6 +2000,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -1999,6 +2000,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
// Generate a table lookup. // Generate a table lookup.
return EmitTableSwitch(sw, index_operand); return EmitTableSwitch(sw, index_operand);
} }
}
// Generate a sequence of conditional jumps. // Generate a sequence of conditional jumps.
return EmitLookupSwitch(sw, value_operand); return EmitLookupSwitch(sw, value_operand);
......
...@@ -2361,6 +2361,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -2361,6 +2361,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
// Emit either ArchTableSwitch or ArchLookupSwitch. // Emit either ArchTableSwitch or ArchLookupSwitch.
if (enable_switch_jump_table_ == kEnableSwitchJumpTable) {
static const size_t kMaxTableSwitchValueRange = 2 << 16; static const size_t kMaxTableSwitchValueRange = 2 << 16;
size_t table_space_cost = 4 + sw.value_range; size_t table_space_cost = 4 + sw.value_range;
size_t table_time_cost = 3; size_t table_time_cost = 3;
...@@ -2380,6 +2381,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -2380,6 +2381,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
// Generate a table lookup. // Generate a table lookup.
return EmitTableSwitch(sw, index_operand); return EmitTableSwitch(sw, index_operand);
} }
}
// Generate a sequence of conditional jumps. // Generate a sequence of conditional jumps.
return EmitLookupSwitch(sw, value_operand); return EmitLookupSwitch(sw, value_operand);
......
...@@ -1431,6 +1431,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -1431,6 +1431,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
// Emit either ArchTableSwitch or ArchLookupSwitch. // Emit either ArchTableSwitch or ArchLookupSwitch.
if (enable_switch_jump_table_ == kEnableSwitchJumpTable) {
static const size_t kMaxTableSwitchValueRange = 2 << 16; static const size_t kMaxTableSwitchValueRange = 2 << 16;
size_t table_space_cost = 4 + sw.value_range; size_t table_space_cost = 4 + sw.value_range;
size_t table_time_cost = 3; size_t table_time_cost = 3;
...@@ -1450,6 +1451,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -1450,6 +1451,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
// Generate a table lookup. // Generate a table lookup.
return EmitTableSwitch(sw, index_operand); return EmitTableSwitch(sw, index_operand);
} }
}
// Generate a sequence of conditional jumps. // Generate a sequence of conditional jumps.
return EmitLookupSwitch(sw, value_operand); return EmitLookupSwitch(sw, value_operand);
......
...@@ -24,6 +24,7 @@ InstructionSelector::InstructionSelector( ...@@ -24,6 +24,7 @@ InstructionSelector::InstructionSelector(
Zone* zone, size_t node_count, Linkage* linkage, Zone* zone, size_t node_count, Linkage* linkage,
InstructionSequence* sequence, Schedule* schedule, InstructionSequence* sequence, Schedule* schedule,
SourcePositionTable* source_positions, Frame* frame, SourcePositionTable* source_positions, Frame* frame,
EnableSwitchJumpTable enable_switch_jump_table,
SourcePositionMode source_position_mode, Features features, SourcePositionMode source_position_mode, Features features,
EnableScheduling enable_scheduling, EnableScheduling enable_scheduling,
EnableSerialization enable_serialization) EnableSerialization enable_serialization)
...@@ -45,6 +46,7 @@ InstructionSelector::InstructionSelector( ...@@ -45,6 +46,7 @@ InstructionSelector::InstructionSelector(
scheduler_(nullptr), scheduler_(nullptr),
enable_scheduling_(enable_scheduling), enable_scheduling_(enable_scheduling),
enable_serialization_(enable_serialization), enable_serialization_(enable_serialization),
enable_switch_jump_table_(enable_switch_jump_table),
frame_(frame), frame_(frame),
instruction_selection_failed_(false) { instruction_selection_failed_(false) {
instructions_.reserve(node_count); instructions_.reserve(node_count);
......
...@@ -51,11 +51,16 @@ class V8_EXPORT_PRIVATE InstructionSelector final { ...@@ -51,11 +51,16 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
enum SourcePositionMode { kCallSourcePositions, kAllSourcePositions }; enum SourcePositionMode { kCallSourcePositions, kAllSourcePositions };
enum EnableScheduling { kDisableScheduling, kEnableScheduling }; enum EnableScheduling { kDisableScheduling, kEnableScheduling };
enum EnableSerialization { kDisableSerialization, kEnableSerialization }; enum EnableSerialization { kDisableSerialization, kEnableSerialization };
enum EnableSwitchJumpTable {
kDisableSwitchJumpTable,
kEnableSwitchJumpTable
};
InstructionSelector( InstructionSelector(
Zone* zone, size_t node_count, Linkage* linkage, Zone* zone, size_t node_count, Linkage* linkage,
InstructionSequence* sequence, Schedule* schedule, InstructionSequence* sequence, Schedule* schedule,
SourcePositionTable* source_positions, Frame* frame, SourcePositionTable* source_positions, Frame* frame,
EnableSwitchJumpTable enable_switch_jump_table,
SourcePositionMode source_position_mode = kCallSourcePositions, SourcePositionMode source_position_mode = kCallSourcePositions,
Features features = SupportedFeatures(), Features features = SupportedFeatures(),
EnableScheduling enable_scheduling = FLAG_turbo_instruction_scheduling EnableScheduling enable_scheduling = FLAG_turbo_instruction_scheduling
...@@ -445,6 +450,7 @@ class V8_EXPORT_PRIVATE InstructionSelector final { ...@@ -445,6 +450,7 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
InstructionScheduler* scheduler_; InstructionScheduler* scheduler_;
EnableScheduling enable_scheduling_; EnableScheduling enable_scheduling_;
EnableSerialization enable_serialization_; EnableSerialization enable_serialization_;
EnableSwitchJumpTable enable_switch_jump_table_;
Frame* frame_; Frame* frame_;
bool instruction_selection_failed_; bool instruction_selection_failed_;
}; };
......
...@@ -1608,6 +1608,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -1608,6 +1608,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
// Emit either ArchTableSwitch or ArchLookupSwitch. // Emit either ArchTableSwitch or ArchLookupSwitch.
if (enable_switch_jump_table_ == kEnableSwitchJumpTable) {
static const size_t kMaxTableSwitchValueRange = 2 << 16; static const size_t kMaxTableSwitchValueRange = 2 << 16;
size_t table_space_cost = 9 + sw.value_range; size_t table_space_cost = 9 + sw.value_range;
size_t table_time_cost = 3; size_t table_time_cost = 3;
...@@ -1627,6 +1628,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -1627,6 +1628,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
// Generate a table lookup. // Generate a table lookup.
return EmitTableSwitch(sw, index_operand); return EmitTableSwitch(sw, index_operand);
} }
}
// Generate a sequence of conditional jumps. // Generate a sequence of conditional jumps.
return EmitLookupSwitch(sw, value_operand); return EmitLookupSwitch(sw, value_operand);
......
...@@ -2216,6 +2216,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -2216,6 +2216,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
// Emit either ArchTableSwitch or ArchLookupSwitch. // Emit either ArchTableSwitch or ArchLookupSwitch.
if (enable_switch_jump_table_ == kEnableSwitchJumpTable) {
static const size_t kMaxTableSwitchValueRange = 2 << 16; static const size_t kMaxTableSwitchValueRange = 2 << 16;
size_t table_space_cost = 10 + 2 * sw.value_range; size_t table_space_cost = 10 + 2 * sw.value_range;
size_t table_time_cost = 3; size_t table_time_cost = 3;
...@@ -2235,6 +2236,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -2235,6 +2236,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
// Generate a table lookup. // Generate a table lookup.
return EmitTableSwitch(sw, index_operand); return EmitTableSwitch(sw, index_operand);
} }
}
// Generate a sequence of conditional jumps. // Generate a sequence of conditional jumps.
return EmitLookupSwitch(sw, value_operand); return EmitLookupSwitch(sw, value_operand);
......
...@@ -1525,6 +1525,9 @@ struct InstructionSelectionPhase { ...@@ -1525,6 +1525,9 @@ struct InstructionSelectionPhase {
InstructionSelector selector( InstructionSelector selector(
temp_zone, data->graph()->NodeCount(), linkage, data->sequence(), temp_zone, data->graph()->NodeCount(), linkage, data->sequence(),
data->schedule(), data->source_positions(), data->frame(), data->schedule(), data->source_positions(), data->frame(),
data->info()->switch_jump_table_enabled()
? InstructionSelector::kEnableSwitchJumpTable
: InstructionSelector::kDisableSwitchJumpTable,
data->info()->is_source_positions_enabled() data->info()->is_source_positions_enabled()
? InstructionSelector::kAllSourcePositions ? InstructionSelector::kAllSourcePositions
: InstructionSelector::kCallSourcePositions, : InstructionSelector::kCallSourcePositions,
......
...@@ -1762,6 +1762,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -1762,6 +1762,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
// Emit either ArchTableSwitch or ArchLookupSwitch. // Emit either ArchTableSwitch or ArchLookupSwitch.
if (enable_switch_jump_table_ == kEnableSwitchJumpTable) {
static const size_t kMaxTableSwitchValueRange = 2 << 16; static const size_t kMaxTableSwitchValueRange = 2 << 16;
size_t table_space_cost = 4 + sw.value_range; size_t table_space_cost = 4 + sw.value_range;
size_t table_time_cost = 3; size_t table_time_cost = 3;
...@@ -1781,6 +1782,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -1781,6 +1782,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
// Generate a table lookup. // Generate a table lookup.
return EmitTableSwitch(sw, index_operand); return EmitTableSwitch(sw, index_operand);
} }
}
// Generate a sequence of conditional jumps. // Generate a sequence of conditional jumps.
return EmitLookupSwitch(sw, value_operand); return EmitLookupSwitch(sw, value_operand);
......
...@@ -2138,6 +2138,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -2138,6 +2138,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
// Emit either ArchTableSwitch or ArchLookupSwitch. // Emit either ArchTableSwitch or ArchLookupSwitch.
if (enable_switch_jump_table_ == kEnableSwitchJumpTable) {
static const size_t kMaxTableSwitchValueRange = 2 << 16; static const size_t kMaxTableSwitchValueRange = 2 << 16;
size_t table_space_cost = 4 + sw.value_range; size_t table_space_cost = 4 + sw.value_range;
size_t table_time_cost = 3; size_t table_time_cost = 3;
...@@ -2162,6 +2163,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -2162,6 +2163,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
// Generate a table lookup. // Generate a table lookup.
return EmitTableSwitch(sw, index_operand); return EmitTableSwitch(sw, index_operand);
} }
}
// Generate a sequence of conditional jumps. // Generate a sequence of conditional jumps.
return EmitLookupSwitch(sw, value_operand); return EmitLookupSwitch(sw, value_operand);
......
...@@ -1959,6 +1959,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -1959,6 +1959,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
// Emit either ArchTableSwitch or ArchLookupSwitch. // Emit either ArchTableSwitch or ArchLookupSwitch.
if (enable_switch_jump_table_ == kEnableSwitchJumpTable) {
static const size_t kMaxTableSwitchValueRange = 2 << 16; static const size_t kMaxTableSwitchValueRange = 2 << 16;
size_t table_space_cost = 4 + sw.value_range; size_t table_space_cost = 4 + sw.value_range;
size_t table_time_cost = 3; size_t table_time_cost = 3;
...@@ -1971,7 +1972,8 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -1971,7 +1972,8 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
sw.value_range <= kMaxTableSwitchValueRange) { sw.value_range <= kMaxTableSwitchValueRange) {
InstructionOperand index_operand = g.TempRegister(); InstructionOperand index_operand = g.TempRegister();
if (sw.min_value) { if (sw.min_value) {
// The leal automatically zero extends, so result is a valid 64-bit index. // The leal automatically zero extends, so result is a valid 64-bit
// index.
Emit(kX64Lea32 | AddressingModeField::encode(kMode_MRI), index_operand, Emit(kX64Lea32 | AddressingModeField::encode(kMode_MRI), index_operand,
value_operand, g.TempImmediate(-sw.min_value)); value_operand, g.TempImmediate(-sw.min_value));
} else { } else {
...@@ -1981,6 +1983,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -1981,6 +1983,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
// Generate a table lookup. // Generate a table lookup.
return EmitTableSwitch(sw, index_operand); return EmitTableSwitch(sw, index_operand);
} }
}
// Generate a sequence of conditional jumps. // Generate a sequence of conditional jumps.
return EmitLookupSwitch(sw, value_operand); return EmitLookupSwitch(sw, value_operand);
......
...@@ -490,6 +490,10 @@ DEFINE_BOOL(untrusted_code_mitigations, V8_DEFAULT_UNTRUSTED_CODE_MITIGATIONS, ...@@ -490,6 +490,10 @@ DEFINE_BOOL(untrusted_code_mitigations, V8_DEFAULT_UNTRUSTED_CODE_MITIGATIONS,
"Enable mitigations for executing untrusted code") "Enable mitigations for executing untrusted code")
#undef V8_DEFAULT_UNTRUSTED_CODE_MITIGATIONS #undef V8_DEFAULT_UNTRUSTED_CODE_MITIGATIONS
DEFINE_BOOL(turbo_disable_switch_jump_table, false,
"do not emit jump-tables in Turbofan")
DEFINE_IMPLICATION(untrusted_code_mitigations, turbo_disable_switch_jump_table)
// Flags to help platform porters // Flags to help platform porters
DEFINE_BOOL(minimal, false, DEFINE_BOOL(minimal, false,
"simplifies execution model to make porting " "simplifies execution model to make porting "
......
...@@ -43,6 +43,7 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build( ...@@ -43,6 +43,7 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build(
SourcePositionTable source_position_table(graph()); SourcePositionTable source_position_table(graph());
InstructionSelector selector(test_->zone(), node_count, &linkage, &sequence, InstructionSelector selector(test_->zone(), node_count, &linkage, &sequence,
schedule, &source_position_table, nullptr, schedule, &source_position_table, nullptr,
InstructionSelector::kEnableSwitchJumpTable,
source_position_mode, features, source_position_mode, features,
InstructionSelector::kDisableScheduling); InstructionSelector::kDisableScheduling);
selector.SelectInstructions(); selector.SelectInstructions();
......
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