home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
mitsch75.zip
/
scheme-7_5_17-src.zip
/
scheme-7.5.17
/
src
/
microcode
/
stack.h
< prev
next >
Wrap
C/C++ Source or Header
|
1999-01-02
|
12KB
|
360 lines
/* -*-C-*-
$Id: stack.h,v 9.38 1999/01/02 06:11:34 cph Exp $
Copyright (c) 1987-1999 Massachusetts Institute of Technology
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.
This program 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* This file contains macros for manipulating stacks and stacklets. */
#ifndef STACK_RESET
# define STACK_RESET() do {} while (0)
#endif /* STACK_RESET */
#ifdef USE_STACKLETS
/*
Stack is made up of linked small parts, each in the heap
*/
#define INITIALIZE_STACK() do \
{ \
if (GC_Check(Default_Stacklet_Size)) \
Microcode_Termination(TERM_STACK_ALLOCATION_FAILED); \
SET_STACK_GUARD (Free + STACKLET_HEADER_SIZE); \
*Free = \
(MAKE_OBJECT (TC_MANIFEST_VECTOR, (Default_Stacklet_Size - 1))); \
Free += Default_Stacklet_Size; \
Stack_Pointer = Free; \
Free_Stacklets = NULL; \
Prev_Restore_History_Stacklet = NULL; \
Prev_Restore_History_Offset = 0; \
} while (0)
/* This is a lie, but OK in the context in which it is used. */
#define STACK_OVERFLOWED_P() FALSE
#define Internal_Will_Push(N) \
{ \
if ((Stack_Pointer - (N)) < Stack_Guard) \
{ \
Export_Registers(); \
Allocate_New_Stacklet((N)); \
Import_Registers(); \
} \
}
/* No space required independent of the heap for the stacklets */
#define STACK_ALLOCATION_SIZE(Stack_Blocks) 0
#define Current_Stacklet (Stack_Guard - STACKLET_HEADER_SIZE)
/* Make the unused portion of the old stacklet invisible to garbage
* collection. This also allows the stack pointer to be reconstructed.
*/
#define Internal_Terminate_Old_Stacklet() \
{ \
Current_Stacklet[STACKLET_REUSE_FLAG] = SHARP_T; \
Current_Stacklet[STACKLET_UNUSED_LENGTH] = \
MAKE_OBJECT (TC_MANIFEST_NM_VECTOR, (Stack_Pointer - Stack_Guard)); \
}
#ifdef ENABLE_DEBUGGING_TOOLS
#define Terminate_Old_Stacklet() \
{ \
if (Stack_Pointer < Stack_Guard) \
{ \
outf_fatal ("\nStack_Pointer: 0x%lx, Guard: 0x%lx\n", \
((long) Stack_Pointer), ((long) Stack_Guard)); \
Microcode_Termination(TERM_EXIT); \
} \
Internal_Terminate_Old_Stacklet(); \
}
#else /* not ENABLE_DEBUGGING_TOOLS */
#define Terminate_Old_Stacklet() Internal_Terminate_Old_Stacklet()
#endif /* ENABLE_DEBUGGING_TOOLS */
/* Used by garbage collector to detect the end of constant space */
#define CONSTANT_AREA_START() Constant_Space
#define Get_Current_Stacklet() \
(MAKE_POINTER_OBJECT (TC_CONTROL_POINT, Current_Stacklet))
#define Previous_Stack_Pointer(Where) \
(MEMORY_LOC \
(Where, \
(STACKLET_HEADER_SIZE + \
(OBJECT_DATUM (MEMORY_REF (Where, STACKLET_UNUSED_LENGTH))))))
#define Set_Current_Stacklet(Where) \
{ \
SCHEME_OBJECT Our_Where; \
\
Our_Where = (Where); \
SET_STACK_GUARD (MEMORY_LOC (Our_Where, STACKLET_HEADER_SIZE)); \
Stack_Pointer = Previous_Stack_Pointer(Our_Where); \
}
#define STACKLET_SLACK (STACKLET_HEADER_SIZE + CONTINUATION_SIZE)
#define Default_Stacklet_Size (Stack_Size + STACKLET_SLACK)
#define New_Stacklet_Size(N) \
(STACKLET_SLACK + Stack_Size * (((N) + Stack_Size - 1) / Stack_Size))
#define Get_End_Of_Stacklet() \
(&(Current_Stacklet[1 + OBJECT_DATUM (Current_Stacklet[STACKLET_LENGTH])]))
#define Apply_Stacklet_Backout() \
Will_Push((2 * CONTINUATION_SIZE) + (STACK_ENV_EXTRA_SLOTS + 2)); \
Store_Expression(SHARP_F); \
Store_Return(RC_END_OF_COMPUTATION); \
Save_Cont(); \
STACK_PUSH (Val); \
STACK_PUSH (Previous_Stacklet); \
STACK_PUSH (STACK_FRAME_HEADER + 1); \
Store_Return(RC_INTERNAL_APPLY); \
Save_Cont(); \
Pushed()
#define Join_Stacklet_Backout() Apply_Stacklet_Backout()
/* This depends on the fact that Within_Control_Point is going to
* push an apply frame immediately after Return_To_Previous_Stacklet
* "returns". This apply will cause the GC, then the 2nd argument to
* Within_Control_Point will be invoked, and finally the control point
* will be entered.
*/
#define Within_Stacklet_Backout() \
{ \
SCHEME_OBJECT Old_Expression; \
\
Old_Expression = Fetch_Expression(); \
Store_Expression(Previous_Stacklet); \
Store_Return(RC_JOIN_STACKLETS); \
Save_Cont(); \
Store_Expression(Old_Expression); \
}
/* Our_Throw is used in chaining from one stacklet to another. In
* order to improve efficiency, the entire stack is copied neither on
* catch or throw, but is instead copied one stacklet at a time as
* needed. The need to copy a stacklet is signified by the object in
* the STACKLET_REUSE_FLAG of a stacklet. If this object is #F, the
* stacklet is copied when it is "returned into", and the word is set
* to #F in the stacklet into which the copied one will return. When a
* stacklet is returned from, it is no longer needed for anything so it
* can be deallocated. A free list of deallocate stacklets is kept in
* order to improve the efficiencty of their use.
*/
#define Our_Throw(From_Pop_Return, Stacklet) \
{ \
SCHEME_OBJECT Previous_Stacklet; \
SCHEME_OBJECT *Stacklet_Top; \
\
Previous_Stacklet = (Stacklet); \
Stacklet_Top = Current_Stacklet; \
Stacklet_Top[STACKLET_FREE_LIST_LINK] = \
((SCHEME_OBJECT) Free_Stacklets); \
Free_Stacklets = Stacklet_Top; \
if (!(From_Pop_Return)) \
{ \
Prev_Restore_History_Stacklet = NULL; \
Prev_Restore_History_Offset = 0; \
} \
if ((MEMORY_REF (Previous_Stacklet, STACKLET_REUSE_FLAG)) == SHARP_F) \
{ \
/* We need to copy the stacklet into which we are \
returning. \
*/ \
\
if (GC_Check(VECTOR_LENGTH (Previous_Stacklet) + 1)) \
{ \
/* We don't have enough space to copy the stacklet. */ \
\
Free_Stacklets = \
((SCHEME_OBJECT *) Free_Stacklets[STACKLET_FREE_LIST_LINK]); \
Stack_Pointer = Get_End_Of_Stacklet(); \
Prev_Restore_History_Stacklet = NULL; \
Prev_Restore_History_Offset = 0
/* Backout code inserted here by macro user */
#define Our_Throw_Part_2() \
Request_GC(VECTOR_LENGTH (Previous_Stacklet) + 1); \
} \
else \
{ \
/* There is space available to copy the stacklet. */ \
\
long Unused_Length; \
fast Used_Length; \
fast SCHEME_OBJECT *Old_Stacklet_Top, *temp; \
SCHEME_OBJECT *First_Continuation; \
\
Old_Stacklet_Top = OBJECT_ADDRESS (Previous_Stacklet); \
First_Continuation = \
MEMORY_LOC (Previous_Stacklet, \
((1 + VECTOR_LENGTH (Previous_Stacklet)) - \
CONTINUATION_SIZE)); \
if (Old_Stacklet_Top == Prev_Restore_History_Stacklet) \
Prev_Restore_History_Stacklet = NULL; \
if (First_Continuation[CONTINUATION_RETURN_CODE] == \
MAKE_OBJECT (TC_RETURN_CODE, RC_JOIN_STACKLETS)) \
{ \
SCHEME_OBJECT Older_Stacklet; \
\
Older_Stacklet = First_Continuation[CONTINUATION_EXPRESSION]; \
MEMORY_SET (Older_Stacklet, STACKLET_REUSE_FLAG, SHARP_F); \
} \
temp = Free; \
SET_STACK_GUARD (& (temp[STACKLET_HEADER_SIZE])); \
temp[STACKLET_LENGTH] = Old_Stacklet_Top[STACKLET_LENGTH]; \
Unused_Length = \
OBJECT_DATUM (Old_Stacklet_Top[STACKLET_UNUSED_LENGTH]) + \
STACKLET_HEADER_SIZE; \
temp += Unused_Length; \
Stack_Pointer = temp; \
Used_Length = \
(OBJECT_DATUM (Old_Stacklet_Top[STACKLET_LENGTH]) - \
Unused_Length) + 1; \
Old_Stacklet_Top += Unused_Length; \
while (--Used_Length >= 0) \
*temp++ = *Old_Stacklet_Top++; \
Free = temp; \
} \
} \
else \
{ \
/* No need to copy the stacklet we are going into */ \
\
if (OBJECT_ADDRESS (Previous_Stacklet)== \
Prev_Restore_History_Stacklet) \
Prev_Restore_History_Stacklet = NULL; \
Set_Current_Stacklet(Previous_Stacklet); \
} \
}
#else /* not USE_STACKLETS */
/*
Full size stack in a statically allocated area
*/
#define Stack_Check(P) do \
{ \
if ((P) <= Stack_Guard) \
{ \
extern void EXFUN (stack_death, (CONST char *)); \
if (STACK_OVERFLOWED_P ()) \
stack_death ("Stack_Check"); \
REQUEST_INTERRUPT (INT_Stack_Overflow); \
} \
} while (0)
#define Internal_Will_Push(N) Stack_Check(Stack_Pointer - (N))
#define Terminate_Old_Stacklet()
#define Get_Current_Stacklet() SHARP_F
#define Set_Current_Stacklet(Where) {}
#define Previous_Stack_Pointer(Where) \
(MEMORY_LOC \
(Where, \
(STACKLET_HEADER_SIZE + \
(OBJECT_DATUM (MEMORY_REF (Where, STACKLET_UNUSED_LENGTH))))))
/* Never allocate more space */
#define New_Stacklet_Size(N) 0
#define Get_End_Of_Stacklet() Stack_Top
/* Not needed in this version */
#define Join_Stacklet_Backout()
#define Apply_Stacklet_Backout()
#define Within_Stacklet_Backout()
/* This piece of code KNOWS which way the stack grows.
The assumption is that successive pushes modify decreasing addresses.
*/
/* Clear the stack and replace it with a copy of the contents of the
control point. Also disables the history collection mechanism,
since the saved history would be incorrect on the new stack. */
#define Our_Throw(From_Pop_Return, P) do \
{ \
SCHEME_OBJECT Control_Point; \
fast SCHEME_OBJECT *To_Where, *From_Where; \
fast long len, valid, invalid; \
\
Control_Point = (P); \
if ((Consistency_Check) \
&& (OBJECT_TYPE (Control_Point) != TC_CONTROL_POINT)) \
Microcode_Termination (TERM_BAD_STACK); \
len = VECTOR_LENGTH (Control_Point); \
invalid = ((OBJECT_DATUM (MEMORY_REF (Control_Point, \
STACKLET_UNUSED_LENGTH))) + \
STACKLET_HEADER_SIZE); \
valid = ((len + 1) - invalid); \
CLEAR_INTERRUPT(INT_Stack_Overflow); \
To_Where = (Stack_Top - valid); \
From_Where = MEMORY_LOC (Control_Point, invalid); \
Stack_Check (To_Where); \
Stack_Pointer = To_Where; \
while (--valid >= 0) \
*To_Where++ = *From_Where++; \
if (Consistency_Check) \
{ \
if ((To_Where != Stack_Top) || \
(From_Where != \
MEMORY_LOC (Control_Point, (1 + len)))) \
Microcode_Termination (TERM_BAD_STACK); \
} \
STACK_RESET (); \
if (!(From_Pop_Return)) \
{ \
Prev_Restore_History_Stacklet = NULL; \
Prev_Restore_History_Offset = 0; \
if ((!Valid_Fixed_Obj_Vector ()) || \
(Get_Fixed_Obj_Slot (Dummy_History) == SHARP_F)) \
History = Make_Dummy_History (); \
else \
History = OBJECT_ADDRESS (Get_Fixed_Obj_Slot (Dummy_History)); \
} \
else if (Prev_Restore_History_Stacklet == \
OBJECT_ADDRESS (Control_Point)) \
Prev_Restore_History_Stacklet = NULL; \
} while (0)
#define Our_Throw_Part_2()
#endif /* USE_STACKLETS */