string	asis

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

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

 if POWER601
	macro
	time_hi	&r
	dialect	Power
	mfrtcu	&r
	dialect	PowerPC
	endm

	macro
	time_lo	&r
	dialect	Power
	mfrtcl	&r
	dialect	PowerPC
	endm
 else
	macro
	time_hi	&r
	mftbu	&r
	endm

	macro
	time_lo	&r
	mftb	&r
	endm
 endif

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

 if POWER601
lo1e9	set	1000000000 % 65536
hi1e9	set	(1000000000 / 65536)+1
 endif

	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	.Gestalt
	import	__STRING__
	import	openF
	import	closeF
	import	writeFC
	import	writeFI
	import	print_error
	import	new_file_creator
	import	stack_size
	import	.er_print_string
	import	.er_print_char
	import	.create_profile_file_name
 if CHECK_STACK_OVERFLOWS
	import	.Debugger
 endif

FunctionProfile: 	record
next:		ds.l	1
time_hi:		ds.l	1
time_lo:		ds.l	1
n_profiler_calls:	ds.l	1
n_strict_calls:	ds.l	1
n_lazy_calls:	ds.l	1
n_curried_calls:	ds.l	1
n_words_allocated:	ds.l	1
name:		ds.l	1
		endr
	
	csect	.profile_t
profile_ti:
@read_clock:
	time_hi	r9
	time_lo	r10
	time_hi	r4
	cmpw	0,r4,r9
	bne-	@read_clock

	lea	r5,profile_globals
	b	profile_t_

profile_t:
@read_clock:
	time_hi	r9
	time_lo	r10
	time_hi	r4
	cmpw	0,r4,r9
	bne-	@read_clock

	mflr	r12
	lea	r5,profile_globals
	mtctr	r12
	mtlr	r0
profile_t_:
	lwz	r6,Globals.stack_pointer(r5)

	lwz	r7,Globals.time_hi(r5)
	lwz	r8,Globals.time_lo(r5)

	lwzu	r4,-4(r6)
	stw	r6,Globals.stack_pointer(r5)
	stw	r4,Globals.last_tail_call(r5)

 if POWER601	
	sub.	r10,r10,r8
	sub	r9,r9,r7
	bge+	@no_borrow
	addis	r10,r10,hi1e9
	addi	r10,r10,lo1e9
	subi	r9,r9,1
@no_borrow:
 else
	subc	r10,r10,r8
	subfe	r9,r7,r9
 endif
	lwz	r8,FunctionProfile.time_lo(r4)
	lwz	r7,FunctionProfile.time_hi(r4)

 if POWER601
	add	r8,r8,r10
	add	r7,r7,r9

	subis	r9,r8,hi1e9
	cmpwi	0,r9,lo1e9

	lwz	r6,FunctionProfile.n_profiler_calls(r4)

	blt+	@no_carry

	subi	r8,r9,lo1e9
	addi	r7,r7,1

@no_carry:
 else
	addc	r8,r8,r10
	lwz	r6,FunctionProfile.n_profiler_calls(r4)
	adde	r7,r7,r9
 endif
	addi	r6,r6,1
	stw	r7,FunctionProfile.time_hi(r4)
	stw	r8,FunctionProfile.time_lo(r4)
	stw	r6,FunctionProfile.n_profiler_calls(r4)

 if ALLOCATION_PROFILE
	lwz	r11,Globals.n_words_free(r5)
	stw	d7,Globals.n_words_free(r5)
	lwz	r12,FunctionProfile.n_words_allocated(r4)
	sub	r11,r11,d7
	add	r12,r12,r11	
	stw	r12,FunctionProfile.n_words_allocated(r4)
 endif

@store_clock:
	time_hi	r9
	stw	r9,Globals.time_hi(r5)
	time_lo	r10
	time_hi	r4
	stw	r10,Globals.time_lo(r5)
	cmpw	0,r4,r9
	beqctr+

	b	@store_clock

	csect	.profile_r
profile_r:
@read_clock:
	time_hi	r9
	time_lo	r10
	time_hi	r4
	cmpw	0,r4,r9
	bne-	@read_clock

	lea	r5,profile_globals

	lwz	r6,Globals.stack_pointer(r5)

	lwz	r7,Globals.time_hi(r5)
	lwz	r8,Globals.time_lo(r5)

	lwzu	r4,-4(r6)
	li	r3,0
	stw	r6,Globals.stack_pointer(r5)
	stw	r3,Globals.last_tail_call(r5)
	
 if POWER601	
	sub.	r10,r10,r8
	sub	r9,r9,r7
	bge+	@no_borrow
	addis	r10,r10,hi1e9
	addi	r10,r10,lo1e9
	subi	r9,r9,1
