/* call-seq: * swap_method_tables(other) -> self * * Swap the method table of the receiver with the method table of the given * class or module. If +other+ is not a class or module, raise a +TypeError+. */ static VALUE evilr_swap_method_tables(VALUE self, VALUE other) { struct st_table *tmp; evilr__check_immediate(other); if(BUILTIN_TYPE(other) != T_MODULE && BUILTIN_TYPE(other) != T_CLASS) { rb_raise(rb_eTypeError, "non-class or module used"); } tmp = RCLASS_M_TBL(self); RCLASS(self)->m_tbl = RCLASS_M_TBL(other); RCLASS(other)->m_tbl = tmp; rb_clear_cache_by_class(self); rb_clear_cache_by_class(other); return self; }
/* call-seq: * set_singleton_class(klass) -> klass * * Makes the given +klass+ the singleton class of the receiver, * ignoring any existing singleton class and modules extending the receiver. * Modules already included in +klass+ become modules that extend the receiver. * If the receiver is an immediate or +klass+ is not a Class, * raises +TypeError+. */ static VALUE evilr_set_singleton_class(VALUE self, VALUE klass) { evilr__check_obj_and_class(self, klass); RCLASS_SET_SUPER(evilr__iclass_before_next_class(klass), rb_obj_class(self)); rb_clear_cache_by_class(klass); evilr__make_singleton(self, klass); return klass; }
/* Walk the super chain starting with the given iclass and include * the modules related to each iclass into the mod such that the * order of the initial iclass super chain and mod's super chain are * the same. */ void evilr__include_iclasses(VALUE mod, VALUE iclass) { if (iclass && BUILTIN_TYPE(iclass) == T_ICLASS) { evilr__include_iclasses(mod, RCLASS_SUPER(iclass)); rb_include_module(mod, RBASIC_KLASS(iclass)); } rb_clear_cache_by_class(mod); }
/* call-seq: * superclass=(klass) -> klass * * Modifies the superclass of the current class to be the given * class. Any modules included in the receiver remain included. * Raises +TypeError+ if klass is not a Class or if the receiver * and class are not compatible (where their instances use * different internal types). */ static VALUE evilr_superclass_e(VALUE klass, VALUE super) { VALUE iclass; evilr__check_compatible_classes(klass, super); iclass = evilr__iclass_before_next_class(klass); RCLASS_SET_SUPER(iclass, super); rb_clear_cache_by_class(klass); return super; }
static void set_method_visibility(VALUE self, int argc, VALUE *argv, ID ex) { int i; secure_visibility(self); for (i = 0; i < argc; i++) { rb_export_method(self, rb_to_id(argv[i]), ex); } rb_clear_cache_by_class(self); }
/* If self has a singleton class, set the superclass of the * singleton class to the given klass, keeping all modules * that are included in the singleton class. Otherwise, set the * object's klass to the given klass. */ void evilr__reparent_singleton_class(VALUE self, VALUE klass) { VALUE self_klass = RBASIC_KLASS(self); if (IS_SINGLETON_CLASS(self_klass)) { RCLASS_SET_SUPER(evilr__iclass_before_next_class(self_klass), klass); rb_clear_cache_by_class(self_klass); } else { RBASIC_SET_KLASS(self, klass); } }
static void set_method_visibility(VALUE self, int argc, VALUE *argv, rb_method_flag_t ex) { int i; secure_visibility(self); for (i = 0; i < argc; i++) { VALUE v = argv[i]; ID id = rb_check_id(&v); if (!id) { rb_print_undef_str(self, v); } rb_export_method(self, id, ex); } rb_clear_cache_by_class(self); }
/* call-seq: * unextend(mod) -> mod || nil * * Unextends the given module +mod+ from the receiver. If the receiver's class includes the * module, does not uninclude it, so this should not affect any other objects besides the * receiver. If +mod+ already extended the object, returns +mod+, otherwise returns +nil+. * Raises +TypeError+ if +mod+ is not a Module or if the receiver is an immediate. */ static VALUE evilr_unextend(VALUE self, VALUE mod) { VALUE prev, cur; evilr__check_immediates(self, mod); evilr__check_type(T_MODULE, mod); self = rb_singleton_class(self); rb_clear_cache_by_class(self); for (prev = self, cur = RCLASS_SUPER(self); cur && BUILTIN_TYPE(cur) != T_CLASS; prev = cur, cur = RCLASS_SUPER(cur)) { if (BUILTIN_TYPE(cur) == T_ICLASS && RBASIC_KLASS(cur) == mod) { RCLASS_SET_SUPER(prev, RCLASS_SUPER(cur)); return mod; } } return Qnil; }
/* call-seq: * uninclude(mod) -> mod || nil * * Unincludes the given module +mod+ from the receiver or any of the receiver's * ancestors. Walks the super chain of the receiver, and if an iclass for +mod+ is * encountered, the super chain is modified to skip that iclass. Returns +mod+ if * an iclass for mod was present in the super chain, and +nil+ otherwise. If +mod+ is * not a Module, a +TypeError+ is raised. */ static VALUE evilr_uninclude(VALUE klass, VALUE mod) { VALUE cur, prev; evilr__check_immediate(mod); evilr__check_type(T_MODULE, mod); for (prev = klass, cur = RCLASS_SUPER(klass); cur ; prev = cur, cur = RCLASS_SUPER(cur)) { if (BUILTIN_TYPE(prev) == T_CLASS) { rb_clear_cache_by_class(prev); } if (BUILTIN_TYPE(cur) == T_ICLASS && RBASIC_KLASS(cur) == mod) { RCLASS_SET_SUPER(prev, RCLASS_SUPER(cur)); return mod; } } return Qnil; }
/* call-seq: * include_between(mod){|p, c| } -> mod || nil * * Walks the receiver's super chain, yielding the previous and current entries in * the super chain at every step. The first time the block returns +true+, +mod+ is * inserted into the super chain between the two values, and the method returns * immediately. Raises +TypeError+ if +mod+ is not a Module. * If the block ever returns +true+, the return value is +mod+. If * the block never returns +true+, the return value is +nil+. On the first block call, * the first block argument is the receiver, and on the last block call, the last block * argument is +nil+. */ static VALUE evilr_include_between(VALUE klass, VALUE mod) { VALUE iclass, prev, cur; evilr__check_immediate(mod); evilr__check_type(T_MODULE, mod); /* Create ICLASS for module by inserting it and removing it. * If module already in super chain, will change it's position. */ rb_include_module(klass, mod); iclass = evilr__iclass_matching(klass, mod); evilr_uninclude(klass, mod); for (prev = klass, cur = RCLASS_SUPER(klass); prev ; prev = cur, cur = cur ? RCLASS_SUPER(cur) : cur) { if (BUILTIN_TYPE(prev) == T_CLASS) { rb_clear_cache_by_class(prev); } if (rb_yield_values(2, INCLUDE_BETWEEN_VAL(prev), INCLUDE_BETWEEN_VAL(cur)) == Qtrue) { RCLASS_SET_SUPER(prev, iclass); RCLASS_SET_SUPER(iclass, cur); return mod; } } return Qnil; }
/* Set the superclass of self to the given klass, keeping all * modules that are included in the class. */ void evilr__reparent_class(VALUE self, VALUE klass) { RCLASS_SET_SUPER(evilr__iclass_before_next_class(self), klass); rb_clear_cache_by_class(self); }
VALUE rb_object_free(VALUE obj) { ID id_destructor = rb_intern("__destruct__"); /* value returned by destructor */ VALUE destruct_value = Qnil; /* prevent freeing of immediates */ switch (TYPE(obj)) { case T_NIL: case T_FIXNUM: case T_TRUE: case T_FALSE: case T_SYMBOL: rb_raise(rb_eTypeError, "obj_free() called for immediate value"); break; } /* prevent freeing of *some* critical objects */ if ((obj == rb_cObject) || (obj == rb_cClass) || (obj == rb_cModule) || (obj == rb_cSymbol) || (obj == rb_cFixnum) || (obj == rb_cFloat) || (obj == rb_cString) || (obj == rb_cRegexp) || (obj == rb_cInteger) || (obj == rb_cArray) || (obj == rb_cNilClass) || (obj == rb_cFalseClass) || (obj == rb_cTrueClass) || (obj == rb_cNumeric) || (obj == rb_cBignum) || (obj == rb_cStruct)) rb_raise(rb_eTypeError, "obj_free() called for critical object"); /* run destructor (if one is defined) */ if (rb_respond_to(obj, id_destructor)) destruct_value = rb_funcall(obj, id_destructor, 0); #ifdef RUBY_19 switch (BUILTIN_TYPE(obj)) { case T_NIL: case T_FIXNUM: case T_TRUE: case T_FALSE: rb_bug("obj_free() called for broken object"); break; } if (FL_TEST(obj, FL_EXIVAR)) { rb_free_generic_ivar((VALUE)obj); FL_UNSET(obj, FL_EXIVAR); } switch (BUILTIN_TYPE(obj)) { case T_OBJECT: if (!(RANY(obj)->as.basic.flags & ROBJECT_EMBED) && RANY(obj)->as.object.as.heap.ivptr) { xfree(RANY(obj)->as.object.as.heap.ivptr); } break; case T_MODULE: case T_CLASS: rb_clear_cache_by_class((VALUE)obj); rb_free_m_table(RCLASS_M_TBL(obj)); if (RCLASS_IV_TBL(obj)) { st_free_table(RCLASS_IV_TBL(obj)); } if (RCLASS_IV_INDEX_TBL(obj)) { st_free_table(RCLASS_IV_INDEX_TBL(obj)); } xfree(RANY(obj)->as.klass.ptr); break; case T_STRING: rb_str_free(obj); break; case T_ARRAY: rb_ary_free(obj); break; case T_HASH: if (RANY(obj)->as.hash.ntbl) { st_free_table(RANY(obj)->as.hash.ntbl); } break; case T_REGEXP: if (RANY(obj)->as.regexp.ptr) { onig_free(RANY(obj)->as.regexp.ptr); } break; case T_DATA: if (DATA_PTR(obj)) { if (RTYPEDDATA_P(obj)) { RDATA(obj)->dfree = RANY(obj)->as.typeddata.type->dfree; } if ((long)RANY(obj)->as.data.dfree == -1) { xfree(DATA_PTR(obj)); } else if (RANY(obj)->as.data.dfree) { make_deferred(RANY(obj)); return 1; } } break; case T_MATCH: if (RANY(obj)->as.match.rmatch) { struct rmatch *rm = RANY(obj)->as.match.rmatch; onig_region_free(&rm->regs, 0); if (rm->char_offset) xfree(rm->char_offset); xfree(rm); } break; case T_FILE: if (RANY(obj)->as.file.fptr) { make_io_deferred(RANY(obj)); return 1; } break; case T_RATIONAL: case T_COMPLEX: break; case T_ICLASS: /* iClass shares table with the module */ xfree(RANY(obj)->as.klass.ptr); break; case T_FLOAT: break; case T_BIGNUM: if (!(RBASIC(obj)->flags & RBIGNUM_EMBED_FLAG) && RBIGNUM_DIGITS(obj)) { xfree(RBIGNUM_DIGITS(obj)); } break; case T_NODE: switch (nd_type(obj)) { case NODE_SCOPE: if (RANY(obj)->as.node.u1.tbl) { xfree(RANY(obj)->as.node.u1.tbl); } break; case NODE_ALLOCA: xfree(RANY(obj)->as.node.u1.node); break; } break; /* no need to free iv_tbl */ case T_STRUCT: if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 && RANY(obj)->as.rstruct.as.heap.ptr) { xfree(RANY(obj)->as.rstruct.as.heap.ptr); } break; default: rb_bug("gc_sweep(): unknown data type 0x%x(%p)", BUILTIN_TYPE(obj), (void*)obj); } #else switch (BUILTIN_TYPE(obj)) { case T_NIL: case T_FIXNUM: case T_TRUE: case T_FALSE: rb_bug("obj_free() called for broken object"); break; } if (FL_TEST(obj, FL_EXIVAR)) { rb_free_generic_ivar((VALUE)obj); } switch (BUILTIN_TYPE(obj)) { case T_OBJECT: if (RANY(obj)->as.object.iv_tbl) { st_free_table(RANY(obj)->as.object.iv_tbl); } break; case T_MODULE: case T_CLASS: rb_clear_cache_by_class((VALUE)obj); st_free_table(RANY(obj)->as.klass.m_tbl); if (RANY(obj)->as.object.iv_tbl) { st_free_table(RANY(obj)->as.object.iv_tbl); } break; case T_STRING: if (RANY(obj)->as.string.ptr && !FL_TEST(obj, ELTS_SHARED)) { RUBY_CRITICAL(free(RANY(obj)->as.string.ptr)); } break; case T_ARRAY: if (RANY(obj)->as.array.ptr && !FL_TEST(obj, ELTS_SHARED)) { RUBY_CRITICAL(free(RANY(obj)->as.array.ptr)); } break; case T_HASH: if (RANY(obj)->as.hash.tbl) { st_free_table(RANY(obj)->as.hash.tbl); } break; case T_REGEXP: if (RANY(obj)->as.regexp.ptr) { re_free_pattern(RANY(obj)->as.regexp.ptr); } if (RANY(obj)->as.regexp.str) { RUBY_CRITICAL(free(RANY(obj)->as.regexp.str)); } break; case T_DATA: if (DATA_PTR(obj)) { if ((long)RANY(obj)->as.data.dfree == -1) { RUBY_CRITICAL(free(DATA_PTR(obj))); } else if (RANY(obj)->as.data.dfree) { make_deferred(RANY(obj)); return 1; } } break; case T_MATCH: if (RANY(obj)->as.match.regs) { re_free_registers(RANY(obj)->as.match.regs); RUBY_CRITICAL(free(RANY(obj)->as.match.regs)); } break; case T_FILE: if (RANY(obj)->as.file.fptr) { struct rb_io_t *fptr = RANY(obj)->as.file.fptr; make_deferred(RANY(obj)); RDATA(obj)->dfree = (void (*)(void*))rb_io_fptr_finalize; RDATA(obj)->data = fptr; return 1; } break; case T_ICLASS: /* iClass shares table with the module */ break; case T_FLOAT: case T_VARMAP: case T_BLKTAG: break; case T_BIGNUM: if (RANY(obj)->as.bignum.digits) { RUBY_CRITICAL(free(RANY(obj)->as.bignum.digits)); } break; case T_NODE: switch (nd_type(obj)) { case NODE_SCOPE: if (RANY(obj)->as.node.u1.tbl) { RUBY_CRITICAL(free(RANY(obj)->as.node.u1.tbl)); } break; case NODE_ALLOCA: RUBY_CRITICAL(free(RANY(obj)->as.node.u1.node)); break; } break; /* no need to free iv_tbl */ case T_SCOPE: if (RANY(obj)->as.scope.local_vars && RANY(obj)->as.scope.flags != SCOPE_ALLOCA) { VALUE *vars = RANY(obj)->as.scope.local_vars-1; if (!(RANY(obj)->as.scope.flags & SCOPE_CLONE) && vars[0] == 0) RUBY_CRITICAL(free(RANY(obj)->as.scope.local_tbl)); if ((RANY(obj)->as.scope.flags & (SCOPE_MALLOC|SCOPE_CLONE)) == SCOPE_MALLOC) RUBY_CRITICAL(free(vars)); } break; case T_STRUCT: if (RANY(obj)->as.rstruct.ptr) { RUBY_CRITICAL(free(RANY(obj)->as.rstruct.ptr)); } break; default: rb_bug("gc_sweep(): unknown data type 0x%lx(0x%lx)", RANY(obj)->as.basic.flags & T_MASK, obj); } #endif rb_gc_force_recycle(obj); return destruct_value; }