[deoptimizer][wasm] Test memory access after deopt

Liftoff caches the memory start address and reuses it on repeated
accesses. Deopt points may only be at calls at which liftoff
invalidates the cached register anyways.

Bug: 42204618
Change-Id: I07e26d5720b97745c1edfd74872df44b9ca42fed
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5573729
Auto-Submit: Matthias Liedtke <mliedtke@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
Cr-Commit-Position: refs/heads/main@{#94126}
diff --git a/src/wasm/wasm-deopt-data.h b/src/wasm/wasm-deopt-data.h
index 467c71a..1582c75 100644
--- a/src/wasm/wasm-deopt-data.h
+++ b/src/wasm/wasm-deopt-data.h
@@ -100,9 +100,6 @@
   std::vector<LiftoffVarState> var_state = {};
   // If the trusted_instance is cached in a register additionally to the stack
   // slot, this register needs to be updated as well.
-  // TODO(42204618): The memory start and memory instance are other fields that
-  // can be cached in liftoff and need to be initialized when performing a
-  // deopt.
   Register trusted_instance = no_reg;
   int total_frame_size = 0;
 };
diff --git a/test/mjsunit/regress/wasm/regress-1255354.js b/test/mjsunit/regress/wasm/regress-1255354.js
index d41babd..30faf96 100644
--- a/test/mjsunit/regress/wasm/regress-1255354.js
+++ b/test/mjsunit/regress/wasm/regress-1255354.js
@@ -14,8 +14,8 @@
     kExprIf, kWasmI32,
       kExprLocalGet, 0,
     kExprElse,
-      kExprI32Const, 42, // value
-      kExprI32Const, 0,  // index
+      kExprI32Const, 42, // index
+      kExprI32Const, 0,  // value
       kExprI32StoreMem, 0, 0,
       kExprI32Const, 11,
       kExprLocalGet, 0,
diff --git a/test/mjsunit/wasm/deopt/deopt-feedback-states.js b/test/mjsunit/wasm/deopt/deopt-feedback-states.js
index 938dc0c..162a28e 100644
--- a/test/mjsunit/wasm/deopt/deopt-feedback-states.js
+++ b/test/mjsunit/wasm/deopt/deopt-feedback-states.js
@@ -35,7 +35,8 @@
     .addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32Eq,])
     .exportFunc();
 
-  let mainSig = makeSig([kWasmI32, kWasmI32, wasmRefType(funcRefT)], [kWasmI32]);
+  let mainSig =
+    makeSig([kWasmI32, kWasmI32, wasmRefType(funcRefT)], [kWasmI32]);
   builder.addFunction("main", mainSig)
     .addLocals(kWasmI32, 1)
     .addBody([
diff --git a/test/mjsunit/wasm/deopt/deopt-inlined-stacktrace.js b/test/mjsunit/wasm/deopt/deopt-inlined-stacktrace.js
index 71dd91f..525314f 100644
--- a/test/mjsunit/wasm/deopt/deopt-inlined-stacktrace.js
+++ b/test/mjsunit/wasm/deopt/deopt-inlined-stacktrace.js
@@ -20,7 +20,8 @@
     .addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32DivS])
     .exportFunc();
 
-  let mainSig = makeSig([kWasmI32, kWasmI32, wasmRefType(funcRefT)], [kWasmI32]);
+  let mainSig =
+    makeSig([kWasmI32, kWasmI32, wasmRefType(funcRefT)], [kWasmI32]);
   let inlinee = builder.addFunction("inlinee", mainSig)
     .addBody([
       kExprLocalGet, 0,
diff --git a/test/mjsunit/wasm/deopt/deopt-memory-access.js b/test/mjsunit/wasm/deopt/deopt-memory-access.js
new file mode 100644
index 0000000..92e414b
--- /dev/null
+++ b/test/mjsunit/wasm/deopt/deopt-memory-access.js
@@ -0,0 +1,56 @@
+// Copyright 2024 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: --wasm-deopt --allow-natives-syntax --turboshaft-wasm
+// Flags: --experimental-wasm-inlining --liftoff
+// Flags: --turboshaft-wasm-instruction-selection-staged
+
+d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
+
+(function TestDeoptMemoryStart() {
+  var builder = new WasmModuleBuilder();
+  let funcRefT = builder.addType(kSig_i_ii);
+
+  builder.addMemory(1, 1);
+
+  builder.addFunction("add", funcRefT)
+    .addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32Add])
+    .exportFunc();
+  builder.addFunction("mul", funcRefT)
+    .addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32Mul])
+    .exportFunc();
+
+
+  let mainSig =
+    makeSig([kWasmI32, kWasmI32, wasmRefType(funcRefT)], [kWasmI32]);
+  builder.addFunction("main", mainSig)
+    .addBody([
+      // Store some value in the memory.
+      kExprI32Const, 24,            // index
+      ...wasmI32Const(0x12345678),  // value
+      kExprI32StoreMem, 0, 0,
+      // Perform the call_ref with potential deopt.
+      kExprLocalGet, 0,
+      kExprLocalGet, 1,
+      kExprLocalGet, 2,
+      kExprCallRef, funcRefT,
+      // Load back the value and check that it's the same.
+      // Note that the cached memory start should have been invalidated by the
+      // call_ref, so this should reload the memory start.
+      kExprI32Const, 24,
+      kExprI32LoadMem, 0, 0,
+      ...wasmI32Const(0x12345678),
+      kExprI32Ne,
+      kExprIf, kWasmVoid,
+        kExprUnreachable,
+      kExprEnd,
+  ]).exportFunc();
+
+  let wasm = builder.instantiate().exports;
+  assertEquals(42, wasm.main(12, 30, wasm.add));
+  %WasmTierUpFunction(wasm.main);
+  assertEquals(42, wasm.main(12, 30, wasm.add));
+  assertTrue(%IsTurboFanFunction(wasm.main));
+  assertEquals(360, wasm.main(12, 30, wasm.mul));
+})();
diff --git a/test/mjsunit/wasm/deopt/deopt-signal-handler.js b/test/mjsunit/wasm/deopt/deopt-signal-handler.js
index 1807272..c585eaa 100644
--- a/test/mjsunit/wasm/deopt/deopt-signal-handler.js
+++ b/test/mjsunit/wasm/deopt/deopt-signal-handler.js
@@ -23,7 +23,8 @@
     .exportFunc();
 
 
-  let mainSig = makeSig([kWasmI32, kWasmI32, wasmRefType(funcRefT)], [kWasmI32]);
+  let mainSig =
+    makeSig([kWasmI32, kWasmI32, wasmRefType(funcRefT)], [kWasmI32]);
   builder.addFunction("main", mainSig)
     .addLocals(kWasmI32, 1)
     .addBody([