Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion deps/v8/include/v8-version.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#define V8_MAJOR_VERSION 13
#define V8_MINOR_VERSION 7
#define V8_BUILD_NUMBER 152
#define V8_PATCH_LEVEL 9
#define V8_PATCH_LEVEL 10

// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
Expand Down
14 changes: 10 additions & 4 deletions deps/v8/src/compiler/turboshaft/late-load-elimination-reducer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -409,11 +409,17 @@ void LateLoadEliminationAnalyzer::ProcessStore(OpIndex op_idx,
non_aliasing_objects_.Set(value, false);
}

// If we just stored a map, invalidate the maps for this base.
// If we just stored a map, invalidate all object_maps_.
if (store.offset == HeapObject::kMapOffset && !store.index().valid()) {
if (object_maps_.HasKeyFor(store.base())) {
TRACE(">> Wiping map\n");
object_maps_.Set(store.base(), MapMaskAndOr{});
// TODO(dmercadier): can we only do this for objects that are potentially
// aliasing with the `base` (based on their maps and the maps of `base`)?
// Also, it might be worth to record a new map if this is actually a map
// store.
// TODO(dmercadier): do this only if `value` is a Constant with kind
// kHeapObject, since all map stores should store a known constant maps.
TRACE(">> Wiping all maps\n");
for (auto it : object_maps_) {
object_maps_.Set(it.second, MapMaskAndOr{});
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions deps/v8/src/compiler/turboshaft/snapshot-table-opindex.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ class SparseOpIndexSnapshotTable : public SnapshotTable<Value, KeyData> {
return std::nullopt;
}

auto begin() { return indices_to_keys_.begin(); }
auto end() { return indices_to_keys_.end(); }

private:
Key GetOrCreateKey(OpIndex idx) {
auto it = indices_to_keys_.find(idx);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
namespace v8::internal::compiler::turboshaft {

void StoreStoreEliminationPhase::Run(PipelineData* data, Zone* temp_zone) {
UnparkedScopeIfNeeded unparked_scope(
data->broker(), v8_flags.turboshaft_trace_load_elimination);

turboshaft::CopyingPhase<
LoopStackCheckElisionReducer, StoreStoreEliminationReducer,
LateLoadEliminationReducer, MachineOptimizationReducer,
Expand Down
2 changes: 2 additions & 0 deletions deps/v8/src/flags/flag-definitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -1610,6 +1610,8 @@ DEFINE_BOOL_READONLY(turboshaft_trace_emitted, false,
"trace emitted Turboshaft instructions")
DEFINE_BOOL_READONLY(turboshaft_trace_intermediate_reductions, false,
"trace intermediate Turboshaft reduction steps")
DEFINE_BOOL_READONLY(turboshaft_trace_load_elimination, false,
"trace Turboshaft's late load elimination")
#endif // DEBUG

DEFINE_BOOL(profile_guided_optimization, true, "profile guided optimization")
Expand Down
24 changes: 24 additions & 0 deletions deps/v8/test/mjsunit/turboshaft/regress-417169470-1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2025 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax --turbofan

function foo(a, b, c) {
a.x = 42;
b.y = 99; // Transitioning store
c.x = 17;
return a.x;
}

// Using a constructor so that we don't go out of object when creating the .y
// property in foo.
function MyObject() { this.x = 27; }
let o1 = new MyObject();
let o2 = new MyObject();

%PrepareFunctionForOptimization(foo);
assertEquals(17, foo(o1, o1, o1));

%OptimizeFunctionOnNextCall(foo);
assertEquals(17, foo(o2, o2, o2));
21 changes: 21 additions & 0 deletions deps/v8/test/mjsunit/turboshaft/regress-417169470-2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2025 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax --turbofan

function foo(a, b, c) {
a.x = 42;
b.y = 99; // Transitioning store
c.x = 17;
return a.x;
}

let o1 = { x : 27 };
let o2 = { x : 27 };

%PrepareFunctionForOptimization(foo);
assertEquals(17, foo(o1, o1, o1));

%OptimizeFunctionOnNextCall(foo);
assertEquals(17, foo(o2, o2, o2));
31 changes: 31 additions & 0 deletions deps/v8/test/mjsunit/turboshaft/regress-417169470-3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2025 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax --turbofan

function foo(a, b, c) {
a.x = 42;
b.y = 99; // Transitioning store
c.x = 17;
return a.x;
}

let o1 = { x : 27 };
// If we add additional properties, we need to add at least 2 so that `b.y = 99`
// doesn't end up at offset 12, because that's also the offset of .x (which is
// in-object rather than out-of-object), and because we don't have map
// information for backing stores in Late load elimination, we'll assume that
// the store at b.y can alias with the a.x that was previously loaded.
o1.unused1 = 12;
o1.unused2 = 12;

let o2 = { x : 27 };
o2.unused1 = 12;
o2.unused2 = 12;

%PrepareFunctionForOptimization(foo);
assertEquals(17, foo(o1, o1, o1));

%OptimizeFunctionOnNextCall(foo);
assertEquals(17, foo(o2, o2, o2));
31 changes: 31 additions & 0 deletions deps/v8/test/mjsunit/turboshaft/regress-417169470-4.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2025 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax --turbofan

function opt() {
const nop = 0;
const empty = {};
const a = {p1: 42.42};

function foo(b) {
nop;

a.p4 = 42;
b.p2 = 42;
b.p5 = empty;
a.p6 = 41.414;
}

a.p3 = 42;
a.p4 = 42;

for (let i = 0; i < 300; i++) {
foo(a);
}
}

opt();
opt();
opt();
Loading