DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ T h

⟦6232e024f⟧ TextFile

    Length: 18767 (0x494f)
    Types: TextFile
    Names: »hooks.c«

Derivation

└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
    └─ ⟦this⟧ »EUUGD11/gnu-31mar87/scheme/microcode/hooks.c« 

TextFile

/*          Hey EMACS, this is -*- C -*- code!                 */

/****************************************************************
*                                                               *
*                         Copyright (c) 1985                    *
*               Massachusetts Institute of Technology           *
*                                                               *
* This material was developed by the Scheme project at the      *
* Massachusetts Institute of Technology, Department of          *
* Electrical Engineering and Computer Science.  Permission to   *
* copy this software, to redistribute it, and to use it for any *
* purpose is granted, subject to the following restrictions and *
* understandings.                                               *
*                                                               *
* 1. Any copy made of this software must include this copyright *
* notice in full.                                               *
*                                                               *
* 2. Users of this software agree to make their best efforts (a)*
* to return to the MIT Scheme project any improvements or       *
* extensions that they make, so that these may be included in   *
* future releases; and (b) to inform MIT of noteworthy uses of  *
* this software.                                                *
*                                                               *
* 3.  All materials developed as a consequence of the use of    *
* this software shall duly acknowledge such use, in accordance  *
* with the usual standards of acknowledging credit in academic  *
* research.                                                     *
*                                                               *
* 4. MIT has made no warrantee or representation that the       *
* operation of this software will be error-free, and MIT is     *
* under no obligation to provide any services, by way of        *
* maintenance, update, or otherwise.                            *
*                                                               *
* 5.  In conjunction with products arising from the use of this *
* material, there shall be no use of the name of the            *
* Massachusetts Institute of Technology nor of any adaptation   *
* thereof in any advertising, promotional, or sales literature  *
* without prior written consent from MIT in each case.          *
*                                                               *
****************************************************************/
\f


/* File: HOOKS.C
 *
 * This file contains various hooks and handles which connect the
 * primitives with the main interpreter.
 */

#include "scheme.h"
#include "primitive.h"
\f


/* (APPLY FN LIST-OF-ARGUMENTS)
      Calls the function FN on the arguments specified in the list
      LIST-OF-ARGUMENTS. FN must be a primitive procedure, compound
      procedure, or control point.
*/

Built_In_Primitive(Prim_Apply, 2, "APPLY")
{ Pointer New_Frame, List, *Next_From_Slot, *Next_To_Slot;
  long Number_Of_Args, i;
  /* Since this primitive must pop its own frame off and push a new
   * frame on the stack, it has to be careful.  Its own stack frame is
   * needed if an error or GC is required.  So these checks are done
   * first (at the cost of traversing the argument list twice), then
   * the primitive's frame is popped, and finally the new frame is
   * constructed.
   */
  Primitive_2_Args();
  Number_Of_Args = 0;
  Touch_In_Primitive(Arg2, List);
  Next_To_Slot = Free;
  while (Type_Code(List) == TC_LIST)
  { Number_Of_Args += 1;
    *Next_To_Slot++ = Vector_Ref(List, CONS_CAR);
    Primitive_GC_If_Needed(Next_To_Slot);
    Touch_In_Primitive(Vector_Ref(List, CONS_CDR), List);
  }
  if (List != NIL)
    Primitive_Error(ERR_ARG_2_WRONG_TYPE);
  Pop_Primitive_Frame(2);
  Next_From_Slot = Free;
  Next_To_Slot = Stack_Pointer - Number_Of_Args;
 Will_Push(Number_Of_Args + STACK_ENV_EXTRA_SLOTS + 1);
			/* + 1 for the vector header */
  Stack_Pointer = Next_To_Slot;
  for (i=0; i < Number_Of_Args; i++) *Next_To_Slot++ = *Next_From_Slot++;
  Push(Arg1);		/* The function */
  Push(STACK_FRAME_HEADER+Number_Of_Args);
 Pushed();
  longjmp(*Back_To_Eval, PRIM_APPLY);
}
\f


