/*
 	strip symbol table
 	
	marked internal references
	in principle after resolving it.  	
*/

strip_symbol_table :: !*State -> (!*{#Bool},!*State);
strip_symbol_table state=:{n_xcoff_symbols,n_library_symbols}
	#! references
		= createArray (n_xcoff_symbols + n_library_symbols) False;
	// each unmarked symbol having at least one reference is set to True
	#! (references,state)
		= mark_referenced_symbols_in_xcoff 0 0 references state;
		
	// mark external definitions
	#! (names_table,state)
		= select_namestable state;
	#! (s_names_table,names_table)
		= usize names_table;
	
	#! (references,names_table,state)
		= mark_external_definitions 0 s_names_table names_table references state;
		
	#! state
		= update_namestable names_table state;
		
	#! (references,state)
		= remove_unreferenced_symbols 0 0 references state;
		
	= (references,state); //abort ("a!" +++ (p 0 (size references) references "" )); //state; // abort "strip_symbol_tab";

/*
where {
	p i limit a s 
 		| i == limit
			= s
			
			#! (element,a)
				= a![i];
			= p (inc i) limit a (s +++ (if element "t" "f" ));
}
*/

remove_unreferenced_symbols :: !Int !Int !*{#Bool} !*State -> (!*{#Bool},!*State);
remove_unreferenced_symbols file_n first_symbol_n references state=:{n_xcoff_files}
	| file_n == n_xcoff_files // + n_libraries
		= (references,state);
		
		#! (n_symbols,state)
			= select_n_symbols file_n state;
		
		#! (references,state)
			= remove_unreferenced_symbols_in_xcoff 0 n_symbols references state;
		= remove_unreferenced_symbols (inc file_n) (first_symbol_n + n_symbols) references state;	
where //{
	remove_unreferenced_symbols_in_xcoff :: !Int !Int !*{#Bool} !*State -> (!*{#Bool},!*State);
	remove_unreferenced_symbols_in_xcoff symbol_n n_symbols references state
		| symbol_n == n_symbols
			= (references,state);
			
			#! (unreferenced_symbol,references)
				= references![first_symbol_n + symbol_n];
			| not unreferenced_symbol
				= remove_unreferenced_symbols_in_xcoff (inc symbol_n) n_symbols references state;
				
				// remove unreferenced symbol 
				//#! state
				//	= update_symbol EmptySymbol file_n symbol_n state;
				= remove_unreferenced_symbols_in_xcoff (inc symbol_n) n_symbols references state;
				
				//= abort "remove_unreferenced_symbols_in_xcoff";
//}
	
	
	
mark_external_definitions :: !Int !Int *NamesTable !*{#Bool} !*State -> (!*{#Bool},*NamesTable,!*State);
mark_external_definitions i limit names_table references state
	| i == limit
		= (references,names_table,state);
		
		#! (names_table_elements,names_table)
			= names_table![i];
		#! (references,state)
			= mark_names_table_elements names_table_elements references state;			
		= mark_external_definitions (inc i) limit names_table references state; 
where //{
	mark_names_table_elements EmptyNamesTableElement references state
		= (references,state);
	mark_names_table_elements (NamesTableElement _ symbol_n file_n ntes) references state
		#! (first_symbol_n,state)
			= case file_n < 0 of {
				True	-> selacc_so_marked_offset_a file_n state;
				False	-> selacc_marked_offset_a file_n state;	
			}
		#! references
			= { references & [first_symbol_n + symbol_n] = True };
		= mark_names_table_elements ntes references state;
//}

mark_referenced_symbols_in_xcoff :: !Int !Int !*{#Bool} !*State -> (!*{#Bool},!*State);
mark_referenced_symbols_in_xcoff file_n first_symbol_n references state=:{n_xcoff_files,n_xcoff_symbols,xcoff_a}
	| /*F (toString file_n)*/ file_n == n_xcoff_files
		= (references,state); //abort "strip_symbol_table";
		
		// for each symbol it must be known if there are references to it. Initially
		// there are no references to the symbols. A false in the reference-array 
		// means that for the corresponding symbol, no references exist.
		
		/*
			Purpose: removal of symbols not being used by references
			
			
		*/
		#! (n_symbols,state)
			= select_n_symbols file_n state;
//		#! references
//			= createArray n_symbols False;
		
		// text symbols
		#! (text_symbols,state)
			= selacc_text_symbols file_n state;
		#! (references,state)
			= mark_referenced_symbols text_symbols references state;
			
		// data symbols
		#! (data_symbols,state)
			= selacc_data_symbols file_n state;
		#! (references,state)
			= mark_referenced_symbols data_symbols references state;
			
		// bss symbols
		#! (bss_symbols,state)
			= selacc_data_symbols file_n state;
		#! (references,state)
			= mark_referenced_symbols bss_symbols references state;		
		
		#! s
			= (p 0 (size references) references "");
		
//		| True
//			= abort (p 0 (size references) references ""); //(toString (size references));
		
		= mark_referenced_symbols_in_xcoff (inc file_n) (first_symbol_n + n_symbols) references state;
where //{
	mark_referenced_symbols :: SymbolIndexList *{#Bool} !*State -> (*{#Bool},!*State);
	mark_referenced_symbols EmptySymbolIndex references state
		= (references,state);
		
	mark_referenced_symbols (SymbolIndex module_n sils) references state
	
		#! (marked_module_symbol,state)
			= selacc_marked_bool_a (first_symbol_n + module_n) state;
		| marked_module_symbol
			// references from marked symbols do not count anymore because
			// these have already been resolved; from the point of view of
			// the marked module these could already have been thrown out.
			// Thus the reference-array remains unchanged.
			= mark_referenced_symbols sils references state;

			// a unmarked module may contain references to other symbols.
			#! (Module _ _ _ _ _ n_relocations relocations,state)
				= sel_symbol file_n module_n state;
			#! (references,state)
				= mark_references 0 n_relocations references relocations state;
			= mark_referenced_symbols sils references state;
	where //{
		mark_references relocation_n n_relocations references relocations state
			| relocation_n == n_relocations
				= (references,state);

				#! (marked_relocation_symbol,state)
					= selacc_marked_bool_a (first_symbol_n + relocation_symbol_n) state;
				| marked_relocation_symbol
					= mark_references (inc relocation_n) n_relocations references relocations state;

					#! (at_least_one_reference,references)
						= references![first_symbol_n + relocation_symbol_n];
					| at_least_one_reference
						= mark_references (inc relocation_n) n_relocations references relocations state;
								
						#! references
							= { references & [first_symbol_n + relocation_symbol_n] = True };
						= mark_references (inc relocation_n) n_relocations references relocations state;
		where //{
			relocation_symbol_n=relocations ILONG (relocation_index+4);
			relocation_index=relocation_n * SIZE_OF_RELOCATION;
		//} 
//	}	
//}