Skip to content

Commit

Permalink
AccountSharedData::set_data_from_slice: skip extra alloc + memcpy
Browse files Browse the repository at this point in the history
We used call make_data_mut() from set_data_from_slice() from the days
when direct mapping couldn't deal with accounts getting shrunk. That
changed in solana-labs#32649 (see the
if callee_account.capacity() < min_capacity check in
cpi.rs:update_caller_account()).

With this change we don't call make_data_mut() anymore before
set_data_from_slice(), saving the cost of a memcpy since
set_data_from_slice() overrides the whole account content anyway.
  • Loading branch information
alessandrod committed May 6, 2024
1 parent f8969b7 commit b03ce11
Show file tree
Hide file tree
Showing 2 changed files with 7 additions and 9 deletions.
5 changes: 3 additions & 2 deletions programs/bpf_loader/src/syscalls/cpi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1308,8 +1308,9 @@ fn update_caller_account(
// never points to an invalid address.
//
// Note that the capacity can be smaller than the original length only if the account is
// reallocated using the AccountSharedData API directly (deprecated). BorrowedAccount
// and CoW don't trigger this, see BorrowedAccount::make_data_mut.
// reallocated using the AccountSharedData API directly (deprecated) or using
// BorrowedAccount::set_data_from_slice(), which implements an optimization to avoid an
// extra allocation.
let min_capacity = caller_account.original_data_len;
if callee_account.capacity() < min_capacity {
callee_account
Expand Down
11 changes: 4 additions & 7 deletions sdk/src/transaction_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -869,13 +869,10 @@ impl<'a> BorrowedAccount<'a> {
self.can_data_be_changed()?;
self.touch()?;
self.update_accounts_resize_delta(data.len())?;
// Calling make_data_mut() here guarantees that set_data_from_slice()
// copies in places, extending the account capacity if necessary but
// never reducing it. This is required as the account migh be directly
// mapped into a MemoryRegion, and therefore reducing capacity would
// leave a hole in the vm address space. After CPI or upon program
// termination, the runtime will zero the extra capacity.
self.make_data_mut();
// Note that we intentionally don't call self.make_data_mut() here. make_data_mut() will
// allocate + memcpy the current data if self.account is shared. We don't need the memcpy
// here tho because account.set_data_from_slice(data) is going to replace the content
// anyway.
self.account.set_data_from_slice(data);

Ok(())
Expand Down

0 comments on commit b03ce11

Please sign in to comment.