/* (CATCH PROCEDURE)
      [Primitive number 0x03]
      Creates a control point (copy of the current stack) and passes
      it to PROCEDURE as its only argument.  The inverse operation,
      typically called THROW, is performed by using the control point
      as you would a procedure.  A control point accepts one argument
      which is then returned as the value of the CATCH which created
      the control point.  A control point may be reused as often as
      desired, since the stack is copied when it is made and then
      copied back on every throw.  The user level CATCH is built on
      this primitive but is not the same, since it handles
      dynamic-wind while the primitive does not.
*/
Built_In_Primitive(Prim_Catch, 1, "CALL-WITH-CURRENT-CONTINUATION")
{ Pointer Control_Point;
  long Length;
  fast Pointer *From_Where;
  fast long i, Stack_Cells;
  /* Implementation detail: in addition to making a copy of the stack
     as described above, the actual stack is cleared and a return
     code is placed at the base of the (now clear) stack indicating
     that a return back through here requires restoring the control
     point. The currently enabled interrupts are also saved away here
     and restored on a throw.
     >>> Temporarily (maybe) the act of doing a CATCH will disable any
     >>> return hook that may be in the stack.
  */
  Primitive_1_Arg();
  /* Should be a call to Make_Control_Point, but in-line coded */
  Stack_Cells = (Stack_Top - Stack_Pointer) - 1;
  /* The "- 1" is for the frame that is about to be popped */
  Length = Stack_Cells + REGBLOCK_NDISPLAYS + 2;
  Primitive_GC_If_Needed(Free + Length + 1);
  Pop_Primitive_Frame(1);
  if (Return_Hook_Address != NULL)
  { *Return_Hook_Address = Old_Return_Code;
    Return_Hook_Address = NULL;
  }

/* Prim_Catch continues on the next page */
\f


/* Prim_Catch, continued */

  /* Save Display Registers */
  Control_Point = Make_Pointer(TC_CONTROL_POINT, Free);
  *Free++ = Make_Non_Pointer(TC_MANIFEST_VECTOR, Length);
  *Free++ = Make_Non_Pointer(TC_FIXNUM, IntEnb);
  if (Previous_Restore_History == NULL)
    *Free++ = FIXNUM_0;
  else
  { *Free++ = Make_Non_Pointer(TC_FIXNUM,
                               (Previous_Restore_History-Stack_Pointer));
    Previous_Restore_History[CONTINUATION_RETURN_CODE-
                             (1+CONTINUATION_SIZE)] =
      Make_Non_Pointer(TC_RETURN_CODE, RC_RESTORE_HISTORY);
  }

#ifdef COMPILER
  for(i=0, From_Where = &Registers[REGBLOCK_DISPLAYS];
      i < REGBLOCK_NDISPLAYS; i++) *Free++ = *From_Where++;
#else
  for(i=0; i < REGBLOCK_NDISPLAYS; i++) *Free++ = NIL;
#endif

  for (i=0; i < Stack_Cells; i++) *Free++ = Pop();
  if (Consistency_Check)  
    if (Stack_Pointer != Stack_Top)
      Microcode_Termination(TERM_BAD_STACK);
  Store_Expression(Control_Point);
  Store_Return(RC_RESTORE_CONTROL_POINT);
  Save_Cont();
  Previous_Restore_History = NULL;
/* End of Make_Control_Point */
/* Will_Push(3); -- we just cleared the stack so there MUST be room */
  Push(Control_Point);
  Push(Arg1);	/* Function */
  Push(STACK_FRAME_HEADER+1);
/*  Pushed(); */
  longjmp(*Back_To_Eval, PRIM_APPLY);
}
\f


/* (ENABLE-INTERRUPTS! INTERRUPTS)
      [Primitive number 0x06]
      Changes the enabled interrupt bits to bitwise-or of INTERRUPTS
      and previous value of interrupts.  Returns the previous value.
      See MASK_INTERRUPT_ENABLES for more information on interrupts.
*/
Built_In_Primitive(Prim_Enable_Interrupts, 1, "ENABLE-INTERRUPTS!")
{ Pointer Result;
  Primitive_1_Arg();
  Arg_1_Type(TC_FIXNUM);
  Result = Make_Non_Pointer(TC_FIXNUM, IntEnb);
  IntEnb = Get_Integer(Arg1) | INT_Mask;
  New_Compiler_MemTop();
  return Result;
}

/* (GET_FIXED_OBJECTS_VECTOR)
      [Primitive number 0x7A]
      Returns the current fixed objects vector.  This vector is used
      for communication between the interpreter and the runtime
      system.  See the file UTABCSCM.SCM in the runtime system for the
      names of the slots in the vector.
*/
Built_In_Primitive(Prim_Get_Fixed_Objects_Vector, 0,
		 "GET-FIXED-OBJECTS-VECTOR")
{ Primitive_0_Args();
  if (Valid_Fixed_Obj_Vector())
    return Get_Fixed_Obj_Slot(Me_Myself);
  else return NIL;
}
\f


