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:
Richard Frith-MacDonald 1998-08-13 20:45:32 +00:00
parent 517bb29e48
commit be3ff6a3e3
5 changed files with 1150 additions and 872 deletions

View file

@ -1,9 +1,11 @@
/* Implementation for GNUstep NSInvocation object
Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
Created: May 1993
/* Implementation of NSInvocation for GNUStep
Copyright (C) 1998 Free Software Foundation, Inc.
Written: Richard Frith-Macdonald <richard@brainstorm.co.uk>
Date: August 1998
Based on code by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
This file is part of the GNUstep Base Library.
This library is free software; you can redistribute it and/or
@ -15,57 +17,547 @@
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.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
*/
#include <config.h>
#include <gnustep/base/preface.h>
#include <Foundation/NSException.h>
#include <Foundation/NSCoder.h>
#include <Foundation/NSInvocation.h>
#include <Foundation/NSMethodSignature.h>
#include <gnustep/base/Invocation.h>
#include <gnustep/base/behavior.h>
#include <gnustep/base/mframe.h>
@implementation NSInvocation
+ (void) initialize
+ (NSInvocation*) invocationWithMethodSignature: (NSMethodSignature*)signature
{
if (self == [NSInvocation class])
class_add_behavior (self, [MethodInvocation class]);
return [[[NSInvocation alloc] initWithMethodSignature: signature]
autorelease];
}
+ (NSInvocation*) invocationWithObjCTypes: (const char*) types
- (void) dealloc
{
return [[self alloc] initWithArgframe: NULL type: types];
if (argsRetained) {
[target release];
argsRetained = NO;
if (argframe && sig) {
int i;
for (i = 3; i <= numArgs; i++) {
if (*info[i].type == _C_CHARPTR) {
char *str;
mframe_get_arg(argframe, &info[i], &str);
objc_free(str);
}
else if (*info[i].type == _C_ID) {
id obj;
mframe_get_arg(argframe, &info[i], &obj);
[obj release];
}
}
}
}
if (argframe) {
mframe_destroy_argframe([sig methodType], argframe);
}
if (retval) {
objc_free(retval);
}
[sig release];
[super dealloc];
}
+ (NSInvocation*) invocationWithMethodSignature: (NSMethodSignature*)ms
#if 0
- (void)_verifySignature
{
return [self invocationWithObjCTypes: [ms methodType]];
const char* types;
struct objc_method_description* mth;
if(!target)
THROW([NullTargetException new]);
if(!selector)
THROW([NullSelectorException new]);
mth = (struct objc_method_description*)
(CLS_ISCLASS(((struct objc_class*)target)->class_pointer) ?
class_get_instance_method(
((struct objc_class*)target)->class_pointer, selector)
: class_get_class_method(
((struct objc_class*)target)->class_pointer, selector));
selector = mth ? mth->name : (SEL)0;
if(!selector)
THROW([NullSelectorException new]);
types = mth->types;
if(!types)
THROW([[CouldntGetTypeForSelector alloc] initForSelector:selector]);
if(sig) {
if(!sel_types_match(types, [sig types]))
THROW([[TypesDontMatchException alloc]
initWithTypes:types :[sig types]]);
}
else sig = [[NSMethodSignature sigWithObjCTypes:types] retain];
}
#endif
/*
* Accessing message elements.
*/
- (void) getArgument: (void*)buffer
atIndex: (int)index
{
if ((unsigned)index >= numArgs) {
[NSException raise: NSInvalidArgumentException
format: @"bad invocation argument index"];
}
if (index == 0) {
*(id*)buffer = target;
}
else if (index == 1) {
*(SEL*)buffer = selector;
}
else {
index++; /* Allow offset for return type info. */
mframe_get_arg(argframe, &info[index], buffer);
}
}
- (void) getReturnValue: (void*)buffer
{
const char *type;
type = [sig methodReturnType];
if (*info[0].type != _C_VOID) {
int length = info[0].size;
#if WORDS_BIGENDIAN
if (length < sizeof(void*))
length = sizeof(void*);
#endif
memcpy(buffer, retval, length);
}
}
- (SEL) selector
{
return selector;
}
- (void) setArgument: (void*)buffer
atIndex: (int)index
{
if ((unsigned)index >= numArgs) {
[NSException raise: NSInvalidArgumentException
format: @"bad invocation argument index"];
}
if (index == 0) {
[self setTarget: *(id*)buffer];
}
else if (index == 1) {
[self setSelector: *(SEL*)buffer];
}
else {
int i = index+1; /* Allow for return type in 'info' */
const char *type = info[i].type;
if (argsRetained && (*type == _C_ID || *type == _C_CHARPTR)) {
if (*type == _C_ID) {
id old;
mframe_get_arg(argframe, &info[i], &old);
mframe_set_arg(argframe, &info[i], buffer);
[*(id*)buffer retain];
if (old != nil) {
[old release];
}
}
else {
char *oldstr;
char *newstr = *(char**)buffer;
mframe_get_arg(argframe, &info[i], &oldstr);
if (newstr == 0) {
mframe_set_arg(argframe, &info[i], buffer);
}
else {
char *tmp = objc_malloc(strlen(newstr)+1);
strcpy(tmp, newstr);
mframe_set_arg(argframe, &info[i], tmp);
}
if (oldstr != 0) {
objc_free(oldstr);
}
}
}
else {
mframe_set_arg(argframe, &info[i], buffer);
}
}
}
- (void) setReturnValue: (void*)buffer
{
const char *type;
type = info[0].type;
if (*type != _C_VOID) {
int length = info[0].size;
#if WORDS_BIGENDIAN
if (length < sizeof(void*))
length = sizeof(void*);
#endif
memcpy(retval, buffer, length);
}
}
- (void) setSelector: (SEL)aSelector
{
selector = aSelector;
}
- (void) setTarget: (id)anObject
{
if (argsRetained) {
[anObject retain];
[target release];
}
target = anObject;
}
- (id) target
{
return target;
}
/*
* Managing arguments.
*/
- (BOOL) argumentsRetained
{
return argsRetained;
}
- (void)retainArguments
{
if (argsRetained) {
return;
}
else {
int i;
argsRetained = YES;
[target retain];
if (argframe == 0) {
return;
}
for (i = 3; i <= numArgs; i++) {
if (*info[i].type == _C_ID || *info[i].type == _C_CHARPTR) {
if (*info[i].type == _C_ID) {
id old;
mframe_get_arg(argframe, &info[i], &old);
if (old != nil) {
[old retain];
}
}
else {
char *str;
mframe_get_arg(argframe, &info[i], &str);
if (str != 0) {
char *tmp = objc_malloc(strlen(str)+1);
strcpy(tmp, str);
mframe_set_arg(argframe, &info[i], &tmp);
}
}
}
}
}
}
/*
* Dispatching an Invocation.
*/
- (void) invoke
{
[self invokeWithTarget: target];
}
- (void) invokeWithTarget:(id)anObject
{
id old_target;
retval_t returned;
IMP imp;
int stack_argsize;
/*
* A message to a nil object returns nil.
*/
if (anObject == nil) {
memset(retval, '\0', info[0].size); /* Clear return value */
return;
}
NSAssert(selector != 0, @"you must set the selector before invoking");
/*
* Temporarily set new target and copy it (and the selector) into the
* argframe.
*/
old_target = [target retain];
[self setTarget: anObject];
mframe_set_arg(argframe, &info[1], &target);
mframe_set_arg(argframe, &info[2], &selector);
imp = method_get_imp(object_is_instance(target) ?
class_get_instance_method(
((struct objc_class*)target)->class_pointer, selector)
: class_get_class_method(
((struct objc_class*)target)->class_pointer, selector));
/*
* If fast lookup failed, we may be forwarding or something ...
*/
if (imp == 0)
imp = objc_msg_lookup(target, selector);
[self setTarget: old_target];
[old_target release];
stack_argsize = [sig frameLength];
returned = __builtin_apply((void(*)(void))imp, argframe, stack_argsize);
if (info[0].size) {
mframe_decode_return(info[0].type, retval, returned);
}
}
/*
* Getting the method signature.
*/
- (NSMethodSignature*) methodSignature
{
#if 0
/* xxx This isn't really needed by the our implementation anyway. */
[self notImplemented: _cmd];
#else
SEL mysel = [self selector];
const char * my_sel_type;
if (mysel)
{
my_sel_type = sel_get_type(mysel);
if (my_sel_type)
return [NSMethodSignature signatureWithObjCTypes: my_sel_type];
else
return nil;
}
#endif
return nil;
return sig;
}
/* All other methods come from the MethodInvocation behavior. */
- (NSString*)description
{
/* Don't use -[NSString stringWithFormat:] method because it can cause
infinite recursion. */
char buffer[1024];
sprintf (buffer, "<%s %p selector: %s target: %s>", \
(char*)object_get_class_name(self), \
self, \
selector ? [NSStringFromSelector(selector) cString] : "nil", \
target ? [NSStringFromClass([target class]) cString] : "nil" \
);
return [NSString stringWithCString:buffer];
}
- (void) encodeWithCoder: (NSCoder*)aCoder
{
const char *types = [sig methodType];
int i;
[aCoder encodeValueOfObjCType: @encode(char*)
at: &types
withName: @"invocation types"];
[aCoder encodeBycopyObject: target
withName: @"target"];
[aCoder encodeValueOfObjCType: info[2].type
at: &selector
withName: @"selector"];
for (i = 3; i <= numArgs; i++) {
const char *type = info[i].type;
void *datum;
datum = mframe_arg_addr(argframe, &info[i]);
if (*type == _C_ID)
[aCoder encodeBycopyObject: *(id*)datum withName: @"arg"];
else
[aCoder encodeValueOfObjCType: type at: datum withName: @"arg"];
}
}
- (id) initWithCoder: (NSCoder*)aCoder
{
NSMethodSignature *newSig;
const char *types;
void *datum;
int i;
[aCoder decodeValueOfObjCType: @encode(char*) at: &types];
newSig = [NSMethodSignature signatureWithObjCTypes: types];
self = [self initWithMethodSignature: newSig];
target = [aCoder decodeObject];
[aCoder decodeValueOfObjCType: @encode(SEL) at: &selector];
for (i = 3; i <= numArgs; i++) {
const char *type = info[i].type;
datum = mframe_arg_addr(argframe, &info[i]);
if (*type == _C_ID)
*(id*)datum = [aCoder decodeObject];
else
[aCoder decodeValueOfObjCType: type at: datum];
}
argsRetained = YES;
}
@end
@implementation NSInvocation (GNUstep)
- initWithArgframe: (arglist_t)frame selector: (SEL)aSelector
{
const char *types;
NSMethodSignature *newSig;
types = sel_get_type(aSelector);
if (types == 0) {
types = sel_get_type(sel_get_any_typed_uid(sel_get_name(aSelector)));
}
if (types == 0) {
[NSException raise: NSInvalidArgumentException
format: @"Couldn't find encoding type for selector %s.",
sel_get_name(aSelector)];
}
newSig = [NSMethodSignature signatureWithObjCTypes: types];
self = [self initWithMethodSignature: newSig];
if (self) {
[self setSelector: aSelector];
/*
* Copy the argframe we were given.
*/
if (frame) {
int i;
mframe_get_arg(frame, &info[1], &target);
for (i = 1; i <= numArgs; i++) {
mframe_cpy_arg(argframe, frame, &info[i]);
}
}
}
return self;
}
/*
* This is the designated initialiser.
*/
- initWithMethodSignature: (NSMethodSignature*)aSignature
{
sig = [aSignature retain];
numArgs = [aSignature numberOfArguments];
info = [aSignature methodInfo];
argframe = mframe_create_argframe([sig methodType], &retval);
if (retval == 0 && info[0].size > 0) {
retval = objc_malloc(info[0].size);
}
return self;
}
- initWithSelector: (SEL)aSelector
{
return [self initWithArgframe: 0 selector: aSelector];
}
- initWithTarget: anObject selector: (SEL)aSelector, ...
{
va_list ap;
self = [self initWithArgframe: 0 selector: aSelector];
if (self) {
int i;
[self setTarget: anObject];
va_start (ap, aSelector);
for (i = 3; i <= numArgs; i++) {
const char *type = info[i].type;
unsigned size = info[i].size;
void *datum;
datum = mframe_arg_addr(argframe, &info[i]);
#define CASE_TYPE(_C,_T) case _C: *(_T*)datum = va_arg (ap, _T); break
switch (*type) {
case _C_ID:
*(id*)datum = va_arg (ap, id);
if (argsRetained)
[*(id*)datum retain];
break;
case _C_CHARPTR:
*(char**)datum = va_arg (ap, char*);
if (argsRetained) {
char *old = *(char**)datum;
if (old != 0) {
char *tmp = objc_malloc(strlen(old)+1);
strcpy(tmp, old);
*(char**)datum = tmp;
}
}
break;
CASE_TYPE(_C_CLASS, Class);
CASE_TYPE(_C_SEL, SEL);
CASE_TYPE(_C_LNG, long);
CASE_TYPE(_C_ULNG, unsigned long);
CASE_TYPE(_C_INT, int);
CASE_TYPE(_C_UINT, unsigned int);
CASE_TYPE(_C_SHT, short);
CASE_TYPE(_C_USHT, unsigned short);
CASE_TYPE(_C_CHR, char);
CASE_TYPE(_C_UCHR, unsigned char);
CASE_TYPE(_C_FLT, float);
CASE_TYPE(_C_DBL, double);
CASE_TYPE(_C_PTR, void*);
default:
{
memcpy(datum, va_arg(ap, typeof(char[size])), size);
} /* default */
}
}
}
return self;
}
- (void*) returnFrame: (arglist_t)argFrame
{
return mframe_handle_return(info[0].type, retval, argFrame);
}
@end
@implementation NSInvocation (BackwardCompatibility)
- (void) invokeWithObject: (id)obj
{
[self invokeWithTarget: (id)obj];
}
@end

