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