Example #1
0
void ik_error(ikptr args){
  fprintf(stderr, "Error: ");
  ik_fprint(stderr, args);
  fprintf(stderr, "\n");
  exit(0);
}
Example #2
0
ikptr_t
ik_exec_code (ikpcb_t * pcb, ikptr_t s_code, ikptr_t s_argcount, ikptr_t s_closure)
/* Execute  Scheme  code  and  all   its  continuations  until  no  more
   continuations are stored in the PCB or a system continuation is found
   in the continuations linked list.

   S_CODE  is  a  tagged  memory pointer  referencing  the  code  object
   implementing S_CLOSURE, if any.

   S_ARGCOUNT  is a  fixnum representing  the negated  number of  Scheme
   arguments.

   S_CLOSURE is a reference to the  closure object to execute; it can be
   the fixnum zero if there is no closure to execute, as when we enter a
   loaded FASL file.

   Return the return value of the last executed continuation. */
{
  /* A fixnum representing the negated number of returned Scheme values.
     It can be zero. */
  ikptr_t		s_retval_count;
  /* Reference to the  continuation object representing the  C or Scheme
     continuation we want to go back to. */
  ikptr_t	s_kont;
  if (0 || DEBUG_EXEC) {
    ik_debug_message_no_newline("%s: enter closure 0x%016lx, code 0x%016lx, annotation: ",
				__func__, (long)s_closure, (long) s_code);
    ik_fprint(stderr, IK_REF(s_code, off_code_annotation));
    fprintf(stderr, "\n");
  }
  /* Enter compiled Scheme code.

     Before and after we assert that  the frame pointer equals the frame
     base; this constraint on the Scheme stack is needed by the assembly
     routine  "ik_asm_enter".  It  is  responsibility of  the caller  of
     "ik_exec_code()" to set the Scheme stack appropriately. */
  {
    assert(pcb->frame_base == pcb->frame_pointer);
    s_retval_count = ik_asm_enter(pcb, IK_CODE_ENTRY_POINT(s_code), s_argcount, s_closure);
    assert(pcb->frame_base == pcb->frame_pointer);
  }
  /* Loop until there are continuations to be reinstated. */
  for (s_kont = pcb->next_k; s_kont; s_kont = pcb->next_k) {
#ifndef NDEBUG
    {
      /* Assert that the situation on the Scheme stack is:
       *
       *        high memory
       *  |                      | <- pcb->frame_pointer = pcb->frame_base
       *  |----------------------|
       *  | ik_underflow_handler | <- pcb->frame_pointer - wordsize
       *  |----------------------|
       *  |    return value 0    |
       *  |----------------------|
       *  |    return value 1    |
       *  |----------------------|
       *  |    return value 2    |
       *  |----------------------|
       *  |                      |
       *        low memory
       *
       * Of course we cannot check for the presence of return values.
       */
      ikptr_t	underflow_handler;
      assert(pcb->frame_base == pcb->frame_pointer);
      underflow_handler = *(ikptr_t *)(pcb->frame_pointer - wordsize);
      assert(IK_UNDERFLOW_HANDLER == underflow_handler);
    }
#endif
    assert(IK_IS_ANY_CONTINUATION(s_kont));
    if (0 || DEBUG_EXEC) {
      ik_debug_message("%s: resuming process continuation s_kont=0x%016lx",
		       __func__, (long)s_kont);
    }
    ikcont_t * kont = IK_CONTINUATION_STRUCT(s_kont);
    /* System continuations are created by the FFI to save the current C
       execution contest just before calling back a Scheme function.  So
       if S_KONT is a system continuation:  we have no Scheme code to go
       back to, we just return to the  caller of this C function.  It is
       responsibility of such caller to  reinstate the continuation to C
       code. */
    if (system_continuation_tag == kont->tag)
      break;
    assert(continuation_tag == kont->tag);
    /* RETURN_ADDRESS is a  raw memory address being the  entry point in
       machine code we have to jump back to. */
    ikptr_t	return_address = IK_REF(kont->top, 0);
    /* FRAMESIZE is stack  frame size of the function we  have to return
       to.  This value was computed at compile time and stored in binary
       code just before the "call" instruction. */
    iksword_t	framesize = IK_CALLTABLE_FRAMESIZE(return_address);
    if (0 || DEBUG_EXEC) {
      ik_debug_message("%s: framesize=%ld kont->size=%ld return_address=0x%016lx",
		       __func__, framesize, kont->size, return_address);
    }
    /* A continuation  object can  never have  the underflow  handler as
       return address  of the  top stack frame;  if it has  it: it  is a
       wrongly  generated   continuation  object.    Wrong  continuation
       generation is  the problem  of issue #35,  so we  react specially
       here by logging the state. */
    if (IK_UNDERFLOW_HANDLER == return_address) {
      ik_exec_code_log_and_abort(pcb, s_kont);
    }
    /* Zero  framesize means  that we  are returning  to a  continuation
       having as  topmost stack frame  a frame  whose size could  not be
       computed at compile  time.  In such cases the  framesize field in
       the call table is set to zero  and the actual stack frame size is
       computed at runtime  and pushed on the stack  frame itself before
       performing a "call" assembly instruction. */
    if (0 == framesize) {
      framesize = IK_REF(kont->top, wordsize);
    }
    /* Perform  some framesize  validations.  If  these happen  it means
       that there is a bug in Vicare. */
    {
      if (framesize <= 0) {
	ik_abort("invalid caller function framesize %ld\n", framesize);
      }
      if (framesize > kont->size) {
	ik_exec_code_log_and_abort(pcb, s_kont);
      }
    }
    if (framesize < kont->size) {
      /* The process continuation  we have to reinstate  references 2 or
	 more  freezed  frames.  Mutate  S_KONT  to  reference only  the
	 topmost  freezed frame  and  create a  new continuation  object
	 referencing  the  rest of  the  freezed  frames.  Register  the
	 "rest" continuation as "next process continuation". */
      ikcont_t *	rest_kont   = (ikcont_t*)ik_unsafe_alloc(pcb, IK_ALIGN(continuation_size));
      ikptr_t	s_rest_kont = (ikptr_t)(((ikuword_t)rest_kont) | continuation_primary_tag);
      rest_kont->tag	= continuation_tag;
      rest_kont->next	= kont->next;
      rest_kont->top	= kont->top  + framesize;
      rest_kont->size	= kont->size - framesize;
      kont->size	= framesize;
      kont->next	= s_rest_kont;
      /* FIXME Is it required to signal dirt for both the fields?  Or it
	 always  happens that  a continuation  object's memory  block is
	 fully in a  single page?  In the original Ikarus  code only the
	 "kont->next" dirt was registered, but debugging of Issue #35 is
	 making me paranoid.  (Marco Maggi; Wed Mar 27, 2013) */
      IK_SIGNAL_DIRT_IN_PAGE_OF_POINTER(pcb, &(kont->size));
      IK_SIGNAL_DIRT_IN_PAGE_OF_POINTER(pcb, &(kont->next));
      { /* Special validations to ease debugging of issue #35. */
	if (0 == kont->size) {
	  ik_debug_message("%s: next continuation with zero size 0x%016lx,\n\
\tframe return address=0x%016lx",
			   __func__, s_kont, IK_REF(kont->top, 0));
	}
	if (0 == rest_kont->size) {
	  ik_debug_message("%s: rest continuation with zero size 0x%016lx,\n\
\ttop frame return address=0x%016lx",
			   __func__, s_rest_kont, IK_REF(rest_kont->top, 0));
	}
      }