.macro	lea_	&r,&a
	lis	$0,ha16($1)
	addi	$0,$0,lo16($1)
.endmacro

MACOSX		=	1
USE_TEMPORARY_MEMORY	=	1
CHECK_STACK_OVERFLOWS	=	0
MODULE_NAMES	=	1

#define sp r1

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

#define a0 r23
#define a1 r22
#define a2 r21
#define a3 r20
#define a4 r19
#define a5 r18
#define a6 r17

#define o0 r3
#define o1 r4
#define o2 r5
#define o3 r6
#define o4 r7
#define o5 r8

#define g2 r9
#define g3 r10

#define g0 r11
#define g1 r12

#define int_reg r16
#define char_reg r15
#define real_reg r14
#define bool_reg r13

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

 .if USE_TEMPORARY_MEMORY
	.globl	_TempNewHandle
	.globl	_TempHLock
	.globl	_TempHUnlock
	.globl	_TempDisposeHandle
 .else
	.globl	_NewPtr
 .endif
	.globl	__STRING__
	.globl	writeFC
	.globl	writeFI
	.globl	print_error
	.globl	_stack_size
	.globl	_er_print_string
	.globl	_er_print_char
 .if CHECK_STACK_OVERFLOWS
	.globl	_Debugger
 .endif

#define FunctionProfile_next 0
#define FunctionProfile_name 4

#define FunctionProfile	8

#define Globals_n_free_records_in_block 	0
				# comment 0 n free records in block
#define Globals_last_allocated_block	4
				# comment 4 latest allocated block
#define Globals_profile_records		8
				# comment 8 profile record list
#define Globals_stack_pointer      		12
				# comment 12 stack pointer
#define Globals_n_words_free		16
 .if USE_TEMPORARY_MEMORY
#define Globals_temp_handle_list		20
#define Globals_profile_stack_handle	24
  .if CHECK_STACK_OVERFLOWS
Globals_end_profile_stack =		28
Globals =				32
 .else
Globals =				28
  .endif
 .else
  .if CHECK_STACK_OVERFLOWS
Globals_end_profile_stack =		20
Globals =				24
  .else
Globals =				20
  .endif
 .endif

	.text
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

profile_r:
	lea_	r5,profile_globals
	lwz	r6,Globals_stack_pointer(r5)
	lwzu	r4,-4(r6)
	stw	r6,Globals_stack_pointer(r5)
	blr

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

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

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

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

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

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

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

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
	li	o0,13
	bl	_er_print_char
 .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

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	L_TempNewHandle$stub
	nop

	mr.	r31,r3
	beq	return_r31

	addi	r4,sp,56
	bl	L_TempHLock$stub
	nop

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

	mr	r3,r31
	addi	r4,sp,56
	bl	L_TempDisposeHandle$stub
	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	L_TempHUnlock$stub
	nop

	lwz	r3,96-4(sp)
	addi	r4,sp,56
	bl	L_TempDisposeHandle$stub
	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

	.data
	.align	2
	.comm	profile_globals,Globals

	.align	2
 .if MODULE_NAMES
m_system_:
	.long	6
	.ascii	"System"
	.byte	0,0
	.long	m_system_
 .endif
start_string:
	.long	0
	.ascii	"start"
	.byte	0
	.align	2
not_enough_memory_for_profile_stack:
	.ascii	"not enough memory for profile stack"
	.byte	13
	.byte	0
not_enough_memory_for_profiler:
	.ascii	"not enough memory for profiler"
	.byte	13
	.byte	0
stack_trace_string:
	.ascii	"Stack trace:"
	.byte	13
	.byte	0
	.align	2

.picsymbol_stub
L_TempDisposeHandle$stub:
	.indirect_symbol _TempDisposeHandle
	mflr r0
	bcl 20,31,L21$pb
L21$pb:
	mflr r11
	addis r11,r11,ha16(L21$lz-L21$pb)
	mtlr r0
	lwz r12,lo16(L21$lz-L21$pb)(r11)
	mtctr r12
	addi r11,r11,lo16(L21$lz-L21$pb )
	bctr
.lazy_symbol_pointer
L21$lz:
	.indirect_symbol _TempDisposeHandle
	.long dyld_stub_binding_helper


.picsymbol_stub
L_TempHLock$stub:
	.indirect_symbol _TempHLock
	mflr r0
	bcl 20,31,L22$pb
L22$pb:
	mflr r11
	addis r11,r11,ha16(L22$lz-L22$pb)
	mtlr r0
	lwz r12,lo16(L22$lz-L22$pb)(r11)
	mtctr r12
	addi r11,r11,lo16(L22$lz-L22$pb )
	bctr
.lazy_symbol_pointer
L22$lz:
	.indirect_symbol _TempHLock
	.long dyld_stub_binding_helper



.picsymbol_stub
L_TempHUnlock$stub:
	.indirect_symbol _TempHUnlock
	mflr r0
	bcl 20,31,L23$pb
L23$pb:
	mflr r11
	addis r11,r11,ha16(L23$lz-L23$pb)
	mtlr r0
	lwz r12,lo16(L23$lz-L23$pb)(r11)
	mtctr r12
	addi r11,r11,lo16(L23$lz-L23$pb )
	bctr
.lazy_symbol_pointer
L23$lz:
	.indirect_symbol _TempHUnlock
	.long dyld_stub_binding_helper



.picsymbol_stub
L_TempNewHandle$stub:
	.indirect_symbol _TempNewHandle
	mflr r0
	bcl 20,31,L24$pb
L24$pb:
	mflr r11
	addis r11,r11,ha16(L24$lz-L24$pb)
	mtlr r0
	lwz r12,lo16(L24$lz-L24$pb)(r11)
	mtctr r12
	addi r11,r11,lo16(L24$lz-L24$pb )
	bctr
.lazy_symbol_pointer
L24$lz:
	.indirect_symbol _TempNewHandle
	.long dyld_stub_binding_helper