-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
[move-stdlib] Add vector::move_range native function #14863
base: igor/move_mem_swap
Are you sure you want to change the base?
Conversation
⏱️ 2h 43m total CI duration on this PR
|
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## igor/move_mem_swap #14863 +/- ##
====================================================
Coverage 60.1% 60.1%
====================================================
Files 857 858 +1
Lines 211341 211455 +114
====================================================
+ Hits 127147 127233 +86
- Misses 84194 84222 +28 ☔ View full report in Codecov by Sentry. |
2253183
to
0f08236
Compare
d724063
to
e4540db
Compare
e4540db
to
ae8e817
Compare
783b338
to
3d7877e
Compare
48df5f1
to
1407c00
Compare
7c0fbc1
to
02eedf5
Compare
1407c00
to
94d1b68
Compare
02eedf5
to
c5f381e
Compare
94d1b68
to
51f1f1c
Compare
c5f381e
to
8b0d35b
Compare
51f1f1c
to
b36187b
Compare
// potentially unnecessary as native call should've checked the types already | ||
// (unlike other vector functions that are bytecodes) | ||
check_elem_layout(type_param, from_c)?; | ||
check_elem_layout(type_param, to_c)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one question - given no checks in mem::swap, should I have these checks here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good question. It has the same indirect guarantees as the from_self != to_self.
if module_name.as_str() == "string" | ||
&& vector_bytecode_instruction_methods.contains(func_name.as_str()) | ||
{ | ||
println!("ERROR: Tried to register as native a vector bytecode_instruction method {}, skipping.", func_name.as_str()); | ||
continue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure if this check is even needed (this is mostly to make sure we don't create new native function with same name as bytecode instruction), or if it's better to remove it - or on the other hand panic
here.
but this is basically to be a fixed replacement of the filter in aptos-move/aptos-vm/src/natives.rs
@@ -2307,6 +2307,25 @@ fn check_elem_layout(ty: &Type, v: &Container) -> PartialVMResult<()> { | |||
} | |||
|
|||
impl VectorRef { | |||
pub fn len_usize_raw(&self, type_param: &Type) -> PartialVMResult<usize> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added this to not need to wrap / unwrap / cast for getting the length inside of native function.
/// Moves range of elements `[removal_position, removal_position + length)` from vector `from`, | ||
/// to vector `to`, inserting them starting at the `insert_position`. | ||
/// In the `from` vector, elements after the selected range are moved left to fill the hole | ||
/// (i.e. range is removed, while the order of the rest of the elements is kept) | ||
/// In the `to` vector, elements after the `insert_position` are moved the the right to make space for new elements | ||
/// (i.e. range is inserted, while the order of the rest of the elements is kept) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add that to the comment here.
/// (i.e. range is removed, while the order of the rest of the elements is kept) | ||
/// In the `to` vector, elements after the `insert_position` are moved the the right to make space for new elements | ||
/// (i.e. range is inserted, while the order of the rest of the elements is kept) | ||
native public fun range_move<T>(from: &mut vector<T>, removal_position: u64, length: u64, to: &mut vector<T>, insert_position: u64); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't move_range
more intuitive and better descripting name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now that you say it, makes more sense :D
// Copyright (c) The Move Contributors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
//! Implementation of native functions for utf8 strings. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrong leftover comment
|
||
use super::mem::get_feature_not_available_error; | ||
|
||
/// The generic type supplied to aggregator snapshots is not supported. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably some leftover comment from wherever a snipped was copied (aggregator_natives/aggregator_v2.rs?)
use super::mem::get_feature_not_available_error; | ||
|
||
/// The generic type supplied to aggregator snapshots is not supported. | ||
pub const EINDEX_OUT_OF_BOUNDS: u64 = 0x03_0001; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How are these constants picked?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is this utility now - https://github.com/aptos-labs/aptos-core/blob/main/types/src/error.rs
I'll use that, but it might be worth revisiting where to put it, to not require importing whole aptos-types for that.
let removal_position = usize::try_from(safely_pop_arg!(args, u64)).map_err(map_err)?; | ||
let from = safely_pop_arg!(args, VectorRef); | ||
|
||
// need to fetch sizes here to charge upfront, and later in move_range, not sure if possible to combine |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't fully understand this comment without reading the code
@@ -2307,6 +2307,25 @@ fn check_elem_layout(ty: &Type, v: &Container) -> PartialVMResult<()> { | |||
} | |||
|
|||
impl VectorRef { | |||
pub fn len_usize_raw(&self, type_param: &Type) -> PartialVMResult<usize> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
length_as_usize
? Why raw
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure , as usize sounds good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
raw was meant to mean not as a move value - i.e. not Value::usize (which doesn't exist), but just rust usize
}; | ||
Ok(len) | ||
} | ||
|
||
pub fn len(&self, type_param: &Type) -> PartialVMResult<Value> { | ||
let c: &Container = self.0.container(); | ||
check_elem_layout(type_param, c)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the new function here:
Ok(Value::u64(length_as_usize(....))
@@ -2452,6 +2471,67 @@ impl VectorRef { | |||
self.0.mark_dirty(); | |||
Ok(()) | |||
} | |||
|
|||
pub fn move_range( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd make it static (associated):
this: &Self
instead of &self and use it with VectorRef::move_range(....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also need to either document, or check that self != to_self
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
VM will guarantee there cannot be two &mut references to same self.
I can still defensively check, but it should never be possible to go there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pre-condition for this function is self != to_self (we can just document it, as a comment, and mention that it's enforced by the overall VM design).
@@ -81,8 +81,26 @@ impl NativeFunctions { | |||
where | |||
I: IntoIterator<Item = (AccountAddress, Identifier, Identifier, NativeFunction)>, | |||
{ | |||
let vector_bytecode_instruction_methods = HashSet::from([ | |||
"empty", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason for adding this check now (in this PR)?
Do we really want to prevent this? There's nothing wrong with having native functions that have the same functionality as instructions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
previous comment:
not sure if this check is even needed (this is mostly to make sure we don't create new native function with same name as bytecode instruction), or if it's better to remove it - or on the other hand panic here.
but this is basically to be a fixed replacement of the filter in aptos-move/aptos-vm/src/natives.rs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think there's a general reason to disallow these in MoveVM. I'd rather keep the filter in AptosVM. Is there any other reason for wanting to remove it from AptosVM?
8b0d35b
to
170eca3
Compare
b36187b
to
5b9f388
Compare
updated PR with addressed comments |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More like a question that I have before stamping this.
// potentially unnecessary as native call should've checked the types already | ||
// (unlike other vector functions that are bytecodes) | ||
check_elem_layout(type_param, from_c)?; | ||
check_elem_layout(type_param, to_c)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good question. It has the same indirect guarantees as the from_self != to_self.
@@ -81,8 +81,26 @@ impl NativeFunctions { | |||
where | |||
I: IntoIterator<Item = (AccountAddress, Identifier, Identifier, NativeFunction)>, | |||
{ | |||
let vector_bytecode_instruction_methods = HashSet::from([ | |||
"empty", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think there's a general reason to disallow these in MoveVM. I'd rather keep the filter in AptosVM. Is there any other reason for wanting to remove it from AptosVM?
170eca3
to
a99eccd
Compare
5b9f388
to
fc3c349
Compare
addressed all comments. move the filtering back to AptosVM. added comment for redundant check |
fc3c349
to
9e0fd82
Compare
23c63a3
to
c95646e
Compare
9e0fd82
to
db496b3
Compare
{ | ||
return Err(SafeNativeError::Abort { | ||
abort_code: EINDEX_OUT_OF_BOUNDS, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There appears to be a typo in the comment: moved the the right
contains a duplicated word and should be moved to the right
Spotted by Graphite Reviewer
Is this helpful? React 👍 or 👎 to let us know.
Description
Memcopy (i.e.
ptr::copy_nonoverlapping
inside ofVec
) is extremely efficient, and using Vec operations that use it directly is significantly faster (orders of magnitude on bigger vectors) than issuing operations in move.Operations on
vector
that can be speed-up:insert
,remove
,append
,split_off
.To keep amount of native functions short, instead of having native for each of those, providing one more general native function:
vector::move_range
, which is enough to support all 4 of the above, in addition to other uses.Internally, we shortcircuit a few special cases, for faster speed.
How Has This Been Tested?
Full performance evaluation is in the follow-up PR: #14862
Key Areas to Review
Type of Change
Which Components or Systems Does This Change Impact?
Checklist