00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <ruby/ruby.h>
00027 #include <ruby/st.h>
00028 #include <ruby/io.h>
00029 #include <ruby/re.h>
00030 #include "node.h"
00031 #include "gc.h"
00032 #include "regint.h"
00033 #include "internal.h"
00034
00035 size_t rb_str_memsize(VALUE);
00036 size_t rb_ary_memsize(VALUE);
00037 size_t rb_io_memsize(const rb_io_t *);
00038 size_t rb_generic_ivar_memsize(VALUE);
00039 size_t rb_objspace_data_type_memsize(VALUE obj);
00040
00041 static size_t
00042 memsize_of(VALUE obj)
00043 {
00044 size_t size = 0;
00045
00046 if (SPECIAL_CONST_P(obj)) {
00047 return 0;
00048 }
00049
00050 if (FL_TEST(obj, FL_EXIVAR)) {
00051 size += rb_generic_ivar_memsize(obj);
00052 }
00053
00054 switch (BUILTIN_TYPE(obj)) {
00055 case T_OBJECT:
00056 if (!(RBASIC(obj)->flags & ROBJECT_EMBED) &&
00057 ROBJECT(obj)->as.heap.ivptr) {
00058 size += ROBJECT(obj)->as.heap.numiv * sizeof(VALUE);
00059 }
00060 break;
00061 case T_MODULE:
00062 case T_CLASS:
00063 if (RCLASS_M_TBL(obj)) {
00064 size += st_memsize(RCLASS_M_TBL(obj));
00065 }
00066 if (RCLASS_IV_TBL(obj)) {
00067 size += st_memsize(RCLASS_IV_TBL(obj));
00068 }
00069 if (RCLASS_IV_INDEX_TBL(obj)) {
00070 size += st_memsize(RCLASS_IV_INDEX_TBL(obj));
00071 }
00072 if (RCLASS(obj)->ptr->iv_tbl) {
00073 size += st_memsize(RCLASS(obj)->ptr->iv_tbl);
00074 }
00075 if (RCLASS(obj)->ptr->const_tbl) {
00076 size += st_memsize(RCLASS(obj)->ptr->const_tbl);
00077 }
00078 size += sizeof(rb_classext_t);
00079 break;
00080 case T_STRING:
00081 size += rb_str_memsize(obj);
00082 break;
00083 case T_ARRAY:
00084 size += rb_ary_memsize(obj);
00085 break;
00086 case T_HASH:
00087 if (RHASH(obj)->ntbl) {
00088 size += st_memsize(RHASH(obj)->ntbl);
00089 }
00090 break;
00091 case T_REGEXP:
00092 if (RREGEXP(obj)->ptr) {
00093 size += onig_memsize(RREGEXP(obj)->ptr);
00094 }
00095 break;
00096 case T_DATA:
00097 size += rb_objspace_data_type_memsize(obj);
00098 break;
00099 case T_MATCH:
00100 if (RMATCH(obj)->rmatch) {
00101 struct rmatch *rm = RMATCH(obj)->rmatch;
00102 size += onig_region_memsize(&rm->regs);
00103 size += sizeof(struct rmatch_offset) * rm->char_offset_num_allocated;
00104 size += sizeof(struct rmatch);
00105 }
00106 break;
00107 case T_FILE:
00108 if (RFILE(obj)->fptr) {
00109 size += rb_io_memsize(RFILE(obj)->fptr);
00110 }
00111 break;
00112 case T_RATIONAL:
00113 case T_COMPLEX:
00114 break;
00115 case T_ICLASS:
00116
00117 break;
00118
00119 case T_FLOAT:
00120 break;
00121
00122 case T_BIGNUM:
00123 if (!(RBASIC(obj)->flags & RBIGNUM_EMBED_FLAG) && RBIGNUM_DIGITS(obj)) {
00124 size += RBIGNUM_LEN(obj) * sizeof(BDIGIT);
00125 }
00126 break;
00127 case T_NODE:
00128 switch (nd_type(obj)) {
00129 case NODE_SCOPE:
00130 if (RNODE(obj)->u1.tbl) {
00131
00132 }
00133 break;
00134 case NODE_ALLOCA:
00135
00136 ;
00137 }
00138 break;
00139
00140 case T_STRUCT:
00141 if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 &&
00142 RSTRUCT(obj)->as.heap.ptr) {
00143 size += sizeof(VALUE) * RSTRUCT_LEN(obj);
00144 }
00145 break;
00146
00147 case T_ZOMBIE:
00148 break;
00149
00150 default:
00151 rb_bug("objspace/memsize_of(): unknown data type 0x%x(%p)",
00152 BUILTIN_TYPE(obj), (void*)obj);
00153 }
00154
00155 return size;
00156 }
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171 static VALUE
00172 memsize_of_m(VALUE self, VALUE obj)
00173 {
00174 return SIZET2NUM(memsize_of(obj));
00175 }
00176
00177 struct total_data {
00178 size_t total;
00179 VALUE klass;
00180 };
00181
00182 static int
00183 total_i(void *vstart, void *vend, size_t stride, void *ptr)
00184 {
00185 VALUE v;
00186 struct total_data *data = (struct total_data *)ptr;
00187
00188 for (v = (VALUE)vstart; v != (VALUE)vend; v += stride) {
00189 if (RBASIC(v)->flags) {
00190 switch (BUILTIN_TYPE(v)) {
00191 case T_NONE:
00192 case T_ICLASS:
00193 case T_NODE:
00194 case T_ZOMBIE:
00195 continue;
00196 case T_CLASS:
00197 if (FL_TEST(v, FL_SINGLETON))
00198 continue;
00199 default:
00200 if (data->klass == 0 || rb_obj_is_kind_of(v, data->klass)) {
00201 data->total += memsize_of(v);
00202 }
00203 }
00204 }
00205 }
00206
00207 return 0;
00208 }
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237 static VALUE
00238 memsize_of_all_m(int argc, VALUE *argv, VALUE self)
00239 {
00240 struct total_data data = {0, 0};
00241
00242 if (argc > 0) {
00243 rb_scan_args(argc, argv, "01", &data.klass);
00244 }
00245
00246 rb_objspace_each_objects(total_i, &data);
00247 return SIZET2NUM(data.total);
00248 }
00249
00250 static int
00251 set_zero_i(st_data_t key, st_data_t val, st_data_t arg)
00252 {
00253 VALUE k = (VALUE)key;
00254 VALUE hash = (VALUE)arg;
00255 rb_hash_aset(hash, k, INT2FIX(0));
00256 return ST_CONTINUE;
00257 }
00258
00259 static int
00260 cos_i(void *vstart, void *vend, size_t stride, void *data)
00261 {
00262 size_t *counts = (size_t *)data;
00263 VALUE v = (VALUE)vstart;
00264
00265 for (;v != (VALUE)vend; v += stride) {
00266 if (RBASIC(v)->flags) {
00267 counts[BUILTIN_TYPE(v)] += memsize_of(v);
00268 }
00269 }
00270 return 0;
00271 }
00272
00273 static VALUE
00274 type2sym(enum ruby_value_type i)
00275 {
00276 VALUE type;
00277 switch (i) {
00278 #define CASE_TYPE(t) case t: type = ID2SYM(rb_intern(#t)); break;
00279 CASE_TYPE(T_NONE);
00280 CASE_TYPE(T_OBJECT);
00281 CASE_TYPE(T_CLASS);
00282 CASE_TYPE(T_MODULE);
00283 CASE_TYPE(T_FLOAT);
00284 CASE_TYPE(T_STRING);
00285 CASE_TYPE(T_REGEXP);
00286 CASE_TYPE(T_ARRAY);
00287 CASE_TYPE(T_HASH);
00288 CASE_TYPE(T_STRUCT);
00289 CASE_TYPE(T_BIGNUM);
00290 CASE_TYPE(T_FILE);
00291 CASE_TYPE(T_DATA);
00292 CASE_TYPE(T_MATCH);
00293 CASE_TYPE(T_COMPLEX);
00294 CASE_TYPE(T_RATIONAL);
00295 CASE_TYPE(T_NIL);
00296 CASE_TYPE(T_TRUE);
00297 CASE_TYPE(T_FALSE);
00298 CASE_TYPE(T_SYMBOL);
00299 CASE_TYPE(T_FIXNUM);
00300 CASE_TYPE(T_UNDEF);
00301 CASE_TYPE(T_NODE);
00302 CASE_TYPE(T_ICLASS);
00303 CASE_TYPE(T_ZOMBIE);
00304 #undef CASE_TYPE
00305 default: rb_bug("type2sym: unknown type (%d)", i);
00306 }
00307 return type;
00308 }
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333 static VALUE
00334 count_objects_size(int argc, VALUE *argv, VALUE os)
00335 {
00336 size_t counts[T_MASK+1];
00337 size_t total = 0;
00338 enum ruby_value_type i;
00339 VALUE hash;
00340
00341 if (rb_scan_args(argc, argv, "01", &hash) == 1) {
00342 if (!RB_TYPE_P(hash, T_HASH))
00343 rb_raise(rb_eTypeError, "non-hash given");
00344 }
00345
00346 for (i = 0; i <= T_MASK; i++) {
00347 counts[i] = 0;
00348 }
00349
00350 rb_objspace_each_objects(cos_i, &counts[0]);
00351
00352 if (hash == Qnil) {
00353 hash = rb_hash_new();
00354 }
00355 else if (!RHASH_EMPTY_P(hash)) {
00356 st_foreach(RHASH_TBL(hash), set_zero_i, hash);
00357 }
00358
00359 for (i = 0; i <= T_MASK; i++) {
00360 if (counts[i]) {
00361 VALUE type = type2sym(i);
00362 total += counts[i];
00363 rb_hash_aset(hash, type, SIZET2NUM(counts[i]));
00364 }
00365 }
00366 rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total));
00367 return hash;
00368 }
00369
00370 static int
00371 cn_i(void *vstart, void *vend, size_t stride, void *n)
00372 {
00373 size_t *nodes = (size_t *)n;
00374 VALUE v = (VALUE)vstart;
00375
00376 for (; v != (VALUE)vend; v += stride) {
00377 if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_NODE) {
00378 size_t s = nd_type((NODE *)v);
00379 nodes[s]++;
00380 }
00381 }
00382
00383 return 0;
00384 }
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408 static VALUE
00409 count_nodes(int argc, VALUE *argv, VALUE os)
00410 {
00411 size_t nodes[NODE_LAST+1];
00412 size_t i;
00413 VALUE hash;
00414
00415 if (rb_scan_args(argc, argv, "01", &hash) == 1) {
00416 if (!RB_TYPE_P(hash, T_HASH))
00417 rb_raise(rb_eTypeError, "non-hash given");
00418 }
00419
00420 for (i = 0; i <= NODE_LAST; i++) {
00421 nodes[i] = 0;
00422 }
00423
00424 rb_objspace_each_objects(cn_i, &nodes[0]);
00425
00426 if (hash == Qnil) {
00427 hash = rb_hash_new();
00428 }
00429 else if (!RHASH_EMPTY_P(hash)) {
00430 st_foreach(RHASH_TBL(hash), set_zero_i, hash);
00431 }
00432
00433 for (i=0; i<NODE_LAST; i++) {
00434 if (nodes[i] != 0) {
00435 VALUE node;
00436 switch (i) {
00437 #define COUNT_NODE(n) case n: node = ID2SYM(rb_intern(#n)); break;
00438 COUNT_NODE(NODE_SCOPE);
00439 COUNT_NODE(NODE_BLOCK);
00440 COUNT_NODE(NODE_IF);
00441 COUNT_NODE(NODE_CASE);
00442 COUNT_NODE(NODE_WHEN);
00443 COUNT_NODE(NODE_OPT_N);
00444 COUNT_NODE(NODE_WHILE);
00445 COUNT_NODE(NODE_UNTIL);
00446 COUNT_NODE(NODE_ITER);
00447 COUNT_NODE(NODE_FOR);
00448 COUNT_NODE(NODE_BREAK);
00449 COUNT_NODE(NODE_NEXT);
00450 COUNT_NODE(NODE_REDO);
00451 COUNT_NODE(NODE_RETRY);
00452 COUNT_NODE(NODE_BEGIN);
00453 COUNT_NODE(NODE_RESCUE);
00454 COUNT_NODE(NODE_RESBODY);
00455 COUNT_NODE(NODE_ENSURE);
00456 COUNT_NODE(NODE_AND);
00457 COUNT_NODE(NODE_OR);
00458 COUNT_NODE(NODE_MASGN);
00459 COUNT_NODE(NODE_LASGN);
00460 COUNT_NODE(NODE_DASGN);
00461 COUNT_NODE(NODE_DASGN_CURR);
00462 COUNT_NODE(NODE_GASGN);
00463 COUNT_NODE(NODE_IASGN);
00464 COUNT_NODE(NODE_IASGN2);
00465 COUNT_NODE(NODE_CDECL);
00466 COUNT_NODE(NODE_CVASGN);
00467 COUNT_NODE(NODE_CVDECL);
00468 COUNT_NODE(NODE_OP_ASGN1);
00469 COUNT_NODE(NODE_OP_ASGN2);
00470 COUNT_NODE(NODE_OP_ASGN_AND);
00471 COUNT_NODE(NODE_OP_ASGN_OR);
00472 COUNT_NODE(NODE_OP_CDECL);
00473 COUNT_NODE(NODE_CALL);
00474 COUNT_NODE(NODE_FCALL);
00475 COUNT_NODE(NODE_VCALL);
00476 COUNT_NODE(NODE_SUPER);
00477 COUNT_NODE(NODE_ZSUPER);
00478 COUNT_NODE(NODE_ARRAY);
00479 COUNT_NODE(NODE_ZARRAY);
00480 COUNT_NODE(NODE_VALUES);
00481 COUNT_NODE(NODE_HASH);
00482 COUNT_NODE(NODE_RETURN);
00483 COUNT_NODE(NODE_YIELD);
00484 COUNT_NODE(NODE_LVAR);
00485 COUNT_NODE(NODE_DVAR);
00486 COUNT_NODE(NODE_GVAR);
00487 COUNT_NODE(NODE_IVAR);
00488 COUNT_NODE(NODE_CONST);
00489 COUNT_NODE(NODE_CVAR);
00490 COUNT_NODE(NODE_NTH_REF);
00491 COUNT_NODE(NODE_BACK_REF);
00492 COUNT_NODE(NODE_MATCH);
00493 COUNT_NODE(NODE_MATCH2);
00494 COUNT_NODE(NODE_MATCH3);
00495 COUNT_NODE(NODE_LIT);
00496 COUNT_NODE(NODE_STR);
00497 COUNT_NODE(NODE_DSTR);
00498 COUNT_NODE(NODE_XSTR);
00499 COUNT_NODE(NODE_DXSTR);
00500 COUNT_NODE(NODE_EVSTR);
00501 COUNT_NODE(NODE_DREGX);
00502 COUNT_NODE(NODE_DREGX_ONCE);
00503 COUNT_NODE(NODE_ARGS);
00504 COUNT_NODE(NODE_ARGS_AUX);
00505 COUNT_NODE(NODE_OPT_ARG);
00506 COUNT_NODE(NODE_KW_ARG);
00507 COUNT_NODE(NODE_POSTARG);
00508 COUNT_NODE(NODE_ARGSCAT);
00509 COUNT_NODE(NODE_ARGSPUSH);
00510 COUNT_NODE(NODE_SPLAT);
00511 COUNT_NODE(NODE_TO_ARY);
00512 COUNT_NODE(NODE_BLOCK_ARG);
00513 COUNT_NODE(NODE_BLOCK_PASS);
00514 COUNT_NODE(NODE_DEFN);
00515 COUNT_NODE(NODE_DEFS);
00516 COUNT_NODE(NODE_ALIAS);
00517 COUNT_NODE(NODE_VALIAS);
00518 COUNT_NODE(NODE_UNDEF);
00519 COUNT_NODE(NODE_CLASS);
00520 COUNT_NODE(NODE_MODULE);
00521 COUNT_NODE(NODE_SCLASS);
00522 COUNT_NODE(NODE_COLON2);
00523 COUNT_NODE(NODE_COLON3);
00524 COUNT_NODE(NODE_CREF);
00525 COUNT_NODE(NODE_DOT2);
00526 COUNT_NODE(NODE_DOT3);
00527 COUNT_NODE(NODE_FLIP2);
00528 COUNT_NODE(NODE_FLIP3);
00529 COUNT_NODE(NODE_SELF);
00530 COUNT_NODE(NODE_NIL);
00531 COUNT_NODE(NODE_TRUE);
00532 COUNT_NODE(NODE_FALSE);
00533 COUNT_NODE(NODE_ERRINFO);
00534 COUNT_NODE(NODE_DEFINED);
00535 COUNT_NODE(NODE_POSTEXE);
00536 COUNT_NODE(NODE_ALLOCA);
00537 COUNT_NODE(NODE_BMETHOD);
00538 COUNT_NODE(NODE_MEMO);
00539 COUNT_NODE(NODE_IFUNC);
00540 COUNT_NODE(NODE_DSYM);
00541 COUNT_NODE(NODE_ATTRASGN);
00542 COUNT_NODE(NODE_PRELUDE);
00543 COUNT_NODE(NODE_LAMBDA);
00544 #undef COUNT_NODE
00545 default: node = INT2FIX(i);
00546 }
00547 rb_hash_aset(hash, node, SIZET2NUM(nodes[i]));
00548 }
00549 }
00550 return hash;
00551 }
00552
00553 static int
00554 cto_i(void *vstart, void *vend, size_t stride, void *data)
00555 {
00556 VALUE hash = (VALUE)data;
00557 VALUE v = (VALUE)vstart;
00558
00559 for (; v != (VALUE)vend; v += stride) {
00560 if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_DATA) {
00561 VALUE counter;
00562 VALUE key = RBASIC(v)->klass;
00563
00564 if (key == 0) {
00565 const char *name = rb_objspace_data_type_name(v);
00566 if (name == 0) name = "unknown";
00567 key = ID2SYM(rb_intern(name));
00568 }
00569
00570 counter = rb_hash_aref(hash, key);
00571 if (NIL_P(counter)) {
00572 counter = INT2FIX(1);
00573 }
00574 else {
00575 counter = INT2FIX(FIX2INT(counter) + 1);
00576 }
00577
00578 rb_hash_aset(hash, key, counter);
00579 }
00580 }
00581
00582 return 0;
00583 }
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617 static VALUE
00618 count_tdata_objects(int argc, VALUE *argv, VALUE self)
00619 {
00620 VALUE hash;
00621
00622 if (rb_scan_args(argc, argv, "01", &hash) == 1) {
00623 if (!RB_TYPE_P(hash, T_HASH))
00624 rb_raise(rb_eTypeError, "non-hash given");
00625 }
00626
00627 if (hash == Qnil) {
00628 hash = rb_hash_new();
00629 }
00630 else if (!RHASH_EMPTY_P(hash)) {
00631 st_foreach(RHASH_TBL(hash), set_zero_i, hash);
00632 }
00633
00634 rb_objspace_each_objects(cto_i, (void *)hash);
00635
00636 return hash;
00637 }
00638
00639 static void
00640 iow_mark(void *ptr)
00641 {
00642 rb_gc_mark((VALUE)ptr);
00643 }
00644
00645 static size_t
00646 iow_size(const void *ptr)
00647 {
00648 VALUE obj = (VALUE)ptr;
00649 return memsize_of(obj);
00650 }
00651
00652 static const rb_data_type_t iow_data_type = {
00653 "ObjectSpace::InternalObjectWrapper",
00654 {iow_mark, 0, iow_size,},
00655 };
00656
00657 static VALUE rb_mInternalObjectWrapper;
00658
00659 static VALUE
00660 iow_newobj(VALUE obj)
00661 {
00662 return rb_data_typed_object_alloc(rb_mInternalObjectWrapper, (void *)obj, &iow_data_type);
00663 }
00664
00665 static VALUE
00666 iow_type(VALUE self)
00667 {
00668 VALUE obj = (VALUE)DATA_PTR(self);
00669 return type2sym(BUILTIN_TYPE(obj));
00670 }
00671
00672 static VALUE
00673 iow_inspect(VALUE self)
00674 {
00675 VALUE obj = (VALUE)DATA_PTR(self);
00676 VALUE type = type2sym(BUILTIN_TYPE(obj));
00677
00678 return rb_sprintf("#<InternalObject:%p %s>", (void *)obj, rb_id2name(SYM2ID(type)));
00679 }
00680
00681 static VALUE
00682 iow_internal_object_id(VALUE self)
00683 {
00684 VALUE obj = (VALUE)DATA_PTR(self);
00685 return rb_obj_id(obj);
00686 }
00687
00688 struct rof_data {
00689 st_table *refs;
00690 VALUE internals;
00691 };
00692
00693 static void
00694 reachable_object_from_i(VALUE obj, void *data_ptr)
00695 {
00696 struct rof_data *data = (struct rof_data *)data_ptr;
00697 VALUE key = obj;
00698 VALUE val = obj;
00699
00700 if (rb_objspace_markable_object_p(obj)) {
00701 if (rb_objspace_internal_object_p(obj)) {
00702 val = iow_newobj(obj);
00703 rb_ary_push(data->internals, val);
00704 }
00705 st_insert(data->refs, key, val);
00706 }
00707 }
00708
00709 static int
00710 collect_values(st_data_t key, st_data_t value, st_data_t data)
00711 {
00712 VALUE ary = (VALUE)data;
00713 rb_ary_push(ary, (VALUE)value);
00714 return ST_CONTINUE;
00715 }
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758 static VALUE
00759 reachable_objects_from(VALUE self, VALUE obj)
00760 {
00761 if (rb_objspace_markable_object_p(obj)) {
00762 VALUE ret = rb_ary_new();
00763 struct rof_data data;
00764
00765 if (rb_typeddata_is_kind_of(obj, &iow_data_type)) {
00766 obj = (VALUE)DATA_PTR(obj);
00767 }
00768
00769 data.refs = st_init_numtable();
00770 data.internals = rb_ary_new();
00771
00772 rb_objspace_reachable_objects_from(obj, reachable_object_from_i, &data);
00773
00774 st_foreach(data.refs, collect_values, (st_data_t)ret);
00775 return ret;
00776 }
00777 else {
00778 return Qnil;
00779 }
00780 }
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792 void
00793 Init_objspace(void)
00794 {
00795 VALUE rb_mObjSpace = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
00796
00797 rb_define_module_function(rb_mObjSpace, "memsize_of", memsize_of_m, 1);
00798 rb_define_module_function(rb_mObjSpace, "memsize_of_all", memsize_of_all_m, -1);
00799
00800 rb_define_module_function(rb_mObjSpace, "count_objects_size", count_objects_size, -1);
00801 rb_define_module_function(rb_mObjSpace, "count_nodes", count_nodes, -1);
00802 rb_define_module_function(rb_mObjSpace, "count_tdata_objects", count_tdata_objects, -1);
00803
00804 rb_define_module_function(rb_mObjSpace, "reachable_objects_from", reachable_objects_from, 1);
00805
00806 rb_mInternalObjectWrapper = rb_define_class_under(rb_mObjSpace, "InternalObjectWrapper", rb_cObject);
00807 rb_define_method(rb_mInternalObjectWrapper, "type", iow_type, 0);
00808 rb_define_method(rb_mInternalObjectWrapper, "inspect", iow_inspect, 0);
00809 rb_define_method(rb_mInternalObjectWrapper, "internal_object_id", iow_internal_object_id, 0);
00810 }
00811