Skip to content

Commit

Permalink
alpha: Add support for Go closures
Browse files Browse the repository at this point in the history
  • Loading branch information
rth7680 committed Nov 12, 2014
1 parent f41bec3 commit 9761b7b
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 37 deletions.
53 changes: 43 additions & 10 deletions src/alpha/ffi.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@
# define FFI_TYPE_LONGDOUBLE 4
#endif

extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)(void))
FFI_HIDDEN;
extern void ffi_call_osf(void *stack, void *frame, unsigned flags,
void *raddr, void (*fn)(void), void *closure)
FFI_HIDDEN;
extern void ffi_closure_osf(void) FFI_HIDDEN;
extern void ffi_go_closure_osf(void) FFI_HIDDEN;

/* Promote a float value to its in-register double representation.
Unlike actually casting to double, this does not trap on NaN. */
Expand Down Expand Up @@ -222,12 +224,14 @@ extend_basic_type(void *valp, int type, int argn)
}
}

void
ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
static void
ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
void **avalue, void *closure)
{
unsigned long *argp;
long i, avn, argn, flags = cif->flags;
ffi_type **arg_types;
void *frame;

/* If the return value is a struct and we don't have a return
value address then we need to make one. */
Expand All @@ -236,7 +240,8 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)

/* Allocate the space for the arguments, plus 4 words of temp
space for ffi_call_osf. */
argp = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
argp = frame = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
frame += cif->bytes;

argn = 0;
if (flags == ALPHA_RET_IN_MEM)
Expand Down Expand Up @@ -301,9 +306,21 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
}

flags = (flags >> ALPHA_ST_SHIFT) & 0xff;
ffi_call_osf(argp, cif->bytes, flags, rvalue, fn);
ffi_call_osf(argp, frame, flags, rvalue, fn, closure);
}

void
ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
ffi_call_int(cif, fn, rvalue, avalue, NULL);
}

void
ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
void **avalue, void *closure)
{
ffi_call_int(cif, fn, rvalue, avalue, closure);
}

ffi_status
ffi_prep_closure_loc (ffi_closure* closure,
Expand Down Expand Up @@ -339,15 +356,31 @@ ffi_prep_closure_loc (ffi_closure* closure,
return FFI_OK;
}

ffi_status
ffi_prep_go_closure (ffi_go_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*))
{
if (cif->abi != FFI_OSF)
return FFI_BAD_ABI;

closure->tramp = (void *)ffi_go_closure_osf;
closure->cif = cif;
closure->fun = fun;

return FFI_OK;
}

long FFI_HIDDEN
ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
ffi_closure_osf_inner (ffi_cif *cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data,
void *rvalue, unsigned long *argp)
{
ffi_cif *cif;
void **avalue;
ffi_type **arg_types;
long i, avn, argn, flags;

cif = closure->cif;
avalue = alloca(cif->nargs * sizeof(void *));
flags = cif->flags;
argn = 0;
Expand Down Expand Up @@ -481,7 +514,7 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
}

/* Invoke the closure. */
closure->fun (cif, rvalue, avalue, closure->user_data);
fun (cif, rvalue, avalue, user_data);

