ObjFW  Diff

Differences From Artifact [6d60b227fa]:

To Artifact [9b9e08d0f0]:

  • File src/OFAutoreleasePool.m — part of check-in [f5927f8a84] at 2012-07-14 20:00:11 on branch trunk — New autorelease pools.

    This uses the runtime's autorelease pools and implements autorelease
    pools in the ObjFW runtime. It therefore uses ObjFW's autorelease pools
    when using the ObjFW runtime and Apple's autorelease pools when using
    the Apple runtime.

    These new pools should be ARC-compatible now and finally, it should be
    possible to mix OFAutoreleasePools and NSAutoreleasePools again, even
    @autoreleasepool is allowed in the mix now. This also means the old
    bridge to NSAutoreleasePool should not be required anymore, as both use
    the runtime's autorelease pools now.

    As a bonus, it's significantly faster to use the ObjFW runtime with
    ObjFW's autorelease pools than to use Apple's runtime with Apple's
    autorelease pools, as a quick benchmark using OFXMLParser on large files
    showed. (Note: This is not only due to the different autorelease pools,
    but also due to the fact that even with the same autorelease pools it is
    faster using the ObjFW runtime, as can be seen in versions prior to this
    commit.) (user: js, size: 1924) [annotate] [blame] [check-ins using]


17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207

208
209
210
211
212
213
214
#include "config.h"

#include <stdlib.h>

#import "OFAutoreleasePool.h"
#import "OFArray.h"

#import "OFInitializationFailedException.h"
#import "OFNotImplementedException.h"

#ifdef OF_THREADS
# import "threading.h"
static of_tlskey_t firstKey, lastKey;
#else
static OFAutoreleasePool *firstPool = nil, *lastPool = nil;
#endif

#define GROW_SIZE 16

@implementation OFAutoreleasePool
#ifdef OF_THREADS
+ (void)initialize
{
	if (self != [OFAutoreleasePool class])
		return;

	if (!of_tlskey_new(&firstKey) || !of_tlskey_new(&lastKey))
		@throw [OFInitializationFailedException
		    exceptionWithClass: self];
}
#endif

+ (void)addObject: (id)object
{
#ifdef OF_THREADS
	id lastPool = of_tlskey_get(lastKey);
#endif

	if (lastPool == nil) {
		@try {
			[[self alloc] init];
		} @catch (id e) {
			[object release];
			@throw e;
		}

#ifdef OF_THREADS
		lastPool = of_tlskey_get(lastKey);
#endif
	}

	if (lastPool == nil) {
		[object release];
		@throw [OFInitializationFailedException
		    exceptionWithClass: self];
	}

	@try {
		[lastPool _addObject: object];
	} @catch (id e) {
		[object release];
		@throw e;
	}
}

+ (void)_releaseAll
{
#ifdef OF_THREADS
	[of_tlskey_get(firstKey) release];
#else
	[firstPool release];
#endif
}