/* (FORCE DELAYED-OBJECT)
      [Primitive number 0xAF]
      Returns the memoized value of the DELAYED-OBJECT (created by a
      DELAY special form) if it has already been calculated.
      Otherwise, it calculates the value and memoizes it for future
      use.
*/
Built_In_Primitive(Prim_Force, 1, "FORCE")
{ Primitive_1_Arg();
  Arg_1_Type(TC_DELAYED);
  if (Vector_Ref(Arg1, THUNK_SNAPPED) == TRUTH)
    return Vector_Ref(Arg1, THUNK_VALUE);
  Pop_Primitive_Frame(1);
 Will_Push(2);
  Store_Return(RC_SNAP_NEED_THUNK);
  Store_Expression(Arg1);
  Save_Cont();
 Pushed();
  Store_Env(Fast_Vector_Ref(Arg1, THUNK_ENVIRONMENT));
  Store_Expression(Fast_Vector_Ref(Arg1, THUNK_PROCEDURE));
  longjmp(*Back_To_Eval, PRIM_DO_EXPRESSION);
}
\f


/* (EXECUTE_AT_NEW_POINT SPACE BACKWARD CONS)
      [Primitive number 0xE2]
      Create a new state point in the specified state SPACE.  To enter
      the new point you must execute the BACKWARD thunk.  The CONS has
      the forward thunk in its CAR, and the code to execute at that
      point in its CDR.
*/
Built_In_Primitive(Prim_Execute_At_New_Point, 3, "EXECUTE-AT-NEW-POINT")
{ Primitive_3_Args();
  Arg_1_Type(TC_VECTOR);
  if (Vector_Ref(Arg1, STATE_SPACE_TAG) !=
      Get_Fixed_Obj_Slot(State_Space_Tag))
    Primitive_Error(ERR_ARG_1_WRONG_TYPE);
  Arg_3_Type(TC_LIST);
  Primitive_GC_If_Needed(Free+5);
  Free[STATE_POINT_HEADER] = Make_Non_Pointer(TC_MANIFEST_VECTOR, 4);
  Free[STATE_POINT_TAG] = Get_Fixed_Obj_Slot(State_Point_Tag);
  Free[STATE_POINT_FORWARD_THUNK] = Vector_Ref(Arg3, CONS_CAR);
  Free[STATE_POINT_BACKWARD_THUNK] = Arg2;
  Free[STATE_POINT_NEARER_POINT] =
    Vector_Ref(Arg1, STATE_SPACE_NEAREST_POINT);
  Free += 5;
  Pop_Primitive_Frame(3);
 Will_Push(2*CONTINUATION_SIZE + (STACK_ENV_EXTRA_SLOTS+1));
  /* Push a continuation to go back to the current state after the
     body is evaluated */
  Store_Expression(Vector_Ref(Arg1, STATE_SPACE_NEAREST_POINT));
  Store_Return(RC_RESTORE_TO_STATE_POINT);
  Save_Cont();
  /* Push a stack frame which will call the body after we have moved
     into the new state point */
  Push(Vector_Ref(Arg3, CONS_CDR));
  Push(STACK_FRAME_HEADER);
  /* Push the continuation to go with the stack frame */
  Store_Expression(NIL);
  Store_Return(RC_INTERNAL_APPLY);
  Save_Cont();
 Pushed();
  /* And set up to go off to the requested state point */
  Store_Expression(Make_Pointer(TC_VECTOR, Free-5));
  longjmp(*Back_To_Eval, PRIM_TRANSLATE);
}
\f


/* (MASK_INTERRUPT_ENABLES MASK)
      [Primitive number 0xC9]
      ANDs the internal interrupt register with the specified value
      and returns the previous value.  The precise definition of the
      interrupt bits is available only by reference to the interpreter
      implementation.
*/
Built_In_Primitive(Prim_Mask_Interrupt_Enables, 1, "MASK-INTERRUPT-ENABLES!")
{ Pointer Result;
  /* The bits are defined in CONST.H */
  Primitive_1_Arg();
  Arg_1_Type(TC_FIXNUM);
  Result = FIXNUM_0+IntEnb;
  IntEnb &= Get_Integer(Arg1);
  New_Compiler_MemTop();
  return Result;
}

/* (MAKE_STATE_SPACE)
      [Primitive number 0xE1]
      Creates a new state space for the dynamic winder.  Used only
      internally to the dynamic wind operations.
*/
Built_In_Primitive(Prim_Make_State_Space, 0, "MAKE-STATE-SPACE")
{ Primitive_0_Args();
  Primitive_GC_If_Needed(Free+8);
  Free[STATE_POINT_HEADER] = Make_Non_Pointer(TC_MANIFEST_VECTOR, 4);
  Free[STATE_POINT_TAG] = Get_Fixed_Obj_Slot(State_Point_Tag);
  Free[STATE_POINT_FORWARD_THUNK] = NIL;
  Free[STATE_POINT_BACKWARD_THUNK] = NIL;
  Free[STATE_POINT_NEARER_POINT] = Make_Pointer(TC_VECTOR, Free+5);
  Free += 5;
  Free[STATE_SPACE_HEADER] = Make_Non_Pointer(TC_MANIFEST_VECTOR, 2);
  Free[STATE_SPACE_TAG] = Get_Fixed_Obj_Slot(State_Space_Tag);
  Free[STATE_SPACE_NEAREST_POINT] = Make_Pointer(TC_VECTOR, Free-5);
  Free += 3;
  return Make_Pointer(TC_VECTOR, Free-3);
}
\f


/* (SCODE_EVAL SCODE-EXPRESSION ENVIRONMENT)
      [Primitive number 0x04]
      Evaluate the piece of SCode (SCODE-EXPRESSION) in the
      ENVIRONMENT. This is like Eval, except that it expects its input
      to be syntaxed into SCode rather than just a list.
*/
Built_In_Primitive(Prim_Scode_Eval, 2, "SCODE-EVAL")
{ Primitive_2_Args();
  if (Type_Code(Arg2) != GLOBAL_ENV) Arg_2_Type(TC_ENVIRONMENT);
  Pop_Primitive_Frame(2);
  Store_Env(Arg2);
  Store_Expression(Arg1);
  longjmp(*Back_To_Eval, PRIM_DO_EXPRESSION);
}

/* (SET_INTERRUPT_ENABLES NEW-INT-ENABLES)
      [Primitive number 0x06]
      Changes the enabled interrupt bits to NEW-INT-ENABLES and
      returns the previous value.  See MASK_INTERRUPT_ENABLES for more
      information on interrupts.
*/
Built_In_Primitive(Prim_Set_Interrupt_Enables, 1, "SET-INTERRUPT-ENABLES!")
{ Pointer Result;
  Primitive_1_Arg();
  Arg_1_Type(TC_FIXNUM);
  Result = FIXNUM_0+IntEnb;
  IntEnb = Get_Integer(Arg1) & INT_Mask;
  New_Compiler_MemTop();
  return Result;
}

/* Called with a mask and a thunk */
Built_In_Primitive(Prim_With_Interrupt_Mask, 2, "WITH-INTERRUPT-MASK")
{ Pointer New_Mask;
  Primitive_2_Args();
  Arg_1_Type(TC_FIXNUM);
  Pop_Primitive_Frame(2);
 Will_Push(CONTINUATION_SIZE + (STACK_ENV_EXTRA_SLOTS+2));
  Store_Return(RC_RESTORE_INT_MASK);
  Store_Expression(FIXNUM_0+IntEnb);
  Save_Cont();
  Push(FIXNUM_0 + IntEnb);	/* Current interrupt mask */
  Push(Arg2);			/* Function to call */
  Push(STACK_FRAME_HEADER+1);
 Pushed();
  IntEnb = INT_Mask & Get_Integer(Arg1);
  longjmp(*Back_To_Eval, PRIM_APPLY);
}
\f


/* (SET_CURRENT_HISTORY TRIPLE)
      [Primitive number 0x2F]
      Begins recording history into TRIPLE.  The history structure is
      somewhat complex and should be understood before trying to use
      this primitive.  It is used in the Read-Eval-Print loop in the
      Scheme runtime system.
*/
Built_In_Primitive(Prim_Set_Current_History, 1, "SET-CURRENT-HISTORY")
{ Pointer Result;
  Primitive_1_Arg();
  Arg_1_Type(TC_HUNK3);
  Result = *History;
#ifdef COMPILE_HISTORY
  History = Get_Pointer(Arg1);
#else
  History = Get_Pointer(Get_Fixed_Obj_Slot(Dummy_History));
#endif
  return Result;
}

/* (SET_FIXED_OBJECTS_VECTOR VECTOR)
      [Primitive number 0x7B]
      Replace the current fixed objects vector with VECTOR.  The fixed
      objects vector is used for communication between the Scheme
      runtime system and the interpreter.  The file UTABCSCM.SCM
      contains the names of the slots in the vector.  Returns (bad
      style to depend on this) the previous fixed objects vector.
*/
Built_In_Primitive(Prim_Set_Fixed_Objects_Vector, 1,
		   "SET-FIXED-OBJECTS-VECTOR!")
{ Pointer Result;
  Primitive_1_Arg();
  Arg_1_Type(TC_VECTOR);

  if (Valid_Fixed_Obj_Vector())
    Result = Get_Fixed_Obj_Slot(Me_Myself);
  else Result = NIL;
  Set_Fixed_Obj_Hook(Arg1);
  Set_Fixed_Obj_Slot(Me_Myself, Arg1);
  return Result;
}
\f


