- | |
-
- As can be inferred from this drawing, it is assumed that
- `sizeof (SCM *) == sizeof (SCM)', since pointers (the `link' parts) are
- assumed to be as long as SCM objects. */
-
-#define SCM_FRAME_DATA_ADDRESS(fp) (fp - 4)
-#define SCM_FRAME_STACK_ADDRESS(fp) (fp)
-#define SCM_FRAME_UPPER_ADDRESS(fp) (fp - 2)
-#define SCM_FRAME_LOWER_ADDRESS(fp) (fp - 4)
-
-#define SCM_FRAME_BYTE_CAST(x) ((scm_t_uint8 *) SCM_UNPACK (x))
-#define SCM_FRAME_STACK_CAST(x) ((SCM *) SCM_UNPACK (x))
-
-#define SCM_FRAME_RETURN_ADDRESS(fp) \
- (SCM_FRAME_BYTE_CAST (SCM_FRAME_DATA_ADDRESS (fp)[2]))
-#define SCM_FRAME_SET_RETURN_ADDRESS(fp, ra) \
- ((SCM_FRAME_DATA_ADDRESS (fp)[2])) = SCM_PACK (ra)
-#define SCM_FRAME_MV_RETURN_ADDRESS(fp) \
- (SCM_FRAME_BYTE_CAST (SCM_FRAME_DATA_ADDRESS (fp)[1]))
-#define SCM_FRAME_SET_MV_RETURN_ADDRESS(fp, mvra) \
- ((SCM_FRAME_DATA_ADDRESS (fp)[1])) = SCM_PACK (mvra)
-#define SCM_FRAME_DYNAMIC_LINK(fp) \
- (SCM_FRAME_STACK_CAST (SCM_FRAME_DATA_ADDRESS (fp)[0]))
-#define SCM_FRAME_SET_DYNAMIC_LINK(fp, dl) \
- ((SCM_FRAME_DATA_ADDRESS (fp)[0])) = SCM_PACK (dl)
-#define SCM_FRAME_VARIABLE(fp,i) SCM_FRAME_STACK_ADDRESS (fp)[i]
-#define SCM_FRAME_PROGRAM(fp) SCM_FRAME_STACK_ADDRESS (fp)[-1]
+ | | <- fp - 3 = SCM_FRAME_PREVIOUS_SP (fp)
+
+ The calling convention is that a caller prepares a stack frame
+ consisting of the saved FP and the return address, followed by the
+ procedure and then the arguments to the call, in order. Thus in the
+ beginning of a call, the procedure being called is in slot 0, the
+ first argument is in slot 1, and the SP points to the last argument.
+ The number of arguments, including the procedure, is thus SP - FP +
+ 1.
+
+ After ensuring that the correct number of arguments have been passed,
+ a function will set the stack pointer to point to the last local
+ slot. This lets a function allocate the temporary space that it
+ needs once in the beginning of the call, instead of pushing and
+ popping the stack pointer during the call's extent.
+
+ When a program returns, it returns its values in the slots starting
+ from local 1, as if the values were arguments to a tail call. We
+ start from 1 instead of 0 for the convenience of the "values" builtin
+ function, which can just leave its arguments in place.
+
+ The callee resets the stack pointer to point to the last value. In
+ this way the caller knows how many values there are: it's the number
+ of words between the stack pointer and the slot at which the caller
+ placed the procedure.
+
+ After checking that the number of values returned is appropriate, the
+ caller shuffles the values around (if needed), and resets the stack
+ pointer back to its original value from before the call. */
+
+
+\f
+
+/* This structure maps to the contents of a VM stack frame. It can
+ alias a frame directly. */
+struct scm_vm_frame
+{
+ SCM *dynamic_link;
+ scm_t_uint8 *return_address;
+ SCM locals[1]; /* Variable-length */
+};
+
+#define SCM_FRAME_LOWER_ADDRESS(fp) (((SCM *) (fp)) - 2)
+#define SCM_FRAME_STRUCT(fp) \
+ ((struct scm_vm_frame *) SCM_FRAME_LOWER_ADDRESS (fp))
+#define SCM_FRAME_LOCALS_ADDRESS(fp) (SCM_FRAME_STRUCT (fp)->locals)
+
+#define SCM_FRAME_PREVIOUS_SP(fp) (((SCM *) (fp)) - 3)
+
+#define SCM_FRAME_RETURN_ADDRESS(fp) \
+ (SCM_FRAME_STRUCT (fp)->return_address)
+#define SCM_FRAME_SET_RETURN_ADDRESS(fp, ra) \
+ SCM_FRAME_STRUCT (fp)->return_address = (ra)
+#define SCM_FRAME_DYNAMIC_LINK(fp) \
+ (SCM_FRAME_STRUCT (fp)->dynamic_link)
+#define SCM_FRAME_SET_DYNAMIC_LINK(fp, dl) \
+ SCM_FRAME_DYNAMIC_LINK (fp) = (dl)
+#define SCM_FRAME_LOCAL(fp,i) \
+ (SCM_FRAME_STRUCT (fp)->locals[i])
+
+#define SCM_FRAME_NUM_LOCALS(fp, sp) \
+ ((sp) + 1 - &SCM_FRAME_LOCAL (fp, 0))
+
+/* Currently (November 2013) we keep the procedure and arguments in
+ their slots for the duration of the procedure call, regardless of
+ whether the values are live or not. This allows for backtraces that
+ show the closure and arguments. We may allow the compiler to relax
+ this restriction in the future, if the user so desires. This would
+ conserve stack space and make GC more precise. We would need better
+ debugging information to do that, however.
+
+ Even now there is an exception to the rule that slot 0 holds the
+ procedure, which is in the case of tail calls. The compiler will
+ emit code that shuffles the new procedure and arguments into position
+ before performing the tail call, so there is a window in which
+ SCM_FRAME_PROGRAM does not correspond to the program being executed.
+
+ The moral of the story is to use the IP in a frame to determine what
+ procedure is being called. It is only appropriate to use
+ SCM_FRAME_PROGRAM in the prologue of a procedure call, when you know
+ it must be there. */
+
+#define SCM_FRAME_PROGRAM(fp) (SCM_FRAME_LOCAL (fp, 0))
+
+\f
+
+/* FIXME: Replace SCM_FRAME_RETURN_ADDRESS with these. */
+#define SCM_FRAME_RTL_RETURN_ADDRESS(fp) \
+ ((scm_t_uint32 *) SCM_FRAME_RETURN_ADDRESS (fp))
+#define SCM_FRAME_SET_RTL_RETURN_ADDRESS(fp, ip) \
+ SCM_FRAME_SET_RETURN_ADDRESS (fp, (scm_t_uint8 *) (ip))