mirror of
https://github.com/gnustep/libs-gsweb.git
synced 2025-02-22 19:21:23 +00:00
(IsStyle,IsNumberStyle, ExceptionRaise, ExceptionRaise0, ValidationExceptionRaise, ValidationExceptionRaise0, ExceptionByAddingUserInfoObjectFrameInfo, ExceptionByAddingUserInfoObjectFrameInfo0, ExceptionByAddingUserInfoFunctionFrameInfo, ExceptionByAddingUserInfoFunctionFrameInfo0, ): Reformat defines. (GSW_LOCK_LIMIT): New define. (ExceptionRaiseFn, ExceptionRaiseFn0, ValidationExceptionRaiseFn, ValidationExceptionRaiseFn0): Reformat declaration. (TmpLock, TmpTryLockBeforeDate, TmpLockBeforeDate, TmpUnlock): Remove. ([NSLock isLocked]): Remove. ([NSLock tmplock]): Ditto. ([NSLock tmplockFromFunction:file:line:]): Ditto. ([NSLock tmptryLock]): Ditto. ([NSLock tmptryLockFromFunction:file:line:]): Ditto. ([NSLock tmptryLockBeforeDate:]): Ditto. ([NSLock tmptryLockBeforeDate:fromFunction:file:line:]): Ditto. ([NSLock tmpunlock]): Ditto. ([NSLock tmpunlockFromFunction:file:line:]): Ditto. ([NSLock description]): Ditto. ([NSRecursiveLock isLocked]): Ditto. ([NSRecursiveLock tmplock]): Ditto. ([NSRecursiveLock tmplockFromFunction:file:line:]): Ditto. ([NSRecursiveLock tmptryLock]): Ditto. ([NSRecursiveLock tmptryLockFromFunction:file:line:]): Ditto. ([NSRecursiveLock tmptryLockBeforeDate:]): Ditto. ([NSRecursiveLock tmptryLockBeforeDate:fromFunction:file:line:]): Ditto. ([NSRecursiveLock tmpunlock]): Ditto. ([NSRecursiveLock tmpunlockFromFunction:file:line:]): Ditto. (NSLockException, MessageForMutexLockError) (LoggedLock, LoggedLockBeforeDate, LoggedTryLock, LoggedTryLockBeforeDate, LoggedUnlock): New macros. (loggedLockBeforeDateFromFunctionInFileInLine, loggedUnlockFromFunctionInFileInLine): New logging lock functions. ([NSThread description]): New Category. (volatileInternalDescription): New static function. (GSW_LOCK_LIMIT): New marco. * GSWeb.framework/GSWApplication.m ([GSWApplication isRequestHandlingLocked]): Test lock instead of relying on obsolete lock categories. ([GSWApplication lockRequestHandling]): Use new locking macros. ([GSWApplication unlockRequestHandling]): Ditto. ([GSWApplication lock]): Ditto. ([GSWApplication unlock]): Ditto. * GSWeb.framework/GSWAssociation.m ([GSWAssociation setClasse:forHandler:]): Ditto ([GSWAssociation addLogHandlerClasse:]): Ditto. ([GSWAssociation removeLogHandlerClasse:]): Ditto. ([GSWAssociation logValue:forSet:]): Ditto. ([GSWAssociation logSynchronizeForValue:inComponent:componentToParent:]): Ditto. * GSWeb.framework/GSWBundle.m ([GSWBundle unlock]): Ditto. ([GSWBundle lock]): Ditto. * GSWeb.framework/GSWDefaultAdaptor.m ([GSWDefaultAdaptor tryLock]): Ditto. ([GSWDefaultAdaptor unlock]): Ditto. * GSWeb.framework/GSWDeployedBundle.m ([GSWDeployedBundle lock]): Ditto. ([GSWDeployedBundle unlock]): Ditto. * GSWeb.framework/GSWResourceManager.m ([GSWResourceManager unlock]): Ditto. ([GSWResourceManager lock]): Ditto. * GSWeb.framework/GSWSessionStore.m ([GSWSessionStore unlock]): Ditto. ([GSWSessionStore tryLock]): Ditto. ([GSWSessionStore lock]): Ditto. * GSWeb.framework/GSWSessionTimeOutManager.m ([GSWSessionTimeOutManager tryLockBeforeTimeIntervalSinceNow:]): Ditto. ([GSWSessionTimeOutManager lockBeforeTimeIntervalSinceNow]): Ditto. ([GSWSessionTimeOutManager unlock]): Ditto. * GSWeb.framework/GSWStaticResourceRequestHandler.m ([GSWStaticResourceRequestHandler handleRequest:]): Ditto. * GSWeb.framework/GSWStatisticsStore.m ([GSWStatisticsStore unlock]): Ditto. ([GSWStatisticsStore lock]): Ditto. * GSWeb.framework/NSObject+IVarAccess+PerformSel.m: ([NSObject getIVarNamed]): Use GSW_LOCK_LIMIT macro. Reformat. ([NSObject setIVarNamed:withValue:]): Ditto. * Makefile.postamble: Remove autom4te.cache on distclean. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gsweb/trunk@18605 72102866-910b-0410-8b05-ffd578937521
959 lines
27 KiB
Objective-C
959 lines
27 KiB
Objective-C
/* NSObject+IVarAccess+PerformSel.m
|
|
Copyright (C) 1999 Free Software Foundation, Inc.
|
|
|
|
Written by: Manuel Guesdon <mguesdon@sbuilders.com>
|
|
Date: Jan 1999
|
|
|
|
This file is part of the GNUstep Web Library.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
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.
|
|
*/
|
|
|
|
static char rcsId[] = "$Id$";
|
|
|
|
#include "GSWeb.h"
|
|
|
|
NSMutableDictionary* objectIVarAccessCache_Set=nil;
|
|
NSMutableDictionary* objectIVarAccessCache_Get=nil;
|
|
NSLock* objectClassLock=nil;
|
|
|
|
//===================================================================================
|
|
typedef enum
|
|
{
|
|
NSObjectIVarsAccessType_Error = -1,
|
|
NSObjectIVarsAccessType_None = 0,
|
|
NSObjectIVarsAccessType_PerformSelector,
|
|
NSObjectIVarsAccessType_Invocation,
|
|
|
|
NSObjectIVarsAccessType_Direct,
|
|
|
|
NSObjectIVarsAccessType_Dictionary,
|
|
NSObjectIVarsAccessType_DictionaryWithRemoveObject,
|
|
NSObjectIVarsAccessType_DictionaryWithoutRemoveObject,
|
|
NSObjectIVarsAccessType_EO
|
|
|
|
} NSObjectIVarsAccessType;
|
|
|
|
//====================================================================
|
|
@interface NSObjectIVarsAccess : NSObject
|
|
{
|
|
@public
|
|
NSObjectIVarsAccessType accessType;
|
|
union
|
|
{
|
|
SEL selector;
|
|
NSInvocation* invocation;
|
|
struct objc_ivar* ivar;
|
|
} infos;
|
|
};
|
|
|
|
+(id)ivarAccess;
|
|
@end
|
|
|
|
//====================================================================
|
|
@implementation NSObjectIVarsAccess
|
|
|
|
//--------------------------------------------------------------------
|
|
+(id)ivarAccess
|
|
{
|
|
return [[self new]autorelease];
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(void)dealloc
|
|
{
|
|
if (accessType==NSObjectIVarsAccessType_Invocation)
|
|
{
|
|
DESTROY(infos.invocation);
|
|
};
|
|
[super dealloc];
|
|
};
|
|
@end
|
|
|
|
//====================================================================
|
|
struct objc_ivar* GSGetInstanceVariableStruct(id obj,
|
|
NSString* iVarName,
|
|
BOOL underscored)
|
|
{
|
|
const char* name=NULL;
|
|
Class class;
|
|
struct objc_ivar_list *ivars=NULL;
|
|
struct objc_ivar *ivar=NULL;
|
|
if (underscored)
|
|
iVarName=[NSString stringWithFormat:@"_%@",iVarName];
|
|
name=[iVarName cString];
|
|
class=[obj class];
|
|
while (class && !ivar)
|
|
{
|
|
ivars = class->ivars;
|
|
class = class->super_class;
|
|
if (ivars)
|
|
{
|
|
int i;
|
|
for (i=0;!ivar && i<ivars->ivar_count;i++)
|
|
{
|
|
if (strcmp(ivars->ivar_list[i].ivar_name, name)==0)
|
|
ivar = &ivars->ivar_list[i];
|
|
};
|
|
};
|
|
};
|
|
return ivar;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
const char* GSGetInstanceVariableType(id obj,
|
|
NSString *iVarName,
|
|
BOOL underscored)
|
|
{
|
|
struct objc_ivar *ivar = GSGetInstanceVariableStruct(obj,iVarName,underscored);
|
|
if (ivar)
|
|
return ivar->ivar_type;
|
|
else
|
|
return NULL;
|
|
};
|
|
|
|
//====================================================================
|
|
@implementation NSObject (IVarsAccess)
|
|
|
|
//--------------------------------------------------------------------
|
|
+(BOOL)isIVarAccessCachingDisabled
|
|
{
|
|
return NO;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
+(NSString*)getFunctionNameWithTemplate:(NSString*)tpl
|
|
forVariable:(NSString*)varName
|
|
uppercaseFirstLetter:(BOOL)uppercaseFirstLetter
|
|
{
|
|
NSString* fn=nil;
|
|
if (tpl && [tpl length]>0)
|
|
{
|
|
NSString* fnMain=nil;
|
|
if (uppercaseFirstLetter)
|
|
{
|
|
NSString* first=[[varName substringToIndex:1] uppercaseString];
|
|
NSString* next=[varName substringFromIndex:1];
|
|
fnMain=[NSString stringWithFormat:@"%@%@",first,next];
|
|
}
|
|
else
|
|
fnMain=varName;
|
|
fn=[NSString stringWithFormat:tpl,fnMain];
|
|
}
|
|
else
|
|
fn=[NSString stringWithString:varName];
|
|
return fn;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(SEL)getSelectorWithFunctionTemplate:(NSString*)tpl
|
|
forVariable:(NSString*)varName
|
|
uppercaseFirstLetter:(BOOL)uppercaseFirstLetter
|
|
{
|
|
NSString* fnName=nil;
|
|
SEL selector=NULL;
|
|
fnName=[NSObject getFunctionNameWithTemplate:tpl
|
|
forVariable:varName
|
|
uppercaseFirstLetter:uppercaseFirstLetter];
|
|
selector=NSSelectorFromString(fnName);
|
|
if (selector && ![self respondsToSelector:selector])
|
|
selector=NULL;
|
|
return selector;
|
|
};
|
|
|
|
#if HAVE_GDL2
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
- (id)getIVarNamed:(NSString *)name_
|
|
{
|
|
id value=nil;
|
|
SEL sel = @selector(valueForKey:);//NEW NSSelectorFromString(@"valueForKey:");
|
|
//MGNEW id (*imp)(id, SEL, id) = (id (*)(id, SEL, id))[NSObject instanceMethodForSelector: sel];
|
|
NSDebugMLLog(@"low",@"getIVarNamed %@ in %@ %p (superClass:%@)",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]);
|
|
//NSLog(@"%@",name_);
|
|
//NSLog(@"sel (valueForKey <NSObject>) : %d", (int)sel);
|
|
|
|
NS_DURING
|
|
value = [self valueForKey:name_];//MGNEW
|
|
//MGNEW value = (*imp)(self, sel, name_);
|
|
NS_HANDLER
|
|
{
|
|
NSDebugMLLog(@"low",@"getIVarNamed %@ in %@ %p (superClass:%@). valueForKey: exception",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]);
|
|
if([self respondsToSelector:@selector(objectForKey:)] == YES) {
|
|
if (name_) {
|
|
value = [self objectForKey:name_];
|
|
} else {
|
|
value=nil;
|
|
}
|
|
} else {
|
|
LOGException(@"==> %@ (%@) gvfk from string=%p gvfk sel=%p initWithCapacity from string:=%p initWithCapacity sel:=%p NSStringFromSelector(sel)",
|
|
localException,
|
|
[localException reason],
|
|
NSSelectorFromString(@"valueForKey:"),
|
|
@selector(valueForKey:),
|
|
NSSelectorFromString(@"initWithCapacity:"),
|
|
@selector(initWithCapacity:),
|
|
NSStringFromSelector(sel));
|
|
[localException raise];
|
|
}
|
|
}
|
|
NS_ENDHANDLER;
|
|
|
|
return value;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
- (void)setIVarNamed:(NSString *)name_
|
|
withValue:(id)value_
|
|
{
|
|
SEL sel = @selector(takeValue:forKey:);//NEW NSSelectorFromString(@"takeValue:forKey:");
|
|
//MGNEW id (*imp)(id, SEL, id, id) = (id (*)(id, SEL, id, id))[NSObject instanceMethodForSelector: sel];
|
|
|
|
//NSLog(@"sel (takeValue:forKey: <NSObject>) : %d", (int)sel);
|
|
|
|
NS_DURING
|
|
//NSLog(@"setIVarNamed : self = %@", NSStringFromClass([self class]));
|
|
//NSLog(@"setIVarNamed : name_ = %@ (%@)", name_, NSStringFromClass([name_ class]));
|
|
//NSLog(@"setIVarNamed : value_ = %@ (%@)", value_, NSStringFromClass([value_ class]));
|
|
[self takeValue:value_ forKey:name_];//MGNEW
|
|
//MGNEW (*imp)(self, sel, value_, name_);
|
|
NS_HANDLER
|
|
{
|
|
if (![name_ isEqualToString:@"self"]) {
|
|
|
|
if([self respondsToSelector:@selector(setObject:forKey:)] == YES) {
|
|
if (value_ && name_) {
|
|
[self setObject:value_ forKey:name_];
|
|
}
|
|
} else {
|
|
[localException raise];
|
|
}
|
|
}
|
|
}
|
|
NS_ENDHANDLER;
|
|
}
|
|
|
|
#else
|
|
|
|
//--------------------------------------------------------------------
|
|
id PDataToId(const char* retType,void* pdata)
|
|
{
|
|
id value=nil;
|
|
switch(*retType)
|
|
{
|
|
case _C_CLASS:
|
|
value=*((id*)pdata);
|
|
break;
|
|
case _C_ID:
|
|
value=*((id*)pdata);
|
|
break;
|
|
case _C_CHR:
|
|
value=[NSNumber numberWithChar:*((char*)pdata)];
|
|
break;
|
|
case _C_UCHR:
|
|
value=[NSNumber numberWithUnsignedChar:*((unsigned char*)pdata)];
|
|
break;
|
|
case _C_SHT:
|
|
value=[NSNumber numberWithShort:*((short*)pdata)];
|
|
break;
|
|
case _C_USHT:
|
|
value=[NSNumber numberWithUnsignedShort:*((unsigned short*)pdata)];
|
|
break;
|
|
case _C_INT:
|
|
value=[NSNumber numberWithInt:*((int*)pdata)];
|
|
break;
|
|
case _C_UINT:
|
|
value=[NSNumber numberWithUnsignedInt:*((unsigned int*)pdata)];
|
|
break;
|
|
case _C_LNG:
|
|
value=[NSNumber numberWithLong:*((long*)pdata)];
|
|
break;
|
|
case _C_ULNG:
|
|
value=[NSNumber numberWithUnsignedLong:*((unsigned long*)pdata)];
|
|
break;
|
|
case _C_FLT:
|
|
value=[NSNumber numberWithFloat:*((float*)pdata)];
|
|
break;
|
|
case _C_DBL:
|
|
value=[NSNumber numberWithFloat:*((double*)pdata)];
|
|
break;
|
|
case _C_CHARPTR:
|
|
value=[NSString stringWithCString:*((char**)pdata)];
|
|
break;
|
|
case _C_SEL:
|
|
case _C_VOID:
|
|
case _C_PTR:
|
|
case _C_STRUCT_B:
|
|
default:
|
|
//TODO
|
|
break;
|
|
};
|
|
return value;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
void IdToPData(const char* retType,id _value,void* pdata)
|
|
{
|
|
switch(*retType)
|
|
{
|
|
case _C_CLASS:
|
|
*((Class*)pdata)=_value;
|
|
break;
|
|
case _C_ID:
|
|
*((id*)pdata)=_value;
|
|
break;
|
|
case _C_CHR:
|
|
*((char*)pdata)=[_value charValue];
|
|
break;
|
|
case _C_UCHR:
|
|
*((unsigned char*)pdata)=[_value unsignedCharValue];
|
|
break;
|
|
case _C_SHT:
|
|
*((short*)pdata)=[_value shortValue];
|
|
break;
|
|
case _C_USHT:
|
|
*((unsigned short*)pdata)=[_value unsignedShortValue];
|
|
break;
|
|
case _C_INT:
|
|
*((int*)pdata)=[_value intValue];
|
|
break;
|
|
case _C_UINT:
|
|
*((unsigned int*)pdata)=[_value unsignedIntValue];
|
|
break;
|
|
case _C_LNG:
|
|
*((long*)pdata)=[_value longValue];
|
|
break;
|
|
case _C_ULNG:
|
|
*((unsigned long*)pdata)=[_value unsignedLongValue];
|
|
break;
|
|
case _C_FLT:
|
|
*((float*)pdata)=[_value floatValue];
|
|
break;
|
|
case _C_DBL:
|
|
*((double*)pdata)=[_value doubleValue];
|
|
break;
|
|
case _C_CHARPTR:
|
|
case _C_SEL:
|
|
case _C_VOID:
|
|
case _C_PTR:
|
|
case _C_STRUCT_B:
|
|
default:
|
|
//TODO
|
|
break;
|
|
};
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(id)getIVarNamed:(NSString*)name_
|
|
withCacheObject:(NSObjectIVarsAccess*)ivarAccess_
|
|
{
|
|
id _value=nil;
|
|
switch(ivarAccess_->accessType)
|
|
{
|
|
case NSObjectIVarsAccessType_Error:
|
|
break;
|
|
case NSObjectIVarsAccessType_None:
|
|
break;
|
|
case NSObjectIVarsAccessType_PerformSelector:
|
|
NSDebugMLLog(@"low",@"getIVarNamed %@ in %@ %p (superClass:%@)with performSelector",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]);
|
|
_value=[self performSelector:ivarAccess_->infos.selector];
|
|
break;
|
|
case NSObjectIVarsAccessType_Invocation:
|
|
{
|
|
const char* retType=[[ivarAccess_->infos.invocation methodSignature] methodReturnType];
|
|
NSAssert([ivarAccess_->infos.invocation selector],@"No Selector in Invocation");
|
|
[ivarAccess_->infos.invocation setTarget:self];
|
|
[ivarAccess_->infos.invocation invoke];
|
|
if (*retType!=_C_VOID)
|
|
{
|
|
void* pdata=objc_atomic_malloc(objc_sizeof_type(retType));
|
|
if (!pdata)
|
|
{
|
|
NSAssert(pdata,@"No ret value buffer");
|
|
//TODO
|
|
}
|
|
else
|
|
{
|
|
NSDebugMLLog(@"low",
|
|
@"getIVarNamed %@ in %@ %p (superClass:%@) with invocation %@ (retType=%s)",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass],
|
|
ivarAccess_->infos.invocation,
|
|
retType);
|
|
[ivarAccess_->infos.invocation getReturnValue:pdata];
|
|
_value=PDataToId(retType,pdata);
|
|
objc_free(pdata);
|
|
};
|
|
};
|
|
};
|
|
break;
|
|
case NSObjectIVarsAccessType_Direct:
|
|
{
|
|
const char* IVarType=ivarAccess_->infos.ivar->ivar_type;
|
|
unsigned int size=objc_sizeof_type(IVarType);
|
|
void* pdata=objc_atomic_malloc(size);
|
|
NSDebugMLLog(@"low",@"getIVarNamed %@ in %@ %p (superClass:%@) by variable ",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]);
|
|
if (pdata)
|
|
{
|
|
int offset = ivarAccess_->infos.ivar->ivar_offset;
|
|
memcpy(pdata,((void*)self)+offset, size);
|
|
_value=PDataToId(IVarType,pdata);
|
|
objc_free(pdata);
|
|
}
|
|
else
|
|
{
|
|
//TODO
|
|
NSAssert(NO,@"no pdata");
|
|
};
|
|
};
|
|
break;
|
|
case NSObjectIVarsAccessType_Dictionary:
|
|
_value=[self objectForKey:name_];
|
|
break;
|
|
case NSObjectIVarsAccessType_EO:
|
|
_value=[self valueForKey:name_];
|
|
break;
|
|
default:
|
|
break;
|
|
};
|
|
return _value;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(id)getIVarNamed:(NSString*)name_
|
|
{
|
|
id _value=nil;
|
|
NSException* _exception=nil;
|
|
BOOL _cachindEnabled=YES;
|
|
Class _class=Nil;
|
|
NSObjectIVarsAccess* _ivarAccess=nil;
|
|
NSMutableDictionary* _classCache=nil;
|
|
LOGObjectFnStart();
|
|
NSDebugMLLog(@"low",@"getIVarNamed %@ in %p %@ (superClass:%@)",
|
|
name_,self,[self class],[self superclass]);
|
|
_class=[self class];
|
|
_classCache=[objectIVarAccessCache_Get objectForKey:_class];
|
|
if (!_classCache)
|
|
{
|
|
_cachindEnabled=![_class isIVarAccessCachingDisabled];
|
|
if (_cachindEnabled)
|
|
{
|
|
if (!objectClassLock)
|
|
objectClassLock=[NSLock new];
|
|
LoggedLockBeforeDate(objectClassLock, GSW_LOCK_LIMIT);
|
|
_classCache=[NSMutableDictionary dictionary];
|
|
if (!objectIVarAccessCache_Get)
|
|
objectIVarAccessCache_Get=[NSMutableDictionary new];
|
|
[objectIVarAccessCache_Get setObject:_classCache
|
|
forKey:_class];
|
|
LoggedUnlock(objectClassLock);
|
|
};
|
|
};
|
|
if (_cachindEnabled)
|
|
_ivarAccess=[_classCache objectForKey:name_];
|
|
if (!_ivarAccess)
|
|
{
|
|
SEL sel=NULL;
|
|
_ivarAccess=[NSObjectIVarsAccess ivarAccess];
|
|
sel=[self getSelectorWithFunctionTemplate:@"get%@"
|
|
forVariable:name_
|
|
uppercaseFirstLetter:YES];
|
|
if (!sel)
|
|
sel=[self getSelectorWithFunctionTemplate:@"%@"
|
|
forVariable:name_
|
|
uppercaseFirstLetter:NO];
|
|
NSDebugMLLog(@"low",@"getIVarNamed %@ in %@ %p sel=%p ",
|
|
name_,[self class],self,(void*)sel);
|
|
if (sel)
|
|
{
|
|
NSMethodSignature* _sig = [self methodSignatureForSelector:sel];
|
|
if ([_sig numberOfArguments]!=2)
|
|
{
|
|
_exception =[NSException exceptionWithName: @"NSObject IVar"
|
|
format: @"Can't get Variable named "
|
|
@"%@ in %@ %p (superClass:%@): "
|
|
@"fn args mismatch",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]];
|
|
}
|
|
else
|
|
{
|
|
const char* retType=[_sig methodReturnType];
|
|
NSDebugMLLog(@"low",@"retType=%s",retType);
|
|
if (!retType)
|
|
{
|
|
_exception=[NSException exceptionWithName:@"NSObject IVar"
|
|
format:@"Can't get Variable named "
|
|
@"%@ in %@ %p (superClass:%@): "
|
|
@"fn unknown type",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]];
|
|
}
|
|
else
|
|
{
|
|
if (*retType==_C_ID)
|
|
{
|
|
_ivarAccess->accessType
|
|
= NSObjectIVarsAccessType_PerformSelector;
|
|
_ivarAccess->infos.selector=sel;
|
|
}
|
|
else
|
|
{
|
|
NSInvocation* _invocation
|
|
= [NSInvocation invocationWithMethodSignature:_sig];
|
|
NSDebugMLLog(@"low",
|
|
@"_invocation methodSignature "
|
|
@"methodReturnType=%s",
|
|
[[_invocation methodSignature]
|
|
methodReturnType]);
|
|
[_invocation setSelector:sel];
|
|
_ivarAccess->accessType
|
|
= NSObjectIVarsAccessType_Invocation;
|
|
_ivarAccess->infos.invocation=_invocation;
|
|
NSAssert([_ivarAccess->infos.invocation selector],
|
|
@"No Selector in Invocation");
|
|
[_ivarAccess->infos.invocation retain];
|
|
};
|
|
};
|
|
};
|
|
}
|
|
else
|
|
{
|
|
struct objc_ivar* ivar=GSGetInstanceVariableStruct(self,name_,YES);
|
|
if (!ivar)
|
|
ivar=GSGetInstanceVariableStruct(self,name_,NO);
|
|
if (ivar)
|
|
{
|
|
_ivarAccess->accessType=NSObjectIVarsAccessType_Direct;
|
|
_ivarAccess->infos.ivar=ivar;
|
|
}
|
|
else
|
|
{
|
|
NSDebugMLLog(@"low",
|
|
@"getIVarNamed %@ in %@ %p (superClass:%@) "
|
|
@"with objectForKey ",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]);
|
|
if ([self respondsToSelector:@selector(objectForKey:)])
|
|
{
|
|
_ivarAccess->accessType=NSObjectIVarsAccessType_Dictionary;
|
|
}
|
|
else if ([self respondsToSelector:@selector(valueForKey:)])
|
|
{
|
|
_ivarAccess->accessType=NSObjectIVarsAccessType_EO;
|
|
}
|
|
else
|
|
{
|
|
_exception=[NSException exceptionWithName:@"NSObject IVar"
|
|
format:@"Can't get Variable named "
|
|
@"%@ in %@ %p (superClass:%@) "
|
|
@"with objectForKey",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]];
|
|
};
|
|
};
|
|
};
|
|
|
|
if (_exception)
|
|
_ivarAccess->accessType=NSObjectIVarsAccessType_Error;
|
|
if (_cachindEnabled)
|
|
{
|
|
if (!objectClassLock)
|
|
objectClassLock=[NSLock new];
|
|
LoggedLockBeforeDate(objectClassLock, GSW_LOCK_LIMIT);
|
|
[_classCache setObject:_ivarAccess
|
|
forKey:name_];
|
|
LoggedUnlock(objectClassLock);
|
|
};
|
|
};
|
|
if (_exception)
|
|
[_exception raise];
|
|
else
|
|
_value=[self getIVarNamed:name_
|
|
withCacheObject:_ivarAccess];
|
|
// LOGObjectFnStop();
|
|
return _value;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(void)setIVarNamed:(NSString*)name_
|
|
withValue:(id)value_
|
|
withCacheObject:(NSObjectIVarsAccess*)ivarAccess_
|
|
{
|
|
LOGObjectFnStart();
|
|
switch(ivarAccess_->accessType)
|
|
{
|
|
case NSObjectIVarsAccessType_Error:
|
|
break;
|
|
case NSObjectIVarsAccessType_None:
|
|
break;
|
|
case NSObjectIVarsAccessType_PerformSelector:
|
|
NSDebugMLLog(@"low",
|
|
@"setIVarNamed %@ in %@ %p (superClass:%@) with performSelector value:%@",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass],
|
|
value_);
|
|
[self performSelector:ivarAccess_->infos.selector
|
|
withObject:value_];
|
|
break;
|
|
case NSObjectIVarsAccessType_Invocation:
|
|
{
|
|
const char* type=[[ivarAccess_->infos.invocation methodSignature] getArgumentTypeAtIndex:2];
|
|
void* pdata=objc_atomic_malloc(objc_sizeof_type(type));
|
|
IdToPData(type,value_,pdata);
|
|
NSAssert([ivarAccess_->infos.invocation selector],@"No Selector in Invocation");
|
|
[ivarAccess_->infos.invocation setTarget:self];
|
|
[ivarAccess_->infos.invocation setArgument:pdata
|
|
atIndex:2];
|
|
NSDebugMLLog(@"low",
|
|
@"setIVarNamed %@ in %@ %p (superClass:%@) with invocation value:%@",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass],
|
|
value_);
|
|
[ivarAccess_->infos.invocation invoke];
|
|
objc_free(pdata);
|
|
};
|
|
break;
|
|
case NSObjectIVarsAccessType_Direct:
|
|
{
|
|
const char* IVarType=ivarAccess_->infos.ivar->ivar_type;
|
|
if (IVarType)
|
|
{
|
|
unsigned int size=objc_sizeof_type(IVarType);
|
|
void* pdata=objc_atomic_malloc(size);
|
|
int offset = ivarAccess_->infos.ivar->ivar_offset;
|
|
IdToPData(IVarType,value_,pdata);
|
|
memcpy(((void*)self)+offset,pdata, size);
|
|
objc_free(pdata);
|
|
}
|
|
else
|
|
{
|
|
ExceptionRaise(@"NSObject IVar",
|
|
@"Can't set Variable named %@ in %@ %p (superClass:%@)",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]);
|
|
};
|
|
};
|
|
break;
|
|
case NSObjectIVarsAccessType_DictionaryWithRemoveObject:
|
|
case NSObjectIVarsAccessType_DictionaryWithoutRemoveObject:
|
|
if (value_ || ivarAccess_->accessType==NSObjectIVarsAccessType_DictionaryWithoutRemoveObject)
|
|
{
|
|
NSDebugMLLog(@"low",
|
|
@"setIVarNamed %@ in %@ %p (superClass:%@) with setObjectForKey:",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]);
|
|
// keyvalue coding
|
|
[self setObject:value_
|
|
forKey:name_];
|
|
}
|
|
else
|
|
{
|
|
NSDebugMLLog(@"low",
|
|
@"setIVarNamed %@ in %@ %p (superClass:%@) with removeObjectForKey:",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]);
|
|
// keyvalue coding
|
|
[self removeObjectForKey:name_];
|
|
};
|
|
break;
|
|
case NSObjectIVarsAccessType_EO:
|
|
NSDebugMLLog(@"low",
|
|
@"setIVarNamed %@ in %@ %p (superClass:%@) with takeValue:forKey:",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]);
|
|
// keyvalue coding
|
|
[self takeValue:value_
|
|
forKey:name_];
|
|
break;
|
|
default:
|
|
break;
|
|
};
|
|
LOGObjectFnStop();
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(void)setIVarNamed:(NSString*)name_
|
|
withValue:(id)value_
|
|
{
|
|
NSException* _exception=nil;
|
|
BOOL _cachindEnabled=YES;
|
|
Class _class=[self class];
|
|
NSObjectIVarsAccess* _ivarAccess=nil;
|
|
NSMutableDictionary* _classCache
|
|
= [objectIVarAccessCache_Set objectForKey:_class];
|
|
// LOGObjectFnStart();
|
|
NSDebugMLLog(@"low",
|
|
@"LOG setIVarNamed:%@ withValue:%@ in %p %@ (superClass:%@)",
|
|
name_,value_,self,[self class],[self superclass]);
|
|
if (!_classCache)
|
|
{
|
|
_cachindEnabled=![_class isIVarAccessCachingDisabled];
|
|
if (_cachindEnabled)
|
|
{
|
|
if (!objectClassLock)
|
|
objectClassLock=[NSLock new];
|
|
LoggedLockBeforeDate(objectClassLock, GSW_LOCK_LIMIT);
|
|
_classCache=[NSMutableDictionary dictionary];
|
|
if (!objectIVarAccessCache_Set)
|
|
objectIVarAccessCache_Set=[NSMutableDictionary new];
|
|
[objectIVarAccessCache_Set setObject:_classCache
|
|
forKey:_class];
|
|
LoggedUnlock(objectClassLock);
|
|
};
|
|
};
|
|
if (_cachindEnabled)
|
|
_ivarAccess=[_classCache objectForKey:name_];
|
|
if (!_ivarAccess)
|
|
{
|
|
SEL sel=NULL;
|
|
NSDebugMLLog(@"low",@"Not ivarAccess for name:%@",name_);
|
|
_ivarAccess=[NSObjectIVarsAccess ivarAccess];
|
|
// NSDebugMLLog(@"low",@"LOG setIVarNamed:%@ withValue:%@ in %@",name_,value_,[self class]);
|
|
sel=[self getSelectorWithFunctionTemplate:@"set%@:"
|
|
forVariable:name_
|
|
uppercaseFirstLetter:YES];
|
|
NSDebugMLLog(@"low",
|
|
@"sel=%ld (for %@ in %@)",
|
|
sel,name_,[self class]);
|
|
if (sel)
|
|
{
|
|
NSMethodSignature* _sig = [self methodSignatureForSelector:sel];
|
|
if ([_sig numberOfArguments]!=3)
|
|
{
|
|
_exception=[NSException exceptionWithName:@"NSObject IVar"
|
|
format:@"Can't set Variable named %@ "
|
|
@"in %@ %p (superClass:%@) "
|
|
@"(fn Bad number of Arguments)",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]];
|
|
}
|
|
else
|
|
{
|
|
const char* type=[_sig getArgumentTypeAtIndex:2];
|
|
if (!type)
|
|
{
|
|
_exception
|
|
=[NSException exceptionWithName:@"NSObject IVar"
|
|
format:@"Can't set Variable named %@ "
|
|
@"in %@ %p (superClass:%@) "
|
|
@"(fn get argument type)",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]];
|
|
}
|
|
else
|
|
{
|
|
if (*type==_C_ID)
|
|
{
|
|
_ivarAccess->accessType
|
|
= NSObjectIVarsAccessType_PerformSelector;
|
|
_ivarAccess->infos.selector=sel;
|
|
NSDebugMLLog(@"low",
|
|
@"perform selector (IVar named :%@)",
|
|
name_);
|
|
}
|
|
else
|
|
{
|
|
NSInvocation* _invocation
|
|
= [NSInvocation invocationWithMethodSignature:_sig];
|
|
[_invocation setSelector:sel];
|
|
_ivarAccess->accessType
|
|
= NSObjectIVarsAccessType_Invocation;
|
|
_ivarAccess->infos.invocation=_invocation;
|
|
NSAssert([_ivarAccess->infos.invocation selector],
|
|
@"No Selector in Invocation");
|
|
[_ivarAccess->infos.invocation retain];
|
|
NSDebugMLLog(@"low",
|
|
@"invocation (IVar named :%@)",
|
|
name_);
|
|
};
|
|
};
|
|
};
|
|
}
|
|
else
|
|
{
|
|
struct objc_ivar* ivar=GSGetInstanceVariableStruct(self,name_,YES);
|
|
if (!ivar)
|
|
ivar=GSGetInstanceVariableStruct(self,name_,NO);
|
|
if (ivar)
|
|
{
|
|
_ivarAccess->accessType=NSObjectIVarsAccessType_Direct;
|
|
_ivarAccess->infos.ivar=ivar;
|
|
NSDebugMLLog(@"low",
|
|
@"direct (IVar named :%@)",
|
|
name_);
|
|
}
|
|
else
|
|
{
|
|
BOOL _respondsToSetObject=NO;
|
|
BOOL _respondsToRemoveObject=NO;
|
|
NSDebugMLLog(@"low",
|
|
@"setIVarNamed %@ in %@ %p (superClass:%@) "
|
|
@"with dictionary ",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]);
|
|
_respondsToSetObject
|
|
= [self respondsToSelector:@selector(setObject:forKey:)];
|
|
_respondsToRemoveObject
|
|
=[self respondsToSelector:@selector(removeObjectForKey:)];
|
|
if (_respondsToSetObject)
|
|
{
|
|
if (_respondsToRemoveObject)
|
|
_ivarAccess->accessType
|
|
= NSObjectIVarsAccessType_DictionaryWithRemoveObject;
|
|
else
|
|
_ivarAccess->accessType
|
|
= NSObjectIVarsAccessType_DictionaryWithoutRemoveObject;
|
|
}
|
|
else
|
|
{
|
|
BOOL _respondsToTakeValue
|
|
= [self respondsToSelector:@selector(takeValue:forKey:)];
|
|
if (_respondsToTakeValue)
|
|
_ivarAccess->accessType=NSObjectIVarsAccessType_EO;
|
|
else
|
|
{
|
|
_exception
|
|
= [NSException exceptionWithName:@"NSObject IVar"
|
|
format:@"Can't set Variable named %@ "
|
|
@"in %@ %p (superClass:%@) value=%@",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass],
|
|
value_];
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
if (_exception)
|
|
_ivarAccess->accessType=NSObjectIVarsAccessType_Error;
|
|
if (_cachindEnabled)
|
|
{
|
|
if (!objectClassLock)
|
|
objectClassLock=[NSLock new];
|
|
LoggedLockBeforeDate(objectClassLock, GSW_LOCK_LIMIT);
|
|
[_classCache setObject:_ivarAccess
|
|
forKey:name_];
|
|
LoggedUnlock(objectClassLock);
|
|
};
|
|
};
|
|
if (_exception)
|
|
[_exception raise];
|
|
else
|
|
[self setIVarNamed:name_
|
|
withValue:value_
|
|
withCacheObject:_ivarAccess];
|
|
// LOGObjectFnStop();
|
|
};
|
|
#endif
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
#define PERFORM_SELECTOR_WITH_XX_VALUE \
|
|
id retValue=nil; \
|
|
NSMethodSignature* methodSignature=[NSObject methodSignatureForSelector:_selector]; \
|
|
const char* retType=[methodSignature methodReturnType]; \
|
|
NSInvocation* invocation= [NSInvocation invocationWithMethodSignature:methodSignature]; \
|
|
[invocation setTarget:self]; \
|
|
[invocation setSelector:_selector]; \
|
|
[invocation setArgument:&_value atIndex:2]; \
|
|
[invocation invoke]; \
|
|
if (retType && *retType==_C_ID) \
|
|
[invocation getReturnValue:&retValue]; \
|
|
return retValue;
|
|
|
|
//--------------------------------------------------------------------
|
|
-(id)performSelector:(SEL)_selector
|
|
withIntValue:(int)_value
|
|
{
|
|
PERFORM_SELECTOR_WITH_XX_VALUE
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(id)performSelector:(SEL)_selector
|
|
withFloatValue:(float)_value
|
|
{
|
|
PERFORM_SELECTOR_WITH_XX_VALUE
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(id)performSelector:(SEL)_selector
|
|
withDoubleValue:(double)_value
|
|
{
|
|
PERFORM_SELECTOR_WITH_XX_VALUE
|
|
};
|
|
//--------------------------------------------------------------------
|
|
-(id)performSelector:(SEL)_selector
|
|
withShortValue:(short)_value
|
|
{
|
|
PERFORM_SELECTOR_WITH_XX_VALUE
|
|
};
|
|
//--------------------------------------------------------------------
|
|
-(id)performSelector:(SEL)_selector
|
|
withUShortValue:(ushort)_value
|
|
{
|
|
PERFORM_SELECTOR_WITH_XX_VALUE
|
|
};
|
|
|
|
@end
|
|
|