- init
{
	self = [super init];

	@try {
#ifdef OF_THREADS
		id firstPool = of_tlskey_get(firstKey);
		previousPool = of_tlskey_get(lastKey);

		if (!of_tlskey_set(lastKey, self))
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
#else
		previousPool = lastPool;
		lastPool = self;
#endif

		if (firstPool == nil) {
#ifdef OF_THREADS
			if (!of_tlskey_set(firstKey, self)) {
				of_tlskey_set(lastKey, previousPool);
				@throw [OFInitializationFailedException
				    exceptionWithClass: [self class]];
			}
#else
			firstPool = self;
#endif
		}

		if (previousPool != nil)
			previousPool->nextPool = self;

		size = GROW_SIZE;
		objects = [self allocMemoryWithSize: sizeof(id)
					      count: GROW_SIZE];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)_addObject: (id)object
{
	if (count + 1 > size) {
		objects = [self resizeMemory: objects
					size: sizeof(id)
				       count: size + GROW_SIZE];
		size += GROW_SIZE;
	}

	objects[count] = object;
	count++;
}

- (void)releaseObjects
{
	size_t i;

	[nextPool releaseObjects];

	for (i = 0; i < count; i++)
		[objects[i] release];

	count = 0;
}

- (void)release
{
	[self dealloc];
}

- (void)drain
{
	[self dealloc];
}

- (void)dealloc
{
	size_t i;

	[nextPool dealloc];

	for (i = 0; i < count; i++)
		[objects[i] release];

	/*
	 * If of_tlskey_set fails, this is a real problem. The best we can do
	 * is to not change the pool below the current pool and stop
	 * deallocation. This way, new objects will be added to the current
	 * pool, but released when the pool below gets released - and maybe
	 * the pool itself will be released as well then, because maybe
	 * of_tlskey_set will work this time.
	 */
#ifdef OF_THREADS
	if (!of_tlskey_set(lastKey, previousPool))
		return;
#else
	lastPool = previousPool;
#endif

	if (previousPool != nil)
		previousPool->nextPool = nil;

	/*
	 * If of_tlskey_set fails here, this is even worse, as this will
	 * definitely be a memory leak. But this should never happen anyway.
	 */
#ifdef OF_THREADS
	if (of_tlskey_get(firstKey) == self)
		if (!of_tlskey_set(firstKey, nil))
			return;
#else
	if (firstPool == self)
		firstPool = nil;
#endif


	[super dealloc];
}

- retain
{
	@throw [OFNotImplementedException exceptionWithClass: [self class]







<


<
<
<
<
<
<
|
<
|
|
<
<
|
<
<
|
<
<
<
|
<
|
|

<
<
<
|
<
<
|
<
<
<
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




<
<
<
|
<







<
<
<
|
<
<
<
<
<
<
<

|
<
<
<
<
<
<
<
|
<
|
|
<
<
<
<
<
<








|

<
<
<
<
<
<
|
<
<
|
|
|
|
<
|
<

<
<
|
<














<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

<
<
<

<
|

<
<
<
<
<
<
<
<
<
|
|
|
>







17
18
19
20
21
22
23

24
25






26

27
28


29


30



31

32
33
34



35


36



37
38

















39
40
41
42



43

44
45
46
47
48
49
50



51







52
53







54

55
56






57
58
59
60
61
62
63
64
65
66






67


68
69
70
71

72

73


74

75
76
77
78
79
80
81
82
83
84
85
86
87
88

89















90



91

92
93









94
95
96
97
98
99
100
101
102
103
104
#include "config.h"

#include <stdlib.h>

#import "OFAutoreleasePool.h"
#import "OFArray.h"


#import "OFNotImplementedException.h"







extern id _objc_rootAutorelease(id);

extern void* objc_autoreleasePoolPush(void);
extern void objc_autoreleasePoolPop(void*);





static __thread void *first = NULL;





@implementation OFAutoreleasePool
+ (id)addObject: (id)object
{



	if (first == NULL)


		[[OFAutoreleasePool alloc] init];




	return _objc_rootAutorelease(object);

















}

+ (void)_releaseAll
{



	objc_autoreleasePoolPop(first);

}

- init
{
	self = [super init];

	@try {



		pool = objc_autoreleasePoolPush();








		if (first == NULL)







			first = pool;


		_objc_rootAutorelease(self);






	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)releaseObjects
{






	ignoreRelease = YES;



	objc_autoreleasePoolPop(pool);
	pool = objc_autoreleasePoolPush();


	_objc_rootAutorelease(self);




	ignoreRelease = NO;

}

- (void)release
{
	[self dealloc];
}

- (void)drain
{
	[self dealloc];
}

- (void)dealloc
{

	if (ignoreRelease)















		return;





	ignoreRelease = YES;










	if (first == pool)
		first = NULL;

	objc_autoreleasePoolPop(pool);

	[super dealloc];
}

- retain
{
	@throw [OFNotImplementedException exceptionWithClass: [self class]