V8 commit: 5068658e0b754814453e62dfe5898027ee052506

=== src/maglev/maglev-graph-builder.cc:4136-4146 (escape predicate) ===
  4136	bool MaglevGraphBuilder::IsEscaping(InlinedAllocation* alloc) {
  4137	  if (alloc->HasEscapingUses()) return true;
  4138	  auto it = graph_->allocations_elide_map().find(alloc);
  4139	  if (it == graph_->allocations_elide_map().end()) return false;
  4140	  for (InlinedAllocation* inner_alloc : it->second) {
  4141	    if (IsEscaping(inner_alloc)) {
  4142	      return true;
  4143	    }
  4144	  }
  4145	  return false;
  4146	}

=== src/maglev/maglev-graph-builder.cc:8745-8825 (vulnerable reducer) ===
  8745	
  8746	MaybeReduceResult MaglevGraphBuilder::TryReduceArrayIteratorPrototypeNext(
  8747	    compiler::JSFunctionRef target, CallArguments& args) {
  8748	  if (!CanSpeculateCall()) return {};
  8749	
  8750	  ValueNode* receiver = args.receiver();
  8751	  if (!receiver) return {};
  8752	
  8753	  if (!receiver->Is<InlinedAllocation>()) return {};
  8754	  VirtualObject* iterator = receiver->Cast<InlinedAllocation>()->object();
  8755	  if (!iterator->map() || !iterator->map()->IsJSArrayIteratorMap()) {
  8756	    FAIL("iterator is not a JS array iterator object");
  8757	  }
  8758	
  8759	  std::optional<MapInference> map_inference;
  8760	  ValueNode* iterated_object =
  8761	      iterator->get(offsetof(JSArrayIterator, iterated_object_));
  8762	  ElementsKind elements_kind;
  8763	  base::SmallVector<compiler::MapRef, 4> maps;
  8764	  if (iterated_object->Is<InlinedAllocation>()) {
  8765	    VirtualObject* array = iterated_object->Cast<InlinedAllocation>()->object();
  8766	    // TODO(victorgomes): Remove this once we track changes in the inlined
  8767	    // allocated object.
  8768	    if (IsEscaping(iterated_object->Cast<InlinedAllocation>())) {
  8769	      FAIL("allocation is escaping, map could have been changed");
  8770	    }
  8771	    // TODO(victorgomes): This effectively disable the optimization for `for-of`
  8772	    // loops. We need to figure it out a way to re-enable this.
  8773	    if (IsInsideLoop()) {
  8774	      FAIL("we're inside a loop, iterated object map could change");
  8775	    }
  8776	    auto map = *array->map();
  8777	    if (!map.supports_fast_array_iteration(broker())) {
  8778	      FAIL("no fast array iteration support");
  8779	    }
  8780	    elements_kind = map.elements_kind();
  8781	    maps.push_back(map);
  8782	  } else {
  8783	    map_inference.emplace(this, iterated_object);
  8784	    auto possible_maps = map_inference->TryGetPossibleMaps();
  8785	    if (!possible_maps) {
  8786	      FAIL("iterated object is unknown");
  8787	    }
  8788	    if (!CanInlineArrayIteratingBuiltin(broker(), *possible_maps,
  8789	                                        &elements_kind)) {
  8790	      FAIL("no fast array iteration support or incompatible maps");
  8791	    }
  8792	    for (auto map : *possible_maps) {
  8793	      maps.push_back(map);
  8794	    }
  8795	  }
  8796	
  8797	  // TODO(victorgomes): Support typed arrays.
  8798	  if (IsTypedArrayElementsKind(elements_kind)) {
  8799	    FAIL("no typed arrays support");
  8800	  }
  8801	
  8802	  if (IsHoleyElementsKind(elements_kind) &&
  8803	      !broker()->dependencies()->DependOnNoElementsProtector()) {
  8804	    FAIL("no elements protector");
  8805	  }
  8806	
  8807	  if (map_inference.has_value()) {
  8808	    RETURN_IF_ABORT(map_inference->InsertMapChecks(zone()));
  8809	  }
  8810	
  8811	  // Load the [[NextIndex]] from the {iterator}.
  8812	  // We can assume index and length fit in Uint32.
  8813	  ValueNode* index;
  8814	  GET_VALUE_OR_ABORT(
  8815	      index,
  8816	      BuildLoadTaggedField(receiver, offsetof(JSArrayIterator, next_index_)));
  8817	  ValueNode* uint32_index;
  8818	  GET_VALUE_OR_ABORT(uint32_index, GetUint32ElementIndex(index));
  8819	  ValueNode* length;
  8820	  GET_VALUE_OR_ABORT(
  8821	      length,
  8822	      BuildLoadJSArrayLength(iterated_object, IsFastElementsKind(elements_kind)
  8823	                                                  ? LoadType::kSmi
  8824	                                                  : LoadType::kNumber));
  8825	  ValueNode* uint32_length;

=== src/maglev/maglev-graph-builder.cc:5732-5792 (representation-specific element load) ===
  5732	ReduceResult MaglevGraphBuilder::BuildElementLoadOnJSArrayOrJSObject(
  5733	    ValueNode* object, ValueNode* index_object,
  5734	    base::Vector<const compiler::MapRef> maps, ElementsKind elements_kind,
  5735	    KeyedAccessLoadMode load_mode) {
  5736	  DCHECK(IsFastElementsKind(elements_kind));
  5737	  bool is_jsarray = HasOnlyJSArrayMaps(maps);
  5738	  DCHECK(is_jsarray || HasOnlyJSObjectMaps(maps));
  5739	
  5740	  ValueNode* elements_array;
  5741	  GET_VALUE_OR_ABORT(elements_array, BuildLoadElements(object, elements_kind));
  5742	  ValueNode* index;
  5743	  GET_VALUE_OR_ABORT(index, GetInt32ElementIndex(index_object));
  5744	  ValueNode* length;
  5745	  if (is_jsarray) {
  5746	    GET_VALUE_OR_ABORT(length, GetInt32(BuildLoadJSArrayLength(object)));
  5747	  } else {
  5748	    length = BuildLoadFixedArrayLength(elements_array);
  5749	  }
  5750	
  5751	  auto emit_load = [&]() -> ReduceResult {
  5752	    ValueNode* result;
  5753	    if (elements_kind == HOLEY_DOUBLE_ELEMENTS) {
  5754	      GET_VALUE_OR_ABORT(result, BuildLoadHoleyFixedDoubleArrayElement(
  5755	                                     elements_array, index,
  5756	                                     CanTreatHoleAsUndefined(maps) &&
  5757	                                         LoadModeHandlesHoles(load_mode)));
  5758	    } else if (elements_kind == PACKED_DOUBLE_ELEMENTS) {
  5759	      GET_VALUE_OR_ABORT(
  5760	          result, BuildLoadFixedDoubleArrayElement(elements_array, index));
  5761	    } else {
  5762	      DCHECK(!IsDoubleElementsKind(elements_kind));
  5763	      bool is_holey = IsHoleyElementsKind(elements_kind);
  5764	      bool is_holey_and_treat_hole_as_undefined =
  5765	          is_holey && CanTreatHoleAsUndefined(maps) &&
  5766	          LoadModeHandlesHoles(load_mode);
  5767	      bool is_smi = elements_kind == PACKED_SMI_ELEMENTS;
  5768	      GET_VALUE_OR_ABORT(result,
  5769	                         BuildLoadFixedArrayElement(
  5770	                             elements_array, index,
  5771	                             is_smi ? LoadType::kSmi : LoadType::kUnknown));
  5772	      if (is_holey) {
  5773	        if (is_holey_and_treat_hole_as_undefined) {
  5774	          GET_VALUE_OR_ABORT(result, BuildConvertHoleToUndefined(result));
  5775	        } else {
  5776	          RETURN_IF_ABORT(BuildCheckNotHole(result));
  5777	          if (IsSmiElementsKind(elements_kind)) {
  5778	            // After the hole-check, we're guaranteed to have a Smi.
  5779	            // TODO(dmercadier): EnsureType doesn't work nicely with the
  5780	            // MaglevOptimizer (because the MaglevOptimizer won't insert an
  5781	            // EnsureType and thus won't realize that we have a Smi). It would
  5782	            // be better to add a new SmiOrHole LoadType, which would be refined
  5783	            // to just Smi after we insert a hole check. This isn't trivial
  5784	            // because the Maglev type system currently doesn't have a "Hole"
  5785	            // type.
  5786	            EnsureType(result, NodeType::kSmi);
  5787	          }
  5788	        }
  5789	      }
  5790	    }
  5791	    return result;
  5792	  };

=== src/maglev/x64/maglev-assembler-x64-inl.h:396-436 (checks are debug_code-only) ===
   396	void MaglevAssembler::LoadFixedArrayElement(Register result, Register array,
   397	                                            Register index) {
   398	  if (v8_flags.debug_code) {
   399	    AssertObjectType(array, FIXED_ARRAY_TYPE, AbortReason::kUnexpectedValue);
   400	    CompareInt32AndAssert(index, 0, kUnsignedGreaterThanEqual,
   401	                          AbortReason::kUnexpectedNegativeValue);
   402	  }
   403	  LoadTaggedFieldByIndex(result, array, index, kTaggedSize,
   404	                         OFFSET_OF_DATA_START(FixedArray));
   405	}
   406	
   407	inline void MaglevAssembler::LoadTaggedFieldWithoutDecompressing(
   408	    Register result, Register object, int offset) {
   409	  MacroAssembler::LoadTaggedFieldWithoutDecompressing(
   410	      result, FieldMemOperand(object, offset));
   411	}
   412	
   413	void MaglevAssembler::LoadFixedArrayElementWithoutDecompressing(
   414	    Register result, Register array, Register index) {
   415	  if (v8_flags.debug_code) {
   416	    AssertObjectType(array, FIXED_ARRAY_TYPE, AbortReason::kUnexpectedValue);
   417	    CompareInt32AndAssert(index, 0, kUnsignedGreaterThanEqual,
   418	                          AbortReason::kUnexpectedNegativeValue);
   419	  }
   420	  MacroAssembler::LoadTaggedFieldWithoutDecompressing(
   421	      result, FieldOperand(array, index, times_tagged_size,
   422	                           OFFSET_OF_DATA_START(FixedArray)));
   423	}
   424	
   425	void MaglevAssembler::LoadFixedDoubleArrayElement(DoubleRegister result,
   426	                                                  Register array,
   427	                                                  Register index) {
   428	  if (v8_flags.debug_code) {
   429	    AssertObjectType(array, FIXED_DOUBLE_ARRAY_TYPE,
   430	                     AbortReason::kUnexpectedValue);
   431	    CompareInt32AndAssert(index, 0, kUnsignedGreaterThanEqual,
   432	                          AbortReason::kUnexpectedNegativeValue);
   433	  }
   434	  Movsd(result, FieldOperand(array, index, times_8,
   435	                             OFFSET_OF_DATA_START(FixedDoubleArray)));
   436	}

=== src/flags/flag-definitions.h:2860-2880 (production debug_code is false) ===
  2860	// assembler-ia32.cc / assembler-arm.cc / assembler-arm64.cc / assembler-x64.cc
  2861	#ifdef V8_ENABLE_DEBUG_CODE
  2862	DEFINE_BOOL(debug_code, DEBUG_BOOL,
  2863	            "generate extra code (assertions) for debugging")
  2864	DEFINE_BOOL(trap_on_abort, false, "trap instead of calling abort for debugging")
  2865	#if defined(V8_ENABLE_SLOW_DEBUG_CODE_BY_DEFAULT) || \
  2866	    defined(ENABLE_SLOW_DCHECKS)
  2867	#define V8_ENABLE_SLOW_DEBUG_CODE_BY_DEFAULT_BOOL true
  2868	#else
  2869	#define V8_ENABLE_SLOW_DEBUG_CODE_BY_DEFAULT_BOOL false
  2870	#endif
  2871	// slow_debug_code is enabled by default for builds with is_debug or
  2872	// v8_enable_slow_dchecks.
  2873	DEFINE_BOOL(slow_debug_code, V8_ENABLE_SLOW_DEBUG_CODE_BY_DEFAULT_BOOL,
  2874	            "generate slow extra code (assertions) for debugging")
  2875	DEFINE_NEG_NEG_IMPLICATION(debug_code, slow_debug_code)
  2876	#else
  2877	DEFINE_BOOL_READONLY(debug_code, false, "")
  2878	DEFINE_BOOL_READONLY(trap_on_abort, true, "")
  2879	DEFINE_BOOL_READONLY(slow_debug_code, false, "")
  2880	#endif

=== src/builtins/accessors.cc:387-453 (materializing inlined frame arguments) ===
   387	Handle<JSObject> ArgumentsFromDeoptInfo(JavaScriptFrame* frame,
   388	                                        int inlined_frame_index) {
   389	  Isolate* isolate = frame->isolate();
   390	  Factory* factory = isolate->factory();
   391	
   392	  TranslatedState translated_values(frame);
   393	  translated_values.Prepare(frame->fp());
   394	
   395	  int argument_count = 0;
   396	  TranslatedFrame* translated_frame =
   397	      translated_values.GetArgumentsInfoFromJSFrameIndex(inlined_frame_index,
   398	                                                         &argument_count);
   399	  TranslatedFrame::iterator iter = translated_frame->begin();
   400	
   401	  // Materialize the function.
   402	  bool should_deoptimize = iter->IsMaterializedObject();
   403	  DirectHandle<JSFunction> function = Cast<JSFunction>(iter->GetValue());
   404	  iter++;
   405	
   406	  // Skip the receiver.
   407	  iter++;
   408	  argument_count--;
   409	
   410	  Handle<JSObject> arguments =
   411	      factory->NewArgumentsObject(function, argument_count);
   412	  DirectHandle<FixedArray> array = factory->NewFixedArray(argument_count);
   413	  for (int i = 0; i < argument_count; ++i) {
   414	    // If we materialize any object, we should deoptimize the frame because we
   415	    // might alias an object that was eliminated by escape analysis.
   416	    should_deoptimize = should_deoptimize || iter->IsMaterializedObject();
   417	    DirectHandle<Object> value = iter->GetValue();
   418	    array->set(i, *value);
   419	    iter++;
   420	  }
   421	  arguments->set_elements(*array);
   422	
   423	  if (should_deoptimize) {
   424	    translated_values.StoreMaterializedValuesAndDeopt(frame);
   425	  }
   426	
   427	  // Return the freshly allocated arguments object.
   428	  return arguments;
   429	}
   430	
   431	int FindFunctionInFrame(JavaScriptFrame* frame,
   432	                        DirectHandle<JSFunction> function) {
   433	  FrameSummaries summaries = frame->Summarize();
   434	  for (int i = summaries.size(); i != 0; i--) {
   435	    if (*summaries.frames[i - 1].AsJavaScript().function() == *function) {
   436	      return static_cast<int>(i) - 1;
   437	    }
   438	  }
   439	  return -1;
   440	}
   441	
   442	Handle<JSObject> GetFrameArguments(Isolate* isolate,
   443	                                   JavaScriptStackFrameIterator* it,
   444	                                   int function_index) {
   445	  JavaScriptFrame* frame = it->frame();
   446	
   447	  if (function_index > 0) {
   448	    // The function in question was inlined.  Inlined functions have the
   449	    // correct number of arguments and no allocated arguments object, so
   450	    // we can construct a fresh one by interpreting the function's
   451	    // deoptimization input data.
   452	    return ArgumentsFromDeoptInfo(frame, function_index);
   453	  }

=== src/builtins/accessors.cc:511-527 (legacy frame walk) ===
   511	// static
   512	DirectHandle<Object> Accessors::GetLegacyFunctionArguments(
   513	    Isolate* isolate, DirectHandle<JSFunction> function) {
   514	  DirectHandle<Object> result = isolate->factory()->null_value();
   515	  if (!function->shared()->native()) {
   516	    // Find the top invocation of the function by traversing frames.
   517	    for (JavaScriptStackFrameIterator it(isolate); !it.done(); it.Advance()) {
   518	      JavaScriptFrame* frame = it.frame();
   519	      int function_index = FindFunctionInFrame(frame, function);
   520	      if (function_index >= 0) {
   521	        result = GetFrameArguments(isolate, &it, function_index);
   522	        break;
   523	      }
   524	    }
   525	  }
   526	  return result;
   527	}

=== src/deoptimizer/deoptimizer.h:102-112 (deoptimization is lazy on return) ===
   102	  static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame,
   103	                                                        int jsframe_index,
   104	                                                        Isolate* isolate);
   105	
   106	  // Deoptimize the function now. Its current optimized code will never be run
   107	  // again and any activations of the optimized code will get deoptimized when
   108	  // execution returns. If {code} is specified then the given code is targeted
   109	  // instead of the function code (e.g. OSR code not installed on function).
   110	  static void DeoptimizeFunction(Tagged<JSFunction> function,
   111	                                 LazyDeoptimizeReason reason,
   112	                                 Tagged<Code> code = {});

=== src/deoptimizer/translated-state.cc:2768-2832 (store materialized values and mark code) ===
  2768	void TranslatedState::StoreMaterializedValuesAndDeopt(JavaScriptFrame* frame) {
  2769	  MaterializedObjectStore* materialized_store =
  2770	      isolate_->materialized_object_store();
  2771	  DirectHandle<FixedArray> previously_materialized_objects =
  2772	      materialized_store->Get(stack_frame_pointer_);
  2773	
  2774	  Handle<Object> marker = isolate_->factory()->arguments_marker();
  2775	
  2776	  uint32_t length = base::checked_cast<uint32_t>(object_positions_.size());
  2777	  bool new_store = false;
  2778	  if (previously_materialized_objects.is_null()) {
  2779	    previously_materialized_objects =
  2780	        isolate_->factory()->NewFixedArray(length, AllocationType::kOld);
  2781	    for (uint32_t i = 0; i < length; i++) {
  2782	      previously_materialized_objects->set(i, *marker);
  2783	    }
  2784	    new_store = true;
  2785	  }
  2786	
  2787	  CHECK_EQ(length, previously_materialized_objects->ulength().value());
  2788	
  2789	  bool value_changed = false;
  2790	  for (uint32_t i = 0; i < length; i++) {
  2791	    TranslatedState::ObjectPosition pos = object_positions_[i];
  2792	    TranslatedValue* value_info =
  2793	        &(frames_[pos.frame_index_].values_[pos.value_index_]);
  2794	
  2795	    CHECK(value_info->IsMaterializedObject());
  2796	
  2797	    // Skip duplicate objects (i.e., those that point to some other object id).
  2798	    if (static_cast<uint32_t>(value_info->object_index()) != i) continue;
  2799	
  2800	    DirectHandle<Object> previous_value(previously_materialized_objects->get(i),
  2801	                                        isolate_);
  2802	    DirectHandle<Object> value(value_info->GetRawValue(), isolate_);
  2803	
  2804	    if (value.is_identical_to(marker)) {
  2805	      DCHECK_EQ(*previous_value, *marker);
  2806	    } else {
  2807	      if (*previous_value == *marker) {
  2808	        if (IsSmi(*value)) {
  2809	          value =
  2810	              isolate()->factory()->NewHeapNumber(Object::NumberValue(*value));
  2811	        }
  2812	        previously_materialized_objects->set(i, *value);
  2813	        value_changed = true;
  2814	      } else {
  2815	        CHECK(*previous_value == *value ||
  2816	              (IsHeapNumber(*previous_value) && IsSmi(*value) &&
  2817	               Object::NumberValue(*previous_value) ==
  2818	                   Object::NumberValue(*value)));
  2819	      }
  2820	    }
  2821	  }
  2822	
  2823	  if (new_store && value_changed) {
  2824	    materialized_store->Set(stack_frame_pointer_,
  2825	                            previously_materialized_objects);
  2826	    CHECK_EQ(frames_[0].kind(), TranslatedFrame::kUnoptimizedFunction);
  2827	    CHECK_EQ(frame->function(), frames_[0].front().GetRawValue());
  2828	    Deoptimizer::DeoptimizeFunction(
  2829	        frame->function(), LazyDeoptimizeReason::kFrameValueMaterialized,
  2830	        frame->LookupCode());
  2831	  }
  2832	}

=== src/builtins/builtins-collections-gen.cc:3184-3196 (TheHole security guard) ===
  3184	  auto context = Parameter<Context>(Descriptor::kContext);
  3185	  auto receiver = Parameter<Object>(Descriptor::kReceiver);
  3186	  auto key = Parameter<Object>(Descriptor::kKey);
  3187	
  3188	  ThrowIfNotInstanceType(context, receiver, JS_WEAK_MAP_TYPE,
  3189	                         "WeakMap.prototype.delete");
  3190	
  3191	  // This check breaks a known exploitation technique. See crbug.com/1263462
  3192	  CSA_HOLE_SECURITY_CHECK(this, TaggedNotEqual(key, TheHoleConstant()));
  3193	
  3194	  Return(CallBuiltin(Builtin::kWeakCollectionDelete, context, receiver, key));
  3195	}
  3196	

=== test/mjsunit/maglev/regress-495751197.js (nearby graph-visible case already covered upstream) ===
     1	// Copyright 2026 the V8 project authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style license that can be
     3	// found in the LICENSE file.
     4	
     5	// Flags: --allow-natives-syntax
     6	
     7	let do_transition = false;
     8	let marker = {x: 1.337};
     9	
    10	Object.defineProperty(Object.prototype, '_leak', {
    11	  get() {
    12	    if (do_transition) {
    13	      this[1][0] = marker;
    14	    }
    15	    return this;
    16	  },
    17	  configurable: true
    18	});
    19	
    20	function target(iter) {
    21	  return iter.next().value;
    22	}
    23	
    24	function inner() {
    25	  var leaked;
    26	  // Forces WithContext creation. _leak triggers the runtime call.
    27	  with (arguments) { leaked = _leak; }
    28	  return target.apply(null, arguments);
    29	}
    30	
    31	function outer() {
    32	  let a = [1.1, 2.2, 3.3];
    33	  let iter = a.values();
    34	  return inner(iter, a);
    35	}
    36	
    37	%PrepareFunctionForOptimization(target);
    38	%PrepareFunctionForOptimization(inner);
    39	%PrepareFunctionForOptimization(outer);
    40	
    41	outer(); outer(); outer();
    42	
    43	%OptimizeMaglevOnNextCall(outer);
    44	
    45	do_transition = true;
    46	let r = outer();
    47	assertFalse(typeof r === "number");
