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
) {
22 meta
= metaclass_s_attach(state
, cls
);
23 class_set_superclass(meta
, sup
);
28 OBJECT
object_metaclass(STATE
, OBJECT obj
) {
29 if(REFERENCE_P(obj
)) {
30 if( metaclass_s_metaclass_p(state
, obj
->klass
) ) {
33 return object_create_metaclass(state
, obj
, 0);
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
;
47 OBJECT
object_make_weak_ref(STATE
, OBJECT self
) {
50 tup
= tuple_new2(state
, 1, self
);
51 tup
->RefsAreWeak
= TRUE
;
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
) {
65 if(REFERENCE_P(self
)) { /* object_class() skips metaclasses */
69 found
= state
->global
->special_classes
[((uintptr_t)self
) & SPECIAL_CLASS_MASK
];
77 found
= class_get_superclass(found
);
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
) {
94 #define REMEMBER_FLAG 0x10
96 void object_propgate_gc_info(STATE
, OBJECT self
, OBJECT dest
) {
97 if(dest
->gc_zone
!= MatureObjectZone
|| dest
->Remember
)
100 if(self
->gc_zone
== MatureObjectZone
) {
102 ptr_array_append(state
->om
->gc
->remember_set
, (xpointer
)dest
);
103 dest
->Remember
= TRUE
;
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. */
123 int object_copy_bytes_into(STATE
, OBJECT self
, OBJECT dest
, int count
, int offset
) {
126 str
= (char*)object_byte_start(state
, dest
);
127 start
= str
+ offset
;
129 memcpy((void*)start
, object_byte_start(state
, self
), count
);
133 unsigned int object_hash_int(STATE
, OBJECT self
) {
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 */
140 int val
= N2I(self
); // FIXME for 64bit
141 /* We do this so the 2's complement will fit into 29 bits properly. */
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));
155 hsh
= object_get_id(state
, self
);
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
) {
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
);
181 return lookuptable_fetch(state
, tbl
, sym
);
184 } else if(!object_has_ivars(state
, self
)) {
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
);
209 OBJECT
object_set_ivar(STATE
, OBJECT self
, OBJECT sym
, OBJECT val
) {
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
);
218 t2
= lookuptable_new(state
);
219 lookuptable_store(state
, state
->global
->external_ivars
, self
, t2
);
222 lookuptable_store(state
, tbl
, sym
, val
);
224 } else if(!object_has_ivars(state
, self
)) {
226 meta
= object_metaclass(state
, self
);
227 tbl
= metaclass_get_has_ivars(meta
);
230 t2
= lookuptable_new(state
);
231 metaclass_set_has_ivars(meta
, t2
);
235 lookuptable_store(state
, tbl
, sym
, val
);
239 tbl
= object_get_instance_variables(self
);
241 /* Lazy creation of hash to store instance variables. */
243 tbl
= csm_new(state
);
244 object_set_instance_variables(self
, tbl
);
245 csm_add(state
, tbl
, sym
, val
);
249 if(ISA(tbl
, state
->global
->tuple
)) {
250 if(TRUE_P(csm_add(state
, tbl
, sym
, 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
);
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
) {
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
);
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
);
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
);
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;
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
) {
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
);