summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-14 12:11:19 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-14 15:23:57 +0000
commita26c352168ec12cb917318b626a31f569a711980 (patch)
treeb6681b500d4b4263c8756365133cedeb59e43013
parent82b53e95166ef361bc8963fb0b482e236e347ece (diff)
downloadqtwebengine-chromium-a26c352168ec12cb917318b626a31f569a711980.tar.gz
[Backport] Fix for CVE-2019-5784
[regalloc] Splinter to the end of interval if value dies If a value dies in deferred code, there is no need to reload it at the end of the deferred code, as it will be dead in the non-deferred code that follows in control flow order. In the linearized view of register allocation, this is encoded as a lifetime gap (or the end of an interval). Moreover, this may lead to wrong assignments if the value dies between two deferred blocks and we leave a non-splintered live range in the middle of deferred code. Bug: chromium:915975 Change-Id: Iec68fe86f0dfbbac612635a637f3239475906d14 Reviewed-on: https://chromium-review.googlesource.com/c/1433784 Commit-Queue: Stephan Herhut <herhut@chromium.org> Reviewed-by: Jaroslav Sevcik <jarin@chromium.org> Cr-Commit-Position: refs/heads/master@{#59068} Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
-rw-r--r--chromium/v8/src/compiler/live-range-separator.cc31
1 files changed, 24 insertions, 7 deletions
diff --git a/chromium/v8/src/compiler/live-range-separator.cc b/chromium/v8/src/compiler/live-range-separator.cc
index 67d1c77a83c..2d43ba92a08 100644
--- a/chromium/v8/src/compiler/live-range-separator.cc
+++ b/chromium/v8/src/compiler/live-range-separator.cc
@@ -52,8 +52,9 @@ void CreateSplinter(TopLevelLiveRange *range, RegisterAllocationData *data,
range->SetSplinter(splinter);
}
Zone *zone = data->allocation_zone();
- TRACE("creating splinter for range %d between %d and %d\n", range->vreg(),
- start.ToInstructionIndex(), end.ToInstructionIndex());
+ TRACE("creating splinter %d for range %d between %d and %d\n",
+ range->splinter()->vreg(), range->vreg(), start.ToInstructionIndex(),
+ end.ToInstructionIndex());
range->Splinter(start, end, zone);
}
}
@@ -76,7 +77,10 @@ void SplinterLiveRange(TopLevelLiveRange *range, RegisterAllocationData *data) {
LifetimePosition last_cut = LifetimePosition::Invalid();
while (interval != nullptr) {
+ // We have to cache these here, as splintering might destroy the original
+ // interval below.
UseInterval *next_interval = interval->next();
+ LifetimePosition interval_end = interval->end();
const InstructionBlock *first_block =
code->GetInstructionBlock(interval->FirstGapIndex());
const InstructionBlock *last_block =
@@ -91,6 +95,12 @@ void SplinterLiveRange(TopLevelLiveRange *range, RegisterAllocationData *data) {
first_cut = LifetimePosition::GapFromInstructionIndex(
current_block->first_instruction_index());
}
+ // We splinter until the last gap in the block. I assume this is done to
+ // leave a little range to be allocated by normal register allocation
+ // and then use that range to connect when splinters are merged back.
+ // This might be done as control flow resolution does not insert moves
+ // if two consecutive blocks in rpo order are also consecutive in
+ // control flow.
last_cut = LifetimePosition::GapFromInstructionIndex(
current_block->last_instruction_index());
} else {
@@ -101,13 +111,20 @@ void SplinterLiveRange(TopLevelLiveRange *range, RegisterAllocationData *data) {
}
}
}
+ // If we reach the end of an interval with a first_cut and last_cut set, it
+ // means that we can splinter to the end of the interval, as the value dies
+ // in this control flow branch or is not live in the next block. In the
+ // former case, we won't need to reload the value, so we can splinter to the
+ // end of its lifetime. In the latter case, control flow resolution will
+ // have to connect blocks anyway, so we can also splinter to the end of the
+ // block, too.
+ if (first_cut.IsValid()) {
+ CreateSplinter(range, data, first_cut, interval_end);
+ first_cut = LifetimePosition::Invalid();
+ last_cut = LifetimePosition::Invalid();
+ }
interval = next_interval;
}
- // When the range ends in deferred blocks, first_cut will be valid here.
- // Splinter from there to the last instruction that was in a deferred block.
- if (first_cut.IsValid()) {
- CreateSplinter(range, data, first_cut, last_cut);
- }
// Redo has_slot_use
if (range->has_slot_use() && range->splinter() != nullptr) {