// WARNING:
// consistency required with StdDynamicLowInterface!

// ModuleIDs can only occur in the main library instance. 
#include "gts_code_and_type_runtime_ids.h"

#define LINKED_MODULE_LIST_IS_SUPERFLUOUS

#define RID_N_RANGE_ENTRIES_OFFSET		0
#define RID_N_TYPE_TABLES_OFFSET		4
#define RID_HEADER_SIZE					(RID_N_TYPE_TABLES_OFFSET + 4)

#define RIDE_BEGIN_ADDRESS_OFFSET		0
#define RIDE_END_ADDRESS_OFFSET			4
#define RIDE_RUNTIME_ID_LIB_NUMBER		8
#define RIDE_SIZE						(RIDE_RUNTIME_ID_LIB_NUMBER + 4)

#define TTUT_UNUSED						0xffffffff

	.data
type_module_list:
	.long 	0
disk_type_id:
	.long 	0
	
#ifdef COLLECT_AND_RENUMBER_EXTERNAL_TYPE_REFERENCES
type_ref_id:
	.long	0
#endif
	
#ifdef LINKED_MODULE_LIST_IS_SUPERFLUOUS
current_module_id:
	.long	0
#endif

#ifdef CONVERT_LAZY_RUN_TIME_ID
found_runtime_id_entry: 
	.long 	0
searched_runtime_id_entry:
	.long	0
#endif
	
	.align	4
unknown_address:
	.long	__STRING__+2
	.long	116
	//       012345678901234567890123456789012345678901234567890123456789012345
	//		 0         1         2         3         4         5
	.ascii  "find_address_in_range_id in gts_range_id; unknown address; the add"
	.ascii	"ress does not seem to be allocated to code or data"
	.byte 	0
	.byte 	0
	.byte 	0
	.byte	0
	
	.text

init_range_id:
	movl	$0,type_module_list
	movl	$1,disk_type_id
	
#ifdef COLLECT_AND_RENUMBER_EXTERNAL_TYPE_REFERENCES
// see StdDynamicLowLevelInterface.icl
# define INITIAL_TYPE_REFERENCE_NUMBER 0
	movl	$ INITIAL_TYPE_REFERENCE_NUMBER,type_ref_id
#endif 

#ifdef LINKED_MODULE_LIST_IS_SUPERFLUOUS
	movl	$80000000,current_module_id					// uninitialized
#endif 
	ret

	// -------------------------------------------------------------------------------------
	// Shared

	// input:
	// - %ebx = address to find
	// 
	// output:
	// - %eax = library instance number (on disk)
	//
	// destroys:
	// - %eax, %ecx
find_code_library_instance_nr:
	call	find_address_in_range_id				// %ecx = ride_ptr
	movl	RIDE_RUNTIME_ID_LIB_NUMBER(%ecx),%eax	// %eax = run-time id number
	call	convert_code_rt_to_disk_id					// %ecx = corresponding disk id
	movl	%ecx,%eax								// disk id in output register
	ret

	// input:
	// - %ebx = address to find
	// 
	// output:
	// - %ecx = ptr to range_id_entry
	//
	// destroys:
	// - %eax, %ecx
find_address_in_range_id:
#define temp %edx
	pushl	temp
	
#define ride_ptr arity
#define rid_end_ptr nodeP
	movl	range_table,ride_ptr				// load base address of range_id table
	leal	8(ride_ptr),ride_ptr				// skip Clean STRING descriptor and length
	
	movl	RID_N_RANGE_ENTRIES_OFFSET(ride_ptr),rid_end_ptr
	movl	$ RIDE_SIZE,temp
	mull	temp		
	
	leal	RID_HEADER_SIZE(ride_ptr),ride_ptr	// ride_ptr = range_table + RID_HEADER_SIZE
	addl	ride_ptr,rid_end_ptr				// rid_end_ptr = ride_ptr + RID_N_RANGE_ENTRIES_OFFSET * RIDE_SIZE

1:
	// comparison i.e. start =< descP =< end
	cmpl 	RIDE_BEGIN_ADDRESS_OFFSET(ride_ptr),descP
	jb		2f
	cmpl	RIDE_END_ADDRESS_OFFSET(ride_ptr),descP
	jbe		3f
	
2:	
	addl	$ RIDE_SIZE,ride_ptr			
	cmpl	ride_ptr,rid_end_ptr
	jne 	1b

	popl	temp
	
	int3
	movl	$ unknown_address,%ecx	
	jmp		abort	
