Added spec:commit task to commit changes to spec/ruby sources.
[rbx.git] / shotgun / lib / object.c
blob82380446fc7595efffb42d8e9d998cfc477775a5
1 #include <string.h>
2 #include <stdlib.h>
4 #include "shotgun/lib/shotgun.h"
5 #include "shotgun/lib/metaclass.h"
6 #include "shotgun/lib/hash.h"
7 #include "shotgun/lib/lookuptable.h"
8 #include "shotgun/lib/string.h"
9 #include "shotgun/lib/tuple.h"
10 #include "shotgun/lib/class.h"
12 OBJECT object_new(STATE) {
13 return object_allocate(state);
16 OBJECT object_create_metaclass(STATE, OBJECT cls, OBJECT sup) {
17 OBJECT meta;
18 if(!sup) {
19 sup = cls->klass;
22 meta = metaclass_s_attach(state, cls);
23 class_set_superclass(meta, sup);
25 return meta;
28 OBJECT object_metaclass(STATE, OBJECT obj) {
29 if(REFERENCE_P(obj)) {
30 if( metaclass_s_metaclass_p(state, obj->klass) ) {
31 return obj->klass;
33 return object_create_metaclass(state, obj, 0);
36 if( NIL_P(obj) ) {
37 return state->global->nil_class;
38 } else if( TRUE_P(obj) ) {
39 return state->global->true_class;
40 } else if( FALSE_P(obj) ) {
41 return state->global->false_class;
44 return Qnil;
47 OBJECT object_make_weak_ref(STATE, OBJECT self) {
48 OBJECT tup;
50 tup = tuple_new2(state, 1, self);
51 tup->RefsAreWeak = TRUE;
53 return tup;
57 * Object#kind_of?
58 * True if given Module is obj's class or one of object's ancestors,
59 * a module included in class or in an ancestor or obj extended by
60 * the module. False otherwise.
62 int object_kind_of_p(STATE, OBJECT self, OBJECT mod) {
63 OBJECT found;
65 if(REFERENCE_P(self)) { /* object_class() skips metaclasses */
66 found = self->klass;
68 else {
69 found = state->global->special_classes[((uintptr_t)self) & SPECIAL_CLASS_MASK];
72 if(found == mod) {
73 return TRUE;
76 while(RTEST(found)) {
77 found = class_get_superclass(found);
79 if(found == mod) {
80 return TRUE;
83 /* IncludedModule is a wrapper around, well, an #included Module */
84 if(REFERENCE_P(found) && found->obj_type == IncModType) {
85 if(included_module_get_module(found) == mod) {
86 return TRUE;
91 return FALSE;
94 #define REMEMBER_FLAG 0x10
96 void object_propgate_gc_info(STATE, OBJECT self, OBJECT dest) {
97 if(dest->gc_zone != MatureObjectZone || dest->Remember)
98 return;
100 if(self->gc_zone == MatureObjectZone) {
101 if(self->Remember) {
102 ptr_array_append(state->om->gc->remember_set, (xpointer)dest);
103 dest->Remember = TRUE;
105 } else {
106 int i;
107 OBJECT tmp;
108 for(i = 0; i < NUM_FIELDS(dest); i++) {
109 tmp = NTH_FIELD(dest, i);
110 if(!REFERENCE_P(tmp)) continue;
112 if(tmp->gc_zone == YoungObjectZone) {
113 ptr_array_append(state->om->gc->remember_set, (xpointer)dest);
114 dest->Remember = TRUE;
115 /* We can return because the only setting we have is now
116 correct, no need to look through all the rest. */
117 return;
123 int object_copy_bytes_into(STATE, OBJECT self, OBJECT dest, int count, int offset) {
124 char *str, *start;
126 str = (char*)object_byte_start(state, dest);
127 start = str + offset;
129 memcpy((void*)start, object_byte_start(state, self), count);
130 return TRUE;
133 unsigned int object_hash_int(STATE, OBJECT self) {
134 unsigned int hsh;
135 hsh = (unsigned int)(uintptr_t)self;
137 if(!REFERENCE_P(self)) {
138 /* Get rid of the tag part (i.e. the part that indicate nature of self */
139 if(FIXNUM_P(self)) {
140 int val = N2I(self); // FIXME for 64bit
141 /* We do this so the 2's complement will fit into 29 bits properly. */
142 if(val < 0) {
143 hsh = hsh >> 1;
146 hsh = hsh >> 2;
147 } else {
148 if(ISA(self, state->global->string)) {
149 hsh = string_hash_int(state, self);
150 } else if(ISA(self, BASIC_CLASS(bignum))) {
151 hsh = bignum_hash_int(self);
152 } else if(ISA(self, BASIC_CLASS(floatpoint))) {
153 hsh = string_hash_str((unsigned char *)BYTES_OF(self), sizeof(double));
154 } else {
155 hsh = object_get_id(state, self);
159 return hsh;
162 /* TODO: here we could check that the 1st field
163 is currently storing a Hash for the ivars and also
164 use that to determine if this object has ivars. */
165 int object_has_ivars(STATE, OBJECT self) {
166 return (self->CanStoreIvars);
169 void object_set_has_ivars(STATE, OBJECT self) {
170 self->CanStoreIvars = TRUE;
173 OBJECT object_get_ivar(STATE, OBJECT self, OBJECT sym) {
174 OBJECT tbl, val;
176 /* Implements the external ivars table for objects that don't
177 have their own space for ivars. */
178 if(!REFERENCE_P(self)) {
179 tbl = lookuptable_fetch(state, state->global->external_ivars, self);
180 if(RTEST(tbl)) {
181 return lookuptable_fetch(state, tbl, sym);
183 return Qnil;
184 } else if(!object_has_ivars(state, self)) {
185 OBJECT meta;
186 meta = object_metaclass(state, self);
187 tbl = metaclass_get_has_ivars(meta);
189 if(NIL_P(tbl)) return Qnil;
191 return lookuptable_fetch(state, tbl, sym);
194 tbl = object_get_instance_variables(self);
196 /* No table, no ivar! */
197 if(!RTEST(tbl)) return Qnil;
199 /* It's a tuple, use csm */
200 if(ISA(tbl, state->global->tuple)) {
201 return csm_find(state, tbl, sym);
204 /* It's a normal hash, no problem. */
205 val = lookuptable_fetch(state, tbl, sym);
206 return val;
209 OBJECT object_set_ivar(STATE, OBJECT self, OBJECT sym, OBJECT val) {
210 OBJECT tbl, t2;
212 /* Implements the external ivars table for objects that don't
213 have their own space for ivars. */
214 if(!REFERENCE_P(self)) {
215 tbl = lookuptable_fetch(state, state->global->external_ivars, self);
217 if(NIL_P(tbl)) {
218 t2 = lookuptable_new(state);
219 lookuptable_store(state, state->global->external_ivars, self, t2);
220 tbl = t2;
222 lookuptable_store(state, tbl, sym, val);
223 return val;
224 } else if(!object_has_ivars(state, self)) {
225 OBJECT meta;
226 meta = object_metaclass(state, self);
227 tbl = metaclass_get_has_ivars(meta);
229 if(NIL_P(tbl)) {
230 t2 = lookuptable_new(state);
231 metaclass_set_has_ivars(meta, t2);
232 tbl = t2;
235 lookuptable_store(state, tbl, sym, val);
236 return val;
239 tbl = object_get_instance_variables(self);
241 /* Lazy creation of hash to store instance variables. */
242 if(NIL_P(tbl)) {
243 tbl = csm_new(state);
244 object_set_instance_variables(self, tbl);
245 csm_add(state, tbl, sym, val);
246 return val;
249 if(ISA(tbl, state->global->tuple)) {
250 if(TRUE_P(csm_add(state, tbl, sym, val))) {
251 return val;
253 /* csm_add said false, meaning there is no room. We convert
254 the csm into a normal hash and use it from now on. */
255 tbl = csm_into_lookuptable(state, tbl);
256 object_set_instance_variables(self, tbl);
258 lookuptable_store(state, tbl, sym, val);
259 return val;
262 OBJECT object_get_ivars(STATE, OBJECT self) {
263 if(!REFERENCE_P(self)) {
264 return lookuptable_fetch(state, state->global->external_ivars, self);
265 } else if(!object_has_ivars(state, self)) {
266 return metaclass_get_has_ivars(object_metaclass(state, self));
269 return object_get_instance_variables(self);
272 void object_copy_ivars(STATE, OBJECT self, OBJECT dest) {
273 OBJECT tbl;
274 if(!REFERENCE_P(self)) {
275 tbl = lookuptable_fetch(state, state->global->external_ivars, self);
276 } else if(!object_has_ivars(state, self)) {
277 if(metaclass_s_metaclass_p(state, self->klass)) {
278 tbl = metaclass_get_has_ivars(self->klass);
279 } else {
280 return;
282 } else {
283 tbl = object_get_instance_variables(self);
286 if(NIL_P(tbl)) return;
288 if(ISA(tbl, state->global->tuple)) {
289 tbl = tuple_dup(state, tbl);
290 } else {
291 tbl = lookuptable_dup(state, tbl);
294 if(!REFERENCE_P(dest)) {
295 lookuptable_store(state, state->global->external_ivars, dest, tbl);
296 } else if(!object_has_ivars(state, dest)) {
297 metaclass_set_has_ivars(object_metaclass(state, dest), tbl);
298 } else {
299 object_set_instance_variables(dest, tbl);
303 void object_copy_metaclass(STATE, OBJECT self, OBJECT dest) {
304 OBJECT meta, new_meta;
305 if(!REFERENCE_P(self)) return;
307 meta = self->klass;
308 if(!metaclass_s_metaclass_p(state, meta)) return;
310 new_meta = object_metaclass(state, dest);
311 module_set_method_table(new_meta, lookuptable_dup(state, module_get_method_table(meta)));
314 int object_stores_bytes_p(STATE, OBJECT self) {
315 if(!REFERENCE_P(self)) return FALSE;
316 return self->StoresBytes;
319 int _object_stores_bytes(OBJECT self) {
320 return self->StoresBytes;
323 void object_make_byte_storage(STATE, OBJECT self) {
324 self->StoresBytes = TRUE;
327 void object_initialize_bytes(STATE, OBJECT self) {
328 int sz;
329 sz = SIZE_OF_BODY(self);
330 memset(object_byte_start(state, self), 0, sz);
333 void object_set_tainted(STATE, OBJECT self) {
334 if(!REFERENCE_P(self)) return;
335 self->IsTainted = TRUE;
338 int object_tainted_p(STATE, OBJECT self) {
339 return (REFERENCE_P(self) && self->IsTainted);
342 void object_set_untainted(STATE, OBJECT self) {
343 if(!REFERENCE_P(self)) return;
344 self->IsTainted = FALSE;
347 void object_set_frozen(STATE, OBJECT self) {
348 if(!REFERENCE_P(self)) return;
349 self->IsFrozen = TRUE;
352 int object_frozen_p(STATE, OBJECT self) {
353 return (REFERENCE_P(self) && self->IsFrozen);