string	asis

	macro
	lea	&r,&a
	lwz	&r,&a{TC}(RTOC)
	endm

; MACOSX		set	1
USE_TEMPORARY_MEMORY	set	1
CHECK_STACK_OVERFLOWS	set	0
MODULE_NAMES	set	1

d0:	set	r24
d1:	set	r25
d2:	set	r26
d3:	set	r27
d4:	set	r28
d5:	set	r29
d6:	set	r30
d7:	set	r31

a0:	set	r23
a1:	set	r22
a2:	set	r21
a3:	set	r20
a4:	set	r19
a5:	set	r18
a6:	set	r17

o0:	set	r3
o1:	set	r4
o2:	set	r5
o3:	set	r6
o4:	set	r7
o5:	set	r8

g2:	set	r9
g3:	set	r10

g0:	set	r11
g1:	set	r12

int_reg	set	r16
char_reg	set	r15
real_reg	set	r14
bool_reg	set	r13

	export	init_profiler
	export	profile_r
	export 	profile_l
	export 	profile_l2
	export 	profile_n
	export 	profile_n2
	export 	profile_s
	export 	profile_s2
	export 	profile_t
	export	profile_ti
	export	write_profile_information
	export	write_profile_stack

 if USE_TEMPORARY_MEMORY
	import	.TempNewHandle
	import	.TempHLock
	import	.TempHUnlock
	import	.TempDisposeHandle
 else
	import	.NewPtr
 endif
	import	__STRING__
	import	writeFC
	import	writeFI
	import	print_error
	import	stack_size
	import	.er_print_string
	import	.er_print_char
 if CHECK_STACK_OVERFLOWS
	import	.Debugger
 endif

FunctionProfile: 	record
next:		ds.l	1
name:		ds.l	1
		endr
	
	csect	.profile_t
profile_ti:
	lea	r5,profile_globals
	b	profile_t_

profile_t:
	mflr	r12
	lea	r5,profile_globals
	mtctr	r12
	mtlr	r0
profile_t_:
	lwz	r6,Globals.stack_pointer(r5)
	lwzu	r4,-4(r6)
	stw	r6,Globals.stack_pointer(r5)
	bctr

	csect	.profile_r
profile_r:
	lea	r5,profile_globals
	lwz	r6,Globals.stack_pointer(r5)
	lwzu	r4,-4(r6)
	stw	r6,Globals.stack_pointer(r5)
	blr

	csect	.profile_l
profile_l:
	mflr	r12
	lea	r5,profile_globals
	lwz	r4,0(r3)
	mtctr	r12
		
	cmpwi	0,r4,0
	beql	allocate_function_profile_record

	lwz	r6,Globals.stack_pointer(r5)
	stw	r4,0(r6)
	addi	r6,r6,4
 if CHECK_STACK_OVERFLOWS
	lwz	r12,Globals.end_profile_stack(r5)
 endif
	stw	r6,Globals.stack_pointer(r5)
 if CHECK_STACK_OVERFLOWS 
	cmpw	r6,r12
	bge	profile_stack_overflow
 endif
	mtlr	r0
	bctr

	csect	.profile_l2
profile_l2:
	mflr	r12
	lea	r5,profile_globals
	lwz	r4,0(r3)
	mtctr	r12
		
	cmpwi	0,r4,0
	beql	allocate_function_profile_record

	lwz	r6,Globals.stack_pointer(r5)	
	stw	r4,0(r6)
	stw	r4,4(r6)
	addi	r6,r6,8
 if CHECK_STACK_OVERFLOWS
	lwz	r12,Globals.end_profile_stack(r5)
 endif
	stw	r6,Globals.stack_pointer(r5)
 if CHECK_STACK_OVERFLOWS 
	cmpw	r6,r12
	bge	profile_stack_overflow
 endif

	mtlr	r0
	bctr

	csect	.profile_n
profile_n:
	mflr	r12
	lea	r5,profile_globals
	lwz	r4,0(r3)
	mtctr	r12
		
	cmpwi	0,r4,0
	beql	allocate_function_profile_record

	lwz	r6,Globals.stack_pointer(r5)
	stw	r4,0(r6)
	addi	r6,r6,4
 if CHECK_STACK_OVERFLOWS
	lwz	r12,Globals.end_profile_stack(r5)
 endif
	stw	r6,Globals.stack_pointer(r5)
 if CHECK_STACK_OVERFLOWS 
	cmpw	r6,r12
	bge	profile_stack_overflow
 endif
	mtlr	r0
	bctr

	csect	.profile_n2
