Commit 352e81424fe for nodejs

commit 352e81424feef226f04423d48752f0845d616196
Author: Node.js GitHub Bot <github-bot@iojs.org>
Date:   Mon Oct 26 13:50:47 2026 -0400

    deps: patch V8 to 15.6.75.25

    Refs: https://github.com/v8/v8/compare/15.6.75.13...15.6.75.25
    PR-URL: https://github.com/nodejs/node/pull/66820
    Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
    Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
    Reviewed-By: Richard Lau <richard.lau@ibm.com>

diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h
index d47b8f7f5c8..f91b6e7018f 100644
--- a/deps/v8/include/v8-version.h
+++ b/deps/v8/include/v8-version.h
@@ -11,7 +11,7 @@
 #define V8_MAJOR_VERSION 15
 #define V8_MINOR_VERSION 6
 #define V8_BUILD_NUMBER 75
-#define V8_PATCH_LEVEL 13
+#define V8_PATCH_LEVEL 25

 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
diff --git a/deps/v8/src/ast/scopes.cc b/deps/v8/src/ast/scopes.cc
index 7713cd8103d..725f007719d 100644
--- a/deps/v8/src/ast/scopes.cc
+++ b/deps/v8/src/ast/scopes.cc
@@ -345,6 +345,7 @@ void DeclarationScope::SetDefaults() {
                            is_module_scope());
   set_needs_private_name_context_chain_recalc(false);
   set_class_scope_has_private_brand(false);
+  set_class_initializer_allows_await(false);
   receiver_ = nullptr;
   new_target_ = nullptr;
   function_ = nullptr;
@@ -1575,7 +1576,8 @@ bool Scope::NeedsScopeInfo() const {
 }

 bool Scope::ShouldBanArguments() {
-  return GetReceiverScope()->should_ban_arguments();
+  return GetReceiverScope()->should_ban_arguments() &&
+         !GetClosureScope()->from_scope_info();
 }

 DeclarationScope* Scope::GetReceiverScope() {
diff --git a/deps/v8/src/ast/scopes.h b/deps/v8/src/ast/scopes.h
index f85e7420968..fa13cc9a176 100644
--- a/deps/v8/src/ast/scopes.h
+++ b/deps/v8/src/ast/scopes.h
@@ -1387,6 +1387,13 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
     return ClassScopeHasPrivateBrandField::decode(flags_);
   }

+  bool class_initializer_allows_await() const {
+    return ClassInitializerAllowsAwaitField::decode(flags_);
+  }
+  void set_class_initializer_allows_await(bool value) {
+    flags_ = ClassInitializerAllowsAwaitField::update(flags_, value);
+  }
+
  private:
   V8_INLINE void AllocateParameter(Variable* var, int index);

@@ -1430,6 +1437,8 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
       HasThisDeclarationField::Next<bool, 1>;
   using ClassScopeHasPrivateBrandField =
       NeedsPrivateNameContextChainRecalcField::Next<bool, 1>;
+  using ClassInitializerAllowsAwaitField =
+      ClassScopeHasPrivateBrandField::Next<bool, 1>;

 #if DEBUG
   bool is_being_lazily_parsed_;