View file

@ -1,8 +1,10 @@
/* Implementation of NSMethodSignature for GNUStep
Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
Copyright (C) 1994, 1995, 1996, 1998 Free Software Foundation, Inc.
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
Date: August 1994
Rewritten: Richard Frith-Macdonald <richard@brainstorm.co.uk>
Date: August 1998
This file is part of the GNUstep Base Library.
@ -23,585 +25,111 @@
#include <config.h>
#include <gnustep/base/preface.h>
/* Deal with memchr: */
#if STDC_HEADERS || HAVE_STRING_H
#include <string.h>
/* An ANSI string.h and pre-ANSI memory.h might conflict. */
#if !STDC_HEADERS && HAVE_MEMORY_H
#include <memory.h>
#endif /* not STDC_HEADERS and HAVE_MEMORY_H */
#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 */
#include <gnustep/base/mframe.h>
#include <Foundation/NSMethodSignature.h>
#include <Foundation/NSException.h>
#include <Foundation/NSString.h>
/*
* These macros incorporated from libFoundation by R. Frith-Macdonald
* are subject to the following copyright rather than the LGPL -
*
* Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea.
* All rights reserved.
*
* Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>
*
* This file is part of libFoundation.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation.
*
* We disclaim all warranties with regard to this software, including all
* implied warranties of merchantability and fitness, in no event shall
* we be liable for any special, indirect or consequential damages or any
* damages whatsoever resulting from loss of use, data or profits, whether in
* an action of contract, negligence or other tortious action, arising out of
* or in connection with the use or performance of this software.
*/
#ifndef ROUND
#define ROUND(V, A) \
({ typeof(V) __v=(V); typeof(A) __a=(A); \
__a*((__v+__a-1)/__a); })
#endif
#if defined(alpha) && defined(linux)
#ifndef OBJC_FORWARDING_STACK_OFFSET
#define OBJC_FORWARDING_STACK_OFFSET 0
#endif
#ifndef OBJC_FORWARDING_MIN_OFFSET
#define OBJC_FORWARDING_MIN_OFFSET 0
#endif
#define CUMULATIVE_ARGS int
#define INIT_CUMULATIVE_ARGS(CUM) ((CUM) = 0)
#define FUNCTION_ARG_ENCODING(CUM, TYPE, STACK_ARGSIZE) \
({ id encoding; \
const char* type = [(TYPE) cString]; \
int align = objc_alignof_type(type); \
int type_size = objc_sizeof_type(type); \
\
(CUM) = ROUND((CUM), align); \
encoding = [NSString stringWithFormat:@"%@%d", \
(TYPE), \
(CUM) + OBJC_FORWARDING_STACK_OFFSET]; \
(STACK_ARGSIZE) = (CUM) + type_size; \
(CUM) += ROUND(type_size, sizeof(void*)); \
encoding; })
#endif /* i386 linux */
#if defined(hppa)
#ifndef OBJC_FORWARDING_STACK_OFFSET
#define OBJC_FORWARDING_STACK_OFFSET 0
#endif
#ifndef OBJC_FORWARDING_MIN_OFFSET
#define OBJC_FORWARDING_MIN_OFFSET 0
#endif
#define CUMULATIVE_ARGS int
#define INIT_CUMULATIVE_ARGS(CUM) ((CUM) = 0)
#define FUNCTION_ARG_SIZE(TYPESIZE) \
((TYPESIZE + 3) / 4)
#define FUNCTION_ARG_ENCODING(CUM, TYPE, STACK_ARGSIZE) \
({ id encoding; \
int align = objc_alignof_type([(TYPE) cString]); \
int type_size = objc_sizeof_type([(TYPE) cString]); \
const char* type = [(TYPE) cString]; \
\
(CUM) = ROUND((CUM), align); \
encoding = [NSString stringWithFormat:@"%@%d", \
(TYPE), \
(CUM) + OBJC_FORWARDING_STACK_OFFSET]; \
if((*type == _C_STRUCT_B || *type == _C_UNION_B || *type == _C_ARY_B)) \
(STACK_ARGSIZE) = (CUM) + ROUND(type_size, align); \
else (STACK_ARGSIZE) = (CUM) + type_size; \
\
/* Compute the new value of cumulative args */ \
((((CUM) & 01) && FUNCTION_ARG_SIZE(type_size) > 1) && (CUM)++); \
(CUM) += FUNCTION_ARG_SIZE(type_size); \
encoding; })
#endif /* hppa */
#if defined(i386) && defined(linux)
#ifndef OBJC_FORWARDING_STACK_OFFSET
#define OBJC_FORWARDING_STACK_OFFSET 0
#endif
#ifndef OBJC_FORWARDING_MIN_OFFSET
#define OBJC_FORWARDING_MIN_OFFSET 0
#endif
#define CUMULATIVE_ARGS int
#define INIT_CUMULATIVE_ARGS(CUM) ((CUM) = 0)
#define FUNCTION_ARG_ENCODING(CUM, TYPE, STACK_ARGSIZE) \
({ id encoding; \
const char* type = [(TYPE) cString]; \
int align = objc_alignof_type(type); \
int type_size = objc_sizeof_type(type); \
\
(CUM) = ROUND((CUM), align); \
encoding = [NSString stringWithFormat:@"%@%d", \
(TYPE), \
(CUM) + OBJC_FORWARDING_STACK_OFFSET]; \
if((*type == _C_STRUCT_B || *type == _C_UNION_B || *type == _C_ARY_B) \
&& type_size > 2) \
(STACK_ARGSIZE) = (CUM) + ROUND(type_size, align); \
else (STACK_ARGSIZE) = (CUM) + type_size; \
(CUM) += ROUND(type_size, sizeof(void*)); \
encoding; })
#endif /* i386 linux */
#if defined(m68k)
#ifndef OBJC_FORWARDING_STACK_OFFSET
#define OBJC_FORWARDING_STACK_OFFSET 0
#endif
#ifndef OBJC_FORWARDING_MIN_OFFSET
#define OBJC_FORWARDING_MIN_OFFSET 0
#endif
#define CUMULATIVE_ARGS int
#define INIT_CUMULATIVE_ARGS(CUM) ((CUM) = 0)
#define FUNCTION_ARG_ENCODING(CUM, TYPE, STACK_ARGSIZE) \
({ id encoding; \
const char* type = [(TYPE) cString]; \
int align = objc_alignof_type(type); \
int type_size = objc_sizeof_type(type); \
\
(CUM) = ROUND((CUM), align); \
if(type_size < sizeof(int)) \
(CUM) += sizeof(int) - ROUND(type_size, align); \
encoding = [NSString stringWithFormat:@"%@%d", \
(TYPE), \
(CUM) + OBJC_FORWARDING_STACK_OFFSET]; \
if((*type == _C_STRUCT_B || *type == _C_UNION_B || *type == _C_ARY_B) \
&& type_size > 2) \
(STACK_ARGSIZE) = (CUM) + ROUND(type_size, align); \
else (STACK_ARGSIZE) = (CUM) + ROUND(type_size, align); \
(CUM) += type_size < sizeof(int) \
? ROUND(type_size, align) \
: ROUND(type_size, sizeof(void*)); \
encoding; })
#endif /* m68k */
#if defined(sparc) && defined(solaris)
#ifndef OBJC_FORWARDING_STACK_OFFSET
#define OBJC_FORWARDING_STACK_OFFSET 0
#endif
#ifndef OBJC_FORWARDING_MIN_OFFSET
#define OBJC_FORWARDING_MIN_OFFSET 0
#endif
/* From config/sparc/sparc.h in the GCC sources:
On SPARC the first six args are normally in registers
and the rest are pushed. Any arg that starts within the first 6 words
is at least partially passed in a register unless its data type forbids.
For v9, the first 6 int args are passed in regs and the first N
float args are passed in regs (where N is such that %f0-15 are filled).
The rest are pushed. Any arg that starts within the first 6 words
is at least partially passed in a register unless its data type forbids.
...
The SPARC ABI stipulates passing struct arguments (of any size) and
(!v9) quad-precision floats by invisible reference.
*/
enum sparc_arg_location { IN_REGS = 0, ON_STACK = 1 };
struct sparc_args {
int offsets[2]; /* 0 for args in regs, 1 for the rest of args on stack */
int onStack;
};
#define CUMULATIVE_ARGS struct sparc_args
/* Initialize a variable of type CUMULATIVE_ARGS. This macro is called before
processing the first argument of a method. */
#define INIT_CUMULATIVE_ARGS(CUM) \
({ (CUM).offsets[0] = 8; /* encoding in regs starts from 8 */ \
(CUM).offsets[1] = 20; /* encoding in regs starts from 20 or 24 */ \
(CUM).onStack = NO; })
#define GET_SPARC_ARG_LOCATION(CUM, CSTRING_TYPE, TYPESIZE) \
((CUM).onStack \
? ON_STACK \
: ((CUM).offsets[IN_REGS] + TYPESIZE <= 6 * sizeof(int) + 8 \
? (((CUM).offsets[IN_REGS] + TYPESIZE <= 6 * sizeof(int) + 4 \
? 0 : ((CUM).offsets[ON_STACK] += 4)),\
IN_REGS) \
: ((CUM).onStack = YES, ON_STACK)))
#define FUNCTION_ARG_ENCODING(CUM, TYPE, STACK_ARGSIZE) \
({ id encoding; \
const char* type = [(TYPE) cString]; \
int align = objc_alignof_type(type); \
int type_size = objc_sizeof_type(type); \
int arg_location = GET_SPARC_ARG_LOCATION(CUM, type, type_size); \
\
(CUM).offsets[arg_location] \
= ROUND((CUM).offsets[arg_location], align); \
if(type_size < sizeof(int)) \
(CUM).offsets[arg_location] += sizeof(int) - ROUND(type_size, align); \
encoding = [NSString stringWithFormat: \
(arg_location == IN_REGS ? @"%@+%d" : @"%@%d"), \
(TYPE), \
(arg_location == IN_REGS \
? ((CUM).offsets[arg_location] \
+ OBJC_FORWARDING_STACK_OFFSET) \
: (CUM).offsets[arg_location])]; \
if(arg_location == ON_STACK) { \
if((*type == _C_STRUCT_B || *type == _C_UNION_B \
|| *type == _C_ARY_B)) \
(STACK_ARGSIZE) = (CUM).offsets[ON_STACK] + ROUND(type_size, align); \
else (STACK_ARGSIZE) = (CUM).offsets[ON_STACK] + type_size; \
} \
(CUM).offsets[arg_location] += \
type_size < sizeof(int) \
? ROUND(type_size, align) \
: ROUND(type_size, sizeof(void*)); \
encoding; })
#endif /* sparc solaris */
#if defined(sparc) && defined(linux)
#ifndef OBJC_FORWARDING_STACK_OFFSET
#define OBJC_FORWARDING_STACK_OFFSET 0
#endif
#ifndef OBJC_FORWARDING_MIN_OFFSET
#define OBJC_FORWARDING_MIN_OFFSET 0
#endif
enum sparc_arg_location { IN_REGS = 0, ON_STACK = 1 };
struct sparc_args {
int offsets[2]; /* 0 for args in regs, 1 for the rest of args on stack */
int onStack;
};
#define CUMULATIVE_ARGS struct sparc_args
#define INIT_CUMULATIVE_ARGS(CUM) \
({ (CUM).offsets[0] = 8; /* encoding in regs starts from 8 */ \
(CUM).offsets[1] = 20; /* encoding in regs starts from 20 or 24 */ \
(CUM).onStack = NO; })
#define GET_SPARC_ARG_LOCATION(CUM, CSTRING_TYPE, TYPESIZE) \
((CUM).onStack \
? ON_STACK \
: ((CUM).offsets[IN_REGS] + TYPESIZE <= 6 * sizeof(int) + 8 \
? (((CUM).offsets[IN_REGS] + TYPESIZE <= 6 * sizeof(int) + 4 \
? 0 : ((CUM).offsets[ON_STACK] += 4)),\
IN_REGS) \
: ((CUM).onStack = YES, ON_STACK)))
#define FUNCTION_ARG_ENCODING(CUM, TYPE, STACK_ARGSIZE) \
({ id encoding; \
const char* type = [(TYPE) cString]; \
int align = objc_alignof_type(type); \
int type_size = objc_sizeof_type(type); \
int arg_location = GET_SPARC_ARG_LOCATION(CUM, type, type_size); \
\
(CUM).offsets[arg_location] \
= ROUND((CUM).offsets[arg_location], align); \
if(type_size < sizeof(int)) \
(CUM).offsets[arg_location] += sizeof(int) - ROUND(type_size, align); \
encoding = [NSString stringWithFormat: \
(arg_location == IN_REGS ? @"%@+%d" : @"%@%d"), \
(TYPE), \
(arg_location == IN_REGS \
? ((CUM).offsets[arg_location] \
+ OBJC_FORWARDING_STACK_OFFSET) \
: (CUM).offsets[arg_location])]; \
if(arg_location == ON_STACK) { \
if((*type == _C_STRUCT_B || *type == _C_UNION_B \
|| *type == _C_ARY_B)) \
(STACK_ARGSIZE) = (CUM).offsets[ON_STACK] + ROUND(type_size, align); \
else (STACK_ARGSIZE) = (CUM).offsets[ON_STACK] + type_size; \
} \
(CUM).offsets[arg_location] += \
type_size < sizeof(int) \
? ROUND(type_size, align) \
: ROUND(type_size, sizeof(void*)); \
encoding; })
#endif /* sparc linux */
#ifndef FUNCTION_ARG_ENCODING
#ifndef OBJC_FORWARDING_STACK_OFFSET
#define OBJC_FORWARDING_STACK_OFFSET 0
#endif
#ifndef OBJC_FORWARDING_MIN_OFFSET
#define OBJC_FORWARDING_MIN_OFFSET 0
#endif
#define CUMULATIVE_ARGS int
#define INIT_CUMULATIVE_ARGS(CUM) ((CUM) = 0)
#define FUNCTION_ARG_ENCODING(CUM, TYPE, STACK_ARGSIZE) \
({ id encoding; \
const char* type = [(TYPE) cString]; \
int align = objc_alignof_type(type); \
int type_size = objc_sizeof_type(type); \
\
(CUM) = ROUND((CUM), align); \
encoding = [NSString stringWithFormat:@"%@%d", \
(TYPE), \
(CUM) + OBJC_FORWARDING_STACK_OFFSET]; \
(STACK_ARGSIZE) = (CUM) + type_size; \
(CUM) += ROUND(type_size, sizeof(void*)); \
encoding; })
#endif /* generic */
/*
* End of libFoundation macros.
*/
static NSString*
isolate_type(const char* types)
{
const char* p = objc_skip_typespec(types);
return [NSString stringWithCString:types length:(unsigned)(p - types)];
}
static int
types_get_size_of_arguments(const char *types)
{
const char* type = objc_skip_typespec (types);
return atoi (type);
}
static int
types_get_number_of_arguments (const char *types)
{
int i = 0;
const char* type = types;
while (*type)
{
type = objc_skip_argspec (type);
i += 1;
}
return i - 1;
}
static BOOL
rtn_type_is_oneway(const char * types)
{
char * oneway_pos = strrchr(types, _C_ONEWAY);
if (oneway_pos != (char *)0)
return YES;
else
return NO;
}
@implementation NSMethodSignature
+ (NSMethodSignature*) signatureWithObjCTypes: (const char*)t
{
NSMethodSignature *newMs = [[NSMethodSignature alloc] autorelease];
const char *positionOfSizeInfo;
const char *positionOfFirstParam;
int len;
NSMethodSignature *newMs = [[NSMethodSignature alloc] autorelease];
positionOfSizeInfo = objc_skip_typespec(t);
newMs->methodTypes = mframe_build_signature(t, &newMs->argFrameLength,
&newMs->numArgs, 0);
if (!isdigit(*positionOfSizeInfo))
{
CUMULATIVE_ARGS cumulative_args;
int stack_argsize = 0;
id encoding = [[NSMutableString new] autorelease];
const char* retval = t;
/* Skip returned value. */
t = objc_skip_typespec(t);
newMs->numArgs = 0;
INIT_CUMULATIVE_ARGS(cumulative_args);
while(*t) {
[encoding appendString:
FUNCTION_ARG_ENCODING(cumulative_args,
isolate_type(t),
stack_argsize)];
t = objc_skip_typespec(t);
newMs->numArgs++;
}
encoding = [NSString stringWithFormat:@"%@%d%@",
isolate_type(retval), stack_argsize, encoding];
newMs->types = objc_malloc([encoding cStringLength]+1);
[encoding getCString: newMs->types];
}
else
{
newMs->types = objc_malloc(strlen(t) + 1);
strcpy(newMs->types, t);
newMs->numArgs = types_get_number_of_arguments(newMs->types);
}
positionOfFirstParam = objc_skip_typespec(newMs->types);
len = positionOfFirstParam - newMs->types;
newMs->returnTypes = objc_malloc(len + 1);
memcpy(newMs->returnTypes, newMs->types, len);
newMs->returnTypes[len] = '\0';
newMs->argFrameLength = types_get_size_of_arguments(newMs->types);
if (*newMs->types == _C_VOID)
newMs->returnFrameLength = 0;
else
newMs->returnFrameLength = objc_sizeof_type(newMs->types);
return newMs;
return newMs;
}
- (NSArgumentInfo) argumentInfoAtIndex: (unsigned)index
{
/* 0 1 2 3 position
"C0@+8:+12C+19C+23" types
^ ^ ^ ^
(index == 0) tmptype->0, pretmptype->0
(index == 1) tmptype->1, pretmptype->0
(index == 2) tmptype->2, pretmptype->1
(index == 3) tmptype->3, pretmptype->2
and so on... */
const char *tmptype = types;
const char *pretmptype = NULL;
int offset, preoffset, size;
const char * result_type;
if (index >= numArgs)
[NSException raise:NSInvalidArgumentException
format:@"Index too high."];
do
{
pretmptype = tmptype;
tmptype = objc_skip_argspec (tmptype);
if (index >= numArgs) {
[NSException raise: NSInvalidArgumentException
format: @"Index too high."];
}
while (index--);
result_type = tmptype;
if (pretmptype == types) // index == 0
{
tmptype = objc_skip_typespec(tmptype);
if (*tmptype == '+')
offset = atoi(tmptype + 1);
else
#if m68k
offset = (atoi(tmptype) - 8);
#else
offset = atoi(tmptype);
#endif // m68k
size = offset;
if (info == 0) {
[self methodInfo];
}
else // index != 0
{
tmptype = objc_skip_typespec(tmptype);
pretmptype = objc_skip_typespec(pretmptype);
if (*tmptype == '+')
offset = atoi(tmptype + 1);
else
#if m68k
offset = (atoi(tmptype) - 8);
#else
offset = atoi(tmptype);
#endif // m68k
if (*pretmptype == '+')
preoffset = atoi(pretmptype + 1);
else
#if m68k
preoffset = (atoi(pretmptype) - 8);
#else
preoffset = atoi(pretmptype);
size = offset - preoffset;
}
#endif // m68k
return (NSArgumentInfo){offset, size, (char*)result_type};
return info[index+1];
}
- (unsigned) frameLength
{
return argFrameLength;
return argFrameLength;
}
- (const char*) getArgumentTypeAtIndex: (unsigned)index
{
if (index >= numArgs) {
[NSException raise: NSInvalidArgumentException
format: @"Index too high."];
}
if (info == 0) {
[self methodInfo];
}
return info[index+1].type;
}
- (BOOL) isOneway
{
return rtn_type_is_oneway(returnTypes);
if (info == 0) {
[self methodInfo];
}
return (info[0].qual & _F_ONEWAY) ? YES : NO;
}
- (unsigned) methodReturnLength
{
return returnFrameLength;
if (info == 0) {
[self methodInfo];
}
return info[0].size;
}
- (char*) methodReturnType
- (const char*) methodReturnType
{
return returnTypes;
if (info == 0) {
[self methodInfo];
}
return info[0].type;
}
- (unsigned) numberOfArguments
{
return numArgs;
return numArgs;
}
- (void) dealloc
{
objc_free(types);
objc_free(returnTypes);
[super dealloc];
if (methodTypes)
objc_free((void*)methodTypes);
if (info)
objc_free((void*)info);
[super dealloc];
}
@end
@implementation NSMethodSignature(GNU)
- (char*) methodType
- (NSArgumentInfo*) methodInfo
{
return types;
if (info == 0) {
const char *types = methodTypes;
int i;
info = objc_malloc(sizeof(NSArgumentInfo)*(numArgs+1));
for (i = 0; i <= numArgs; i++) {
types = mframe_next_arg(types, &info[i]);
}
}
return info;
}
- (const char*) methodType
{
return methodTypes;
}
@end

View file

@ -25,6 +25,7 @@
#include <gnustep/base/preface.h>
#include <Foundation/NSObjCRuntime.h>
#include <Foundation/NSString.h>
#include <gnustep/base/mframe.h>
NSString *
NSStringFromSelector(SEL aSelector)
@ -58,176 +59,14 @@ NSStringFromClass(Class aClass)
return nil;
}
#ifdef MAX
#undef MAX
#endif
#define MAX(X, Y) \
({ typeof(X) __x = (X), __y = (Y); \
(__x > __y ? __x : __y); })
#ifdef ROUND
#undef ROUND
#endif
#define ROUND(V, A) \
({ typeof(V) __v=(V); typeof(A) __a=(A); \
__a*((__v+__a-1)/__a); })
/* This function was built by copying and modifying code from the objc runtime
* rather than calling the objc runtime functions directly. I did this for
* efficiency, and because the existing runtime can't cope with 'void'.
*/
const char *
NSGetSizeAndAlignment(const char *typePtr, unsigned *sizep, unsigned *alignp)
{
unsigned int size;
unsigned int align;
/* Skip any leading type qualifiers */
while (*typePtr == _C_CONST
|| *typePtr == _C_IN
|| *typePtr == _C_INOUT
|| *typePtr == _C_OUT
|| *typePtr == _C_BYCOPY
#ifdef _C_BYREF
|| *typePtr == _C_BYREF
#endif
|| *typePtr == _C_ONEWAY)
{
typePtr++;
}
switch(*typePtr++)
{
case _C_ID:
size = sizeof(id);
align = __alignof__(id);
break;
case _C_CLASS:
size = sizeof(Class);
align = __alignof__(Class);
break;
case _C_SEL:
size = sizeof(SEL);
align = __alignof__(SEL);
break;
case _C_CHR:
size = sizeof(char);
align = __alignof__(char);
break;
case _C_UCHR:
size = sizeof(unsigned char);
align = __alignof__(unsigned char);
break;
case _C_SHT:
size = sizeof(short);
align = __alignof__(short);
break;
case _C_USHT:
size = sizeof(unsigned short);
align = __alignof__(unsigned short);
break;
case _C_INT:
size = sizeof(int);
align = __alignof__(int);
break;
case _C_UINT:
size = sizeof(unsigned int);
align = __alignof__(unsigned int);
break;
case _C_LNG:
size = sizeof(long);
align = __alignof__(long);
break;
case _C_ULNG:
size = sizeof(unsigned long);
align = __alignof__(unsigned long);
break;
case _C_FLT:
size = sizeof(float);
align = __alignof__(float);
break;
case _C_DBL:
size = sizeof(double);
align = __alignof__(double);
break;
case _C_PTR:
case _C_ATOM:
case _C_CHARPTR:
size = sizeof(char*);
align = __alignof__(char*);
break;
case _C_ARY_B:
{
int len = atoi(typePtr);
while (isdigit(*typePtr))
typePtr++;
typePtr = NSGetSizeAndAlignment(typePtr, &size, &align);
size *= len;
}
break;
case _C_STRUCT_B:
{
struct { int x; double y; } fooalign;
int a;
int s;
align = __alignof__(fooalign);
size = 0;
while (*typePtr != _C_STRUCT_E && *typePtr++ != '=');
while (*typePtr != _C_STRUCT_E)
{
typePtr = NSGetSizeAndAlignment(typePtr, &s, &a);
align = MAX (align, a);
size = ROUND (size, a);
size += s; /* add component size */
}
typePtr++;
}
case _C_UNION_B:
{
int a;
int s;
align = 0;
size = 0;
while (*typePtr != _C_STRUCT_E && *typePtr++ != '=');
while (*typePtr != _C_STRUCT_E)
{
typePtr = NSGetSizeAndAlignment(typePtr, &s, &a);
align = MAX (align, a);
size = MAX (size, s);
}
typePtr++;
}
case _C_VOID:
size = 0;
align = 1;
break;
default:
return 0; /* Unknown type. */
}
if (alignp)
*alignp = align;
NSArgumentInfo info;
typePtr = mframe_next_arg(typePtr, &info);
if (sizep)
*sizep = size;
return typePtr;
*sizep = info.size;
if (alignp)
*alignp = info.align;
}

View file

@ -60,6 +60,21 @@
* Define a structure to hold information that is held locally
* (before the start) in each object.
*/
typedef struct obj_layout_unpadded {
#if defined(REFCNT_LOCAL)
unsigned retained;
#endif
#if defined(CACHE_ZONE)
NSZone *zone;
#endif
} unp;
/*
* Now do the REAL version - using the other version to determine
* what padding (if any) is required to get the alignment of the
* structure correct.
*/
struct obj_layout {
#if defined(REFCNT_LOCAL)
unsigned retained;
@ -67,6 +82,7 @@ struct obj_layout {
#if defined(CACHE_ZONE)
NSZone *zone;
#endif
char padding[__alignof(double) - sizeof(unp)%__alignof__(double)];
};
typedef struct obj_layout *obj;
@ -439,24 +455,12 @@ static BOOL double_release_check_enabled = NO;
- (retval_t) forward:(SEL)aSel :(arglist_t)argFrame
{
void *retFrame;
NSMethodSignature *sig;
NSInvocation *inv;
int retLength;
inv = [[[NSInvocation alloc] initWithArgframe: argFrame
selector: aSel] autorelease];
/* is this right? */
sig = [inv methodSignature];
retLength = [sig methodReturnLength];
/* Make sure we have something even if we are returnign void */
if (retLength == 0)
retLength = sizeof(void*);
retFrame = (void*) alloca(retLength);
[self forwardInvocation:inv];
[inv getReturnValue: retFrame];
return retFrame;
return [inv returnFrame: argFrame];
}
- (void) forwardInvocation: (NSInvocation*)anInvocation

View file

@ -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;
}