@no_borrow:
 else
	subc	r10,r10,r8
	subfe	r9,r7,r9
 endif

	lwz	r8,FunctionProfile.time_lo(r4)
	lwz	r7,FunctionProfile.time_hi(r4)

 if POWER601	
	add	r8,r8,r10
	add	r7,r7,r9

	subis	r9,r8,hi1e9
	cmpwi	0,r9,lo1e9

	lwz	r6,FunctionProfile.n_profiler_calls(r4)

	blt+	@no_carry

	subi	r8,r9,lo1e9
	addi	r7,r7,1

@no_carry:
 else
	addc	r8,r8,r10
	lwz	r6,FunctionProfile.n_profiler_calls(r4)
	adde	r7,r7,r9
 endif

	addi	r6,r6,1
	stw	r7,FunctionProfile.time_hi(r4)
	stw	r8,FunctionProfile.time_lo(r4)
	stw	r6,FunctionProfile.n_profiler_calls(r4)

 if ALLOCATION_PROFILE
	lwz	r11,Globals.n_words_free(r5)
	stw	d7,Globals.n_words_free(r5)
	lwz	r12,FunctionProfile.n_words_allocated(r4)
	sub	r11,r11,d7
	add	r12,r12,r11	
	stw	r12,FunctionProfile.n_words_allocated(r4)
 endif

@store_clock:
	time_hi	r9
	stw	r9,Globals.time_hi(r5)
	time_lo	r10
	time_hi	r4
	stw	r10,Globals.time_lo(r5)
	cmpw	0,r4,r9
	beqlr+

	b	@store_clock

	csect	.profile_l
profile_l:
@read_clock:
	time_hi	r9
	time_lo	r10
	time_hi	r4
	cmpw	0,r4,r9
	bne-	@read_clock

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

	lwz	r3,Globals.last_tail_call(r5)
	lwz	r6,Globals.stack_pointer(r5)
	cmpwi	0,r3,0
	
	lwz	r7,Globals.time_hi(r5)
	lwz	r8,Globals.time_lo(r5)

	bne	@use_tail_calling_function

	lwz	r3,-4(r6)
@c_use_tail_calling_function:

	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
	lwz	r6,FunctionProfile.n_curried_calls(r4)
	mtlr	r0
	addi	r6,r6,1
	stw	r6,FunctionProfile.n_curried_calls(r4)
	b	profile_n_

@use_tail_calling_function:
	li	r12,0
	stw	r12,Globals.last_tail_call(r5)
	b	@c_use_tail_calling_function

	csect	.profile_l2
profile_l2:
@read_clock:
	time_hi	r9
	time_lo	r10
	time_hi	r4
	cmpw	0,r4,r9
	bne-	@read_clock

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

	lwz	r3,Globals.last_tail_call(r5)
	lwz	r6,Globals.stack_pointer(r5)
	cmpwi	0,r3,0
	
	lwz	r7,Globals.time_hi(r5)
	lwz	r8,Globals.time_lo(r5)

	bne	@use_tail_calling_function

	lwz	r3,-4(r6)
@c_use_tail_calling_function:

	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

	lwz	r6,FunctionProfile.n_curried_calls(r4)
	mtlr	r0
	addi	r6,r6,1
	stw	r6,FunctionProfile.n_curried_calls(r4)	
	b	profile_n_

@use_tail_calling_function:
	li	r12,0
	stw	r12,Globals.last_tail_call(r5)
	b	@c_use_tail_calling_function

	csect	.profile_n
profile_n:
@read_clock:
	time_hi	r9
	time_lo	r10
	time_hi	r4
	cmpw	0,r4,r9
	bne-	@read_clock

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

	lwz	r3,Globals.last_tail_call(r5)
	lwz	r6,Globals.stack_pointer(r5)
	cmpwi	0,r3,0
	
	lwz	r7,Globals.time_hi(r5)
	lwz	r8,Globals.time_lo(r5)

	bne	@use_tail_calling_function

	lwz	r3,-4(r6)
@c_use_tail_calling_function:

	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

	lwz	r6,FunctionProfile.n_lazy_calls(r4)
	mtlr	r0
	addi	r6,r6,1
	stw	r6,FunctionProfile.n_lazy_calls(r4)
	b	profile_n_

