mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 08:21:25 +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
513ac17aa2
commit
d8f84859f0
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 file is part of the GNUstep Base Library.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
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
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Library General Public License for more details.
|
Library General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
You should have received a copy of the GNU Library General Public
|
||||||
License along with this library; if not, write to the Free
|
License along with this library; if not, write to the Free
|
||||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <Foundation/NSException.h>
|
||||||
#include <gnustep/base/preface.h>
|
#include <Foundation/NSCoder.h>
|
||||||
#include <Foundation/NSInvocation.h>
|
#include <Foundation/NSInvocation.h>
|
||||||
#include <Foundation/NSMethodSignature.h>
|
#include <gnustep/base/mframe.h>
|
||||||
#include <gnustep/base/Invocation.h>
|
|
||||||
#include <gnustep/base/behavior.h>
|
|
||||||
|
|
||||||
@implementation NSInvocation
|
@implementation NSInvocation
|
||||||
|
|
||||||
+ (void) initialize
|
+ (NSInvocation*) invocationWithMethodSignature: (NSMethodSignature*)signature
|
||||||
{
|
{
|
||||||
if (self == [NSInvocation class])
|
return [[[NSInvocation alloc] initWithMethodSignature: signature]
|
||||||
class_add_behavior (self, [MethodInvocation class]);
|
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
|
- (NSMethodSignature*) methodSignature
|
||||||
{
|
{
|
||||||
#if 0
|
return sig;
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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
|
@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
|
/* 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>
|
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
||||||
Date: August 1994
|
Date: August 1994
|
||||||
|
Rewritten: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||||
|
Date: August 1998
|
||||||
|
|
||||||
This file is part of the GNUstep Base Library.
|
This file is part of the GNUstep Base Library.
|
||||||
|
|
||||||
|
@ -23,585 +25,111 @@
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <gnustep/base/preface.h>
|
#include <gnustep/base/preface.h>
|
||||||
|
#include <gnustep/base/mframe.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 <Foundation/NSMethodSignature.h>
|
#include <Foundation/NSMethodSignature.h>
|
||||||
#include <Foundation/NSException.h>
|
#include <Foundation/NSException.h>
|
||||||
#include <Foundation/NSString.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
|
@implementation NSMethodSignature
|
||||||
|
|
||||||
+ (NSMethodSignature*) signatureWithObjCTypes: (const char*)t
|
+ (NSMethodSignature*) signatureWithObjCTypes: (const char*)t
|
||||||
{
|
{
|
||||||
NSMethodSignature *newMs = [[NSMethodSignature alloc] autorelease];
|
NSMethodSignature *newMs = [[NSMethodSignature alloc] autorelease];
|
||||||
const char *positionOfSizeInfo;
|
|
||||||
const char *positionOfFirstParam;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
positionOfSizeInfo = objc_skip_typespec(t);
|
newMs->methodTypes = mframe_build_signature(t, &newMs->argFrameLength,
|
||||||
|
&newMs->numArgs, 0);
|
||||||
|
|
||||||
if (!isdigit(*positionOfSizeInfo))
|
return newMs;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArgumentInfo) argumentInfoAtIndex: (unsigned)index
|
- (NSArgumentInfo) argumentInfoAtIndex: (unsigned)index
|
||||||
{
|
{
|
||||||
/* 0 1 2 3 position
|
if (index >= numArgs) {
|
||||||
"C0@+8:+12C+19C+23" types
|
[NSException raise: NSInvalidArgumentException
|
||||||
^ ^ ^ ^
|
format: @"Index too high."];
|
||||||
(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);
|
|
||||||
}
|
}
|
||||||
while (index--);
|
if (info == 0) {
|
||||||
|
[self methodInfo];
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
else // index != 0
|
return info[index+1];
|
||||||
{
|
|
||||||
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};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (unsigned) frameLength
|
- (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
|
- (BOOL) isOneway
|
||||||
{
|
{
|
||||||
return rtn_type_is_oneway(returnTypes);
|
if (info == 0) {
|
||||||
|
[self methodInfo];
|
||||||
|
}
|
||||||
|
return (info[0].qual & _F_ONEWAY) ? YES : NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (unsigned) methodReturnLength
|
- (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
|
- (unsigned) numberOfArguments
|
||||||
{
|
{
|
||||||
return numArgs;
|
return numArgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) dealloc
|
- (void) dealloc
|
||||||
{
|
{
|
||||||
objc_free(types);
|
if (methodTypes)
|
||||||
objc_free(returnTypes);
|
objc_free((void*)methodTypes);
|
||||||
[super dealloc];
|
if (info)
|
||||||
|
objc_free((void*)info);
|
||||||
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation NSMethodSignature(GNU)
|
@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
|
@end
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <gnustep/base/preface.h>
|
#include <gnustep/base/preface.h>
|
||||||
#include <Foundation/NSObjCRuntime.h>
|
#include <Foundation/NSObjCRuntime.h>
|
||||||
#include <Foundation/NSString.h>
|
#include <Foundation/NSString.h>
|
||||||
|
#include <gnustep/base/mframe.h>
|
||||||
|
|
||||||
NSString *
|
NSString *
|
||||||
NSStringFromSelector(SEL aSelector)
|
NSStringFromSelector(SEL aSelector)
|
||||||
|
@ -58,176 +59,14 @@ NSStringFromClass(Class aClass)
|
||||||
return nil;
|
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 *
|
const char *
|
||||||
NSGetSizeAndAlignment(const char *typePtr, unsigned *sizep, unsigned *alignp)
|
NSGetSizeAndAlignment(const char *typePtr, unsigned *sizep, unsigned *alignp)
|
||||||
{
|
{
|
||||||
unsigned int size;
|
NSArgumentInfo info;
|
||||||
unsigned int align;
|
typePtr = mframe_next_arg(typePtr, &info);
|
||||||
|
|
||||||
/* 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;
|
|
||||||
if (sizep)
|
if (sizep)
|
||||||
*sizep = size;
|
*sizep = info.size;
|
||||||
return typePtr;
|
if (alignp)
|
||||||
|
*alignp = info.align;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,21 @@
|
||||||
* Define a structure to hold information that is held locally
|
* Define a structure to hold information that is held locally
|
||||||
* (before the start) in each object.
|
* (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 {
|
struct obj_layout {
|
||||||
#if defined(REFCNT_LOCAL)
|
#if defined(REFCNT_LOCAL)
|
||||||
unsigned retained;
|
unsigned retained;
|
||||||
|
@ -67,6 +82,7 @@ struct obj_layout {
|
||||||
#if defined(CACHE_ZONE)
|
#if defined(CACHE_ZONE)
|
||||||
NSZone *zone;
|
NSZone *zone;
|
||||||
#endif
|
#endif
|
||||||
|
char padding[__alignof(double) - sizeof(unp)%__alignof__(double)];
|
||||||
};
|
};
|
||||||
typedef struct obj_layout *obj;
|
typedef struct obj_layout *obj;
|
||||||
|
|
||||||
|
@ -439,24 +455,12 @@ static BOOL double_release_check_enabled = NO;
|
||||||
|
|
||||||
- (retval_t) forward:(SEL)aSel :(arglist_t)argFrame
|
- (retval_t) forward:(SEL)aSel :(arglist_t)argFrame
|
||||||
{
|
{
|
||||||
void *retFrame;
|
|
||||||
NSMethodSignature *sig;
|
|
||||||
NSInvocation *inv;
|
NSInvocation *inv;
|
||||||
int retLength;
|
|
||||||
|
|
||||||
inv = [[[NSInvocation alloc] initWithArgframe: argFrame
|
inv = [[[NSInvocation alloc] initWithArgframe: argFrame
|
||||||
selector: aSel] autorelease];
|
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];
|
[self forwardInvocation:inv];
|
||||||
[inv getReturnValue: retFrame];
|
return [inv returnFrame: argFrame];
|
||||||
return retFrame;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) forwardInvocation: (NSInvocation*)anInvocation
|
- (void) forwardInvocation: (NSInvocation*)anInvocation
|
||||||
|
|
659
Source/mframe.m
659
Source/mframe.m
|
@ -36,24 +36,6 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.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: */
|
/* Deal with strrchr: */
|
||||||
#if STDC_HEADERS || HAVE_STRING_H
|
#if STDC_HEADERS || HAVE_STRING_H
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -90,18 +72,357 @@
|
||||||
value. The code doesn't currently handle that case.
|
value. The code doesn't currently handle that case.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Do we need separate _PASSED_BY_REFERENCE and _RETURNED_BY_REFERENCE? */
|
|
||||||
|
|
||||||
#if (sparc) || (hppa) || (AM29K)
|
char*
|
||||||
#define MFRAME_STRUCTURES_PASSED_BY_REFERENCE 1
|
mframe_build_signature(const char *typePtr, int *size, int *narg, char *buf)
|
||||||
#else
|
{
|
||||||
#define MFRAME_STRUCTURES_PASSED_BY_REFERENCE 0
|
MFRAME_ARGS cum;
|
||||||
#endif
|
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); \
|
* Step through method encoding information extracting details.
|
||||||
__a*((__v+__a-1)/__a); })
|
*/
|
||||||
|
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 */
|
/* To fix temporary bug in method_get_next_argument() on NeXT boxes */
|
||||||
/* xxx Perhaps this isn't working with the NeXT runtime? */
|
/* xxx Perhaps this isn't working with the NeXT runtime? */
|
||||||
/* Uses 'offset' to adjust for a pointer used to return a structur */
|
|
||||||
|
|
||||||
char*
|
char*
|
||||||
method_types_get_next_argument (arglist_t argf,
|
method_types_get_next_argument (arglist_t argf, const char **type)
|
||||||
const char **type, int offset)
|
|
||||||
{
|
{
|
||||||
const char *t = objc_skip_argspec (*type);
|
const char *t = objc_skip_argspec (*type);
|
||||||
union {
|
arglist_t argframe;
|
||||||
char *arg_ptr;
|
|
||||||
char arg_regs[sizeof (char*)];
|
|
||||||
} *argframe;
|
|
||||||
|
|
||||||
argframe = (void*)argf;
|
argframe = (void*)argf;
|
||||||
|
|
||||||
|
@ -170,9 +486,9 @@ method_types_get_next_argument (arglist_t argf,
|
||||||
else
|
else
|
||||||
/* xxx What's going on here? This -8 needed on my 68k NeXT box. */
|
/* xxx What's going on here? This -8 needed on my 68k NeXT box. */
|
||||||
#if NeXT
|
#if NeXT
|
||||||
return argframe->arg_ptr + offset + (atoi(t) - 8);
|
return argframe->arg_ptr + (atoi(t) - 8);
|
||||||
#else
|
#else
|
||||||
return argframe->arg_ptr + offset + atoi(t);
|
return argframe->arg_ptr + atoi(t);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,28 +516,19 @@ mframe_dissect_call_opts (arglist_t argframe, const char *type,
|
||||||
char *datum;
|
char *datum;
|
||||||
int argnum;
|
int argnum;
|
||||||
BOOL out_parameters = NO;
|
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) {
|
if (*type == _C_STRUCT_B || *type == _C_UNION_B || *type == _C_ARY_B) {
|
||||||
int rsize = objc_sizeof_type(type);
|
datum = alloca((strlen(type)+1)*10);
|
||||||
if (rsize > SMALL_STRUCT_ON_STACK) {
|
type = mframe_build_signature(type, 0, 0, datum);
|
||||||
off = sizeof(void*);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Enumerate all the arguments in ARGFRAME, and call ENCODER for
|
/* Enumerate all the arguments in ARGFRAME, and call ENCODER for
|
||||||
each one. METHOD_TYPES_GET_NEXT_ARGUEMENT() returns 0 when
|
each one. METHOD_TYPES_GET_NEXT_ARGUEMENT() returns 0 when
|
||||||
there are no more arguments, otherwise it returns a pointer to the
|
there are no more arguments, otherwise it returns a pointer to the
|
||||||
argument in the ARGFRAME. */
|
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;
|
||||||
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. */
|
/* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */
|
||||||
flags = objc_get_type_qualifiers(type);
|
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. */
|
/* Handle struct and array arguments. */
|
||||||
/* Whether DATUM points to the data, or points to a pointer
|
/* Whether DATUM points to the data, or points to a pointer
|
||||||
that points to the data, depends on the value of
|
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. */
|
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);
|
(*encoder) (argnum, *(void**)datum, type, flags);
|
||||||
#else
|
#else
|
||||||
(*encoder) (argnum, datum, type, flags);
|
(*encoder) (argnum, datum, type, flags);
|
||||||
|
@ -413,17 +720,8 @@ mframe_do_call_opts (const char *encoded_types,
|
||||||
int stack_argsize;
|
int stack_argsize;
|
||||||
/* The number bytes for holding arguments passed in registers. */
|
/* The number bytes for holding arguments passed in registers. */
|
||||||
int reg_argsize;
|
int reg_argsize;
|
||||||
/* Offset for arguments on stack. */
|
|
||||||
int off = 0;
|
|
||||||
/* The structure for holding the arguments to the method. */
|
/* 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;
|
arglist_t argframe;
|
||||||
#endif
|
|
||||||
/* A pointer into the ARGFRAME; points at individual arguments. */
|
/* A pointer into the ARGFRAME; points at individual arguments. */
|
||||||
char *datum;
|
char *datum;
|
||||||
/* Type qualifier flags; see <objc/objc-api.h>. */
|
/* Type qualifier flags; see <objc/objc-api.h>. */
|
||||||
|
@ -500,23 +798,22 @@ mframe_do_call_opts (const char *encoded_types,
|
||||||
NSCParameterAssert (type);
|
NSCParameterAssert (type);
|
||||||
NSCParameterAssert (sel_types_match(encoded_types, type));
|
NSCParameterAssert (sel_types_match(encoded_types, type));
|
||||||
|
|
||||||
#ifdef STRUCT_ADDR_ON_STACK
|
/*
|
||||||
/* On machines which pass a pointer to a location for returning
|
* The compiler/runtime doesn't always seem to get the encoding right
|
||||||
structures before the first real argument, we need to use an offset
|
* for our purposes - so we generate our own encoding as required by
|
||||||
into the arg frame. */
|
* __builtin_apply().
|
||||||
|
*/
|
||||||
if (*type == _C_STRUCT_B || *type == _C_UNION_B || *type == _C_ARY_B) {
|
if (*type == _C_STRUCT_B || *type == _C_UNION_B || *type == _C_ARY_B) {
|
||||||
if (objc_sizeof_type(type) > SMALL_STRUCT_ON_STACK) {
|
tmptype = alloca((strlen(type)+1)*10);
|
||||||
off = sizeof(void*);
|
type = mframe_build_signature(type, 0, 0, (char*)tmptype);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Allocate an argframe, using memory on the stack */
|
/* Allocate an argframe, using memory on the stack */
|
||||||
|
|
||||||
/* Calculate the amount of memory needed for storing variables that
|
/* Calculate the amount of memory needed for storing variables that
|
||||||
are passed in registers, and the amount of memory for storing
|
are passed in registers, and the amount of memory for storing
|
||||||
variables that are passed on the stack. */
|
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);
|
reg_argsize = method_types_get_size_of_register_arguments (type);
|
||||||
/* Allocate the space for variables passed in registers. */
|
/* Allocate the space for variables passed in registers. */
|
||||||
argframe = (arglist_t) alloca(sizeof(char*) + reg_argsize);
|
argframe = (arglist_t) alloca(sizeof(char*) + reg_argsize);
|
||||||
|
@ -527,10 +824,12 @@ mframe_do_call_opts (const char *encoded_types,
|
||||||
argframe->arg_ptr = 0;
|
argframe->arg_ptr = 0;
|
||||||
|
|
||||||
if (*type == _C_STRUCT_B || *type == _C_UNION_B || *type == _C_ARY_B) {
|
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
|
/* 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. */
|
the memory for it and put it in the correct place in the argframe. */
|
||||||
if (stack_argsize)
|
buf = alloca(objc_sizeof_type(type));
|
||||||
*(void**)argframe->arg_ptr = alloca(objc_sizeof_type(type));
|
MFRAME_SET_STRUCT_ADDR(argframe, type, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Put OBJECT and SELECTOR into the ARGFRAME. */
|
/* 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);
|
etmptype = objc_skip_argspec (encoded_types);
|
||||||
/* Get a pointer into ARGFRAME, pointing to the location where the
|
/* Get a pointer into ARGFRAME, pointing to the location where the
|
||||||
first argument is to be stored. */
|
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 (datum);
|
||||||
NSCParameterAssert (*tmptype == _C_ID);
|
NSCParameterAssert (*tmptype == _C_ID);
|
||||||
/* Put the target object there. */
|
/* Put the target object there. */
|
||||||
*(id*)datum = object;
|
*(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. */
|
second argument is to be stored. */
|
||||||
etmptype = objc_skip_argspec(etmptype);
|
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 (datum);
|
||||||
NSCParameterAssert (*tmptype == _C_SEL);
|
NSCParameterAssert (*tmptype == _C_SEL);
|
||||||
/* Put the selector there. */
|
/* 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
|
ARGFRAME. Step TMPTYPE and ETMPTYPE in lock-step through their
|
||||||
method type strings. */
|
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;
|
etmptype = objc_skip_argspec (etmptype), argnum = 2;
|
||||||
datum;
|
datum;
|
||||||
datum = method_types_get_next_argument (argframe, &tmptype, off),
|
datum = method_types_get_next_argument (argframe, &tmptype),
|
||||||
etmptype = objc_skip_argspec (etmptype), argnum++)
|
etmptype = objc_skip_argspec (etmptype), argnum++)
|
||||||
{
|
{
|
||||||
/* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */
|
/* 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. */
|
/* Handle struct and array arguments. */
|
||||||
/* Whether DATUM points to the data, or points to a pointer
|
/* Whether DATUM points to the data, or points to a pointer
|
||||||
that points to the data, depends on the value of
|
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. */
|
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
|
/* Allocate some memory to be pointed to, and to hold the
|
||||||
data. Note that it is allocated on the stack, and
|
data. Note that it is allocated on the stack, and
|
||||||
methods that want to keep the data pointed to, will have
|
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:
|
case _C_ARY_B:
|
||||||
/* The argument is a structure or array returned by value.
|
/* The argument is a structure or array returned by value.
|
||||||
(In C, are array's allowed to be returned by value?) */
|
(In C, are array's allowed to be returned by value?) */
|
||||||
/* xxx Does MFRAME_STRUCTURES_PASSED_BY_REFERENCE have
|
(*encoder)(-1, MFRAME_GET_STRUCT_ADDR(argframe, tmptype), tmptype, flags);
|
||||||
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);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case _C_FLT:
|
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
|
/* Step through all the arguments, finding the ones that were
|
||||||
passed by reference. */
|
passed by reference. */
|
||||||
for (datum = method_types_get_next_argument (argframe, &tmptype, off),
|
for (datum = method_types_get_next_argument (argframe, &tmptype),
|
||||||
argnum = 1,
|
argnum = 1,
|
||||||
etmptype = objc_skip_argspec (etmptype);
|
etmptype = objc_skip_argspec (etmptype);
|
||||||
datum;
|
datum;
|
||||||
datum = method_types_get_next_argument (argframe, &tmptype, off),
|
datum = method_types_get_next_argument (argframe, &tmptype),
|
||||||
argnum++,
|
argnum++,
|
||||||
etmptype = objc_skip_argspec (etmptype))
|
etmptype = objc_skip_argspec (etmptype))
|
||||||
{
|
{
|
||||||
|
@ -892,7 +1180,6 @@ mframe_build_return_opts (arglist_t argframe,
|
||||||
const char *tmptype;
|
const char *tmptype;
|
||||||
/* A pointer into the ARGFRAME; points at individual arguments. */
|
/* A pointer into the ARGFRAME; points at individual arguments. */
|
||||||
void *datum;
|
void *datum;
|
||||||
int off = 0;
|
|
||||||
const char *rettype;
|
const char *rettype;
|
||||||
/* For returning strucutres etc */
|
/* For returning strucutres etc */
|
||||||
typedef struct { id many[8];} __big;
|
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*));
|
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. */
|
/* Get the return type qualifier flags, and the return type. */
|
||||||
flags = objc_get_type_qualifiers(type);
|
flags = objc_get_type_qualifiers(type);
|
||||||
tmptype = objc_skip_type_qualifiers(type);
|
tmptype = objc_skip_type_qualifiers(type);
|
||||||
rettype = tmptype;
|
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
|
/* Decode the return value and pass-by-reference values, if there
|
||||||
are any. OUT_PARAMETERS should be the value returned by
|
are any. OUT_PARAMETERS should be the value returned by
|
||||||
mframe_dissect_call(). */
|
mframe_dissect_call(). */
|
||||||
|
@ -1018,18 +1297,7 @@ mframe_build_return_opts (arglist_t argframe,
|
||||||
case _C_ARY_B:
|
case _C_ARY_B:
|
||||||
/* The argument is a structure or array returned by value.
|
/* The argument is a structure or array returned by value.
|
||||||
(In C, are array's allowed to be returned by value?) */
|
(In C, are array's allowed to be returned by value?) */
|
||||||
/* xxx Does MFRAME_STRUCTURES_PASSED_BY_REFERENCE
|
*(void**)retframe = MFRAME_GET_STRUCT_ADDR(argframe, tmptype);
|
||||||
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));
|
|
||||||
/* Decode the return value into the memory we allocated. */
|
/* Decode the return value into the memory we allocated. */
|
||||||
(*decoder) (-1, *(void**)retframe, tmptype, flags);
|
(*decoder) (-1, *(void**)retframe, tmptype, flags);
|
||||||
break;
|
break;
|
||||||
|
@ -1079,10 +1347,10 @@ mframe_build_return_opts (arglist_t argframe,
|
||||||
{
|
{
|
||||||
/* Step through all the arguments, finding the ones that were
|
/* Step through all the arguments, finding the ones that were
|
||||||
passed by reference. */
|
passed by reference. */
|
||||||
for (datum = method_types_get_next_argument(argframe, &tmptype, off),
|
for (datum = method_types_get_next_argument(argframe, &tmptype),
|
||||||
argnum=0;
|
argnum=0;
|
||||||
datum;
|
datum;
|
||||||
(datum = method_types_get_next_argument(argframe, &tmptype, off)),
|
(datum = method_types_get_next_argument(argframe, &tmptype)),
|
||||||
argnum++)
|
argnum++)
|
||||||
{
|
{
|
||||||
/* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */
|
/* 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_SHT:
|
||||||
case _C_USHT:
|
case _C_USHT:
|
||||||
return apply_short(*(short*)retframe);
|
return apply_short(*(short*)retframe);
|
||||||
#if 1
|
#if 0
|
||||||
case _C_ARY_B:
|
case _C_ARY_B:
|
||||||
case _C_UNION_B:
|
case _C_UNION_B:
|
||||||
case _C_STRUCT_B:
|
case _C_STRUCT_B:
|
||||||
if (off == 0 && objc_sizeof_type(rettype) > 8) {
|
if (objc_sizeof_type(rettype) > 8) {
|
||||||
return apply_block(*(void**)retframe);
|
return apply_block(*(void**)retframe);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1174,6 +1442,52 @@ mframe_build_return (arglist_t argframe,
|
||||||
return mframe_build_return_opts(argframe,type,out_parameters,decoder,NO);
|
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
|
BOOL
|
||||||
mframe_decode_return (const char *type, void* buffer, void* retframe)
|
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;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void*
|
||||||
|
mframe_handle_return(const char* type, void* retval, arglist_t argframe)
|
||||||
|
{
|
||||||
|
retval_t retframe;
|
||||||
|
typedef struct { id many[8];} __big;
|
||||||
|
__big return_block (void* data)
|
||||||
|
{
|
||||||
|
return *(__big*)data;
|
||||||
|
}
|
||||||
|
/* For returning a char (or unsigned char) */
|
||||||
|
char return_char (char data)
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
/* For returning a double */
|
||||||
|
double return_double (double data)
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
/* For returning a float */
|
||||||
|
float return_float (float data)
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
/* For returning a short (or unsigned short) */
|
||||||
|
short return_short (short data)
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
retval_t apply_block(void* data)
|
||||||
|
{
|
||||||
|
void* args = __builtin_apply_args();
|
||||||
|
return __builtin_apply((apply_t)return_block, args, sizeof(void*));
|
||||||
|
}
|
||||||
|
retval_t apply_char(char data)
|
||||||
|
{
|
||||||
|
void* args = __builtin_apply_args();
|
||||||
|
return __builtin_apply((apply_t)return_char, args, sizeof(void*));
|
||||||
|
}
|
||||||
|
retval_t apply_float(float data)
|
||||||
|
{
|
||||||
|
void* args = __builtin_apply_args();
|
||||||
|
return __builtin_apply((apply_t)return_float, args, sizeof(float));
|
||||||
|
}
|
||||||
|
retval_t apply_double(double data)
|
||||||
|
{
|
||||||
|
void* args = __builtin_apply_args();
|
||||||
|
return __builtin_apply((apply_t)return_double, args, sizeof(double));
|
||||||
|
}
|
||||||
|
retval_t apply_short(short data)
|
||||||
|
{
|
||||||
|
void* args = __builtin_apply_args();
|
||||||
|
return __builtin_apply((apply_t)return_short, args, sizeof(void*));
|
||||||
|
}
|
||||||
|
|
||||||
|
retframe = alloca(MFRAME_RESULT_SIZE);
|
||||||
|
|
||||||
|
switch (*type) {
|
||||||
|
case _C_VOID:
|
||||||
|
break;
|
||||||
|
case _C_CHR:
|
||||||
|
case _C_UCHR:
|
||||||
|
return apply_char(*(char*)retval);
|
||||||
|
case _C_DBL:
|
||||||
|
return apply_double(*(double*)retval);
|
||||||
|
case _C_FLT:
|
||||||
|
return apply_float(*(float*)retval);
|
||||||
|
case _C_SHT:
|
||||||
|
case _C_USHT:
|
||||||
|
return apply_short(*(short*)retval);
|
||||||
|
case _C_ARY_B:
|
||||||
|
case _C_UNION_B:
|
||||||
|
case _C_STRUCT_B:
|
||||||
|
{
|
||||||
|
int size = objc_sizeof_type(type);
|
||||||
|
#if 1
|
||||||
|
void *dest;
|
||||||
|
|
||||||
|
dest = MFRAME_GET_STRUCT_ADDR(argframe, type);
|
||||||
|
memcpy(dest, retval, size);
|
||||||
|
#else
|
||||||
|
if (size > 8) {
|
||||||
|
return apply_block(*(void**)retval);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memcpy(retframe, retval, size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
memcpy(retframe, retval, objc_sizeof_type(type));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retframe;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue