Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimizing vector::replace and compiler-v2 vector depenency fix #15524

Merged
merged 2 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion aptos-move/framework/aptos-stdlib/doc/big_vector.md
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ Aborts if <code>i</code> is out of bounds.
<b>if</b> (self.end_index == i) {
<b>return</b> last_val
};
// because the lack of mem::swap, here we swap remove the requested value from the bucket
// because the lack of <a href="../../move-stdlib/doc/mem.md#0x1_mem_swap">mem::swap</a>, here we swap remove the requested value from the bucket
// and append the last_val <b>to</b> the bucket then swap the last bucket val back
<b>let</b> bucket = <a href="table_with_length.md#0x1_table_with_length_borrow_mut">table_with_length::borrow_mut</a>(&<b>mut</b> self.buckets, i / self.bucket_size);
<b>let</b> bucket_len = <a href="../../move-stdlib/doc/vector.md#0x1_vector_length">vector::length</a>(bucket);
Expand Down
18 changes: 9 additions & 9 deletions aptos-move/framework/move-stdlib/doc/vector.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ the return on investment didn't seem worth it for these simple functions.
- [Function `rotate_slice`](#@Specification_1_rotate_slice)


<pre><code></code></pre>
<pre><code><b>use</b> <a href="mem.md#0x1_mem">0x1::mem</a>;
</code></pre>



Expand Down Expand Up @@ -930,14 +931,13 @@ Aborts if <code>i</code> is out of bounds.
<pre><code><b>public</b> <b>fun</b> <a href="vector.md#0x1_vector_replace">replace</a>&lt;Element&gt;(self: &<b>mut</b> <a href="vector.md#0x1_vector">vector</a>&lt;Element&gt;, i: u64, val: Element): Element {
<b>let</b> last_idx = <a href="vector.md#0x1_vector_length">length</a>(self);
<b>assert</b>!(i &lt; last_idx, <a href="vector.md#0x1_vector_EINDEX_OUT_OF_BOUNDS">EINDEX_OUT_OF_BOUNDS</a>);
// TODO: Enable after tests are fixed.
// <b>if</b> (<a href="vector.md#0x1_vector_USE_MOVE_RANGE">USE_MOVE_RANGE</a>) {
// <a href="mem.md#0x1_mem_replace">mem::replace</a>(<a href="vector.md#0x1_vector_borrow_mut">borrow_mut</a>(self, i), val)
// } <b>else</b> {
<a href="vector.md#0x1_vector_push_back">push_back</a>(self, val);
<a href="vector.md#0x1_vector_swap">swap</a>(self, i, last_idx);
<a href="vector.md#0x1_vector_pop_back">pop_back</a>(self)
// }
<b>if</b> (<a href="vector.md#0x1_vector_USE_MOVE_RANGE">USE_MOVE_RANGE</a>) {
<a href="mem.md#0x1_mem_replace">mem::replace</a>(<a href="vector.md#0x1_vector_borrow_mut">borrow_mut</a>(self, i), val)
} <b>else</b> {
<a href="vector.md#0x1_vector_push_back">push_back</a>(self, val);
<a href="vector.md#0x1_vector_swap">swap</a>(self, i, last_idx);
<a href="vector.md#0x1_vector_pop_back">pop_back</a>(self)
}
}
</code></pre>

Expand Down
2 changes: 1 addition & 1 deletion aptos-move/framework/move-stdlib/sources/mem.move
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
module std::mem {
// TODO - functions here are `public(friend)` here for one release,
// and to be changed to `public` one release later.
// friend std::vector;
friend std::vector;
#[test_only]
friend std::mem_tests;

Expand Down
17 changes: 8 additions & 9 deletions aptos-move/framework/move-stdlib/sources/vector.move
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/// Move functions here because many have loops, requiring loop invariants to prove, and
/// the return on investment didn't seem worth it for these simple functions.
module std::vector {
// use std::mem;
use std::mem;

/// The index into the vector is out of bounds
const EINDEX_OUT_OF_BOUNDS: u64 = 0x20000;
Expand Down Expand Up @@ -357,14 +357,13 @@ module std::vector {
public fun replace<Element>(self: &mut vector<Element>, i: u64, val: Element): Element {
let last_idx = length(self);
assert!(i < last_idx, EINDEX_OUT_OF_BOUNDS);
// TODO: Enable after tests are fixed.
// if (USE_MOVE_RANGE) {
// mem::replace(borrow_mut(self, i), val)
// } else {
push_back(self, val);
swap(self, i, last_idx);
pop_back(self)
// }
if (USE_MOVE_RANGE) {
mem::replace(borrow_mut(self, i), val)
} else {
push_back(self, val);
swap(self, i, last_idx);
pop_back(self)
}
}

/// Apply the function to each element in the vector, consuming it.
Expand Down
29 changes: 23 additions & 6 deletions third_party/move/move-model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,13 +305,25 @@ pub fn run_model_builder_with_options_and_compilation_flags<
},
};

// Extract the module/script closure
// Extract the module/script dependency closure
let mut visited_modules = BTreeSet::new();
// Extract the module dependency closure for the vector module
let mut vector_and_its_dependencies = BTreeSet::new();
let mut seen_vector = false;
for (_, mident, mdef) in &expansion_ast.modules {
let src_file_hash = mdef.loc.file_hash();
if !dep_files.contains(&src_file_hash) {
collect_related_modules_recursive(mident, &expansion_ast.modules, &mut visited_modules);
}
if !seen_vector && is_vector(*mident) {
seen_vector = true;
// Collect the vector module and its dependencies.
collect_related_modules_recursive(
mident,
&expansion_ast.modules,
&mut vector_and_its_dependencies,
);
}
}
for sdef in expansion_ast.scripts.values() {
let src_file_hash = sdef.loc.file_hash();
Expand All @@ -330,14 +342,13 @@ pub fn run_model_builder_with_options_and_compilation_flags<
let mut expansion_ast = {
let E::Program { modules, scripts } = expansion_ast;
let modules = modules.filter_map(|mident, mut mdef| {
// We need to always include the `vector` module (only for compiler v2),
// For compiler v2, we need to always include the `vector` module and any of its dependencies,
// to handle cases of implicit usage.
// E.g., index operation on a vector results in a call to `vector::borrow`.
// TODO(#15483): consider refactoring code to avoid this special case.
let is_vector = mident.value.address.into_addr_bytes().into_inner()
== AccountAddress::ONE
&& mident.value.module.0.value.as_str() == "vector";
(is_vector && compile_via_model || visited_modules.contains(&mident.value)).then(|| {
((compile_via_model && vector_and_its_dependencies.contains(&mident.value))
|| visited_modules.contains(&mident.value))
.then(|| {
mdef.is_source_module = true;
mdef
})
Expand Down Expand Up @@ -416,6 +427,12 @@ pub fn run_model_builder_with_options_and_compilation_flags<
}
}

/// Is `module_ident` the `vector` module?
fn is_vector(module_ident: ModuleIdent_) -> bool {
module_ident.address.into_addr_bytes().into_inner() == AccountAddress::ONE
&& module_ident.module.0.value.as_str() == "vector"
}

fn run_move_checker(env: &mut GlobalEnv, program: E::Program) {
let mut builder = ModelBuilder::new(env);
for (module_count, (module_id, module_def)) in program
Expand Down
Loading