@use_tail_calling_function:
	li	r12,0
	stw	r12,Globals.last_tail_call(r5)
	b	@c_use_tail_calling_function

	csect	.profile_n2
profile_n2:
@read_clock:
	time_hi	r9
	time_lo	r10
	time_hi	r4
	cmpw	0,r4,r9
	bne-	@read_clock

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

	lwz	r3,Globals.last_tail_call(r5)
	lwz	r6,Globals.stack_pointer(r5)
	cmpwi	0,r3,0
	
	lwz	r7,Globals.time_hi(r5)
	lwz	r8,Globals.time_lo(r5)

	bne	@use_tail_calling_function

	lwz	r3,-4(r6)
@c_use_tail_calling_function:

	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

	lwz	r6,FunctionProfile.n_lazy_calls(r4)
	mtlr	r0
	addi	r6,r6,1
	stw	r6,FunctionProfile.n_lazy_calls(r4)	
	b	profile_n_

@use_tail_calling_function:
	li	r12,0
	stw	r12,Globals.last_tail_call(r5)
	b	@c_use_tail_calling_function

	csect	.profile_s2
profile_s2:
@read_clock:
	time_hi	r9
	time_lo	r10
	time_hi	r4
	cmpw	0,r4,r9
	bne-	@read_clock

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

	lwz	r3,Globals.last_tail_call(r5)
	lwz	r6,Globals.stack_pointer(r5)
	cmpwi	0,r3,0
	
	lwz	r7,Globals.time_hi(r5)
	lwz	r8,Globals.time_lo(r5)

	bne	@use_tail_calling_function

	lwz	r3,-4(r6)
@c_use_tail_calling_function:

	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
	b	profile_s_

@use_tail_calling_function:
	li	r12,0
	stw	r12,Globals.last_tail_call(r5)
	b	@c_use_tail_calling_function

	csect	.profile_s
profile_s:
@read_clock:
	time_hi	r9
	time_lo	r10
	time_hi	r4
	cmpw	0,r4,r9
	bne-	@read_clock

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

	lwz	r3,Globals.last_tail_call(r5)
	lwz	r6,Globals.stack_pointer(r5)
	cmpwi	0,r3,0
	
	lwz	r7,Globals.time_hi(r5)
	lwz	r8,Globals.time_lo(r5)

	bne	use_tail_calling_function0

	lwz	r3,-4(r6)
c_use_tail_calling_function0:

	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

profile_s_:
	lwz	r6,FunctionProfile.n_strict_calls(r4)
	mtlr	r0
	addi	r6,r6,1
	stw	r6,FunctionProfile.n_strict_calls(r4)

profile_n_:
 if POWER601	
	sub.	r10,r10,r8
	sub	r9,r9,r7
	bge+	@no_borrow
	addis	r10,r10,hi1e9
	addi	r10,r10,lo1e9
	subi	r9,r9,1
@no_borrow:
 else
	subc	r10,r10,r8
	subfe	r9,r7,r9
 endif

	lwz	r8,FunctionProfile.time_lo(r3)
	lwz	r7,FunctionProfile.time_hi(r3)
	
 if POWER601	
	add	r8,r8,r10
	add	r7,r7,r9

	subis	r9,r8,hi1e9
	cmpwi	0,r9,lo1e9

	lwz	r6,FunctionProfile.n_profiler_calls(r3)

	blt+	@no_carry

	subi	r8,r9,lo1e9
	addi	r7,r7,1

@no_carry:
 else
	addc	r8,r8,r10
	lwz	r6,FunctionProfile.n_profiler_calls(r3)
	adde	r7,r7,r9
 endif
	addi	r6,r6,1
	stw	r7,FunctionProfile.time_hi(r3)
	stw	r8,FunctionProfile.time_lo(r3)
	stw	r6,FunctionProfile.n_profiler_calls(r3)

 if ALLOCATION_PROFILE
	lwz	r11,Globals.n_words_free(r5)
	stw	d7,Globals.n_words_free(r5)
	lwz	r12,FunctionProfile.n_words_allocated(r3)
	sub	r11,r11,d7
	add	r12,r12,r11	
	stw	r12,FunctionProfile.n_words_allocated(r3)
 endif

@store_clock:
	time_hi	r9
	stw	r9,Globals.time_hi(r5)
	time_lo	r10
	time_hi	r4
	stw	r10,Globals.time_lo(r5)
	cmpw	0,r4,r9
	beqctr+
	
	b	@store_clock