diff --git a/deps/v8/src/codegen/compiler.cc b/deps/v8/src/codegen/compiler.cc
index fbcf0d8ba77..0a3599ee41c 100644
--- a/deps/v8/src/codegen/compiler.cc
+++ b/deps/v8/src/codegen/compiler.cc
@@ -2852,8 +2852,8 @@ void BackgroundDeserializeTask::Run() {
   LocalHandleScope handle_scope(&isolate);

   DirectHandle<SharedFunctionInfo> inner_result;
-  off_thread_data_ =
-      CodeSerializer::StartDeserializeOffThread(&isolate, &cached_data_);
+  CodeSerializer::StartDeserializeOffThread(&isolate, &cached_data_,
+                                            &off_thread_data_);
   if (v8_flags.enable_slow_asserts && off_thread_data_.HasResult()) {
 #ifdef ENABLE_SLOW_DCHECKS
     MergeAssumptionChecker checker(&isolate, false);
@@ -2866,6 +2866,11 @@ void BackgroundDeserializeTask::SourceTextAvailable(
     Isolate* isolate, Handle<String> source_text,
     const ScriptDetails& script_details) {
   DCHECK_EQ(isolate, isolate_for_local_isolate_);
+  if (!CodeSerializer::NotifySourceTextAvailable(isolate, &off_thread_data_,
+                                                 &cached_data_, source_text,
+                                                 script_details)) {
+    return;
+  }
   LanguageMode language_mode = construct_language_mode(v8_flags.use_strict);
   background_merge_task_.SetUpOnMainThread(isolate, source_text, script_details,
                                            language_mode);
diff --git a/deps/v8/src/codegen/compiler.h b/deps/v8/src/codegen/compiler.h
index 7f8c3152e8a..cfa6af01010 100644
--- a/deps/v8/src/codegen/compiler.h
+++ b/deps/v8/src/codegen/compiler.h
@@ -719,7 +719,7 @@ class V8_EXPORT_PRIVATE BackgroundDeserializeTask {
  private:
   Isolate* isolate_for_local_isolate_;
   AlignedCachedData cached_data_;
-  CodeSerializer::OffThreadDeserializeData off_thread_data_;
+  OffThreadDeserializeData off_thread_data_;
   BackgroundMergeTask background_merge_task_;
   TimedHistogram* timer_;
   int64_t background_time_in_microseconds_ = 0;
diff --git a/deps/v8/src/compiler/common-operator.cc b/deps/v8/src/compiler/common-operator.cc
index 37ab33d7f74..0bc7016d6ab 100644
--- a/deps/v8/src/compiler/common-operator.cc
+++ b/deps/v8/src/compiler/common-operator.cc
@@ -515,6 +515,32 @@ const ExitMachineGraphParameters& ExitMachineGraphParametersOf(
   return OpParameter<ExitMachineGraphParameters>(op);
 }

+#if V8_ENABLE_SANDBOX
+size_t hash_value(const LoadTrustedPointerParameters& params) {
+  return base::hash_combine(params.offset, params.tag);
+}
+
+V8_EXPORT_PRIVATE std::ostream& operator<<(
+    std::ostream& os, LoadTrustedPointerParameters params) {
+  return os << "offset=" << params.offset << ", tag.first=" << params.tag.first
+            << ", tag.last=" << params.tag.last;
+}
+
+class LoadTrustedPointerOperator final
+    : public Operator1<LoadTrustedPointerParameters> {
+ public:
+  LoadTrustedPointerOperator(int offset, IndirectPointerTagRange tag)
+      : Operator1<LoadTrustedPointerParameters>(
+            IrOpcode::kLoadTrustedPointer, Operator::kEliminatable,
+            "LoadTrustedPointer", 1, 1, 1, 1, 1, 0, {offset, tag}) {}
+};
+
+const Operator* CommonOperatorBuilder::LoadTrustedPointer(
+    int offset, IndirectPointerTagRange tag) {
+  return zone_->New<LoadTrustedPointerOperator>(offset, tag);
+}
+#endif  // V8_ENABLE_SANDBOX
+
 #define COMMON_CACHED_OP_LIST(V)                          \
   V(Plug, Operator::kNoProperties, 0, 0, 0, 1, 0, 0)      \
   V(Dead, Operator::kFoldable, 0, 0, 0, 1, 1, 1)          \
diff --git a/deps/v8/src/compiler/common-operator.h b/deps/v8/src/compiler/common-operator.h
index 6499e23637c..3a1188f3574 100644
--- a/deps/v8/src/compiler/common-operator.h
+++ b/deps/v8/src/compiler/common-operator.h
@@ -538,6 +538,20 @@ V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
 V8_EXPORT_PRIVATE const ExitMachineGraphParameters&
 ExitMachineGraphParametersOf(const Operator* op) V8_WARN_UNUSED_RESULT;

+#if V8_ENABLE_SANDBOX
+struct LoadTrustedPointerParameters {
+  int offset;
+  IndirectPointerTagRange tag;
+
+  bool operator==(const LoadTrustedPointerParameters&) const = default;
+};
+
+size_t hash_value(const LoadTrustedPointerParameters& params);
+
+V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
+                                           LoadTrustedPointerParameters params);
+#endif  // V8_ENABLE_SANDBOX
+
 // Interface for building common operators that can be used at any level of IR,
 // including JavaScript, mid-level, and low-level.
 class V8_EXPORT_PRIVATE CommonOperatorBuilder final
@@ -616,6 +630,9 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
   const Operator* HeapConstant(const Handle<HeapObject>&);
   const Operator* CompressedHeapConstant(const Handle<HeapObject>&);
   const Operator* TrustedHeapConstant(const Handle<HeapObject>&);
+#if V8_ENABLE_SANDBOX
+  const Operator* LoadTrustedPointer(int offset, IndirectPointerTagRange tag);
+#endif
   const Operator* ObjectId(uint32_t);

   const Operator* RelocatableInt32Constant(int32_t value,
diff --git a/deps/v8/src/compiler/opcodes.h b/deps/v8/src/compiler/opcodes.h
index de11918ad13..d74406bfe7b 100644
--- a/deps/v8/src/compiler/opcodes.h
+++ b/deps/v8/src/compiler/opcodes.h
@@ -85,15 +85,16 @@
   V(EnterMachineGraph)      \
   V(ExitMachineGraph)

-#define COMMON_OP_LIST(V)      \
-  CONSTANT_OP_LIST(V)          \
-  INNER_OP_LIST(V)             \
-  V(Unreachable)               \
-  V(DeadValue)                 \
-  V(Dead)                      \
-  V(Plug)                      \
-  V(SLVerifierHint)            \
-  V(MajorGCForCompilerTesting) \
+#define COMMON_OP_LIST(V)           \
+  CONSTANT_OP_LIST(V)               \
+  INNER_OP_LIST(V)                  \
+  V(Unreachable)                    \
+  V(DeadValue)                      \
+  V(Dead)                           \
+  V(Plug)                           \
+  V(SLVerifierHint)                 \
+  V(MajorGCForCompilerTesting)      \
+  IF_SANDBOX(V, LoadTrustedPointer) \
   V(StaticAssert)

 // Opcodes for JavaScript operators.
diff --git a/deps/v8/src/compiler/simplified-lowering-verifier.cc b/deps/v8/src/compiler/simplified-lowering-verifier.cc
index d288ed102b0..6d41bbb8a32 100644
--- a/deps/v8/src/compiler/simplified-lowering-verifier.cc
+++ b/deps/v8/src/compiler/simplified-lowering-verifier.cc
@@ -504,6 +504,7 @@ void SimplifiedLoweringVerifier::VisitNode(Node* node,
       CASE(Dead)
       CASE(Plug)
       CASE(MajorGCForCompilerTesting)
+      IF_SANDBOX(CASE, LoadTrustedPointer)
       CASE(StaticAssert)
       // Simplified change operators
       CASE(ChangeTaggedSignedToInt32)
diff --git a/deps/v8/src/compiler/turbofan-typer.cc b/deps/v8/src/compiler/turbofan-typer.cc
index 16fa4b6c443..04df6121129 100644
--- a/deps/v8/src/compiler/turbofan-typer.cc
+++ b/deps/v8/src/compiler/turbofan-typer.cc
@@ -1297,6 +1297,9 @@ Type Typer::Visitor::TypeMajorGCForCompilerTesting(Node* node) {
   UNREACHABLE();
 }
 Type Typer::Visitor::TypeStaticAssert(Node* node) { UNREACHABLE(); }
+#if V8_ENABLE_SANDBOX
+Type Typer::Visitor::TypeLoadTrustedPointer(Node* node) { UNREACHABLE(); }
+#endif
 Type Typer::Visitor::TypeSLVerifierHint(Node* node) { UNREACHABLE(); }

 // JS comparison operators.
diff --git a/deps/v8/src/compiler/turboshaft/graph-builder.cc b/deps/v8/src/compiler/turboshaft/graph-builder.cc
index 4864bf773c5..5866bba154e 100644
--- a/deps/v8/src/compiler/turboshaft/graph-builder.cc
+++ b/deps/v8/src/compiler/turboshaft/graph-builder.cc
@@ -1434,6 +1434,14 @@ OpIndex GraphBuilder::Process(
       return __ Load(Map(node->InputAt(0)), Map(node->InputAt(1)),
                      LoadOp::Kind::Trapping(), loaded_rep);
     }
+#if V8_ENABLE_SANDBOX
+    case IrOpcode::kLoadTrustedPointer: {
+      auto params = OpParameter<LoadTrustedPointerParameters>(op);
+      return __ LoadTrustedPointer(Map(node->InputAt(0)),
+                                   LoadOp::Kind::TaggedBase(), params.tag,
+                                   params.offset + kHeapObjectTag);
+    }
+#endif

     case IrOpcode::kStore:
     case IrOpcode::kUnalignedStore: {
diff --git a/deps/v8/src/compiler/verifier.cc b/deps/v8/src/compiler/verifier.cc
index a4787d8391b..39d2dbced49 100644
--- a/deps/v8/src/compiler/verifier.cc
+++ b/deps/v8/src/compiler/verifier.cc
@@ -653,6 +653,11 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
     case IrOpcode::kExitMachineGraph:
       CheckValueInputIs(node, 0, Type::Machine());
       break;
+#if V8_ENABLE_SANDBOX
+    case IrOpcode::kLoadTrustedPointer:
+      // TODO(manoskouk): what are the constraints here?
+      break;
+#endif

     // JavaScript operators
     // --------------------
diff --git a/deps/v8/src/compiler/wasm-graph-assembler.cc b/deps/v8/src/compiler/wasm-graph-assembler.cc
index c5c4dd9160d..f4e55a54a11 100644
--- a/deps/v8/src/compiler/wasm-graph-assembler.cc
+++ b/deps/v8/src/compiler/wasm-graph-assembler.cc
@@ -242,55 +242,6 @@ Node* WasmGraphAssembler::BuildDecodeSandboxedExternalPointer(
 #endif  // V8_ENABLE_SANDBOX
 }

-Node* WasmGraphAssembler::BuildDecodeTrustedPointer(
-    Node* handle, IndirectPointerTagRange tag_range) {
-#if V8_ENABLE_SANDBOX
-  Node* index = Word32Shr(handle, Int32Constant(kTrustedPointerHandleShift));
-  Node* offset = ChangeUint32ToUint64(
-      Word32Shl(index, Int32Constant(kTrustedPointerTableEntrySizeLog2)));
-  Node* table = Load(MachineType::Pointer(), LoadRootRegister(),
-                     IsolateData::trusted_pointer_table_offset() +
-                         Internals::kExternalEntityTableBasePointerOffset);
-  Node* decoded_ptr = Load(MachineType::Pointer(), table, offset);
-
-  if (IsFastIndirectPointerTagRange(tag_range)) {
-    uint64_t mask = ComputeUntaggingMaskForFastIndirectPointerTag(tag_range);
-    decoded_ptr = WordAnd(decoded_ptr, IntPtrConstant(mask));
-  } else {
-    Node* tag =
-        WordShr(decoded_ptr, IntPtrConstant(kTrustedPointerTableTagShift));
-
-    auto ok = MakeLabel();
-    if (tag_range.Size() == 1) {
-      // The common and simple case: we expect exactly one tag.
-      Node* expected_tag = IntPtrConstant(tag_range.first);
-      GotoIf(WordEqual(tag, expected_tag), &ok, BranchHint::kTrue);
-      RuntimeAbort(AbortReason::kIndirectPointerTagMismatch);
-      Goto(&ok);  // Unreachable, but needed for graph coherency.
-    } else {
-      // Range check.
-      Node* diff = IntPtrSub(tag, IntPtrConstant(tag_range.first));
-      GotoIf(Uint64LessThanOrEqual(
-                 diff, IntPtrConstant(tag_range.last - tag_range.first)),
-             &ok, BranchHint::kTrue);
-      RuntimeAbort(AbortReason::kIndirectPointerTagMismatch);
-      Goto(&ok);  // Unreachable, but needed for graph coherency.
-    }
-
-    Bind(&ok);
-    decoded_ptr =
-        WordAnd(decoded_ptr, IntPtrConstant(kTrustedPointerTablePayloadMask));
-  }
-
-  // We have to change the type of the result value to Tagged, so if the value
-  // gets spilled on the stack, it will get processed by the GC.
-  decoded_ptr = BitcastWordToTagged(decoded_ptr);
-  return decoded_ptr;
-#else
-  UNREACHABLE();
-#endif  // V8_ENABLE_SANDBOX
-}
-
 Node* WasmGraphAssembler::BuildLoadExternalPointerFromObject(
     Node* object, int field_offset, ExternalPointerTagRange tag_range,
     Node* isolate_root) {
@@ -408,38 +359,14 @@ Node* WasmGraphAssembler::LoadByteArrayElement(Node* byte_array,
   return LoadFromObject(type, byte_array, offset);
 }

-Node* WasmGraphAssembler::LoadImmutableTrustedPointerFromObject(
-    Node* object, int field_offset, IndirectPointerTagRange tag) {
-  Node* offset = IntPtrConstant(field_offset);
-#ifdef V8_ENABLE_SANDBOX
-  Node* handle = LoadImmutableFromObject(MachineType::Uint32(), object, offset);
-  return BuildDecodeTrustedPointer(handle, tag);
-#else
-  return LoadImmutableFromObject(MachineType::TaggedPointer(), object, offset);
-#endif
-}
-
 Node* WasmGraphAssembler::LoadTrustedPointerFromObject(
     Node* object, int field_offset, IndirectPointerTagRange tag) {
-  Node* offset = IntPtrConstant(field_offset);
 #ifdef V8_ENABLE_SANDBOX
-  Node* handle = LoadFromObject(MachineType::Uint32(), object, offset);
-  return BuildDecodeTrustedPointer(handle, tag);
+  return AddNode(graph()->NewNode(common_.LoadTrustedPointer(field_offset, tag),
+                                  object, effect(), control()));
 #else
-  return LoadFromObject(MachineType::TaggedPointer(), object, offset);
-#endif
-}
-
-std::pair<Node*, Node*>
-WasmGraphAssembler::LoadTrustedPointerFromObjectTrapOnNull(
-    Node* object, int field_offset, IndirectPointerTagRange tag) {
   Node* offset = IntPtrConstant(field_offset);
-#ifdef V8_ENABLE_SANDBOX
-  Node* handle = LoadTrapOnNull(MachineType::Uint32(), object, offset);
-  return {handle, BuildDecodeTrustedPointer(handle, tag)};
-#else
-  Node* value = LoadTrapOnNull(MachineType::TaggedPointer(), object, offset);
-  return {value, value};
+  return LoadFromObject(MachineType::TaggedPointer(), object, offset);
 #endif
 }

@@ -465,7 +392,7 @@ Node* WasmGraphAssembler::LoadContextNoCellFromJSFunction(Node* js_function) {

 Node* WasmGraphAssembler::LoadFunctionDataFromJSFunction(Node* js_function) {
   Node* shared = LoadSharedFunctionInfo(js_function);
-  return LoadImmutableTrustedPointerFromObject(
+  return LoadTrustedPointerFromObject(
       shared,
       offsetof(SharedFunctionInfo, trusted_function_data_) - kHeapObjectTag,
       kWasmExportedFunctionDataIndirectPointerTag);
@@ -624,7 +551,7 @@ Node* WasmGraphAssembler::StringPrepareForGetCodeunit(Node* string) {

 Node* WasmGraphAssembler::LoadTrustedDataFromInstanceObject(
     Node* instance_object) {
-  return LoadImmutableTrustedPointerFromObject(
+  return LoadTrustedPointerFromObject(
       instance_object,
       offsetof(WasmInstanceObject, trusted_data_) - kHeapObjectTag,
       kWasmTrustedInstanceDataIndirectPointerTag);
diff --git a/deps/v8/src/compiler/wasm-graph-assembler.h b/deps/v8/src/compiler/wasm-graph-assembler.h
index f10e0205091..0737d7999e7 100644
--- a/deps/v8/src/compiler/wasm-graph-assembler.h
+++ b/deps/v8/src/compiler/wasm-graph-assembler.h
@@ -28,7 +28,8 @@ class WasmGraphAssembler : public GraphAssembler {
  public:
   WasmGraphAssembler(MachineGraph* mcgraph, Zone* zone)
       : GraphAssembler(mcgraph, zone, BranchSemantics::kMachine),
-        simplified_(zone) {}
+        simplified_(zone),
+        common_(zone) {}

   // While CallBuiltin() translates to a direct call to the address of the
   // builtin, CallBuiltinThroughJumptable instead jumps to a slot in a jump
@@ -177,15 +178,8 @@ class WasmGraphAssembler : public GraphAssembler {
                                            ExternalPointerTagRange tag_range,
                                            Node* isolate_root);

-  Node* LoadImmutableTrustedPointerFromObject(Node* object, int offset,
-                                              IndirectPointerTagRange tag);
   Node* LoadTrustedPointerFromObject(Node* object, int offset,
                                      IndirectPointerTagRange tag);
-  // Returns the load node (where the source position for the trap needs to be
-  // set by the caller) and the result.
-  std::pair<Node*, Node*> LoadTrustedPointerFromObjectTrapOnNull(
-      Node* object, int offset, IndirectPointerTagRange tag);
-  Node* BuildDecodeTrustedPointer(Node* handle, IndirectPointerTagRange tag);

   Node* IsSmi(Node* object);

@@ -345,6 +339,7 @@ class WasmGraphAssembler : public GraphAssembler {
   }

   SimplifiedOperatorBuilder simplified_;
+  CommonOperatorBuilder common_;
 };

 }  // namespace compiler
diff --git a/deps/v8/src/execution/frames.cc b/deps/v8/src/execution/frames.cc
index 51055f12e0c..12cadd23272 100644
--- a/deps/v8/src/execution/frames.cc
+++ b/deps/v8/src/execution/frames.cc
@@ -1903,10 +1903,35 @@ void WasmFrame::Iterate(RootVisitor* v) const {
   bool has_tagged_outgoing_params =
       wasm_code->kind() != wasm::WasmCode::kWasmFunction &&
       wasm_code->kind() != wasm::WasmCode::kWasmToCapiWrapper;
-  if (!InFastCCall() && has_tagged_outgoing_params) {
-    FullObjectSlot parameters_base(&Memory<Address>(sp()));
-    v->VisitRootPointers(Root::kStackRoots, nullptr, parameters_base,
-                         parameters_limit);
+  if (!InFastCCall()) {
+    if (has_tagged_outgoing_params) {
+      FullObjectSlot parameters_base(&Memory<Address>(sp()));
+      v->VisitRootPointers(Root::kStackRoots, nullptr, parameters_base,
+                           parameters_limit);
+    } else if (wasm_code->kind() == wasm::WasmCode::kWasmFunction &&
+               callee_pc() != kNullAddress) {
+      // If a Wasm function calls a builtin with tagged stack parameters,
+      // visit those parameters. (Calls to other Wasm functions or to
+      // WasmToJsWrapperCSA have their tagged stack parameters visited by the
+      // callee frame instead.)
+      Builtin builtin =
+          OffHeapInstructionStream::TryLookupCode(isolate(), callee_pc());
+      if (Builtins::IsBuiltinId(builtin)) {
+        CallInterfaceDescriptor descriptor =
+            Builtins::CallInterfaceDescriptorFor(builtin);
+        DCHECK(!descriptor.AllowVarArgs());
+        if (!(descriptor.flags() & CallInterfaceDescriptorData::kNoStackScan)) {
+          int stack_params = descriptor.GetStackParameterCount();
+          DCHECK_IMPLIES(builtin == Builtin::kWasmToJsWrapperCSA,
+                         stack_params == 0);
+          if (stack_params > 0) {
+            FullObjectSlot parameters_base(&Memory<Address>(sp()));
+            v->VisitRootPointers(Root::kStackRoots, nullptr, parameters_base,
+                                 parameters_base + stack_params);
+          }
+        }
+      }
+    }
   }

   // Visit pointer spill slots and locals.
diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc
index 7ae7d8f99d0..681dac659f1 100644
--- a/deps/v8/src/ic/ic.cc
+++ b/deps/v8/src/ic/ic.cc
@@ -1760,17 +1760,6 @@ KeyedAccessLoadMode GetUpdatedLoadModeForMap(Isolate* isolate,
 Handle<Object> KeyedLoadIC::LoadElementHandler(
     DirectHandle<Map> receiver_map, KeyedAccessLoadMode new_load_mode,
     MaybeDirectHandle<Map> maybe_transition_target) {
-  // Has a getter interceptor, or is any has and has a query interceptor.
-  if (receiver_map->has_indexed_interceptor() &&
-      (receiver_map->GetIndexedInterceptor()->has_getter() ||
-       (IsAnyHas() && receiver_map->GetIndexedInterceptor()->has_query())) &&
-      !receiver_map->GetIndexedInterceptor()->non_masking()) {
-    // TODO(jgruber): Update counter name.
-    TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedInterceptorStub);
-    return IsAnyHas() ? BUILTIN_CODE(isolate(), HasIndexedInterceptorIC)
-                      : BUILTIN_CODE(isolate(), LoadIndexedInterceptorIC);
-  }
-
   InstanceType instance_type = receiver_map->instance_type();
   if (instance_type < FIRST_NONSTRING_TYPE) {
     TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedStringDH);
@@ -1784,6 +1773,23 @@ Handle<Object> KeyedLoadIC::LoadElementHandler(
   if (instance_type == JS_PROXY_TYPE) {
     return LoadHandler::LoadProxy(isolate());
   }
+  if (receiver_map->is_access_check_needed()) {
+    TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_SlowStub);
+    return LoadHandler::LoadSlow(isolate());
+  }
+
+  // Has a getter interceptor, or is any has and has a query interceptor.
+  if (receiver_map->has_indexed_interceptor() &&
+      (receiver_map->GetIndexedInterceptor()->has_getter() ||
+       (IsAnyHas() && receiver_map->GetIndexedInterceptor()->has_query())) &&
+      !receiver_map->GetIndexedInterceptor()->non_masking()) {
+    DCHECK(!receiver_map->is_access_check_needed());
+    // TODO(jgruber): Update counter name.
+    TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedInterceptorStub);
+    return IsAnyHas() ? BUILTIN_CODE(isolate(), HasIndexedInterceptorIC)
+                      : BUILTIN_CODE(isolate(), LoadIndexedInterceptorIC);
+  }
+
 #if V8_ENABLE_WEBASSEMBLY
   if (InstanceTypeChecker::IsWasmObject(instance_type)) {
     // TODO(jgruber): Update counter name.
@@ -2870,7 +2876,8 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
 Handle<Object> KeyedStoreIC::StoreElementHandler(
     DirectHandle<Map> receiver_map, KeyedAccessStoreMode store_mode,
     MaybeDirectHandle<UnionOf<Smi, Cell>> prev_validity_cell) {
-  if (!IsJSObjectMap(*receiver_map)) {
+  if (!IsJSObjectMap(*receiver_map) || receiver_map->is_access_check_needed() ||
+      receiver_map->IsMapInArrayPrototypeChain(isolate())) {
     // DefineKeyedOwnIC, which is used to define computed fields in instances,
     // should handled by the slow stub below instead of the proxy stub.
     if (IsJSProxyMap(*receiver_map) && !IsDefineKeyedOwnIC()) {
diff --git a/deps/v8/src/maglev/maglev-graph-builder.cc b/deps/v8/src/maglev/maglev-graph-builder.cc
index b0bca8d4128..ca199bab0fa 100644
--- a/deps/v8/src/maglev/maglev-graph-builder.cc
+++ b/deps/v8/src/maglev/maglev-graph-builder.cc
@@ -9110,16 +9110,21 @@ MaglevGraphBuilder::BuildJSArrayBuiltinMapSwitchOnElementsKind(
         sub_graph.GotoOrTrim(&*object_case);
         sub_graph.Bind(&*object_case);
       }
-      any_successful |= (!build_kind_specific(kind).IsDoneWithAbort());
+      ReduceResult result = build_kind_specific(kind);
       if (IsSmiElementsKind(kind) && make_smi_fallthrough_to_object) {
         // After building the SMI specific parts (see build_kind_specific call
         // above), jump to the beginning of the case for the object elements
         // kind.
         DCHECK(object_case.has_value());
         sub_graph.GotoOrTrim(&*object_case);
+
+        // Whether the Smi case is successful depends on whether the object case
+        // is successful, so don't update any_successful here.
       } else {
         DCHECK(do_return.has_value());
         sub_graph.GotoOrTrim(&*do_return);
+
+        any_successful |= !result.IsDoneWithAbort();
       }
       sub_graph.Bind(&check_next_map);
     } else {
@@ -16971,11 +16976,11 @@ void MaglevGraphBuilder::ProcessMergePointPredecessors(
   ResetBuilderCachedState();

   if (merge_state.is_loop()) {
-    DCHECK_EQ(merge_state.predecessors_so_far(),
-              merge_state.predecessor_count() - 1);
+    CHECK_EQ(merge_state.predecessors_so_far(),
+             merge_state.predecessor_count() - 1);
   } else {
-    DCHECK_EQ(merge_state.predecessors_so_far(),
-              merge_state.predecessor_count());
+    CHECK_EQ(merge_state.predecessors_so_far(),
+             merge_state.predecessor_count());
   }

   if (merge_state.predecessor_count() == 1) {
diff --git a/deps/v8/src/maglev/maglev-graph-optimizer.cc b/deps/v8/src/maglev/maglev-graph-optimizer.cc
index 8f5ec525e29..a78420a1338 100644
--- a/deps/v8/src/maglev/maglev-graph-optimizer.cc
+++ b/deps/v8/src/maglev/maglev-graph-optimizer.cc
@@ -688,11 +688,54 @@ ValueNode* MaglevGraphOptimizer::GetConstantWithRepresentation(
   }
 }

+namespace {
+
+// Returns the type check that `alt` is guaranteed to have already performed
+// on its tagged input node.
+NodeType GuaranteedInputType(UseRepresentation repr, ValueNode* alt) {
+  switch (repr) {
+    case UseRepresentation::kInt32:
+    case UseRepresentation::kFloat64:
+      return NodeType::kNumber;
+    case UseRepresentation::kHoleyFloat64:
+      return NodeType::kNumberOrUndefined;
+    // Unlike Int32/Float64, a Truncate node doesn't have a single fixed check,
+    // it depends on its assumed_input_type.
+    case UseRepresentation::kTruncatedInt32:
+      if (auto* t = alt->TryCast<TruncateCheckedNumberOrOddballToInt32>()) {
+        return t->assumed_input_type();
+      }
+      if (auto* t = alt->TryCast<TruncateUnsafeNumberOrOddballToInt32>()) {
+        return t->assumed_input_type();
+      }
+      return NodeType::kNumberOrOddball;
+    case UseRepresentation::kTagged:
+    case UseRepresentation::kTaggedForNumberToString:
+    case UseRepresentation::kUint32:
+    case UseRepresentation::kNonTruncated:
+      UNREACHABLE();
+  }
+  UNREACHABLE();
+}
+
+}  // namespace
+
+bool MaglevGraphOptimizer::CanReuseAlternative(
+    ValueNode* node, ValueNode* alt, UseRepresentation repr,
+    std::optional<NodeType> assumed_input_type) {
+  if (!assumed_input_type.has_value()) return true;
+  // We cannot replace a stricter check with a weaker one, as subsequent
+  // operations might rely on this node to deopt invalid inputs.
+  return reducer_.CheckType(node, *assumed_input_type) ||
+         NodeTypeIs(GuaranteedInputType(repr, alt), *assumed_input_type);
+}
+
 MaybeReduceResult MaglevGraphOptimizer::GetUntaggedValueWithRepresentation(
     ValueNode* node, UseRepresentation use_repr,
     std::optional<NodeType> assumed_input_type) {
   DCHECK_NE(use_repr, UseRepresentation::kTagged);
-  if (node->value_representation() == ValueRepresentationFromUse(use_repr)) {
+  if (node->value_representation() == ValueRepresentationFromUse(use_repr) &&
+      CanReuseAlternative(node, node, use_repr, assumed_input_type)) {
     return node;
   }
   if (node->Is<ReturnedValue>()) {
@@ -710,8 +753,11 @@ MaybeReduceResult MaglevGraphOptimizer::GetUntaggedValueWithRepresentation(
     // Check if we already have a canonical conversion.
     NodeInfo* node_info =
         known_node_aspects().GetOrCreateInfoFor(broker(), node);
-    auto& alternative = node_info->alternative();
-    if (ValueNode* alt = alternative.get(use_repr)) return alt;
+    if (ValueNode* alternative = node_info->alternative().get(use_repr);
+        alternative &&
+        CanReuseAlternative(node, alternative, use_repr, assumed_input_type)) {
+      return alternative;
+    }
     // If `node` is itself tagging an untagged value, convert that value
     // directly instead of untagging the tagged result.
     if (node->is_conversion()) {
@@ -726,6 +772,15 @@ MaybeReduceResult MaglevGraphOptimizer::GetUntaggedValueWithRepresentation(
   if (!CanEagerDeopt()) {
     return {};
   }
+  if (node->is_holey_float64() && assumed_input_type.has_value() &&
+      NodeTypeIs(*assumed_input_type, NodeType::kNumberOrBoolean)) {
+    // HoleyFloat64 can hold the hole or undefined, whereas the replaced node
+    // checked that the input is a number (or boolean, which cannot occur in
+    // HoleyFloat64). Convert to Float64 first so CheckedHoleyFloat64ToFloat64
+    // preserves the check that subsequent operations may rely on.
+    GET_VALUE_OR_ABORT(
+        node, reducer_.GetFloat64ForToNumber(node, *assumed_input_type));
+  }
   switch (use_repr) {
     case UseRepresentation::kInt32:
       return reducer_.GetInt32(node);
diff --git a/deps/v8/src/maglev/maglev-graph-optimizer.h b/deps/v8/src/maglev/maglev-graph-optimizer.h
index f41212a81ab..7e98d1059f2 100644
--- a/deps/v8/src/maglev/maglev-graph-optimizer.h
+++ b/deps/v8/src/maglev/maglev-graph-optimizer.h
@@ -150,6 +150,12 @@ class V8_EXPORT_PRIVATE MaglevGraphOptimizer {
       ValueNode* node, UseRepresentation repr,
       std::optional<NodeType> assumed_input_type);

+  // Returns true if reusing the cached conversion 'alt' safely preserves all
+  // required type checks for 'node'.
+  bool CanReuseAlternative(ValueNode* node, ValueNode* alt,
+                           UseRepresentation repr,
+                           std::optional<NodeType> assumed_input_type);
+
   // Records the untagged input of a tagging conversion as the matching
   // untagged alternative of `tagged`, so a later untagging use can reuse it.
   template <ValueRepresentation kRepresentation>
diff --git a/deps/v8/src/maglev/maglev-known-node-aspects.cc b/deps/v8/src/maglev/maglev-known-node-aspects.cc
index f4abfca2495..63895d1f5f0 100644
--- a/deps/v8/src/maglev/maglev-known-node-aspects.cc
+++ b/deps/v8/src/maglev/maglev-known-node-aspects.cc
@@ -652,22 +652,22 @@ void KnownNodeAspects::ClearUnstableNodeAspectsForStoreMap(
     StoreMap* node, bool is_tracing_enabled) {
   if (!node->is_transitioning()) return;

-  if (NodeInfo* node_info = TryGetInfoFor(node->ValueInput().node())) {
-    if (node_info->possible_maps_are_known() && !node_info->maps_are_stale() &&
-        node_info->possible_maps().size() == 1) {
-      compiler::MapRef old_map = node_info->possible_maps().at(0);
-      auto MaybeAliases = [&](compiler::MapRef map) -> bool {
-        return map.equals(old_map);
-      };
-      // Mark aliasing maps as stale.
-      if (MarkMapsStaleIfAny(MaybeAliases)) {
-        if (V8_UNLIKELY(v8_flags.trace_maglev_kna && is_tracing_enabled)) {
-          std::cout << kRed << "[KNA] StoreMap: Invalidate alias "
-                    << Brief(*old_map.object()) << kReset << std::endl;
-        }
-      }
-      return;
-    }
+  if (MarkSingleMapAsStale(node->ValueInput().node(), is_tracing_enabled)) {
+    return;
+  }
+
+  // TODO(olivf): Only invalidate nodes with the same type.
+  OnSideEffect();
+  if (V8_UNLIKELY(v8_flags.trace_maglev_kna && is_tracing_enabled)) {
+    std::cout << kRed << "[KNA] StoreMap: Invalidate all unstable maps"
+              << kReset << std::endl;
+  }
+}
+
+void KnownNodeAspects::ClearUnstableNodeAspectsForMigration(
+    Node* node, bool is_tracing_enabled) {
+  if (MarkSingleMapAsStale(node->input_node(0), is_tracing_enabled)) {
+    return;
   }

   // TODO(olivf): Only invalidate nodes with the same type.
@@ -1009,6 +1009,28 @@ KnownNodeAspects::ContextStoreResult KnownNodeAspects::RecordContextSlotStore(
   return {ContextStoreResult::kSetNewValue, std::move(aliased_slots)};
 }

+bool KnownNodeAspects::MarkSingleMapAsStale(ValueNode* node,
+                                            bool is_tracing_enabled) {
+  if (NodeInfo* node_info = TryGetInfoFor(node)) {
+    if (node_info->possible_maps_are_known() && !node_info->maps_are_stale() &&
+        node_info->possible_maps().size() == 1) {
+      compiler::MapRef old_map = node_info->possible_maps().at(0);
+      auto MaybeAliases = [&](compiler::MapRef map) -> bool {
+        return map.equals(old_map);
+      };
+      // Mark aliasing maps as stale.
+      if (MarkMapsStaleIfAny(MaybeAliases)) {
+        if (V8_UNLIKELY(v8_flags.trace_maglev_kna && is_tracing_enabled)) {
+          std::cout << kRed << "[KNA]: MarkSingleMapAsStale: Invalidate alias "
+                    << Brief(*old_map.object()) << kReset << std::endl;
+        }
+      }
+      return true;
+    }
+  }
+  return false;
+}
+
 #ifdef DEBUG
 bool IsStringRootIndex(RootIndex index) {
   if (index > RootIndex::kLastReadOnlyRoot) return false;
diff --git a/deps/v8/src/maglev/maglev-known-node-aspects.h b/deps/v8/src/maglev/maglev-known-node-aspects.h
index b7f03911366..dd1ce8cc385 100644
--- a/deps/v8/src/maglev/maglev-known-node-aspects.h
+++ b/deps/v8/src/maglev/maglev-known-node-aspects.h
@@ -407,6 +407,8 @@ class KnownNodeAspects {

   void ClearUnstableNodeAspectsForStoreMap(StoreMap* node,
                                            bool is_tracing_enabled);
+  void ClearUnstableNodeAspectsForMigration(Node* node,
+                                            bool is_tracing_enabled);
   void ClearUnstableNodeAspectsForElementsTransition(
       const ZoneVector<compiler::MapRef>& transition_sources,
       bool is_tracing_enabled);
@@ -824,8 +826,7 @@ class KnownNodeAspects {
                          std::is_same_v<NodeT,
                                         CheckMapsWithMigrationAndDeopt> ||
                          std::is_same_v<NodeT, MigrateMapIfNeeded>) {
-      // These instructions only migrate representations of values, not the
-      // values themselves, so cached values are still valid.
+      ClearUnstableNodeAspectsForMigration(node, is_tracing_enabled);
     } else if constexpr (std::is_same_v<NodeT, StoreMap>) {
       ClearUnstableNodeAspectsForStoreMap(node, is_tracing_enabled);
     } else if constexpr (std::is_same_v<NodeT, TransitionElementsKind> ||
@@ -910,6 +911,8 @@ class KnownNodeAspects {
   SmallZoneVector<LoadedContextSlotsKey, 8> ClearAliasedContextSlotsFor(
       Graph* graph, ValueNode* context, int offset, ValueNode* value);

+  bool MarkSingleMapAsStale(ValueNode* node, bool is_tracing_enabled);
+
   static constexpr uint32_t kEffectEpochForPureInstructions =
       std::numeric_limits<uint32_t>::max();
   static constexpr uint32_t kEffectEpochOverflow =
diff --git a/deps/v8/src/maglev/maglev-phi-representation-selector.cc b/deps/v8/src/maglev/maglev-phi-representation-selector.cc
index eff255ed43c..5b44744d9e9 100644
--- a/deps/v8/src/maglev/maglev-phi-representation-selector.cc
+++ b/deps/v8/src/maglev/maglev-phi-representation-selector.cc
@@ -1074,7 +1074,7 @@ ValueNode* MaglevPhiRepresentationSelector::GetReplacementForPhiInputConversion(
 }

 ProcessResult MaglevPhiRepresentationSelector::UpdateUntaggingOfPhi(
-    Phi* phi, ValueNode* old_untagging) {
+    Phi* phi, ValueNode* old_untagging, const ProcessingState* state) {
   DCHECK_EQ(old_untagging->input_count(), 1);
   DCHECK(old_untagging->input(0).node()->Is<Phi>());

@@ -1192,24 +1192,27 @@ ProcessResult MaglevPhiRepresentationSelector::UpdateUntaggingOfPhi(
   if (old_untagging->Is<TruncateUnsafeNumberOrOddballToInt32>()) {
     conversion_is_truncating_float64 = true;
   } else if (old_untagging->Is<TruncateCheckedNumberOrOddballToInt32>()) {
-    if (from_repr == ValueRepresentation::kFloat64) {
-      // If {from_repr} is Float64, then the "CheckedNumber" part is
-      // guaranteed to pass and this operation just truncates its value to
-      // Int32.
-      conversion_is_truncating_float64 = true;
-    } else {
-      DCHECK_EQ(from_repr, ValueRepresentation::kHoleyFloat64);
+    if (from_repr == ValueRepresentation::kHoleyFloat64) {
       const auto* truncate =
           old_untagging->Cast<TruncateCheckedNumberOrOddballToInt32>();
       // A HoleyFloat64 hole really means Undefined rather than the_hole:
       // whenever it gets rematerialized, it will always be rematerialized as
-      // Undefined. So, we can use a truncating conversion as long as the
-      // original assumed input type was allowing truncating Undefined.
-      // Assumptions without Undefined need to deopt for Hole/Undefined
-      // ==> not truncating.
-      conversion_is_truncating_float64 = !NodeTypeIs(
-          truncate->assumed_input_type(), NodeType::kNumberOrBoolean);
+      // Undefined. Assumptions without Undefined need to deopt on
+      // Hole/Undefined before truncating the Float64 value to Int32.
+      if (!NodeTypeCanBe(truncate->assumed_input_type(),
+                         NodeType::kUndefined)) {
+        eager_deopt_frame_ = &old_untagging->eager_deopt_info()->top_frame();
+        AddNewNodeNoInputConversion<CheckHoleyFloat64NotHoleOrUndefined>(
+            reducer_.current_block(),
+            BasicBlockPosition::At(state->node_index()), {phi});
+#ifdef DEBUG
+        eager_deopt_frame_ = nullptr;
+#endif  // DEBUG
+      }
+    } else {
+      DCHECK_EQ(from_repr, ValueRepresentation::kFloat64);
     }
+    conversion_is_truncating_float64 = true;
   }

   Opcode needed_conversion = GetOpcodeForConversion(
diff --git a/deps/v8/src/maglev/maglev-phi-representation-selector.h b/deps/v8/src/maglev/maglev-phi-representation-selector.h
index 5ecca6b95f2..3007727a099 100644
--- a/deps/v8/src/maglev/maglev-phi-representation-selector.h
+++ b/deps/v8/src/maglev/maglev-phi-representation-selector.h
@@ -206,7 +206,7 @@ class MaglevPhiRepresentationSelector {
       // removed altogether (or rather, replaced by an identity node).
       return UpdateUntaggingOfPhi(
           node->NodeBase::input(0).node()->template Cast<Phi>(),
-          node->template Cast<ValueNode>());
+          node->template Cast<ValueNode>(), state);
     }
     return ProcessResult::kContinue;
   }
@@ -273,7 +273,8 @@ class MaglevPhiRepresentationSelector {

   // Updates {old_untagging} to reflect that its Phi input has been untagged and
   // that a different conversion is now needed.
-  ProcessResult UpdateUntaggingOfPhi(Phi* phi, ValueNode* old_untagging);
+  ProcessResult UpdateUntaggingOfPhi(Phi* phi, ValueNode* old_untagging,
+                                     const ProcessingState* state);

   ProcessResult EmitUnconditionalDeopt(NodeBase* node, DeoptimizeReason reason);

diff --git a/deps/v8/src/maglev/maglev-range-analysis.h b/deps/v8/src/maglev/maglev-range-analysis.h
index 51744959af0..57d415f06ed 100644
--- a/deps/v8/src/maglev/maglev-range-analysis.h
+++ b/deps/v8/src/maglev/maglev-range-analysis.h
@@ -67,6 +67,18 @@ class NodeRanges {
     return *range;
   }

+  void InitializeRangeIfMissing(BasicBlock* block, ValueNode* node,
+                                Range range) {
+    DCHECK(ranges_initialized_.Contains(block->id()));
+    RangeMap& map = ranges_[block->id()];
+    if (!map.find(node)) {
+      map = map.insert(zone(), node, range);
+      TRACE_RANGE("Initializing in Block b" << block->id() << ": "
+                                            << PrintNodeBrief(node) << ": "
+                                            << range);
+    }
+  }
+
   void UnionUpdate(BasicBlock* block, ValueNode* node, Range range) {
     DCHECK(ranges_initialized_.Contains(block->id()));
     RangeMap& map = ranges_[block->id()];
@@ -210,6 +222,15 @@ class RangeProcessor {
   BlockProcessResult PreProcessBasicBlock(BasicBlock* block) {
     current_block_ = block;
     ranges_.EnsureMapExistsFor(block);
+    if (block->has_state() && block->state()->is_resumable_loop() &&
+        block->predecessor_count() == 1) {
+      // Resumable loop headers might not have a live forward predecessor: that
+      // part of the code might be dead even though the loop is still reachable
+      // via a resume point. Make sure we initialize phis in such case. If the
+      // loop has a live predecessor, ProcessPhis is called when processing that
+      // live predecessor, and this code is a no-op.
+      InitializeLoopPhisIfMissing(block);
+    }
     return BlockProcessResult::kContinue;
   }
   BlockProcessResult PostProcessBasicBlock(BasicBlock* block) {
@@ -543,6 +564,14 @@ class RangeProcessor {
     }
   }

+  void InitializeLoopPhisIfMissing(BasicBlock* block) {
+    if (!block->has_phi()) return;
+    for (Phi* phi : *block->phis()) {
+      ranges_.InitializeRangeIfMissing(
+          block, phi, phi->is_int32() ? Range::Int32() : Range::All());
+    }
+  }
+
   // Returns true if the loop reach a fixpoint.
   bool ProcessLoopPhisBackedge(BasicBlock* block, BasicBlock* backedge_pred) {
     if (!block->has_phi()) return true;
diff --git a/deps/v8/src/objects/map-updater.cc b/deps/v8/src/objects/map-updater.cc
index d62c94772f6..f1437356d69 100644
--- a/deps/v8/src/objects/map-updater.cc
+++ b/deps/v8/src/objects/map-updater.cc
@@ -385,8 +385,9 @@ std::optional<Tagged<Map>> MapUpdater::TryUpdateNoLock(Isolate* isolate,
   }

   if (root_map->prototype() != old_map->prototype()) {
-    auto maybe_transition = TransitionsAccessor::GetPrototypeTransition(
-        isolate, root_map, old_map->prototype());
+    auto maybe_transition =
+        TransitionsAccessor(isolate, root_map, IsConcurrent(cmode))
+            .GetPrototypeTransition(old_map->prototype());
     if (!maybe_transition) {
       return {};
     }
diff --git a/deps/v8/src/objects/shared-function-info-inl.h b/deps/v8/src/objects/shared-function-info-inl.h
index 93de8a242af..c4504c0f58b 100644
--- a/deps/v8/src/objects/shared-function-info-inl.h
+++ b/deps/v8/src/objects/shared-function-info-inl.h
@@ -511,6 +511,9 @@ BIT_FIELD_ACCESSORS(SharedFunctionInfo, relaxed_flags,
                     SharedFunctionInfo::PrivateNameLookupSkipsOuterClassBit)
 BIT_FIELD_ACCESSORS(SharedFunctionInfo, relaxed_flags, is_hoisted_in_context,
                     SharedFunctionInfo::IsHoistedInContextBit)
+BIT_FIELD_ACCESSORS(SharedFunctionInfo, relaxed_flags,
+                    class_initializer_allows_await,
+                    SharedFunctionInfo::ClassInitializerAllowsAwaitBit)

 bool SharedFunctionInfo::optimization_disabled(CodeKind kind) const {
   switch (kind) {
diff --git a/deps/v8/src/objects/shared-function-info.cc b/deps/v8/src/objects/shared-function-info.cc
index 5151351c3ac..0f4078ec21b 100644
--- a/deps/v8/src/objects/shared-function-info.cc
+++ b/deps/v8/src/objects/shared-function-info.cc
@@ -600,6 +600,10 @@ void SharedFunctionInfo::InitFromFunctionLiteral(IsolateT* isolate,
         lit->has_static_private_methods_or_accessors());

     raw_sfi->set_is_hoisted_in_context(lit->scope()->is_hoisted_in_context());
+    DCHECK_IMPLIES(lit->scope()->class_initializer_allows_await(),
+                   IsClassInitializerFunction(lit->kind()));
+    raw_sfi->set_class_initializer_allows_await(
+        lit->scope()->class_initializer_allows_await());

     raw_sfi->set_is_toplevel(is_toplevel);
     DCHECK(IsTheHole(raw_sfi->outer_scope_info()));
diff --git a/deps/v8/src/objects/shared-function-info.h b/deps/v8/src/objects/shared-function-info.h
index d5f8a8fc2a9..dd0e0bcb5a4 100644
--- a/deps/v8/src/objects/shared-function-info.h
+++ b/deps/v8/src/objects/shared-function-info.h
@@ -289,6 +289,7 @@ V8_OBJECT class SharedFunctionInfo : public HeapObject {
       PropertiesAreFinalBit::Next<bool, 1>;
   using IsHoistedInContextBit =
       PrivateNameLookupSkipsOuterClassBit::Next<bool, 1>;
+  using ClassInitializerAllowsAwaitBit = IsHoistedInContextBit::Next<bool, 1>;
   // Bit positions in |flags2|.
   using ClassScopeHasPrivateBrandBit = base::BitField<bool, 0, 1, uint8_t>;
   using HasStaticPrivateMethodsOrAccessorsBit =
@@ -708,6 +709,9 @@ V8_OBJECT class SharedFunctionInfo : public HeapObject {
   // Indicates that the function is a hoisted-in-context declaration.
   DECL_BOOLEAN_ACCESSORS(is_hoisted_in_context)

+  // Indicates that a class initializer's enclosing scope allowed await.
+  DECL_BOOLEAN_ACCESSORS(class_initializer_allows_await)
+
   inline FunctionKind kind() const;

   int UniqueIdInScript() const;
diff --git a/deps/v8/src/objects/shared-function-info.tq b/deps/v8/src/objects/shared-function-info.tq
index f4949b0bc77..b46945f2c38 100644
--- a/deps/v8/src/objects/shared-function-info.tq
+++ b/deps/v8/src/objects/shared-function-info.tq
@@ -42,6 +42,7 @@ bitfield struct SharedFunctionInfoFlags extends uint32 {
   properties_are_final: bool: 1 bit;
   private_name_lookup_skips_outer_class: bool: 1 bit;
   is_hoisted_in_context: bool: 1 bit;
+  class_initializer_allows_await: bool: 1 bit;
 }

 @cppScope('SharedFunctionInfo')
diff --git a/deps/v8/src/objects/transitions-inl.h b/deps/v8/src/objects/transitions-inl.h
index af509675f54..b694790a4cd 100644
--- a/deps/v8/src/objects/transitions-inl.h
+++ b/deps/v8/src/objects/transitions-inl.h
@@ -400,6 +400,14 @@ MaybeHandle<Map> TransitionsAccessor::SearchSpecial(Isolate* isolate,
   return MaybeHandle<Map>(result, isolate);
 }

+// static
+std::optional<Tagged<Map>> TransitionsAccessor::GetPrototypeTransition(
+    Isolate* isolate, Tagged<Map> map, Tagged<Object> prototype) {
+  // This helper is supposed to be used only from the main thread.
+  DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
+  return TransitionsAccessor(isolate, map).GetPrototypeTransition(prototype);
+}
+
 // TODO(375937549): Convert to uint32_t.
 int TransitionArray::number_of_transitions() const {
   if (ulength().value() < kFirstIndex) return 0;
diff --git a/deps/v8/src/objects/transitions.cc b/deps/v8/src/objects/transitions.cc
index 907e8e695b5..0c0ac419f30 100644
--- a/deps/v8/src/objects/transitions.cc
+++ b/deps/v8/src/objects/transitions.cc
@@ -435,8 +435,8 @@ bool TransitionsAccessor::PutPrototypeTransition(Isolate* isolate,

   const uint32_t header = TransitionArray::kProtoTransitionHeaderSize;

-  DirectHandle<WeakFixedArray> cache(GetPrototypeTransitions(isolate, *map),
-                                     isolate);
+  DirectHandle<WeakFixedArray> cache(
+      TransitionsAccessor(isolate, *map).GetPrototypeTransitions(), isolate);
   const uint32_t cache_len = cache->ulength().value();
   const uint32_t capacity = cache_len >= header ? cache_len - header : 0;
   const uint32_t transitions =
@@ -477,11 +477,13 @@ bool TransitionsAccessor::PutPrototypeTransition(Isolate* isolate,
   return true;
 }

-// static
 std::optional<Tagged<Map>> TransitionsAccessor::GetPrototypeTransition(
-    Isolate* isolate, Tagged<Map> map, Tagged<Object> prototype) {
+    Tagged<Object> prototype) {
   DisallowGarbageCollection no_gc;
-  Tagged<WeakFixedArray> cache = GetPrototypeTransitions(isolate, map);
+  if (encoding() != kFullTransitionArray) return {};
+  base::MutexGuardIf guard(isolate_->full_transition_array_access(),
+                           concurrent_access_);
+  Tagged<WeakFixedArray> cache = GetPrototypeTransitions();
   const uint32_t length = TransitionArray::NumberOfPrototypeTransitions(cache);
   for (uint32_t i = 0; i < length; i++) {
     Tagged<MaybeObject> target =
@@ -498,19 +500,11 @@ std::optional<Tagged<Map>> TransitionsAccessor::GetPrototypeTransition(
   return {};
 }

-// static
-Tagged<WeakFixedArray> TransitionsAccessor::GetPrototypeTransitions(
-    Isolate* isolate, Tagged<Map> map) {
-  Tagged<MaybeObject> raw_transitions = map->raw_transitions(kAcquireLoad);
-  if (GetEncoding(isolate, raw_transitions) != kFullTransitionArray) {
-    return ReadOnlyRoots(isolate).empty_weak_fixed_array();
-  }
-  Tagged<TransitionArray> transition_array =
-      GetTransitionArray(isolate, raw_transitions);
-  if (!transition_array->HasPrototypeTransitions()) {
-    return ReadOnlyRoots(isolate).empty_weak_fixed_array();
+Tagged<WeakFixedArray> TransitionsAccessor::GetPrototypeTransitions() {
+  if (!HasPrototypeTransitions()) {
+    return ReadOnlyRoots(isolate_).empty_weak_fixed_array();
   }
-  return transition_array->GetPrototypeTransitions();
+  return transitions()->GetPrototypeTransitions();
 }

 // static
diff --git a/deps/v8/src/objects/transitions.h b/deps/v8/src/objects/transitions.h
index 408bcaf0f4e..d7e948ef958 100644
--- a/deps/v8/src/objects/transitions.h
+++ b/deps/v8/src/objects/transitions.h
@@ -185,8 +185,13 @@ class V8_EXPORT_PRIVATE TransitionsAccessor {
   static bool PutPrototypeTransition(Isolate* isolate, DirectHandle<Map>,
                                      DirectHandle<Object> prototype,
                                      DirectHandle<Map> target_map);
-  static std::optional<Tagged<Map>> GetPrototypeTransition(
+
+  std::optional<Tagged<Map>> GetPrototypeTransition(Tagged<Object> prototype);
+  // Convenient helper for calling from the main thread, for other cases
+  // use the instance method above.
+  static inline std::optional<Tagged<Map>> GetPrototypeTransition(
       Isolate* isolate, Tagged<Map> map, Tagged<Object> prototype);
+
   bool HasPrototypeTransitions();

   // During the first-time Map::Update and Map::TryUpdate, the migration target
@@ -267,8 +272,7 @@ class V8_EXPORT_PRIVATE TransitionsAccessor {
   static void SetPrototypeTransitions(
       Isolate* isolate, DirectHandle<Map> map,
       DirectHandle<WeakFixedArray> proto_transitions);
-  static Tagged<WeakFixedArray> GetPrototypeTransitions(Isolate* isolate,
-                                                        Tagged<Map> map);
+  Tagged<WeakFixedArray> GetPrototypeTransitions();

   static void InsertHelper(Isolate* isolate, DirectHandle<Map> map,
                            DirectHandle<Name> name, DirectHandle<Map> target,
diff --git a/deps/v8/src/parsing/parse-info.cc b/deps/v8/src/parsing/parse-info.cc
index f33708abdf8..aa1647ec7f4 100644
--- a/deps/v8/src/parsing/parse-info.cc
+++ b/deps/v8/src/parsing/parse-info.cc
@@ -55,6 +55,8 @@ UnoptimizedCompileFlags UnoptimizedCompileFlags::ForFunctionCompile(
   flags.set_is_lazy_compile(true);

   flags.set_is_repl_mode(script->is_repl_mode());
+  flags.set_class_initializer_allows_await(
+      shared->class_initializer_allows_await());

   // Do not support re-parsing top-level function of a wrapped script.
   DCHECK_IMPLIES(flags.is_toplevel(), !script->is_wrapped());
diff --git a/deps/v8/src/parsing/parse-info.h b/deps/v8/src/parsing/parse-info.h
index ef6f4f577ee..d62979f3f62 100644
--- a/deps/v8/src/parsing/parse-info.h
+++ b/deps/v8/src/parsing/parse-info.h
@@ -66,6 +66,7 @@ class Zone;
   V(compile_hints_magic_enabled, bool, 1, _)                    \
   V(compile_hints_per_function_magic_enabled, bool, 1, _)       \
   V(is_hoisted_in_context, bool, 1, _)                          \
+  V(class_initializer_allows_await, bool, 1, _)                 \
   V(allow_heap_allocation, bool, 1, _)

 class V8_EXPORT_PRIVATE UnoptimizedCompileFlags {
diff --git a/deps/v8/src/parsing/parser-base.h b/deps/v8/src/parsing/parser-base.h
index 5b552c58379..1df1fa026f5 100644
--- a/deps/v8/src/parsing/parser-base.h
+++ b/deps/v8/src/parsing/parser-base.h
@@ -450,7 +450,11 @@ class ParserBase {
   class FunctionState final : public BlockState {
    public:
     FunctionState(FunctionState** function_state_stack, Scope** scope_stack,
-                  DeclarationScope* scope);
+                  DeclarationScope* scope)
+        : FunctionState(function_state_stack, scope_stack, scope,
+                        scope->function_kind()) {}
+    FunctionState(FunctionState** function_state_stack, Scope** scope_stack,
+                  DeclarationScope* scope, FunctionKind kind);
     ~FunctionState();

     DeclarationScope* scope() const { return scope_->AsDeclarationScope(); }
@@ -467,7 +471,7 @@ class ParserBase {
     int suspend_count() const { return suspend_count_; }
     bool CanSuspend() const { return suspend_count_ > 0; }

-    FunctionKind kind() const { return scope()->function_kind(); }
+    FunctionKind kind() const { return kind_; }

     bool next_function_is_likely_called() const {
       return next_function_is_likely_called_;
@@ -534,6 +538,7 @@ class ParserBase {
     FunctionState** function_state_stack_;
     FunctionState* outer_function_state_;
     DeclarationScope* scope_;
+    FunctionKind kind_;
     Target* target_stack_ = nullptr;  // for break, continue statements

     // A reason, if any, why this function should not be optimized.
@@ -639,6 +644,8 @@ class ParserBase {
         static_elements_scope = parser->NewFunctionScope(kind);
         static_elements_scope->SetLanguageMode(LanguageMode::kStrict);
         static_elements_scope->set_start_position(beg_pos);
+        static_elements_scope->set_class_initializer_allows_await(
+            parser->is_await_allowed());
         static_elements_function_id = info_id;
         // Actually consume the id. The id that was passed in might be an
         // earlier id in case of computed property names.
@@ -657,6 +664,8 @@ class ParserBase {
         instance_members_scope = parser->NewFunctionScope(kind);
         instance_members_scope->SetLanguageMode(LanguageMode::kStrict);
         instance_members_scope->set_start_position(beg_pos);
+        instance_members_scope->set_class_initializer_allows_await(
+            parser->is_await_allowed());
         instance_members_function_id = info_id;
         // Actually consume the id. The id that was passed in might be an
         // earlier id in case of computed property names.
@@ -1833,13 +1842,14 @@ class ParserBase {
 template <typename Impl>
 ParserBase<Impl>::FunctionState::FunctionState(
     FunctionState** function_state_stack, Scope** scope_stack,
-    DeclarationScope* scope)
+    DeclarationScope* scope, FunctionKind kind)
     : BlockState(scope_stack, scope),
       expected_property_count_(0),
       suspend_count_(0),
       function_state_stack_(function_state_stack),
       outer_function_state_(*function_state_stack),
       scope_(scope),
+      kind_(kind),
       dont_optimize_reason_(BailoutReason::kNoReason),
       next_function_is_likely_called_(false),
       previous_function_was_likely_called_(false),
diff --git a/deps/v8/src/parsing/parser.cc b/deps/v8/src/parsing/parser.cc
index 94f19994ccf..388e4f1c96e 100644
--- a/deps/v8/src/parsing/parser.cc
+++ b/deps/v8/src/parsing/parser.cc
@@ -1274,10 +1274,19 @@ FunctionLiteral* Parser::ParseClassForMemberInitialization(
   // this point the scanner should be rewound to the position of the class
   // token.
   DCHECK_EQ(peek_position(), initializer_pos);
-  // Insert a FunctionState with the closest outer Declaration scope
+  // Insert a FunctionState with the closest outer Declaration scope.
+  // The immediate enclosing function scope may have been elided from the
+  // ScopeInfo chain if it did not allocate a context. Since class bodies are
+  // always strict mode, 'yield' is never a valid identifier in computed
+  // property names, so we can unconditionally enable generator mode; whether
+  // 'await' is a keyword is recorded on the initializer SharedFunctionInfo.
   DeclarationScope* nearest_decl_scope = original_scope_->GetDeclarationScope();
   DCHECK_NOT_NULL(nearest_decl_scope);
-  FunctionState function_state(&function_state_, &scope_, nearest_decl_scope);
+  FunctionKind enclosing_kind = flags().class_initializer_allows_await()
+                                    ? FunctionKind::kAsyncGeneratorFunction
+                                    : FunctionKind::kGeneratorFunction;
+  FunctionState function_state(&function_state_, &scope_, nearest_decl_scope,
+                               enclosing_kind);

   // We preparse the class members that are not fields with initializers
   // in order to collect the function literal ids.
diff --git a/deps/v8/src/snapshot/code-serializer.cc b/deps/v8/src/snapshot/code-serializer.cc
index 034ef5f52ea..78ba29eeca3 100644
--- a/deps/v8/src/snapshot/code-serializer.cc
+++ b/deps/v8/src/snapshot/code-serializer.cc
@@ -345,8 +345,8 @@ class StressOffThreadDeserializeThread final : public base::Thread {
     LocalIsolate local_isolate(isolate_, ThreadKind::kBackground);
     UnparkedScope unparked_scope(&local_isolate);
     LocalHandleScope handle_scope(&local_isolate);
-    off_thread_data_ =
-        CodeSerializer::StartDeserializeOffThread(&local_isolate, cached_data_);
+    CodeSerializer::StartDeserializeOffThread(&local_isolate, cached_data_,
+                                              &off_thread_data_);
   }

   MaybeDirectHandle<SharedFunctionInfo> Finalize(
@@ -360,7 +360,7 @@ class StressOffThreadDeserializeThread final : public base::Thread {
  private:
   Isolate* isolate_;
   AlignedCachedData* cached_data_;
-  CodeSerializer::OffThreadDeserializeData off_thread_data_;
+  OffThreadDeserializeData off_thread_data_;
 };

 void FinalizeDeserialization(Isolate* isolate,
@@ -554,8 +554,7 @@ MaybeDirectHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
   return scope.CloseAndEscape(result);
 }

-DirectHandle<Script> CodeSerializer::OffThreadDeserializeData::GetOnlyScript(
-    LocalHeap* heap) {
+DirectHandle<Script> OffThreadDeserializeData::GetOnlyScript(LocalHeap* heap) {
   std::unique_ptr<PersistentHandles> previous_persistent_handles =
       heap->DetachPersistentHandles();
   heap->AttachPersistentHandles(std::move(persistent_handles));
@@ -573,32 +572,47 @@ DirectHandle<Script> CodeSerializer::OffThreadDeserializeData::GetOnlyScript(
   return script;
 }

-CodeSerializer::OffThreadDeserializeData
-CodeSerializer::StartDeserializeOffThread(LocalIsolate* local_isolate,
-                                          AlignedCachedData* cached_data) {
-  OffThreadDeserializeData result;
-
+void CodeSerializer::StartDeserializeOffThread(LocalIsolate* local_isolate,
+                                               AlignedCachedData* cached_data,
+                                               OffThreadDeserializeData* data) {
   DCHECK(!local_isolate->heap()->HasPersistentHandles());

   const SerializedCodeData scd =
       SerializedCodeData::FromCachedDataWithoutSource(
-          local_isolate, cached_data, &result.sanity_check_result);
-  if (result.sanity_check_result != SerializedCodeSanityCheckResult::kSuccess) {
+          local_isolate, cached_data, &data->sanity_check_result);
+  if (data->sanity_check_result != SerializedCodeSanityCheckResult::kSuccess) {
     // Exit early but don't report yet, we'll re-check this when finishing on
     // the main thread
     DCHECK(cached_data->rejected());
-    return result;
+    return;
   }

   MaybeDirectHandle<SharedFunctionInfo> local_maybe_result =
       OffThreadObjectDeserializer::DeserializeSharedFunctionInfo(
-          local_isolate, &scd, &result.scripts);
+          local_isolate, &scd, &data->scripts);

-  result.maybe_result =
+  data->maybe_result =
       local_isolate->heap()->NewPersistentMaybeHandle(local_maybe_result);
-  result.persistent_handles = local_isolate->heap()->DetachPersistentHandles();
+  data->persistent_handles = local_isolate->heap()->DetachPersistentHandles();
+}

-  return result;
+bool CodeSerializer::NotifySourceTextAvailable(
+    Isolate* isolate, OffThreadDeserializeData* data,
+    const AlignedCachedData* cached_data, DirectHandle<String> source,
+    const ScriptDetails& script_details) {
+  HandleScope scope(isolate);
+
+  // Only check the source hash against the immutable cached_data header and
+  // write the main-thread-only data->source_sanity_check_result field here. Do
+  // not read/write data->sanity_check_result or mutate cached_data->Reject(),
+  // as StartDeserializeOffThread may still be running concurrently on a
+  // background thread. Full rejection and histogram reporting happen in
+  // FinishOffThreadDeserialize.
+  SerializedCodeData scd(cached_data);
+  SerializedCodeSanityCheckResult sanity_check_result =
+      scd.SanityCheckJustSource(isolate, source, script_details);
+  data->source_sanity_check_result = sanity_check_result;
+  return sanity_check_result == SerializedCodeSanityCheckResult::kSuccess;
 }

 MaybeDirectHandle<SharedFunctionInfo>
@@ -614,11 +628,6 @@ CodeSerializer::FinishOffThreadDeserialize(

   HandleScope scope(isolate);

-  DirectHandle<FixedArray> wrapped_arguments;
-  if (!script_details.wrapped_arguments.is_null()) {
-    wrapped_arguments = script_details.wrapped_arguments.ToHandleChecked();
-  }
-
   // Do a source sanity check now that we have the source. It's important for
   // FromPartiallySanityCheckedCachedData call that the sanity_check_result
   // holds the result of the off-thread sanity check.
@@ -626,10 +635,9 @@ CodeSerializer::FinishOffThreadDeserialize(
       data.sanity_check_result;
   const SerializedCodeData scd =
       SerializedCodeData::FromPartiallySanityCheckedCachedData(
-          cached_data,
-          SerializedCodeData::SourceHash(source, wrapped_arguments,
-                                         script_details.origin_options),
+          isolate, cached_data, data, source, script_details,
           &sanity_check_result);
+  USE(scd);
   if (sanity_check_result != SerializedCodeSanityCheckResult::kSuccess) {
     // The only case where the deserialization result could exist despite a
     // check failure is on a source mismatch, since we can't test for this
@@ -768,8 +776,22 @@ SerializedCodeSanityCheckResult SerializedCodeData::SanityCheck(
   return SanityCheckJustSource(expected_source_hash);
 }

+SerializedCodeSanityCheckResult SerializedCodeData::SanityCheckJustSource(
+    Isolate* isolate, DirectHandle<String> source,
+    const ScriptDetails& script_details) const {
+  DirectHandle<FixedArray> wrapped_arguments;
+  if (!script_details.wrapped_arguments.is_null()) {
+    wrapped_arguments = script_details.wrapped_arguments.ToHandleChecked();
+  }
+  return SanityCheckJustSource(
+      SourceHash(source, wrapped_arguments, script_details.origin_options));
+}
+
 SerializedCodeSanityCheckResult SerializedCodeData::SanityCheckJustSource(
     uint32_t expected_source_hash) const {
+  if (size_ < kHeaderSize) {
+    return SerializedCodeSanityCheckResult::kInvalidHeader;
+  }
   uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
   if (source_hash != expected_source_hash) {
     return SerializedCodeSanityCheckResult::kSourceMismatch;
@@ -847,7 +869,7 @@ base::Vector<const uint8_t> SerializedCodeData::Payload() const {
   return base::Vector<const uint8_t>(payload, length);
 }

-SerializedCodeData::SerializedCodeData(AlignedCachedData* data)
+SerializedCodeData::SerializedCodeData(const AlignedCachedData* data)
     : SerializedData(const_cast<uint8_t*>(data->data()), data->length()) {}

 SerializedCodeData SerializedCodeData::FromCachedData(
@@ -882,12 +904,14 @@ SerializedCodeData SerializedCodeData::FromCachedDataWithoutSource(
 }

 SerializedCodeData SerializedCodeData::FromPartiallySanityCheckedCachedData(
-    AlignedCachedData* cached_data, uint32_t expected_source_hash,
+    Isolate* isolate, AlignedCachedData* cached_data,
+    const OffThreadDeserializeData& data, DirectHandle<String> source,
+    const ScriptDetails& script_details,
     SerializedCodeSanityCheckResult* rejection_result) {
-  DisallowGarbageCollection no_gc;
   // The previous call to FromCachedDataWithoutSource may have already rejected
   // the cached data, so reuse the previous rejection result if it's not a
   // success.
+  *rejection_result = data.sanity_check_result;
   if (*rejection_result != SerializedCodeSanityCheckResult::kSuccess) {
     // FromCachedDataWithoutSource doesn't check the source, so there can't be
     // a source mismatch.
@@ -897,7 +921,14 @@ SerializedCodeData SerializedCodeData::FromPartiallySanityCheckedCachedData(
     return SerializedCodeData(nullptr, 0);
   }
   SerializedCodeData scd(cached_data);
-  *rejection_result = scd.SanityCheckJustSource(expected_source_hash);
+  if (data.source_sanity_check_result.has_value()) {
+    DCHECK_EQ(*data.source_sanity_check_result,
+              scd.SanityCheckJustSource(isolate, source, script_details));
+    *rejection_result = *data.source_sanity_check_result;
+  } else {
+    *rejection_result =
+        scd.SanityCheckJustSource(isolate, source, script_details);
+  }
   if (*rejection_result != SerializedCodeSanityCheckResult::kSuccess) {
     // This check only checks the source, so the only possible failure is a
     // source mismatch.
diff --git a/deps/v8/src/snapshot/code-serializer.h b/deps/v8/src/snapshot/code-serializer.h
index ed2281113f4..6cfafc4d26b 100644
--- a/deps/v8/src/snapshot/code-serializer.h
+++ b/deps/v8/src/snapshot/code-serializer.h
@@ -5,6 +5,8 @@
 #ifndef V8_SNAPSHOT_CODE_SERIALIZER_H_
 #define V8_SNAPSHOT_CODE_SERIALIZER_H_

+#include <optional>
+
 #include "src/base/macros.h"
 #include "src/codegen/script-details.h"
 #include "src/snapshot/serializer.h"
@@ -57,21 +59,26 @@ typedef v8::ScriptCompiler::CachedData::CompatibilityCheckResult
 // histogram definition.
 static_assert(static_cast<int>(SerializedCodeSanityCheckResult::kLast) == 9);

-class CodeSerializer : public Serializer {
+class CodeSerializer;
+
+struct OffThreadDeserializeData {
  public:
-  struct OffThreadDeserializeData {
-   public:
-    bool HasResult() const { return !maybe_result.is_null(); }
-    DirectHandle<Script> GetOnlyScript(LocalHeap* heap);
-
-   private:
-    friend class CodeSerializer;
-    MaybeIndirectHandle<SharedFunctionInfo> maybe_result;
-    std::vector<IndirectHandle<Script>> scripts;
-    std::unique_ptr<PersistentHandles> persistent_handles;
-    SerializedCodeSanityCheckResult sanity_check_result;
-  };
+  bool HasResult() const { return !maybe_result.is_null(); }
+  DirectHandle<Script> GetOnlyScript(LocalHeap* heap);
+
+ private:
+  friend class CodeSerializer;
+  friend class SerializedCodeData;
+  MaybeIndirectHandle<SharedFunctionInfo> maybe_result;
+  std::vector<IndirectHandle<Script>> scripts;
+  std::unique_ptr<PersistentHandles> persistent_handles;
+  SerializedCodeSanityCheckResult sanity_check_result =
+      SerializedCodeSanityCheckResult::kSuccess;
+  std::optional<SerializedCodeSanityCheckResult> source_sanity_check_result;
+};

+class CodeSerializer : public Serializer {
+ public:
   CodeSerializer(const CodeSerializer&) = delete;
   CodeSerializer& operator=(const CodeSerializer&) = delete;
   V8_EXPORT_PRIVATE static ScriptCompiler::CachedData* Serialize(
@@ -85,9 +92,14 @@ class CodeSerializer : public Serializer {
               DirectHandle<String> source, const ScriptDetails& script_details,
               MaybeDirectHandle<Script> maybe_cached_script = {});

-  V8_WARN_UNUSED_RESULT static OffThreadDeserializeData
-  StartDeserializeOffThread(LocalIsolate* isolate,
-                            AlignedCachedData* cached_data);
+  static void StartDeserializeOffThread(LocalIsolate* isolate,
+                                        AlignedCachedData* cached_data,
+                                        OffThreadDeserializeData* data);
+
+  V8_WARN_UNUSED_RESULT static bool NotifySourceTextAvailable(
+      Isolate* isolate, OffThreadDeserializeData* data,
+      const AlignedCachedData* cached_data, DirectHandle<String> source,
+      const ScriptDetails& script_details);

   V8_WARN_UNUSED_RESULT static MaybeDirectHandle<SharedFunctionInfo>
   FinishOffThreadDeserialize(
@@ -140,7 +152,9 @@ class SerializedCodeData : public SerializedData {
   // FromCachedDataWithoutSource. The rejection result from that call should be
   // passed into this one.
   static SerializedCodeData FromPartiallySanityCheckedCachedData(
-      AlignedCachedData* cached_data, uint32_t expected_source_hash,
+      Isolate* isolate, AlignedCachedData* cached_data,
+      const OffThreadDeserializeData& data, DirectHandle<String> source,
+      const ScriptDetails& script_details,
       SerializedCodeSanityCheckResult* rejection_result);

   // Used when producing.
@@ -157,7 +171,8 @@ class SerializedCodeData : public SerializedData {
                              ScriptOriginOptions origin_options);

  private:
-  explicit SerializedCodeData(AlignedCachedData* data);
+  friend class CodeSerializer;
+  explicit SerializedCodeData(const AlignedCachedData* data);
   SerializedCodeData(const uint8_t* data, int size)
       : SerializedData(const_cast<uint8_t*>(data), size) {}

@@ -169,6 +184,9 @@ class SerializedCodeData : public SerializedData {
   SerializedCodeSanityCheckResult SanityCheck(
       uint32_t expected_ro_snapshot_checksum,
       uint32_t expected_source_hash) const;
+  SerializedCodeSanityCheckResult SanityCheckJustSource(
+      Isolate* isolate, DirectHandle<String> source,
+      const ScriptDetails& script_details) const;
   SerializedCodeSanityCheckResult SanityCheckJustSource(
       uint32_t expected_source_hash) const;
   SerializedCodeSanityCheckResult SanityCheckWithoutSource(
diff --git a/deps/v8/test/mjsunit/es6/regress-class-member-init-reparse-await-yield-arguments.js b/deps/v8/test/mjsunit/es6/regress-class-member-init-reparse-await-yield-arguments.js
new file mode 100644
index 00000000000..d53e38336e3
--- /dev/null
+++ b/deps/v8/test/mjsunit/es6/regress-class-member-init-reparse-await-yield-arguments.js
@@ -0,0 +1,82 @@
+// Copyright 2026 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
+
+// Test reparsing of class member initializers when the immediately enclosing
+// function did not allocate a context (and is therefore absent from the
+// ScopeInfo chain).
+
+// 1. Computed property key using 'arguments' inside a contextless function
+// nested inside a class static block whose initializer allocates a context.
+{
+  let x = 1;
+  class Outer {
+    static {
+      () => this;
+      function foo() {
+        class Inner {
+          [arguments] = x();
+        }
+        new Inner();
+      }
+      assertThrows(foo, TypeError, "x is not a function");
+    }
+  }
+}
+
+// 2. Computed property key using 'await / 1' inside a contextless async
+// function where 'await / 1... /g' is an AwaitExpression of a RegExp literal.
+{
+  let x = 1;
+  async function inner() {
+    class C {
+      [await / 1]() { [[a] + 1 /g] = { a: x() }
+    }
+    new C();
+  }
+  let error;
+  inner().catch(e => { error = e; });
+  %PerformMicrotaskCheckpoint();
+  assertInstanceof(error, TypeError);
+  assertMatches(/x is not a function/, error.message);
+}
+
+// 3. Computed property key using 'yield' inside a contextless generator
+// function.
+{
+  let x = 1;
+  function* gen() {
+    class C {
+      [yield 1] = x();
+    }
+    return C;
+  }
+  let iter = gen();
+  assertEquals({ value: 1, done: false }, iter.next());
+  let C = iter.next("prop").value;
+  assertThrows(() => new C(), TypeError, "x is not a function");
+}
+
+// 4. Computed property key using 'await / 1' as division inside a contextless
+// synchronous function nested inside an async function that allocates a
+// context.
+{
+  var await = 2;
+  async function outer() {
+    let x = 1;
+    function sync_inner() {
+      class C {
+        [await / 1] = x();
+      }
+      new C();
+    }
+    sync_inner();
+  }
+  let error;
+  outer().catch(e => { error = e; });
+  %PerformMicrotaskCheckpoint();
+  assertInstanceof(error, TypeError);
+  assertMatches(/x is not a function/, error.message);
+}
diff --git a/deps/v8/test/mjsunit/maglev/regress-564326894.js b/deps/v8/test/mjsunit/maglev/regress-564326894.js
new file mode 100644
index 00000000000..0a48ca5b224
--- /dev/null
+++ b/deps/v8/test/mjsunit/maglev/regress-564326894.js
@@ -0,0 +1,29 @@
+// Copyright 2026 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 --maglev
+
+const arr = [1.5, ,];
+
+function foo(a) {
+  let x = a[0];
+  let y = a[0];
+  for (let i = 0; i < 5; i++) {
+    const t = (y | 0) + y;
+    y = x;
+    x = t;
+  }
+  return x;
+}
+
+%PrepareFunctionForOptimization(foo);
+assertEquals(8.5, foo(arr));
+assertEquals(8.5, foo(arr));
+%OptimizeMaglevOnNextCall(foo);
+assertEquals(8.5, foo(arr));
+assertOptimized(foo);
+
+// Passing a hole when feedback only saw Number must still deopt and return NaN.
+assertEquals(NaN, foo([, 1.5]));
+assertUnoptimized(foo);
diff --git a/deps/v8/test/mjsunit/maglev/regress-569286602-1.js b/deps/v8/test/mjsunit/maglev/regress-569286602-1.js
new file mode 100644
index 00000000000..b89ebdcb482
--- /dev/null
+++ b/deps/v8/test/mjsunit/maglev/regress-569286602-1.js
@@ -0,0 +1,24 @@
+// Copyright 2026 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 --maglev
+
+function f(r) {
+  let pos;
+  while ('a'.startsWith('b', pos)) { do { pos = 1; } while (pos); }
+  r.push(pos);
+}
+
+%PrepareFunctionForOptimization(f);
+let a = [{}];
+assertEquals(undefined, f(a));
+assertEquals([{}, undefined], a);
+let b = [1];
+assertEquals(undefined, f(b));
+assertEquals([1, undefined], b);
+
+%OptimizeMaglevOnNextCall(f);
+let c = [1];
+assertEquals(undefined, f(c));
+assertEquals([1, undefined], c);
diff --git a/deps/v8/test/mjsunit/maglev/regress-569286602-2.js b/deps/v8/test/mjsunit/maglev/regress-569286602-2.js
new file mode 100644
index 00000000000..dc186b862a9
--- /dev/null
+++ b/deps/v8/test/mjsunit/maglev/regress-569286602-2.js
@@ -0,0 +1,24 @@
+// Copyright 2026 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 --maglev
+
+function f(r) {
+  let pos;
+  while ('a'.startsWith('b', pos)) { do { pos = 1; } while (pos); }
+  if (r) r.push(pos);
+}
+
+%PrepareFunctionForOptimization(f);
+let a = [{}];
+assertEquals(undefined, f(a));
+assertEquals([{}, undefined], a);
+let b = [1];
+assertEquals(undefined, f(b));
+assertEquals([1, undefined], b);
+
+%OptimizeMaglevOnNextCall(f);
+let c = [1];
+assertEquals(undefined, f(c));
+assertEquals([1, undefined], c);
diff --git a/deps/v8/test/mjsunit/mjsunit.status b/deps/v8/test/mjsunit/mjsunit.status
index af6517a6a8f..5974a6eb18b 100644
--- a/deps/v8/test/mjsunit/mjsunit.status
+++ b/deps/v8/test/mjsunit/mjsunit.status
@@ -2943,6 +2943,7 @@
   'regress/wasm/regress-543901836': [SKIP],
   'regress/wasm/regress-560536735': [SKIP],
   'regress/wasm/regress-561660149': [SKIP],
+  'regress/wasm/regress-574223268': [SKIP],
   'compiler/regress-347724915': [SKIP],
   'regress/regress-crbug-418520151': [SKIP],
   'regress/regress-535000102': [SKIP],
diff --git a/deps/v8/test/mjsunit/regress/regress-566091009.js b/deps/v8/test/mjsunit/regress/regress-566091009.js
new file mode 100644
index 00000000000..aaf8c217d3c
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-566091009.js
@@ -0,0 +1,69 @@
+// Copyright 2026 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: --no-lazy-feedback-allocation --allow-natives-syntax
+
+(function TestAccessCheck() {
+  const target = d8.test.createAccessCheckedObject(true);
+  target[0] = "secret";
+  d8.test.setAccessPolicy(target, false);
+
+  const namedObj = { a: 1 };
+
+  // 1. KeyedLoadIC: transition from named property access to element access.
+  function read(obj, key) {
+    return obj[key];
+  }
+  read(namedObj, "a");
+  assertThrows(() => read(target, "a"), TypeError);
+  read([1.1], 0);
+  assertThrows(() => read(target, 0), TypeError);
+
+  // 2. KeyedHasIC: transition from named property access to element access.
+  function has(obj, key) {
+    return key in obj;
+  }
+  has(namedObj, "a");
+  assertThrows(() => has(target, "a"), TypeError);
+  has([1.1], 0);
+  assertThrows(() => has(target, 0), TypeError);
+
+  // 3. KeyedStoreIC: transition from named property access to element access.
+  function write(obj, key, val) {
+    obj[key] = val;
+  }
+  write(namedObj, "a", 2);
+  assertThrows(() => write(target, "a", 2), TypeError);
+  write([1.1], 0, 2.2);
+  assertThrows(() => write(target, 0, "overwritten"), TypeError);
+
+  d8.test.setAccessPolicy(target, true);
+  assertEquals("secret", target[0]);
+})();
+
+(function TestNoElementsProtector() {
+  function readHole(a) {
+    return a[0];
+  }
+  const holey = [, 1];
+  %PrepareFunctionForOptimization(readHole);
+  assertEquals(undefined, readHole(holey));
+  %OptimizeFunctionOnNextCall(readHole);
+  assertEquals(undefined, readHole(holey));
+
+  Object.defineProperty(Object.prototype, "prop", {
+    set(_) {},
+    configurable: true,
+  });
+  function write(o, k, v) {
+    o[k] = v;
+  }
+  write({ prop: 1 }, "prop", 1);
+  write(Array.prototype, "prop", 1);
+  write([], 0, 1);
+  write(Array.prototype, 0, "boom");
+
+  assertEquals("boom", holey[0]);
+  assertEquals("boom", readHole(holey));
+})();
diff --git a/deps/v8/test/mjsunit/regress/regress-570003644-1.js b/deps/v8/test/mjsunit/regress/regress-570003644-1.js
new file mode 100644
index 00000000000..f56634f7a54
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-570003644-1.js
@@ -0,0 +1,110 @@
+// Copyright 2026 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: --maglev-non-eager-inlining --expose-gc --allow-natives-syntax
+
+class D {
+  constructor(x) {
+    this.x = x;
+    this.p = 7;
+    this.q = 9;
+  }
+}
+
+// Map: MD1 where x is const SMI
+let dOld = new D(1);
+
+// Map: MD2 (after adding "tail")
+// Map transition: MD1 --tail--> MD2
+let dExtra = new D(1);
+dExtra.tail = 1;
+
+class C {
+  constructor(z) {
+    this.z = z;
+    this.q = 11;
+  }
+}
+
+// Map: MC1 where z is a const SMI
+let cOld = new C(1);
+
+// Map: MC2 w where z is a const HeapNumber
+let cTarget = new C(1.5);
+
+// Migrate to MC2: this makes MC2 a migration target
+cOld.z = 2.5;
+
+// Larger than the eager-inline bytecode limit.
+function noop() {
+  let n = 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  return n;
+}
+%PrepareFunctionForOptimization(noop);
+
+function polyQ(o) {
+  noop(); // Not inlined
+  // MigrateMapIfNeeded, then a polymorphic branch with MC2 and MD1 (in this
+  // order).
+  return o.q;
+}
+%PrepareFunctionForOptimization(polyQ);
+
+polyQ(cTarget);
+polyQ(dOld);
+
+let smi_array = [0, 0];
+
+function victim(cObj, dObj) {
+  // CheckMapsWithMigration(MC2) cObj; tries to migrate to MC2 (but the cTarget we
+  // pass already has MC2).
+  cObj.q;
+
+  // CheckMaps(MD1) dObj
+  dObj.p;
+
+  // Eagerly inlining polyQ. Here we need to conservatively assume that the noop
+  // call might change the maps, so we get:
+  // CallFunction noop
+  // MigrateMapIfNeeded dObj
+  // Polymoprhic branch (MC2, MD1):
+  // /-- Branch if dObj's map is MC2
+  // |      |
+  // |      v
+  // |   CheckMap(MD1) dObj <<< Load-bearing! Must not be eliminated
+  // |      |
+  // |      v
+  // \--> Result unused, so this is empty
+  polyQ(dObj);
+
+  // The map better be MD1 or this goes wrong.
+  smi_array[0] = dObj.x;
+}
+%PrepareFunctionForOptimization(victim);
+victim(cTarget, dOld);
+
+%OptimizeMaglevOnNextCall(victim);
+
+victim(cTarget, dOld);
+
+// Move the smi_array backing store to old space before storing a young pointer.
+gc();
+
+// Create a new map MD3 where x is a HeapNumber; MD1 deprecated.
+new D(1.5);
+
+// Now the MigrateMapIfNeeded will migrate dOld to MD3 where x is a HeapNumber.
+victim(cTarget, dOld);
diff --git a/deps/v8/test/mjsunit/regress/regress-570003644-2.js b/deps/v8/test/mjsunit/regress/regress-570003644-2.js
new file mode 100644
index 00000000000..fe9c96dd215
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-570003644-2.js
@@ -0,0 +1,111 @@
+// Copyright 2026 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: --maglev-non-eager-inlining --expose-gc --allow-natives-syntax
+// Flags: --max-maglev-eager-inlined-bytecode-size=0
+
+class D {
+  constructor(x) {
+    this.x = x;
+    this.p = 7;
+    this.q = 9;
+  }
+}
+
+// Map: MD1 where x is const SMI
+let dOld = new D(1);
+
+// Map: MD2 (after adding "tail")
+// Map transition: MD1 --tail--> MD2
+let dExtra = new D(1);
+dExtra.tail = 1;
+
+class C {
+  constructor(z) {
+    this.z = z;
+    this.q = 11;
+  }
+}
+
+// Map: MC1 where z is a const SMI
+let cOld = new C(1);
+
+// Map: MC2 w where z is a const HeapNumber
+let cTarget = new C(1.5);
+
+// Migrate to MC2: this makes MC2 a migration target
+cOld.z = 2.5;
+
+// Larger than the eager-inline bytecode limit.
+function noop() {
+  let n = 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  n += 0;
+  return n;
+}
+%PrepareFunctionForOptimization(noop);
+
+function polyQ(o) {
+  noop(); // Not inlined
+  // MigrateMapIfNeeded, then a polymorphic branch with MC2 and MD1 (in this
+  // order).
+  return o.q;
+}
+%PrepareFunctionForOptimization(polyQ);
+
+polyQ(cTarget);
+polyQ(dOld);
+
+let smi_array = [0, 0];
+
+function victim(cObj, dObj) {
+  // CheckMapsWithMigration(MC2) cObj; tries to migrate to MC2 (but the cTarget we
+  // pass already has MC2).
+  cObj.q;
+
+  // CheckMaps(MD1) dObj
+  dObj.p;
+
+  // Eventually we'l inline polyQ here. Here we need to conservatively assume
+  // that the noop call might change the maps, so we get:
+  // CallFunction noop
+  // MigrateMapIfNeeded dObj
+  // Polymoprhic branch (MC2, MD1):
+  // /-- Branch if dObj's map is MC2
+  // |      |
+  // |      v
+  // |   CheckMap(MD1) dObj <<< Load-bearing! Must not be eliminated
+  // |      |
+  // |      v
+  // \--> Result unused, so this is empty
+  polyQ(dObj);
+
+  // The map better be MD1 or this goes wrong.
+  smi_array[0] = dObj.x;
+}
+%PrepareFunctionForOptimization(victim);
+victim(cTarget, dOld);
+
+%OptimizeMaglevOnNextCall(victim);
+
+victim(cTarget, dOld);
+
+// Move the smi_array backing store to old space before storing a young pointer.
+gc();
+
+// Create a new map MD3 where x is a HeapNumber; MD1 deprecated.
+new D(1.5);
+
+// Now the MigrateMapIfNeeded will migrate dOld to MD3 where x is a HeapNumber.
+victim(cTarget, dOld);
diff --git a/deps/v8/test/mjsunit/regress/regress-570203091-1.js b/deps/v8/test/mjsunit/regress/regress-570203091-1.js
new file mode 100644
index 00000000000..2ac6c407c77
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-570203091-1.js
@@ -0,0 +1,29 @@
+// Copyright 2026 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: --turbolev --allow-natives-syntax
+
+let sink = 0;
+function* gen() {
+  try { unknown_global; } catch {}
+  let x = 0;
+  for (;;) {
+    if (x === 0) {
+      sink = 1;
+    } else {
+      sink = 2;
+    }
+    const is_zero = x === 0 ? true : false;
+    x = (yield is_zero).length;
+  }
+}
+
+%PrepareFunctionForOptimization(gen);
+const g = gen();
+g.next();     // x = 0
+g.next("a");  // x = 1
+g.next("");   // x = 0
+
+%OptimizeFunctionOnNextCall(gen);
+assertEquals(false, g.next("hello").value);
diff --git a/deps/v8/test/mjsunit/regress/regress-570203091-2.js b/deps/v8/test/mjsunit/regress/regress-570203091-2.js
new file mode 100644
index 00000000000..f99037288cd
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-570203091-2.js
@@ -0,0 +1,35 @@
+// Copyright 2026 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: --turbolev --allow-natives-syntax
+
+let sink = 0;
+const arr = [1.1, 2.2];
+const victim = [3.3];
+
+function* gen() {
+  try { unknown_global; } catch {}
+  let x = 0;
+  for (;;) {
+    if (x === 0) {
+      sink = 1;
+    } else {
+      sink = 2;
+    }
+    if (arr.length <= 0) return;
+    arr[x] = 1.5;
+    x = (yield).length;
+  }
+}
+
+%PrepareFunctionForOptimization(gen);
+const g = gen();
+g.next();     // x = 0
+g.next("a");  // x = 1
+g.next("");   // x = 0
+
+%OptimizeFunctionOnNextCall(gen);
+g.next("abcdef");
+assertEquals(3.3, victim[0]);
+assertEquals(7, arr.length);
diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-574223268.js b/deps/v8/test/mjsunit/regress/wasm/regress-574223268.js
new file mode 100644
index 00000000000..edbbaa76ede
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/wasm/regress-574223268.js
@@ -0,0 +1,55 @@
+// Copyright 2026 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 --stress-compaction
+
+d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
+
+function buildModule(numTargets, tableSize = numTargets) {
+  const builder = new WasmModuleBuilder();
+  builder.addMemory(1, 1);
+  const sig_v_v = builder.addType(kSig_v_v);
+  const sig_v_i = builder.addType(kSig_v_i);
+  const funcs = [];
+  for (let i = 0; i < numTargets; i++) {
+    const f = builder.addFunction('f' + i, sig_v_v)
+        .addBody([
+          kExprI32Const, 0,
+          kExprI32Const, 42 + i,
+          kExprI32StoreMem, 0, 0,
+        ])
+        .exportFunc();
+    funcs.push(f.index);
+  }
+  builder.addFunction('call', sig_v_i)
+      .addBody([
+        kExprLocalGet, 0,
+        kExprCallIndirect, sig_v_v, kTableZero,
+      ])
+      .exportFunc();
+  builder.setTableBounds(tableSize, tableSize);
+  builder.addActiveElementSegment(0, wasmI32Const(0), funcs);
+  return builder.toModule();
+}
+
+// Fill the bootstrap trusted page(s) (which are marked never_evacuate) so that
+// subsequent trusted objects land on movable pages.
+const filler = [];
+const fillerModule = buildModule(1, 2000);
+for (let i = 0; i < 64; i++) {
+  filler.push(new WebAssembly.Instance(fillerModule));
+}
+
+const targetModule = buildModule(2);
+const instance = new WebAssembly.Instance(targetModule);
+
+// Compile both callees up front.
+instance.exports.f0();
+instance.exports.f1();
+// Make the call site monomorphic on target 0.
+instance.exports.call(0);
+// Force the monomorphic-miss FixedArray allocation inside CallIndirectIC to
+// trigger a compacting GC while WasmTrustedInstanceData is on the stack.
+%SimulateNewspaceFull();
+instance.exports.call(1);
diff --git a/deps/v8/test/mjsunit/turbolev/regress-567129324.js b/deps/v8/test/mjsunit/turbolev/regress-567129324.js
new file mode 100644
index 00000000000..1abeaeaafc1
--- /dev/null
+++ b/deps/v8/test/mjsunit/turbolev/regress-567129324.js
@@ -0,0 +1,38 @@
+// Copyright 2026 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 --turbolev
+// Flags: --max-turbolev-eager-inlined-bytecode-size=0
+
+// The graph optimizer must not replace a TruncateChecked...ToInt32[Number]
+// with a cached truncation that only assumed NumberOrOddball: the Number check
+// narrows `x` (Smi|Boolean) to Smi, which the Smi-field store relies on.
+// `alt` must not be eagerly inlined, so that its truncation is only added to
+// the graph by the inliner, after `x | y` has been built.
+
+function alt(x) {
+  return Math.imul(x, 3);
+}
+
+const obj = { b: 123 };
+
+function f(flag, y, obj) {
+  const x = flag ? true : 123;
+  const a = alt(x);
+  const b = x | y;
+  obj.b = x;
+  return b + a;
+}
+
+%PrepareFunctionForOptimization(alt);
+%PrepareFunctionForOptimization(f);
+f(false, 0.125, obj);
+%OptimizeFunctionOnNextCall(f);
+assertEquals(123 + 369, f(false, 0.125, obj));
+assertOptimized(f);
+
+assertEquals(1 + 3, f(true, 0.125, obj));
+assertUnoptimized(f);
+assertEquals(true, obj.b);
+%HeapObjectVerify(obj);
diff --git a/deps/v8/test/mjsunit/turbolev/regress-568348290.js b/deps/v8/test/mjsunit/turbolev/regress-568348290.js
new file mode 100644
index 00000000000..2f39a98cc33
--- /dev/null
+++ b/deps/v8/test/mjsunit/turbolev/regress-568348290.js
@@ -0,0 +1,149 @@
+// Copyright 2026 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 --turbolev
+// Flags: --max-turbolev-eager-inlined-bytecode-size=0
+
+// 1. Unwrapping ReturnedValue(HoleyFloat64) for a kNumber truncation must
+// preserve the number check via CheckedHoleyFloat64ToFloat64.
+(function TestReturnedValueHoleyFloat64() {
+  function get_elem(arr, i) {
+    return arr[i];
+  }
+
+  function opt(arr, i) {
+    const x = get_elem(arr, i);
+    const y = x | 0;
+    return String(x) + y;
+  }
+
+  const holey = [1.5, , 2.5];
+  %PrepareFunctionForOptimization(get_elem);
+  %PrepareFunctionForOptimization(opt);
+  assertEquals('1.51', opt(holey, 0));
+  assertEquals(undefined, get_elem(holey, 1));
+  assertEquals('1.51', opt(holey, 0));
+  %OptimizeFunctionOnNextCall(opt);
+  assertEquals('1.51', opt(holey, 0));
+  assertOptimized(opt);
+
+  assertEquals('undefined0', opt(holey, 1));
+  assertUnoptimized(opt);
+})();
+
+// 2. Unwrapping HoleyFloat64ToTagged(HoleyFloat64) for a kNumber truncation
+// must also preserve the number check.
+(function TestHoleyFloat64ToTaggedConversion() {
+  function get_elem_tagged(arr, i, flag) {
+    let v = arr[i];
+    if (flag) {
+      v = arr[0];
+    }
+    return v;
+  }
+
+  function opt(arr, i, flag) {
+    const x = get_elem_tagged(arr, i, flag);
+    const y = x | 0;
+    return String(x) + y;
+  }
+
+  const holey = [1.5, , 2.5];
+  %PrepareFunctionForOptimization(get_elem_tagged);
+  %PrepareFunctionForOptimization(opt);
+  assertEquals('1.51', opt(holey, 0, false));
+  assertEquals(undefined, get_elem_tagged(holey, 1, false));
+  assertEquals(1.5, get_elem_tagged(holey, 1, true));
+  assertEquals('1.51', opt(holey, 0, false));
+  %OptimizeFunctionOnNextCall(opt);
+  assertEquals('1.51', opt(holey, 0, false));
+  assertOptimized(opt);
+
+  assertEquals('undefined0', opt(holey, 1, false));
+  assertUnoptimized(opt);
+})();
+
+// 3. A prior weaker truncation (NumberOrOddball via Math.imul) on the same
+// HoleyFloat64 node must not cause a subsequent kNumber truncation to skip
+// CheckedHoleyFloat64ToFloat64.
+(function TestWeakerTruncationBeforeNumberTruncation() {
+  function get_elem(arr, i) {
+    return arr[i];
+  }
+
+  function imul(x) {
+    return Math.imul(x, 3);
+  }
+
+  function opt(arr, i) {
+    const x = get_elem(arr, i);
+    const a = imul(x);
+    const b = x | 0;
+    return String(x) + a + b;
+  }
+
+  const holey = [1.5, , 2.5];
+  %PrepareFunctionForOptimization(get_elem);
+  %PrepareFunctionForOptimization(imul);
+  %PrepareFunctionForOptimization(opt);
+  assertEquals('1.531', opt(holey, 0));
+  assertEquals(undefined, get_elem(holey, 1));
+  assertEquals('1.531', opt(holey, 0));
+  %OptimizeFunctionOnNextCall(opt);
+  assertEquals('1.531', opt(holey, 0));
+  assertOptimized(opt);
+
+  assertEquals('undefined00', opt(holey, 1));
+  assertUnoptimized(opt);
+})();
+
+// 4. Merging kSmi and kJSReceiverOrNullOrUndefined and intersecting with
+// kNumber on `x | y` narrows `x` to kSmi, eliding CheckSmi on a subsequent
+// Smi-field store. Dropping the kNumber check corrupts `smi_obj.a` with
+// #undefined in a Smi field.
+(function TestSmiFieldCorruptionViaTypeIntersection() {
+  function get_elem(arr, i) {
+    return arr[i];
+  }
+
+  const smi_obj = {a: 100};
+  smi_obj.a = 1;
+
+  function opt(arr, i, mode, bailout, y, obj, n) {
+    const x = get_elem(arr, i);
+    let cmp = false;
+    if (mode === 1) {
+      cmp = (x + 1) === 2;
+    } else {
+      cmp = (x === n);
+      if (bailout) return 0;
+    }
+    const b = x | y;
+    obj.a = x;
+    return b + (cmp ? 1 : 0);
+  }
+
+  const smi_arr = [1, 2];
+  const holey = [1, , 2.5];
+
+  %PrepareFunctionForOptimization(opt);
+  opt(smi_arr, 0, 1, false, 0.125, smi_obj, null);
+  opt(smi_arr, 0, 1, false, 0.125, smi_obj, null);
+
+  %PrepareFunctionForOptimization(get_elem);
+  get_elem(holey, 0);
+  get_elem(holey, 1);
+
+  opt(holey, 1, 0, true, 0.125, smi_obj, null);
+  opt(holey, 1, 0, true, 0.125, smi_obj, null);
+
+  %OptimizeFunctionOnNextCall(opt);
+  assertEquals(2, opt(holey, 0, 1, false, 0.125, smi_obj, null));
+  assertOptimized(opt);
+
+  assertEquals(0, opt(holey, 1, 0, false, 0.125, smi_obj, null));
+  assertUnoptimized(opt);
+  assertEquals(undefined, smi_obj.a);
+  %HeapObjectVerify(smi_obj);
+})();
diff --git a/deps/v8/test/unittests/api/deserialize-unittest.cc b/deps/v8/test/unittests/api/deserialize-unittest.cc
index ecd607e46fe..fb9fb9983b7 100644
--- a/deps/v8/test/unittests/api/deserialize-unittest.cc
+++ b/deps/v8/test/unittests/api/deserialize-unittest.cc
@@ -1333,4 +1333,148 @@ TEST_F(MergeDeserializedCodeTest, MergeThatStartsButDoesNotFinish) {
   }
 }

+TEST_F(MergeDeserializedCodeTest, ModuleCacheClassicScriptMismatch) {
+  i::v8_flags.merge_background_deserialized_script_with_compilation_cache =
+      true;
+  std::unique_ptr<v8::ScriptCompiler::CachedData> cached_data;
+  IsolateAndContextScope scope(this);
+  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate());
+  PersistentScriptOrigin default_origin(
+      isolate(), NewString("http://example.com/test.js"));
+
+  constexpr char kPolyglotSource[] =
+      "let L0 = 1;\n"
+      "var z, o;\n"
+      "function g() { throw 1; }\n"
+      "function K(a, b) { var t = globalThis.top; (t.__keep = t.__keep || "
+      "[]).push(a, b); }\n"
+      "z = await /1; function lazyOuter() { function inner() {} } { try { g() "
+      "} catch /* 1, o = { a: function () {}, 'NAMENAMENAMENAME' //*/\n"
+      "(e) { K(() => e, function later() { return e }) } }\n";
+
+  // Setup: define `await` and `top` in global scope for classic script parse.
+  {
+    v8::HandleScope handle_scope(isolate());
+    Local<Script> setup =
+        Script::Compile(
+            context(), NewString("var await = 6; globalThis.top = globalThis;"))
+            .ToLocalChecked();
+    CHECK(!setup->Run(context()).IsEmpty());
+  }
+
+  // Step 1: Compile and run as a classic script, populating the Isolate
+  // compilation cache and retaining catch-block closures in globalThis.__keep.
+  // Also compile as a module with the same resource name and create a module
+  // code cache, then age and flush the classic script's top-level bytecode.
+  {
+    v8::HandleScope handle_scope(isolate());
+    ScriptOrigin classic_origin = default_origin.AsScriptOrigin();
+    Local<Script> script =
+        Script::Compile(context(), NewString(kPolyglotSource), &classic_origin)
+            .ToLocalChecked();
+    CHECK(!script->Run(context()).IsEmpty());
+
+    ScriptOrigin module_origin(NewString("http://example.com/test.js"), 0, 0,
+                               false, -1, Local<Value>(), false, false,
+                               /*is_module=*/true);
+    ScriptCompiler::Source module_source(NewString(kPolyglotSource),
+                                         module_origin);
+    Local<Module> module =
+        ScriptCompiler::CompileModule(isolate(), &module_source)
+            .ToLocalChecked();
+    cached_data.reset(
+        ScriptCompiler::CreateCodeCache(module->GetUnboundModuleScript()));
+
+    i::SharedFunctionInfo::EnsureOldForTesting(GetSharedFunctionInfo(script));
+  }
+
+  // Step 2: Flush the classic script's top-level bytecode via major GC.
+  {
+    i::DisableConservativeStackScanningScopeForTesting no_css_scope(
+        i_isolate->heap());
+    InvokeMajorGC(i_isolate);
+    InvokeMajorGC(i_isolate);
+  }
+
+  // Step 3a: Start off-thread consumption of the MODULE code cache, then notify
+  // SourceTextAvailable with the CLASSIC ScriptOrigin after Run() completes.
+  {
+    auto task_cached_data = std::make_unique<ScriptCompiler::CachedData>(
+        cached_data->data, cached_data->length,
+        ScriptCompiler::CachedData::BufferNotOwned);
+    DeserializeThread deserialize_thread(
+        ScriptCompiler::StartConsumingCodeCache(
+            isolate(), std::make_unique<ScriptCompiler::CachedData>(
+                           cached_data->data, cached_data->length,
+                           ScriptCompiler::CachedData::BufferNotOwned)));
+    CHECK(deserialize_thread.Start());
+    deserialize_thread.Join();
+
+    std::unique_ptr<ScriptCompiler::ConsumeCodeCacheTask> task =
+        deserialize_thread.TakeTask();
+    task->SourceTextAvailable(isolate(), NewString(kPolyglotSource),
+                              default_origin.AsScriptOrigin());
+    CHECK(!task->ShouldMergeWithExistingScript());
+
+    v8::HandleScope handle_scope(isolate());
+    ScriptCompiler::Source source(NewString(kPolyglotSource),
+                                  default_origin.AsScriptOrigin(),
+                                  task_cached_data.release(), task.release());
+    Local<Script> script =
+        ScriptCompiler::Compile(context(), &source,
+                                ScriptCompiler::kConsumeCodeCache)
+            .ToLocalChecked();
+    CHECK(!script.IsEmpty());
+    CHECK(source.GetCachedData()->rejected);
+
+    // Age and flush the recompiled classic script's top-level bytecode again so
+    // Step 3b also sees a flushed Script in the Isolate compilation cache.
+    i::SharedFunctionInfo::EnsureOldForTesting(GetSharedFunctionInfo(script));
+  }
+  {
+    i::DisableConservativeStackScanningScopeForTesting no_css_scope(
+        i_isolate->heap());
+    InvokeMajorGC(i_isolate);
+    InvokeMajorGC(i_isolate);
+  }
+
+  // Step 3b: Also test calling SourceTextAvailable on the main thread BEFORE
+  // Run() executes on the background thread.
+  {
+    auto task_cached_data = std::make_unique<ScriptCompiler::CachedData>(
+        cached_data->data, cached_data->length,
+        ScriptCompiler::CachedData::BufferNotOwned);
+    std::unique_ptr<ScriptCompiler::ConsumeCodeCacheTask> task(
+        ScriptCompiler::StartConsumingCodeCache(
+            isolate(), std::make_unique<ScriptCompiler::CachedData>(
+                           cached_data->data, cached_data->length,
+                           ScriptCompiler::CachedData::BufferNotOwned)));
+    task->SourceTextAvailable(isolate(), NewString(kPolyglotSource),
+                              default_origin.AsScriptOrigin());
+
+    DeserializeThread deserialize_thread(task.release());
+    CHECK(deserialize_thread.Start());
+    deserialize_thread.Join();
+    task = deserialize_thread.TakeTask();
+    CHECK(!task->ShouldMergeWithExistingScript());
+
+    v8::HandleScope handle_scope(isolate());
+    ScriptCompiler::Source source(NewString(kPolyglotSource),
+                                  default_origin.AsScriptOrigin(),
+                                  task_cached_data.release(), task.release());
+    Local<Script> script =
+        ScriptCompiler::Compile(context(), &source,
+                                ScriptCompiler::kConsumeCodeCache)
+            .ToLocalChecked();
+    CHECK(!script.IsEmpty());
+    CHECK(source.GetCachedData()->rejected);
+
+    Local<Script> run_kept =
+        Script::Compile(context(),
+                        NewString("for (const f of globalThis.__keep) f();"))
+            .ToLocalChecked();
+    CHECK(!run_kept->Run(context()).IsEmpty());
+  }
+}
+
 }  // namespace v8