0

Protected Audience: Eagerly compile only if we're not waiting on JS

We currently always eagerly compile our JS worklet scripts. However, in
the case that our bid/score tasks are ready by the time the JS
downloads, it's better to lazily compile the JS so that we can run
our tasks earlier.

Bug: 385384684
Change-Id: I0931b84244b856f7500271d5670a3df52127228a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6308953
Commit-Queue: Abigail Katcoff <abigailkatcoff@chromium.org>
Reviewed-by: Russ Hamilton <behamilton@google.com>
Cr-Commit-Position: refs/heads/main@{#1426597}
This commit is contained in:
Abigail Katcoff
2025-02-28 15:07:16 -08:00
committed by Chromium LUCI CQ
parent f888bcc8e1
commit 673610447f
6 changed files with 68 additions and 7 deletions

@ -554,7 +554,8 @@ v8::MaybeLocal<v8::UnboundScript> AuctionV8Helper::Compile(
if (cached_data) {
compile_options = v8::ScriptCompiler::kConsumeCodeCache;
} else if (base::FeatureList::IsEnabled(
features::kFledgeEagerJSCompilation)) {
features::kFledgeEagerJSCompilation) &&
eagerly_compile_js_) {
compile_options = v8::ScriptCompiler::kEagerCompile;
}
auto result = v8::ScriptCompiler::CompileUnboundScript(

@ -430,6 +430,8 @@ class CONTENT_EXPORT AuctionV8Helper
static std::string FormatExceptionMessage(v8::Local<v8::Context> context,
v8::Local<v8::Message> message);
void DisableEagerJsCompilation() { eagerly_compile_js_ = false; }
private:
friend class base::RefCountedDeleteOnSequence<AuctionV8Helper>;
friend class base::DeleteHelper<AuctionV8Helper>;
@ -455,6 +457,10 @@ class CONTENT_EXPORT AuctionV8Helper
scoped_refptr<base::SequencedTaskRunner> v8_runner_;
scoped_refptr<base::SequencedTaskRunner> timer_task_runner_;
// This starts true but can be set to false if a task is waiting on the script
// to be ready.
bool eagerly_compile_js_ = true;
// This needs to be invoked after ~IsolateHolder to make sure that V8 is
// really shut down.
base::ScopedClosureRunner destroyed_callback_run_;

@ -2435,7 +2435,7 @@ void BidderWorklet::MaybePrepareContexts() {
bool frozen_mode_tasks = false;
for (auto generate_bid_task = generate_bid_tasks_.begin();
generate_bid_task != generate_bid_tasks_.end(); ++generate_bid_task) {
if (IsReadyToGenerateBid(*generate_bid_task)) {
if (GenerateBidTaskHasInputs(*generate_bid_task)) {
return;
}
switch (
@ -2629,16 +2629,35 @@ void BidderWorklet::OnDirectFromSellerAuctionSignalsDownloadedGenerateBid(
GenerateBidIfReady(task);
}
bool BidderWorklet::IsReadyToGenerateBid(const GenerateBidTask& task) const {
bool BidderWorklet::GenerateBidTaskHasInputs(
const GenerateBidTask& task) const {
return task.signals_received_callback_invoked &&
task.finalize_generate_bid_called &&
!task.direct_from_seller_request_per_buyer_signals &&
!task.direct_from_seller_request_auction_signals && IsCodeReady();
!task.direct_from_seller_request_auction_signals;
}
bool BidderWorklet::IsReadyToGenerateBid(const GenerateBidTask& task) const {
return GenerateBidTaskHasInputs(task) && IsCodeReady();
}
void BidderWorklet::DisableEagerJsCompilationIfOnlyWaitingOnJs(
const GenerateBidTask& task) {
if (GenerateBidTaskHasInputs(task) && worklet_loader_ && !wasm_loader_) {
for (size_t thread_index = 0; thread_index < v8_runners_.size();
++thread_index) {
v8_runners_[thread_index]->PostTask(
FROM_HERE,
base::BindOnce(&AuctionV8Helper::DisableEagerJsCompilation,
base::Unretained(v8_helpers_[thread_index].get())));
}
}
}
void BidderWorklet::GenerateBidIfReady(GenerateBidTaskList::iterator task) {
DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
if (!IsReadyToGenerateBid(*task)) {
DisableEagerJsCompilationIfOnlyWaitingOnJs(*task);
return;
}

@ -810,10 +810,18 @@ class CONTENT_EXPORT BidderWorklet : public mojom::BidderWorklet,
GenerateBidTaskList::iterator task,
DirectFromSellerSignalsRequester::Result result);
// Returns true iff all generateBid()'s inputs are ready. The JS and WASM
// may or may not be ready yet.
bool GenerateBidTaskHasInputs(const GenerateBidTask& task) const;
// Returns true iff all generateBid()'s prerequisite loading tasks have
// completed.
bool IsReadyToGenerateBid(const GenerateBidTask& task) const;
// If the task is ready other than waiting for the JS script, avoid eager
// compilation so that we can get started on generating this bid.
void DisableEagerJsCompilationIfOnlyWaitingOnJs(const GenerateBidTask& task);
// Checks if IsReadyToGenerateBid(). If so, calls generateBid(), and invokes
// the task callback with the resulting bid, if any.
void GenerateBidIfReady(GenerateBidTaskList::iterator task);

@ -2302,19 +2302,38 @@ void SellerWorklet::OnDirectFromSellerAuctionSignalsDownloadedScoreAd(
ScoreAdIfReady(task);
}
bool SellerWorklet::ScoreAdTaskHasInputs(
const SellerWorklet::ScoreAdTask& task) const {
return !task.waiting_for_signals_fetch &&
!task.direct_from_seller_request_seller_signals &&
!task.direct_from_seller_request_auction_signals;
}
bool SellerWorklet::IsReadyToScoreAd(const ScoreAdTask& task) const {
// The first check should be implied by IsCodeReady(), but best to be safe.
return trusted_signals_relation_ !=
SignalsOriginRelation::kUnknownPermissionCrossOriginSignals &&
!task.waiting_for_signals_fetch &&
!task.direct_from_seller_request_seller_signals &&
!task.direct_from_seller_request_auction_signals && IsCodeReady();
ScoreAdTaskHasInputs(task) && IsCodeReady();
}
void SellerWorklet::DisableEagerJsCompilationIfOnlyWaitingOnJs(
const ScoreAdTask& task) {
if (ScoreAdTaskHasInputs(task) && worklet_loader_) {
for (size_t thread_index = 0; thread_index < v8_runners_.size();
++thread_index) {
v8_runners_[thread_index]->PostTask(
FROM_HERE,
base::BindOnce(&AuctionV8Helper::DisableEagerJsCompilation,
base::Unretained(v8_helpers_[thread_index].get())));
}
}
}
void SellerWorklet::ScoreAdIfReady(ScoreAdTaskList::iterator task) {
DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
if (!IsReadyToScoreAd(*task)) {
DisableEagerJsCompilationIfOnlyWaitingOnJs(*task);
return;
}

@ -586,10 +586,18 @@ class CONTENT_EXPORT SellerWorklet : public mojom::SellerWorklet {
ScoreAdTaskList::iterator task,
DirectFromSellerSignalsRequester::Result result);
// Returns true iff all scoreAd()'s inputs are ready. The JS
// may or may not be ready yet.
bool ScoreAdTaskHasInputs(const SellerWorklet::ScoreAdTask& task) const;
// Returns true iff all scoreAd()'s prerequisite loading tasks have
// completed.
bool IsReadyToScoreAd(const ScoreAdTask& task) const;
// If the task is ready other than waiting for the JS script, avoid eager
// compilation so that we can get started on scoring this ad.
void DisableEagerJsCompilationIfOnlyWaitingOnJs(const ScoreAdTask& task);
// Checks if the script has been loaded successfully, the
// DirectFromSellerSignals loads have finished and the TrustedSignals load has
// finished, if needed (successfully or not). If so, calls scoreAd().