/* Tell ffi_closure_osf how to perform return type promotions. */
return (flags >> ALPHA_LD_SHIFT) & 0xff;
Expand Down
1 change: 1 addition & 0 deletions src/alpha/ffitarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ typedef enum ffi_abi {
/* ---- Definitions for closures ----------------------------------------- */

#define FFI_CLOSURES 1
#define FFI_GO_CLOSURES 1
#define FFI_TRAMPOLINE_SIZE 24
#define FFI_NATIVE_RAW_API 0

Expand Down
82 changes: 55 additions & 27 deletions src/alpha/osf.S
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@
.org 99b + \index * 16
.endm

/* ffi_call_osf (void *args, unsigned long bytes, unsigned flags,
void *raddr, void (*fnaddr)(void));
/* ffi_call_osf (void *stack, void *frame, unsigned flags,
void *raddr, void (*fnaddr)(void), void *closure)
Bit o trickiness here -- ARGS+BYTES is the base of the stack frame
Bit o trickiness here -- FRAME is the base of the stack frame
for this function. This has been allocated by ffi_call. We also
deallocate some of the stack that has been alloca'd. */

Expand All @@ -52,22 +52,21 @@
FFI_HIDDEN(ffi_call_osf)

ffi_call_osf:
.frame $15, 32, $26, 0
.mask 0x4008000, -32
cfi_startproc
addq $16,$17,$1
cfi_def_cfa($17, 32)
mov $16, $30
stq $26, 0($1)
stq $15, 8($1)
stq $18, 16($1)
mov $1, $15
stq $26, 0($17)
stq $15, 8($17)
mov $17, $15
.prologue 0
cfi_def_cfa($15, 32)
cfi_def_cfa_register($15)
cfi_rel_offset($26, 0)
cfi_rel_offset($15, 8)

stq $19, 24($1)
mov $20, $27
stq $18, 16($17) # save flags into frame
stq $19, 24($17) # save rvalue into frame
mov $20, $27 # fn into place for call
mov $21, $1 # closure into static chain

# Load up all of the (potential) argument registers.
ldq $16, 0($30)
Expand All @@ -89,16 +88,16 @@ ffi_call_osf:
jsr $26, ($27), 0
0:
ldah $29, 0($26) !gpdisp!1
ldq $2, 24($15)
ldq $2, 24($15) # reload rvalue
lda $29, 0($29) !gpdisp!1
ldq $3, 16($15)
ldq $3, 16($15) # reload flags
lda $1, 99f-0b($26)
ldq $26, 0($15)
ldq $15, 8($15)
cfi_restore($26)
cfi_restore($15)
cfi_def_cfa($sp, 0)
cmoveq $2, ALPHA_ST_VOID, $3 # mash null return to void
cmoveq $2, ALPHA_ST_VOID, $3 # mash null rvalue to void
addq $3, $3, $3
s8addq $3, $1, $1 # 99f + stcode * 16
jmp $31, ($1), $st_int
Expand Down Expand Up @@ -135,14 +134,38 @@ E ALPHA_ST_CPLXD

#define CLOSURE_FS (16*8)

.align 4
.globl ffi_go_closure_osf
.ent ffi_go_closure_osf
FFI_HIDDEN(ffi_go_closure_osf)

ffi_go_closure_osf:
cfi_startproc
ldgp $29, 0($27)
subq $30, CLOSURE_FS, $30
cfi_adjust_cfa_offset(CLOSURE_FS)
stq $26, 0($30)
.prologue 1
cfi_rel_offset($26, 0)

stq $16, 10*8($30)
stq $17, 11*8($30)
stq $18, 12*8($30)

ldq $16, 8($1) # load cif
ldq $17, 16($1) # load fun
mov $1, $18 # closure is user_data
br $do_closure

cfi_endproc
.end ffi_go_closure_osf

.align 4
.globl ffi_closure_osf
.ent ffi_closure_osf
FFI_HIDDEN(ffi_closure_osf)

ffi_closure_osf:
.frame $30, CLOSURE_FS, $26, 0
.mask 0x4000000, -CLOSURE_FS
cfi_startproc
ldgp $29, 0($27)
subq $30, CLOSURE_FS, $30
Expand All @@ -152,23 +175,28 @@ ffi_closure_osf:
cfi_rel_offset($26, 0)

# Store all of the potential argument registers in va_list format.
stt $f16, 4*8($30)
stt $f17, 5*8($30)
stt $f18, 6*8($30)
stt $f19, 7*8($30)
stt $f20, 8*8($30)
stt $f21, 9*8($30)
stq $16, 10*8($30)
stq $17, 11*8($30)
stq $18, 12*8($30)

ldq $16, 24($1) # load cif
ldq $17, 32($1) # load fun
ldq $18, 40($1) # load user_data

$do_closure:
stq $19, 13*8($30)
stq $20, 14*8($30)
stq $21, 15*8($30)
stt $f16, 4*8($30)
stt $f17, 5*8($30)
stt $f18, 6*8($30)
stt $f19, 7*8($30)
stt $f20, 8*8($30)
stt $f21, 9*8($30)

# Call ffi_closure_osf_inner to do the bulk of the work.
mov $1, $16
lda $17, 2*8($30)
lda $18, 10*8($30)
lda $19, 2*8($30)
lda $20, 10*8($30)
jsr $26, ffi_closure_osf_inner
0:
ldah $29, 0($26) !gpdisp!2
Expand Down

0 comments on commit 9761b7b

Please sign in to comment.