/*
 * Copyright 2005-2009 Clozure Associates
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

	include(lisp.s)
	_beginfile

	.globl _SPmkcatch1v
	.globl _SPnthrow1value


/* This is called from a c-style context and calls a lisp function.*/
/* This does the moral equivalent of*/
/*   (loop */
/*	(let* ((fn (%function_on_top_of_lisp_stack)))*/
/*	  (if fn*/
/*            (catch %toplevel-catch%*/
/*	       (funcall fn))*/
/*            (return nil))))*/


_exportfn(toplevel_loop)
Xsubprims_start:        	
	__(push %rbp)
	__(movq %rsp,%rbp)
	/* Switch to the lisp stack */
        __(push $0)
        __(push $0)
	__(movq %rsp,rcontext(tcr.foreign_sp))
	__(movq rcontext(tcr.save_vsp),%rsp)
	__(push $0)
	__(movq %rsp,%rbp)
        
        __(TSP_Alloc_Fixed(0,%temp0))
        __(movsd %fpzero,tsp_frame.save_rbp(%temp0)) /* sentinel */
	__(jmp local_label(test))
local_label(loop):
	__(ref_nrs_value(toplcatch,%arg_z))
	__(leaq local_label(back_from_catch)(%rip),%ra0)
	__(leaq local_label(test)(%rip),%xfn)
        __(push %ra0)
	__(jmp _SPmkcatch1v)
__(tra(local_label(back_from_catch)))
	__(movq %arg_x,%temp0)
	__(leaq local_label(back_from_funcall)(%rip),%ra0)
        __(push %ra0)
	__(set_nargs(0))
	__(jmp _SPfuncall)
__(tra(local_label(back_from_funcall)))
	__(movl $fixnumone,%imm0_l)
	__(leaq local_label(test)(%rip),%ra0)
	__(jmp _SPnthrow1value)	
__(tra(local_label(test)))
	__(movq 8(%rbp),%arg_x)
	__(cmpq $nil_value,%arg_x)
	__(jnz local_label(loop))
local_label(back_to_c):
        __(discard_temp_frame(%imm0))
	__(movq rcontext(tcr.foreign_sp),%rsp)
        __(addq $dnode_size,%rsp)
	__(movq %rsp,%rbp)
	__(leave)
	__(ret)

/* This is called from C code when a thread (including the initial thread) */
/* starts execution.  (Historically, it also provided a primitive way of */
/* "resettting" a thread in the event of catastrophic failure, but this */
/* hasn't worked in a long time.) */
/* For compatibility with PPC code, this is called with the first foreign */
/* argument pointing to the thread's TCR and the second foreign argument */
/*  being a Boolean which indicates whether the thread should try to */
/* "reset" itself or start running lisp code.  Both of these arguments */
/* are currently ignored (the TCR is maintained in a segment register and */
/*  the reset/panic code doesn't work ...), except on Windows, where we use */
/* the first arg to set up the TCR register */	
   
_exportfn(C(start_lisp))
	__(push %rbp)
	__(movq %rsp,%rbp)
	__(push %csave0)
	__(push %csave1)
	__(push %csave2)
	__(push %csave3)
	__(push %csave4)
	__ifdef(`WINDOWS')
	__(push %csave5)
	__(push %csave6)
        __endif
        __ifdef(`TCR_IN_GPR')
	__(movq %carg0,%rcontext_reg)
	__endif
	__(sub $8,%rsp)	/* %rsp is now 16-byte aligned  */
	/* Put harmless values in lisp node registers  */
	__(clr %arg_z)
	__(clr %arg_y)
	__(clr %arg_x)
	__(clr %temp0)
	__(clr %temp1)
	__(clr %temp2)
	__(clr %fn)
        /*	__(clr %ra0) */ /* %ra0 == %temp2, now zeroed above */
	__(clr %temp3)
	__(clr %temp4)
	__(clr %temp5)
	__ifndef(`TCR_IN_GPR') /* no %save3, r11 is %rcontext_reg */
	__(clr %temp6)
	__endif
	__(pxor %fpzero,%fpzero)	/* fpzero = 0.0`d0' */
        __(stmxcsr rcontext(tcr.foreign_mxcsr))
        __(andb $~mxcsr_all_exceptions,rcontext(tcr.foreign_mxcsr))
        __(ldmxcsr rcontext(tcr.lisp_mxcsr))
	__(movq $TCR_STATE_LISP,rcontext(tcr.valence))
	__(call toplevel_loop)
	__(movq $TCR_STATE_FOREIGN,rcontext(tcr.valence))
	__(emms)
	__(addq $8,%rsp)	/* discard alignment word */
	__ifdef(`WINDOWS')
	__(pop %csave6)
	__(pop %csave5)
	__endif
	__(pop %csave4)
	__(pop %csave3)
	__(pop %csave2)
	__(pop %csave1)
	__(pop %csave0)
        __(ldmxcsr rcontext(tcr.foreign_mxcsr))
	__(movl $nil_value,%eax)
	__(leave)
	__(ret)
Xsubprims_end:           
_endfn

        .data
        .globl C(subprims_start)
        .globl C(subprims_end)
C(subprims_start):      .quad Xsubprims_start
C(subprims_end):        .quad Xsubprims_end
        .text
                                
