rt_public EIF_BOOLEAN eequal(register EIF_REFERENCE target, register EIF_REFERENCE source) { /* Eiffel standard equality: it assumes that dynamic type of Eiffel * object refered by `source' conforms to dynamic type of Eiffel * object refered by `target'. `source' and `target' cannot be NULL * or special objects here. * If both `source' and `target' have the same dynamic type and this * type is not composite, then perform a block comparison; otherwise * perform a field by field comparison. * It is the feature `standard_is_equal' of class ANY. * Return a boolean. */ REQUIRE ("source_not_null", source); REQUIRE ("target_not_null", target); if (source == target) { /* Minor optimization, if references are equal then it is the same object. */ return EIF_TRUE; } if (Dftype(source) == Dftype(target)) { /* Dynamic type are the same: because of the intra-expanded * references, we can perform only a block comparison if * the target (or the source) is a composite object (i.e: it has * expanded attributes): since an attribute keeps expanded or * not expanded all the time, we can test either the source or * the target. */ if (HEADER(source)->ov_flags & EO_SPEC) { /* Works for both SPECIAL and TUPLE object */ /* Eiffel standard equality on special objects: type check assumes * the comparison is on areas of the same type (containing the same * thing). Called by the redefinition of feature `equal' of special * class. `source' and/or `target' cannot be NULL. * Return a boolean. */ /* First condition: same count */ if ((RT_SPECIAL_COUNT(source) != RT_SPECIAL_COUNT(target)) || (RT_SPECIAL_ELEM_SIZE(source) != RT_SPECIAL_ELEM_SIZE(target))) { return EIF_FALSE; } else { /* Second condition: block equality */ return EIF_TEST(!memcmp (source, target, RT_SPECIAL_VISIBLE_SIZE(source))); } } else { if (!(HEADER(source)->ov_flags & EO_COMP)) /* Perform a block comparison */ return EIF_TEST(!memcmp (source, target, EIF_Size(Dtype(source)))); else return e_field_equal(target, source); } } /* Field by field comparison */ return EIF_FALSE; }
rt_public void eif_std_ref_copy(register EIF_REFERENCE source, register EIF_REFERENCE target) { /* Copy Eiffel object `source' into Eiffel object `target'. * Dynamic type of `source' is supposed to be the same as dynamic type * of `target'. It assumes also that `source' and `target' are not * references on special objects. * Problem: updating intra-references on expanded object * because the garbage collector needs to explore those references. */ uint16 flags; /* Source object flags */ union overhead *s_zone; /* Source object header */ union overhead *t_zone; /* Target object header */ #ifdef ISE_GC EIF_REFERENCE enclosing; /* Enclosing target object */ #endif rt_uint_ptr size; s_zone = HEADER(source); flags = s_zone->ov_flags; t_zone = HEADER(target); if (s_zone->ov_dftype == t_zone->ov_dftype) { if (flags & EO_COMP) { /* Case of composite object: updating of references on expanded objects. */ eif_std_field_copy (source, target); } else { /* Copy of source object into target object with same dynamic type. Block copy here. */ if (flags & EO_SPEC) { size = RT_SPECIAL_VISIBLE_SIZE(source); } else { size = EIF_Size(s_zone->ov_dtype); } memmove(target, source, size); } #ifdef ISE_GC /* Precompute the enclosing target object */ enclosing = target; /* By default */ if (eif_is_nested_expanded(t_zone->ov_flags)) { enclosing -= t_zone->ov_size & B_SIZE; } /* Perform aging tests. We need the address of the enclosing object to * update the flags there, in case the target is to be memorized. */ flags = HEADER(enclosing)->ov_flags; CHECK ("Not forwarded", !(HEADER (enclosing)->ov_size & B_FWD)); if ( flags & EO_OLD && /* Object is old */ !(flags & EO_REM) && /* Not remembered */ refers_new_object(target) /* And copied refers to new objects */ ) erembq(enclosing); /* Then remember the enclosing object */ #endif /* ISE_GC */ } }
rt_private EIF_REFERENCE duplicate(EIF_REFERENCE source, EIF_REFERENCE enclosing, rt_uint_ptr offset) /* Object to be duplicated */ /* Object where attachment is made */ /* Offset within enclosing where attachment is made */ { /* Duplicate the source object (shallow duplication) and attach the freshly * allocated copy at the address pointed to by receiver, which is protected * against GC movements. Returns the address of the cloned object. */ RT_GET_CONTEXT union overhead *zone; /* Malloc info zone */ uint16 flags; /* Object's flags */ rt_uint_ptr size; /* Object's size */ EIF_REFERENCE *hash_zone; /* Hash table entry recording duplication */ EIF_REFERENCE clone; /* Where clone is allocated */ REQUIRE("source not null", source); REQUIRE("enclosing not null", enclosing); zone = HEADER(source); /* Where eif_malloc stores its information */ flags = zone->ov_flags; /* Eiffel flags */ if (flags & EO_SPEC) { size = RT_SPECIAL_VISIBLE_SIZE(source); } else { size = EIF_Size(zone->ov_dtype); } clone = eif_access(map_next()); /* Get next stacked object */ *(EIF_REFERENCE *) (enclosing + offset) = clone; /* Attach new object */ hash_zone = hash_search(&hclone, source); /* Get an hash table entry */ CHECK("Enough space", HEADER(clone)->ov_size >= size); memcpy (clone, source, size); /* Block copy */ *hash_zone = clone; /* Fill it in with the clone address */ #ifdef ISE_GC /* Once the duplication is done, the receiving object might refer to a new * object (a newly allocated object is always new), and thus aging tests * must be performed, to eventually remember the enclosing object of the * receiver. */ flags = HEADER(enclosing)->ov_flags; if (!(flags & EO_OLD)) /* Receiver is a new object */ return clone; /* No aging tests necessary */ if (HEADER (clone)->ov_flags & EO_OLD) /* Old object with old reference.*/ return clone; /* No further action necessary */ CHECK ("Object is old and has reference to new one", (flags & EO_OLD) && !(HEADER (clone)->ov_flags & EO_OLD)); if (flags & EO_REM) /* Old object is already remembered */ return clone; /* No further action necessary */ else erembq(enclosing); /* Then remember the enclosing object */ #endif /* ISE_GC */ return clone; }