1
1
use revm_primitives:: U256 ;
2
2
3
3
use crate :: alloc:: vec;
4
- use crate :: alloc:: vec:: Vec ;
4
+ use crate :: alloc:: { boxed :: Box , slice , vec:: Vec } ;
5
5
use core:: {
6
6
cmp:: min,
7
7
fmt,
@@ -14,119 +14,111 @@ use core::{
14
14
/// the `new` static method to ensure memory safety.
15
15
pub struct SharedMemory {
16
16
/// Shared buffer
17
- data : Vec < u8 > ,
17
+ data : Box < [ u8 ] > ,
18
18
/// Memory checkpoints for each depth
19
19
checkpoints : Vec < usize > ,
20
20
/// Raw pointer used for the portion of memory used
21
21
/// by the current context
22
- current_slice : * mut [ u8 ] ,
22
+ current_ptr : * mut u8 ,
23
23
/// How much memory has been used in the current context
24
24
current_len : usize ,
25
25
/// Amount of memory left for assignment
26
- pub limit : u64 ,
26
+ pub limit : usize ,
27
27
}
28
28
29
29
impl fmt:: Debug for SharedMemory {
30
30
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
31
31
f. debug_struct ( "SharedMemory" )
32
32
. field (
33
33
"current_slice" ,
34
- & crate :: primitives:: hex:: encode ( self . get_current_slice ( ) ) ,
34
+ & crate :: primitives:: hex:: encode ( self . current_slice ( ) ) ,
35
35
)
36
36
. finish ( )
37
37
}
38
38
}
39
39
40
40
impl SharedMemory {
41
+ /// Calculates memory allocation upper bound using
42
+ /// https://2π.com/22/eth-max-mem
43
+ #[ inline]
44
+ pub fn calculate_upper_bound ( gas_limit : u64 ) -> u64 {
45
+ 4096 * sqrt ( 2 * gas_limit)
46
+ }
47
+
41
48
/// Allocate memory to be shared between calls.
42
49
/// Memory size is estimated using https://2π.com/22/eth-max-mem
43
50
/// which depends on transaction [gas_limit].
44
51
/// Maximum allocation size is 2^32 - 1 bytes;
45
52
pub fn new ( gas_limit : u64 ) -> Self {
46
- let size = min (
47
- SharedMemory :: calculate_upper_bound ( gas_limit) as usize ,
48
- 2usize . pow ( 32 ) - 1 ,
49
- ) ;
50
-
51
- let mut data = vec ! [ 0 ; size] ;
52
- let current_slice: * mut [ u8 ] = & mut data[ ..] ;
53
- SharedMemory {
54
- data,
55
- checkpoints : Vec :: with_capacity ( 1024 ) ,
56
- current_slice,
57
- current_len : 0 ,
58
- limit : size as u64 ,
59
- }
53
+ Self :: new_with_memory_limit ( gas_limit, ( u32:: MAX - 1 ) as u64 )
60
54
}
61
55
62
56
/// Allocate memory to be shared between calls.
63
57
/// Memory size is estimated using https://2π.com/22/eth-max-mem
64
58
/// which depends on transaction [gas_limit].
65
59
/// Uses [memory_limit] as maximum allocation size
66
60
pub fn new_with_memory_limit ( gas_limit : u64 , memory_limit : u64 ) -> Self {
67
- let size = min (
68
- SharedMemory :: calculate_upper_bound ( gas_limit) as usize ,
61
+ let limit = min (
62
+ Self :: calculate_upper_bound ( gas_limit) as usize ,
69
63
memory_limit as usize ,
70
64
) ;
71
65
72
- let mut data = vec ! [ 0 ; size ] ;
73
- let current_slice: * mut [ u8 ] = & mut data[ .. ] ;
74
- SharedMemory {
66
+ let mut data = vec ! [ 0 ; limit ] . into_boxed_slice ( ) ;
67
+ let current_slice = data. as_mut_ptr ( ) ;
68
+ Self {
75
69
data,
76
- checkpoints : Vec :: with_capacity ( 1024 ) ,
77
- current_slice,
70
+ checkpoints : Vec :: with_capacity ( 32 ) ,
71
+ current_ptr : current_slice,
78
72
current_len : 0 ,
79
- limit : size as u64 ,
73
+ limit,
80
74
}
81
75
}
82
76
83
77
/// Prepares the shared memory for a new context
84
78
pub fn new_context_memory ( & mut self ) {
85
- let base_offset = self . checkpoints . last ( ) . unwrap_or ( & 0 ) ;
79
+ let base_offset = self . last_checkpoint ( ) ;
86
80
let new_checkpoint = base_offset + self . current_len ;
87
81
88
82
self . checkpoints . push ( new_checkpoint) ;
89
83
90
- self . current_slice = & mut self . data [ new_checkpoint..] ;
84
+ self . current_ptr = self . data [ new_checkpoint..] . as_mut_ptr ( ) ;
91
85
self . current_len = 0 ;
92
86
}
93
87
94
88
/// Prepares the shared memory for returning to the previous context
95
89
pub fn free_context_memory ( & mut self ) {
96
90
if let Some ( old_checkpoint) = self . checkpoints . pop ( ) {
97
- let last = * self . checkpoints . last ( ) . unwrap_or ( & 0 ) ;
98
- self . current_slice = & mut self . data [ last ..] ;
99
- self . current_len = old_checkpoint - last ;
91
+ let last_checkpoint = self . last_checkpoint ( ) ;
92
+ self . current_ptr = self . data [ last_checkpoint ..] . as_mut_ptr ( ) ;
93
+ self . current_len = old_checkpoint - last_checkpoint ;
100
94
self . update_limit ( ) ;
101
95
}
102
96
}
103
97
104
98
/// Get the length of the current memory range.
99
+ #[ inline( always) ]
105
100
pub fn len ( & self ) -> usize {
106
101
self . current_len
107
102
}
108
103
109
- /// Return true if current effective memory range is zero.
104
+ # [ inline ( always ) ]
110
105
pub fn is_empty ( & self ) -> bool {
111
106
self . current_len == 0
112
107
}
113
108
114
- /// Return the memory of the current context
115
- pub fn data ( & self ) -> & [ u8 ] {
116
- self . get_current_slice ( )
117
- }
118
-
119
109
/// Resize the memory. assume that we already checked if:
120
- /// - we have enought gas to resize this vector
110
+ /// - we have enough gas to resize this vector
121
111
/// - we made new_size as multiply of 32
122
112
/// - [new_size] is greater than `self.len()`
113
+ #[ inline( always) ]
123
114
pub fn resize ( & mut self , new_size : usize ) {
124
115
// extend with zeros
125
116
let range = self . current_len ..new_size;
126
117
127
- self . get_current_slice_mut ( ) [ range]
128
- . iter_mut ( )
129
- . for_each ( |byte| * byte = 0 ) ;
118
+ for byte in self . current_slice_mut ( ) [ range] . iter_mut ( ) {
119
+ * byte = 0 ;
120
+ }
121
+
130
122
self . current_len = new_size;
131
123
self . update_limit ( ) ;
132
124
}
@@ -137,7 +129,7 @@ impl SharedMemory {
137
129
#[ inline( always) ]
138
130
#[ cfg_attr( debug_assertions, track_caller) ]
139
131
pub fn slice ( & self , offset : usize , size : usize ) -> & [ u8 ] {
140
- match self . get_current_slice ( ) . get ( offset..offset + size) {
132
+ match self . current_slice ( ) . get ( offset..offset + size) {
141
133
Some ( slice) => slice,
142
134
None => debug_unreachable ! ( "slice OOB: {offset}..{size}; len: {}" , self . len( ) ) ,
143
135
}
@@ -150,7 +142,7 @@ impl SharedMemory {
150
142
#[ cfg_attr( debug_assertions, track_caller) ]
151
143
pub fn slice_mut ( & mut self , offset : usize , size : usize ) -> & mut [ u8 ] {
152
144
let len = self . current_len ;
153
- match self . get_current_slice_mut ( ) . get_mut ( offset..offset + size) {
145
+ match self . current_slice_mut ( ) . get_mut ( offset..offset + size) {
154
146
Some ( slice) => slice,
155
147
None => debug_unreachable ! ( "slice OOB: {offset}..{size}; len: {}" , len) ,
156
148
}
@@ -162,7 +154,7 @@ impl SharedMemory {
162
154
#[ inline( always) ]
163
155
#[ cfg_attr( debug_assertions, track_caller) ]
164
156
pub fn set_byte ( & mut self , index : usize , byte : u8 ) {
165
- match self . get_current_slice_mut ( ) . get_mut ( index) {
157
+ match self . current_slice_mut ( ) . get_mut ( index) {
166
158
Some ( b) => * b = byte,
167
159
None => debug_unreachable ! ( "set_byte OOB: {index}; len: {}" , self . len( ) ) ,
168
160
}
@@ -219,36 +211,33 @@ impl SharedMemory {
219
211
#[ inline( always) ]
220
212
#[ cfg_attr( debug_assertions, track_caller) ]
221
213
pub fn copy ( & mut self , dst : usize , src : usize , len : usize ) {
222
- self . get_current_slice_mut ( )
223
- . copy_within ( src..src + len, dst) ;
214
+ self . current_slice_mut ( ) . copy_within ( src..src + len, dst) ;
224
215
}
225
216
226
- /// Get a refernce to the memory of the current context
217
+ /// Get a reference to the memory of the current context
227
218
#[ inline( always) ]
228
- fn get_current_slice ( & self ) -> & [ u8 ] {
219
+ fn current_slice ( & self ) -> & [ u8 ] {
229
220
// Safety: if it is a valid pointer to a slice of `self.data`
230
- unsafe { & * self . current_slice }
221
+ unsafe { slice :: from_raw_parts ( self . current_ptr , self . limit ) }
231
222
}
232
223
233
- /// Get a mutable refernce to the memory of the current context
224
+ /// Get a mutable reference to the memory of the current context
234
225
#[ inline( always) ]
235
- fn get_current_slice_mut ( & mut self ) -> & mut [ u8 ] {
226
+ fn current_slice_mut ( & mut self ) -> & mut [ u8 ] {
236
227
// Safety: it is a valid pointer to a slice of `self.data`
237
- unsafe { & mut * self . current_slice }
228
+ unsafe { slice :: from_raw_parts_mut ( self . current_ptr , self . limit ) }
238
229
}
239
230
240
- /// Calculates memory allocation upper bound using
241
- /// https://2π.com/22/eth-max-mem
231
+ /// Update the amount of memory left for usage
242
232
#[ inline( always) ]
243
- fn calculate_upper_bound ( gas_limit : u64 ) -> u64 {
244
- 4096 * sqrt ( 2 * gas_limit )
233
+ fn update_limit ( & mut self ) {
234
+ self . limit = self . data . len ( ) - self . last_checkpoint ( ) - self . current_len ;
245
235
}
246
236
247
- /// Update the amount of memory left for usage
237
+ /// Get the last memory checkpoint
248
238
#[ inline( always) ]
249
- fn update_limit ( & mut self ) {
250
- self . limit =
251
- ( self . data . len ( ) - * self . checkpoints . last ( ) . unwrap_or ( & 0 ) - self . current_len ) as u64 ;
239
+ fn last_checkpoint ( & self ) -> usize {
240
+ * self . checkpoints . last ( ) . unwrap_or ( & 0 )
252
241
}
253
242
}
254
243
0 commit comments