Skip to content

Commit 254c794

Browse files
GeorgNeisCommit Bot
authored andcommitted
Merged: [deoptimizer] Fix bug in OptimizedFrame::Summarize
Revision: 3353a7d BUG=chromium:1182647 NOTRY=true NOPRESUBMIT=true NOTREECHECKS=true R=​[email protected] (cherry picked from commit c0c96b7) 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-Original-Commit-Position: refs/branch-heads/8.9@{#49} Cr-Original-Branched-From: 16b9bbb-refs/heads/8.9.255@{#1} Cr-Original-Branched-From: d16a2a6-refs/heads/master@{#72039} Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2794427 Reviewed-by: Victor-Gabriel Savu <[email protected]> Commit-Queue: Artem Sumaneev <[email protected]> Cr-Commit-Position: refs/branch-heads/8.6@{#72} Cr-Branched-From: a64aed2-refs/heads/8.6.395@{#1} Cr-Branched-From: a626bc0-refs/heads/master@{#69472}
1 parent 5f4f1ec commit 254c794

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
@@ -3353,7 +3353,8 @@ Address TranslatedState::DecompressIfNeeded(intptr_t value) {
33533353
}
33543354
}
33553355

3356-
TranslatedState::TranslatedState(const JavaScriptFrame* frame) {
3356+
TranslatedState::TranslatedState(const JavaScriptFrame* frame)
3357+
: purpose_(kFrameInspection) {
33573358
int deopt_index = Safepoint::kNoDeoptimizationIndex;
33583359
DeoptimizationData data =
33593360
static_cast<const OptimizedFrame*>(frame)->GetDeoptimizationData(
@@ -3740,25 +3741,63 @@ void TranslatedState::EnsureCapturedObjectAllocatedAt(
37403741
}
37413742

37423743
default:
3743-
CHECK(map->IsJSObjectMap());
37443744
EnsureJSObjectAllocated(slot, map);
3745-
TranslatedValue* properties_slot = &(frame->values_[value_index]);
3746-
value_index++;
3745+
int remaining_children_count = slot->GetChildrenCount() - 1;
3746+
3747+
TranslatedValue* properties_slot = frame->ValueAt(value_index);
3748+
value_index++, remaining_children_count--;
37473749
if (properties_slot->kind() == TranslatedValue::kCapturedObject) {
3748-
// If we are materializing the property array, make sure we put
3749-
// the mutable heap numbers at the right places.
3750+
// We are materializing the property array, so make sure we put the
3751+
// mutable heap numbers at the right places.
37503752
EnsurePropertiesAllocatedAndMarked(properties_slot, map);
37513753
EnsureChildrenAllocated(properties_slot->GetChildrenCount(), frame,
37523754
&value_index, worklist);
3755+
} else {
3756+
CHECK_EQ(properties_slot->kind(), TranslatedValue::kTagged);
37533757
}
3754-
// Make sure all the remaining children (after the map and properties) are
3755-
// allocated.
3756-
return EnsureChildrenAllocated(slot->GetChildrenCount() - 2, frame,
3758+
3759+
TranslatedValue* elements_slot = frame->ValueAt(value_index);
3760+
value_index++, remaining_children_count--;
3761+
if (elements_slot->kind() == TranslatedValue::kCapturedObject ||
3762+
!map->IsJSArrayMap()) {
3763+
// Handle this case with the other remaining children below.
3764+
value_index--, remaining_children_count++;
3765+
} else {
3766+
CHECK_EQ(elements_slot->kind(), TranslatedValue::kTagged);
3767+
elements_slot->GetValue();
3768+
if (purpose_ == kFrameInspection) {
3769+
// We are materializing a JSArray for the purpose of frame inspection.
3770+
// If we were to construct it with the above elements value then an
3771+
// actual deopt later on might create another JSArray instance with
3772+
// the same elements store. That would violate the key assumption
3773+
// behind left-trimming.
3774+
elements_slot->ReplaceElementsArrayWithCopy();
3775+
}
3776+
}
3777+
3778+
// Make sure all the remaining children (after the map, properties store,
3779+
// and possibly elements store) are allocated.
3780+
return EnsureChildrenAllocated(remaining_children_count, frame,
37573781
&value_index, worklist);
37583782
}
37593783
UNREACHABLE();
37603784
}
37613785

3786+
void TranslatedValue::ReplaceElementsArrayWithCopy() {
3787+
DCHECK_EQ(kind(), TranslatedValue::kTagged);
3788+
DCHECK_EQ(materialization_state(), TranslatedValue::kFinished);
3789+
auto elements = Handle<FixedArrayBase>::cast(GetValue());
3790+
DCHECK(elements->IsFixedArray() || elements->IsFixedDoubleArray());
3791+
if (elements->IsFixedDoubleArray()) {
3792+
DCHECK(!elements->IsCowArray());
3793+
set_storage(isolate()->factory()->CopyFixedDoubleArray(
3794+
Handle<FixedDoubleArray>::cast(elements)));
3795+
} else if (!elements->IsCowArray()) {
3796+
set_storage(isolate()->factory()->CopyFixedArray(
3797+
Handle<FixedArray>::cast(elements)));
3798+
}
3799+
}
3800+
37623801
void TranslatedState::EnsureChildrenAllocated(int count, TranslatedFrame* frame,
37633802
int* value_index,
37643803
std::stack<int>* worklist) {
@@ -3823,6 +3862,7 @@ Handle<ByteArray> TranslatedState::AllocateStorageFor(TranslatedValue* slot) {
38233862

38243863
void TranslatedState::EnsureJSObjectAllocated(TranslatedValue* slot,
38253864
Handle<Map> map) {
3865+
CHECK(map->IsJSObjectMap());
38263866
CHECK_EQ(map->instance_size(), slot->GetChildrenCount() * kTaggedSize);
38273867

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

src/deoptimizer/deoptimizer.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ class TranslatedValue {
118118
return storage_;
119119
}
120120

121+
void ReplaceElementsArrayWithCopy();
122+
121123
Kind kind_;
122124
MaterializationState materialization_state_ = kUninitialized;
123125
TranslatedState* container_; // This is only needed for materialization of
@@ -314,7 +316,15 @@ class TranslatedFrame {
314316

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

320330
void Prepare(Address stack_frame_pointer);
@@ -348,6 +358,12 @@ class TranslatedState {
348358
private:
349359
friend TranslatedValue;
350360

361+
// See the description of the constructors for an explanation of the two
362+
// purposes. The only actual difference is that in the kFrameInspection case
363+
// extra work is needed to not violate assumptions made by left-trimming. For
364+
// details, see the code around ReplaceElementsArrayWithCopy.
365+
enum Purpose { kDeoptimization, kFrameInspection };
366+
351367
TranslatedFrame CreateNextTranslatedFrame(TranslationIterator* iterator,
352368
FixedArray literal_array,
353369
Address fp, FILE* trace_file);
@@ -404,6 +420,7 @@ class TranslatedState {
404420
static Float32 GetFloatSlot(Address fp, int slot_index);
405421
static Float64 GetDoubleSlot(Address fp, int slot_index);
406422

423+
Purpose const purpose_;
407424
std::vector<TranslatedFrame> frames_;
408425
Isolate* isolate_ = nullptr;
409426
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)