Browse Source

chore: cherry-pick 10 changes from 3-M126 (#43142)

* chore: [29-x-y] cherry-pick 11 changes from 3-M126

* d54105311590 from chromium
* 43b8b682d05c from chromium
* c5dd8839bfaf from chromium
* cdbc1d9684a3 from v8
* 38e4483e47f9 from chromium
* 70d2fe6b7c47 from v8
* 901377bb2f3b from v8
* 1b9040817119 from chromium
* bb28367eed73 from v8
* 99cafbf4b4b9 from chromium
* bc545b15a0ee from v8

* chore: update patches

* 5672472: [M120-LTS] Prevent script injection on reload when racing with a navigation | https://chromium-review.googlesource.com/c/chromium/src/+/5672472

* 5645901: [maglev] Fix skipped smi check due to phi hoisting | https://chromium-review.googlesource.com/c/v8/v8/+/5645901

Patch does not apply, hoisting is not used

* 5639725: [wasm] Fix scanning of wasm-to-js params | https://chromium-review.googlesource.com/c/v8/v8/+/5639725

* 5630530: [turboshaft] Lower LoadStackArgument to a Tagged load | https://chromium-review.googlesource.com/c/v8/v8/+/5630530

---------

Co-authored-by: Shelley Vohr <[email protected]>
Keeley Hammond 8 months ago
parent
commit
13fd9851c9

+ 6 - 0
patches/chromium/.patches

@@ -150,4 +150,10 @@ cherry-pick-24329fe5c4d0.patch
 m120-lts_mediasession_use_a_mediasessionimpl_weakptr_in.patch
 x11_fix_crash_when_randr_getmonitors_fails.patch
 feat_enable_passing_exit_code_on_service_process_crash.patch
+cherry-pick-d54105311590.patch
+cherry-pick-43b8b682d05c.patch
+cherry-pick-c5dd8839bfaf.patch
+cherry-pick-38e4483e47f9.patch
+cherry-pick-1b9040817119.patch
+cherry-pick-99cafbf4b4b9.patch
 cherry-pick-44b7fbf35b10.patch

+ 84 - 0
patches/chromium/cherry-pick-1b9040817119.patch

@@ -0,0 +1,84 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Bryant Chandler <[email protected]>
+Date: Mon, 24 Jun 2024 17:28:53 +0000
+Subject: Fix pointer tear down order problem
+
+Holding a RenderFrameHost* in the `OnceBinding` isn't safe,
+because the `RenderFrameHost` can be destroyed before the
+binding. This CL changes the task strategy so that the
+RenderFrameHost* doesn't need to be bound in a callback.
+
+Tested using the repro steps in the bug and this change stops
+it from reproducing.
+
+Fixed: 347373236
+Change-Id: Id639f317b0f37a508833aba9fe52ffc5c0ed590c
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5640501
+Reviewed-by: Dave Tapuska <[email protected]>
+Commit-Queue: Bryant Chandler <[email protected]>
+Reviewed-by: Guido Urdaneta <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#1318653}
+
+diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
+index 5db8665f1466dcfd896b3de3b2f3a2ae307e87de..0153cd1160cb47de471df92211c320920758058a 100644
+--- a/content/browser/renderer_host/media/media_stream_manager.cc
++++ b/content/browser/renderer_host/media/media_stream_manager.cc
+@@ -2847,25 +2847,19 @@ void MediaStreamManager::GetRawDeviceIdsOpenedForFrame(
+     RenderFrameHost* render_frame_host,
+     blink::mojom::MediaStreamType type,
+     GetRawDeviceIdsOpenedForFrameCallback callback) const {
+-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+-  CHECK(render_frame_host);
+-  auto collect_all_render_frame_host_ids = base::BindOnce(
+-      [](RenderFrameHost* render_frame_host) {
+-        base::flat_set<GlobalRenderFrameHostId> all_render_frame_host_ids;
+-        render_frame_host->ForEachRenderFrameHost(
+-            [&all_render_frame_host_ids](RenderFrameHost* render_frame_host) {
+-              all_render_frame_host_ids.insert(
+-                  render_frame_host->GetGlobalId());
+-            });
+-        return all_render_frame_host_ids;
+-      },
+-      render_frame_host);
+-
+-  GetUIThreadTaskRunner()->PostTaskAndReplyWithResult(
+-      FROM_HERE, std::move(collect_all_render_frame_host_ids),
+-      base::BindPostTaskToCurrentDefault(
+-          base::BindOnce(&MediaStreamManager::GetRawDeviceIdsOpenedForFrameIds,
+-                         base::Unretained(this), type, std::move(callback))));
++  DCHECK_CURRENTLY_ON(BrowserThread::UI);
++
++  base::flat_set<GlobalRenderFrameHostId> all_render_frame_host_ids;
++  render_frame_host->ForEachRenderFrameHost(
++      [&all_render_frame_host_ids](RenderFrameHost* render_frame_host) {
++        all_render_frame_host_ids.insert(render_frame_host->GetGlobalId());
++      });
++
++  GetIOThreadTaskRunner()->PostTask(
++      FROM_HERE,
++      base::BindOnce(&MediaStreamManager::GetRawDeviceIdsOpenedForFrameIds,
++                     base::Unretained(this), type, std::move(callback),
++                     all_render_frame_host_ids));
+ }
+ 
+ void MediaStreamManager::GetRawDeviceIdsOpenedForFrameIds(
+diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
+index 00e0321382a562ffb3733c48540d4f3071f13527..90cd9138510cf1c4a77bdd39610890a407870a22 100644
+--- a/content/browser/web_contents/web_contents_impl.cc
++++ b/content/browser/web_contents/web_contents_impl.cc
+@@ -10613,12 +10613,9 @@ void WebContentsImpl::GetMediaCaptureRawDeviceIdsOpened(
+     return;
+   }
+ 
+-  GetIOThreadTaskRunner({})->PostTask(
+-      FROM_HERE,
+-      base::BindOnce(&MediaStreamManager::GetRawDeviceIdsOpenedForFrame,
+-                     base::Unretained(media_stream_manager),
+-                     GetPrimaryMainFrame(), type,
+-                     base::BindPostTaskToCurrentDefault(std::move(callback))));
++  media_stream_manager->GetRawDeviceIdsOpenedForFrame(
++      GetPrimaryMainFrame(), type,
++      base::BindPostTaskToCurrentDefault(std::move(callback)));
+ }
+ 
+ }  // namespace content

+ 88 - 0
patches/chromium/cherry-pick-38e4483e47f9.patch

