mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 20:00:19 +02:00
133 lines
3.5 KiB
C
133 lines
3.5 KiB
C
/*
|
|
* QuickThreads -- Threads-building toolkit.
|
|
* Copyright (c) 1993 by David Keppel
|
|
*
|
|
* Permission to use, copy, modify and distribute this software and
|
|
* its documentation for any purpose and without fee is hereby
|
|
* granted, provided that the above copyright notice and this notice
|
|
* appear in all copies. This software is provided as a
|
|
* proof-of-concept and for demonstration purposes; there is no
|
|
* representation about the suitability of this software for any
|
|
* purpose.
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
#include "qt.h"
|
|
|
|
|
|
/* Varargs is harder on the AXP. Parameters are saved on the stack as
|
|
something like (stack grows down to low memory; low at bottom of
|
|
picture):
|
|
|
|
| :
|
|
| arg6
|
|
+---
|
|
| iarg5
|
|
| :
|
|
| iarg3 <-- va_list._a0 + va_list._offset
|
|
| :
|
|
| iarg0 <-- va_list._a0
|
|
+---
|
|
| farg5
|
|
| :
|
|
| farg0
|
|
+---
|
|
|
|
When some of the arguments have known type, there is no need to
|
|
save all of them in the struct. So, for example, if the routine is
|
|
called
|
|
|
|
zork (int a0, float a1, int a2, ...)
|
|
{
|
|
va_list ap;
|
|
va_start (ap, a2);
|
|
qt_vargs (... &ap ...);
|
|
}
|
|
|
|
then offset is set to 3 * 8 (8 === sizeof machine word) = 24.
|
|
|
|
What this means for us is that the user's routine needs to be
|
|
called with an arg list where some of the words in the `any type'
|
|
parameter list have to be split and moved up in to the int/fp
|
|
region.
|
|
|
|
Ways in which this can fail:
|
|
- The user might not know the size of the pushed arguments anyway.
|
|
- Structures have funny promotion rules.
|
|
- Probably lots of other things.
|
|
|
|
All in all, we never promised varargs would work reliably. */
|
|
|
|
|
|
|
|
#define QT_VADJ(sp) (((char *)sp) - QT_VSTKBASE)
|
|
|
|
#define QT_VARGS_MD0(sp, vabytes) \
|
|
((qt_t *)(((char *)(sp)) - 6*2*8 - QT_STKROUNDUP(vabytes)))
|
|
|
|
extern void qt_vstart(void);
|
|
#define QT_VARGS_MD1(sp) (QT_SPUT (sp, QT_R26, qt_vstart))
|
|
|
|
|
|
/* Different machines use different implementations for varargs.
|
|
Unfortunately, the code below ``looks in to'' the varargs
|
|
structure, `va_list', and thus depends on the conventions.
|
|
The following #defines try to deal with it but don't catch
|
|
everything. */
|
|
|
|
#ifdef __GNUC__
|
|
#define _a0 __base
|
|
#define _offset __offset
|
|
#else
|
|
#ifdef __OSF1__
|
|
#define _a0 a0
|
|
#define _offset offset
|
|
#endif
|
|
#endif /* def __GNUC__ */
|
|
|
|
|
|
struct qt_t *
|
|
qt_vargs (struct qt_t *qsp, int nbytes, struct va_list *vargs,
|
|
void *pt, qt_function_t *startup,
|
|
qt_function_t *vuserf, qt_function_t *cleanup)
|
|
{
|
|
va_list ap;
|
|
int i;
|
|
int max; /* Maximum *words* of args to copy. */
|
|
int tmove; /* *Words* of args moved typed->typed. */
|
|
qt_word_t *sp;
|
|
|
|
ap = *(va_list *)vargs;
|
|
qsp = QT_VARGS_MD0 (qsp, nbytes);
|
|
sp = (qt_word_t *)qsp;
|
|
|
|
tmove = 6 - ap._offset/sizeof(qt_word_t);
|
|
|
|
/* Copy from one typed area to the other. */
|
|
for (i=0; i<tmove; ++i) {
|
|
/* Integer args: */
|
|
sp[i+6] = ((qt_word_t *)(ap._a0 + ap._offset))[i];
|
|
/* Fp args: */
|
|
sp[i] = ((qt_word_t *)(ap._a0 + ap._offset))[i-6];
|
|
}
|
|
|
|
max = nbytes/sizeof(qt_word_t);
|
|
|
|
/* Copy from the untyped area to the typed area. Split each arg.
|
|
in to integer and floating-point save areas. */
|
|
for (; i<6 && i<max; ++i) {
|
|
sp[i] = sp[i+6] = ((qt_word_t *)(ap._a0 + ap._offset))[i];
|
|
}
|
|
|
|
/* Copy from the untyped area to the other untyped area. */
|
|
for (; i<max; ++i) {
|
|
sp[i+6] = ((qt_word_t *)(ap._a0 + ap._offset))[i];
|
|
}
|
|
|
|
QT_VARGS_MD1 (QT_VADJ(sp));
|
|
QT_SPUT (QT_VADJ(sp), QT_VARGT_INDEX, pt);
|
|
QT_SPUT (QT_VADJ(sp), QT_VSTARTUP_INDEX, startup);
|
|
QT_SPUT (QT_VADJ(sp), QT_VUSERF_INDEX, vuserf);
|
|
QT_SPUT (QT_VADJ(sp), QT_VCLEANUP_INDEX, cleanup);
|
|
return ((qt_t *)QT_VADJ(sp));
|
|
}
|