Skip to content

Commit c0c96b7

Browse files
GeorgNeisCommit Bot
authored andcommitted
Merged: [deoptimizer] Fix bug in OptimizedFrame::Summarize
Revision: 3353a7d BUG=chromium:1182647 NOTRY=true NOPRESUBMIT=true NOTREECHECKS=true [email protected] Change-Id: I86abd6a3f34169be5f99aa9f54bb7bb3706fa85a Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2780300 Reviewed-by: Georg Neis <[email protected]> Reviewed-by: Benedikt Meurer <[email protected]> Commit-Queue: Georg Neis <[email protected]> Cr-Commit-Position: refs/branch-heads/8.9@{#49} Cr-Branched-From: 16b9bbb-refs/heads/8.9.255@{#1} Cr-Branched-From: d16a2a6-refs/heads/master@{#72039}
1 parent c07ef73 commit c0c96b7

3 files changed

Lines changed: 92 additions & 10 deletions

File tree

src/deoptimizer/deoptimizer.cc

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3511,7 +3511,8 @@ Address TranslatedState::DecompressIfNeeded(intptr_t value) {
35113511
}
35123512
}
35133513

3514-
TranslatedState::TranslatedState(const JavaScriptFrame* frame) {
3514+
TranslatedState::TranslatedState(const JavaScriptFrame* frame)
3515+
: purpose_(kFrameInspection) {
35153516
int deopt_index = Safepoint::kNoDeoptimizationIndex;
35163517
DeoptimizationData data =
35173518
static_cast<const OptimizedFrame*>(frame)->GetDeoptimizationData(
@@ -3907,25 +3908,63 @@ void TranslatedState::EnsureCapturedObjectAllocatedAt(
39073908
}
39083909

39093910
default:
3910-
CHECK(map->IsJSObjectMap());
39113911
EnsureJSObjectAllocated(slot, map);
3912-
TranslatedValue* properties_slot = &(frame->values_[value_index]);
3913-
value_index++;
3912+
int remaining_children_count = slot->GetChildrenCount() - 1;
3913+
3914+
TranslatedValue* properties_slot = frame->ValueAt(value_index);
3915+
value_index++, remaining_children_count--;
39143916
if (properties_slot->kind() == TranslatedValue::kCapturedObject) {
3915-
// If we are materializing the property array, make sure we put
3916-
// the mutable heap numbers at the right places.
3917+
// We are materializing the property array, so make sure we put the
3918+
// mutable heap numbers at the right places.
39173919
EnsurePropertiesAllocatedAndMarked(properties_slot, map);
39183920
EnsureChildrenAllocated(properties_slot->GetChildrenCount(), frame,
39193921
&value_index, worklist);
3922+
} else {
3923+
CHECK_EQ(properties_slot->kind(), TranslatedValue::kTagged);
39203924
}
3921-
// Make sure all the remaining children (after the map and properties) are
3922-
// allocated.
3923-
return EnsureChildrenAllocated(slot->GetChildrenCount() - 2, frame,
3925+
3926+
TranslatedValue* elements_slot = frame->ValueAt(value_index);
3927+
value_index++, remaining_children_count--;
3928+
if (elements_slot->kind() == TranslatedValue::kCapturedObject ||
3929+
!map->IsJSArrayMap()) {
3930+
// Handle this case with the other remaining children below.
3931+
value_index--, remaining_children_count++;
3932+
} else {
3933+
CHECK_EQ(elements_slot->kind(), TranslatedValue::kTagged);
3934+
elements_slot->GetValue();
3935+
if (purpose_ == kFrameInspection) {
3936+
// We are materializing a JSArray for the purpose of frame inspection.
3937+
// If we were to construct it with the above elements value then an
3938+
// actual deopt later on might create another JSArray instance with
3939+
// the same elements store. That would violate the key assumption
3940+
// behind left-trimming.
3941+
elements_slot->ReplaceElementsArrayWithCopy();
3942+
}
3943+
}
3944+
3945+
// Make sure all the remaining children (after the map, properties store,
3946+
// and possibly elements store) are allocated.
3947+
return EnsureChildrenAllocated(remaining_children_count, frame,
39243948
&value_index, worklist);
39253949
}
39263950
UNREACHABLE();
39273951
}
39283952

3953+
void TranslatedValue::ReplaceElementsArrayWithCopy() {
3954+
DCHECK_EQ(kind(), TranslatedValue::kTagged);
3955+
DCHECK_EQ(materialization_state(), TranslatedValue::kFinished);
3956+
auto elements = Handle<FixedArrayBase>::cast(GetValue());
3957+
DCHECK(elements->IsFixedArray() || elements->IsFixedDoubleArray());
3958+
if (elements->IsFixedDoubleArray()) {
3959+
DCHECK(!elements->IsCowArray());
3960+
set_storage(isolate()->factory()->CopyFixedDoubleArray(
3961+
Handle<FixedDoubleArray>::cast(elements)));
3962+
} else if (!elements->IsCowArray()) {
3963+
set_storage(isolate()->factory()->CopyFixedArray(
3964+
Handle<FixedArray>::cast(elements)));
3965+
}
3966+
}
3967+
39293968
void TranslatedState::EnsureChildrenAllocated(int count, TranslatedFrame* frame,
39303969
int* value_index,
39313970
std::stack<int>* worklist) {
@@ -3991,6 +4030,7 @@ Handle<ByteArray> TranslatedState::AllocateStorageFor(TranslatedValue* slot) {
39914030

39924031
void TranslatedState::EnsureJSObjectAllocated(TranslatedValue* slot,
39934032
Handle<Map> map) {
4033+
CHECK(map->IsJSObjectMap());
39944034
CHECK_EQ(map->instance_size(), slot->GetChildrenCount() * kTaggedSize);
39954035

39964036
Handle<ByteArray> object_storage = AllocateStorageFor(slot);

src/deoptimizer/deoptimizer.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ class TranslatedValue {
122122
return storage_;
123123
}
124124

125+
void ReplaceElementsArrayWithCopy();
126+
125127
Kind kind_;
126128
MaterializationState materialization_state_ = kUninitialized;
127129
TranslatedState* container_; // This is only needed for materialization of
@@ -318,7 +320,15 @@ class TranslatedFrame {
318320

319321
class TranslatedState {
320322
public:
321-
TranslatedState() = default;
323+
// There are two constructors, each for a different purpose:
324+
325+
// The default constructor is for the purpose of deoptimizing an optimized
326+
// frame (replacing it with one or several unoptimized frames). It is used by
327+
// the Deoptimizer.
328+
TranslatedState() : purpose_(kDeoptimization) {}
329+
330+
// This constructor is for the purpose of merely inspecting an optimized
331+
// frame. It is used by stack trace generation and various debugging features.
322332
explicit TranslatedState(const JavaScriptFrame* frame);
323333

324334
void Prepare(Address stack_frame_pointer);
@@ -353,6 +363,12 @@ class TranslatedState {
353363
private:
354364
friend TranslatedValue;
355365

366+
// See the description of the constructors for an explanation of the two
367+
// purposes. The only actual difference is that in the kFrameInspection case
368+
// extra work is needed to not violate assumptions made by left-trimming. For
369+
// details, see the code around ReplaceElementsArrayWithCopy.
370+
enum Purpose { kDeoptimization, kFrameInspection };
371+
356372
TranslatedFrame CreateNextTranslatedFrame(TranslationIterator* iterator,
357373
FixedArray literal_array,
358374
Address fp, FILE* trace_file);
@@ -409,6 +425,7 @@ class TranslatedState {
409425
static Float32 GetFloatSlot(Address fp, int slot_index);
410426
static Float64 GetDoubleSlot(Address fp, int slot_index);
411427

428+
Purpose const purpose_;
412429
std::vector<TranslatedFrame> frames_;
413430
Isolate* isolate_ = nullptr;
414431
Address stack_frame_pointer_ = kNullAddress;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2021 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 --verify-heap
6+
7+
function foo() {
8+
const arr = Array(1000);
9+
10+
function bar() {
11+
try { ({a: p4nda, b: arr.length}); } catch(e) {}
12+
}
13+
14+
for (var i = 0; i < 25; i++) bar();
15+
16+
/p4nda/.test({}); // Deopt here.
17+
18+
arr.shift();
19+
}
20+
21+
%PrepareFunctionForOptimization(foo);
22+
foo();
23+
foo();
24+
%OptimizeFunctionOnNextCall(foo);
25+
foo();

0 commit comments

Comments
 (0)