profile_n2:
	mflr	r12
	lea	r5,profile_globals
	lwz	r4,0(r3)
	mtctr	r12
		
	cmpwi	0,r4,0
	beql	allocate_function_profile_record

	lwz	r6,Globals.stack_pointer(r5)
	stw	r4,0(r6)
	stw	r4,4(r6)
	addi	r6,r6,8
 if CHECK_STACK_OVERFLOWS
	lwz	r12,Globals.end_profile_stack(r5)
 endif
	stw	r6,Globals.stack_pointer(r5)
 if CHECK_STACK_OVERFLOWS 
	cmpw	r6,r12
	bge	profile_stack_overflow
 endif
	mtlr	r0
	bctr

	csect	.profile_s2
profile_s2:
	mflr	r12
	lea	r5,profile_globals
	lwz	r4,0(r3)
	mtctr	r12
		
	cmpwi	0,r4,0
	beql	allocate_function_profile_record

	lwz	r6,Globals.stack_pointer(r5)
	stw	r4,0(r6)
	stw	r4,4(r6)
	addi	r6,r6,8
 if CHECK_STACK_OVERFLOWS
	lwz	r12,Globals.end_profile_stack(r5)
 endif
	stw	r6,Globals.stack_pointer(r5)
 if CHECK_STACK_OVERFLOWS 
	cmpw	r6,r12
	bge	profile_stack_overflow
 endif
	mtlr	r0
	bctr

	csect	.profile_s
profile_s:
	mflr	r12
	lea	r5,profile_globals
	lwz	r4,0(r3)
	mtctr	r12
		
	cmpwi	0,r4,0
	beql	allocate_function_profile_record

	lwz	r6,Globals.stack_pointer(r5)

	stw	r4,0(r6)
	addi	r6,r6,4
 if CHECK_STACK_OVERFLOWS
	lwz	r12,Globals.end_profile_stack(r5)
 endif
	stw	r6,Globals.stack_pointer(r5)
 if CHECK_STACK_OVERFLOWS 
	cmpw	r6,r12
	bge	profile_stack_overflow
 endif
	mtlr	r0
	bctr

allocate_function_profile_record:
	lwz	r6,Globals.n_free_records_in_block(r5)
	lwz	r4,Globals.last_allocated_block(r5)
	cmpwi	0,r6,0
	bne+	no_alloc

	stw	r0,-4(sp)
	stw	r3,-8(sp)
	stw	r9,-12(sp)
	stw	r10,-16(sp)
	mfctr	r11
	stw	r11,-20(sp)
	mflr	r12
	stw	r12,-24(sp)
	
 if USE_TEMPORARY_MEMORY
	li	r3,(512*FunctionProfile)+4
 else
	li	r3,512*FunctionProfile
 endif
 if MACOSX
 	mr	g0,sp
 	ori	sp,sp,28
 	stwu	g0,-(64+32+28)(sp)
 else
	stwu	sp,-(64+32)(sp)
 endif
 if USE_TEMPORARY_MEMORY
 	bl	allocate_temp_memory_handle
 else
	bl	.NewPtr
	nop
 endif
 if MACOSX
	lwz	sp,0(sp)
 else
	addi	sp,sp,64+32
 endif
	and.	r4,r3,r3
	
	lwz	r12,-24(sp)
	lwz	r11,-20(sp)
	mtlr	r12
	lwz	r10,-16(sp)
	mtctr	r11
	lwz	r9,-12(sp)
	lwz	r3,-8(sp)
	lwz	r0,-4(sp)

	lea	r5,profile_globals

	beq	profiler_memory_error

 if USE_TEMPORARY_MEMORY
	lwz	r6,Globals.temp_handle_list(r5)
	stw	r4,Globals.temp_handle_list(r5)
	lwz	r4,0(r4)
	stw	r6,0(r4)
	addi	r4,r4,4
 endif
	li	r6,512
	stw	r4,Globals.last_allocated_block(r5)	