use_tail_calling_function0:
	li	r12,0
	stw	r12,Globals.last_tail_call(r5)
	b	c_use_tail_calling_function0

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,(128*FunctionProfile)+4
 else
	li	r3,128*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,128
	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	r8,FunctionProfile.time_hi(r4)
	stw	r8,FunctionProfile.time_lo(r4)
	stw	r8,FunctionProfile.n_profiler_calls(r4)
	stw	r8,FunctionProfile.n_strict_calls(r4)
	stw	r8,FunctionProfile.n_lazy_calls(r4)
	stw	r8,FunctionProfile.n_curried_calls(r4)
	stw	r8,FunctionProfile.n_words_allocated(r4)
	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:
	lea	o0,profile_file_name

	mflr	r0
	stwu	r0,-4(sp)
 if MACOSX
 	mr	g0,sp
 	ori	sp,sp,28
 	stwu	g0,-(64+28)(sp)
 else
	stwu	sp,-64(sp)
 endif
	bl	.create_profile_file_name
	nop
 if MACOSX
 	lwz	sp,0(sp)
	lwz	r0,0(sp)
	addi	sp,sp,4
 else
	lwz	r0,64(sp)
	addi	sp,sp,68
 endif
	mtlr	r0

	lea	d3,new_file_creator
	li	d5,'T'*256+'I'
	lwz	d4,0(d3)
	addis	d5,d5,'P'*256+'R'
	stw	d5,0(d3)

	li	d0,1
	lea	a0,profile_file_name

	mflr	r0
	stwu	r0,-4(sp)	
	bl	openF
	mtlr	r0

	stw	d4,0(d3)

	cmpwi	0,d2,0
	beq	cannot_open
	
	mflr	r0
	li	d3,0
	stw	r0,-4(sp)
	stwu	d3,-8(sp)
	
 if MACOSX
 	mr	g0,sp
 	ori	sp,sp,28
 	stwu	g0,-(64+28)(sp)
 else
	stwu	sp,-64(sp)
 endif
	stw	d3,64(sp)
	li	r3,'u'*256+'t'
	addi	r4,sp,64
	addis	r3,r3,'c'*256+'p'
	bl	.Gestalt
	nop

	lwz	d2,64(sp)
	stwu	r0,-4(sp)	
	bl	writeFI_space
	mtlr	r0

	stw	d3,64(sp)
	li	r3,'l'*256+'k'
	addi	r4,sp,64
	addis	r3,r3,'p'*256+'c'
	bl	.Gestalt
	nop
	
	lwz	d2,64(sp)
	stwu	r0,-4(sp)	
	bl	writeFI_space
	mtlr	r0

	stw	d3,64(sp)
	li	r3,'l'*256+'k'
	addi	r4,sp,64
	addis	r3,r3,'b'*256+'c'
	bl	.Gestalt
	nop

	lwz	d2,64(sp)
	stwu	r0,-4(sp)	
	bl	writeFI
	mtlr	r0
	
	li	d2,13
	stwu	r0,-4(sp)	
	bl	writeFC
	mtlr	r0

 if MACOSX
 	lwz	sp,0(sp)
	lwz	r0,4(sp)
	addi	sp,sp,8
 else
	lwz	r0,68(sp)
	addi	sp,sp,72
 endif
	mtlr	r0

	lea	d2,profile_globals
	lwz	d2,Globals.profile_records(d2)

write_profile_lp:	
	cmpwi	0,d2,0
	beq	end_list

	lwz	d3,FunctionProfile.name(d2)
	stwu	d2,-4(sp)
	
#if MODULE_NAMES
	stwu	d3,-4(sp)

	lwz	d3,-4(d3)
	lwz	d2,0(d3)
	addi	d3,d3,3

write_module_name_lp:
	subic.	d2,d2,1
	blt	end_module_name
	
	stw	d2,-4(sp)
	lbzu	d2,1(d3)

	mflr	r0

	stw	d3,-8(sp)

	stwu	r0,-12(sp)	
	bl	writeFC
	mtlr	r0

	lwz	d2,4(sp)
	lwz	d3,0(sp)
	addi	sp,sp,8
	b	write_module_name_lp

end_module_name:
	li	d2,' '

	mflr	r0
	stwu	r0,-4(sp)	
	bl	writeFC
	mtlr	r0	

	lwz	d3,0(sp)
	addi	sp,sp,4
#endif

	addi	d3,d3,3
	
