-
Notifications
You must be signed in to change notification settings - Fork 431
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
Align the start pointer in ink allocator #2100
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
0cd3d96
align the start pointer
SkymanOne db47774
add test
SkymanOne 55adeaf
apply suggestions
SkymanOne 16f5339
Merge branch 'master' into gn/fix-alloc
SkymanOne 7f3c186
add allocator e2e test
SkymanOne 2546c04
changelog entry
SkymanOne 43141cb
prepend var names
SkymanOne 6431fcb
fix vars
SkymanOne 815edee
fix fuzz tests and add docs
SkymanOne da598d3
update docs comment
SkymanOne 4afc0c1
cleanup tests
SkymanOne 72b2467
remove old comment
SkymanOne 850566a
Merge branch 'master' into gn/fix-alloc
SkymanOne File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,7 @@ Wasm32 | |
WebAssembly | ||
adjunctive | ||
bitvector | ||
bitmask | ||
bitwise | ||
callee | ||
codegen | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,9 +14,6 @@ | |
|
||
//! A simple bump allocator. | ||
//! | ||
//! Its goal to have a much smaller footprint than the admittedly more full-featured | ||
//! `wee_alloc` allocator which is currently being used by ink! smart contracts. | ||
//! | ||
//! The heap which is used by this allocator is built from pages of Wasm memory (each page | ||
//! is `64KiB`). We will request new pages of memory as needed until we run out of memory, | ||
//! at which point we will crash with an `OOM` error instead of freeing any memory. | ||
|
@@ -174,9 +171,10 @@ impl InnerAlloc { | |
/// Note: This implementation results in internal fragmentation when allocating across | ||
/// pages. | ||
fn alloc(&mut self, layout: Layout) -> Option<usize> { | ||
let alloc_start = self.next; | ||
let alloc_start = self.align_ptr(&layout); | ||
|
||
let aligned_size = layout.size(); | ||
|
||
let aligned_size = layout.pad_to_align().size(); | ||
let alloc_end = alloc_start.checked_add(aligned_size)?; | ||
|
||
if alloc_end > self.upper_limit { | ||
|
@@ -194,6 +192,20 @@ impl InnerAlloc { | |
Some(alloc_start) | ||
} | ||
} | ||
|
||
/// Aligns the start pointer of the next allocation. | ||
/// | ||
/// We inductively calculate the start index | ||
/// of a layout in the linear memory. | ||
/// - Initially `self.next` is `0`` and aligned | ||
/// - `layout.align() - 1` accounts for `0` as the first index. | ||
/// - the binary with the inverse of the align creates a | ||
/// bitmask that is used to zero out bits, ensuring alignment according to type | ||
/// requirements and ensures that the next allocated pointer address is of the | ||
/// power of 2. | ||
fn align_ptr(&self, layout: &Layout) -> usize { | ||
(self.next + layout.align() - 1) & !(layout.align() - 1) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add a comment with the reasoning behind the calculation and the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe some concrete example will help here |
||
} | ||
} | ||
|
||
/// Calculates the number of pages of memory needed for an allocation of `size` bytes. | ||
|
@@ -329,6 +341,18 @@ mod tests { | |
let expected_alloc_start = 2 * PAGE_SIZE + size_of::<u8>(); | ||
assert_eq!(inner.next, expected_alloc_start); | ||
} | ||
|
||
#[test] | ||
fn correct_alloc_types() { | ||
let mut inner = InnerAlloc::new(); | ||
let layout1 = Layout::for_value(&Vec::<u128>::with_capacity(3)); | ||
assert_eq!(inner.alloc(layout1), Some(0)); | ||
assert_eq!(inner.next, 24); | ||
|
||
let layout2 = Layout::for_value(&Vec::<u128>::with_capacity(1)); | ||
assert_eq!(inner.alloc(layout2), Some(24)); | ||
assert_eq!(inner.next, 48); | ||
} | ||
} | ||
|
||
#[cfg(all(test, feature = "ink-fuzz-tests"))] | ||
|
@@ -351,7 +375,7 @@ mod fuzz_tests { | |
Err(_) => return TestResult::discard(), | ||
}; | ||
|
||
let size = layout.pad_to_align().size(); | ||
let size = layout.size(); | ||
assert_eq!( | ||
inner.alloc(layout), | ||
Some(0), | ||
|
@@ -390,7 +414,7 @@ mod fuzz_tests { | |
Err(_) => return TestResult::discard(), | ||
}; | ||
|
||
let size = layout.pad_to_align().size(); | ||
let size = layout.size(); | ||
assert_eq!( | ||
inner.alloc(layout), | ||
Some(0), | ||
|
@@ -459,7 +483,7 @@ mod fuzz_tests { | |
Err(_) => return TestResult::discard(), | ||
}; | ||
|
||
let size = layout.pad_to_align().size(); | ||
let size = layout.size(); | ||
|
||
let current_page_limit = PAGE_SIZE * required_pages(inner.next).unwrap(); | ||
let is_too_big_for_current_page = inner.next + size > current_page_limit; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Just out of curiosity, how is padding performed for fields in a struct, considering they field types have their own alignment requirements?
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 is not really the concern of the allocator. The allocator will just create an allocation that adheres to the
Layout
passed. For a struct the alignment will be set to the alignment for the whole struct (AFAIK the alignment of the largest type in the struct). The padding within the struct is given implicitly by the size of theLayout
. Rust will just assume the padding when accessing the struct.