static VALUE bigmul_low_digits(VALUE x, VALUE y, int digits) { int xn = RBIGNUM_LEN(x); if (FIXNUM_P(y)) y = INTVALUE2BIG(y); int yn = RBIGNUM_LEN(y); if (digits > xn + yn) { digits = xn + yn; } VALUE z = rb_big_new(digits, 1); BDIGIT* xds = RBIGNUM_DIGITS(x); BDIGIT* yds = RBIGNUM_DIGITS(y); BDIGIT* zds = RBIGNUM_DIGITS(z); BDIGIT c0,c1,c2; // carry int i, j, k, beg, end; for (k = c0 = c1 = c2 = 0; k < digits; k++) { beg = k >= yn - 1 ? k - yn + 1 : 0; end = k >= xn ? xn - 1 : k; for (i = beg, j = k - beg; i <= end; ++i, --j) MULADD(xds[i], yds[j]); zds[k] = c0; c0 = c1; c1 = c2; c2 = 0; } return rb_big_norm(z); }
unsigned long rb_hash_code(VALUE obj) { switch (TYPE(obj)) { case T_FIXNUM: case T_FLOAT: case T_SYMBOL: case T_NIL: case T_FALSE: case T_TRUE: return (unsigned long)obj; case T_STRING: return rb_str_hash(obj); case T_ARRAY: return rb_ary_hash(obj); } VALUE v = rb_vm_call(obj, selHash, 0, NULL); retry: switch (TYPE(v)) { case T_FIXNUM: return FIX2LONG(v); case T_BIGNUM: return ((unsigned long *)(RBIGNUM_DIGITS(v)))[0]; default: v = rb_to_int(v); goto retry; } }
int bignum_to_int64(VALUE value, sqlite3_int64 *result) { #ifdef HAVE_RB_INTEGER_PACK const int nails = 0; int t = rb_integer_pack(value, result, 1, sizeof(*result), nails, INTEGER_PACK_NATIVE_BYTE_ORDER| INTEGER_PACK_2COMP); switch (t) { case -2: case +2: return 0; case +1: if (!nails) { if (*result < 0) return 0; } break; case -1: if (!nails) { if (*result >= 0) return 0; } else { *result += INT64_MIN; } break; } return 1; #else # ifndef RBIGNUM_LEN # define RBIGNUM_LEN(x) RBIGNUM(x)->len # endif const long len = RBIGNUM_LEN(value); if (len == 0) { *result = 0; return 1; } if (len > 63 / (SIZEOF_BDIGITS * CHAR_BIT) + 1) return 0; if (len == 63 / (SIZEOF_BDIGITS * CHAR_BIT) + 1) { const BDIGIT *digits = RBIGNUM_DIGITS(value); BDIGIT blast = digits[len-1]; BDIGIT bmax = (BDIGIT)1UL << (63 % (CHAR_BIT * SIZEOF_BDIGITS)); if (blast > bmax) return 0; if (blast == bmax) { if (RBIGNUM_POSITIVE_P(value)) { return 0; } else { long i = len-1; while (i) { if (digits[--i]) return 0; } } } } *result = (sqlite3_int64)NUM2LL(value); return 1; #endif }
static VALUE bigmul_high_digits(VALUE x, VALUE y, int dontcare, int x_right_shift) { int xn = RBIGNUM_LEN(x); if (FIXNUM_P(y)) y = INTVALUE2BIG(y); int yn = RBIGNUM_LEN(y); BDIGIT* xds = RBIGNUM_DIGITS(x); BDIGIT* yds = RBIGNUM_DIGITS(y); /* in order to avoid rb_big_clone call, let's virtually "shift" x instead of actual shifting */ if (x_right_shift >= xn) { return INT2BIG(0); } else { xds += x_right_shift; xn -= x_right_shift; } int digits = xn + yn; int i, j, k; VALUE z = rb_big_new(digits, 1); BDIGIT* zds = RBIGNUM_DIGITS(z); for (i = 0; i < digits; zds[i++] = 0); int beg, end; BDIGIT c0, c1, c2; for (k = dontcare, c0 = c1 = c2 = 0; k < digits; k++) { beg = k >= yn - 1 ? k - yn + 1 : 0; end = k >= xn ? xn - 1 : k; for (i = beg, j = k - beg; i <= end; ++i, --j) MULADD(xds[i], yds[j]); zds[k] = c0; c0 = c1; c1 = c2; c2 = 0; } return z; }
inline static VALUE rshift_digits_inplace(VALUE n, int k) { if (FIXNUM_P(n)) { return INT2FIX(0); } BDIGIT* ds = RBIGNUM_DIGITS(n); int len = RBIGNUM_LEN(n); if (len > k) { memmove(ds, ds + k, SIZEOF_BDIGITS * (len - k)); RBIGNUM_SET_LEN(n, len - k); return n; } else { RBIGNUM_SET_LEN(n, 0); return n; } }
static size_t memsize_of(VALUE obj) { size_t size = 0; if (SPECIAL_CONST_P(obj)) { return 0; } if (FL_TEST(obj, FL_EXIVAR)) { size += rb_generic_ivar_memsize(obj); } switch (BUILTIN_TYPE(obj)) { case T_OBJECT: if (!(RBASIC(obj)->flags & ROBJECT_EMBED) && ROBJECT(obj)->as.heap.ivptr) { size += ROBJECT(obj)->as.heap.numiv * sizeof(VALUE); } break; case T_MODULE: case T_CLASS: size += st_memsize(RCLASS_M_TBL(obj)); if (RCLASS_IV_TBL(obj)) { size += st_memsize(RCLASS_IV_TBL(obj)); } if (RCLASS_IV_INDEX_TBL(obj)) { size += st_memsize(RCLASS_IV_INDEX_TBL(obj)); } if (RCLASS(obj)->ptr->iv_tbl) { size += st_memsize(RCLASS(obj)->ptr->iv_tbl); } if (RCLASS(obj)->ptr->const_tbl) { size += st_memsize(RCLASS(obj)->ptr->const_tbl); } size += sizeof(rb_classext_t); break; case T_STRING: size += rb_str_memsize(obj); break; case T_ARRAY: size += rb_ary_memsize(obj); break; case T_HASH: if (RHASH(obj)->ntbl) { size += st_memsize(RHASH(obj)->ntbl); } break; case T_REGEXP: if (RREGEXP(obj)->ptr) { size += onig_memsize(RREGEXP(obj)->ptr); } break; case T_DATA: size += rb_objspace_data_type_memsize(obj); break; case T_MATCH: if (RMATCH(obj)->rmatch) { struct rmatch *rm = RMATCH(obj)->rmatch; size += sizeof(struct re_registers); /* TODO: onig_region_memsize(&rm->regs); */ size += sizeof(struct rmatch_offset) * rm->char_offset_num_allocated; size += sizeof(struct rmatch); } break; case T_FILE: if (RFILE(obj)->fptr) { size += rb_io_memsize(RFILE(obj)->fptr); } break; case T_RATIONAL: case T_COMPLEX: break; case T_ICLASS: /* iClass shares table with the module */ break; case T_FLOAT: break; case T_BIGNUM: if (!(RBASIC(obj)->flags & RBIGNUM_EMBED_FLAG) && RBIGNUM_DIGITS(obj)) { size += RBIGNUM_LEN(obj) * sizeof(BDIGIT); } break; case T_NODE: switch (nd_type(obj)) { case NODE_SCOPE: if (RNODE(obj)->u1.tbl) { /* TODO: xfree(RANY(obj)->as.node.u1.tbl); */ } break; case NODE_ALLOCA: /* TODO: xfree(RANY(obj)->as.node.u1.node); */ ; } break; /* no need to free iv_tbl */ case T_STRUCT: if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 && RSTRUCT(obj)->as.heap.ptr) { size += sizeof(VALUE) * RSTRUCT_LEN(obj); } break; case T_ZOMBIE: break; default: rb_bug("objspace/memsize_of(): unknown data type 0x%x(%p)", BUILTIN_TYPE(obj), (void*)obj); } return size; }
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; }