/* (WITH_HISTORY_DISABLED THUNK)
      [Primitive number 0x9C]
      THUNK must be a procedure or primitive procedure which takes no
      arguments.  Turns off the history collection mechanism.  Removes
      the most recent reduction (the expression which called the
      primitive) from the current history and saves the history.  Then
      it calls the THUNK.  When (if) the THUNK returns, the history is
      restored back and collection resumes.  The net result is that the
      THUNK is called with history collection turned off.
*/
Built_In_Primitive(Prim_With_History_Disabled, 1, "WITH-HISTORY-DISABLED")
{ Pointer *First_Rib, *Rib, *Second_Rib;
  Primitive_1_Arg();
  /* Remove one reduction from the history before saving it */
  First_Rib = Get_Pointer(History[HIST_RIB]);
  Second_Rib = Get_Pointer(First_Rib[RIB_NEXT_REDUCTION]);
  if (!((Dangerous(First_Rib[RIB_MARK])) ||
       (First_Rib == Second_Rib)))
  { Set_Danger_Bit(Second_Rib[RIB_MARK]);
    for (Rib = First_Rib;
         Get_Pointer(Rib[RIB_NEXT_REDUCTION]) != First_Rib;
         Rib = Get_Pointer(Rib[RIB_NEXT_REDUCTION]))
    { /* Look for one that points to the first rib */ }
    History[HIST_RIB] = Make_Pointer(Type_Code(History[HIST_RIB]), Rib);
  }
  Pop_Primitive_Frame(1);
  Stop_History();
 Will_Push(STACK_ENV_EXTRA_SLOTS+1);
  Push(Arg1);
  Push(STACK_FRAME_HEADER);
 Pushed();
  longjmp(*Back_To_Eval, PRIM_APPLY);
}
\f


/* (WITHIN_CONTROL_POINT CONTROL-POINT THUNK)
      [Primitive number 0xBF]
      THUNK must be a procedure or primitive procedure which takes no
      arguments.  Restores the state of the machine from the control
      point, and then calls the THUNK in this new state.
*/
Built_In_Primitive(Prim_Within_Control_Point, 2, "WITHIN-CONTROL-POINT")
{ Primitive_2_Args();
  Arg_1_Type(TC_CONTROL_POINT);
  Throw(Arg1);
 Will_Push(STACK_ENV_EXTRA_SLOTS+1);
  Push(Arg2);
  Push(STACK_FRAME_HEADER);
 Pushed();
  longjmp(*Back_To_Eval, PRIM_APPLY);
}
/* (WITH_THREADED_STACK PROCEDURE THUNK)
      [Primitive number 0xBE]
      THUNK must be a procedure or primitive procedure which takes no
      arguments.  PROCEDURE must expect one argument.  Basically this
      primitive does (PROCEDURE (THUNK)) ... it calls the THUNK and
      passes the result on as an argument to PROCEDURE.  However, it
      leaves a "well-known continuation code" on the stack for use by
      the continuation parser in the Scheme runtime system.
*/
Built_In_Primitive(Prim_With_Threaded_Stack, 2, "WITH-THREADED-STACK")
{ Primitive_2_Args();
  Pop_Primitive_Frame(2);
 Will_Push(CONTINUATION_SIZE + (STACK_ENV_EXTRA_SLOTS+1));
  Store_Expression(Arg1);	/* Save procedure to call later */
  Store_Return(RC_INVOKE_STACK_THREAD);
  Save_Cont();
  Push(Arg2);	/* Function to call now */
  Push(STACK_FRAME_HEADER);
 Pushed();
  longjmp(*Back_To_Eval, PRIM_APPLY);
}
\f


/* (TRANSLATE_TO_POINT STATE_POINT)
      [Primitive number 0xE3]
      Move to a new dynamic wind environment by performing all of the
      necessary enter and exit forms to get form the current state to
      the new state as specified by STATE_POINT.
*/
Built_In_Primitive(Prim_Translate_To_Point, 1, "TRANSLATE-TO-POINT")
{ Primitive_1_Arg();
  Arg_1_Type(TC_VECTOR);
  if (Vector_Ref(Arg1, STATE_POINT_TAG) != Get_Fixed_Obj_Slot(State_Point_Tag))
    Primitive_Error(ERR_ARG_1_WRONG_TYPE);
  Pop_Primitive_Frame(1);
  Store_Expression(Arg1);
  longjmp(*Back_To_Eval, PRIM_TRANSLATE);
}