2016-05-03 17:15:17 +00:00
//: Reclaiming memory when it's no longer used.
: ( scenario new_reclaim )
def main [
2018-06-24 16:16:17 +00:00
10 : & : num < - new number : type
20 : num < - deaddress 10 : & : num
abandon 10 : & : num
30 : & : num < - new number : type # must be same size as abandoned memory to reuse
40 : num < - deaddress 30 : & : num
50 : bool < - equal 20 : num , 40 : num
2016-05-03 17:15:17 +00:00
]
# both allocations should have returned the same address
2018-06-24 16:16:17 +00:00
+ mem : storing 1 in location 50
2016-05-03 17:15:17 +00:00
//: When abandoning addresses we'll save them to a 'free list', segregated by size.
: ( before " End routine Fields " )
map < int , int > free_list ;
2018-01-03 08:31:10 +00:00
: ( before " End Primitive Recipe Declarations " )
ABANDON ,
: ( before " End Primitive Recipe Numbers " )
put ( Recipe_ordinal , " abandon " , ABANDON ) ;
: ( before " End Primitive Recipe Checks " )
case ABANDON : {
if ( ! inst . products . empty ( ) ) {
raise < < maybe ( get ( Recipe , r ) . name ) < < " 'abandon' shouldn't write to any products in ' " < < to_original_string ( inst ) < < " ' \n " < < end ( ) ;
break ;
}
for ( int i = 0 ; i < SIZE ( inst . ingredients ) ; + + i ) {
if ( ! is_mu_address ( inst . ingredients . at ( i ) ) )
raise < < maybe ( get ( Recipe , r ) . name ) < < " ingredients of 'abandon' should be addresses, but ingredient " < < i < < " is ' " < < to_string ( inst . ingredients . at ( i ) ) < < ' \n ' < < end ( ) ;
break ;
2016-05-18 01:32:41 +00:00
}
2018-01-03 08:31:10 +00:00
break ;
}
: ( before " End Primitive Recipe Implementations " )
case ABANDON : {
for ( int i = 0 ; i < SIZE ( current_instruction ( ) . ingredients ) ; + + i ) {
reagent /*copy*/ ingredient = current_instruction ( ) . ingredients . at ( i ) ;
canonize ( ingredient ) ;
2018-06-24 16:16:17 +00:00
abandon ( get_or_insert ( Memory , ingredient . value + /*skip alloc id*/ 1 ) , payload_size ( ingredient ) ) ;
2016-05-18 01:32:41 +00:00
}
2018-01-03 08:31:10 +00:00
break ;
}
: ( code )
void abandon ( int address , int payload_size ) {
2016-05-03 17:15:17 +00:00
// clear memory
2016-10-20 05:10:35 +00:00
for ( int curr = address ; curr < address + payload_size ; + + curr )
2016-05-03 17:15:17 +00:00
put ( Memory , curr , 0 ) ;
// append existing free list to address
2018-06-16 05:16:09 +00:00
trace ( " abandon " ) < < " saving " < < address < < " in free-list of size " < < payload_size < < end ( ) ;
2016-05-18 01:32:41 +00:00
put ( Memory , address , get_or_insert ( Current_routine - > free_list , payload_size ) ) ;
put ( Current_routine - > free_list , payload_size , address ) ;
2016-05-03 17:15:17 +00:00
}
2018-05-13 06:08:39 +00:00
int payload_size ( reagent /*copy*/ x ) {
x . properties . push_back ( pair < string , string_tree * > ( " lookup " , NULL ) ) ;
lookup_memory_core ( x , /*check_for_null*/ false ) ;
2018-06-24 16:16:17 +00:00
return size_of ( x ) + /*alloc id*/ 1 ;
2018-05-13 06:08:39 +00:00
}
2016-06-29 02:33:43 +00:00
: ( after " Allocate Special-cases " )
2016-05-03 17:15:17 +00:00
if ( get_or_insert ( Current_routine - > free_list , size ) ) {
2017-11-03 08:50:46 +00:00
trace ( " abandon " ) < < " picking up space from free-list of size " < < size < < end ( ) ;
2016-05-03 17:15:17 +00:00
int result = get_or_insert ( Current_routine - > free_list , size ) ;
2017-11-03 08:50:46 +00:00
trace ( " mem " ) < < " new alloc from free list: " < < result < < end ( ) ;
2016-05-03 17:15:17 +00:00
put ( Current_routine - > free_list , size , get_or_insert ( Memory , result ) ) ;
2016-06-29 02:33:43 +00:00
put ( Memory , result , 0 ) ;
2016-10-20 05:10:35 +00:00
for ( int curr = result ; curr < result + size ; + + curr ) {
2016-05-03 17:15:17 +00:00
if ( get_or_insert ( Memory , curr ) ! = 0 ) {
raise < < maybe ( current_recipe_name ( ) ) < < " memory in free list was not zeroed out: " < < curr < < ' / ' < < result < < " ; somebody wrote to us after free!!! \n " < < end ( ) ;
break ; // always fatal
}
}
2016-06-29 02:33:43 +00:00
return result ;
2016-05-03 17:15:17 +00:00
}
: ( scenario new_differing_size_no_reclaim )
def main [
2018-06-18 02:53:52 +00:00
1 : & : num < - new number : type
2 : num < - deaddress 1 : & : num
abandon 1 : & : num
3 : & : @ : num < - new number : type , 2 # different size
4 : num < - deaddress 3 : & : @ : num
2018-06-16 05:16:09 +00:00
5 : bool < - equal 2 : num , 4 : num
2016-05-03 17:15:17 +00:00
]
# no reuse
2018-06-16 05:16:09 +00:00
+ mem : storing 0 in location 5
2016-05-03 17:15:17 +00:00
: ( scenario new_reclaim_array )
def main [
2018-06-24 16:16:17 +00:00
10 : & : @ : num < - new number : type , 2
20 : num < - deaddress 10 : & : @ : num
abandon 10 : & : @ : num
30 : & : @ : num < - new number : type , 2 # same size
40 : num < - deaddress 30 : & : @ : num
50 : bool < - equal 20 : num , 40 : num
2016-05-03 17:15:17 +00:00
]
2016-05-18 00:26:55 +00:00
# both calls to new returned identical addresses
2018-06-24 16:16:17 +00:00
+ mem : storing 1 in location 50