write_function_name_lp:
	lbzu	d2,1(d3)
	cmpwi	0,d2,0
	beq	end_function_name

	stw	d3,-4(sp)

	mflr	r0
	stwu	r0,-8(sp)	
	bl	writeFC
	mtlr	r0	

	lwz	d3,0(sp)
	addi	sp,sp,4
	b	write_function_name_lp

end_function_name:
	li	d2,' '

	mflr	r0
	stwu	r0,-4(sp)	
	bl	writeFC

	lwz	d2,0(sp)	
	lwz	d2,FunctionProfile.n_strict_calls(d2)
	stwu	r0,-4(sp)	
	bl	writeFI_space

	lwz	d2,0(sp)	
	lwz	d2,FunctionProfile.n_lazy_calls(d2)
	stwu	r0,-4(sp)	
	bl	writeFI_space

	lwz	d2,0(sp)	
	lwz	d2,FunctionProfile.n_curried_calls(d2)
	stwu	r0,-4(sp)
	bl	writeFI_space

	lwz	d2,0(sp)	
	lwz	d2,FunctionProfile.n_profiler_calls(d2)
	stwu	r0,-4(sp)
	bl	writeFI_space

	lwz	d2,0(sp)
	lwz	d2,FunctionProfile.n_words_allocated(d2)
	stwu	r0,-4(sp)	
	bl	writeFI_space

	lwz	d2,0(sp)
	lwz	d2,FunctionProfile.time_hi(d2)
	stwu	r0,-4(sp)	
	bl	writeFI_space

	lwz	d2,0(sp)	
	lwz	d2,FunctionProfile.time_lo(d2)
	stwu	r0,-4(sp)	
	bl	writeFI

	li	d2,13
	stwu	r0,-4(sp)	
	bl	writeFC
	mtlr	r0

	lwz	d2,0(sp)
	addi	sp,sp,4
	lwz	d2,FunctionProfile.next(d2)
	b	write_profile_lp

writeFI_space:
	mflr	r0
	stwu	r0,-4(sp)	
	bl	writeFI
	mtlr	r0

	li	d2,' '
	b	writeFC

end_list:
	mflr	r0
	stwu	r0,-4(sp)	
	bl	closeF
	mtlr	r0	

cannot_open:

 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
	nop
 if MACOSX
 	lwz	sp,0(sp)
 else
	addi	sp,sp,64
 endif

 if 1
	li	d2,12
 else
	li	d2,24
 endif
@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 MACOSX
 	subi	sp,sp,8
	mr	g0,sp
 	ori	sp,sp,28
 	stwu	g0,-(64+28)(sp)
 else
	stwu	sp,-72(sp)
 endif
	li	r3,0
	addi	r4,sp,64
	stw	r3,64(sp)
	li	r3,'u'*256+'t'
	addis	r3,r3,'c'*256+'p'
	bl	.Gestalt
	nop
	lwz	r3,64(sp)
 if MACOSX
 	lwz	sp,0(sp)
	addi	sp,sp,8
 else
	addi	sp,sp,72
 endif

	cmpwi	0,r3,257
 if POWER601
	bne	init_profiler_error1
 else
	beq	init_profiler_error1
 endif

 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	r0,Globals.last_tail_call(r5)
	stw	d7,Globals.n_words_free(r5)

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

@store_clock:
	time_hi	r9
	stw	r9,Globals.time_hi(r5)
	time_lo	r10
	time_hi	r4
	stw	r10,Globals.time_lo(r5)
	cmpw	0,r4,r9
	beqlr+

	b	@store_clock

 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_error1:
	lea	o0,wrong_processor
	lea	r5,profile_globals
	li	r4,0
	stw	r4,Globals.stack_pointer(r5)
	b	print_error
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
time_hi:		ds.l	1 ; 12 clock
time_lo:		ds.l	1
stack_pointer:	ds.l	1 ; 20 stack pointer
last_tail_call	ds.l	1 ; 24 last tail calling function
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

profile_file_name:
	dc.l	__STRING__+2
	dc.l	0
	ds.b	32
	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
wrong_processor:
 if POWER601
	dc.b	'Not a PowerPC601 processor (don''t use profiling option for 601)'
 else
 	dc.b	'This is a PowerPC601 processor (use profiling option for 601)'
 endif
	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	profile_file_name
	te	not_enough_memory_for_profile_stack
	te	not_enough_memory_for_profiler
	te	wrong_processor
	te	start_string
	te	stack_trace_string
	te	new_file_creator
	te	stack_size