Skip to content

Commit d5dd2e6

Browse files
ripsawridgeCommit Bot
authored andcommitted
[Turbofan]: Fix error in serializer try ranges with generators
When simulating bytecode, we store the current environment at the site of the appropriate catch handler when entering a try range. If the start of the try range is dead, we don't bother to store an environment. However, generators can create alive regions inside the try range. At such moments, we should recognize we're in a try range and store the environment for the handler. Bug: chromium:1017159 Change-Id: Icccc2ccf530895099bc62b97d9aaec8b97d5f4e8 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1879247 Reviewed-by: Georg Neis <neis@chromium.org> Reviewed-by: Maya Lekova <mslekova@chromium.org> Commit-Queue: Michael Stanton <mvstanton@chromium.org> Cr-Commit-Position: refs/heads/master@{#64929}
1 parent 1d493d3 commit d5dd2e6

2 files changed

Lines changed: 82 additions & 22 deletions

File tree

src/compiler/serializer-for-background-compilation.cc

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,31 +1028,64 @@ class HandlerRangeMatcher {
10281028
: bytecode_iterator_(bytecode_iterator) {
10291029
HandlerTable table(*bytecode_array);
10301030
for (int i = 0, n = table.NumberOfRangeEntries(); i < n; ++i) {
1031-
ranges_.insert(
1032-
std::make_pair(table.GetRangeStart(i), table.GetRangeHandler(i)));
1031+
ranges_.insert({table.GetRangeStart(i), table.GetRangeEnd(i),
1032+
table.GetRangeHandler(i)});
10331033
}
10341034
ranges_iterator_ = ranges_.cbegin();
10351035
}
10361036

1037-
int NextHandlerOffsetForRangeStart() {
1037+
using OffsetReporter = std::function<void(int handler_offset)>;
1038+
1039+
void HandlerOffsetForCurrentPosition(const OffsetReporter& offset_reporter) {
10381040
CHECK(!bytecode_iterator_.done());
1039-
int handler_offset = -1;
1041+
const int current_offset = bytecode_iterator_.current_offset();
1042+
1043+
// Remove outdated try ranges from the stack.
1044+
while (!stack_.empty()) {
1045+
const int end = stack_.top().end;
1046+
if (end < current_offset) {
1047+
stack_.pop();
1048+
} else {
1049+
break;
1050+
}
1051+
}
1052+
1053+
// Advance the iterator and maintain the stack.
10401054
while (ranges_iterator_ != ranges_.cend() &&
1041-
ranges_iterator_->first < bytecode_iterator_.current_offset()) {
1055+
ranges_iterator_->start <= current_offset) {
1056+
if (ranges_iterator_->end >= current_offset) {
1057+
stack_.push(*ranges_iterator_);
1058+
if (ranges_iterator_->start == current_offset) {
1059+
offset_reporter(ranges_iterator_->handler);
1060+
}
1061+
}
10421062
ranges_iterator_++;
10431063
}
1044-
if (ranges_iterator_ != ranges_.cend() &&
1045-
ranges_iterator_->first == bytecode_iterator_.current_offset()) {
1046-
handler_offset = ranges_iterator_->second;
1047-
ranges_iterator_++;
1064+
1065+
if (!stack_.empty() && stack_.top().start < current_offset) {
1066+
offset_reporter(stack_.top().handler);
10481067
}
1049-
return handler_offset;
10501068
}
10511069

10521070
private:
10531071
BytecodeArrayIterator const& bytecode_iterator_;
1054-
std::multimap<int, int> ranges_;
1055-
std::multimap<int, int>::const_iterator ranges_iterator_;
1072+
1073+
struct Range {
1074+
int start;
1075+
int end;
1076+
int handler;
1077+
friend bool operator<(const Range& a, const Range& b) {
1078+
if (a.start < b.start) return true;
1079+
if (a.start == b.start) {
1080+
if (a.end < b.end) return true;
1081+
CHECK_GT(a.end, b.end);
1082+
}
1083+
return false;
1084+
}
1085+
};
1086+
std::set<Range> ranges_;
1087+
std::set<Range>::const_iterator ranges_iterator_;
1088+
std::stack<Range> stack_;
10561089
};
10571090

10581091
Handle<FeedbackVector> SerializerForBackgroundCompilation::feedback_vector()
@@ -1104,16 +1137,16 @@ void SerializerForBackgroundCompilation::TraverseBytecode() {
11041137
continue; // Skip this bytecode since TF won't generate code for it.
11051138
}
11061139

1107-
int handler_offset = try_start_matcher.NextHandlerOffsetForRangeStart();
1108-
while (handler_offset >= 0) {
1109-
// We may have nested try ranges that nonetheless start at the same
1110-
// offset. We loop here in order to save the environment for each catch
1111-
// handler.
1112-
TRACE_BROKER(broker(),
1113-
"Entered try block. Handler at offset " << handler_offset);
1114-
ContributeToJumpTargetEnvironment(handler_offset);
1115-
handler_offset = try_start_matcher.NextHandlerOffsetForRangeStart();
1116-
}
1140+
auto save_handler_environments = [&](int handler_offset) {
1141+
auto it = jump_target_environments_.find(handler_offset);
1142+
if (it == jump_target_environments_.end()) {
1143+
ContributeToJumpTargetEnvironment(handler_offset);
1144+
TRACE_BROKER(broker(),
1145+
"Handler offset for current pos: " << handler_offset);
1146+
}
1147+
};
1148+
try_start_matcher.HandlerOffsetForCurrentPosition(
1149+
save_handler_environments);
11171150

11181151
if (bytecode_analysis.IsLoopHeader(current_offset)) {
11191152
// Graph builder might insert jumps to resume targets in the loop body.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2019 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
//
5+
// Flags: --allow-natives-syntax
6+
7+
function* foo() {
8+
__v_1 = foo.x; // LdaNamedProperty
9+
for (;;) {
10+
try {
11+
yield;
12+
try {
13+
__v_0 == "object";
14+
__v_1[__getRandomProperty()]();
15+
} catch(e) {
16+
print();
17+
}
18+
} catch(e) {
19+
"Caught: " + e;
20+
}
21+
break;
22+
}
23+
};
24+
25+
%PrepareFunctionForOptimization(foo);
26+
%OptimizeFunctionOnNextCall(foo);
27+
foo();

0 commit comments

Comments
 (0)