Objectively
Object oriented framework for C.
Loading...
Searching...
No Matches
Class.c
Go to the documentation of this file.
1/*
2 * Objectively: Ultra-lightweight object oriented framework for GNU C.
3 * Copyright (C) 2014 Jay Dolan <jay@jaydolan.com>
4 *
5 * This software is provided 'as-is', without any express or implied
6 * warranty. In no event will the authors be held liable for any damages
7 * arising from the use of this software.
8 *
9 * Permission is granted to anyone to use this software for any purpose,
10 * including commercial applications, and to alter it and redistribute it
11 * freely, subject to the following restrictions:
12 *
13 * 1. The origin of this software must not be misrepresented; you must not
14 * claim that you wrote the original software. If you use this software
15 * in a product, an acknowledgment in the product documentation would be
16 * appreciated but is not required.
17 *
18 * 2. Altered source versions must be plainly marked as such, and must not be
19 * misrepresented as being the original software.
20 *
21 * 3. This notice may not be removed or altered from any source distribution.
22 */
23
24#include "Config.h"
25
26#include <assert.h>
27#include <dlfcn.h>
28#include <stdlib.h>
29#include <stdio.h>
30#include <string.h>
31
32#if defined(_WIN32)
33#include <Windows.h>
34#elif defined(__APPLE__)
35#include <mach-o/dyld.h>
36#else
37#include <link.h>
38#endif
39
40#if HAVE_UNISTD_H
41#include <unistd.h>
42#endif
43
44#include "Class.h"
45#include "Object.h"
46
47size_t _pageSize;
48
50
57#define MAX_CLASS_IMAGES 8
59static size_t _classImageCount;
60
64static void teardown(void) {
65 Class *c;
66
67 c = _classes;
68 while (c) {
69 if (c->def.destroy) {
70 c->def.destroy(c);
71 }
72
73 c = c->next;
74 }
75
76 c = _classes;
77 while (c) {
78
79 Class *next = c->next;
80
81 free(c->interface);
82 free(c);
83
84 c = next;
85 }
86}
87
91static void setup(void) {
92
93 _classes = NULL;
94
95#if !defined(_SC_PAGESIZE)
96 _pageSize = 4096;
97#else
98 _pageSize = sysconf(_SC_PAGESIZE);
99#endif
100
101 atexit(teardown);
102}
103
109static const ident imageForAddress(const ident address) {
110
111 assert(address);
112
113#if defined(_WIN32)
114 HMODULE module;
115 if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
116 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR) address, &module)) {
117 return module;
118 }
119#else
120 Dl_info info;
121 if (dladdr(address, &info)) {
122 return info.dli_fbase;
123 }
124#endif
125
126 return NULL;
127}
128
130
131 static Once once;
132 do_once(&once, setup());
133
134 assert(def);
135 assert(def->name);
136 assert(def->instanceSize);
137 assert(def->interfaceSize);
138 assert(def->interfaceOffset);
139
140 Class *clazz = calloc(1, sizeof(Class));
141 assert(clazz);
142
143 clazz->def = *def;
144
145 clazz->interface = calloc(1, def->interfaceSize);
146 assert(clazz->interface);
147
148 Class *superclass = clazz->def.superclass;
149 if (superclass) {
150
151 assert(superclass->def.instanceSize <= def->instanceSize);
152 assert(superclass->def.interfaceSize <= def->interfaceSize);
153
154 memcpy(clazz->interface, superclass->interface, superclass->def.interfaceSize);
155 }
156
157 if (clazz->def.initialize) {
158 clazz->def.initialize(clazz);
159 }
160
161 /* def.name is a literal in the declaring image, where the ClassDef itself is
162 * a compound literal with automatic storage. */
163 clazz->image = imageForAddress((ident) def->name);
164
165 clazz->next = __sync_lock_test_and_set(&_classes, clazz);
166
167 return clazz;
168}
169
171
172 ident obj = calloc(1, clazz->def.instanceSize);
173 assert(obj);
174
175 Object *object = (Object *) obj;
176
177 object->magic = OBJECTIVELY_MAGIC;
178 object->clazz = clazz;
179 object->referenceCount = 1;
180
181 ident interface = clazz->interface;
182 do {
183 *(ident *) (obj + clazz->def.interfaceOffset) = interface;
184 } while ((clazz = clazz->def.superclass));
185
186 return obj;
187}
188
189ident _cast(const Class *clazz, const ident obj) {
190
191 if (obj) {
192 const Class *c = ((Object *) obj)->clazz;
193 while (c) {
194
195 // as a special case, we optimize for _Object
196 if (c == clazz || clazz == _Object()) {
197 break;
198 }
199
200 c = c->def.superclass;
201 }
202 assert(c);
203 }
204
205 return (ident) obj;
206}
207
215static ident imageForHandle(ident handle) {
216
217 assert(handle);
218
219#if defined(_WIN32)
220 char path[MAX_PATH];
221 if (GetModuleFileNameA((HMODULE) handle, path, sizeof(path))) {
222 return handle;
223 }
224#elif defined(__APPLE__)
225 for (uint32_t i = 0; i < _dyld_image_count(); i++) {
226
227 /* RTLD_LOCAL is not the default on macOS, and dlopen of an image already
228 * loaded promotes it to the global namespace, which would put every image in
229 * the process there - undoing the isolation the caller loaded it for. */
230 ident image = dlopen(_dyld_get_image_name(i), RTLD_LAZY | RTLD_NOLOAD | RTLD_LOCAL);
231 if (image == NULL) {
232 continue;
233 }
234
235 dlclose(image);
236
237 if (image == handle) {
238 return (ident) _dyld_get_image_header(i);
239 }
240 }
241#else
242 struct link_map *map;
243 if (dlinfo(handle, RTLD_DI_LINKMAP, &map) == 0 && map) {
244 return (ident) map->l_addr;
245 }
246#endif
247
248 return NULL;
249}
250
252
253 assert(handle);
254
255 for (size_t i = 0; i < _classImageCount; i++) {
256 if (_classImages[i] == handle) {
257
258 memmove(_classImages + i, _classImages + i + 1,
259 (_classImageCount - i - 1) * sizeof(ident));
260
262 break;
263 }
264 }
265
266 const ident image = imageForHandle(handle);
267 if (image == NULL) {
268 return;
269 }
270
271 Class **link = &_classes;
272 while (*link) {
273 Class *clazz = *link;
274
275 if (clazz->image == image) {
276 *link = clazz->next;
277 clazz->next = NULL;
278 } else {
279 link = &clazz->next;
280 }
281 }
282}
283
284void addClassImage(ident handle) {
285
286 assert(handle);
288
289 _classImages[_classImageCount++] = handle;
290}
291
292Class *classForName(const char *name) {
293
294 if (name) {
295 Class *c = _classes;
296 while (c) {
297 if (strcmp(name, c->def.name) == 0) {
298 return c;
299 }
300 c = c->next;
301 }
302
303 char *s;
304 if (asprintf(&s, "_%s", name) > 0) {
305 Class *clazz = NULL;
306 Class *(*archetype)(void) = NULL;
307
308 for (size_t i = _classImageCount; i > 0 && archetype == NULL; i--) {
309 archetype = dlsym(_classImages[i - 1], s);
310 }
311
312 if (archetype == NULL) {
313#if defined(_WIN32)
314 static Once once;
315 static ident handle;
316 do_once(&once, { handle = dlopen(NULL, RTLD_LAZY); });
317 archetype = handle ? dlsym(handle, s) : NULL;
318#else
319 archetype = dlsym(RTLD_DEFAULT, s);
320#endif
321 }
322
323 if (archetype) {
324 clazz = archetype();
325 }
326
327 free(s);
328 return clazz;
329 }
330 }
331
332 return NULL;
333}
334
336
337 if (obj) {
338 Object *object = cast(Object, obj);
339
340 assert(object);
341
342 if (__sync_add_and_fetch(&object->referenceCount, -1) == 0) {
343 $(object, dealloc);
344 }
345 }
346
347 return NULL;
348}
349
351
352 Object *object = cast(Object, obj);
353
354 assert(object);
355
356 __sync_add_and_fetch(&object->referenceCount, 1);
357
358 return obj;
359}
static void map(Array *self, Functor functor, ident data)
Definition Array.c:536
static void dealloc(Object *self)
Definition Array.c:99
void addClassImage(ident handle)
Registers an image that provides Classes, e.g. a plugin.
Definition Class.c:284
static const ident imageForAddress(const ident address)
Definition Class.c:109
#define MAX_CLASS_IMAGES
The registered images providing Classes.
Definition Class.c:57
static ident _classImages[MAX_CLASS_IMAGES]
Definition Class.c:58
static void teardown(void)
Called atexit to teardown Objectively.
Definition Class.c:64
ident _alloc(Class *clazz)
Instantiate a type through the given Class.
Definition Class.c:170
static void setup(void)
Called when initializing Object to setup Objectively.
Definition Class.c:91
static ident imageForHandle(ident handle)
Definition Class.c:215
size_t _pageSize
Definition Class.c:47
Class * classForName(const char *name)
Definition Class.c:292
ident release(ident obj)
Atomically decrement the given Object's reference count. If the resulting reference count is 0,...
Definition Class.c:335
Class * _initialize(const ClassDef *def)
Initializes the given Class.
Definition Class.c:129
static Class * _classes
Definition Class.c:49
static size_t _classImageCount
Definition Class.c:59
void removeClassImage(ident handle)
Unregisters an image, and every Class it declared.
Definition Class.c:251
ident retain(ident obj)
Atomically increment the given Object's reference count.
Definition Class.c:350
ident _cast(const Class *clazz, const ident obj)
Perform a type-checking cast.
Definition Class.c:189
Classes describe the state and behavior of an Objectively type.
#define obj
#define cast(type, obj)
Safely cast obj to type.
Definition Class.h:228
#define OBJECTIVELY_MAGIC
The header value identifying Objectively types.
Definition Class.h:205
static void info(const Log *self, const char *fmt,...)
Definition Log.c:118
Class * _Object(void)
Definition Object.c:136
Object is the root Class of The Objectively Class hierarchy.
UTF-8 strings.
static Unicode next(StringReader *self, StringReaderMode mode)
void * ident
The identity type, similar to Objective-C id.
Definition Types.h:49
long Once
The Once type.
Definition Once.h:37
#define do_once(once, block)
Executes the given block at most one time.
Definition Once.h:43
ClassDefs are passed to _initialize via an archetype to initialize a Class.
Definition Class.h:41
size_t instanceSize
The instance size (required).
Definition Class.h:69
size_t interfaceSize
The interface size (required).
Definition Class.h:79
ptrdiff_t interfaceOffset
The interface offset (required).
Definition Class.h:74
Class * superclass
The superclass (required). e.g. _Object().
Definition Class.h:89
void(* destroy)(Class *clazz)
The Class destructor (optional). This method is run for initialized Classes when your application exi...
Definition Class.h:47
const char * name
The Class name (required).
Definition Class.h:84
void(* initialize)(Class *clazz)
The Class initializer (optional).
Definition Class.h:64
The runtime representation of a Class.
Definition Class.h:95
ident image
The base address of the image that declared this Class.
Definition Class.h:118
ClassDef def
The Class definition.
Definition Class.h:100
Class * next
Provides chaining of initialized Classes.
Definition Class.h:110
ident interface
The interface of the Class.
Definition Class.h:105
Object is the root Class of The Objectively Class hierarchy.
Definition Object.h:46
unsigned int magic
A header to allow introspection of Object types.
Definition Object.h:50