no_alloc:	
	subi	r6,r6,1
	stw	r6,Globals.n_free_records_in_block(r5)
	addi	r7,r4,FunctionProfile
	stw	r7,Globals.last_allocated_block(r5)

	lwz	r6,Globals.profile_records(r5)
	li	r8,0
	stw	r6,FunctionProfile.next(r4)
	stw	r4,Globals.profile_records(r5)
	stw	r3,FunctionProfile.name(r4)
	
	stw	r4,0(r3)
	blr

	csect	.write_profile_information
write_profile_information:
 if USE_TEMPORARY_MEMORY
 	mflr	r0
  if MACOSX
 	mr	g0,sp
 	ori	sp,sp,28
 	stwu	g0,-(96+28)(sp)
  else
	stwu	sp,-96(sp)
  endif
	stw	r0,96-4(sp)
	lea	r5,profile_globals
	lwz	r3,Globals.profile_stack_handle(r5)
 	bl	free_temp_memory_handle

	lea	r5,profile_globals

	stw	r31,96-8(sp)
	
	lwz	r31,Globals.temp_handle_list(r5)
	b	free_temp_handles
	
free_temp_handles_lp:
	mr	r3,r31
	lwz	r31,0(r31)
	lwz	r31,0(r31)
	bl	free_temp_memory_handle

free_temp_handles:
	cmpwi	0,r31,0
	bne	free_temp_handles_lp

	lwz	r31,96-8(sp)
	
	lwz	r0,96-4(sp)
  if MACOSX
	lwz	sp,0(sp)
  else
	addi	sp,sp,96
  endif
 	mtlr	r0
 endif
	lwz	r0,0(sp)
	addi	sp,sp,4
	blr

	csect	.write_profile_stack
write_profile_stack:
	mflr	r0
	lea	d0,profile_globals
	stwu	r0,-4(sp)
	lwz	d0,Globals.stack_pointer(d0)

	cmpwi	0,d0,0
	beq	@stack_not_initialised

 if MACOSX
 	mr	g0,sp
 	ori	sp,sp,28
 	stwu	g0,-(64+28)(sp)
 else
	stwu	sp,-64(sp)
 endif
	lea	o0,stack_trace_string
	bl	.er_print_string
 if MACOSX
 	lwz	sp,0(sp)
 else
	addi	sp,sp,64
 endif
	
	li	d2,12
@write_functions_on_stack
	lwzu	d1,-4(d0)
	cmpwi	0,d1,0
	beq	@end_profile_stack
		
	lwz	o0,FunctionProfile.name(d1)

 if MACOSX
 	mr	g0,sp
 	ori	sp,sp,28
 	stwu	g0,-(64+28)(sp)
 else
	stwu	sp,-64(sp)
 endif
	addi	o0,o0,4
	bl	.er_print_string
	nop
	li	o0,13
	bl	.er_print_char
	nop
 if MACOSX
 	lwz	sp,0(sp)
 else
	addi	sp,sp,64
 endif

	subic.	d2,d2,1
 if 0
	b	@write_functions_on_stack
 else
	bne	@write_functions_on_stack
 endif

@end_profile_stack:
@stack_not_initialised:
	lwz	r0,0(sp)
	mtlr	r0
	lwz	r0,4(sp)
	addi	sp,sp,8
	blr

	csect	.init_profiler
init_profiler:
 if 0
	mflr	r0
	stw	r0,-4(sp)
	stwu	sp,-64(sp)

	bl	.Debugger
	nop
	
	lwz	r0,64-4(sp)
	addi	sp,sp,64
	mtlr	r0
 endif

	mflr	r0
	stwu	r0,-4(sp)

 if 1
	lea	r3,stack_size
	lwz	r3,0(r3)
	addi	r3,r3,4095
	rlwinm	r3,r3,0,0,31-12
 else
	li	r3,   (512*1024) % 65536
	addis	r3,r3,(512*1024) / 65536
 endif

 if MACOSX
 	mr	g0,sp
 	ori	sp,sp,28
 	stwu	g0,-(64+28)(sp)
 else
	stwu	sp,-64(sp)
 endif
 if USE_TEMPORARY_MEMORY
 	bl	allocate_temp_memory_handle
 else
	bl	.NewPtr
	nop
 endif
 if MACOSX
 	lwz	sp,0(sp)
 else
	addi	sp,sp,64
 endif
	lea	r5,profile_globals

	and.	r9,r3,r3
	beq	init_profiler_error

 if USE_TEMPORARY_MEMORY
	stw	r9,Globals.profile_stack_handle(r5)
 	lwz	r9,0(r9)
	li	r0,0
	stw	r0,Globals.temp_handle_list(r5)
 endif
 if CHECK_STACK_OVERFLOWS
  if 1
	lea	r3,stack_size
	lwz	r3,0(r3)
  else
	li	r3,   (512*1024) % 65536
	addis	r3,r3,(512*1024) / 65536
  endif
	add	r3,r3,r9
	stw	r3,Globals.end_profile_stack(r5)
 endif
	lea	r3,start_string
	bl	allocate_function_profile_record

	lwz	r0,0(sp)
	addi	sp,sp,4
	mtlr	r0

	li	r0,0
	stw	r4,4(r9)
	stw	r0,0(r9)
	addi	r9,r9,8
	stw	r9,Globals.stack_pointer(r5)
	stw	d7,Globals.n_words_free(r5)

	lwz	r0,0(sp)
	addi	sp,sp,4

	blr

 if USE_TEMPORARY_MEMORY
