Mercurial > repos > rhope
comparison runtime/object.c @ 7:d61550e2c001
Added current work on new runtime
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Wed, 13 May 2009 00:47:40 -0400 |
parents | |
children | 31f8182f3433 |
comparison
equal
deleted
inserted
replaced
6:f67d9be38ddf | 7:d61550e2c001 |
---|---|
1 #include "object.h" | |
2 #include "builtin.h" | |
3 #include <stdlib.h> | |
4 #include <string.h> | |
5 #include <stdio.h> | |
6 | |
7 blueprint ** registered_types = NULL; | |
8 uint32_t max_registered_type = 0; | |
9 uint32_t type_storage = 0; | |
10 | |
11 returntype call_method(uint32_t methodid, calldata * params) | |
12 { | |
13 int i; | |
14 blueprint * bp = get_blueprint(params->params[0]); | |
15 if(methodid >= bp->first_methodid && methodid < bp->last_methodid && bp->method_lookup[methodid - bp->first_methodid]) | |
16 { | |
17 params->tail_func = bp->method_lookup[methodid - bp->first_methodid]; | |
18 return TAIL_RETURN; | |
19 } else { | |
20 if(METHOD_MISSING >= bp->first_methodid && METHOD_MISSING < bp->last_methodid && bp->method_lookup[METHOD_MISSING - bp->first_methodid]) | |
21 { | |
22 params->tail_func = bp->method_lookup[METHOD_MISSING - bp->first_methodid]; | |
23 return TAIL_RETURN; | |
24 } else { | |
25 //TODO: Add useful info to exception | |
26 for(i = 0; i < params->num_params; ++i) | |
27 release_ref(params->params[i]); | |
28 params->params[0] = new_object(TYPE_METHODMISSINGEXCEPTION); | |
29 return EXCEPTION_RETURN; | |
30 } | |
31 } | |
32 } | |
33 | |
34 returntype set_field(uint32_t setfieldid, calldata * params) | |
35 { | |
36 int i; | |
37 blueprint * bp = get_blueprint(params->params[0]); | |
38 if(setfieldid >= bp->first_setfieldid && setfieldid < bp->last_setfieldid && bp->setter_lookup[setfieldid - bp->first_setfieldid]) | |
39 { | |
40 params->tail_func = bp->setter_lookup[setfieldid - bp->first_setfieldid]; | |
41 return TAIL_RETURN; | |
42 } else { | |
43 if(METHOD_SETFIELDMISSING >= bp->first_setfieldid && METHOD_SETFIELDMISSING < bp->last_setfieldid && bp->method_lookup[METHOD_SETFIELDMISSING - bp->first_methodid]) | |
44 { | |
45 params->tail_func = bp->method_lookup[METHOD_SETFIELDMISSING - bp->first_methodid]; | |
46 params->original_methodid = setfieldid; | |
47 return TAIL_RETURN; | |
48 } else { | |
49 //TODO: Add useful info to exception | |
50 for(i = 0; i < params->num_params; ++i) | |
51 release_ref(params->params[i]); | |
52 params->params[0] = new_object(TYPE_FIELDMISSINGEXCEPTION); | |
53 return EXCEPTION_RETURN; | |
54 } | |
55 } | |
56 } | |
57 | |
58 | |
59 returntype get_field(uint32_t getfieldid, calldata * params) | |
60 { | |
61 int i; | |
62 blueprint * bp = get_blueprint(params->params[0]); | |
63 if(getfieldid >= bp->first_getfieldid && getfieldid < bp->last_getfieldid && bp->getter_lookup[getfieldid - bp->first_getfieldid]) | |
64 { | |
65 params->tail_func = bp->getter_lookup[getfieldid - bp->first_getfieldid]; | |
66 return TAIL_RETURN; | |
67 } else { | |
68 if(METHOD_GETFIELDMISSING >= bp->first_getfieldid && METHOD_GETFIELDMISSING < bp->last_getfieldid && bp->method_lookup[METHOD_GETFIELDMISSING - bp->first_methodid]) | |
69 { | |
70 params->tail_func = bp->method_lookup[METHOD_GETFIELDMISSING - bp->first_methodid]; | |
71 params->original_methodid = getfieldid; | |
72 return TAIL_RETURN; | |
73 } else { | |
74 //TODO: Add useful info to exception | |
75 for(i = 0; i < params->num_params; ++i) | |
76 release_ref(params->params[i]); | |
77 params->params[0] = new_object(TYPE_FIELDMISSINGEXCEPTION); | |
78 return EXCEPTION_RETURN; | |
79 } | |
80 } | |
81 } | |
82 | |
83 returntype convert_to(uint32_t convertto, calldata * params) | |
84 { | |
85 int i; | |
86 blueprint * bp = get_blueprint(params->params[0]); | |
87 if(convertto >= bp->first_convertto && convertto < bp->last_convertto && bp->convert_to[convertto]) | |
88 { | |
89 params->tail_func = bp->convert_to[convertto - bp->first_convertto]; | |
90 return TAIL_RETURN; | |
91 } else { | |
92 return NO_CONVERSION; | |
93 } | |
94 } | |
95 | |
96 returntype convert_from(uint32_t convertfrom, calldata * params) | |
97 { | |
98 int i; | |
99 blueprint * bp = registered_types[convertfrom]; | |
100 if(convertfrom >= bp->first_convertfrom && convertfrom < bp->last_convertfrom && bp->convert_from[convertfrom]) | |
101 { | |
102 params->tail_func = bp->convert_from[convertfrom - bp->first_convertfrom]; | |
103 return TAIL_RETURN; | |
104 } else { | |
105 return NO_CONVERSION; | |
106 } | |
107 } | |
108 | |
109 returntype coerce_value(uint32_t type, calldata * params) | |
110 { | |
111 int i; | |
112 blueprint * bp = get_blueprint(params->params[0]); | |
113 if(bp == registered_types[type]) | |
114 return NORMAL_RETURN; | |
115 if(convert_to(type, params) == TAIL_RETURN) | |
116 return TAIL_RETURN; | |
117 if(convert_from(type, params) == TAIL_RETURN) | |
118 return TAIL_RETURN; | |
119 //TODO: Add useful info to exception | |
120 for(i = 0; i < params->num_params; ++i) | |
121 release_ref(params->params[i]); | |
122 params->params[0] = new_object(TYPE_WRONGTYPEEXCEPTION); | |
123 return EXCEPTION_RETURN; | |
124 } | |
125 | |
126 object * alloc_object(blueprint * bp) | |
127 { | |
128 //TODO: Replace with something more performant | |
129 return malloc(bp->boxed_size); | |
130 } | |
131 | |
132 void * alloc_variable(uint32_t size) | |
133 { | |
134 return malloc(size); | |
135 } | |
136 | |
137 void dealloc_object(blueprint * bp, object * obj) | |
138 { | |
139 //TODO: Replace with something more performant | |
140 free(obj); | |
141 } | |
142 | |
143 object * new_object(uint32_t type) | |
144 { | |
145 blueprint * bp; | |
146 object * ret; | |
147 if(type >= max_registered_type || !registered_types[type]) | |
148 return NULL; | |
149 bp = registered_types[type]; | |
150 ret = alloc_object(bp); | |
151 if(ret) | |
152 { | |
153 ret->bprint = bp; | |
154 rh_atomic_set(ret, refcount, 1); | |
155 memset(((char *)ret) + sizeof(object), '\0', bp->size); | |
156 bp->init(ret); | |
157 } | |
158 return ret; | |
159 } | |
160 | |
161 multisize * new_multisize(uint32_t type, uint32_t size) | |
162 { | |
163 blueprint *bp; | |
164 multisize * ret; | |
165 if(type >= max_registered_type || !registered_types[type]) | |
166 return NULL; | |
167 ret = alloc_variable(sizeof(multisize) + type); | |
168 if(ret) | |
169 { | |
170 bp = registered_types[type]; | |
171 ret->base.bprint = bp; | |
172 ret->size = size; | |
173 rh_atomic_set(&(ret->base), refcount, 1); | |
174 memset(((char *)ret) + sizeof(multisize), '\0', size); | |
175 bp->init((object *)ret); | |
176 } | |
177 return ret; | |
178 } | |
179 | |
180 object * copy_object(object * tocopy) | |
181 { | |
182 object * copy; | |
183 multisize * mcopy, *mtocopy; | |
184 blueprint * bp; | |
185 if(rh_atomic_get(tocopy, refcount) == 1) | |
186 return tocopy; | |
187 bp = get_blueprint(tocopy); | |
188 if(bp->size < 0) { | |
189 mtocopy = (multisize *)tocopy; | |
190 mcopy = alloc_variable(sizeof(multisize) + mtocopy->size); | |
191 mcopy->size = mtocopy->size; | |
192 memcpy(((char *)mcopy)+sizeof(multisize), ((char *)mtocopy)+sizeof(multisize), mtocopy->size); | |
193 copy = (object *)mcopy; | |
194 } else { | |
195 copy = alloc_object(bp); | |
196 memcpy(((char *)copy) + sizeof(object), ((char *)tocopy)+sizeof(object), bp->size); | |
197 } | |
198 copy->bprint = bp; | |
199 rh_atomic_set(copy, refcount, 1); | |
200 bp->copy(copy); | |
201 release_ref(tocopy); | |
202 return copy; | |
203 } | |
204 | |
205 void free_object(object * obj) | |
206 { | |
207 blueprint * bp = get_blueprint(obj); | |
208 if(bp->cleanup) | |
209 bp->cleanup(obj); | |
210 dealloc_object(bp, obj); | |
211 } | |
212 | |
213 void release_ref(object * obj) | |
214 { | |
215 if(rh_atomic_sub_testzero(obj, refcount, 1)) | |
216 free_object(obj); | |
217 } | |
218 | |
219 void check_type_storage(type) | |
220 { | |
221 uint32_t type_storage_temp; | |
222 blueprint ** temp; | |
223 if(type >= type_storage) | |
224 if(type_storage) | |
225 { | |
226 type_storage_temp = (type + (type_storage >> 1)); | |
227 temp = realloc(registered_types, type_storage_temp * sizeof(blueprint *)); | |
228 if(temp) | |
229 { | |
230 registered_types = temp; | |
231 memset(registered_types + type_storage, '\0', (type_storage_temp - type_storage) * sizeof(blueprint *)); | |
232 type_storage = type_storage_temp; | |
233 } | |
234 else | |
235 { | |
236 free(registered_types); | |
237 fprintf(stderr, "Couldn't allocate %d bytes for type storage array\n", type_storage_temp * sizeof(blueprint *)); | |
238 exit(-1); | |
239 } | |
240 } else { | |
241 | |
242 if(type < INITIAL_TYPE_STORAGE) | |
243 type_storage =INITIAL_TYPE_STORAGE; | |
244 else | |
245 type_storage = type + 8; | |
246 registered_types = malloc(type_storage * sizeof(blueprint *)); | |
247 if(registered_types) | |
248 memset(registered_types, '\0', type_storage * sizeof(blueprint *)); | |
249 else | |
250 { | |
251 fprintf(stderr, "Couldn't allocate %d bytes for type storage array\n", type_storage * sizeof(blueprint *)); | |
252 exit(-1); | |
253 } | |
254 | |
255 } | |
256 } | |
257 | |
258 void default_action(object * obj) | |
259 { | |
260 } | |
261 | |
262 blueprint * new_blueprint(uint32_t type, uint32_t size, special_func init, special_func copy, special_func cleanup) | |
263 { | |
264 blueprint * bp = malloc(sizeof(blueprint)); | |
265 if(bp) | |
266 { | |
267 bp->size = size; | |
268 bp->boxed_size = size >= 0 ? size + sizeof(object) : size; | |
269 bp->method_lookup = bp->getter_lookup = bp->setter_lookup = bp->convert_to = bp->convert_from = NULL; | |
270 bp->init = init ? init : default_action; | |
271 bp->copy = copy ? copy : default_action; | |
272 bp->cleanup = cleanup ? cleanup : default_action; | |
273 bp->first_methodid = bp->last_methodid = bp->first_getfieldid = bp->last_getfieldid = bp->first_setfieldid = bp->last_setfieldid = bp->first_convertto = bp->last_convertto = bp->first_convertfrom = bp->last_convertfrom = 0; | |
274 //TODO: Handle names | |
275 bp->name = NULL; | |
276 } | |
277 return bp; | |
278 } | |
279 | |
280 blueprint * register_type_byid(uint32_t type, uint32_t size, special_func init, special_func copy, special_func cleanup) | |
281 { | |
282 check_type_storage(type); | |
283 if(registered_types[type]) | |
284 return registered_types[type]; | |
285 registered_types[type] = new_blueprint(type, size, init, copy, cleanup); | |
286 if(!registered_types[type]) | |
287 { | |
288 fputs("Couldn't allocate new object blueprint\n", stderr); | |
289 exit(-1); | |
290 } | |
291 if(type >= max_registered_type) | |
292 max_registered_type = type + 1; | |
293 return registered_types[type]; | |
294 } | |
295 | |
296 void add_method(blueprint * bp, uint32_t methodid, rhope_func impl) | |
297 { | |
298 rhope_func * temp; | |
299 if(methodid < 1) { | |
300 fputs("Attempt to add a method with an ID < 1\n", stderr); | |
301 exit(-1); | |
302 } | |
303 if (!bp->method_lookup) | |
304 { | |
305 bp->method_lookup = malloc(sizeof(rhope_func) * INITIAL_METHOD_LOOKUP); | |
306 if(!bp->method_lookup) { | |
307 fprintf(stderr, "Couldn't allocate %d bytes for method lookup table\n", sizeof(rhope_func) * INITIAL_METHOD_LOOKUP); | |
308 exit(-1); | |
309 } | |
310 if(methodid - BELOW_INITIAL_METHOD < 1) { | |
311 bp->first_methodid = 1; | |
312 bp->last_methodid = 1+INITIAL_METHOD_LOOKUP; | |
313 } else { | |
314 bp->first_methodid = methodid - BELOW_INITIAL_METHOD; | |
315 bp->last_methodid = bp->first_methodid + INITIAL_METHOD_LOOKUP; | |
316 } | |
317 memset(bp->method_lookup, '\0', sizeof(rhope_func) * INITIAL_METHOD_LOOKUP); | |
318 } else { | |
319 if (methodid < bp->first_methodid) { | |
320 temp = bp->method_lookup; | |
321 //Note: if this gets changed to generating an exception on failure, we need to restore the original buffer | |
322 bp->method_lookup = malloc(sizeof(rhope_func) * (bp->last_methodid-methodid)); | |
323 if(!bp->method_lookup) { | |
324 fprintf(stderr, "Couldn't allocate %d bytes for method lookup table\n", sizeof(rhope_func) * (bp->last_methodid-methodid)); | |
325 exit(-1); | |
326 } | |
327 memset(bp->method_lookup, '\0', (bp->first_methodid-methodid) * sizeof(rhope_func)); | |
328 memcpy(bp->method_lookup + bp->first_methodid-methodid, temp, (bp->last_methodid-bp->first_methodid)*sizeof(rhope_func)); | |
329 free(temp); | |
330 bp->first_methodid = methodid; | |
331 } else if(methodid >= bp->last_methodid) { | |
332 //Note: if this gets changed to generating an exception on failure, we need to restore the original buffer | |
333 bp->method_lookup = realloc(bp->method_lookup, (methodid+1-bp->first_methodid) * sizeof(rhope_func)); | |
334 if(!bp->method_lookup) { | |
335 fprintf(stderr, "Couldn't resize method lookup table to %d bytes\n", (methodid+1-bp->first_methodid) * sizeof(rhope_func)); | |
336 exit(-1); | |
337 } | |
338 memset(bp->method_lookup+bp->last_methodid, '\0', (methodid+1)-bp->last_methodid); | |
339 bp->last_methodid = methodid; | |
340 } | |
341 } | |
342 bp->method_lookup[methodid-bp->first_methodid] = impl; | |
343 } |