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
/
utils.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-03-08
|
34KB
|
1,169 lines
/* -*-C-*-
$Id: utils.c,v 9.78 2001/03/08 18:24:30 cph Exp $
Copyright (c) 1987-2001 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 utilities for interrupts, errors, etc. */
#include "scheme.h"
#include "prims.h"
#include "winder.h"
#include "history.h"
#include "cmpint.h"
#include "syscall.h"
#ifdef __OS2__
extern void OS2_handle_attention_interrupt (void);
#endif
/* Helper procedures for Setup_Interrupt, which follows. */
static long
DEFUN (compute_interrupt_number, (masked_interrupts),
long masked_interrupts)
{
long interrupt_number = 0;
long bit_mask = 1;
while ((interrupt_number <= MAX_INTERRUPT_NUMBER)
&& ((masked_interrupts & bit_mask) == 0))
{
interrupt_number += 1;
bit_mask <<= 1;
}
return (interrupt_number);
}
/* This default is solely for compatibility with the previous behavior
of the microcode. It is not a good default and should be
overridden by the runtime system. */
#define DEFAULT_INTERRUPT_HANDLER_MASK(interrupt_number) \
((1 << (interrupt_number)) - 1)
static long
DEFUN (compute_interrupt_handler_mask, (interrupt_masks, interrupt_number),
SCHEME_OBJECT interrupt_masks AND
long interrupt_number)
{
if ((VECTOR_P (interrupt_masks))
&& (interrupt_number <= ((long) (VECTOR_LENGTH (interrupt_masks)))))
{
SCHEME_OBJECT mask =
(VECTOR_REF (interrupt_masks, interrupt_number));
if ((INTEGER_P (mask)) && (integer_to_long_p (mask)))
/* Guarantee that the given interrupt is disabled. */
return ((integer_to_long (mask)) &~ (1 << interrupt_number));
}
return
((interrupt_number <= MAX_INTERRUPT_NUMBER)
? (DEFAULT_INTERRUPT_HANDLER_MASK (interrupt_number))
: (FETCH_INTERRUPT_MASK ()));
}
static void
DEFUN (terminate_no_interrupt_handler, (masked_interrupts),
long masked_interrupts)
{
outf_fatal("\nInterrupts = 0x%08lx, Mask = 0x%08lx, Masked = 0x%08lx\n",
(FETCH_INTERRUPT_CODE ()),
(FETCH_INTERRUPT_MASK ()),
masked_interrupts);
Microcode_Termination (TERM_NO_INTERRUPT_HANDLER);
}
SCHEME_OBJECT
DEFUN_VOID (initialize_interrupt_handler_vector)
{
return (make_vector ((MAX_INTERRUPT_NUMBER + 2), SHARP_F, false));
}
SCHEME_OBJECT
DEFUN_VOID (initialize_interrupt_mask_vector)
{
SCHEME_OBJECT result =
(make_vector ((MAX_INTERRUPT_NUMBER + 2), SHARP_F, false));
long interrupt_number;
for (interrupt_number = 0;
(interrupt_number <= MAX_INTERRUPT_NUMBER);
interrupt_number += 1)
VECTOR_SET
(result, interrupt_number,
(long_to_integer (DEFAULT_INTERRUPT_HANDLER_MASK (interrupt_number))));
return (result);
}
/* Setup_Interrupt is called from the Interrupt macro to do all of the
setup for calling the user's interrupt routines. */
void
DEFUN (Setup_Interrupt, (masked_interrupts), long masked_interrupts)
{
SCHEME_OBJECT interrupt_handlers = SHARP_F;
SCHEME_OBJECT interrupt_masks = SHARP_F;
long interrupt_number = (compute_interrupt_number (masked_interrupts));
long interrupt_mask;
SCHEME_OBJECT interrupt_handler;
#ifdef __OS2__
if ((1 << interrupt_number) == INT_Global_1)
{
OS2_handle_attention_interrupt ();
abort_to_interpreter (PRIM_POP_RETURN);
}
#endif /* __OS2__ */
if (! (Valid_Fixed_Obj_Vector ()))
{
outf_fatal ("\nInvalid fixed-objects vector.");
terminate_no_interrupt_handler (masked_interrupts);
}
interrupt_handlers = (Get_Fixed_Obj_Slot (System_Interrupt_Vector));
interrupt_masks = (Get_Fixed_Obj_Slot (FIXOBJ_INTERRUPT_MASK_VECTOR));
if (! (VECTOR_P (interrupt_handlers)))
{
outf_fatal ("\nInvalid handlers vector (0x%lx).", interrupt_handlers);
terminate_no_interrupt_handler (masked_interrupts);
}
if (interrupt_number >= ((long) (VECTOR_LENGTH (interrupt_handlers))))
{
outf_fatal("\nInterrupt out of range: %ld (vector length = %ld).",
interrupt_number,
(VECTOR_LENGTH (interrupt_handlers)));
terminate_no_interrupt_handler (masked_interrupts);
}
interrupt_mask =
(compute_interrupt_handler_mask (interrupt_masks, interrupt_number));
Global_Interrupt_Hook ();
interrupt_handler = (VECTOR_REF (interrupt_handlers, interrupt_number));
#if 0
/* This label may be used in Global_Interrupt_Hook: */
passed_checks:
#endif
Stop_History ();
preserve_interrupt_mask ();
Will_Push (STACK_ENV_EXTRA_SLOTS + 3);
/* There used to be some code here for gc checks, but that is done
uniformly now by RC_NORMAL_GC_DONE. */
/* Now make an environment frame for use in calling the
user supplied interrupt routine. It will be given two arguments:
the UNmasked interrupt requests, and the currently enabled
interrupts. */
STACK_PUSH (LONG_TO_FIXNUM (FETCH_INTERRUPT_MASK ()));
STACK_PUSH (LONG_TO_FIXNUM (FETCH_INTERRUPT_CODE ()));
STACK_PUSH (interrupt_handler);
STACK_PUSH (STACK_FRAME_HEADER + 2);
Pushed ();
/* Turn off interrupts: */
SET_INTERRUPT_MASK (interrupt_mask);
}
/* Error processing utilities */
void
DEFUN (err_print, (error_code, where), long error_code AND outf_channel where)
{
extern char * Error_Names [];
if (error_code > MAX_ERROR)
outf (where, "Unknown error code 0x%lx.\n", error_code);
else
outf (where, "Error code 0x%lx (%s).\n",
error_code,
(Error_Names [error_code]));
return;
}
extern long death_blow;
long death_blow;
void
DEFUN (error_death, (code, message), long code AND char * message)
{
death_blow = code;
outf_fatal ("\nMicrocode Error: %s.\n", message);
err_print (code, fatal_output);
outf_error ("\n**** Stack Trace ****\n\n");
Back_Trace (error_output);
termination_no_error_handler ();
/*NOTREACHED*/
}
void
DEFUN_VOID (Stack_Death)
{
outf_fatal("\nWill_Push vs. Pushed inconsistency.\n");
Microcode_Termination (TERM_BAD_STACK);
/*NOTREACHED*/
}
void
DEFUN_VOID (preserve_interrupt_mask)
{
Will_Push (CONTINUATION_SIZE);
Store_Return (RC_RESTORE_INT_MASK);
Store_Expression (LONG_TO_FIXNUM (FETCH_INTERRUPT_MASK ()));
Save_Cont ();
Pushed ();
return;
}
/* back_out_of_primitive sets the registers up so that the backout
mechanism in interpret.c will cause the primitive to be
restarted if the error/interrupt is proceeded. */
void
DEFUN_VOID (back_out_of_primitive_internal)
{
long nargs;
SCHEME_OBJECT primitive;
/* Setup a continuation to return to compiled code if the primitive is
restarted and completes successfully. */
primitive = (Regs [REGBLOCK_PRIMITIVE]);
if (! (PRIMITIVE_P (primitive)))
{
outf_fatal(
"\nback_out_of_primitive backing out when not in primitive!\n");
Microcode_Termination (TERM_BAD_BACK_OUT);
}
nargs = (PRIMITIVE_N_ARGUMENTS (primitive));
if (COMPILED_CODE_ADDRESS_P (STACK_REF (nargs)))
compiler_apply_procedure (nargs);
STACK_PUSH (primitive);
STACK_PUSH (STACK_FRAME_HEADER + nargs);
Store_Env (MAKE_OBJECT (GLOBAL_ENV, END_OF_CHAIN));
Val = SHARP_F;
Store_Return (RC_INTERNAL_APPLY);
Store_Expression (SHARP_F);
(Regs [REGBLOCK_PRIMITIVE]) = SHARP_F;
return;
}
void
DEFUN_VOID (back_out_of_primitive)
{
back_out_of_primitive_internal ();
Save_Cont ();
return;
}
/* canonicalize_primitive_context should be used by "unsafe" primitives
to guarantee that their execution context is the expected one, ie.
they are called from the interpreter.
If they are called from compiled code, they should abort to the
interpreter and reenter.
Note: This is called only from the macro PRIMITIVE_CANONICALIZE_CONTEXT,
so that the work can be divided between them if it is an issue. */
void
DEFUN_VOID (canonicalize_primitive_context)
{
long nargs;
SCHEME_OBJECT primitive;
primitive = (Regs [REGBLOCK_PRIMITIVE]);
if (! (PRIMITIVE_P (primitive)))
{
outf_fatal
("\ncanonicalize_primitive_context invoked when not in primitive!\n");
Microcode_Termination (TERM_BAD_BACK_OUT);
}
nargs = (PRIMITIVE_N_ARGUMENTS (primitive));
if (! (COMPILED_CODE_ADDRESS_P (STACK_REF (nargs))))
return;
/* The primitive has been invoked from compiled code. */
PRIMITIVE_ABORT (PRIM_REENTER);
/*NOTREACHED*/
}
/* Useful error procedures */
/* Note that backing out of the primitives happens after aborting,
not before.
This guarantees that the interpreter state is consistent, since the
longjmp restores the relevant registers even if the primitive was
invoked from compiled code. */
void
DEFUN (signal_error_from_primitive, (error_code), long error_code)
{
PRIMITIVE_ABORT (error_code);
/*NOTREACHED*/
}
void
DEFUN_VOID (signal_interrupt_from_primitive)
{
PRIMITIVE_ABORT (PRIM_INTERRUPT);
/*NOTREACHED*/
}
void
DEFUN (error_wrong_type_arg, (n), int n)
{
fast long error_code;
switch (n)
{
case 1: error_code = ERR_ARG_1_WRONG_TYPE; break;
case 2: error_code = ERR_ARG_2_WRONG_TYPE; break;
case 3: error_code = ERR_ARG_3_WRONG_TYPE; break;
case 4: error_code = ERR_ARG_4_WRONG_TYPE; break;
case 5: error_code = ERR_ARG_5_WRONG_TYPE; break;
case 6: error_code = ERR_ARG_6_WRONG_TYPE; break;
case 7: error_code = ERR_ARG_7_WRONG_TYPE; break;
case 8: error_code = ERR_ARG_8_WRONG_TYPE; break;
case 9: error_code = ERR_ARG_9_WRONG_TYPE; break;
case 10: error_code = ERR_ARG_10_WRONG_TYPE; break;
default: error_code = ERR_EXTERNAL_RETURN; break;
}
signal_error_from_primitive (error_code);
}
void
DEFUN (error_bad_range_arg, (n), int n)
{
fast long error_code;
switch (n)
{
case 1: error_code = ERR_ARG_1_BAD_RANGE; break;
case 2: error_code = ERR_ARG_2_BAD_RANGE; break;
case 3: error_code = ERR_ARG_3_BAD_RANGE; break;
case 4: error_code = ERR_ARG_4_BAD_RANGE; break;
case 5: error_code = ERR_ARG_5_BAD_RANGE; break;
case 6: error_code = ERR_ARG_6_BAD_RANGE; break;
case 7: error_code = ERR_ARG_7_BAD_RANGE; break;
case 8: error_code = ERR_ARG_8_BAD_RANGE; break;
case 9: error_code = ERR_ARG_9_BAD_RANGE; break;
case 10: error_code = ERR_ARG_10_BAD_RANGE; break;
default: error_code = ERR_EXTERNAL_RETURN; break;
}
signal_error_from_primitive (error_code);
}
void
DEFUN_VOID (error_external_return)
{
signal_error_from_primitive (ERR_EXTERNAL_RETURN);
}
static SCHEME_OBJECT error_argument;
void
DEFUN (error_with_argument, (argument), SCHEME_OBJECT argument)
{
error_argument = argument;
signal_error_from_primitive (ERR_WITH_ARGUMENT);
/*NOTREACHED*/
}
void
DEFUN (error_in_system_call, (err, name),
enum syserr_names err AND enum syscall_names name)
{
/* System call errors have some additional information.
Encode this as a vector in place of the error code. */
SCHEME_OBJECT v = (allocate_marked_vector (TC_VECTOR, 3, 0));
VECTOR_SET (v, 0, (LONG_TO_UNSIGNED_FIXNUM (ERR_IN_SYSTEM_CALL)));
VECTOR_SET (v, 1, (LONG_TO_UNSIGNED_FIXNUM ((unsigned int) err)));
VECTOR_SET (v, 2, (LONG_TO_UNSIGNED_FIXNUM ((unsigned int) name)));
error_argument = v;
signal_error_from_primitive (ERR_IN_SYSTEM_CALL);
/*NOTREACHED*/
}
void
DEFUN (error_system_call, (code, name),
int code AND enum syscall_names name)
{
error_in_system_call ((OS_error_code_to_syserr (code)), name);
/*NOTREACHED*/
}
long
DEFUN (arg_integer, (arg_number), int arg_number)
{
fast SCHEME_OBJECT object = (ARG_REF (arg_number));
if (! (INTEGER_P (object)))
error_wrong_type_arg (arg_number);
if (! (integer_to_long_p (object)))
error_bad_range_arg (arg_number);
return (integer_to_long (object));
}
long
DEFUN (arg_nonnegative_integer, (arg_number), int arg_number)
{
fast long result = (arg_integer (arg_number));
if (result < 0)
error_bad_range_arg (arg_number);
return (result);
}
long
DEFUN (arg_index_integer, (arg_number, upper_limit),
int arg_number AND long upper_limit)
{
fast long result = (arg_integer (arg_number));
if ((result < 0) || (result >= upper_limit))
error_bad_range_arg (arg_number);
return (result);
}
long
DEFUN (arg_integer_in_range,
(arg_number, lower_limit, upper_limit),
int arg_number AND long lower_limit AND long upper_limit)
{
fast long result = (arg_integer (arg_number));
if ((result < lower_limit) || (result >= upper_limit))
error_bad_range_arg (arg_number);
return (result);
}
unsigned long
DEFUN (arg_ulong_integer, (arg_number), int arg_number)
{
fast SCHEME_OBJECT object = (ARG_REF (arg_number));
if (! (INTEGER_P (object)))
error_wrong_type_arg (arg_number);
if (! (integer_to_ulong_p (object)))
error_bad_range_arg (arg_number);
return (integer_to_ulong (object));
}
unsigned long
DEFUN (arg_ulong_index_integer, (arg_number, upper_limit),
int arg_number AND unsigned long upper_limit)
{
fast unsigned long result = (arg_ulong_integer (arg_number));
if (result >= upper_limit)
error_bad_range_arg (arg_number);
return (result);
}
Boolean
DEFUN (real_number_to_double_p, (x), fast SCHEME_OBJECT x)
{
return ((! (BIGNUM_P (x))) || (BIGNUM_TO_DOUBLE_P (x)));
}
double
DEFUN (real_number_to_double, (x), fast SCHEME_OBJECT x)
{
return
((FIXNUM_P (x))
? (FIXNUM_TO_DOUBLE (x))
: (BIGNUM_P (x))
? (bignum_to_double (x))
: (FLONUM_TO_DOUBLE (x)));
}
double
DEFUN (arg_real_number, (arg_number), int arg_number)
{
fast SCHEME_OBJECT number = (ARG_REF (arg_number));
if (! (REAL_P (number)))
error_wrong_type_arg (arg_number);
if (! (real_number_to_double_p (number)))
error_bad_range_arg (arg_number);
return (real_number_to_double (number));
}
double
DEFUN (arg_real_in_range, (arg_number, lower_limit, upper_limit),
int arg_number AND double lower_limit AND double upper_limit)
{
fast double result = (arg_real_number (arg_number));
if ((result < lower_limit) || (result > upper_limit))
error_bad_range_arg (arg_number);
return (result);
}
Boolean
DEFUN (interpreter_applicable_p, (object), fast SCHEME_OBJECT object)
{
tail_recurse:
switch (OBJECT_TYPE (object))
{
case TC_PRIMITIVE:
case TC_PROCEDURE:
case TC_EXTENDED_PROCEDURE:
case TC_CONTROL_POINT:
return (true);
case TC_ENTITY:
{
object = (MEMORY_REF (object, ENTITY_OPERATOR));
goto tail_recurse;
}
case TC_COMPILED_ENTRY:
{
long results [3];
compiled_entry_type (object, results);
return ((results [0]) == 0);
}
default:
return (false);
}
}
/******************/
/* ERROR HANDLING */
/******************/
/* It is assumed that any caller of the error code has already
* restored its state to a situation which will make it
* restartable if the error handler returns normally. As a
* result, the only work to be done on an error is to verify
* that there is an error handler, save the current continuation and
* create a new one if entered from Pop_Return rather than Eval,
* turn off interrupts, and call it with two arguments: Error-Code
* and Interrupt-Enables.
*/
void
DEFUN (Do_Micro_Error, (Err, From_Pop_Return),
long Err AND Boolean From_Pop_Return)
{
SCHEME_OBJECT Error_Vector = SHARP_F;
SCHEME_OBJECT Handler;
if (Consistency_Check)
{
err_print(Err, error_output);
Print_Expression(Fetch_Expression(), "Expression was");
outf_error ("\nEnvironment 0x%lx (#%lo).\n",
((long) (Fetch_Env ())), ((long) (Fetch_Env ())));
Print_Return("Return code");
outf_error ("\n");
}
Error_Exit_Hook();
if (Trace_On_Error)
{
outf_error ("\n\n**** Stack Trace ****\n\n");
Back_Trace (error_output);
}
#ifdef ENABLE_DEBUGGING_TOOLS
{
int *From = &(local_circle[0]), *To = &(debug_circle[0]), i;
for (i = 0; i < local_nslots; i++)
*To++ = *From++;
debug_nslots = local_nslots;
debug_slotno = local_slotno;
}
#endif
/* Do_Micro_Error continues on the next page. */
/* Do_Micro_Error, continued */
/* This can NOT be folded into the Will_Push below since we cannot
afford to have the Will_Push put down its own continuation.
There is guaranteed to be enough space for this one
continuation; in fact, the Will_Push here is really unneeded!
*/
if (From_Pop_Return)
{
Will_Push (CONTINUATION_SIZE);
Save_Cont ();
Pushed ();
}
Will_Push (CONTINUATION_SIZE + (From_Pop_Return ? 0 : 1));
if (From_Pop_Return)
Store_Expression (Val);
else
STACK_PUSH (Fetch_Env ());
Store_Return ((From_Pop_Return) ?
RC_POP_RETURN_ERROR :
RC_EVAL_ERROR);
Save_Cont ();
Pushed ();
/* Do_Micro_Error continues on the next page. */
/* Do_Micro_Error, continued */
if ((!Valid_Fixed_Obj_Vector()) ||
(OBJECT_TYPE ((Error_Vector =
Get_Fixed_Obj_Slot(System_Error_Vector))) !=
TC_VECTOR))
{
error_death (Err,
(((Valid_Fixed_Obj_Vector())
&& (Error_Vector == SHARP_F))
? "No error handlers"
: "No error handlers: Bad handlers vector"));
/*NOTREACHED*/
}
if ((Err < 0) || (Err >= ((long) (VECTOR_LENGTH (Error_Vector)))))
{
if (VECTOR_LENGTH (Error_Vector) == 0)
error_death (Err, "No error handlers: Empty handlers vector");
/*NOTREACHED*/
Handler = (VECTOR_REF (Error_Vector, ERR_BAD_ERROR_CODE));
}
else
Handler = (VECTOR_REF (Error_Vector, Err));
/* Return from error handler will re-enable interrupts & restore history */
Stop_History();
preserve_interrupt_mask ();
Will_Push (STACK_ENV_EXTRA_SLOTS + 3);
/* Arg 2: Int. mask */
STACK_PUSH (LONG_TO_FIXNUM(FETCH_INTERRUPT_MASK()));
/* Arg 1: Err. No */
if ((Err == ERR_WITH_ARGUMENT) || (Err == ERR_IN_SYSTEM_CALL))
STACK_PUSH (error_argument);
else if ((Err >= SMALLEST_FIXNUM) && (Err <= BIGGEST_FIXNUM))
STACK_PUSH (LONG_TO_FIXNUM (Err));
else
STACK_PUSH (LONG_TO_UNSIGNED_FIXNUM (ERR_BAD_ERROR_CODE));
/* Procedure: Handler */
STACK_PUSH (Handler);
STACK_PUSH (STACK_FRAME_HEADER + 2);
Pushed();
/* Disable all interrupts */
SET_INTERRUPT_MASK(0);
return;
}
/* HISTORY manipulation */
SCHEME_OBJECT *
DEFUN_VOID (Make_Dummy_History)
{
SCHEME_OBJECT *History_Rib = Free;
SCHEME_OBJECT *Result;
Free[RIB_EXP] = SHARP_F;
Free[RIB_ENV] = SHARP_F;
Free[RIB_NEXT_REDUCTION] =
MAKE_POINTER_OBJECT (UNMARKED_HISTORY_TYPE, History_Rib);
Free += 3;
Result = Free;
Free[HIST_RIB] = MAKE_POINTER_OBJECT (UNMARKED_HISTORY_TYPE, History_Rib);
Free[HIST_NEXT_SUBPROBLEM] =
MAKE_POINTER_OBJECT (UNMARKED_HISTORY_TYPE, Result);
Free[HIST_PREV_SUBPROBLEM] =
MAKE_POINTER_OBJECT (UNMARKED_HISTORY_TYPE, Result);
Free += 3;
return (Result);
}
/* The entire trick to history is right here: it is either copied or
reused when restored. Initially, Stop_History marks the stack so
that the history will merely be popped and reused. On a catch,
however, the return code is changed to force the history to be
copied instead. Thus, histories saved as part of a control point
are not side-effected in the history collection process.
*/
void
DEFUN_VOID (Stop_History)
{
SCHEME_OBJECT Saved_Expression;
long Saved_Return_Code;
Saved_Expression = Fetch_Expression();
Saved_Return_Code = Fetch_Return();
Will_Push(HISTORY_SIZE);
Save_History(RC_RESTORE_DONT_COPY_HISTORY);
Pushed();
Prev_Restore_History_Stacklet = NULL;
Prev_Restore_History_Offset = ((Get_End_Of_Stacklet() - Stack_Pointer) +
CONTINUATION_RETURN_CODE);
Store_Expression(Saved_Expression);
Store_Return(Saved_Return_Code);
return;
}
/* This returns a history object,
or SHARP_F if it needs to GC,
or SHARP_T if it is not a valid history object.
*/
SCHEME_OBJECT
DEFUN (copy_history, (hist_obj), SCHEME_OBJECT hist_obj)
{
long space_left, vert_type, rib_type;
SCHEME_OBJECT *fast_free;
SCHEME_OBJECT new_hunk, *last_hunk, *hist_ptr, *orig_hist, temp;
SCHEME_OBJECT *orig_rib, *source_rib, *rib_slot;
if (!(HUNK3_P (hist_obj)))
return (SHARP_T);
space_left = ((Space_Before_GC ()) - 3);
fast_free = Free;
vert_type = (OBJECT_TYPE (hist_obj));
orig_hist = (OBJECT_ADDRESS (hist_obj));
hist_ptr = orig_hist;
last_hunk = (Heap_Top - 3);
do
{
/* Allocate and link the vertebra. */
space_left -= 3;
if (space_left < 0)
return (SHARP_F);
new_hunk = (MAKE_POINTER_OBJECT (vert_type, fast_free));
last_hunk[HIST_NEXT_SUBPROBLEM] = new_hunk;
fast_free[HIST_PREV_SUBPROBLEM] =
(MAKE_POINTER_OBJECT ((OBJECT_TYPE (hist_ptr[HIST_PREV_SUBPROBLEM])),
last_hunk));
last_hunk = fast_free;
fast_free += 3;
/* Copy the rib. */
temp = hist_ptr[HIST_RIB];
rib_type = (OBJECT_TYPE (temp));
orig_rib = (OBJECT_ADDRESS (temp));
rib_slot = (last_hunk + HIST_RIB);
source_rib = orig_rib;
do
{
space_left -= 3;
if (space_left < 0)
return (SHARP_F);
*rib_slot = (MAKE_POINTER_OBJECT (rib_type, fast_free));
fast_free[RIB_EXP] = source_rib[RIB_EXP];
fast_free[RIB_ENV] = source_rib[RIB_ENV];
rib_slot = (fast_free + RIB_NEXT_REDUCTION);
fast_free += 3;
temp = source_rib[RIB_NEXT_REDUCTION];
rib_type = (OBJECT_TYPE (temp));
source_rib = (OBJECT_ADDRESS (temp));
} while (source_rib != orig_rib);
*rib_slot = (OBJECT_NEW_TYPE (rib_type, last_hunk[HIST_RIB]));
temp = hist_ptr[HIST_NEXT_SUBPROBLEM];
vert_type = (OBJECT_TYPE (temp));
hist_ptr = (OBJECT_ADDRESS (temp));
} while (hist_ptr != orig_hist);
Free = fast_free;
new_hunk = Heap_Top[HIST_NEXT_SUBPROBLEM - 3];
last_hunk[HIST_NEXT_SUBPROBLEM] = (OBJECT_NEW_TYPE (vert_type, new_hunk));
FAST_MEMORY_SET (new_hunk, HIST_PREV_SUBPROBLEM,
(MAKE_POINTER_OBJECT
((OBJECT_TYPE (hist_ptr[HIST_PREV_SUBPROBLEM])),
last_hunk)));
return (new_hunk);
}
/* Restore_History pops a history object off the stack and
makes a COPY of it the current history collection object.
This is called only from the RC_RESTORE_HISTORY case in
interpret.c .
*/
Boolean
DEFUN (Restore_History, (hist_obj), SCHEME_OBJECT hist_obj)
{
SCHEME_OBJECT new_hist;
new_hist = (copy_history (hist_obj));
if (new_hist == SHARP_F)
return (false);
else if (new_hist == SHARP_T)
{
outf_fatal ("\nBad history to restore.\n");
Microcode_Termination (TERM_EXIT);
/*NOTREACHED*/
return (0);
}
else
{
History = (OBJECT_ADDRESS (new_hist));
return (true);
}
}
/* If a "debugging" version of the interpreter is made, then this
procedure is called to actually invoke a primitive. When a
"production" version is made, all of the consistency checks are
omitted and a macro from "default.h" is used to directly code the
call to the primitive function. */
#ifdef ENABLE_DEBUGGING_TOOLS
SCHEME_OBJECT
DEFUN (primitive_apply_internal, (primitive), SCHEME_OBJECT primitive)
{
SCHEME_OBJECT result;
if (Primitive_Debug)
Print_Primitive (primitive);
{
SCHEME_OBJECT * saved_stack = Stack_Pointer;
PRIMITIVE_APPLY_INTERNAL (result, primitive);
if (saved_stack != Stack_Pointer)
{
int arity = (PRIMITIVE_N_ARGUMENTS (primitive));
Print_Expression (primitive, "Stack bad after ");
outf_fatal ("\nStack was 0x%lx, now 0x%lx, #args=%ld.\n",
((long) saved_stack), ((long) Stack_Pointer), ((long) arity));
Microcode_Termination (TERM_EXIT);
}
}
if (Primitive_Debug)
{
Print_Expression (result, "Primitive Result");
outf_error("\n");
outf_flush_error();
}
return (result);
}
#endif /* ENABLE_DEBUGGING_TOOLS */
#ifdef ENABLE_PRIMITIVE_PROFILING
/* The profiling mechanism is enabled by storing a vector in the fixed
objects vector. The vector should be initialized to contain all zeros
*/
void
DEFUN (record_primitive_entry, (primitive), SCHEME_OBJECT primitive)
{
SCHEME_OBJECT table;
if ((Fixed_Objects != SHARP_F) &&
((table = Get_Fixed_Obj_Slot (Primitive_Profiling_Table)) != SHARP_F))
{
long index = (1 + (OBJECT_DATUM (primitive)));
MEMORY_SET
(table,
index,
(long_to_integer (1 + (integer_to_long (MEMORY_REF (table, index))))));
}
return;
}
#endif /* ENABLE_PRIMITIVE_PROFILING */
#ifdef USE_STACKLETS
/******************/
/* STACKLETS */
/******************/
void
DEFUN (Allocate_New_Stacklet, (N), long N)
{
SCHEME_OBJECT Old_Expression, *Old_Stacklet, Old_Return;
Old_Stacklet = Current_Stacklet;
Terminate_Old_Stacklet();
if ((Free_Stacklets == NULL) ||
((N + STACKLET_SLACK) >
(OBJECT_DATUM (Free_Stacklets[STACKLET_LENGTH]))))
{
long size;
/*
Room is set aside for the header bytes of a stacklet plus
the two words required for the RC_JOIN_STACKLETS frame.
*/
size = New_Stacklet_Size(N);
if (GC_Check(size))
{
Request_GC(size);
if ((Free + size) >= Heap_Top)
Microcode_Termination(TERM_STACK_OVERFLOW);
}
Free[STACKLET_LENGTH] = MAKE_OBJECT (TC_MANIFEST_VECTOR, (size - 1));
SET_STACK_GUARD (& (Free[STACKLET_HEADER_SIZE]));
Free += size;
Stack_Pointer = Free;
}
else
{
/* Grab first one on the free list */
SCHEME_OBJECT *New_Stacklet;
New_Stacklet = Free_Stacklets;
Free_Stacklets =
((SCHEME_OBJECT *) Free_Stacklets[STACKLET_FREE_LIST_LINK]);
Stack_Pointer =
&New_Stacklet[1 + (OBJECT_DATUM (New_Stacklet[STACKLET_LENGTH]))];
SET_STACK_GUARD (& (New_Stacklet[STACKLET_HEADER_SIZE]));
}
Old_Expression = Fetch_Expression();
Old_Return = Fetch_Return();
Store_Expression(MAKE_POINTER_OBJECT (TC_CONTROL_POINT, Old_Stacklet));
Store_Return(RC_JOIN_STACKLETS);
/*
Will_Push omitted because size calculation includes enough room.
*/
Save_Cont();
Store_Expression(Old_Expression);
Store_Return(Old_Return);
return;
}
#endif /* USE_STACKLETS */
/* Dynamic Winder support code */
SCHEME_OBJECT
DEFUN (Find_State_Space, (State_Point), SCHEME_OBJECT State_Point)
{
long How_Far =
(UNSIGNED_FIXNUM_TO_LONG
(FAST_MEMORY_REF (State_Point, STATE_POINT_DISTANCE_TO_ROOT)));
long i;
fast SCHEME_OBJECT Point = State_Point;
for (i=0; i <= How_Far; i++)
{
#ifdef ENABLE_DEBUGGING_TOOLS
if (Point == SHARP_F)
{
outf_fatal(
"\nState_Point 0x%lx wrong: count was %ld, #F at %ld\n",
((long) State_Point), ((long) How_Far), ((long) i));
Microcode_Termination(TERM_EXIT);
/*NOTREACHED*/
}
#endif /* ENABLE_DEBUGGING_TOOLS */
Point = FAST_MEMORY_REF (Point, STATE_POINT_NEARER_POINT);
}
return (Point);
}
/* ASSUMPTION: State points, which are created only by the interpreter,
never contain FUTUREs except possibly as the thunks (which are handled
by the apply code).
Furthermore:
(1) On a single processor, things should work with multiple state
spaces. The microcode variable Current_State_Point tracks
the location in the "boot" space (i.e. the one whose space is
#F) and the state spaces themselves (roots of the space
trees) track the other spaces.
(2) On multi-processors, multiple spaces DO NOT work. Only the
initial space (#F) is tracked by the microcode (it is
swapped on every task switch), but no association with trees
is kept. This will work since the initial tree has no space
at the root, indicating that the microcode variable rather
than the state space contains the current state space
location.
NOTE: This procedure is invoked both by primitives and the interpreter
itself. As such, it is using the pun that PRIMITIVE_ABORT is just a
(non-local) return to the interpreter. This should be cleaned up.
NOTE: Any primitive that invokes this procedure must do a
PRIMITIVE_CANONICALIZE_CONTEXT() first!
*/
void
DEFUN (Translate_To_Point, (Target), SCHEME_OBJECT Target)
{
SCHEME_OBJECT State_Space, Current_Location, *Path;
fast SCHEME_OBJECT Path_Point, *Path_Ptr;
long Distance, Merge_Depth, From_Depth, i;
State_Space = Find_State_Space(Target);
Path = Free;
guarantee_state_point();
Distance =
(UNSIGNED_FIXNUM_TO_LONG
(FAST_MEMORY_REF (Target, STATE_POINT_DISTANCE_TO_ROOT)));
if (State_Space == SHARP_F)
Current_Location = Current_State_Point;
else
Current_Location = MEMORY_REF (State_Space, STATE_SPACE_NEAREST_POINT);
if (Target == Current_Location)
{
PRIMITIVE_ABORT (PRIM_POP_RETURN);
/*NOTREACHED*/
}
for (Path_Ptr = (&(Path[Distance])), Path_Point = Target, i = 0;
i <= Distance;
i++)
{
*Path_Ptr-- = Path_Point;
Path_Point = FAST_MEMORY_REF (Path_Point, STATE_POINT_NEARER_POINT);
}
From_Depth =
(UNSIGNED_FIXNUM_TO_LONG
(FAST_MEMORY_REF (Current_Location, STATE_POINT_DISTANCE_TO_ROOT)));
for (Path_Point = Current_Location, Merge_Depth = From_Depth;
Merge_Depth > Distance;
Merge_Depth--)
Path_Point = FAST_MEMORY_REF (Path_Point, STATE_POINT_NEARER_POINT);
for (Path_Ptr = (&(Path[Merge_Depth]));
Merge_Depth >= 0;
Merge_Depth--, Path_Ptr--)
{
if (*Path_Ptr == Path_Point)
break;
Path_Point = FAST_MEMORY_REF (Path_Point, STATE_POINT_NEARER_POINT);
}
#ifdef ENABLE_DEBUGGING_TOOLS
if (Merge_Depth < 0)
{
outf_fatal("\nMerge_Depth went negative: %d\n", Merge_Depth);
Microcode_Termination (TERM_EXIT);
}
#endif /* ENABLE_DEBUGGING_TOOLS */
preserve_interrupt_mask ();
Will_Push(CONTINUATION_SIZE + 4);
STACK_PUSH (LONG_TO_UNSIGNED_FIXNUM((Distance - Merge_Depth)));
STACK_PUSH (Target);
STACK_PUSH (LONG_TO_UNSIGNED_FIXNUM((From_Depth - Merge_Depth)));
STACK_PUSH (Current_Location);
Store_Expression(State_Space);
Store_Return(RC_MOVE_TO_ADJACENT_POINT);
Save_Cont();
Pushed();
{
long mask;
/* Disable lower than GC level */
mask = (FETCH_INTERRUPT_MASK() & ((INT_GC << 1) - 1));
SET_INTERRUPT_MASK(mask);
}
PRIMITIVE_ABORT (PRIM_POP_RETURN);
/*NOTREACHED*/
}
#ifndef __OS2__
SCHEME_OBJECT
DEFUN_VOID (Compiler_Get_Fixed_Objects)
{
if (Valid_Fixed_Obj_Vector())
return (Get_Fixed_Obj_Slot(Me_Myself));
else
return (SHARP_F);
}
extern SCHEME_OBJECT EXFUN (Re_Enter_Interpreter, (void));
extern SCHEME_OBJECT EXFUN
(C_call_scheme, (SCHEME_OBJECT, long, SCHEME_OBJECT *));
#ifdef __WIN32__
# include <windows.h>
#endif
SCHEME_OBJECT
DEFUN (C_call_scheme, (proc, nargs, argvec),
SCHEME_OBJECT proc
AND long nargs
AND SCHEME_OBJECT * argvec)
{
SCHEME_OBJECT primitive, prim_lexpr, * sp, result;
SCHEME_OBJECT * callers_last_return_code;
#ifdef __IA32__
extern void * C_Frame_Pointer;
extern void * C_Stack_Pointer;
void * cfp = C_Frame_Pointer;
void * csp = C_Stack_Pointer;
#ifdef CL386
__try
#endif
#endif
{
primitive = (Regs [REGBLOCK_PRIMITIVE]);
prim_lexpr = (Regs [REGBLOCK_LEXPR_ACTUALS]);
callers_last_return_code = last_return_code;
if (! (PRIMITIVE_P (primitive)))
abort_to_interpreter (ERR_CANNOT_RECURSE);
/*NOTREACHED*/
sp = Stack_Pointer;
Will_Push ((2 * CONTINUATION_SIZE) + (nargs + STACK_ENV_EXTRA_SLOTS + 1));
{
long i;
Store_Return (RC_END_OF_COMPUTATION);
Store_Expression (primitive);
Save_Cont ();
for (i = nargs; --i >= 0; )
STACK_PUSH (argvec[i]);
STACK_PUSH (proc);
STACK_PUSH (STACK_FRAME_HEADER + nargs);
Store_Return (RC_INTERNAL_APPLY);
Store_Expression (SHARP_F);
Save_Cont ();
}
Pushed ();
result = (Re_Enter_Interpreter ());
if (Stack_Pointer != sp)
signal_error_from_primitive (ERR_STACK_HAS_SLIPPED);
/*NOTREACHED*/
last_return_code = callers_last_return_code;
Regs [REGBLOCK_LEXPR_ACTUALS] = prim_lexpr;
Regs [REGBLOCK_PRIMITIVE] = primitive;
}
#ifdef __IA32__
#ifdef CL386
__finally
#endif
{
C_Frame_Pointer = cfp;
C_Stack_Pointer = csp;
}
#endif
return result;
}
#endif /* not __OS2__ */