3:
	// address found
#undef rid_end_ptr
#undef ride_ptr
	popl	temp
#undef temp
	ret
	
	// 
	// input:
	// - %eax = run-time type id
	//
	// output:
	// - %ecx = disk type id
	//
	// destroys:
	// - %eax, %ecx
convert_code_rt_to_disk_id:
#define temp nodeP
#define temp2 arity
	leal	12(,temp,4),temp				// skip ARRAY, INT and length information
	addl	type_table_usage,temp
	movl	(temp),temp2				// get temp-th array element

	cmpl	$ TTUT_UNUSED,temp2
	jne		1f							

	
	movl	disk_type_id,temp2
	movl	temp2,(temp)				// update type_table_usage
	
	incl	disk_type_id				// increment type_table_usage ptr	
1:
	orl		$ CODE_LIBRARY_INSTANCE,(temp)	// mark library instance as used by a code reference

	andl	$ LIBRARY_INSTANCE_MASK,%ecx

	ret
#undef temp2	
#undef temp
	
	// -------------------------------------------------------------------------------------
	// External functions
#ifdef COLLECT_AND_RENUMBER_EXTERNAL_TYPE_REFERENCES
	// dummy
restore__Module_descriptors:					// dummy
	ret
	
#else // COLLECT_AND_RENUMBER_EXTERNAL_TYPE_REFERENCES
	// -------------------------------------------------------------------------------------
	// TYPES
	
	// input:
	// - %ebx ptr to descP = e__<module_name>__d____Module + 2
	//
	//	.long	m__<module_name>
	//  .align	4
	//	.long	e__<module_name>__d____Module+2
	//	.word	0
	//	.word	0
	//	.globl	e__<module_name>__d____Module
	//	e__<module_name>__d____Module:
	//	.word	0
	//	.word	0
	//	.long	8						// 2 bytes, type table id
	// .ascii	"__Module"				// tail, zero iff Nil
	//
	// output:
	// - %eax = library instance number (on disk)
	//
	// destroys:
	// - %eax, %ecx
	// - modified __Module-descriptor
	//
	// function is only called for converting ModuleIDs to (disk) library instances.
find_type_table_id:
# define type_table_id nodeP
# ifdef LINKED_MODULE_LIST_IS_SUPERFLUOUS
	movl	current_module_id,type_table_id
	testl	$80000000,type_table_id
	jnz		find_type_table_id_compute_library_instance_number
	ret

find_type_table_id_compute_library_instance_number:
	call	find_type_library_instance_nr
	
	movl	%eax,current_module_id
	ret

# else // not LINKED_MODULE_LIST_IS_SUPERFLUOUS
	movl	2(descP),type_table_id
	testl	type_table_id,type_table_id
	jns		0f							// 
	shll	$1,type_table_id
	ret
0:
	// convert to disk id
//	int3
/*
	call	find_address_in_range_id				// %ecx = ride_ptr
	movl	RIDE_RUNTIME_ID_LIB_NUMBER(%ecx),%eax	// %eax = run-time id number
	call	get_type_table_disk_id1					// %ecx = corresponding disk id
	movl	%ecx,%eax								// disk id in output register
*/	
	call	find_library_instance_nr

	// overwrite length of __Module with disk id
	shrl	$1,%ecx
	orl		$0x80000000,%ecx
	movl	%ecx,2(descP)
	
	// overwrite first four characters with tail ptr
#  define temp %ecx
	movl	type_module_list,temp
	movl	temp,6(descP)
	
	movl	descP,type_module_list
#  undef temp
# endif // not LINKED_MODULE_LIST_IS_SUPERFLUOUS

	ret
# undef type_table_id

	// input:
	// - %ebx = address to find
	// 
	// output:
	// - %eax = library instance number (on disk)
	//
	// destroys:
	// - %eax, %ecx
find_type_library_instance_nr:
	call	find_address_in_range_id				// %ecx = ride_ptr
	movl	RIDE_RUNTIME_ID_LIB_NUMBER(%ecx),%eax	// %eax = run-time id number
	call	convert_type_rt_to_disk_id				// %ecx = corresponding disk id
	movl	%ecx,%eax								// disk id in output register
	ret

	// input:
	// - nothing
	//
	// output:
	// - nothing
	//
	// destroys:
	// - %ebx
	//
	// description:
	// restore the descriptor names for __Module-linked list
restore__Module_descriptors:

# ifndef LINKED_MODULE_LIST_IS_SUPERFLUOUS
	movl	type_module_list,descP		// get start of list
0:
	cmpl	$0,descP
	je	 	restored__Module_descriptors

	movl	$8,2(descP)					// restore length
#  define temp %ecx
	movl	6(descP),temp				// backup tail
	movl	$0x6f4d5f5f,6(descP)		// restore __Mo
	movl	temp,descP
#  undef temp
	jmp		0b	
restored__Module_descriptors:
	movl	$0,type_module_list
# endif 

	ret

	// 
	// input:
	// - %eax = run-time type id
	//
	// output:
	// - %ecx = disk type id
	//
	// destroys:
	// - %eax, %ecx
convert_type_rt_to_disk_id:
# define temp nodeP
# define temp2 arity

# ifdef CONVERT_LAZY_RUN_TIME_ID
	testl	$ LAZY_LIBRARY_INSTANCE, temp
	jnz		convert_lazy_type_reference_to_disk_id
# endif 
	
	leal	12(,temp,4),temp				// skip ARRAY, INT and length information
	addl	type_table_usage,temp
	movl	(temp),temp2					// get temp-th array element
	
	cmpl	$ TTUT_UNUSED,temp2
	jne		1f							
	
	movl	disk_type_id,temp2
	movl	temp2,(temp)					// update type_table_usage
	
	incl	disk_type_id					// increment type_table_usage ptr	
1:
	orl		$ TYPE_LIBRARY_INSTANCE,(temp)	// mark library instance as used by a type reference

	andl	$ LIBRARY_INSTANCE_MASK,%ecx

	ret
	
	// input:
	// - %eax = run-time type id
	//
	// output:
	// - %ecx = disk type id
	//
	// destroys:
	// - %eax, %ecx
	//
	// only called in case of lazy RunTimeID
# ifdef CONVERT_LAZY_RUN_TIME_ID
convert_lazy_type_reference_to_disk_id:
	movl	temp,searched_runtime_id_entry	// backup searched run-time id

	movl	$0,found_runtime_id_entry		// search for run-time id
	movl	$ find_searched_runtime_id,%ecx
	call	MAKE_ID_FRTID(lb_map_array)
	
	movl	found_runtime_id_entry,temp
	cmpl	$0,temp
	jne		convert_lazy_type_reference_to_disk_id__allocated
	
	call	MAKE_ID_FRTID(lb_alloc_entry)	// allocate lazy run-time id entry
	
	movl	type_string_ptr,temp
	movl	temp,RTID_TYPE_STRING(%ecx)
	
	movl	searched_runtime_id_entry,temp
	movl	temp,RTID_RUNTIME_ID(%ecx)
	
	movl	disk_type_id,temp
	movl	temp,RTID_ASSIGNED_DISK_ID(%ecx)
	
	movl	%ecx,temp
	
	incl	disk_type_id
	
convert_lazy_type_reference_to_disk_id__allocated:
	movl	RTID_ASSIGNED_DISK_ID(temp),%ecx	// extract assigned disk id
	ret
	
find_searched_runtime_id:
	cmpl	$0,found_runtime_id_entry		
	jne 	find_searched_runtime_id_end	// run-time has already been found, end

	movl	RTID_RUNTIME_ID(%ecx),temp
	cmpl	temp,searched_runtime_id_entry
	jne		find_searched_runtime_id_end	// run-time id is different from the searched one, end
	
	movl	RTID_TYPE_STRING(%ecx),temp
	cmpl	temp,type_string_ptr
	jne 	find_searched_runtime_id_end	// ptr to type string is different from the searched one, end
	
	movl	%ecx,found_runtime_id_entry		// searched run-time id has been found

find_searched_runtime_id_end:
	ret

# endif // CONVERT_LAZY_RUN_TIME_ID

# undef temp2	
# undef temp

#endif // COLLECT_AND_RENUMBER_EXTERNAL_TYPE_REFERENCES

	pushl	nodeP
#define temp %ecx
	movl	TOT_TCS_TYPE_NAME(nodeP),temp	// fetch type string
	movl	temp,type_string_ptr
	
#define arg_blockP nodeP
	movl	12(nodeP),arg_blockP
	
#undef temp
	
	popl	nodeP
