mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 00:11:26 +00:00
Rewrite of invocation code with new mframe code.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@2930 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
517bb29e48
commit
be3ff6a3e3
5 changed files with 1150 additions and 872 deletions
659
Source/mframe.m
659
Source/mframe.m
|
@ -36,24 +36,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* Modifications to fix return of floats, doubles, and structures
|
||||
by Richard Frith-Macdonald <richard@brainstorm.co.uk> 1997
|
||||
|
||||
I define STRUCT_ADDR_ON_STACK if functions returns structures, unions
|
||||
and arrays by writing directly to a location passed to them as their
|
||||
first argument. If this is the case then all the visible arguments
|
||||
are displaced in the arg frame by the size of a pointer.
|
||||
|
||||
On GNU/Linux intel, this scheme does not apply where the structures
|
||||
are 8 bytes or smaller! I define SMALL_STRUCT_ON_STACK to the
|
||||
threshold above which the pointer needs to be placed on the stack.
|
||||
|
||||
I don't know which machines work this way, so you need to alter the
|
||||
define by hand as suits you. */
|
||||
|
||||
#define STRUCT_ADDR_ON_STACK 1
|
||||
#define SMALL_STRUCT_ON_STACK 8
|
||||
|
||||
/* Deal with strrchr: */
|
||||
#if STDC_HEADERS || HAVE_STRING_H
|
||||
#include <string.h>
|
||||
|
@ -90,18 +72,357 @@
|
|||
value. The code doesn't currently handle that case.
|
||||
*/
|
||||
|
||||
/* Do we need separate _PASSED_BY_REFERENCE and _RETURNED_BY_REFERENCE? */
|
||||
|
||||
#if (sparc) || (hppa) || (AM29K)
|
||||
#define MFRAME_STRUCTURES_PASSED_BY_REFERENCE 1
|
||||
#else
|
||||
#define MFRAME_STRUCTURES_PASSED_BY_REFERENCE 0
|
||||
#endif
|
||||
char*
|
||||
mframe_build_signature(const char *typePtr, int *size, int *narg, char *buf)
|
||||
{
|
||||
MFRAME_ARGS cum;
|
||||
BOOL doMalloc = NO;
|
||||
const char *types;
|
||||
char *start;
|
||||
char *dest;
|
||||
int total = 0;
|
||||
int count = 0;
|
||||
|
||||
/*
|
||||
* If we have not been given a buffer - allocate space on the stack for
|
||||
* the largest concievable type encoding.
|
||||
*/
|
||||
if (buf == 0) {
|
||||
doMalloc = YES;
|
||||
buf = alloca((strlen(typePtr)+1)*16);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the return type info (including qualifiers) into the buffer.
|
||||
*/
|
||||
types = objc_skip_typespec(typePtr);
|
||||
strncpy(buf, typePtr, types - typePtr);
|
||||
buf[types-typePtr] = '\0';
|
||||
|
||||
/*
|
||||
* Point to the return type, initialise size of stack args, and skip
|
||||
* to the first argument.
|
||||
*/
|
||||
types = objc_skip_type_qualifiers(typePtr);
|
||||
MFRAME_INIT_ARGS(cum, types);
|
||||
types = objc_skip_typespec(types);
|
||||
if (*types == '+') {
|
||||
types++;
|
||||
}
|
||||
while (isdigit(*types)) {
|
||||
types++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Where to start putting encoding information - leave enough room for
|
||||
* the size of the stack args to be stored after the return type.
|
||||
*/
|
||||
start = &buf[strlen(buf)+10];
|
||||
dest = start;
|
||||
|
||||
/*
|
||||
* Now step through all the arguments - copy any type qualifiers, but
|
||||
* let the macro write all the other info into the buffer.
|
||||
*/
|
||||
while (types && *types) {
|
||||
const char *qual = types;
|
||||
|
||||
/*
|
||||
* If there are any type qualifiers - copy the through to the
|
||||
* destination.
|
||||
*/
|
||||
types = objc_skip_type_qualifiers(types);
|
||||
while (qual < types) {
|
||||
*dest++ = *qual++;
|
||||
}
|
||||
MFRAME_ARG_ENCODING(cum, types, total, dest);
|
||||
count++;
|
||||
}
|
||||
*dest = '\0';
|
||||
|
||||
/*
|
||||
* Write the total size of the stack arguments after the return type,
|
||||
* then copy the remaining type information to fill the gap.
|
||||
*/
|
||||
sprintf(&buf[strlen(buf)], "%d", total);
|
||||
dest = &buf[strlen(buf)];
|
||||
while (*start) {
|
||||
*dest++ = *start++;
|
||||
}
|
||||
*dest = '\0';
|
||||
|
||||
/*
|
||||
* If we have written into a local buffer - we need to allocate memory
|
||||
* in which to return our result.
|
||||
*/
|
||||
if (doMalloc) {
|
||||
char *tmp = objc_malloc(dest - buf + 1);
|
||||
|
||||
strcpy(tmp, buf);
|
||||
buf = tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the caller wants to know the total size of the stack and/or the
|
||||
* number of arguments, return them in the appropriate variables.
|
||||
*/
|
||||
if (size) {
|
||||
*size = total;
|
||||
}
|
||||
if (narg) {
|
||||
*narg = count;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
#define ROUND(V, A) \
|
||||
({ typeof(V) __v=(V); typeof(A) __a=(A); \
|
||||
__a*((__v+__a-1)/__a); })
|
||||
/*
|
||||
* Step through method encoding information extracting details.
|
||||
*/
|
||||
const char *
|
||||
mframe_next_arg(const char *typePtr, NSArgumentInfo *info)
|
||||
{
|
||||
NSArgumentInfo local;
|
||||
BOOL flag;
|
||||
|
||||
if (info == 0) {
|
||||
info = &local;
|
||||
}
|
||||
/*
|
||||
* Skip past any type qualifiers - if the caller wants them, return them.
|
||||
*/
|
||||
flag = YES;
|
||||
info->qual = 0;
|
||||
while (flag) {
|
||||
switch (*typePtr) {
|
||||
case _C_CONST: info->qual |= _F_CONST; break;
|
||||
case _C_IN: info->qual |= _F_IN; break;
|
||||
case _C_INOUT: info->qual |= _F_INOUT; break;
|
||||
case _C_OUT: info->qual |= _F_OUT; break;
|
||||
case _C_BYCOPY: info->qual |= _F_BYCOPY; break;
|
||||
#ifdef _C_BYREF
|
||||
case _C_BYREF: info->qual |= _F_BYREF; break;
|
||||
#endif
|
||||
case _C_ONEWAY: info->qual |= _F_ONEWAY; break;
|
||||
default: flag = NO;
|
||||
}
|
||||
if (flag) {
|
||||
typePtr++;
|
||||
}
|
||||
}
|
||||
|
||||
info->type = typePtr;
|
||||
|
||||
/*
|
||||
* Scan for size and alignment information.
|
||||
*/
|
||||
switch (*typePtr++) {
|
||||
case _C_ID:
|
||||
info->size = sizeof(id);
|
||||
info->align = __alignof__(id);
|
||||
break;
|
||||
|
||||
case _C_CLASS:
|
||||
info->size = sizeof(Class);
|
||||
info->align = __alignof__(Class);
|
||||
break;
|
||||
|
||||
case _C_SEL:
|
||||
info->size = sizeof(SEL);
|
||||
info->align = __alignof__(SEL);
|
||||
break;
|
||||
|
||||
case _C_CHR:
|
||||
info->size = sizeof(char);
|
||||
info->align = __alignof__(char);
|
||||
break;
|
||||
|
||||
case _C_UCHR:
|
||||
info->size = sizeof(unsigned char);
|
||||
info->align = __alignof__(unsigned char);
|
||||
break;
|
||||
|
||||
case _C_SHT:
|
||||
info->size = sizeof(short);
|
||||
info->align = __alignof__(short);
|
||||
break;
|
||||
|
||||
case _C_USHT:
|
||||
info->size = sizeof(unsigned short);
|
||||
info->align = __alignof__(unsigned short);
|
||||
break;
|
||||
|
||||
case _C_INT:
|
||||
info->size = sizeof(int);
|
||||
info->align = __alignof__(int);
|
||||
break;
|
||||
|
||||
case _C_UINT:
|
||||
info->size = sizeof(unsigned int);
|
||||
info->align = __alignof__(unsigned int);
|
||||
break;
|
||||
|
||||
case _C_LNG:
|
||||
info->size = sizeof(long);
|
||||
info->align = __alignof__(long);
|
||||
break;
|
||||
|
||||
case _C_ULNG:
|
||||
info->size = sizeof(unsigned long);
|
||||
info->align = __alignof__(unsigned long);
|
||||
break;
|
||||
|
||||
case _C_FLT:
|
||||
info->size = sizeof(float);
|
||||
info->align = __alignof__(float);
|
||||
break;
|
||||
|
||||
case _C_DBL:
|
||||
info->size = sizeof(double);
|
||||
info->align = __alignof__(double);
|
||||
break;
|
||||
|
||||
case _C_PTR:
|
||||
info->size = sizeof(char*);
|
||||
info->align = __alignof__(char*);
|
||||
typePtr = mframe_next_arg(typePtr, &local);
|
||||
info->isReg = local.isReg;
|
||||
info->offset = local.offset;
|
||||
break;
|
||||
|
||||
case _C_ATOM:
|
||||
case _C_CHARPTR:
|
||||
info->size = sizeof(char*);
|
||||
info->align = __alignof__(char*);
|
||||
break;
|
||||
|
||||
case _C_ARY_B:
|
||||
{
|
||||
int length = atoi(typePtr);
|
||||
|
||||
while (isdigit(*typePtr)) {
|
||||
typePtr++;
|
||||
}
|
||||
typePtr = mframe_next_arg(typePtr, &local);
|
||||
info->size = length * ROUND(local.size, local.align);
|
||||
info->align = local.align;
|
||||
typePtr++; /* Skip end-of-array */
|
||||
}
|
||||
break;
|
||||
|
||||
case _C_STRUCT_B:
|
||||
{
|
||||
struct { int x; double y; } fooalign;
|
||||
int acc_size = 0;
|
||||
int acc_align = __alignof__(fooalign);
|
||||
|
||||
/*
|
||||
* Skip "<name>=" stuff.
|
||||
*/
|
||||
while (*typePtr != _C_STRUCT_E) {
|
||||
if (*typePtr++ == '=') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Base structure alignment on first element.
|
||||
*/
|
||||
if (*typePtr != _C_STRUCT_E) {
|
||||
typePtr = mframe_next_arg(typePtr, &local);
|
||||
if (typePtr == 0) {
|
||||
return 0; /* error */
|
||||
}
|
||||
acc_size = ROUND(acc_size, local.align);
|
||||
acc_size += local.size;
|
||||
acc_align = MAX(local.align, __alignof__(fooalign));
|
||||
}
|
||||
/*
|
||||
* Continue accumulating structure size.
|
||||
*/
|
||||
while (*typePtr != _C_STRUCT_E) {
|
||||
typePtr = mframe_next_arg(typePtr, &local);
|
||||
if (typePtr == 0) {
|
||||
return 0; /* error */
|
||||
}
|
||||
acc_size = ROUND(acc_size, local.align);
|
||||
acc_size += local.size;
|
||||
}
|
||||
info->size = acc_size;
|
||||
info->align = acc_align;
|
||||
typePtr++; /* Skip end-of-struct */
|
||||
}
|
||||
break;
|
||||
|
||||
case _C_UNION_B:
|
||||
{
|
||||
int max_size = 0;
|
||||
int max_align = 0;
|
||||
|
||||
/*
|
||||
* Skip "<name>=" stuff.
|
||||
*/
|
||||
while (*typePtr != _C_UNION_E) {
|
||||
if (*typePtr++ == '=') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (*typePtr != _C_UNION_E) {
|
||||
typePtr = mframe_next_arg(typePtr, &local);
|
||||
if (typePtr == 0) {
|
||||
return 0; /* error */
|
||||
}
|
||||
max_size = MAX(max_size, local.size);
|
||||
max_align = MAX(max_align, local.align);
|
||||
}
|
||||
info->size = max_size;
|
||||
info->align = max_align;
|
||||
typePtr++; /* Skip end-of-union */
|
||||
}
|
||||
break;
|
||||
|
||||
case _C_VOID:
|
||||
info->size = 0;
|
||||
info->align = __alignof__(char*);
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (typePtr == 0) { /* Error condition. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we had a pointer argument, we will already have gathered
|
||||
* (and skipped past) the argframe offset information - so we
|
||||
* don't need to (and can't) do it here.
|
||||
*/
|
||||
if (*info->type != _C_PTR) {
|
||||
/*
|
||||
* May tell the caller if the item is stored in a register.
|
||||
*/
|
||||
if (*typePtr == '+') {
|
||||
typePtr++;
|
||||
info->isReg = YES;
|
||||
}
|
||||
else if (info->isReg) {
|
||||
info->isReg = NO;
|
||||
}
|
||||
|
||||
/*
|
||||
* May tell the caller what the stack/register offset is for
|
||||
* this argument.
|
||||
*/
|
||||
info->offset = 0;
|
||||
while (isdigit(*typePtr)) {
|
||||
info->offset = info->offset * 10 + (*typePtr++ - '0');
|
||||
}
|
||||
}
|
||||
|
||||
return typePtr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -145,17 +466,12 @@ method_types_get_size_of_register_arguments(const char *types)
|
|||
|
||||
/* To fix temporary bug in method_get_next_argument() on NeXT boxes */
|
||||
/* xxx Perhaps this isn't working with the NeXT runtime? */
|
||||
/* Uses 'offset' to adjust for a pointer used to return a structur */
|
||||
|
||||
char*
|
||||
method_types_get_next_argument (arglist_t argf,
|
||||
const char **type, int offset)
|
||||
method_types_get_next_argument (arglist_t argf, const char **type)
|
||||
{
|
||||
const char *t = objc_skip_argspec (*type);
|
||||
union {
|
||||
char *arg_ptr;
|
||||
char arg_regs[sizeof (char*)];
|
||||
} *argframe;
|
||||
arglist_t argframe;
|
||||
|
||||
argframe = (void*)argf;
|
||||
|
||||
|
@ -170,9 +486,9 @@ method_types_get_next_argument (arglist_t argf,
|
|||
else
|
||||
/* xxx What's going on here? This -8 needed on my 68k NeXT box. */
|
||||
#if NeXT
|
||||
return argframe->arg_ptr + offset + (atoi(t) - 8);
|
||||
return argframe->arg_ptr + (atoi(t) - 8);
|
||||
#else
|
||||
return argframe->arg_ptr + offset + atoi(t);
|
||||
return argframe->arg_ptr + atoi(t);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -200,28 +516,19 @@ mframe_dissect_call_opts (arglist_t argframe, const char *type,
|
|||
char *datum;
|
||||
int argnum;
|
||||
BOOL out_parameters = NO;
|
||||
int off = 0;
|
||||
|
||||
#ifdef STRUCT_ADDR_ON_STACK
|
||||
/* On machines which pass a pointer to a location for returning
|
||||
structures before the first real argument, we need to use an offset
|
||||
into the arg frame. */
|
||||
if (*type == _C_STRUCT_B || *type == _C_UNION_B || *type == _C_ARY_B) {
|
||||
int rsize = objc_sizeof_type(type);
|
||||
if (rsize > SMALL_STRUCT_ON_STACK) {
|
||||
off = sizeof(void*);
|
||||
}
|
||||
datum = alloca((strlen(type)+1)*10);
|
||||
type = mframe_build_signature(type, 0, 0, datum);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Enumerate all the arguments in ARGFRAME, and call ENCODER for
|
||||
each one. METHOD_TYPES_GET_NEXT_ARGUEMENT() returns 0 when
|
||||
there are no more arguments, otherwise it returns a pointer to the
|
||||
argument in the ARGFRAME. */
|
||||
|
||||
for (datum = method_types_get_next_argument(argframe, &type, off), argnum=0;
|
||||
for (datum = method_types_get_next_argument(argframe, &type), argnum=0;
|
||||
datum;
|
||||
datum = method_types_get_next_argument(argframe, &type, off), argnum++)
|
||||
datum = method_types_get_next_argument(argframe, &type), argnum++)
|
||||
{
|
||||
/* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */
|
||||
flags = objc_get_type_qualifiers(type);
|
||||
|
@ -288,9 +595,9 @@ mframe_dissect_call_opts (arglist_t argframe, const char *type,
|
|||
/* Handle struct and array arguments. */
|
||||
/* Whether DATUM points to the data, or points to a pointer
|
||||
that points to the data, depends on the value of
|
||||
MFRAME_STRUCTURES_PASSED_BY_REFERENCE. Do the right thing
|
||||
MFRAME_STRUCT_BYREF. Do the right thing
|
||||
so that ENCODER gets a pointer to directly to the data. */
|
||||
#if MFRAME_STRUCTURES_PASSED_BY_REFERENCE
|
||||
#if MFRAME_STRUCT_BYREF
|
||||
(*encoder) (argnum, *(void**)datum, type, flags);
|
||||
#else
|
||||
(*encoder) (argnum, datum, type, flags);
|
||||
|
@ -413,17 +720,8 @@ mframe_do_call_opts (const char *encoded_types,
|
|||
int stack_argsize;
|
||||
/* The number bytes for holding arguments passed in registers. */
|
||||
int reg_argsize;
|
||||
/* Offset for arguments on stack. */
|
||||
int off = 0;
|
||||
/* The structure for holding the arguments to the method. */
|
||||
#if NeXT_runtime
|
||||
union {
|
||||
char *arg_ptr;
|
||||
char arg_regs[sizeof (char*)];
|
||||
} *argframe;
|
||||
#else
|
||||
arglist_t argframe;
|
||||
#endif
|
||||
/* A pointer into the ARGFRAME; points at individual arguments. */
|
||||
char *datum;
|
||||
/* Type qualifier flags; see <objc/objc-api.h>. */
|
||||
|
@ -500,23 +798,22 @@ mframe_do_call_opts (const char *encoded_types,
|
|||
NSCParameterAssert (type);
|
||||
NSCParameterAssert (sel_types_match(encoded_types, type));
|
||||
|
||||
#ifdef STRUCT_ADDR_ON_STACK
|
||||
/* On machines which pass a pointer to a location for returning
|
||||
structures before the first real argument, we need to use an offset
|
||||
into the arg frame. */
|
||||
/*
|
||||
* The compiler/runtime doesn't always seem to get the encoding right
|
||||
* for our purposes - so we generate our own encoding as required by
|
||||
* __builtin_apply().
|
||||
*/
|
||||
if (*type == _C_STRUCT_B || *type == _C_UNION_B || *type == _C_ARY_B) {
|
||||
if (objc_sizeof_type(type) > SMALL_STRUCT_ON_STACK) {
|
||||
off = sizeof(void*);
|
||||
}
|
||||
tmptype = alloca((strlen(type)+1)*10);
|
||||
type = mframe_build_signature(type, 0, 0, (char*)tmptype);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Allocate an argframe, using memory on the stack */
|
||||
|
||||
/* Calculate the amount of memory needed for storing variables that
|
||||
are passed in registers, and the amount of memory for storing
|
||||
variables that are passed on the stack. */
|
||||
stack_argsize = off + method_types_get_size_of_stack_arguments (type);
|
||||
stack_argsize = method_types_get_size_of_stack_arguments (type);
|
||||
reg_argsize = method_types_get_size_of_register_arguments (type);
|
||||
/* Allocate the space for variables passed in registers. */
|
||||
argframe = (arglist_t) alloca(sizeof(char*) + reg_argsize);
|
||||
|
@ -527,10 +824,12 @@ mframe_do_call_opts (const char *encoded_types,
|
|||
argframe->arg_ptr = 0;
|
||||
|
||||
if (*type == _C_STRUCT_B || *type == _C_UNION_B || *type == _C_ARY_B) {
|
||||
void *buf;
|
||||
|
||||
/* If we are passing a pointer to return a structure in, we must allocate
|
||||
the memory for it and put it at the start of the argframe. */
|
||||
if (stack_argsize)
|
||||
*(void**)argframe->arg_ptr = alloca(objc_sizeof_type(type));
|
||||
the memory for it and put it in the correct place in the argframe. */
|
||||
buf = alloca(objc_sizeof_type(type));
|
||||
MFRAME_SET_STRUCT_ADDR(argframe, type, buf);
|
||||
}
|
||||
|
||||
/* Put OBJECT and SELECTOR into the ARGFRAME. */
|
||||
|
@ -540,15 +839,15 @@ mframe_do_call_opts (const char *encoded_types,
|
|||
etmptype = objc_skip_argspec (encoded_types);
|
||||
/* Get a pointer into ARGFRAME, pointing to the location where the
|
||||
first argument is to be stored. */
|
||||
datum = method_types_get_next_argument (argframe, &tmptype, off);
|
||||
datum = method_types_get_next_argument (argframe, &tmptype);
|
||||
NSCParameterAssert (datum);
|
||||
NSCParameterAssert (*tmptype == _C_ID);
|
||||
/* Put the target object there. */
|
||||
*(id*)datum = object;
|
||||
/* Get a pionter into ARGFRAME, pointing to the location where the
|
||||
/* Get a pointer into ARGFRAME, pointing to the location where the
|
||||
second argument is to be stored. */
|
||||
etmptype = objc_skip_argspec(etmptype);
|
||||
datum = method_types_get_next_argument(argframe, &tmptype, off);
|
||||
datum = method_types_get_next_argument(argframe, &tmptype);
|
||||
NSCParameterAssert (datum);
|
||||
NSCParameterAssert (*tmptype == _C_SEL);
|
||||
/* Put the selector there. */
|
||||
|
@ -559,10 +858,10 @@ mframe_do_call_opts (const char *encoded_types,
|
|||
ARGFRAME. Step TMPTYPE and ETMPTYPE in lock-step through their
|
||||
method type strings. */
|
||||
|
||||
for (datum = method_types_get_next_argument (argframe, &tmptype, off),
|
||||
for (datum = method_types_get_next_argument (argframe, &tmptype),
|
||||
etmptype = objc_skip_argspec (etmptype), argnum = 2;
|
||||
datum;
|
||||
datum = method_types_get_next_argument (argframe, &tmptype, off),
|
||||
datum = method_types_get_next_argument (argframe, &tmptype),
|
||||
etmptype = objc_skip_argspec (etmptype), argnum++)
|
||||
{
|
||||
/* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */
|
||||
|
@ -640,9 +939,9 @@ mframe_do_call_opts (const char *encoded_types,
|
|||
/* Handle struct and array arguments. */
|
||||
/* Whether DATUM points to the data, or points to a pointer
|
||||
that points to the data, depends on the value of
|
||||
MFRAME_STRUCTURES_PASSED_BY_REFERENCE. Do the right thing
|
||||
MFRAME_STRUCT_BYREF. Do the right thing
|
||||
so that ENCODER gets a pointer to directly to the data. */
|
||||
#if MFRAME_STRUCTURES_PASSED_BY_REFERENCE
|
||||
#if MFRAME_STRUCT_BYREF
|
||||
/* Allocate some memory to be pointed to, and to hold the
|
||||
data. Note that it is allocated on the stack, and
|
||||
methods that want to keep the data pointed to, will have
|
||||
|
@ -727,18 +1026,7 @@ mframe_do_call_opts (const char *encoded_types,
|
|||
case _C_ARY_B:
|
||||
/* The argument is a structure or array returned by value.
|
||||
(In C, are array's allowed to be returned by value?) */
|
||||
/* xxx Does MFRAME_STRUCTURES_PASSED_BY_REFERENCE have
|
||||
anything to do with how structures are returned? What about
|
||||
struct's that are smaller than sizeof(void*)? Are they also
|
||||
returned by reference like this? */
|
||||
/* If 'off' is non-zero, the pointer to the stored structure is at
|
||||
the start of the arg frame rather than in retframe. */
|
||||
if (off)
|
||||
(*encoder) (-1, *(void**)argframe->arg_ptr, tmptype, flags);
|
||||
else
|
||||
{
|
||||
(*encoder) (-1, *(void**)retframe, tmptype, flags);
|
||||
}
|
||||
(*encoder)(-1, MFRAME_GET_STRUCT_ADDR(argframe, tmptype), tmptype, flags);
|
||||
break;
|
||||
|
||||
case _C_FLT:
|
||||
|
@ -797,11 +1085,11 @@ mframe_do_call_opts (const char *encoded_types,
|
|||
{
|
||||
/* Step through all the arguments, finding the ones that were
|
||||
passed by reference. */
|
||||
for (datum = method_types_get_next_argument (argframe, &tmptype, off),
|
||||
for (datum = method_types_get_next_argument (argframe, &tmptype),
|
||||
argnum = 1,
|
||||
etmptype = objc_skip_argspec (etmptype);
|
||||
datum;
|
||||
datum = method_types_get_next_argument (argframe, &tmptype, off),
|
||||
datum = method_types_get_next_argument (argframe, &tmptype),
|
||||
argnum++,
|
||||
etmptype = objc_skip_argspec (etmptype))
|
||||
{
|
||||
|
@ -892,7 +1180,6 @@ mframe_build_return_opts (arglist_t argframe,
|
|||
const char *tmptype;
|
||||
/* A pointer into the ARGFRAME; points at individual arguments. */
|
||||
void *datum;
|
||||
int off = 0;
|
||||
const char *rettype;
|
||||
/* For returning strucutres etc */
|
||||
typedef struct { id many[8];} __big;
|
||||
|
@ -946,23 +1233,15 @@ mframe_build_return_opts (arglist_t argframe,
|
|||
return __builtin_apply((apply_t)return_short, args, sizeof(void*));
|
||||
}
|
||||
|
||||
if (*type == _C_STRUCT_B || *type == _C_UNION_B || *type == _C_ARY_B) {
|
||||
tmptype = alloca((strlen(type)+1)*10);
|
||||
type = mframe_build_signature(type, 0, 0, (char*)tmptype);
|
||||
}
|
||||
/* Get the return type qualifier flags, and the return type. */
|
||||
flags = objc_get_type_qualifiers(type);
|
||||
tmptype = objc_skip_type_qualifiers(type);
|
||||
rettype = tmptype;
|
||||
|
||||
#ifdef STRUCT_ADDR_ON_STACK
|
||||
/* On machines which pass a pointer to a location for returning
|
||||
structures before the first real argument, we need to use an offset
|
||||
into the arg frame. */
|
||||
if (*rettype==_C_STRUCT_B || *rettype==_C_UNION_B || *rettype==_C_ARY_B) {
|
||||
int rsize = objc_sizeof_type(type);
|
||||
if (rsize > SMALL_STRUCT_ON_STACK) {
|
||||
off = sizeof(void*);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Decode the return value and pass-by-reference values, if there
|
||||
are any. OUT_PARAMETERS should be the value returned by
|
||||
mframe_dissect_call(). */
|
||||
|
@ -1018,18 +1297,7 @@ mframe_build_return_opts (arglist_t argframe,
|
|||
case _C_ARY_B:
|
||||
/* The argument is a structure or array returned by value.
|
||||
(In C, are array's allowed to be returned by value?) */
|
||||
/* xxx Does MFRAME_STRUCTURES_PASSED_BY_REFERENCE
|
||||
have anything to do with how structures are returned?
|
||||
What about struct's that are smaller than
|
||||
sizeof(void*)? Are they also returned by reference
|
||||
like this? */
|
||||
if (off)
|
||||
/* If we have been given a pointer to a location to return
|
||||
the structure in, use it. */
|
||||
*(void**)retframe = *(void**)argframe->arg_ptr;
|
||||
else
|
||||
/* Allocate some memory to hold the struct or array. */
|
||||
*(void**)retframe = alloca (objc_sizeof_type (tmptype));
|
||||
*(void**)retframe = MFRAME_GET_STRUCT_ADDR(argframe, tmptype);
|
||||
/* Decode the return value into the memory we allocated. */
|
||||
(*decoder) (-1, *(void**)retframe, tmptype, flags);
|
||||
break;
|
||||
|
@ -1079,10 +1347,10 @@ mframe_build_return_opts (arglist_t argframe,
|
|||
{
|
||||
/* Step through all the arguments, finding the ones that were
|
||||
passed by reference. */
|
||||
for (datum = method_types_get_next_argument(argframe, &tmptype, off),
|
||||
for (datum = method_types_get_next_argument(argframe, &tmptype),
|
||||
argnum=0;
|
||||
datum;
|
||||
(datum = method_types_get_next_argument(argframe, &tmptype, off)),
|
||||
(datum = method_types_get_next_argument(argframe, &tmptype)),
|
||||
argnum++)
|
||||
{
|
||||
/* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */
|
||||
|
@ -1151,11 +1419,11 @@ mframe_build_return_opts (arglist_t argframe,
|
|||
case _C_SHT:
|
||||
case _C_USHT:
|
||||
return apply_short(*(short*)retframe);
|
||||
#if 1
|
||||
#if 0
|
||||
case _C_ARY_B:
|
||||
case _C_UNION_B:
|
||||
case _C_STRUCT_B:
|
||||
if (off == 0 && objc_sizeof_type(rettype) > 8) {
|
||||
if (objc_sizeof_type(rettype) > 8) {
|
||||
return apply_block(*(void**)retframe);
|
||||
}
|
||||
#endif
|
||||
|
@ -1174,6 +1442,52 @@ mframe_build_return (arglist_t argframe,
|
|||
return mframe_build_return_opts(argframe,type,out_parameters,decoder,NO);
|
||||
}
|
||||
|
||||
|
||||
|
||||
arglist_t
|
||||
mframe_create_argframe(const char *types, void** retbuf)
|
||||
{
|
||||
arglist_t argframe = objc_calloc(MFRAME_ARGS_SIZE, 1);
|
||||
const char* rtype = objc_skip_type_qualifiers(types);
|
||||
int stack_argsize = atoi(objc_skip_typespec(rtype));
|
||||
|
||||
/*
|
||||
* Allocate the space for variables passed on the stack.
|
||||
*/
|
||||
if (stack_argsize) {
|
||||
argframe->arg_ptr = objc_calloc(stack_argsize, 1);
|
||||
}
|
||||
else {
|
||||
argframe->arg_ptr = 0;
|
||||
}
|
||||
if (*rtype == _C_STRUCT_B || *rtype == _C_UNION_B || *rtype == _C_ARY_B) {
|
||||
/*
|
||||
* If we haven't been passed a pointer to the location in which
|
||||
* to store a returned structure - allocate space and return
|
||||
* the address of the allocated space.
|
||||
*/
|
||||
if (*retbuf == 0) {
|
||||
*retbuf = objc_calloc(objc_sizeof_type(rtype), 1);
|
||||
}
|
||||
MFRAME_SET_STRUCT_ADDR(argframe, rtype, *retbuf);
|
||||
}
|
||||
return argframe;
|
||||
}
|
||||
|
||||
void
|
||||
mframe_destroy_argframe(const char *types, arglist_t argframe)
|
||||
{
|
||||
const char* rtype = objc_skip_type_qualifiers(types);
|
||||
int stack_argsize = atoi(objc_skip_typespec(rtype));
|
||||
|
||||
if (stack_argsize) {
|
||||
objc_free(argframe->arg_ptr);
|
||||
}
|
||||
objc_free(argframe);
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOL
|
||||
mframe_decode_return (const char *type, void* buffer, void* retframe)
|
||||
{
|
||||
|
@ -1313,3 +1627,104 @@ mframe_decode_return (const char *type, void* buffer, void* retframe)
|
|||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void*
|
||||
mframe_handle_return(const char* type, void* retval, arglist_t argframe)
|
||||
{
|
||||
retval_t retframe;
|
||||
typedef struct { id many[8];} __big;
|
||||
__big return_block (void* data)
|
||||
{
|
||||
return *(__big*)data;
|
||||
}
|
||||
/* For returning a char (or unsigned char) */
|
||||
char return_char (char data)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
/* For returning a double */
|
||||
double return_double (double data)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
/* For returning a float */
|
||||
float return_float (float data)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
/* For returning a short (or unsigned short) */
|
||||
short return_short (short data)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
retval_t apply_block(void* data)
|
||||
{
|
||||
void* args = __builtin_apply_args();
|
||||
return __builtin_apply((apply_t)return_block, args, sizeof(void*));
|
||||
}
|
||||
retval_t apply_char(char data)
|
||||
{
|
||||
void* args = __builtin_apply_args();
|
||||
return __builtin_apply((apply_t)return_char, args, sizeof(void*));
|
||||
}
|
||||
retval_t apply_float(float data)
|
||||
{
|
||||
void* args = __builtin_apply_args();
|
||||
return __builtin_apply((apply_t)return_float, args, sizeof(float));
|
||||
}
|
||||
retval_t apply_double(double data)
|
||||
{
|
||||
void* args = __builtin_apply_args();
|
||||
return __builtin_apply((apply_t)return_double, args, sizeof(double));
|
||||
}
|
||||
retval_t apply_short(short data)
|
||||
{
|
||||
void* args = __builtin_apply_args();
|
||||
return __builtin_apply((apply_t)return_short, args, sizeof(void*));
|
||||
}
|
||||
|
||||
retframe = alloca(MFRAME_RESULT_SIZE);
|
||||
|
||||
switch (*type) {
|
||||
case _C_VOID:
|
||||
break;
|
||||
case _C_CHR:
|
||||
case _C_UCHR:
|
||||
return apply_char(*(char*)retval);
|
||||
case _C_DBL:
|
||||
return apply_double(*(double*)retval);
|
||||
case _C_FLT:
|
||||
return apply_float(*(float*)retval);
|
||||
case _C_SHT:
|
||||
case _C_USHT:
|
||||
return apply_short(*(short*)retval);
|
||||
case _C_ARY_B:
|
||||
case _C_UNION_B:
|
||||
case _C_STRUCT_B:
|
||||
{
|
||||
int size = objc_sizeof_type(type);
|
||||
#if 1
|
||||
void *dest;
|
||||
|
||||
dest = MFRAME_GET_STRUCT_ADDR(argframe, type);
|
||||
memcpy(dest, retval, size);
|
||||
#else
|
||||
if (size > 8) {
|
||||
return apply_block(*(void**)retval);
|
||||
}
|
||||
else {
|
||||
memcpy(retframe, retval, size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
memcpy(retframe, retval, objc_sizeof_type(type));
|
||||
break;
|
||||
}
|
||||
|
||||
return retframe;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue