/*
-- This file is  free  software, which  comes  along  with  SmartEiffel. This
-- software  is  distributed  in the hope that it will be useful, but WITHOUT
-- ANY  WARRANTY;  without  even  the  implied warranty of MERCHANTABILITY or
-- FITNESS  FOR A PARTICULAR PURPOSE. You can modify it as you want, provided
-- this header is kept unaltered, and a notification of the changes is added.
-- You  are  allowed  to  redistribute  it and sell it, alone or as a part of
-- another product.
--       Copyright (C) 1994-2002 LORIA - INRIA - U.H.P. Nancy 1 - FRANCE
--          Dominique COLNET and Suzanne COLLIN - SmartEiffel@loria.fr
--                       http://www.loria.fr/SmartEiffel
--
*/

/*
   GNU Eiffel's VP (Virtual Processor) garbage collector for Elate.
   (c) 2000 Rudi Chiarito <rudi@amiga.com>

   Thanks to Andy Stout and Kevin Croombs at Tao Group for their
   precious help!

   ChangeLog:
   - 2000-06-12 Rudi Chiarito <rudi@amiga.com>
     * Version 1.0
   - 2001-01-01 Joseph Kiniry <kiniry@acm.org>
     * Integrated with new SE 0.75b
   - 2001-08-10 Rudi Chiarito <rudi@amiga.com>
     * Inlined and optimised range marking
     * Added some more comments
     * Added conditional breakpoint in mark_stack_and_registers
   - 2002-09-21 Rudi Chiarito <rudi@amiga.com>
     * Removed redundant 'ret'

*/

__inline__ void mark_stack_and_registers(void)
{

  void *pointer_to_gc_mark = &gc_mark;

  __asm__ __volatile__
  (
    /*
      WARNING: funky code ahead!
      \t and \n are needed to make the final output easier to read
      while debugging. Hopefully you'll never have to bother with all
      of this.

      Registers:
        p0  pointer to stack block
        p1  pointer to gc_mark()
        p2  scratch pointer
        i0  length of current stack block
        i1  scratch register
        
    */

#ifdef __ELATE_SE_DEBUG_GC
   "\tqcall sys/cii/breakpt,(-:-)\n"
#endif

   "\tsync\n"                          /* spill all the registers */
   "\tsyncreg\n"                       /* to the stack */

   "\tcpy.p %0,p1\n"                   /* pointer to gc_mark() */

   /* pointer to the current stack block */

   "\tcpy.p [gp+PROC_STACK],p0\n"

   /* point to last location in the block, before the descriptor */

   "\tcpy.p p0 + ([(p0 - STK_SIZE) + STK_LENGTH] - STK_SIZE - 4),p2\n"

   /* mark the contents of the current stack block */

   "\twhile p2>=sp\n"
      "\t\tgos p1,(p2 : -)\n"
      "\t\tsub.p 4,p2\n"
   "\tendwhile\n"

   /* now scan other blocks (if any) */

   "\tloop\n"
      "\t\tcpy.p [p0 - STK_SIZE + STK_LINK],p0\n" /* get next block */
      "\t\tbreakif p0=NULL\n"

      /* point to last location in the block, before the descriptor */

      "\t\tcpy.p p0 + ([(p0 - STK_SIZE) + STK_LENGTH] - STK_SIZE - 4),p2\n"

      /* mark this block */
      "\t\twhile p2>=p0\n"

         "\t\t\tgos p1,(p2 : -)\n"
         "\t\t\tsub.p 4,p2\n"
      "\t\tendwhile\n"
   "\tendloop\n"

   : /* no output */
   : "p" (pointer_to_gc_mark)
   : "p0", "p1", "p2", "i0" 
   );
}