allocate_temp_memory_handle:
	mflr	r0
	stw	r31,-4(sp)
	stw	r0,8(sp)
	stwu	sp,-96(sp)

	addi	r4,sp,56
	bl	.TempNewHandle
	nop

	mr.	r31,r3
	beq	return_r31

	addi	r4,sp,56
	bl	.TempHLock
	nop

	lha	r0,56(sp)
	cmpwi	r0,0
	beq+	return_r31

	mr	r3,r31
	addi	r4,sp,56
	bl	.TempDisposeHandle
	nop

	li	r31,0
return_r31:
	lwz	r0,104(sp)
	mr	r3,r31
	mtlr	r0
	addi	sp,sp,96
	lwz	r31,-4(sp)
	blr

free_temp_memory_handle:
	mflr	r0
	stw	r3,-4(sp)
	stw	r0,8(sp)
	stwu	sp,-96(sp)

	addi	r4,sp,56
	bl	.TempHUnlock
	nop

	lwz	r3,96-4(sp)
	addi	r4,sp,56
	bl	.TempDisposeHandle
	nop

	lwz	r0,104(sp)
	addi	sp,sp,96
	mtlr	r0
	blr
 endif

init_profiler_error:
	lea	o0,not_enough_memory_for_profile_stack
	lea	r5,profile_globals
	li	r4,0
	stw	r4,Globals.stack_pointer(r5)
	b	print_error
profiler_memory_error:
	lea	o0,not_enough_memory_for_profiler
	b	print_error
 if CHECK_STACK_OVERFLOWS 
profile_stack_overflow:
	mflr	r0
	stw	r0,-4(sp)
	stwu	sp,-64(sp)

	bl	.Debugger
	nop
	
	lwz	r0,64-4(sp)
	addi	sp,sp,64
	mtlr	r0
	b	profile_stack_overflow
 endif


	csect	data{RW}
Globals:		record
n_free_records_in_block:ds.l	1 ; 0 n free records in block
last_allocated_block:	ds.l	1 ; 4 latest allocated block
profile_records:	ds.l	1 ; 8 profile record list
stack_pointer:	ds.l	1 ; 12 stack pointer
n_words_free:	ds.l	1
 if USE_TEMPORARY_MEMORY
temp_handle_list	ds.l	1
profile_stack_handle	ds.l	1
 endif
 if CHECK_STACK_OVERFLOWS
end_profile_stack	ds.l	1
 endif
		endr

	align	2
profile_globals: ds	Globals

	align	2
 if MODULE_NAMES
m_system:
	dc.l	6
	dc.b	'System'
	dc.b	0,0
	dc.l	m_system
 endif
start_string:
	dc.l	0
	dc.b	'start'
	dc.b	0
	align	2
not_enough_memory_for_profile_stack:
	dc.b	'not enough memory for profile stack'
	dc.b	13
	dc.b	0
not_enough_memory_for_profiler:
	dc.b	'not enough memory for profiler'
	dc.b	13
	dc.b	0
stack_trace_string:
	dc.b	'Stack trace:'
	dc.b	13
	dc.b	0
	align	2

	macro
	te	&address
	tc	&address{TC},&address
	endm

	toc
	
	te	profile_globals
	te	not_enough_memory_for_profile_stack
	te	not_enough_memory_for_profiler
	te	start_string
	te	stack_trace_string
	te	stack_size