/* Virtual Machine
- This is Guile's new virtual machine. When I say "new", I mean
- relative to the current virtual machine. At some point it will
- become "the" virtual machine, and we'll delete this paragraph. As
- such, the rest of the comments speak as if there's only one VM.
- In difference from the old VM, local 0 is the procedure, and the
- first argument is local 1. At some point in the future we should
- change the fp to point to the procedure and not to local 1.
-
- <more overview here>
- */
-
-
-/* The VM has three state bits: the instruction pointer (IP), the frame
+ The VM has three state bits: the instruction pointer (IP), the frame
pointer (FP), and the top-of-stack pointer (SP). We cache the first
two of these in machine registers, local to the VM, because they are
used extensively by the VM. As the SP is used more by code outside
} while (0)
-
-/* After advancing vp->sp, but before writing any stack slots, check
- that it is actually in bounds. If it is not in bounds, currently we
- signal an error. In the future we may expand the stack instead,
- possibly by moving it elsewhere, therefore no pointer into the stack
- besides FP is valid across a CHECK_OVERFLOW call. Be careful! */
-#define CHECK_OVERFLOW() \
- do { \
- if (SCM_UNLIKELY (vp->sp >= vp->stack_limit)) \
- { \
- SYNC_IP (); \
- vm_expand_stack (vp); \
- CACHE_FP (); \
- } \
- } while (0)
-
/* Reserve stack space for a frame. Will check that there is sufficient
stack space for N locals, including the procedure. Invoke after
- preparing the new frame and setting the fp and ip. */
+ preparing the new frame and setting the fp and ip.
+
+ If there is not enough space for this frame, we try to expand the
+ stack, possibly relocating it somewhere else in the address space.
+ Because of the possible relocation, no pointer into the stack besides
+ FP is valid across an ALLOC_FRAME call. Be careful! */
#define ALLOC_FRAME(n) \
do { \
- vp->sp = LOCAL_ADDRESS (n - 1); \
- if (vp->sp > vp->sp_max_since_gc) \
+ SCM *new_sp = LOCAL_ADDRESS (n - 1); \
+ if (new_sp > vp->sp_max_since_gc) \
{ \
- vp->sp_max_since_gc = vp->sp; \
- CHECK_OVERFLOW (); \
+ if (SCM_UNLIKELY (new_sp >= vp->stack_limit)) \
+ { \
+ SYNC_IP (); \
+ vm_expand_stack (vp, new_sp); \
+ CACHE_FP (); \
+ } \
+ else \
+ vp->sp_max_since_gc = vp->sp = new_sp; \
} \
+ else \
+ vp->sp = new_sp; \
} while (0)
/* Reset the current frame to hold N locals. Used when we know that no
{ \
scm_t_int32 offset = ip[1]; \
offset >>= 8; /* Sign-extending shift. */ \
- if (offset < 0) \
+ if (offset <= 0) \
VM_HANDLE_INTERRUPTS; \
NEXT (offset); \
} \
{ \
scm_t_int32 offset = ip[1]; \
offset >>= 8; /* Sign-extending shift. */ \
- if (offset < 0) \
+ if (offset <= 0) \
VM_HANDLE_INTERRUPTS; \
NEXT (offset); \
} \
{ \
scm_t_int32 offset = ip[1]; \
offset >>= 8; /* Sign-extending shift. */ \
- if (offset < 0) \
+ if (offset <= 0) \
VM_HANDLE_INTERRUPTS; \
NEXT (offset); \
} \
{ \
scm_t_int32 offset = ip[1]; \
offset >>= 8; /* Sign-extending shift. */ \
- if (offset < 0) \
+ if (offset <= 0) \
VM_HANDLE_INTERRUPTS; \
NEXT (offset); \
} \
NEXT (0);
apply:
- while (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp)))
+ while (!SCM_PROGRAM_P (LOCAL_REF (0)))
{
- SCM proc = SCM_FRAME_PROGRAM (fp);
+ SCM proc = LOCAL_REF (0);
if (SCM_STRUCTP (proc) && SCM_STRUCT_APPLICABLE_P (proc))
{
}
/* Let's go! */
- ip = SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp));
+ ip = SCM_PROGRAM_CODE (LOCAL_REF (0));
NEXT (0);
BEGIN_DISPATCH_SWITCH;
PUSH_CONTINUATION_HOOK ();
APPLY_HOOK ();
- if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp))))
+ if (SCM_UNLIKELY (!SCM_PROGRAM_P (LOCAL_REF (0))))
goto apply;
- ip = SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp));
+ ip = SCM_PROGRAM_CODE (LOCAL_REF (0));
NEXT (0);
}
APPLY_HOOK ();
- if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp))))
+ if (SCM_UNLIKELY (!SCM_PROGRAM_P (LOCAL_REF (0))))
goto apply;
- ip = SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp));
+ ip = SCM_PROGRAM_CODE (LOCAL_REF (0));
NEXT (0);
}
APPLY_HOOK ();
- if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp))))
+ if (SCM_UNLIKELY (!SCM_PROGRAM_P (LOCAL_REF (0))))
goto apply;
- ip = SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp));
+ ip = SCM_PROGRAM_CODE (LOCAL_REF (0));
NEXT (0);
}
APPLY_HOOK ();
- if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp))))
+ if (SCM_UNLIKELY (!SCM_PROGRAM_P (LOCAL_REF (0))))
goto apply;
- ip = SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp));
+ ip = SCM_PROGRAM_CODE (LOCAL_REF (0));
NEXT (0);
}
APPLY_HOOK ();
- if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp))))
+ if (SCM_UNLIKELY (!SCM_PROGRAM_P (LOCAL_REF (0))))
goto apply;
- ip = SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp));
+ ip = SCM_PROGRAM_CODE (LOCAL_REF (0));
NEXT (0);
}
else
scm_t_uint32 expected;
UNPACK_24 (op, expected);
VM_ASSERT (FRAME_LOCALS_COUNT () == expected,
- vm_error_wrong_num_args (SCM_FRAME_PROGRAM (fp)));
+ vm_error_wrong_num_args (LOCAL_REF (0)));
NEXT (1);
}
VM_DEFINE_OP (22, assert_nargs_ge, "assert-nargs-ge", OP1 (U8_U24))
scm_t_uint32 expected;
UNPACK_24 (op, expected);
VM_ASSERT (FRAME_LOCALS_COUNT () >= expected,
- vm_error_wrong_num_args (SCM_FRAME_PROGRAM (fp)));
+ vm_error_wrong_num_args (LOCAL_REF (0)));
NEXT (1);
}
VM_DEFINE_OP (23, assert_nargs_le, "assert-nargs-le", OP1 (U8_U24))
scm_t_uint32 expected;
UNPACK_24 (op, expected);
VM_ASSERT (FRAME_LOCALS_COUNT () <= expected,
- vm_error_wrong_num_args (SCM_FRAME_PROGRAM (fp)));
+ vm_error_wrong_num_args (LOCAL_REF (0)));
NEXT (1);
}
scm_t_uint16 expected, nlocals;
UNPACK_12_12 (op, expected, nlocals);
VM_ASSERT (FRAME_LOCALS_COUNT () == expected,
- vm_error_wrong_num_args (SCM_FRAME_PROGRAM (fp)));
+ vm_error_wrong_num_args (LOCAL_REF (0)));
ALLOC_FRAME (expected + nlocals);
while (nlocals--)
LOCAL_SET (expected + nlocals, SCM_UNDEFINED);
LOCAL_SET (n++, SCM_UNDEFINED);
VM_ASSERT (has_rest || (nkw % 2) == 0,
- vm_error_kwargs_length_not_even (SCM_FRAME_PROGRAM (fp)));
+ vm_error_kwargs_length_not_even (LOCAL_REF (0)));
/* Now bind keywords, in the order given. */
for (n = 0; n < nkw; n++)
break;
}
VM_ASSERT (scm_is_pair (walk) || allow_other_keys,
- vm_error_kwargs_unrecognized_keyword (SCM_FRAME_PROGRAM (fp),
+ vm_error_kwargs_unrecognized_keyword (LOCAL_REF (0),
LOCAL_REF (ntotal + n)));
n++;
}
else
- VM_ASSERT (has_rest, vm_error_kwargs_invalid_keyword (SCM_FRAME_PROGRAM (fp),
+ VM_ASSERT (has_rest, vm_error_kwargs_invalid_keyword (LOCAL_REF (0),
LOCAL_REF (ntotal + n)));
if (has_rest)
{
scm_t_int32 offset = op;
offset >>= 8; /* Sign-extending shift. */
+ if (offset <= 0)
+ VM_HANDLE_INTERRUPTS;
NEXT (offset);
}
var = LOCAL_REF (src);
VM_ASSERT (SCM_VARIABLEP (var),
vm_error_not_a_variable ("variable-ref", var));
- VM_ASSERT (VARIABLE_BOUNDP (var),
- vm_error_unbound (SCM_FRAME_PROGRAM (fp), var));
+ VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (var));
LOCAL_SET (dst, VARIABLE_REF (var));
NEXT (1);
}
* Make an immediate whose low bits are LOW-BITS, and whose top bits are
* 0.
*/
- VM_DEFINE_OP (53, make_long_immediate, "make-long-immediate", OP2 (U8_U24, I32))
+ VM_DEFINE_OP (53, make_long_immediate, "make-long-immediate", OP2 (U8_U24, I32) | OP_DST)
{
scm_t_uint32 dst;
scm_t_bits val;
* that the compiler is unable to statically allocate, like symbols.
* These values would be initialized when the object file loads.
*/
- VM_DEFINE_OP (56, static_ref, "static-ref", OP2 (U8_U24, S32))
+ VM_DEFINE_OP (56, static_ref, "static-ref", OP2 (U8_U24, S32) | OP_DST)
{
scm_t_uint32 dst;
scm_t_int32 offset;
var = scm_lookup (LOCAL_REF (sym));
CACHE_FP ();
if (ip[1] & 0x1)
- VM_ASSERT (VARIABLE_BOUNDP (var),
- vm_error_unbound (fp[0], LOCAL_REF (sym)));
+ VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (LOCAL_REF (sym)));
LOCAL_SET (dst, var);
NEXT (2);
var = scm_module_lookup (mod, sym);
CACHE_FP ();
if (ip[4] & 0x1)
- VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (fp[0], sym));
+ VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (sym));
*var_loc = var;
}
if (!scm_module_system_booted_p)
{
-#ifdef VM_ENABLE_PARANOID_ASSERTIONS
- ASSERT
- (scm_is_true
- scm_equal_p (modname,
- scm_list_2 (SCM_BOOL_T,
- scm_from_utf8_symbol ("guile"))));
-#endif
+ ASSERT (scm_is_true
+ scm_equal_p (modname,
+ scm_list_2
+ (SCM_BOOL_T,
+ scm_from_utf8_symbol ("guile"))));
var = scm_lookup (sym);
}
else if (scm_is_true (SCM_CAR (modname)))
CACHE_FP ();
if (ip[4] & 0x1)
- VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (fp[0], sym));
+ VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (sym));
*var_loc = var;
}
if (scm_is_eq (val, SCM_UNDEFINED))
val = SCM_I_FLUID_DEFAULT (fluid);
VM_ASSERT (!scm_is_eq (val, SCM_UNDEFINED),
- vm_error_unbound_fluid (SCM_FRAME_PROGRAM (fp), fluid));
+ vm_error_unbound_fluid (fluid));
LOCAL_SET (dst, val);
}
VM_DEFINE_OP (95, vector_length, "vector-length", OP1 (U8_U12_U12) | OP_DST)
{
ARGS1 (vect);
- if (SCM_LIKELY (SCM_I_IS_VECTOR (vect)))
- RETURN (SCM_I_MAKINUM (SCM_I_VECTOR_LENGTH (vect)));
- else
- {
- SYNC_IP ();
- RETURN (scm_vector_length (vect));
- }
+ VM_ASSERT (SCM_I_IS_VECTOR (vect),
+ vm_error_not_a_vector ("vector-ref", vect));
+ RETURN (SCM_I_MAKINUM (SCM_I_VECTOR_LENGTH (vect)));
}
/* vector-ref dst:8 src:8 idx:8
{
scm_t_signed_bits i = 0;
ARGS2 (vect, idx);
- if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (vect)
- && SCM_I_INUMP (idx)
- && ((i = SCM_I_INUM (idx)) >= 0)
- && i < SCM_I_VECTOR_LENGTH (vect)))
- RETURN (SCM_I_VECTOR_ELTS (vect)[i]);
- else
- {
- SYNC_IP ();
- RETURN (scm_vector_ref (vect, idx));
- }
+ VM_ASSERT (SCM_I_IS_VECTOR (vect),
+ vm_error_not_a_vector ("vector-ref", vect));
+ VM_ASSERT ((SCM_I_INUMP (idx)
+ && ((i = SCM_I_INUM (idx)) >= 0)
+ && i < SCM_I_VECTOR_LENGTH (vect)),
+ vm_error_out_of_range ("vector-ref", idx));
+ RETURN (SCM_I_VECTOR_ELTS (vect)[i]);
}
/* vector-ref/immediate dst:8 src:8 idx:8
UNPACK_8_8_8 (op, dst, src, idx);
v = LOCAL_REF (src);
- if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (v)
- && idx < SCM_I_VECTOR_LENGTH (v)))
- LOCAL_SET (dst, SCM_I_VECTOR_ELTS (LOCAL_REF (src))[idx]);
- else
- LOCAL_SET (dst, scm_c_vector_ref (v, idx));
+ VM_ASSERT (SCM_I_IS_VECTOR (v),
+ vm_error_not_a_vector ("vector-ref", v));
+ VM_ASSERT (idx < SCM_I_VECTOR_LENGTH (v),
+ vm_error_out_of_range ("vector-ref", scm_from_size_t (idx)));
+ LOCAL_SET (dst, SCM_I_VECTOR_ELTS (LOCAL_REF (src))[idx]);
NEXT (1);
}
idx = LOCAL_REF (idx_var);
val = LOCAL_REF (src);
- if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (vect)
- && SCM_I_INUMP (idx)
- && ((i = SCM_I_INUM (idx)) >= 0)
- && i < SCM_I_VECTOR_LENGTH (vect)))
- SCM_I_VECTOR_WELTS (vect)[i] = val;
- else
- {
- SYNC_IP ();
- scm_vector_set_x (vect, idx, val);
- }
+ VM_ASSERT (SCM_I_IS_VECTOR (vect),
+ vm_error_not_a_vector ("vector-ref", vect));
+ VM_ASSERT ((SCM_I_INUMP (idx)
+ && ((i = SCM_I_INUM (idx)) >= 0)
+ && i < SCM_I_VECTOR_LENGTH (vect)),
+ vm_error_out_of_range ("vector-ref", idx));
+ SCM_I_VECTOR_WELTS (vect)[i] = val;
NEXT (1);
}
vect = LOCAL_REF (dst);
val = LOCAL_REF (src);
- if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (vect)
- && idx < SCM_I_VECTOR_LENGTH (vect)))
- SCM_I_VECTOR_WELTS (vect)[idx] = val;
- else
- {
- SYNC_IP ();
- scm_vector_set_x (vect, scm_from_uint8 (idx), val);
- }
+ VM_ASSERT (SCM_I_IS_VECTOR (vect),
+ vm_error_not_a_vector ("vector-ref", vect));
+ VM_ASSERT (idx < SCM_I_VECTOR_LENGTH (vect),
+ vm_error_out_of_range ("vector-ref", scm_from_size_t (idx)));
+ SCM_I_VECTOR_WELTS (vect)[idx] = val;
NEXT (1);
}
NEXT (3);
}
- /* make-array dst:12 type:12 _:8 fill:12 bounds:12
+ /* make-array dst:8 type:8 fill:8 _:8 bounds:24
*
* Make a new array with TYPE, FILL, and BOUNDS, storing it in DST.
*/
- VM_DEFINE_OP (106, make_array, "make-array", OP2 (U8_U12_U12, X8_U12_U12) | OP_DST)
+ VM_DEFINE_OP (106, make_array, "make-array", OP2 (U8_U8_U8_U8, X8_U24) | OP_DST)
{
- scm_t_uint16 dst, type, fill, bounds;
- UNPACK_12_12 (op, dst, type);
- UNPACK_12_12 (ip[1], fill, bounds);
+ scm_t_uint8 dst, type, fill, bounds;
+ UNPACK_8_8_8 (op, dst, type, fill);
+ UNPACK_24 (ip[1], bounds);
SYNC_IP ();
LOCAL_SET (dst, scm_make_typed_array (LOCAL_REF (type), LOCAL_REF (fill),
LOCAL_REF (bounds)));
#undef BV_INT_REF
#undef BV_INT_SET
#undef CACHE_REGISTER
-#undef CHECK_OVERFLOW
#undef END_DISPATCH_SWITCH
#undef FREE_VARIABLE_REF
#undef INIT