@@ -32,6 +32,17 @@ impl<Module> Default for ModuleCache<Module> {
3232 }
3333}
3434
35+ impl < Module > ModuleCache < Module > {
36+ #[ cfg( test) ]
37+ fn with_max_size ( max_size : u64 ) -> Self {
38+ ModuleCache {
39+ modules : LruCache :: unbounded ( ) ,
40+ total_size : 0 ,
41+ max_size,
42+ }
43+ }
44+ }
45+
3546impl < Module : Clone > ModuleCache < Module > {
3647 /// Returns a `Module` for the requested `bytecode`, creating it with `module_builder` and
3748 /// adding it to the cache if it doesn't already exist in the cache.
@@ -58,11 +69,20 @@ impl<Module: Clone> ModuleCache<Module> {
5869 pub fn insert ( & mut self , bytecode : Bytecode , module : Module ) {
5970 let bytecode_size = bytecode. as_ref ( ) . len ( ) as u64 ;
6071
72+ if bytecode_size > self . max_size {
73+ return ;
74+ }
75+
76+ if self . modules . promote ( & bytecode) {
77+ return ;
78+ }
79+
6180 if self . total_size + bytecode_size > self . max_size {
6281 self . reduce_size_to ( self . max_size - bytecode_size) ;
6382 }
6483
6584 self . modules . put ( bytecode, module) ;
85+ self . total_size += bytecode_size;
6686 }
6787
6888 /// Evicts entries from the cache so that the total size of cached bytecode files is less than
@@ -79,3 +99,71 @@ impl<Module: Clone> ModuleCache<Module> {
7999 }
80100 }
81101}
102+
103+ #[ cfg( test) ]
104+ mod tests {
105+ use super :: * ;
106+
107+ fn bytecode ( size : usize ) -> Bytecode {
108+ Bytecode :: new ( vec ! [ 0u8 ; size] )
109+ }
110+
111+ fn distinct_bytecode ( size : usize , discriminant : u8 ) -> Bytecode {
112+ let mut bytes = vec ! [ 0u8 ; size] ;
113+ bytes[ 0 ] = discriminant;
114+ Bytecode :: new ( bytes)
115+ }
116+
117+ #[ test]
118+ fn total_size_tracks_insertions ( ) {
119+ let mut cache = ModuleCache :: < u32 > :: with_max_size ( 1000 ) ;
120+ cache. insert ( bytecode ( 100 ) , 1 ) ;
121+ assert_eq ! ( cache. total_size, 100 ) ;
122+ cache. insert ( distinct_bytecode ( 200 , 1 ) , 2 ) ;
123+ assert_eq ! ( cache. total_size, 300 ) ;
124+ }
125+
126+ #[ test]
127+ fn eviction_triggers_when_full ( ) {
128+ let mut cache = ModuleCache :: < u32 > :: with_max_size ( 250 ) ;
129+ cache. insert ( bytecode ( 100 ) , 1 ) ;
130+ cache. insert ( distinct_bytecode ( 100 , 1 ) , 2 ) ;
131+ assert_eq ! ( cache. total_size, 200 ) ;
132+ assert_eq ! ( cache. modules. len( ) , 2 ) ;
133+
134+ cache. insert ( distinct_bytecode ( 100 , 2 ) , 3 ) ;
135+ assert_eq ! ( cache. modules. len( ) , 2 ) ;
136+ assert ! ( cache. total_size <= 250 ) ;
137+ }
138+
139+ #[ test]
140+ fn oversized_bytecode_is_rejected ( ) {
141+ let mut cache = ModuleCache :: < u32 > :: with_max_size ( 50 ) ;
142+ cache. insert ( bytecode ( 100 ) , 1 ) ;
143+ assert_eq ! ( cache. total_size, 0 ) ;
144+ assert_eq ! ( cache. modules. len( ) , 0 ) ;
145+ }
146+
147+ #[ test]
148+ fn reinserting_same_key_does_not_double_count ( ) {
149+ let mut cache = ModuleCache :: < u32 > :: with_max_size ( 1000 ) ;
150+ let bc = bytecode ( 100 ) ;
151+ cache. insert ( bc. clone ( ) , 1 ) ;
152+ assert_eq ! ( cache. total_size, 100 ) ;
153+ cache. insert ( bc, 2 ) ;
154+ assert_eq ! ( cache. total_size, 100 ) ;
155+ assert_eq ! ( cache. modules. len( ) , 1 ) ;
156+ }
157+
158+ #[ test]
159+ fn reinserting_existing_key_does_not_evict ( ) {
160+ let mut cache = ModuleCache :: < u32 > :: with_max_size ( 200 ) ;
161+ cache. insert ( bytecode ( 100 ) , 1 ) ;
162+ cache. insert ( distinct_bytecode ( 100 , 1 ) , 2 ) ;
163+ assert_eq ! ( cache. modules. len( ) , 2 ) ;
164+
165+ cache. insert ( bytecode ( 100 ) , 3 ) ;
166+ assert_eq ! ( cache. modules. len( ) , 2 ) ;
167+ assert_eq ! ( cache. total_size, 200 ) ;
168+ }
169+ }
0 commit comments