2005-02-22 11:22:44 +00:00
|
|
|
|
/** Implementation of functions for dissecting/making method calls
|
1998-11-02 10:55:53 +00:00
|
|
|
|
Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1996-04-17 20:17:45 +00:00
|
|
|
|
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
1996-03-30 01:29:07 +00:00
|
|
|
|
Created: Oct 1994
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
|
This file is part of the GNUstep Base Library.
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
Library General Public License for more details.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
|
|
|
License along with this library; if not, write to the Free
|
2005-05-22 03:32:16 +00:00
|
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
*/
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
|
|
|
|
/* These functions can be used for dissecting and making method calls
|
|
|
|
|
for many different situations. They are used for distributed
|
|
|
|
|
objects; they could also be used to make interfaces between
|
1996-03-30 01:29:07 +00:00
|
|
|
|
Objective C and Scheme, Perl, Tcl, or other languages.
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
2001-06-06 11:01:25 +00:00
|
|
|
|
/* Remove `inline' nested functions if they crash your compiler */
|
2005-02-22 11:22:44 +00:00
|
|
|
|
//#define inline
|
2001-06-05 11:52:27 +00:00
|
|
|
|
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "config.h"
|
2003-07-31 23:49:32 +00:00
|
|
|
|
#include "GNUstepBase/preface.h"
|
1998-12-14 06:17:12 +00:00
|
|
|
|
#include <mframe.h>
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "Foundation/NSObjCRuntime.h"
|
|
|
|
|
#include "Foundation/NSData.h"
|
|
|
|
|
#include "Foundation/NSException.h"
|
2001-05-04 21:14:06 +00:00
|
|
|
|
#include <stdio.h>
|
1994-11-04 16:29:24 +00:00
|
|
|
|
#include <stdlib.h>
|
2001-05-04 21:14:06 +00:00
|
|
|
|
#include <ctype.h>
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
|
|
|
|
/* Deal with strrchr: */
|
2002-05-08 05:43:15 +00:00
|
|
|
|
#if STDC_HEADERS || defined(HAVE_STRING_H)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
#include <string.h>
|
|
|
|
|
/* An ANSI string.h and pre-ANSI memory.h might conflict. */
|
2002-05-08 05:43:15 +00:00
|
|
|
|
#if !STDC_HEADERS && defined(HAVE_MEMORY_H)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
#include <memory.h>
|
|
|
|
|
#endif /* not STDC_HEADERS and HAVE_MEMORY_H */
|
|
|
|
|
#define index strchr
|
|
|
|
|
#define rindex strrchr
|
|
|
|
|
#define bcopy(s, d, n) memcpy ((d), (s), (n))
|
|
|
|
|
#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
|
|
|
|
|
#define bzero(s, n) memset ((s), 0, (n))
|
|
|
|
|
#else /* not STDC_HEADERS and not HAVE_STRING_H */
|
|
|
|
|
#include <strings.h>
|
|
|
|
|
/* memory.h and strings.h conflict on some systems. */
|
|
|
|
|
#endif /* not STDC_HEADERS and not HAVE_STRING_H */
|
|
|
|
|
|
1999-06-24 19:57:52 +00:00
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
/* For encoding and decoding the method arguments, we have to know where
|
|
|
|
|
to find things in the "argframe" as returned by __builtin_apply_args.
|
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
|
For some situations this is obvious just from the selector type
|
1994-11-04 16:29:24 +00:00
|
|
|
|
encoding, but structures passed by value cause a problem because some
|
|
|
|
|
architectures actually pass these by reference, i.e. use the
|
|
|
|
|
structure-value-address mentioned in the gcc/config/_/_.h files.
|
|
|
|
|
|
|
|
|
|
These differences are not encoded in the selector types.
|
|
|
|
|
|
|
|
|
|
Below is my current guess for which architectures do this.
|
|
|
|
|
xxx I really should do this properly by looking at the gcc config values.
|
|
|
|
|
|
|
|
|
|
I've also been told that some architectures may pass structures with
|
|
|
|
|
sizef(structure) > sizeof(void*) by reference, but pass smaller ones by
|
|
|
|
|
value. The code doesn't currently handle that case.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
1998-08-13 20:45:32 +00:00
|
|
|
|
char*
|
|
|
|
|
mframe_build_signature(const char *typePtr, int *size, int *narg, char *buf)
|
|
|
|
|
{
|
1998-11-02 10:55:53 +00:00
|
|
|
|
MFRAME_ARGS cum;
|
|
|
|
|
BOOL doMalloc = NO;
|
|
|
|
|
const char *types;
|
|
|
|
|
char *start;
|
|
|
|
|
char *dest;
|
|
|
|
|
int total = 0;
|
|
|
|
|
int count = 0;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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);
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
/*
|
|
|
|
|
* Copy the return type info (including qualifiers) into the buffer.
|
|
|
|
|
*/
|
|
|
|
|
types = objc_skip_typespec(typePtr);
|
|
|
|
|
strncpy(buf, typePtr, types - typePtr);
|
2005-02-22 11:22:44 +00:00
|
|
|
|
buf[types-typePtr] = '\0';
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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++;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
2000-04-14 10:38:22 +00:00
|
|
|
|
if (*types == '-')
|
|
|
|
|
{
|
|
|
|
|
types++;
|
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
while (isdigit(*types))
|
|
|
|
|
{
|
|
|
|
|
types++;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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++;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
MFRAME_ARG_ENCODING(cum, types, total, dest);
|
|
|
|
|
count++;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
*dest = '\0';
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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++;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
*dest = '\0';
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
/*
|
|
|
|
|
* If we have written into a local buffer - we need to allocate memory
|
|
|
|
|
* in which to return our result.
|
|
|
|
|
*/
|
|
|
|
|
if (doMalloc)
|
|
|
|
|
{
|
1999-09-28 11:10:34 +00:00
|
|
|
|
char *tmp = NSZoneMalloc(NSDefaultMallocZone(), dest - buf + 1);
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
strcpy(tmp, buf);
|
|
|
|
|
buf = tmp;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
if (narg)
|
|
|
|
|
{
|
|
|
|
|
*narg = count;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
return buf;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
1998-08-13 20:45:32 +00:00
|
|
|
|
/*
|
|
|
|
|
* Step through method encoding information extracting details.
|
|
|
|
|
*/
|
|
|
|
|
const char *
|
|
|
|
|
mframe_next_arg(const char *typePtr, NSArgumentInfo *info)
|
|
|
|
|
{
|
1998-11-02 10:55:53 +00:00
|
|
|
|
NSArgumentInfo local;
|
|
|
|
|
BOOL flag;
|
2002-11-28 11:48:35 +00:00
|
|
|
|
BOOL negative = NO;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
if (info == 0)
|
|
|
|
|
{
|
|
|
|
|
info = &local;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
#ifdef _C_BYREF
|
1998-11-02 10:55:53 +00:00
|
|
|
|
case _C_BYREF: info->qual |= _F_BYREF; break;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
#endif
|
1998-11-02 10:55:53 +00:00
|
|
|
|
case _C_ONEWAY: info->qual |= _F_ONEWAY; break;
|
1999-09-29 14:13:52 +00:00
|
|
|
|
#ifdef _C_GCINVISIBLE
|
|
|
|
|
case _C_GCINVISIBLE: info->qual |= _F_GCINVISIBLE; break;
|
|
|
|
|
#endif
|
1998-11-02 10:55:53 +00:00
|
|
|
|
default: flag = NO;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
if (flag)
|
|
|
|
|
{
|
|
|
|
|
typePtr++;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
info->type = typePtr;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
/*
|
|
|
|
|
* Scan for size and alignment information.
|
|
|
|
|
*/
|
|
|
|
|
switch (*typePtr++)
|
|
|
|
|
{
|
|
|
|
|
case _C_ID:
|
|
|
|
|
info->size = sizeof(id);
|
|
|
|
|
info->align = __alignof__(id);
|
|
|
|
|
break;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
case _C_CLASS:
|
|
|
|
|
info->size = sizeof(Class);
|
|
|
|
|
info->align = __alignof__(Class);
|
|
|
|
|
break;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
case _C_SEL:
|
|
|
|
|
info->size = sizeof(SEL);
|
|
|
|
|
info->align = __alignof__(SEL);
|
|
|
|
|
break;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
case _C_CHR:
|
|
|
|
|
info->size = sizeof(char);
|
|
|
|
|
info->align = __alignof__(char);
|
|
|
|
|
break;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
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_LNG_LNG:
|
|
|
|
|
info->size = sizeof(long long);
|
|
|
|
|
info->align = __alignof__(long long);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_ULNG_LNG:
|
|
|
|
|
info->size = sizeof(unsigned long long);
|
|
|
|
|
info->align = __alignof__(unsigned long 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*);
|
|
|
|
|
if (*typePtr == '?')
|
|
|
|
|
{
|
|
|
|
|
typePtr++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2002-11-28 11:48:35 +00:00
|
|
|
|
typePtr = objc_skip_typespec(typePtr);
|
1998-11-02 10:55:53 +00:00
|
|
|
|
}
|
|
|
|
|
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++;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
typePtr = mframe_next_arg(typePtr, &local);
|
|
|
|
|
info->size = length * ROUND(local.size, local.align);
|
|
|
|
|
info->align = local.align;
|
|
|
|
|
typePtr++; /* Skip end-of-array */
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
break;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
case _C_STRUCT_B:
|
|
|
|
|
{
|
2003-01-03 20:14:47 +00:00
|
|
|
|
unsigned int acc_size = 0;
|
|
|
|
|
unsigned int def_align = objc_alignof_type(typePtr-1);
|
|
|
|
|
unsigned int acc_align = def_align;
|
2003-06-02 06:03:04 +00:00
|
|
|
|
const char *ptr = typePtr;
|
1998-11-02 10:55:53 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Skip "<name>=" stuff.
|
|
|
|
|
*/
|
2003-06-02 06:03:04 +00:00
|
|
|
|
while (*ptr != _C_STRUCT_E && *ptr != '=') ptr++;
|
|
|
|
|
if (*ptr == '=') typePtr = ptr;
|
|
|
|
|
typePtr++;
|
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
/*
|
|
|
|
|
* Base structure alignment on first element.
|
|
|
|
|
*/
|
|
|
|
|
if (*typePtr != _C_STRUCT_E)
|
|
|
|
|
{
|
|
|
|
|
typePtr = mframe_next_arg(typePtr, &local);
|
|
|
|
|
if (typePtr == 0)
|
|
|
|
|
{
|
|
|
|
|
return 0; /* error */
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
acc_size = ROUND(acc_size, local.align);
|
|
|
|
|
acc_size += local.size;
|
2002-11-27 17:31:38 +00:00
|
|
|
|
acc_align = MAX(local.align, def_align);
|
1998-11-02 10:55:53 +00:00
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Continue accumulating structure size.
|
|
|
|
|
*/
|
|
|
|
|
while (*typePtr != _C_STRUCT_E)
|
|
|
|
|
{
|
|
|
|
|
typePtr = mframe_next_arg(typePtr, &local);
|
|
|
|
|
if (typePtr == 0)
|
|
|
|
|
{
|
|
|
|
|
return 0; /* error */
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
acc_size = ROUND(acc_size, local.align);
|
|
|
|
|
acc_size += local.size;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
info->size = acc_size;
|
|
|
|
|
info->align = acc_align;
|
|
|
|
|
typePtr++; /* Skip end-of-struct */
|
|
|
|
|
}
|
|
|
|
|
break;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
case _C_UNION_B:
|
|
|
|
|
{
|
2003-01-03 20:14:47 +00:00
|
|
|
|
unsigned int max_size = 0;
|
|
|
|
|
unsigned int max_align = 0;
|
1998-11-02 10:55:53 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Skip "<name>=" stuff.
|
|
|
|
|
*/
|
|
|
|
|
while (*typePtr != _C_UNION_E)
|
1998-08-13 20:45:32 +00:00
|
|
|
|
{
|
1998-11-02 10:55:53 +00:00
|
|
|
|
if (*typePtr++ == '=')
|
|
|
|
|
{
|
|
|
|
|
break;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
}
|
|
|
|
|
while (*typePtr != _C_UNION_E)
|
|
|
|
|
{
|
|
|
|
|
typePtr = mframe_next_arg(typePtr, &local);
|
|
|
|
|
if (typePtr == 0)
|
|
|
|
|
{
|
|
|
|
|
return 0; /* error */
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
max_size = MAX(max_size, local.size);
|
|
|
|
|
max_align = MAX(max_align, local.align);
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
info->size = max_size;
|
|
|
|
|
info->align = max_align;
|
|
|
|
|
typePtr++; /* Skip end-of-union */
|
|
|
|
|
}
|
|
|
|
|
break;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
case _C_VOID:
|
|
|
|
|
info->size = 0;
|
|
|
|
|
info->align = __alignof__(char*);
|
|
|
|
|
break;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
default:
|
1998-08-13 20:45:32 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
if (typePtr == 0)
|
|
|
|
|
{ /* Error condition. */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2002-11-28 11:48:35 +00:00
|
|
|
|
* May tell the caller if the item is stored in a register.
|
1998-11-02 10:55:53 +00:00
|
|
|
|
*/
|
2002-11-28 11:48:35 +00:00
|
|
|
|
if (*typePtr == '+')
|
1998-11-02 10:55:53 +00:00
|
|
|
|
{
|
2002-11-28 11:48:35 +00:00
|
|
|
|
typePtr++;
|
|
|
|
|
info->isReg = YES;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
info->isReg = NO;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Cope with negative offsets.
|
|
|
|
|
*/
|
|
|
|
|
if (*typePtr == '-')
|
|
|
|
|
{
|
|
|
|
|
typePtr++;
|
|
|
|
|
negative = YES;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* 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');
|
|
|
|
|
}
|
|
|
|
|
if (negative == YES)
|
|
|
|
|
{
|
|
|
|
|
info->offset = -info->offset;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
return typePtr;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
|
|
|
|
/* Return the number of arguments that the method MTH expects. Note
|
|
|
|
|
that all methods need two implicit arguments `self' and `_cmd'. */
|
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
int
|
|
|
|
|
method_types_get_number_of_arguments (const char *type)
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
1998-11-02 10:55:53 +00:00
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
while (*type)
|
|
|
|
|
{
|
|
|
|
|
type = objc_skip_argspec (type);
|
|
|
|
|
i += 1;
|
|
|
|
|
}
|
|
|
|
|
return i - 1;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
|
|
|
|
/* Return the size of the argument block needed on the stack to invoke
|
1994-11-04 16:29:24 +00:00
|
|
|
|
the method MTH. This may be zero, if all arguments are passed in
|
1996-03-30 01:29:07 +00:00
|
|
|
|
registers. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
method_types_get_size_of_stack_arguments (const char *type)
|
|
|
|
|
{
|
|
|
|
|
type = objc_skip_typespec (type);
|
|
|
|
|
return atoi (type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
method_types_get_size_of_register_arguments(const char *types)
|
|
|
|
|
{
|
|
|
|
|
const char* type = strrchr(types, '+');
|
1998-11-02 10:55:53 +00:00
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
if (type)
|
1998-11-02 10:55:53 +00:00
|
|
|
|
{
|
|
|
|
|
return atoi(++type) + sizeof(void*);
|
|
|
|
|
}
|
1994-11-04 16:29:24 +00:00
|
|
|
|
else
|
1998-11-02 10:55:53 +00:00
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
1996-10-31 17:09:27 +00:00
|
|
|
|
/* To fix temporary bug in method_get_next_argument() on NeXT boxes */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
/* xxx Perhaps this isn't working with the NeXT runtime? */
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
char*
|
1998-08-13 20:45:32 +00:00
|
|
|
|
method_types_get_next_argument (arglist_t argf, const char **type)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
const char *t = objc_skip_argspec (*type);
|
1998-08-13 20:45:32 +00:00
|
|
|
|
arglist_t argframe;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
|
|
|
|
argframe = (void*)argf;
|
|
|
|
|
|
|
|
|
|
if (*t == '\0')
|
1998-11-02 10:55:53 +00:00
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
1994-11-04 16:29:24 +00:00
|
|
|
|
*type = t;
|
|
|
|
|
t = objc_skip_typespec (t);
|
|
|
|
|
|
|
|
|
|
if (*t == '+')
|
1998-11-02 10:55:53 +00:00
|
|
|
|
{
|
|
|
|
|
return argframe->arg_regs + atoi(++t);
|
|
|
|
|
}
|
1994-11-04 16:29:24 +00:00
|
|
|
|
else
|
1998-11-02 10:55:53 +00:00
|
|
|
|
{
|
|
|
|
|
/* xxx What's going on here? This -8 needed on my 68k NeXT box. */
|
1996-10-31 17:09:27 +00:00
|
|
|
|
#if NeXT
|
1998-11-02 10:55:53 +00:00
|
|
|
|
return argframe->arg_ptr + (atoi(t) - 8);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
#else
|
1998-11-02 10:55:53 +00:00
|
|
|
|
return argframe->arg_ptr + atoi(t);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
#endif
|
1998-11-02 10:55:53 +00:00
|
|
|
|
}
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-08-28 18:45:17 +00:00
|
|
|
|
char*
|
|
|
|
|
method_types_get_first_argument (struct objc_method* m,
|
|
|
|
|
arglist_t argframe,
|
|
|
|
|
const char** type)
|
|
|
|
|
{
|
|
|
|
|
*type = m->method_types;
|
2001-12-28 03:40:03 +00:00
|
|
|
|
return method_types_get_next_argument (argframe, type);
|
2001-08-28 18:45:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
method_types_get_sizeof_arguments (struct objc_method* mth)
|
|
|
|
|
{
|
|
|
|
|
const char* type = objc_skip_typespec (mth->method_types);
|
|
|
|
|
return atoi (type);
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
|
|
|
|
/* mframe_dissect_call()
|
|
|
|
|
|
|
|
|
|
This function encodes the arguments of a method call.
|
|
|
|
|
|
|
|
|
|
Call it with an ARGFRAME that was returned by __builtin_args(), and
|
|
|
|
|
a TYPE string that describes the input and return locations,
|
|
|
|
|
i.e. from sel_get_types() or Method->method_types.
|
|
|
|
|
|
|
|
|
|
The function ENCODER will be called once with each input argument.
|
|
|
|
|
|
|
|
|
|
Returns YES iff there are any outparameters---parameters that for
|
|
|
|
|
which we will have to get new values after the method is run,
|
|
|
|
|
e.g. an argument declared (out char*). */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
|
|
|
|
BOOL
|
2001-09-19 21:31:18 +00:00
|
|
|
|
mframe_dissect_call (arglist_t argframe, const char *type,
|
|
|
|
|
void (*encoder)(DOContext *), DOContext *ctxt)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned flags;
|
|
|
|
|
char *datum;
|
|
|
|
|
int argnum;
|
|
|
|
|
BOOL out_parameters = NO;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
if (*type == _C_STRUCT_B || *type == _C_UNION_B || *type == _C_ARY_B) {
|
1998-08-13 20:45:32 +00:00
|
|
|
|
datum = alloca((strlen(type)+1)*10);
|
|
|
|
|
type = mframe_build_signature(type, 0, 0, datum);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* 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. */
|
|
|
|
|
|
1998-08-13 20:45:32 +00:00
|
|
|
|
for (datum = method_types_get_next_argument(argframe, &type), argnum=0;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
datum;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
datum = method_types_get_next_argument(argframe, &type), argnum++)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */
|
|
|
|
|
flags = objc_get_type_qualifiers(type);
|
|
|
|
|
|
|
|
|
|
/* Skip over the type qualifiers, so now TYPE is pointing directly
|
|
|
|
|
at the char corresponding to the argument's type, as defined
|
|
|
|
|
in <objc/objc-api.h> */
|
|
|
|
|
type = objc_skip_type_qualifiers(type);
|
|
|
|
|
|
|
|
|
|
/* Decide how, (or whether or not), to encode the argument
|
|
|
|
|
depending on its FLAGS and TYPE. Only the first two cases
|
|
|
|
|
involve parameters that may potentially be passed by
|
|
|
|
|
reference, and thus only the first two may change the value
|
|
|
|
|
of OUT_PARAMETERS. */
|
|
|
|
|
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->type = type;
|
|
|
|
|
ctxt->flags = flags;
|
|
|
|
|
ctxt->datum = datum;
|
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
switch (*type)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
|
|
|
|
case _C_CHARPTR:
|
|
|
|
|
/* Handle a (char*) argument. */
|
|
|
|
|
/* If the char* is qualified as an OUT parameter, or if it
|
|
|
|
|
not explicitly qualified as an IN parameter, then we will
|
|
|
|
|
have to get this char* again after the method is run,
|
|
|
|
|
because the method may have changed it. Set
|
|
|
|
|
OUT_PARAMETERS accordingly. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
if ((flags & _F_OUT) || !(flags & _F_IN))
|
|
|
|
|
out_parameters = YES;
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* If the char* is qualified as an IN parameter, or not
|
|
|
|
|
explicity qualified as an OUT parameter, then encode
|
|
|
|
|
it. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
if ((flags & _F_IN) || !(flags & _F_OUT))
|
2001-09-19 21:31:18 +00:00
|
|
|
|
(*encoder) (ctxt);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_PTR:
|
|
|
|
|
/* If the pointer's value is qualified as an OUT parameter,
|
|
|
|
|
or if it not explicitly qualified as an IN parameter,
|
|
|
|
|
then we will have to get the value pointed to again after
|
|
|
|
|
the method is run, because the method may have changed
|
|
|
|
|
it. Set OUT_PARAMETERS accordingly. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
if ((flags & _F_OUT) || !(flags & _F_IN))
|
|
|
|
|
out_parameters = YES;
|
2001-09-19 21:31:18 +00:00
|
|
|
|
/* Handle an argument that is a pointer to a non-char. But
|
|
|
|
|
(void*) and (anything**) is not allowed. */
|
|
|
|
|
/* The argument is a pointer to something; increment TYPE
|
|
|
|
|
so we can see what it is a pointer to. */
|
|
|
|
|
type++;
|
|
|
|
|
ctxt->type = type;
|
|
|
|
|
ctxt->datum = *(void**)datum;
|
|
|
|
|
/* If the pointer's value is qualified as an IN parameter,
|
|
|
|
|
or not explicity qualified as an OUT parameter, then
|
|
|
|
|
encode it. */
|
|
|
|
|
if ((flags & _F_IN) || !(flags & _F_OUT))
|
|
|
|
|
(*encoder) (ctxt);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_STRUCT_B:
|
1997-09-01 21:59:51 +00:00
|
|
|
|
case _C_UNION_B:
|
1996-03-30 01:29:07 +00:00
|
|
|
|
case _C_ARY_B:
|
|
|
|
|
/* 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
|
1998-08-13 20:45:32 +00:00
|
|
|
|
MFRAME_STRUCT_BYREF. Do the right thing
|
1996-03-30 01:29:07 +00:00
|
|
|
|
so that ENCODER gets a pointer to directly to the data. */
|
1998-08-13 20:45:32 +00:00
|
|
|
|
#if MFRAME_STRUCT_BYREF
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->datum = *(void**)datum;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
#endif
|
2001-09-19 21:31:18 +00:00
|
|
|
|
(*encoder) (ctxt);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/* Handle arguments of all other types. */
|
2001-09-19 21:31:18 +00:00
|
|
|
|
(*encoder) (ctxt);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
|
|
|
|
/* Return a BOOL indicating whether or not there are parameters that
|
|
|
|
|
were passed by reference; we will need to get those values again
|
|
|
|
|
after the method has finished executing because the execution of
|
|
|
|
|
the method may have changed them.*/
|
1994-11-04 16:29:24 +00:00
|
|
|
|
return out_parameters;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
|
|
|
|
/* mframe_do_call()
|
|
|
|
|
|
|
|
|
|
This function decodes the arguments of method call, builds an
|
|
|
|
|
argframe of type arglist_t, and invokes the method using
|
|
|
|
|
__builtin_apply; then it encodes the return value and any
|
|
|
|
|
pass-by-reference arguments.
|
|
|
|
|
|
|
|
|
|
ENCODED_TYPES should be a string that describes the return value
|
|
|
|
|
and arguments. It's argument types and argument type qualifiers
|
|
|
|
|
should match exactly those that were used when the arguments were
|
|
|
|
|
encoded with mframe_dissect_call()---mframe_do_call() uses
|
|
|
|
|
ENCODED_TYPES to determine which variable types it should decode.
|
|
|
|
|
|
|
|
|
|
ENCODED_TYPES is used to get the types and type qualifiers, but not
|
|
|
|
|
to get the register and stack locations---we get that information
|
|
|
|
|
from the selector type of the SEL that is decoded as the second
|
|
|
|
|
argument. In this way, the ENCODED_TYPES may come from a machine
|
|
|
|
|
of a different architecture. Having the original ENCODED_TYPES is
|
|
|
|
|
good, just in case the machine running mframe_do_call() has some
|
|
|
|
|
slightly different qualifiers. Using different qualifiers for
|
|
|
|
|
encoding and decoding could lead to massive confusion.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DECODER should be a pointer to a function that obtains the method's
|
|
|
|
|
argument values. For example:
|
|
|
|
|
|
|
|
|
|
void my_decoder (int argnum, void *data, const char *type)
|
|
|
|
|
|
|
|
|
|
ARGNUM is the number of the argument, beginning at 0.
|
|
|
|
|
DATA is a pointer to the memory where the value should be placed.
|
|
|
|
|
TYPE is a pointer to the type string of this value.
|
|
|
|
|
|
|
|
|
|
mframe_do_call() calls this function once for each of the methods
|
|
|
|
|
arguments. The DECODER function should place the ARGNUM'th
|
|
|
|
|
argument's value at the memory location DATA.
|
1997-09-01 21:59:51 +00:00
|
|
|
|
mframe_do_call() calls this function once with ARGNUM -1, DATA 0,
|
|
|
|
|
and TYPE 0 to denote completion of decoding.
|
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
|
|
|
|
If DECODER malloc's new memory in the course of doing its
|
|
|
|
|
business, then DECODER is responsible for making sure that the
|
|
|
|
|
memory will get free eventually. For example, if DECODER uses
|
|
|
|
|
-decodeValueOfCType:at:withName: to decode a char* string, you
|
|
|
|
|
should remember that -decodeValueOfCType:at:withName: malloc's
|
|
|
|
|
new memory to hold the string, and DECODER should autorelease the
|
1998-09-30 07:42:38 +00:00
|
|
|
|
malloc'ed pointer, using the NSData class.
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ENCODER should be a pointer to a function that records the method's
|
|
|
|
|
return value and pass-by-reference values. For example:
|
|
|
|
|
|
|
|
|
|
void my_encoder (int argnum, void *data, const char *type, int flags)
|
|
|
|
|
|
|
|
|
|
ARGNUM is the number of the argument; this will be -1 for the
|
|
|
|
|
return value, and the argument index for the pass-by-reference
|
|
|
|
|
values; the indices start at 0.
|
|
|
|
|
DATA is a pointer to the memory where the value can be found.
|
|
|
|
|
TYPE is a pointer to the type string of this value.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
FLAGS is a copy of the type qualifier flags for this argument;
|
1996-03-30 01:29:07 +00:00
|
|
|
|
(see <objc/objc-api.h>).
|
|
|
|
|
|
|
|
|
|
mframe_do_call() calls this function after the method has been
|
|
|
|
|
run---once for the return value, and once for each of the
|
|
|
|
|
pass-by-reference parameters. The ENCODER function should place
|
|
|
|
|
the value at memory location DATA wherever the user wants to
|
|
|
|
|
record the ARGNUM'th return value.
|
1998-04-30 20:11:42 +00:00
|
|
|
|
|
|
|
|
|
PASS_POINTERS is a flag saying whether pointers should be passed
|
|
|
|
|
as pointers (for local stuff) or should be assumed to point to a
|
|
|
|
|
single data item (for distributed objects).
|
1996-03-30 01:29:07 +00:00
|
|
|
|
*/
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
|
|
|
|
void
|
2001-09-19 21:31:18 +00:00
|
|
|
|
mframe_do_call (DOContext *ctxt,
|
|
|
|
|
void(*decoder)(DOContext*),
|
|
|
|
|
void(*encoder)(DOContext*))
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
2005-02-22 11:22:44 +00:00
|
|
|
|
/* The method type string obtained from the target's OBJC_METHOD
|
1996-03-30 01:29:07 +00:00
|
|
|
|
structure for the selector we're sending. */
|
|
|
|
|
const char *type;
|
|
|
|
|
/* A pointer into the local variable TYPE string. */
|
|
|
|
|
const char *tmptype;
|
|
|
|
|
/* A pointer into the argument ENCODED_TYPES string. */
|
|
|
|
|
const char *etmptype;
|
|
|
|
|
/* The target object that will receive the message. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
id object;
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* The selector for the message we're sending to the TARGET. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
SEL selector;
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* The OBJECT's implementation of the SELECTOR. */
|
|
|
|
|
IMP method_implementation;
|
|
|
|
|
/* The number bytes for holding arguments passed on the stack. */
|
|
|
|
|
int stack_argsize;
|
|
|
|
|
/* The number bytes for holding arguments passed in registers. */
|
|
|
|
|
int reg_argsize;
|
|
|
|
|
/* The structure for holding the arguments to the method. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
arglist_t argframe;
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* A pointer into the ARGFRAME; points at individual arguments. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
char *datum;
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Type qualifier flags; see <objc/objc-api.h>. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
unsigned flags;
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Which argument number are we processing now? */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
int argnum;
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* A pointer to the memory holding the return value of the method. */
|
|
|
|
|
void *retframe;
|
|
|
|
|
/* Does the method have any arguments that are passed by reference?
|
|
|
|
|
If so, we need to encode them, since the method may have changed them. */
|
|
|
|
|
BOOL out_parameters = NO;
|
2001-09-19 21:31:18 +00:00
|
|
|
|
const char *encoded_types = ctxt->type;
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* For extracting a return value of type `float' from RETFRAME. */
|
|
|
|
|
float retframe_float (void *rframe)
|
|
|
|
|
{
|
|
|
|
|
__builtin_return (rframe);
|
|
|
|
|
}
|
|
|
|
|
/* For extracting a return value of type `double' from RETFRAME. */
|
|
|
|
|
double retframe_double (void *rframe)
|
|
|
|
|
{
|
|
|
|
|
__builtin_return (rframe);
|
|
|
|
|
}
|
1996-09-02 13:14:50 +00:00
|
|
|
|
/* For extracting a return value of type `char' from RETFRAME */
|
|
|
|
|
char retframe_char (void *rframe)
|
|
|
|
|
{
|
|
|
|
|
__builtin_return (rframe);
|
|
|
|
|
}
|
|
|
|
|
/* For extracting a return value of type `short' from RETFRAME */
|
|
|
|
|
short retframe_short (void *rframe)
|
|
|
|
|
{
|
|
|
|
|
__builtin_return (rframe);
|
|
|
|
|
}
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Decode the object, (which is always the first argument to a method),
|
|
|
|
|
into the local variable OBJECT. */
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->datum = &object;
|
|
|
|
|
ctxt->type = @encode(id);
|
|
|
|
|
(*decoder) (ctxt);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
NSCParameterAssert (object);
|
|
|
|
|
|
|
|
|
|
/* Decode the selector, (which is always the second argument to a
|
|
|
|
|
method), into the local variable SELECTOR. */
|
|
|
|
|
/* xxx @encode(SEL) produces "^v" in gcc 2.5.8. It should be ":" */
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->datum = &selector;
|
|
|
|
|
ctxt->type = @encode(SEL);
|
|
|
|
|
(*decoder) (ctxt);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
NSCParameterAssert (selector);
|
|
|
|
|
|
|
|
|
|
/* Get the "selector type" for this method. The "selector type" is
|
|
|
|
|
a string that lists the return and argument types, and also
|
|
|
|
|
indicates in which registers and where on the stack the arguments
|
|
|
|
|
should be placed before the method call. The selector type
|
|
|
|
|
string we get here should have the same argument and return types
|
|
|
|
|
as the ENCODED_TYPES string, but it will have different register
|
|
|
|
|
and stack locations if the ENCODED_TYPES came from a machine of a
|
|
|
|
|
different architecture. */
|
2001-04-24 03:40:04 +00:00
|
|
|
|
#if NeXT_RUNTIME
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
Method m;
|
1996-03-30 01:29:07 +00:00
|
|
|
|
m = class_getInstanceMethod(object->isa, selector);
|
2005-02-22 11:22:44 +00:00
|
|
|
|
if (!m)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
abort();
|
|
|
|
|
type = m->method_types;
|
|
|
|
|
}
|
1996-04-10 16:37:30 +00:00
|
|
|
|
#elif 0
|
1996-03-30 01:29:07 +00:00
|
|
|
|
{
|
|
|
|
|
Method_t m;
|
1996-04-09 23:55:42 +00:00
|
|
|
|
m = class_get_instance_method (object->class_pointer,
|
1996-03-30 01:29:07 +00:00
|
|
|
|
selector);
|
|
|
|
|
NSCParameterAssert (m);
|
|
|
|
|
type = m->method_types;
|
|
|
|
|
}
|
1996-04-10 16:37:30 +00:00
|
|
|
|
#else
|
|
|
|
|
type = sel_get_type (selector);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
#endif /* NeXT_runtime */
|
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Make sure we successfully got the method type, and that its
|
|
|
|
|
types match the ENCODED_TYPES. */
|
1996-03-30 22:22:20 +00:00
|
|
|
|
NSCParameterAssert (type);
|
2004-08-19 16:19:48 +00:00
|
|
|
|
NSCParameterAssert (GSSelectorTypesMatch(encoded_types, type));
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
1998-08-13 20:45:32 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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().
|
|
|
|
|
*/
|
1997-09-01 21:59:51 +00:00
|
|
|
|
if (*type == _C_STRUCT_B || *type == _C_UNION_B || *type == _C_ARY_B) {
|
1998-08-13 20:45:32 +00:00
|
|
|
|
tmptype = alloca((strlen(type)+1)*10);
|
|
|
|
|
type = mframe_build_signature(type, 0, 0, (char*)tmptype);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* 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. */
|
1998-08-13 20:45:32 +00:00
|
|
|
|
stack_argsize = method_types_get_size_of_stack_arguments (type);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
reg_argsize = method_types_get_size_of_register_arguments (type);
|
|
|
|
|
/* Allocate the space for variables passed in registers. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
argframe = (arglist_t) alloca(sizeof(char*) + reg_argsize);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Allocate the space for variables passed on the stack. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
if (stack_argsize)
|
1996-03-30 01:29:07 +00:00
|
|
|
|
argframe->arg_ptr = alloca (stack_argsize);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
else
|
|
|
|
|
argframe->arg_ptr = 0;
|
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
if (*type == _C_STRUCT_B || *type == _C_UNION_B || *type == _C_ARY_B)
|
|
|
|
|
{
|
1998-08-13 20:45:32 +00:00
|
|
|
|
void *buf;
|
|
|
|
|
|
1998-04-20 14:13:19 +00:00
|
|
|
|
/* If we are passing a pointer to return a structure in, we must allocate
|
1998-08-13 20:45:32 +00:00
|
|
|
|
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);
|
1998-11-02 10:55:53 +00:00
|
|
|
|
}
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
|
|
|
|
/* Put OBJECT and SELECTOR into the ARGFRAME. */
|
|
|
|
|
|
|
|
|
|
/* Initialize our temporary pointers into the method type strings. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
tmptype = type;
|
1996-03-30 01:29:07 +00:00
|
|
|
|
etmptype = objc_skip_argspec (encoded_types);
|
|
|
|
|
/* Get a pointer into ARGFRAME, pointing to the location where the
|
|
|
|
|
first argument is to be stored. */
|
1998-08-13 20:45:32 +00:00
|
|
|
|
datum = method_types_get_next_argument (argframe, &tmptype);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
NSCParameterAssert (datum);
|
|
|
|
|
NSCParameterAssert (*tmptype == _C_ID);
|
|
|
|
|
/* Put the target object there. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
*(id*)datum = object;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
/* Get a pointer into ARGFRAME, pointing to the location where the
|
1996-03-30 01:29:07 +00:00
|
|
|
|
second argument is to be stored. */
|
|
|
|
|
etmptype = objc_skip_argspec(etmptype);
|
1998-08-13 20:45:32 +00:00
|
|
|
|
datum = method_types_get_next_argument(argframe, &tmptype);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
NSCParameterAssert (datum);
|
|
|
|
|
NSCParameterAssert (*tmptype == _C_SEL);
|
|
|
|
|
/* Put the selector there. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
*(SEL*)datum = selector;
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Decode arguments after OBJECT and SELECTOR, and put them into the
|
|
|
|
|
ARGFRAME. Step TMPTYPE and ETMPTYPE in lock-step through their
|
|
|
|
|
method type strings. */
|
|
|
|
|
|
1998-08-13 20:45:32 +00:00
|
|
|
|
for (datum = method_types_get_next_argument (argframe, &tmptype),
|
1996-03-30 01:29:07 +00:00
|
|
|
|
etmptype = objc_skip_argspec (etmptype), argnum = 2;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
datum;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
datum = method_types_get_next_argument (argframe, &tmptype),
|
1996-03-30 01:29:07 +00:00
|
|
|
|
etmptype = objc_skip_argspec (etmptype), argnum++)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */
|
|
|
|
|
flags = objc_get_type_qualifiers (etmptype);
|
|
|
|
|
/* Skip over the type qualifiers, so now TYPE is pointing directly
|
|
|
|
|
at the char corresponding to the argument's type, as defined
|
|
|
|
|
in <objc/objc-api.h> */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
tmptype = objc_skip_type_qualifiers(tmptype);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
|
|
|
|
/* Decide how, (or whether or not), to decode the argument
|
|
|
|
|
depending on its FLAGS and TMPTYPE. Only the first two cases
|
|
|
|
|
involve parameters that may potentially be passed by
|
|
|
|
|
reference, and thus only the first two may change the value
|
|
|
|
|
of OUT_PARAMETERS. *** Note: This logic must match exactly
|
|
|
|
|
the code in mframe_dissect_call(); that function should
|
|
|
|
|
encode exactly what we decode here. *** */
|
|
|
|
|
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->type = tmptype;
|
|
|
|
|
ctxt->datum = datum;
|
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
switch (*tmptype)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
|
|
|
|
case _C_CHARPTR:
|
|
|
|
|
/* Handle a (char*) argument. */
|
|
|
|
|
/* If the char* is qualified as an OUT parameter, or if it
|
|
|
|
|
not explicitly qualified as an IN parameter, then we will
|
|
|
|
|
have to get this char* again after the method is run,
|
|
|
|
|
because the method may have changed it. Set
|
|
|
|
|
OUT_PARAMETERS accordingly. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
if ((flags & _F_OUT) || !(flags & _F_IN))
|
|
|
|
|
out_parameters = YES;
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* If the char* is qualified as an IN parameter, or not
|
|
|
|
|
explicity qualified as an OUT parameter, then decode it.
|
|
|
|
|
Note: the decoder allocates memory for holding the
|
|
|
|
|
string, and it is also responsible for making sure that
|
|
|
|
|
the memory gets freed eventually, (usually through the
|
1998-09-30 07:42:38 +00:00
|
|
|
|
autorelease of NSData object). */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
if ((flags & _F_IN) || !(flags & _F_OUT))
|
2001-09-19 21:31:18 +00:00
|
|
|
|
(*decoder) (ctxt);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_PTR:
|
|
|
|
|
/* If the pointer's value is qualified as an OUT parameter,
|
|
|
|
|
or if it not explicitly qualified as an IN parameter,
|
|
|
|
|
then we will have to get the value pointed to again after
|
|
|
|
|
the method is run, because the method may have changed
|
|
|
|
|
it. Set OUT_PARAMETERS accordingly. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
if ((flags & _F_OUT) || !(flags & _F_IN))
|
|
|
|
|
out_parameters = YES;
|
2001-09-19 21:31:18 +00:00
|
|
|
|
/* Handle an argument that is a pointer to a non-char. But
|
|
|
|
|
(void*) and (anything**) is not allowed. */
|
|
|
|
|
/* The argument is a pointer to something; increment TYPE
|
|
|
|
|
so we can see what it is a pointer to. */
|
|
|
|
|
tmptype++;
|
|
|
|
|
/* Allocate some memory to be pointed to, and to hold the
|
|
|
|
|
value. Note that it is allocated on the stack, and
|
|
|
|
|
methods that want to keep the data pointed to, will have
|
|
|
|
|
to make their own copies. */
|
|
|
|
|
*(void**)datum = alloca (objc_sizeof_type (tmptype));
|
|
|
|
|
/* If the pointer's value is qualified as an IN parameter,
|
|
|
|
|
or not explicity qualified as an OUT parameter, then
|
|
|
|
|
decode it. */
|
|
|
|
|
ctxt->type = tmptype;
|
|
|
|
|
ctxt->datum = *(void**)datum;
|
|
|
|
|
if ((flags & _F_IN) || !(flags & _F_OUT))
|
|
|
|
|
(*decoder) (ctxt);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_STRUCT_B:
|
1997-09-01 21:59:51 +00:00
|
|
|
|
case _C_UNION_B:
|
1996-03-30 01:29:07 +00:00
|
|
|
|
case _C_ARY_B:
|
|
|
|
|
/* 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
|
1998-08-13 20:45:32 +00:00
|
|
|
|
MFRAME_STRUCT_BYREF. Do the right thing
|
1996-03-30 01:29:07 +00:00
|
|
|
|
so that ENCODER gets a pointer to directly to the data. */
|
1998-08-13 20:45:32 +00:00
|
|
|
|
#if MFRAME_STRUCT_BYREF
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* 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
|
|
|
|
|
to make their own copies. */
|
|
|
|
|
*(void**)datum = alloca (objc_sizeof_type(tmptype));
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->datum = datum;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
#endif
|
2001-09-19 21:31:18 +00:00
|
|
|
|
(*decoder) (ctxt);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/* Handle arguments of all other types. */
|
|
|
|
|
/* NOTE FOR OBJECTS: Unlike [Decoder decodeObjectAt:..],
|
|
|
|
|
this function does not generate a reference to the
|
|
|
|
|
object; the object may be autoreleased; if the method
|
|
|
|
|
wants to keep a reference to the object, it will have to
|
|
|
|
|
-retain it. */
|
2001-09-19 21:31:18 +00:00
|
|
|
|
(*decoder) (ctxt);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
/* End of the for () loop that enumerates the method's arguments. */
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->type = 0;
|
|
|
|
|
ctxt->datum = 0;
|
|
|
|
|
(*decoder) (ctxt);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Invoke the method! */
|
|
|
|
|
|
|
|
|
|
/* Find the target object's implementation of this selector. */
|
|
|
|
|
method_implementation = objc_msg_lookup (object, selector);
|
|
|
|
|
NSCParameterAssert (method_implementation);
|
|
|
|
|
/* Do it! Send the message to the target, and get the return value
|
|
|
|
|
in RETFRAME. The arguments will still be in ARGFRAME, so we can
|
|
|
|
|
get the pass-by-reference info from there. */
|
2005-02-22 11:22:44 +00:00
|
|
|
|
retframe = __builtin_apply((void(*)(void))method_implementation,
|
|
|
|
|
argframe,
|
1994-11-04 16:29:24 +00:00
|
|
|
|
stack_argsize);
|
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
|
|
|
|
/* Encode the return value and pass-by-reference values, if there
|
|
|
|
|
are any. This logic must match exactly that in
|
|
|
|
|
mframe_build_return(). */
|
|
|
|
|
/* OUT_PARAMETERS should be true here in exactly the same
|
|
|
|
|
situations as it was true in mframe_dissect_call(). */
|
|
|
|
|
|
|
|
|
|
/* Get the qualifier type of the return value. */
|
|
|
|
|
flags = objc_get_type_qualifiers (encoded_types);
|
|
|
|
|
/* Get the return type; store it our two temporary char*'s. */
|
|
|
|
|
etmptype = objc_skip_type_qualifiers (encoded_types);
|
|
|
|
|
tmptype = objc_skip_type_qualifiers (type);
|
|
|
|
|
|
1997-10-28 14:37:53 +00:00
|
|
|
|
/* Only encode return values if there is a non-void return value,
|
|
|
|
|
a non-oneway void return value, or if there are values that were
|
|
|
|
|
passed by reference. */
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->type = tmptype;
|
|
|
|
|
ctxt->datum = retframe;
|
|
|
|
|
ctxt->flags = flags;
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* If there is a return value, encode it. */
|
|
|
|
|
switch (*tmptype)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-30 01:29:07 +00:00
|
|
|
|
case _C_VOID:
|
1997-10-28 14:37:53 +00:00
|
|
|
|
if ((flags & _F_ONEWAY) == 0)
|
|
|
|
|
{
|
2001-09-19 21:31:18 +00:00
|
|
|
|
int dummy = 0;
|
|
|
|
|
|
|
|
|
|
ctxt->datum = &dummy;
|
|
|
|
|
ctxt->type = @encode(int);
|
|
|
|
|
(*encoder) (ctxt);
|
1997-10-28 14:37:53 +00:00
|
|
|
|
}
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* No return value to encode; do nothing. */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_PTR:
|
2001-09-19 21:31:18 +00:00
|
|
|
|
/* The argument is a pointer to something; increment TYPE
|
|
|
|
|
so we can see what it is a pointer to. */
|
|
|
|
|
tmptype++;
|
|
|
|
|
ctxt->type = tmptype;
|
|
|
|
|
ctxt->datum = *(void**)retframe;
|
|
|
|
|
/* Encode the value that was pointed to. */
|
|
|
|
|
(*encoder) (ctxt);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_STRUCT_B:
|
1997-09-01 21:59:51 +00:00
|
|
|
|
case _C_UNION_B:
|
1996-03-30 01:29:07 +00:00
|
|
|
|
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?) */
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->datum = MFRAME_GET_STRUCT_ADDR(argframe, tmptype);
|
|
|
|
|
(*encoder)(ctxt);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_FLT:
|
|
|
|
|
{
|
|
|
|
|
float ret = retframe_float (retframe);
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->datum = &ret;
|
|
|
|
|
(*encoder) (ctxt);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case _C_DBL:
|
|
|
|
|
{
|
|
|
|
|
double ret = retframe_double (retframe);
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->datum = &ret;
|
|
|
|
|
(*encoder) (ctxt);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case _C_SHT:
|
|
|
|
|
case _C_USHT:
|
1996-09-02 13:14:50 +00:00
|
|
|
|
/* On some (but not all) architectures, for C variable types
|
|
|
|
|
smaller than int, like short, the RETFRAME doesn't actually
|
|
|
|
|
point to the beginning of the short, it points to the
|
|
|
|
|
beginning of an int. So we let RETFRAME_SHORT() take care of
|
|
|
|
|
it. */
|
|
|
|
|
{
|
|
|
|
|
short ret = retframe_short (retframe);
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->datum = &ret;
|
|
|
|
|
(*encoder) (ctxt);
|
1996-09-02 13:14:50 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
|
|
|
|
case _C_CHR:
|
|
|
|
|
case _C_UCHR:
|
1996-09-02 13:14:50 +00:00
|
|
|
|
/* On some (but not all) architectures, for C variable types
|
|
|
|
|
smaller than int, like char, the RETFRAME doesn't actually
|
|
|
|
|
point to the beginning of the char, it points to the
|
|
|
|
|
beginning of an int. So we let RETFRAME_SHORT() take care of
|
|
|
|
|
it. */
|
|
|
|
|
{
|
|
|
|
|
char ret = retframe_char (retframe);
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->datum = &ret;
|
|
|
|
|
(*encoder) (ctxt);
|
1996-09-02 13:14:50 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/* case _C_INT: case _C_UINT: case _C_LNG: case _C_ULNG:
|
1996-09-02 13:14:50 +00:00
|
|
|
|
case _C_CHARPTR: case: _C_ID: */
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* xxx I think this assumes that sizeof(int)==sizeof(void*) */
|
2001-09-19 21:31:18 +00:00
|
|
|
|
(*encoder) (ctxt);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Encode the values returned by reference. Note: this logic
|
|
|
|
|
must match exactly the code in mframe_build_return(); that
|
|
|
|
|
function should decode exactly what we encode here. */
|
|
|
|
|
|
|
|
|
|
if (out_parameters)
|
|
|
|
|
{
|
|
|
|
|
/* Step through all the arguments, finding the ones that were
|
|
|
|
|
passed by reference. */
|
2005-02-22 11:22:44 +00:00
|
|
|
|
for (datum = method_types_get_next_argument (argframe, &tmptype),
|
1996-03-30 01:29:07 +00:00
|
|
|
|
argnum = 1,
|
|
|
|
|
etmptype = objc_skip_argspec (etmptype);
|
|
|
|
|
datum;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
datum = method_types_get_next_argument (argframe, &tmptype),
|
1996-03-30 01:29:07 +00:00
|
|
|
|
argnum++,
|
|
|
|
|
etmptype = objc_skip_argspec (etmptype))
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */
|
|
|
|
|
flags = objc_get_type_qualifiers(etmptype);
|
|
|
|
|
/* Skip over the type qualifiers, so now TYPE is pointing directly
|
|
|
|
|
at the char corresponding to the argument's type, as defined
|
|
|
|
|
in <objc/objc-api.h> */
|
|
|
|
|
tmptype = objc_skip_type_qualifiers (tmptype);
|
|
|
|
|
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->type = tmptype;
|
|
|
|
|
ctxt->datum = datum;
|
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Decide how, (or whether or not), to encode the argument
|
|
|
|
|
depending on its FLAGS and TMPTYPE. */
|
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
|
if ((*tmptype == _C_PTR)
|
2001-09-19 21:31:18 +00:00
|
|
|
|
&& ((flags & _F_OUT) || !(flags & _F_IN)))
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* The argument is a pointer (to a non-char), and the
|
|
|
|
|
pointer's value is qualified as an OUT parameter, or
|
|
|
|
|
it not explicitly qualified as an IN parameter, then
|
|
|
|
|
it is a pass-by-reference argument.*/
|
|
|
|
|
/* The argument is a pointer to something; increment TYPE
|
|
|
|
|
so we can see what it is a pointer to. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
tmptype++;
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->type = tmptype;
|
|
|
|
|
ctxt->datum = *(void**)datum;
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Encode it. */
|
2001-09-19 21:31:18 +00:00
|
|
|
|
(*encoder) (ctxt);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
1996-03-30 01:29:07 +00:00
|
|
|
|
else if (*tmptype == _C_CHARPTR
|
2001-09-19 21:31:18 +00:00
|
|
|
|
&& ((flags & _F_OUT) || !(flags & _F_IN)))
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* The argument is a pointer char string, and the
|
|
|
|
|
pointer's value is qualified as an OUT parameter, or
|
|
|
|
|
it not explicitly qualified as an IN parameter, then
|
|
|
|
|
it is a pass-by-reference argument. Encode it.*/
|
|
|
|
|
/* xxx Perhaps we could save time and space by saving
|
|
|
|
|
a copy of the string before the method call, and then
|
|
|
|
|
comparing it to this string; if it didn't change, don't
|
|
|
|
|
bother to send it back again. */
|
2001-09-19 21:31:18 +00:00
|
|
|
|
(*encoder) (ctxt);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-08 05:43:15 +00:00
|
|
|
|
#if 0
|
2001-09-19 21:31:18 +00:00
|
|
|
|
/* For returning structures etc */
|
1997-09-01 21:59:51 +00:00
|
|
|
|
typedef struct { id many[8];} __big;
|
2001-09-05 21:31:42 +00:00
|
|
|
|
static __big return_block (void* data)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
return *(__big*)data;
|
|
|
|
|
}
|
2002-05-08 05:43:15 +00:00
|
|
|
|
#endif
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/* For returning a char (or unsigned char) */
|
2001-09-05 21:31:42 +00:00
|
|
|
|
static char return_char (char data)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
/* For returning a double */
|
2001-09-05 21:31:42 +00:00
|
|
|
|
static double return_double (double data)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
/* For returning a float */
|
2001-09-05 21:31:42 +00:00
|
|
|
|
static float return_float (float data)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
/* For returning a short (or unsigned short) */
|
2001-09-05 21:31:42 +00:00
|
|
|
|
static short return_short (short data)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2002-05-08 05:43:15 +00:00
|
|
|
|
#if 0
|
2001-09-05 21:31:42 +00:00
|
|
|
|
static retval_t apply_block(void* data)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
void* args = __builtin_apply_args();
|
|
|
|
|
return __builtin_apply((apply_t)return_block, args, sizeof(void*));
|
|
|
|
|
}
|
2002-05-08 05:43:15 +00:00
|
|
|
|
#endif
|
2001-09-05 21:31:42 +00:00
|
|
|
|
static retval_t apply_char(char data)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
void* args = __builtin_apply_args();
|
|
|
|
|
return __builtin_apply((apply_t)return_char, args, sizeof(void*));
|
|
|
|
|
}
|
2001-09-05 21:31:42 +00:00
|
|
|
|
static retval_t apply_float(float data)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
void* args = __builtin_apply_args();
|
|
|
|
|
return __builtin_apply((apply_t)return_float, args, sizeof(float));
|
|
|
|
|
}
|
2001-09-05 21:31:42 +00:00
|
|
|
|
static retval_t apply_double(double data)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
void* args = __builtin_apply_args();
|
|
|
|
|
return __builtin_apply((apply_t)return_double, args, sizeof(double));
|
|
|
|
|
}
|
2001-09-05 21:31:42 +00:00
|
|
|
|
static retval_t apply_short(short data)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
void* args = __builtin_apply_args();
|
|
|
|
|
return __builtin_apply((apply_t)return_short, args, sizeof(void*));
|
|
|
|
|
}
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
2001-09-05 21:31:42 +00:00
|
|
|
|
/* mframe_build_return()
|
|
|
|
|
|
|
|
|
|
This function decodes the values returned from a method call,
|
|
|
|
|
builds a retframe of type retval_t that can be passed to GCC's
|
|
|
|
|
__builtin_return(), and updates the pass-by-reference arguments in
|
|
|
|
|
ARGFRAME. This function returns a retframe pointer.
|
|
|
|
|
|
|
|
|
|
In the function that calls this one, be careful about calling more
|
|
|
|
|
functions after this one. The memory for the retframe is
|
|
|
|
|
alloca()'ed, not malloc()'ed, and therefore is on the stack and can
|
|
|
|
|
be tromped-on by future function calls.
|
|
|
|
|
|
2002-08-20 15:07:58 +00:00
|
|
|
|
The callback function is finally called with the 'type' set to a null pointer
|
2001-09-05 21:31:42 +00:00
|
|
|
|
to tell it that the return value and all return parameters have been
|
|
|
|
|
dealt with. This permits the function to do any tidying up necessary.
|
|
|
|
|
*/
|
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
|
retval_t
|
|
|
|
|
mframe_build_return (arglist_t argframe,
|
|
|
|
|
const char *type,
|
2001-09-05 21:31:42 +00:00
|
|
|
|
BOOL out_parameters,
|
2001-09-19 21:31:18 +00:00
|
|
|
|
void(*decoder)(DOContext*),
|
|
|
|
|
DOContext *ctxt)
|
2001-09-05 21:31:42 +00:00
|
|
|
|
{
|
|
|
|
|
/* A pointer to the memory that will hold the return value. */
|
|
|
|
|
retval_t retframe = NULL;
|
|
|
|
|
/* The size, in bytes, of memory pointed to by RETFRAME. */
|
2003-01-03 20:14:47 +00:00
|
|
|
|
unsigned int retsize;
|
2001-09-05 21:31:42 +00:00
|
|
|
|
/* Which argument number are we processing now? */
|
|
|
|
|
int argnum;
|
|
|
|
|
/* Type qualifier flags; see <objc/objc-api.h>. */
|
|
|
|
|
int flags;
|
|
|
|
|
/* A pointer into the TYPE string. */
|
|
|
|
|
const char *tmptype;
|
|
|
|
|
/* A pointer into the ARGFRAME; points at individual arguments. */
|
|
|
|
|
void *datum;
|
|
|
|
|
const char *rettype;
|
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Get the return type qualifier flags, and the return type. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
flags = objc_get_type_qualifiers(type);
|
|
|
|
|
tmptype = objc_skip_type_qualifiers(type);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
rettype = tmptype;
|
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Decode the return value and pass-by-reference values, if there
|
|
|
|
|
are any. OUT_PARAMETERS should be the value returned by
|
|
|
|
|
mframe_dissect_call(). */
|
1997-10-28 14:37:53 +00:00
|
|
|
|
if (out_parameters || *tmptype != _C_VOID || (flags & _F_ONEWAY) == 0)
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* xxx What happens with method declared "- (oneway) foo: (out int*)ip;" */
|
|
|
|
|
/* xxx What happens with method declared "- (in char *) bar;" */
|
|
|
|
|
/* xxx Is this right? Do we also have to check _F_ONEWAY? */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* If there is a return value, decode it, and put it in retframe. */
|
1997-10-28 14:37:53 +00:00
|
|
|
|
if (*tmptype != _C_VOID || (flags & _F_ONEWAY) == 0)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Get the size of the returned value. */
|
1997-10-28 14:37:53 +00:00
|
|
|
|
if (*tmptype == _C_VOID)
|
|
|
|
|
retsize = sizeof(void*);
|
|
|
|
|
else
|
|
|
|
|
retsize = objc_sizeof_type (tmptype);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Allocate memory on the stack to hold the return value.
|
|
|
|
|
It should be at least 4 * sizeof(void*). */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
/* xxx We need to test retsize's less than 4. Also note that
|
|
|
|
|
if we return structures using a structure-value-address, we
|
|
|
|
|
are potentially alloca'ing much more than we need here. */
|
|
|
|
|
/* xxx Find out about returning structures by reference
|
|
|
|
|
on non--structure-value-address machines, and potentially
|
|
|
|
|
just always alloca(RETFRAME_SIZE == sizeof(void*)*4) */
|
1996-03-30 01:29:07 +00:00
|
|
|
|
retframe = alloca (MAX(retsize, sizeof(void*)*4));
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->type = tmptype;
|
|
|
|
|
ctxt->datum = retframe;
|
|
|
|
|
ctxt->flags = flags;
|
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
switch (*tmptype)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-30 01:29:07 +00:00
|
|
|
|
case _C_PTR:
|
2001-09-19 21:31:18 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned retLength;
|
|
|
|
|
|
|
|
|
|
/* We are returning a pointer to something. */
|
|
|
|
|
/* Increment TYPE so we can see what it is a pointer to. */
|
|
|
|
|
tmptype++;
|
2003-01-03 20:14:47 +00:00
|
|
|
|
retLength = (unsigned int)objc_sizeof_type(tmptype);
|
2001-09-19 21:31:18 +00:00
|
|
|
|
/* Allocate memory to hold the value we're pointing to. */
|
2005-02-22 11:22:44 +00:00
|
|
|
|
*(void**)retframe =
|
2001-09-19 21:31:18 +00:00
|
|
|
|
NSZoneMalloc(NSDefaultMallocZone(), retLength);
|
|
|
|
|
/* We are responsible for making sure this memory gets free'd
|
|
|
|
|
eventually. Ask NSData class to autorelease it. */
|
|
|
|
|
[NSData dataWithBytesNoCopy: *(void**)retframe
|
|
|
|
|
length: retLength];
|
|
|
|
|
ctxt->type = tmptype;
|
|
|
|
|
ctxt->datum = *(void**)retframe;
|
|
|
|
|
/* Decode the return value into the memory we allocated. */
|
|
|
|
|
(*decoder) (ctxt);
|
|
|
|
|
}
|
1996-03-30 01:29:07 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
|
case _C_STRUCT_B:
|
1997-09-01 21:59:51 +00:00
|
|
|
|
case _C_UNION_B:
|
1996-03-30 01:29:07 +00:00
|
|
|
|
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?) */
|
1998-08-13 20:45:32 +00:00
|
|
|
|
*(void**)retframe = MFRAME_GET_STRUCT_ADDR(argframe, tmptype);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Decode the return value into the memory we allocated. */
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->datum = *(void**)retframe;
|
|
|
|
|
(*decoder) (ctxt);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
|
case _C_FLT:
|
1996-03-30 01:29:07 +00:00
|
|
|
|
case _C_DBL:
|
2001-09-19 21:31:18 +00:00
|
|
|
|
(*decoder) (ctxt);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
break;
|
|
|
|
|
|
1997-10-28 14:37:53 +00:00
|
|
|
|
case _C_VOID:
|
|
|
|
|
{
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->type = @encode(int);
|
|
|
|
|
(*decoder) (ctxt);
|
1997-10-28 14:37:53 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
default:
|
2001-09-19 21:31:18 +00:00
|
|
|
|
(*decoder) (ctxt);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Decode the values returned by reference. Note: this logic
|
|
|
|
|
must match exactly the code in mframe_do_call(); that
|
|
|
|
|
function should decode exactly what we encode here. */
|
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
if (out_parameters)
|
|
|
|
|
{
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Step through all the arguments, finding the ones that were
|
|
|
|
|
passed by reference. */
|
2005-02-22 11:22:44 +00:00
|
|
|
|
for (datum = method_types_get_next_argument(argframe, &tmptype),
|
1994-11-04 16:29:24 +00:00
|
|
|
|
argnum=0;
|
|
|
|
|
datum;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
(datum = method_types_get_next_argument(argframe, &tmptype)),
|
1994-11-04 16:29:24 +00:00
|
|
|
|
argnum++)
|
|
|
|
|
{
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
flags = objc_get_type_qualifiers(tmptype);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Skip over the type qualifiers, so now TYPE is
|
|
|
|
|
pointing directly at the char corresponding to the
|
|
|
|
|
argument's type, as defined in <objc/objc-api.h> */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
tmptype = objc_skip_type_qualifiers(tmptype);
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
|
|
|
|
/* Decide how, (or whether or not), to encode the
|
|
|
|
|
argument depending on its FLAGS and TMPTYPE. */
|
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
if (*tmptype == _C_PTR
|
|
|
|
|
&& ((flags & _F_OUT) || !(flags & _F_IN)))
|
|
|
|
|
{
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* The argument is a pointer (to a non-char), and
|
|
|
|
|
the pointer's value is qualified as an OUT
|
|
|
|
|
parameter, or it not explicitly qualified as an
|
|
|
|
|
IN parameter, then it is a pass-by-reference
|
|
|
|
|
argument.*/
|
|
|
|
|
/* The argument is a pointer to something; increment
|
|
|
|
|
TYPE so we can see what it is a pointer to. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
tmptype++;
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->flags = flags;
|
|
|
|
|
ctxt->type = tmptype;
|
|
|
|
|
ctxt->datum = *(void**)datum;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
/* xxx Note that a (char**) is malloc'ed anew here.
|
|
|
|
|
Yucky, or worse than yucky. If the returned string
|
|
|
|
|
is smaller than the original, we should just put it
|
|
|
|
|
there; if the returned string is bigger, I don't know
|
|
|
|
|
what to do. */
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* xxx __builtin_return can't return structures by value? */
|
2001-09-19 21:31:18 +00:00
|
|
|
|
(*decoder) (ctxt);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
else if (*tmptype == _C_CHARPTR
|
2001-09-19 21:31:18 +00:00
|
|
|
|
&& ((flags & _F_OUT) || !(flags & _F_IN)))
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* The argument is a pointer char string, and the
|
|
|
|
|
pointer's value is qualified as an OUT parameter,
|
|
|
|
|
or it not explicitly qualified as an IN
|
|
|
|
|
parameter, then it is a pass-by-reference
|
|
|
|
|
argument. Encode it.*/
|
|
|
|
|
/* xxx Perhaps we could save time and space by
|
|
|
|
|
saving a copy of the string before the method
|
|
|
|
|
call, and then comparing it to this string; if it
|
|
|
|
|
didn't change, don't bother to send it back
|
|
|
|
|
again. */
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->flags = flags;
|
|
|
|
|
ctxt->type = tmptype;
|
|
|
|
|
ctxt->datum = datum;
|
|
|
|
|
(*decoder) (ctxt);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-09-19 21:31:18 +00:00
|
|
|
|
ctxt->type = 0;
|
|
|
|
|
ctxt->datum = 0;
|
|
|
|
|
(*decoder) (ctxt); /* Tell it we have finished. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
1996-03-30 01:29:07 +00:00
|
|
|
|
else /* matches `if (out_parameters)' */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* We are just returning void, but retframe needs to point to
|
|
|
|
|
something or else we can crash. */
|
|
|
|
|
retframe = alloca (sizeof(void*));
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
1996-03-30 01:29:07 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
switch (*rettype) {
|
|
|
|
|
case _C_CHR:
|
|
|
|
|
case _C_UCHR:
|
|
|
|
|
return apply_char(*(char*)retframe);
|
|
|
|
|
case _C_DBL:
|
|
|
|
|
return apply_double(*(double*)retframe);
|
|
|
|
|
case _C_FLT:
|
|
|
|
|
return apply_float(*(float*)retframe);
|
|
|
|
|
case _C_SHT:
|
|
|
|
|
case _C_USHT:
|
|
|
|
|
return apply_short(*(short*)retframe);
|
1998-08-13 20:45:32 +00:00
|
|
|
|
#if 0
|
1997-09-01 21:59:51 +00:00
|
|
|
|
case _C_ARY_B:
|
|
|
|
|
case _C_UNION_B:
|
|
|
|
|
case _C_STRUCT_B:
|
1998-08-13 20:45:32 +00:00
|
|
|
|
if (objc_sizeof_type(rettype) > 8) {
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return apply_block(*(void**)retframe);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-30 01:29:07 +00:00
|
|
|
|
/* Return the retval_t pointer to the return value. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
return retframe;
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
arglist_t
|
|
|
|
|
mframe_create_argframe(const char *types, void** retbuf)
|
|
|
|
|
{
|
1998-11-02 10:55:53 +00:00
|
|
|
|
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));
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Allocate the space for variables passed on the stack.
|
|
|
|
|
*/
|
1998-11-02 10:55:53 +00:00
|
|
|
|
if (stack_argsize)
|
|
|
|
|
{
|
|
|
|
|
argframe->arg_ptr = objc_calloc(stack_argsize, 1);
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
argframe->arg_ptr = 0;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
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);
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
MFRAME_SET_STRUCT_ADDR(argframe, rtype, *retbuf);
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
return argframe;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
mframe_destroy_argframe(const char *types, arglist_t argframe)
|
|
|
|
|
{
|
1998-11-02 10:55:53 +00:00
|
|
|
|
const char* rtype = objc_skip_type_qualifiers(types);
|
|
|
|
|
int stack_argsize = atoi(objc_skip_typespec(rtype));
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
if (stack_argsize)
|
|
|
|
|
{
|
1999-09-28 11:10:34 +00:00
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), argframe->arg_ptr);
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1999-09-28 11:10:34 +00:00
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), argframe);
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1998-07-15 12:50:16 +00:00
|
|
|
|
BOOL
|
|
|
|
|
mframe_decode_return (const char *type, void* buffer, void* retframe)
|
|
|
|
|
{
|
|
|
|
|
int size = 0;
|
|
|
|
|
|
|
|
|
|
type = objc_skip_type_qualifiers(type);
|
|
|
|
|
NSGetSizeAndAlignment(type, &size, 0);
|
|
|
|
|
|
|
|
|
|
switch (*type)
|
|
|
|
|
{
|
|
|
|
|
case _C_ID:
|
|
|
|
|
{
|
|
|
|
|
inline id retframe_id(void *rframe)
|
|
|
|
|
{
|
|
|
|
|
__builtin_return (rframe);
|
|
|
|
|
}
|
|
|
|
|
*(id*)buffer = retframe_id(retframe);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case _C_CLASS:
|
|
|
|
|
{
|
|
|
|
|
inline Class retframe_Class(void *rframe)
|
|
|
|
|
{
|
|
|
|
|
__builtin_return (rframe);
|
|
|
|
|
}
|
|
|
|
|
*(Class*)buffer = retframe_Class(retframe);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case _C_SEL:
|
|
|
|
|
{
|
|
|
|
|
inline SEL retframe_SEL(void *rframe)
|
|
|
|
|
{
|
|
|
|
|
__builtin_return (rframe);
|
|
|
|
|
}
|
|
|
|
|
*(SEL*)buffer = retframe_SEL(retframe);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case _C_CHR:
|
|
|
|
|
case _C_UCHR:
|
|
|
|
|
{
|
|
|
|
|
inline unsigned char retframe_char(void *rframe)
|
|
|
|
|
{
|
|
|
|
|
__builtin_return (rframe);
|
|
|
|
|
}
|
|
|
|
|
*(unsigned char*)buffer = retframe_char(retframe);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case _C_SHT:
|
|
|
|
|
case _C_USHT:
|
|
|
|
|
{
|
|
|
|
|
inline unsigned short retframe_short(void *rframe)
|
|
|
|
|
{
|
|
|
|
|
__builtin_return (rframe);
|
|
|
|
|
}
|
|
|
|
|
*(unsigned short*)buffer = retframe_short(retframe);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case _C_INT:
|
|
|
|
|
case _C_UINT:
|
|
|
|
|
{
|
|
|
|
|
inline unsigned int retframe_int(void *rframe)
|
|
|
|
|
{
|
|
|
|
|
__builtin_return (rframe);
|
|
|
|
|
}
|
|
|
|
|
*(unsigned int*)buffer = retframe_int(retframe);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case _C_LNG:
|
|
|
|
|
case _C_ULNG:
|
|
|
|
|
{
|
|
|
|
|
inline unsigned long retframe_long(void *rframe)
|
|
|
|
|
{
|
|
|
|
|
__builtin_return (rframe);
|
|
|
|
|
}
|
|
|
|
|
*(unsigned long*)buffer = retframe_long(retframe);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
case _C_LNG_LNG:
|
|
|
|
|
case _C_ULNG_LNG:
|
|
|
|
|
{
|
|
|
|
|
inline unsigned long long retframe_longlong(void *rframe)
|
|
|
|
|
{
|
|
|
|
|
__builtin_return (rframe);
|
|
|
|
|
}
|
|
|
|
|
*(unsigned long long*)buffer = retframe_longlong(retframe);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
1998-07-15 12:50:16 +00:00
|
|
|
|
case _C_FLT:
|
|
|
|
|
{
|
|
|
|
|
inline float retframe_float(void *rframe)
|
|
|
|
|
{
|
|
|
|
|
__builtin_return (rframe);
|
|
|
|
|
}
|
|
|
|
|
*(float*)buffer = retframe_float(retframe);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case _C_DBL:
|
|
|
|
|
{
|
|
|
|
|
inline double retframe_double(void *rframe)
|
|
|
|
|
{
|
|
|
|
|
__builtin_return (rframe);
|
|
|
|
|
}
|
|
|
|
|
*(double*)buffer = retframe_double(retframe);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case _C_PTR:
|
|
|
|
|
case _C_ATOM:
|
|
|
|
|
case _C_CHARPTR:
|
|
|
|
|
{
|
|
|
|
|
inline char* retframe_pointer(void *rframe)
|
|
|
|
|
{
|
|
|
|
|
__builtin_return (rframe);
|
|
|
|
|
}
|
|
|
|
|
*(char**)buffer = retframe_pointer(retframe);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case _C_ARY_B:
|
|
|
|
|
case _C_STRUCT_B:
|
|
|
|
|
case _C_UNION_B:
|
|
|
|
|
{
|
|
|
|
|
typedef struct {
|
2005-06-24 16:56:45 +00:00
|
|
|
|
char val[4];
|
1998-07-15 12:50:16 +00:00
|
|
|
|
} block;
|
|
|
|
|
inline block retframe_block(void *rframe)
|
|
|
|
|
{
|
|
|
|
|
__builtin_return (rframe);
|
|
|
|
|
}
|
|
|
|
|
*(block*)buffer = retframe_block(retframe);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case _C_VOID:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return NO; /* Unknown type. */
|
|
|
|
|
}
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void*
|
|
|
|
|
mframe_handle_return(const char* type, void* retval, arglist_t argframe)
|
|
|
|
|
{
|
1998-11-02 10:55:53 +00:00
|
|
|
|
retval_t retframe;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
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);
|
1998-08-13 20:45:32 +00:00
|
|
|
|
#if 1
|
1998-11-02 10:55:53 +00:00
|
|
|
|
void *dest;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
dest = MFRAME_GET_STRUCT_ADDR(argframe, type);
|
|
|
|
|
memcpy(dest, retval, size);
|
1998-08-13 20:45:32 +00:00
|
|
|
|
#else
|
1998-11-02 10:55:53 +00:00
|
|
|
|
if (size > 8)
|
|
|
|
|
{
|
|
|
|
|
return apply_block(*(void**)retval);
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
1998-11-02 10:55:53 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
memcpy(retframe, retval, size);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
memcpy(retframe, retval, objc_sizeof_type(type));
|
|
|
|
|
break;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-11-02 10:55:53 +00:00
|
|
|
|
return retframe;
|
1998-08-13 20:45:32 +00:00
|
|
|
|
}
|
|
|
|
|
|