@@ -0,0 +1,88 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Johannes Kron <[email protected]>
+Date: Wed, 19 Jun 2024 20:59:48 +0000
+Subject: Use BindPostTask() + weak pointer in callback handler
+
+The callback handler incorrectly accessed member objects directly which may
+cause UAF. Avoid this by using BindPostTask() together with a weak pointer.
+
+Fixed: 346898524
+Change-Id: I9d03d6decfd0212af88d3d0d8d70f83f1081d2e3
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5639016
+Reviewed-by: Avi Drissman <[email protected]>
+Reviewed-by: Mark Foltz <[email protected]>
+Commit-Queue: Johannes Kron <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#1317142}
+
+diff --git a/content/browser/media/capture/screen_capture_kit_device_mac.mm b/content/browser/media/capture/screen_capture_kit_device_mac.mm
+index 4fb3e8eb5f34a7ee9e8b0f22a7c842129cdc31eb..e2710fba1a8d7a4cee6023558898c74706a9c189 100644
+--- a/content/browser/media/capture/screen_capture_kit_device_mac.mm
++++ b/content/browser/media/capture/screen_capture_kit_device_mac.mm
+@@ -326,13 +326,18 @@ void OnStreamSample(gfx::ScopedInUseIOSurface io_surface,
+                                destRectInFrame:dest_rect_in_frame
+                                      frameRate:requested_capture_format_->
+                                                frame_rate];
++
++          __block base::OnceCallback<void()> on_update_configuration_error =
++              base::BindPostTask(
++                  device_task_runner_,
++                  base::BindOnce(
++                      &ScreenCaptureKitDeviceMac::OnUpdateConfigurationError,
++                      weak_factory_.GetWeakPtr()));
+           [stream_
+               updateConfiguration:config
+                 completionHandler:^(NSError* _Nullable error) {
+                   if (error) {
+-                    client()->OnError(
+-                        media::VideoCaptureError::kScreenCaptureKitStreamError,
+-                        FROM_HERE, "Error on updateConfiguration");
++                    std::move(on_update_configuration_error).Run();
+                   }
+                 }];
+         }
+@@ -361,6 +366,21 @@ void OnStreamError() {
+                         FROM_HERE, "Stream delegate called didStopWithError");
+     }
+   }
++  void OnUpdateContentFilterCompleted(NSError* _Nullable error) {
++    DCHECK(device_task_runner_->RunsTasksInCurrentSequence());
++    is_resetting_ = false;
++
++    if (error) {
++      client()->OnError(media::VideoCaptureError::kScreenCaptureKitStreamError,
++                        FROM_HERE,
++                        "Error on updateContentFilter (fullscreen window).");
++    }
++  }
++  void OnUpdateConfigurationError() {
++    DCHECK(device_task_runner_->RunsTasksInCurrentSequence());
++    client()->OnError(media::VideoCaptureError::kScreenCaptureKitStreamError,
++                      FROM_HERE, "Error on updateConfiguration");
++  }
+ 
+   // IOSurfaceCaptureDeviceBase:
+   void OnStart() override {
+@@ -411,15 +431,16 @@ void ResetStreamTo(SCWindow* window) override {
+     SCContentFilter* filter =
+         [[SCContentFilter alloc] initWithDesktopIndependentWindow:window];
+ 
++    __block base::OnceCallback<void(NSError*)>
++        on_update_content_filter_completed = base::BindPostTask(
++            device_task_runner_,
++            base::BindOnce(
++                &ScreenCaptureKitDeviceMac::OnUpdateContentFilterCompleted,
++                weak_factory_.GetWeakPtr()));
++
+     [stream_ updateContentFilter:filter
+                completionHandler:^(NSError* _Nullable error) {
+-                 is_resetting_ = false;
+-                 if (error) {
+-                   client()->OnError(
+-                       media::VideoCaptureError::kScreenCaptureKitStreamError,
+-                       FROM_HERE,
+-                       "Error on updateContentFilter (fullscreen window).");
+-                 }
++                 std::move(on_update_content_filter_completed).Run(error);
+                }];
+   }
+ 

+ 264 - 0
patches/chromium/cherry-pick-43b8b682d05c.patch

@@ -0,0 +1,264 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Philip Pfaffe <[email protected]>
+Date: Tue, 18 Jun 2024 10:04:45 +0000
+Subject: Prevent script injection on reload when racing with a navigation
+
+DevTools passes the loaderId now when calling Page.reload, in order to
+prevent accidentally reloading the wrong page when a navigation occurred
+concurrently. It can still happen that the navigation kicks in in between the reload iniated in the browser and the script injection that happens in the renderer, which would run the injected script on the wrong target. We need to check the loaderId also on the renderer side.
+
+Fixed: 341136300
+Change-Id: I891fb37fa10e6789c8697a0f29bf7118788a9319
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5625857
+Reviewed-by: Andrey Kosyakov <[email protected]>
+Commit-Queue: Philip Pfaffe <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#1316330}
+
+diff --git a/third_party/blink/renderer/core/inspector/build.gni b/third_party/blink/renderer/core/inspector/build.gni
+index 2e9feebe066f938506d63d157be65828aa2a27c9..39de006f5f97f9e2a84ee4d38f7bb98e99c41924 100644
+--- a/third_party/blink/renderer/core/inspector/build.gni
++++ b/third_party/blink/renderer/core/inspector/build.gni
+@@ -138,6 +138,7 @@ blink_core_tests_inspector = [
+   "inspector_emulation_agent_test.cc",
+   "inspector_highlight_test.cc",
+   "inspector_history_test.cc",
++  "inspector_page_agent_unittest.cc",
+   "inspector_preload_agent_unittest.cc",
+   "inspector_media_context_impl_unittest.cc",
+   "inspector_session_state_test.cc",
+diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
+index 6936ee92726937deba7e85e30259d7d276f6a397..b4a38117cad3fbe032ac578724032fec7fd6e586 100644
+--- a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
++++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
+@@ -477,6 +477,42 @@ String InspectorPageAgent::CachedResourceTypeJson(
+   return ResourceTypeJson(ToResourceType(cached_resource.GetType()));
+ }
+ 
++InspectorPageAgent::PageReloadScriptInjection::PageReloadScriptInjection(
++    InspectorAgentState& agent_state)
++    : pending_script_to_evaluate_on_load_once_(&agent_state,
++                                               /*default_value=*/{}),
++      target_url_for_pending_script_(&agent_state,
++                                     /*default_value=*/{}) {}
++
++void InspectorPageAgent::PageReloadScriptInjection::clear() {
++  script_to_evaluate_on_load_once_ = {};
++  pending_script_to_evaluate_on_load_once_.Set({});
++  target_url_for_pending_script_.Set({});
++}
++
++void InspectorPageAgent::PageReloadScriptInjection::SetPending(
++    String script,
++    const KURL& target_url) {
++  pending_script_to_evaluate_on_load_once_.Set(script);
++  target_url_for_pending_script_.Set(target_url.GetString());
++}
++
++void InspectorPageAgent::PageReloadScriptInjection::PromoteToLoadOnce() {
++  script_to_evaluate_on_load_once_ =
++      pending_script_to_evaluate_on_load_once_.Get();
++  target_url_for_active_script_ = target_url_for_pending_script_.Get();
++  pending_script_to_evaluate_on_load_once_.Set({});
++  target_url_for_pending_script_.Set({});
++}
++
++String InspectorPageAgent::PageReloadScriptInjection::GetScriptForInjection(
++    const KURL& target_url) {
++  if (target_url_for_active_script_ == target_url.GetString()) {
++    return script_to_evaluate_on_load_once_;
++  }
++  return {};
++}
++
+ InspectorPageAgent::InspectorPageAgent(
+     InspectedFrames* inspected_frames,
+     Client* client,
+@@ -493,8 +529,6 @@ InspectorPageAgent::InspectorPageAgent(
+       screencast_enabled_(&agent_state_, /*default_value=*/false),
+       lifecycle_events_enabled_(&agent_state_, /*default_value=*/false),
+       bypass_csp_enabled_(&agent_state_, /*default_value=*/false),
+-      pending_script_to_evaluate_on_load_once_(&agent_state_,
+-                                               /*default_value=*/String()),
+       scripts_to_evaluate_on_load_(&agent_state_,
+                                    /*default_value=*/String()),
+       worlds_to_evaluate_on_load_(&agent_state_,
+@@ -504,7 +538,8 @@ InspectorPageAgent::InspectorPageAgent(
+           /*default_value=*/false),
+       standard_font_size_(&agent_state_, /*default_value=*/0),
+       fixed_font_size_(&agent_state_, /*default_value=*/0),
+-      script_font_families_cbor_(&agent_state_, std::vector<uint8_t>()) {}
++      script_font_families_cbor_(&agent_state_, std::vector<uint8_t>()),
++      script_injection_on_load_(agent_state_) {}
+ 
+ void InspectorPageAgent::Restore() {
+   if (enabled_.Get())
+@@ -543,8 +578,7 @@ protocol::Response InspectorPageAgent::enable() {
+ protocol::Response InspectorPageAgent::disable() {
+   agent_state_.ClearAllFields();
+   pending_isolated_worlds_.clear();
+-  script_to_evaluate_on_load_once_ = String();
+-  pending_script_to_evaluate_on_load_once_.Set(String());
++  script_injection_on_load_.clear();
+   instrumenting_agents_->RemoveInspectorPageAgent(this);
+   inspector_resource_content_loader_->Cancel(
+       resource_content_loader_client_id_);
+@@ -670,8 +704,9 @@ protocol::Response InspectorPageAgent::setAdBlockingEnabled(bool enable) {
+ protocol::Response InspectorPageAgent::reload(
+     Maybe<bool> optional_bypass_cache,
+     Maybe<String> optional_script_to_evaluate_on_load) {
+-  pending_script_to_evaluate_on_load_once_.Set(
+-      optional_script_to_evaluate_on_load.value_or(""));
++  script_injection_on_load_.SetPending(
++      optional_script_to_evaluate_on_load.value_or(""),
++      inspected_frames_->Root()->Loader().GetDocumentLoader()->Url());
+   v8_session_->setSkipAllPauses(true);
+   v8_session_->resume(true /* terminate on resume */);
+   return protocol::Response::Success();
+@@ -987,7 +1022,9 @@ void InspectorPageAgent::DidCreateMainWorldContext(LocalFrame* frame) {
+     EvaluateScriptOnNewDocument(*frame, key);
+   }
+ 
+-  if (script_to_evaluate_on_load_once_.empty()) {
++  String script = script_injection_on_load_.GetScriptForInjection(
++      frame->Loader().GetDocumentLoader()->Url());
++  if (script.empty()) {
+     return;
+   }
+   ScriptState* script_state = ToScriptStateForMainWorld(frame);
+@@ -995,9 +1032,8 @@ void InspectorPageAgent::DidCreateMainWorldContext(LocalFrame* frame) {
+     return;
+   }
+ 
+-  v8_session_->evaluate(
+-      script_state->GetContext(),
+-      ToV8InspectorStringView(script_to_evaluate_on_load_once_));
++  v8_session_->evaluate(script_state->GetContext(),
++                        ToV8InspectorStringView(script));
+ }
+ 
+ void InspectorPageAgent::EvaluateScriptOnNewDocument(
+@@ -1047,9 +1083,7 @@ void InspectorPageAgent::LoadEventFired(LocalFrame* frame) {
+ 
+ void InspectorPageAgent::WillCommitLoad(LocalFrame*, DocumentLoader* loader) {
+   if (loader->GetFrame() == inspected_frames_->Root()) {
+-    script_to_evaluate_on_load_once_ =
+-        pending_script_to_evaluate_on_load_once_.Get();
+-    pending_script_to_evaluate_on_load_once_.Set(String());
++    script_injection_on_load_.PromoteToLoadOnce();
+   }
+   GetFrontend()->frameNavigated(BuildObjectForFrame(loader->GetFrame()),
+                                 protocol::Page::NavigationTypeEnum::Navigation);
+diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.h b/third_party/blink/renderer/core/inspector/inspector_page_agent.h
+index d0da21e12df1dd11bd57b2226491f61aa34d62c9..3eb5e24fb13428e38a1ebc2e64bdeab9eed28ef2 100644
+--- a/third_party/blink/renderer/core/inspector/inspector_page_agent.h
++++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.h
+@@ -93,6 +93,22 @@ class CORE_EXPORT InspectorPageAgent final
+     kOtherResource
+   };
+ 
++  class CORE_EXPORT PageReloadScriptInjection {
++   private:
++    String script_to_evaluate_on_load_once_;
++    String target_url_for_active_script_;
++    InspectorAgentState::String pending_script_to_evaluate_on_load_once_;
++    InspectorAgentState::String target_url_for_pending_script_;
++
++   public:
++    explicit PageReloadScriptInjection(InspectorAgentState&);
++
++    void clear();
++    void SetPending(String script, const KURL& target_url);
++    void PromoteToLoadOnce();
++    String GetScriptForInjection(const KURL& target_url);
++  };
++
+   static bool CachedResourceContent(const Resource*,
+                                     String* result,
+                                     bool* base64_encoded);
+@@ -306,7 +322,6 @@ class CORE_EXPORT InspectorPageAgent final
+       ad_script_identifiers_;
+   v8_inspector::V8InspectorSession* v8_session_;
+   Client* client_;
+-  String script_to_evaluate_on_load_once_;
+   Member<InspectorResourceContentLoader> inspector_resource_content_loader_;
+   int resource_content_loader_client_id_;
+   InspectorAgentState::Boolean intercept_file_chooser_;
+@@ -314,7 +329,6 @@ class CORE_EXPORT InspectorPageAgent final
+   InspectorAgentState::Boolean screencast_enabled_;
+   InspectorAgentState::Boolean lifecycle_events_enabled_;
+   InspectorAgentState::Boolean bypass_csp_enabled_;
+-  InspectorAgentState::String pending_script_to_evaluate_on_load_once_;
+   InspectorAgentState::StringMap scripts_to_evaluate_on_load_;
+   InspectorAgentState::StringMap worlds_to_evaluate_on_load_;
+   InspectorAgentState::BooleanMap
+@@ -322,6 +336,7 @@ class CORE_EXPORT InspectorPageAgent final
+   InspectorAgentState::Integer standard_font_size_;
+   InspectorAgentState::Integer fixed_font_size_;
+   InspectorAgentState::Bytes script_font_families_cbor_;
++  PageReloadScriptInjection script_injection_on_load_;
+ };
+ 
+ }  // namespace blink
+diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent_unittest.cc b/third_party/blink/renderer/core/inspector/inspector_page_agent_unittest.cc
+new file mode 100644
+index 0000000000000000000000000000000000000000..b81f6b4735392f3f542ccbb2a114c2def185be1c
+--- /dev/null
++++ b/third_party/blink/renderer/core/inspector/inspector_page_agent_unittest.cc
+@@ -0,0 +1,57 @@
++// Copyright 2024 The Chromium Authors
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#include "third_party/blink/renderer/core/inspector/inspector_page_agent.h"
++
++#include "testing/gtest/include/gtest/gtest.h"
++#include "third_party/blink/renderer/core/inspector/inspector_session_state.h"
++#include "third_party/blink/renderer/platform/weborigin/kurl.h"
++
++class PageReloadScriptInjectionTest : public testing::Test {
++ protected:
++  blink::mojom::blink::DevToolsSessionStatePtr session_state_cookie_;
++  blink::InspectorAgentState agent_state_;
++  blink::InspectorPageAgent::PageReloadScriptInjection injection_;
++  blink::InspectorSessionState state_;
++
++ public:
++  PageReloadScriptInjectionTest()
++      : agent_state_("page"),
++        injection_(agent_state_),
++        state_(session_state_cookie_.Clone()) {}
++
++  void SetUp() override { agent_state_.InitFrom(&state_); }
++};
++
++TEST_F(PageReloadScriptInjectionTest, PromotesScript) {
++  blink::KURL url("http://example.com");
++  injection_.SetPending("script", url);
++  ASSERT_TRUE(injection_.GetScriptForInjection(url).empty());
++  injection_.PromoteToLoadOnce();
++  ASSERT_EQ(injection_.GetScriptForInjection(url), "script");
++  injection_.PromoteToLoadOnce();
++  ASSERT_TRUE(injection_.GetScriptForInjection(url).empty());
++}
++
++TEST_F(PageReloadScriptInjectionTest, ClearsScript) {
++  blink::KURL url("http://example.com");
++  injection_.SetPending("script", url);
++  injection_.clear();
++  injection_.PromoteToLoadOnce();
++  ASSERT_TRUE(injection_.GetScriptForInjection(url).empty());
++
++  injection_.SetPending("script", url);
++  injection_.PromoteToLoadOnce();
++  ASSERT_EQ(injection_.GetScriptForInjection(url), "script");
++  injection_.clear();
++  ASSERT_TRUE(injection_.GetScriptForInjection(url).empty());
++}
++
++TEST_F(PageReloadScriptInjectionTest, ChecksLoaderId) {
++  blink::KURL url("http://example.com");
++  blink::KURL url2("about:blank");
++  injection_.SetPending("script", url);
++  injection_.PromoteToLoadOnce();
++  ASSERT_TRUE(injection_.GetScriptForInjection(url2).empty());
++}

+ 166 - 0
patches/chromium/cherry-pick-99cafbf4b4b9.patch

@@ -0,0 +1,166 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Yann Dago <[email protected]>
+Date: Mon, 8 Jul 2024 16:20:32 +0000
+Subject: Ensure chrome://policy/test messages ignored when not supported
+
+It was possible to go to chrome://policy and in the dev tools and send
+the right message to set test policies even if the policy test page was disabled and/or unavailable because both pages share the same handler.
+
+Bug: 338248595
+Change-Id: If689325999cb108b2b71b2821d905e42efd3390d
+Low-Coverage-Reason: TRIVIAL_CHANGE
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5679162
+Auto-Submit: Yann Dago <[email protected]>
+Reviewed-by: Rohit Rao <[email protected]>
+Reviewed-by: Sergey Poromov <[email protected]>
+Commit-Queue: Rohit Rao <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#1324277}
+
+diff --git a/chrome/browser/ui/webui/policy/policy_test_ui_browsertest.cc b/chrome/browser/ui/webui/policy/policy_test_ui_browsertest.cc
+index 1a597e03d83d6efeb6dc7890745cbb88fd251a23..54f1edd9a386469825b6a42217fb1210b1f6e811 100644
+--- a/chrome/browser/ui/webui/policy/policy_test_ui_browsertest.cc
++++ b/chrome/browser/ui/webui/policy/policy_test_ui_browsertest.cc
+@@ -8,6 +8,7 @@
+ #include "base/test/scoped_feature_list.h"
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "chrome/browser/enterprise/browser_management/browser_management_service.h"
+ #include "chrome/browser/enterprise/browser_management/management_service_factory.h"
+ #include "chrome/browser/lifetime/application_lifetime.h"
+ #include "chrome/browser/policy/chrome_browser_policy_connector.h"
+@@ -268,6 +269,57 @@ class PolicyTestHandlerTest : public PlatformBrowserTest {
+ #endif
+ };
+ 
++IN_PROC_BROWSER_TEST_F(PolicyTestHandlerTest,
++                       HandleSetLocalTestPoliciesNotSupported) {
++  // Ensure chrome://policy/test not supported.
++  policy::ScopedManagementServiceOverrideForTesting profile_management(
++      policy::ManagementServiceFactory::GetForProfile(GetProfile()),
++      policy::EnterpriseManagementAuthority::CLOUD);
++  std::unique_ptr<PolicyUIHandler> handler = SetUpHandler();
++  const std::string jsonString =
++      R"([
++      {"level": 0,"scope": 0,"source": 0, "namespace": "chrome",
++       "name": "AutofillAddressEnabled","value": false},
++      {"level": 1,"scope": 1,"source": 2, "namespace": "chrome",
++       "name": "CloudReportingEnabled","value": true}
++      ])";
++  const std::string revertAppliedPoliciesButtonDisabledJs =
++      R"(
++        document
++          .querySelector('#revert-applied-policies')
++          .disabled;
++      )";
++
++  base::Value::List list_args;
++
++  list_args.Append("setLocalTestPolicies");
++  list_args.Append(jsonString);
++  list_args.Append("{}");
++
++  // Open chrome://policy
++  ASSERT_TRUE(
++      content::NavigateToURL(web_contents(), GURL(chrome::kChromeUIPolicyURL)));
++  web_ui()->HandleReceivedMessage("setLocalTestPolicies", list_args);
++
++  base::RunLoop().RunUntilIdle();
++
++  const policy::PolicyNamespace chrome_namespace(policy::POLICY_DOMAIN_CHROME,
++                                                 std::string());
++  policy::PolicyService* policy_service =
++      GetProfile()->GetProfilePolicyConnector()->policy_service();
++
++  // Check policies not applied
++  const policy::PolicyMap* policy_map =
++      &policy_service->GetPolicies(chrome_namespace);
++  ASSERT_TRUE(policy_map);
++
++  {
++    const policy::PolicyMap::Entry* entry =
++        policy_map->Get(policy::key::kAutofillAddressEnabled);
++    ASSERT_FALSE(entry);
++  }
++}
++
+ IN_PROC_BROWSER_TEST_F(PolicyTestHandlerTest,
+                        HandleSetAndRevertLocalTestPolicies) {
+   if (!policy::utils::IsPolicyTestingEnabled(/*pref_service=*/nullptr,
+diff --git a/chrome/browser/ui/webui/policy/policy_ui_handler.cc b/chrome/browser/ui/webui/policy/policy_ui_handler.cc
+index 87c5e5be7936533506def5cb8d6eaaa253ca9110..4878c9951b2ef77a5ff875f2fc00a8b41d0f7140 100644
+--- a/chrome/browser/ui/webui/policy/policy_ui_handler.cc
++++ b/chrome/browser/ui/webui/policy/policy_ui_handler.cc
+@@ -47,6 +47,7 @@
+ #include "chrome/browser/profiles/profile.h"
+ #include "chrome/browser/ui/chrome_select_file_policy.h"
+ #include "chrome/browser/ui/webui/webui_util.h"
++#include "chrome/common/channel_info.h"
+ #include "chrome/grit/branded_strings.h"
+ #include "components/crx_file/id_util.h"
+ #include "components/enterprise/browser/controller/browser_dm_token_storage.h"
+@@ -67,6 +68,7 @@
+ #include "components/policy/core/common/policy_pref_names.h"
+ #include "components/policy/core/common/policy_scheduler.h"
+ #include "components/policy/core/common/policy_types.h"
++#include "components/policy/core/common/policy_utils.h"
+ #include "components/policy/core/common/remote_commands/remote_commands_service.h"
+ #include "components/policy/core/common/schema.h"
+ #include "components/policy/core/common/schema_map.h"
+@@ -288,6 +290,12 @@ void PolicyUIHandler::HandleCopyPoliciesJson(const base::Value::List& args) {
+ void PolicyUIHandler::HandleSetLocalTestPolicies(
+     const base::Value::List& args) {
+   std::string policies = args[1].GetString();
++  AllowJavascript();
++
++  if (!PolicyUI::ShouldLoadTestPage(Profile::FromWebUI(web_ui()))) {
++    ResolveJavascriptCallback(args[0], true);
++    return;
++  }
+ 
+   policy::LocalTestPolicyProvider* local_test_provider =
+       static_cast<policy::LocalTestPolicyProvider*>(
+@@ -310,12 +318,14 @@ void PolicyUIHandler::HandleSetLocalTestPolicies(
+       ->UseLocalTestPolicyProvider();
+ 
+   local_test_provider->LoadJsonPolicies(policies);
+-  AllowJavascript();
+   ResolveJavascriptCallback(args[0], true);
+ }
+ 
+ void PolicyUIHandler::HandleRevertLocalTestPolicies(
+     const base::Value::List& args) {
++  if (!PolicyUI::ShouldLoadTestPage(Profile::FromWebUI(web_ui()))) {
++    return;
++  }
+ #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS)
+   Profile::FromWebUI(web_ui())->GetPrefs()->ClearPref(
+       prefs::kUserCloudSigninPolicyResponseFromPolicyTestPage);
+diff --git a/ios/chrome/browser/ui/webui/policy/policy_ui_handler.mm b/ios/chrome/browser/ui/webui/policy/policy_ui_handler.mm
+index a88ad7da3898757ccff4e9f7fa776ca8bef390d6..69429779c9848b5ab72ce9dd1c83efaa7c0eda33 100644
+--- a/ios/chrome/browser/ui/webui/policy/policy_ui_handler.mm
++++ b/ios/chrome/browser/ui/webui/policy/policy_ui_handler.mm
+@@ -217,6 +217,12 @@
+     const base::Value::List& args) {
+   std::string json_policies_string = args[1].GetString();
+ 
++  if (!PolicyUI::ShouldLoadTestPage(
++          ChromeBrowserState::FromWebUIIOS(web_ui()))) {
++    web_ui()->ResolveJavascriptCallback(args[0], true);
++    return;
++  }
++
+   policy::LocalTestPolicyProvider* local_test_provider =
+       static_cast<policy::LocalTestPolicyProvider*>(
+           GetApplicationContext()
+@@ -235,6 +241,11 @@
+ 
+ void PolicyUIHandler::HandleRevertLocalTestPolicies(
+     const base::Value::List& args) {
++  if (!PolicyUI::ShouldLoadTestPage(
++          ChromeBrowserState::FromWebUIIOS(web_ui()))) {
++    return;
++  }
++
+   ChromeBrowserState::FromWebUIIOS(web_ui())
+       ->GetPolicyConnector()
+       ->RevertUseLocalTestPolicyProvider();

+ 32 - 0
patches/chromium/cherry-pick-c5dd8839bfaf.patch

@@ -0,0 +1,32 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Rakina Zata Amni <[email protected]>
+Date: Wed, 19 Jun 2024 02:49:58 +0000
+Subject: Destruct controller before referenced WebUI in CreateWebUIIfNeeded
+
+Reset `controller` first before resetting `web_ui_`, since the
+controller still has a pointer to `web_ui_`, to avoid referencing to
+the already deleted `web_ui_` object from `controller`'s destructor.
+
+Bug: 345640549
+Change-Id: Ie9c193436b593845d8269605f68bf94bc75beed7
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5624749
+Commit-Queue: Rakina Zata Amni <[email protected]>
+Reviewed-by: Nasko Oskov <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#1316830}
+
+diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
+index 28a5ef2a8751e85cfa8c29138fe45bdec06ed332..b44b27c099ad798f6ed2e91050263cf03d07d8aa 100644
+--- a/content/browser/renderer_host/navigation_request.cc
++++ b/content/browser/renderer_host/navigation_request.cc
+@@ -10086,6 +10086,11 @@ void NavigationRequest::CreateWebUIIfNeeded(RenderFrameHostImpl* frame_host) {
+       bindings() != web_ui_->GetBindings()) {
+     RecordAction(base::UserMetricsAction("ProcessSwapBindingsMismatch_RVHM"));
+     base::WeakPtr<NavigationRequest> self = GetWeakPtr();
++    // Reset `controller` first before resetting `web_ui_`, since the controller
++    // still has a pointer to `web_ui_`, to avoid referencing to the already
++    // deleted  `web_ui_` object from `controller`'s destructor. See also
++    // https://crbug.com/345640549.
++    controller.reset();
+     web_ui_.reset();
+     // Resetting the WebUI may indirectly call content's embedders and delete
+     // `this`. There are no known occurrences of it, so we assume this never

+ 37 - 0
patches/chromium/cherry-pick-d54105311590.patch

@@ -0,0 +1,37 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "mark a. foltz" <[email protected]>
+Date: Mon, 17 Jun 2024 23:07:32 +0000
+Subject: Retain refptr to shared helper to prevent UAF.
+
+Capture a reference to the shared helper in the onerror handler to
+prevent a UAF that can occur when the browser drops the mojo
+connection.
+
+Bug: 346692546
+Change-Id: Ifb264488a6fa8417c134a34d902605d2c141720b
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5634908
+Reviewed-by: Avi Drissman <[email protected]>
+Commit-Queue: Mark Foltz <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#1316145}
+
+diff --git a/media/audio/mac/audio_loopback_input_mac_impl.mm b/media/audio/mac/audio_loopback_input_mac_impl.mm
+index 7b301492f17a3f1da96b8ff990f6deeb4a19b6e3..f90c00e668f58c2389e622466422ae7aa237c94d 100644
+--- a/media/audio/mac/audio_loopback_input_mac_impl.mm
++++ b/media/audio/mac/audio_loopback_input_mac_impl.mm
+@@ -394,12 +394,15 @@ - (void)stream:(SCStream*)stream
+       base::BindRepeating(&SCKAudioInputStream::OnStreamError,
+                           base::Unretained(this)));
+ 
++  // Make a local copy of the shared_refptr in case the error handler is called
++  // after `this` is destroyed.
++  auto local_shared_helper = shared_helper_;
+   [stream_ startCaptureWithCompletionHandler:^(NSError* error) {
+     if (!error) {
+       return;
+     }
+ 
+-    shared_helper_->OnStreamError(error);
++    local_shared_helper->OnStreamError(error);
+   }];
+ }
+ 

+ 4 - 0
patches/v8/.patches

@@ -10,3 +10,7 @@ cherry-pick-f911ff372723.patch
 cherry-pick-8b400f9b7d66.patch
 cherry-pick-ba6cab40612d.patch
 merged_wasm_add_missing_type_canonicalization_for_exceptions_js.patch
+cherry-pick-cdbc1d9684a3.patch
+cherry-pick-70d2fe6b7c47.patch
+cherry-pick-901377bb2f3b.patch
+cherry-pick-bc545b15a0ee.patch

+ 32 - 0
patches/v8/cherry-pick-70d2fe6b7c47.patch

@@ -0,0 +1,32 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Leszek Swirski <[email protected]>
+Date: Fri, 21 Jun 2024 15:11:40 +0200
+Subject: Allow reduced hasInstance to abort
+
+Fixed: 343507800
+Change-Id: I579041fe82e975d83a72e4744013cb04c4d3dc70
+Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5644891
+Commit-Queue: Toon Verwaest <[email protected]>
+Commit-Queue: Leszek Swirski <[email protected]>
+Auto-Submit: Leszek Swirski <[email protected]>
+Reviewed-by: Toon Verwaest <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#94585}
+
+diff --git a/src/maglev/maglev-graph-builder.cc b/src/maglev/maglev-graph-builder.cc
+index 728105c0aaccbaeb018eb9b9a660b5acba4650d8..6bd303b5721403719f1c1a359817e56cd53a3e95 100644
+--- a/src/maglev/maglev-graph-builder.cc
++++ b/src/maglev/maglev-graph-builder.cc
+@@ -8446,10 +8446,9 @@ ReduceResult MaglevGraphBuilder::TryBuildFastInstanceOf(
+ 
+       if (has_instance_field->IsJSFunction()) {
+         SaveCallSpeculationScope saved(this);
+-        ReduceResult result =
+-            ReduceCallForConstant(has_instance_field->AsJSFunction(), args);
+-        DCHECK(!result.IsDoneWithAbort());
+-        call_result = result.value();
++        GET_VALUE_OR_ABORT(
++            call_result,
++            ReduceCallForConstant(has_instance_field->AsJSFunction(), args));
+       } else {
+         call_result = BuildGenericCall(GetConstant(*has_instance_field),
+                                        Call::TargetType::kAny, args);

+ 211 - 0
patches/v8/cherry-pick-901377bb2f3b.patch

@@ -0,0 +1,211 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Thibaud Michaud <[email protected]>
+Date: Fri, 21 Jun 2024 16:31:15 +0200
+Subject: Fix scanning of wasm-to-js params
+
+Wasm-to-js wrappers are sometimes compiled as on-heap Code objects, for
+example when tiering-up from a WasmFuncRef call origin. The frames of
+these functions are mapped to a subclass of TypedFrame, however
+TypedFrame::Iterate() only supports iterating the generic wasm-to-js
+wrapper.
+
+Add support for iterating the tagged parameters of optimized wasm-to-js
+wrappers in TypedFrame::Iterate. For this we also add two 16-bit fields
+in the Code object to encode the incoming tagged parameter region, which
+we would normally find in the WasmCode data.
+
[email protected]
+
+Fixed: 346597059
+Change-Id: I425619fca86c38f91f1ca9cbeb70e7b5a7b2d6c1
+Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5639725
+Reviewed-by: Jakob Kummerow <[email protected]>
+Commit-Queue: Thibaud Michaud <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#94589}
+
+diff --git a/src/diagnostics/objects-printer.cc b/src/diagnostics/objects-printer.cc
+index 4246209b6974d5cb575382c71384fda1c5b6eba0..7759fb1391e6019bf9eaaca0b6e9191f19f64838 100644
+--- a/src/diagnostics/objects-printer.cc
++++ b/src/diagnostics/objects-printer.cc
+@@ -2048,7 +2048,14 @@ void Code::CodePrint(std::ostream& os, const char* name, Address current_pc) {
+   os << "\n - instruction_size: " << instruction_size();
+   os << "\n - metadata_size: " << metadata_size();
+ 
+-  os << "\n - inlined_bytecode_size: " << inlined_bytecode_size();
++  if (kind() != CodeKind::WASM_TO_JS_FUNCTION) {
++    os << "\n - inlined_bytecode_size: " << inlined_bytecode_size();
++  } else {
++    os << "\n - wasm_js_tagged_parameter_count: "
++       << wasm_js_tagged_parameter_count();
++    os << "\n - wasm_js_first_tagged_parameter: "
++       << wasm_js_first_tagged_parameter();
++  }
+   os << "\n - osr_offset: " << osr_offset();
+   os << "\n - handler_table_offset: " << handler_table_offset();
+   os << "\n - unwinding_info_offset: " << unwinding_info_offset();
+diff --git a/src/execution/frames.cc b/src/execution/frames.cc
+index 7b8507384ab5fd8009d2cf2cb2afc764a5332d61..efde8eb70717e785747f335c1b817cdab525ffdc 100644
+--- a/src/execution/frames.cc
++++ b/src/execution/frames.cc
+@@ -1536,7 +1536,7 @@ void WasmFrame::Iterate(RootVisitor* v) const {
+                        frame_header_limit);
+ }
+ 
+-void TypedFrame::IterateParamsOfWasmToJSWrapper(RootVisitor* v) const {
++void TypedFrame::IterateParamsOfGenericWasmToJSWrapper(RootVisitor* v) const {
+   Tagged<Object> maybe_signature = Tagged<Object>(
+       Memory<Address>(fp() + WasmToJSWrapperConstants::kSignatureOffset));
+   if (IsSmi(maybe_signature)) {
+@@ -1652,6 +1652,18 @@ void TypedFrame::IterateParamsOfWasmToJSWrapper(RootVisitor* v) const {
+     }
+   }
+ }
++
++void TypedFrame::IterateParamsOfOptimizedWasmToJSWrapper(RootVisitor* v) const {
++  Tagged<GcSafeCode> code = GcSafeLookupCode();
++  if (code->wasm_js_tagged_parameter_count() > 0) {
++    FullObjectSlot tagged_parameter_base(&Memory<Address>(caller_sp()));
++    tagged_parameter_base += code->wasm_js_first_tagged_parameter();
++    FullObjectSlot tagged_parameter_limit =
++        tagged_parameter_base + code->wasm_js_tagged_parameter_count();
++    v->VisitRootPointers(Root::kStackRoots, nullptr, tagged_parameter_base,
++                         tagged_parameter_limit);
++  }
++}
+ #endif  // V8_ENABLE_WEBASSEMBLY
+ 
+ void TypedFrame::Iterate(RootVisitor* v) const {
+@@ -1683,10 +1695,13 @@ void TypedFrame::Iterate(RootVisitor* v) const {
+   CHECK(entry->code.has_value());
+   Tagged<GcSafeCode> code = entry->code.value();
+ #if V8_ENABLE_WEBASSEMBLY
+-  bool is_wasm_to_js =
++  bool is_generic_wasm_to_js =
+       code->is_builtin() && code->builtin_id() == Builtin::kWasmToJsWrapperCSA;
+-  if (is_wasm_to_js) {
+-    IterateParamsOfWasmToJSWrapper(v);
++  bool is_optimized_wasm_to_js = this->type() == WASM_TO_JS_FUNCTION;
++  if (is_generic_wasm_to_js) {
++    IterateParamsOfGenericWasmToJSWrapper(v);
++  } else if (is_optimized_wasm_to_js) {
++    IterateParamsOfOptimizedWasmToJSWrapper(v);
+   }
+ #endif  // V8_ENABLE_WEBASSEMBLY
+   DCHECK(code->is_turbofanned());
+@@ -1719,10 +1734,13 @@ void TypedFrame::Iterate(RootVisitor* v) const {
+   // wrapper switched to before pushing the outgoing stack parameters and
+   // calling the target. It marks the limit of the stack param area, and is
+   // distinct from the beginning of the spill area.
+-  Address central_stack_sp =
+-      Memory<Address>(fp() + WasmToJSWrapperConstants::kCentralStackSPOffset);
++  int central_stack_sp_offset =
++      is_generic_wasm_to_js
++          ? WasmToJSWrapperConstants::kCentralStackSPOffset
++          : WasmImportWrapperFrameConstants::kCentralStackSPOffset;
++  Address central_stack_sp = Memory<Address>(fp() + central_stack_sp_offset);
+   FullObjectSlot parameters_limit(
+-      v8_flags.experimental_wasm_stack_switching && is_wasm_to_js &&
++      v8_flags.experimental_wasm_stack_switching && is_generic_wasm_to_js &&
+               central_stack_sp != kNullAddress
+           ? central_stack_sp
+           : frame_header_base.address() - spill_slots_size);
+diff --git a/src/execution/frames.h b/src/execution/frames.h
+index 428e50c32a7eca9ad579b2c634607f4be5d1734e..a578a87d67905b19f045465d04532bbb1706e585 100644
+--- a/src/execution/frames.h
++++ b/src/execution/frames.h
+@@ -626,7 +626,8 @@ class TypedFrame : public CommonFrame {
+   Tagged<HeapObject> unchecked_code() const override { return {}; }
+   void Iterate(RootVisitor* v) const override;
+ 
+-  void IterateParamsOfWasmToJSWrapper(RootVisitor* v) const;
++  void IterateParamsOfGenericWasmToJSWrapper(RootVisitor* v) const;
++  void IterateParamsOfOptimizedWasmToJSWrapper(RootVisitor* v) const;
+ 
+  protected:
+   inline explicit TypedFrame(StackFrameIteratorBase* iterator);
+diff --git a/src/objects/code-inl.h b/src/objects/code-inl.h
+index da3c0bd4fe8b9c593ecc25d9a3c277160b9df95b..4f6082f171948385c0fe9feeba51cc51b6fd9674 100644
+--- a/src/objects/code-inl.h
++++ b/src/objects/code-inl.h
+@@ -48,6 +48,8 @@ GCSAFE_CODE_FWD_ACCESSOR(bool, has_tagged_outgoing_params)
+ GCSAFE_CODE_FWD_ACCESSOR(bool, marked_for_deoptimization)
+ GCSAFE_CODE_FWD_ACCESSOR(Tagged<Object>, raw_instruction_stream)
+ GCSAFE_CODE_FWD_ACCESSOR(int, stack_slots)
++GCSAFE_CODE_FWD_ACCESSOR(uint16_t, wasm_js_tagged_parameter_count)
++GCSAFE_CODE_FWD_ACCESSOR(uint16_t, wasm_js_first_tagged_parameter)
+ GCSAFE_CODE_FWD_ACCESSOR(Address, constant_pool)
+ GCSAFE_CODE_FWD_ACCESSOR(Address, safepoint_table_address)
+ #undef GCSAFE_CODE_FWD_ACCESSOR
+@@ -371,6 +373,31 @@ void Code::set_inlined_bytecode_size(unsigned size) {
+   RELAXED_WRITE_UINT_FIELD(*this, kInlinedBytecodeSizeOffset, size);
+ }
+ 
++// For optimized on-heap wasm-js wrappers, we repurpose the (otherwise unused)
++// 32-bit InlinedBytecodeSize field to encode two 16 values needed for scanning
++// the frame: the count and starting offset of incoming tagged parameters.
++// TODO(wasm): Eventually the wrappers should be managed off-heap by the wasm
++// engine. Remove these accessors when that is the case.
++void Code::set_wasm_js_tagged_parameter_count(uint16_t count) {
++  DCHECK_EQ(kind(), CodeKind::WASM_TO_JS_FUNCTION);
++  RELAXED_WRITE_UINT16_FIELD(*this, kInlinedBytecodeSizeOffset, count);
++}
++
++uint16_t Code::wasm_js_tagged_parameter_count() const {
++  DCHECK_EQ(kind(), CodeKind::WASM_TO_JS_FUNCTION);
++  return RELAXED_READ_UINT16_FIELD(*this, kInlinedBytecodeSizeOffset);
++}
++
++void Code::set_wasm_js_first_tagged_parameter(uint16_t count) {
++  DCHECK_EQ(kind(), CodeKind::WASM_TO_JS_FUNCTION);
++  RELAXED_WRITE_UINT16_FIELD(*this, kInlinedBytecodeSizeOffset + 2, count);
++}
++
++uint16_t Code::wasm_js_first_tagged_parameter() const {
++  DCHECK_EQ(kind(), CodeKind::WASM_TO_JS_FUNCTION);
++  return RELAXED_READ_UINT16_FIELD(*this, kInlinedBytecodeSizeOffset + 2);
++}
++
+ BytecodeOffset Code::osr_offset() const {
+   return BytecodeOffset(RELAXED_READ_INT32_FIELD(*this, kOsrOffsetOffset));
+ }
+diff --git a/src/objects/code.h b/src/objects/code.h
+index c6b0eda42849ac46498bb292566b6f74a6716a25..b500da60feb9c60ef77add1a8e8102bdb0b3829a 100644
+--- a/src/objects/code.h
++++ b/src/objects/code.h
+@@ -124,6 +124,25 @@ class Code : public ExposedTrustedObject {
+   // [deoptimization_data]: Array containing data for deopt for non-baseline
+   // code.
+   DECL_ACCESSORS(deoptimization_data, Tagged<FixedArray>)
++  // [parameter_count]: The number of formal parameters, including the
++  // receiver. Currently only available for optimized functions.
++  // TODO(saelo): make this always available. This is just a matter of figuring
++  // out how to obtain the parameter count during code generation when no
++  // BytecodeArray is available from which it can be copied.
++  DECL_PRIMITIVE_ACCESSORS(parameter_count, uint16_t)
++  inline uint16_t parameter_count_without_receiver() const;
++  DECL_PRIMITIVE_ACCESSORS(wasm_js_tagged_parameter_count, uint16_t)
++  DECL_PRIMITIVE_ACCESSORS(wasm_js_first_tagged_parameter, uint16_t)
++
++  // Whether this type of Code uses deoptimization data, in which case the
++  // deoptimization_data field will be populated.
++  inline bool uses_deoptimization_data() const;
++
++  // If neither deoptimization data nor bytecode/interpreter data are used
++  // (e.g. for builtin code), the respective field will contain Smi::zero().
++  inline void clear_deoptimization_data_and_interpreter_data();
++  inline bool has_deoptimization_data_or_interpreter_data() const;
++
+   // [bytecode_or_interpreter_data]: BytecodeArray or InterpreterData for
+   // baseline code.
+   // As BytecodeArrays are located in trusted space, but InterpreterData
+@@ -482,6 +501,10 @@ class GcSafeCode : public HeapObject {
+   inline bool CanDeoptAt(Isolate* isolate, Address pc) const;
+   inline Tagged<Object> raw_instruction_stream(
+       PtrComprCageBase code_cage_base) const;
++  // The two following accessors repurpose the InlinedBytecodeSize field, see
++  // comment in code-inl.h.
++  inline uint16_t wasm_js_tagged_parameter_count() const;
++  inline uint16_t wasm_js_first_tagged_parameter() const;
+ 
+  private:
+   OBJECT_CONSTRUCTORS(GcSafeCode, HeapObject);

+ 39 - 0
patches/v8/cherry-pick-bc545b15a0ee.patch

@@ -0,0 +1,39 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jakob Kummerow <[email protected]>
+Date: Thu, 11 Jul 2024 16:34:00 +0200
+Subject: Fix cast of memory index
+
+"uint8_t" must have been a typo.
+
+Fixed: 351327767
+Bug: 42203854
+Change-Id: I196c961ec2f2ed16acfe16bf304d7eae6551aacc
+Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5695665
+Reviewed-by: Matthias Liedtke <[email protected]>
+Commit-Queue: Matthias Liedtke <[email protected]>
+Auto-Submit: Jakob Kummerow <[email protected]>
+Commit-Queue: Jakob Kummerow <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#94981}
+
+diff --git a/src/compiler/wasm-compiler.cc b/src/compiler/wasm-compiler.cc
+index 5d7d03536d44c283b9ed049a3eec2dde43024af8..89ece5e51eab038b559cc7f2c5205275c0c41a72 100644
+--- a/src/compiler/wasm-compiler.cc
++++ b/src/compiler/wasm-compiler.cc
+@@ -3426,7 +3426,7 @@ Node* WasmGraphBuilder::MemStart(uint32_t mem_index) {
+   DCHECK_NOT_NULL(instance_cache_);
+   V8_ASSUME(cached_memory_index_ == kNoCachedMemoryIndex ||
+             cached_memory_index_ >= 0);
+-  if (mem_index == static_cast<uint8_t>(cached_memory_index_)) {
++  if (mem_index == static_cast<uint32_t>(cached_memory_index_)) {
+     return instance_cache_->mem_start;
+   }
+   return LoadMemStart(mem_index);
+@@ -3436,7 +3436,7 @@ Node* WasmGraphBuilder::MemSize(uint32_t mem_index) {
+   DCHECK_NOT_NULL(instance_cache_);
+   V8_ASSUME(cached_memory_index_ == kNoCachedMemoryIndex ||
+             cached_memory_index_ >= 0);
+-  if (mem_index == static_cast<uint8_t>(cached_memory_index_)) {
++  if (mem_index == static_cast<uint32_t>(cached_memory_index_)) {
+     return instance_cache_->mem_size;
+   }
+ 

+ 112 - 0
patches/v8/cherry-pick-cdbc1d9684a3.patch

@@ -0,0 +1,112 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Darius Mercadier <[email protected]>
+Date: Tue, 18 Jun 2024 16:10:26 +0200
+Subject: Lower LoadStackArgument to a Tagged load
+
+If we start with a graph that looks like
+
+```
+x = LoadStackArgument(a, 40)
+...
+Allocate()
+...
+y = LoadStackArgument(a, 40)
+```
+
+This used to be lowered to
+
+```
+x1 = Load<WordPtr>(a, 40)
+x2 = TaggedBitcast(x1, WordPtr->Tagged)
+...
+Allocate()
+...
+y1 = Load<WordPtr>(a, 40)
+y2 = TaggedBitcast(y1, WordPtr->Tagged)
+```
+
+And then, Load Elimination would remove the second Load, and we'd get:
+
+```
+x1 = Load<WordPtr>(a, 40)
+x2 = TaggedBitcast(x1, WordPtr->Tagged)
+...
+Allocate()
+...
+y2 = TaggedBitcast(x1, WordPtr->Tagged)
+```
+
+And now we would be in trouble: if the allocation in the middle
+triggers a GC, then `x1` could move, and thus `y2` could refer to a
+stale pointer. In theory, Turbofan knows where tagged values are, and
+can thus update them when the GC moves things, but here, `x1` is not
+marked as Tagged (but rather as a raw WordPtr).
+
+This CL fixes this issue by doing a Tagged load from the start, since
+the value we're loading is clearly tagged.
+
+Fixed: chromium:347724915
+Change-Id: Ia659155fbc602907ab9a50fb992c79df6ccdaa44
+Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5630530
+Reviewed-by: Nico Hartmann <[email protected]>
+Auto-Submit: Darius Mercadier <[email protected]>
+Commit-Queue: Nico Hartmann <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#94527}
+
+diff --git a/src/compiler/turboshaft/machine-lowering-reducer-inl.h b/src/compiler/turboshaft/machine-lowering-reducer-inl.h
+index 69607d0bf0ddfe032b6650433685ccb3286807bc..11dcadfbbbc771abd4ce9901c84fb4f7c45f4ff7 100644
+--- a/src/compiler/turboshaft/machine-lowering-reducer-inl.h
++++ b/src/compiler/turboshaft/machine-lowering-reducer-inl.h
+@@ -2100,9 +2100,17 @@ class MachineLoweringReducer : public Next {
+   }
+ 
+   V<Object> REDUCE(LoadStackArgument)(V<WordPtr> base, V<WordPtr> index) {
+-    V<WordPtr> argument = __ template LoadNonArrayBufferElement<WordPtr>(
+-        base, AccessBuilder::ForStackArgument(), index);
+-    return __ BitcastWordPtrToTagged(argument);
++    // Note that this is a load of a Tagged value
++    // (MemoryRepresentation::TaggedPointer()), but since it's on the stack
++    // where stack slots are all kSystemPointerSize, we use kSystemPointerSize
++    // for element_size_log2. On 64-bit plateforms with pointer compression,
++    // this means that we're kinda loading a 32-bit value from an array of
++    // 64-bit values.
++    return __ Load(
++        base, index, LoadOp::Kind::RawAligned(),
++        MemoryRepresentation::TaggedPointer(),
++        CommonFrameConstants::kFixedFrameSizeAboveFp - kSystemPointerSize,
++        kSystemPointerSizeLog2);
+   }
+ 
+   OpIndex REDUCE(StoreTypedElement)(OpIndex buffer, V<Object> base,
+diff --git a/test/mjsunit/compiler/regress-347724915.js b/test/mjsunit/compiler/regress-347724915.js
+new file mode 100644
+index 0000000000000000000000000000000000000000..4a5d1a9a2e3dd7674bf0872c94a971b5f28ddf72
+--- /dev/null
++++ b/test/mjsunit/compiler/regress-347724915.js
+@@ -0,0 +1,26 @@
++// Copyright 2024 the V8 project authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++// Flags: --allow-natives-syntax
++
++function f(...args) {
++  let arr1 = [ undefined, undefined, undefined ];
++  %SimulateNewspaceFull();
++  arr1[0] = args[0];
++  // The following allocation will trigger a full GC, which will move the
++  // argument passed to the function (because it was a young object).
++  let arr2 = [ arr1 ];
++  // Here we're accessing `args[0]` again. This might be load-eliminated with
++  // the `args[0]` load from a few lines above, which has been moved by the GC
++  // since then. This should be fine though, as the loaded value should be
++  // marked as Tagged, which means that it shouldn't point to the stale value
++  // but instead have been updated during GC.
++  arr1[1] = args[0]
++  return arr2;
++}
++
++%PrepareFunctionForOptimization(f);
++let expected = f({ x : 42 });
++%OptimizeFunctionOnNextCall(f);
++assertEquals(expected, f({x : 42}));