mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Add GC.compact
again.
🙏
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67620 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
e3d547f6df
commit
91793b8967
29 changed files with 1730 additions and 109 deletions
9
NEWS
9
NEWS
|
@ -122,6 +122,15 @@ JIT::
|
||||||
|
|
||||||
* Default value of +--jit-min-calls+ is changed from 5 to 10,000
|
* Default value of +--jit-min-calls+ is changed from 5 to 10,000
|
||||||
|
|
||||||
|
GC::
|
||||||
|
|
||||||
|
* New `GC.compact` method for compacting the heap.
|
||||||
|
This function compacts live objects in the heap so that fewer pages may
|
||||||
|
be used, and the heap may be more CoW friendly. [Feature #15626]
|
||||||
|
|
||||||
|
Details on the algorithm and caveats can be found here:
|
||||||
|
https://bugs.ruby-lang.org/issues/15626
|
||||||
|
|
||||||
=== Miscellaneous changes
|
=== Miscellaneous changes
|
||||||
|
|
||||||
* Require compilers to support C99 [Misc #15347]
|
* Require compilers to support C99 [Misc #15347]
|
||||||
|
|
8
class.c
8
class.c
|
@ -539,6 +539,7 @@ boot_defclass(const char *name, VALUE super)
|
||||||
|
|
||||||
rb_name_class(obj, id);
|
rb_name_class(obj, id);
|
||||||
rb_const_set((rb_cObject ? rb_cObject : obj), id, obj);
|
rb_const_set((rb_cObject ? rb_cObject : obj), id, obj);
|
||||||
|
rb_vm_add_root_module(id, obj);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -730,6 +731,9 @@ rb_define_class_id_under(VALUE outer, ID id, VALUE super)
|
||||||
" (%"PRIsVALUE" is given but was %"PRIsVALUE")",
|
" (%"PRIsVALUE" is given but was %"PRIsVALUE")",
|
||||||
outer, rb_id2str(id), RCLASS_SUPER(klass), super);
|
outer, rb_id2str(id), RCLASS_SUPER(klass), super);
|
||||||
}
|
}
|
||||||
|
/* Class may have been defined in Ruby and not pin-rooted */
|
||||||
|
rb_vm_add_root_module(id, klass);
|
||||||
|
|
||||||
return klass;
|
return klass;
|
||||||
}
|
}
|
||||||
if (!super) {
|
if (!super) {
|
||||||
|
@ -740,6 +744,7 @@ rb_define_class_id_under(VALUE outer, ID id, VALUE super)
|
||||||
rb_set_class_path_string(klass, outer, rb_id2str(id));
|
rb_set_class_path_string(klass, outer, rb_id2str(id));
|
||||||
rb_const_set(outer, id, klass);
|
rb_const_set(outer, id, klass);
|
||||||
rb_class_inherited(super, klass);
|
rb_class_inherited(super, klass);
|
||||||
|
rb_vm_add_root_module(id, klass);
|
||||||
rb_gc_register_mark_object(klass);
|
rb_gc_register_mark_object(klass);
|
||||||
|
|
||||||
return klass;
|
return klass;
|
||||||
|
@ -777,10 +782,13 @@ rb_define_module(const char *name)
|
||||||
rb_raise(rb_eTypeError, "%s is not a module (%"PRIsVALUE")",
|
rb_raise(rb_eTypeError, "%s is not a module (%"PRIsVALUE")",
|
||||||
name, rb_obj_class(module));
|
name, rb_obj_class(module));
|
||||||
}
|
}
|
||||||
|
/* Module may have been defined in Ruby and not pin-rooted */
|
||||||
|
rb_vm_add_root_module(id, module);
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
module = rb_define_module_id(id);
|
module = rb_define_module_id(id);
|
||||||
rb_vm_add_root_module(id, module);
|
rb_vm_add_root_module(id, module);
|
||||||
|
rb_gc_register_mark_object(module);
|
||||||
rb_const_set(rb_cObject, id, module);
|
rb_const_set(rb_cObject, id, module);
|
||||||
|
|
||||||
return module;
|
return module;
|
||||||
|
|
|
@ -31,8 +31,8 @@ typedef enum {
|
||||||
typedef struct rb_const_entry_struct {
|
typedef struct rb_const_entry_struct {
|
||||||
rb_const_flag_t flag;
|
rb_const_flag_t flag;
|
||||||
int line;
|
int line;
|
||||||
const VALUE value; /* should be mark */
|
VALUE value; /* should be mark */
|
||||||
const VALUE file; /* should be mark */
|
VALUE file; /* should be mark */
|
||||||
} rb_const_entry_t;
|
} rb_const_entry_t;
|
||||||
|
|
||||||
VALUE rb_mod_private_constant(int argc, const VALUE *argv, VALUE obj);
|
VALUE rb_mod_private_constant(int argc, const VALUE *argv, VALUE obj);
|
||||||
|
|
|
@ -1344,6 +1344,8 @@ void Init_generator(void)
|
||||||
|
|
||||||
eGeneratorError = rb_path2class("JSON::GeneratorError");
|
eGeneratorError = rb_path2class("JSON::GeneratorError");
|
||||||
eNestingError = rb_path2class("JSON::NestingError");
|
eNestingError = rb_path2class("JSON::NestingError");
|
||||||
|
rb_gc_register_mark_object(eGeneratorError);
|
||||||
|
rb_gc_register_mark_object(eNestingError);
|
||||||
|
|
||||||
cState = rb_define_class_under(mGenerator, "State", rb_cObject);
|
cState = rb_define_class_under(mGenerator, "State", rb_cObject);
|
||||||
rb_define_alloc_func(cState, cState_s_allocate);
|
rb_define_alloc_func(cState, cState_s_allocate);
|
||||||
|
|
|
@ -2091,6 +2091,8 @@ void Init_parser(void)
|
||||||
cParser = rb_define_class_under(mExt, "Parser", rb_cObject);
|
cParser = rb_define_class_under(mExt, "Parser", rb_cObject);
|
||||||
eParserError = rb_path2class("JSON::ParserError");
|
eParserError = rb_path2class("JSON::ParserError");
|
||||||
eNestingError = rb_path2class("JSON::NestingError");
|
eNestingError = rb_path2class("JSON::NestingError");
|
||||||
|
rb_gc_register_mark_object(eParserError);
|
||||||
|
rb_gc_register_mark_object(eNestingError);
|
||||||
rb_define_alloc_func(cParser, cJSON_parser_s_allocate);
|
rb_define_alloc_func(cParser, cJSON_parser_s_allocate);
|
||||||
rb_define_method(cParser, "initialize", cParser_initialize, -1);
|
rb_define_method(cParser, "initialize", cParser_initialize, -1);
|
||||||
rb_define_method(cParser, "parse", cParser_parse, 0);
|
rb_define_method(cParser, "parse", cParser_parse, 0);
|
||||||
|
|
4
gc.h
4
gc.h
|
@ -57,6 +57,10 @@ rb_gc_debug_body(const char *mode, const char *msg, int st, void *ptr)
|
||||||
#define RUBY_GC_INFO if(0)printf
|
#define RUBY_GC_INFO if(0)printf
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define RUBY_MARK_NO_PIN_UNLESS_NULL(ptr) do { \
|
||||||
|
VALUE markobj = (ptr); \
|
||||||
|
if (RTEST(markobj)) {rb_gc_mark_no_pin(markobj);} \
|
||||||
|
} while (0)
|
||||||
#define RUBY_MARK_UNLESS_NULL(ptr) do { \
|
#define RUBY_MARK_UNLESS_NULL(ptr) do { \
|
||||||
VALUE markobj = (ptr); \
|
VALUE markobj = (ptr); \
|
||||||
if (RTEST(markobj)) {rb_gc_mark(markobj);} \
|
if (RTEST(markobj)) {rb_gc_mark(markobj);} \
|
||||||
|
|
40
hash.c
40
hash.c
|
@ -781,7 +781,7 @@ ar_add_direct_with_hash(VALUE hash, st_data_t key, st_data_t val, st_hash_t hash
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ar_foreach(VALUE hash, int (*func)(ANYARGS), st_data_t arg)
|
ar_general_foreach(VALUE hash, int (*func)(ANYARGS), st_update_callback_func *replace, st_data_t arg)
|
||||||
{
|
{
|
||||||
if (RHASH_AR_TABLE_SIZE(hash) > 0) {
|
if (RHASH_AR_TABLE_SIZE(hash) > 0) {
|
||||||
unsigned i, bound = RHASH_AR_TABLE_BOUND(hash);
|
unsigned i, bound = RHASH_AR_TABLE_BOUND(hash);
|
||||||
|
@ -799,6 +799,20 @@ ar_foreach(VALUE hash, int (*func)(ANYARGS), st_data_t arg)
|
||||||
case ST_CHECK:
|
case ST_CHECK:
|
||||||
case ST_STOP:
|
case ST_STOP:
|
||||||
return 0;
|
return 0;
|
||||||
|
case ST_REPLACE:
|
||||||
|
if (replace) {
|
||||||
|
VALUE key;
|
||||||
|
VALUE value;
|
||||||
|
|
||||||
|
key = cur_entry->key;
|
||||||
|
value = cur_entry->record;
|
||||||
|
retval = (*replace)(&key, &value, arg, TRUE);
|
||||||
|
|
||||||
|
ar_table_entry *entry = RHASH_AR_TABLE_REF(hash, i);
|
||||||
|
entry->key = key;
|
||||||
|
entry->record = value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case ST_DELETE:
|
case ST_DELETE:
|
||||||
ar_clear_entry(RHASH_AR_TABLE_REF(hash, i));
|
ar_clear_entry(RHASH_AR_TABLE_REF(hash, i));
|
||||||
RHASH_AR_TABLE_SIZE_DEC(hash);
|
RHASH_AR_TABLE_SIZE_DEC(hash);
|
||||||
|
@ -809,6 +823,18 @@ ar_foreach(VALUE hash, int (*func)(ANYARGS), st_data_t arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar_foreach_with_replace(VALUE hash, int (*func)(ANYARGS), st_update_callback_func *replace, st_data_t arg)
|
||||||
|
{
|
||||||
|
return ar_general_foreach(hash, func, replace, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar_foreach(VALUE hash, int (*func)(ANYARGS), st_data_t arg)
|
||||||
|
{
|
||||||
|
return ar_general_foreach(hash, func, NULL, arg);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ar_foreach_check(VALUE hash, int (*func)(ANYARGS), st_data_t arg,
|
ar_foreach_check(VALUE hash, int (*func)(ANYARGS), st_data_t arg,
|
||||||
st_data_t never)
|
st_data_t never)
|
||||||
|
@ -845,6 +871,7 @@ ar_foreach_check(VALUE hash, int (*func)(ANYARGS), st_data_t arg,
|
||||||
case ST_CONTINUE:
|
case ST_CONTINUE:
|
||||||
break;
|
break;
|
||||||
case ST_STOP:
|
case ST_STOP:
|
||||||
|
case ST_REPLACE:
|
||||||
return 0;
|
return 0;
|
||||||
case ST_DELETE: {
|
case ST_DELETE: {
|
||||||
if (!ar_empty_entry(cur_entry)) {
|
if (!ar_empty_entry(cur_entry)) {
|
||||||
|
@ -1257,6 +1284,17 @@ rb_hash_stlike_foreach(VALUE hash, int (*func)(ANYARGS), st_data_t arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rb_hash_stlike_foreach_with_replace(VALUE hash, int (*func)(ANYARGS), st_update_callback_func *replace, st_data_t arg)
|
||||||
|
{
|
||||||
|
if (RHASH_AR_TABLE_P(hash)) {
|
||||||
|
return ar_foreach_with_replace(hash, func, replace, arg);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return st_foreach_with_replace(RHASH_ST_TABLE(hash), func, replace, arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
hash_foreach_call(VALUE arg)
|
hash_foreach_call(VALUE arg)
|
||||||
{
|
{
|
||||||
|
|
22
id_table.c
22
id_table.c
|
@ -266,6 +266,28 @@ rb_id_table_delete(struct rb_id_table *tbl, ID id)
|
||||||
return hash_delete_index(tbl, index);
|
return hash_delete_index(tbl, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_id_table_foreach_with_replace(struct rb_id_table *tbl, rb_id_table_foreach_func_t *func, rb_id_table_update_callback_func_t *replace, void *data)
|
||||||
|
{
|
||||||
|
int i, capa = tbl->capa;
|
||||||
|
|
||||||
|
for (i=0; i<capa; i++) {
|
||||||
|
if (ITEM_KEY_ISSET(tbl, i)) {
|
||||||
|
const id_key_t key = ITEM_GET_KEY(tbl, i);
|
||||||
|
enum rb_id_table_iterator_result ret = (*func)(Qundef, tbl->items[i].val, data);
|
||||||
|
assert(key != 0);
|
||||||
|
|
||||||
|
if (ret == ID_TABLE_REPLACE) {
|
||||||
|
VALUE val = tbl->items[i].val;
|
||||||
|
ret = (*replace)(NULL, &val, data, TRUE);
|
||||||
|
tbl->items[i].val = val;
|
||||||
|
}
|
||||||
|
else if (ret == ID_TABLE_STOP)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rb_id_table_foreach(struct rb_id_table *tbl, rb_id_table_foreach_func_t *func, void *data)
|
rb_id_table_foreach(struct rb_id_table *tbl, rb_id_table_foreach_func_t *func, void *data)
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,6 +9,7 @@ enum rb_id_table_iterator_result {
|
||||||
ID_TABLE_CONTINUE = ST_CONTINUE,
|
ID_TABLE_CONTINUE = ST_CONTINUE,
|
||||||
ID_TABLE_STOP = ST_STOP,
|
ID_TABLE_STOP = ST_STOP,
|
||||||
ID_TABLE_DELETE = ST_DELETE,
|
ID_TABLE_DELETE = ST_DELETE,
|
||||||
|
ID_TABLE_REPLACE = ST_REPLACE,
|
||||||
ID_TABLE_ITERATOR_RESULT_END
|
ID_TABLE_ITERATOR_RESULT_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,9 +24,11 @@ int rb_id_table_insert(struct rb_id_table *tbl, ID id, VALUE val);
|
||||||
int rb_id_table_lookup(struct rb_id_table *tbl, ID id, VALUE *valp);
|
int rb_id_table_lookup(struct rb_id_table *tbl, ID id, VALUE *valp);
|
||||||
int rb_id_table_delete(struct rb_id_table *tbl, ID id);
|
int rb_id_table_delete(struct rb_id_table *tbl, ID id);
|
||||||
|
|
||||||
|
typedef enum rb_id_table_iterator_result rb_id_table_update_callback_func_t(ID *id, VALUE *val, void *data, int existing);
|
||||||
typedef enum rb_id_table_iterator_result rb_id_table_foreach_func_t(ID id, VALUE val, void *data);
|
typedef enum rb_id_table_iterator_result rb_id_table_foreach_func_t(ID id, VALUE val, void *data);
|
||||||
typedef enum rb_id_table_iterator_result rb_id_table_foreach_values_func_t(VALUE val, void *data);
|
typedef enum rb_id_table_iterator_result rb_id_table_foreach_values_func_t(VALUE val, void *data);
|
||||||
void rb_id_table_foreach(struct rb_id_table *tbl, rb_id_table_foreach_func_t *func, void *data);
|
void rb_id_table_foreach(struct rb_id_table *tbl, rb_id_table_foreach_func_t *func, void *data);
|
||||||
|
void rb_id_table_foreach_with_replace(struct rb_id_table *tbl, rb_id_table_foreach_func_t *func, rb_id_table_update_callback_func_t *replace, void *data);
|
||||||
void rb_id_table_foreach_values(struct rb_id_table *tbl, rb_id_table_foreach_values_func_t *func, void *data);
|
void rb_id_table_foreach_values(struct rb_id_table *tbl, rb_id_table_foreach_values_func_t *func, void *data);
|
||||||
|
|
||||||
#endif /* RUBY_ID_TABLE_H */
|
#endif /* RUBY_ID_TABLE_H */
|
||||||
|
|
|
@ -507,10 +507,15 @@ COLDFUNC NORETURN(void rb_memerror(void));
|
||||||
PUREFUNC(int rb_during_gc(void));
|
PUREFUNC(int rb_during_gc(void));
|
||||||
void rb_gc_mark_locations(const VALUE*, const VALUE*);
|
void rb_gc_mark_locations(const VALUE*, const VALUE*);
|
||||||
void rb_mark_tbl(struct st_table*);
|
void rb_mark_tbl(struct st_table*);
|
||||||
|
void rb_mark_tbl_no_pin(struct st_table*);
|
||||||
|
void rb_gc_update_tbl_refs(st_table *ptr);
|
||||||
void rb_mark_set(struct st_table*);
|
void rb_mark_set(struct st_table*);
|
||||||
void rb_mark_hash(struct st_table*);
|
void rb_mark_hash(struct st_table*);
|
||||||
|
void rb_update_st_references(struct st_table *ht);
|
||||||
void rb_gc_mark_maybe(VALUE);
|
void rb_gc_mark_maybe(VALUE);
|
||||||
void rb_gc_mark(VALUE);
|
void rb_gc_mark(VALUE);
|
||||||
|
void rb_gc_mark_no_pin(VALUE);
|
||||||
|
VALUE rb_gc_new_location(VALUE);
|
||||||
void rb_gc_force_recycle(VALUE);
|
void rb_gc_force_recycle(VALUE);
|
||||||
void rb_gc(void);
|
void rb_gc(void);
|
||||||
void rb_gc_copy_finalizer(VALUE,VALUE);
|
void rb_gc_copy_finalizer(VALUE,VALUE);
|
||||||
|
@ -622,6 +627,7 @@ VALUE rb_obj_trust(VALUE);
|
||||||
VALUE rb_obj_freeze(VALUE);
|
VALUE rb_obj_freeze(VALUE);
|
||||||
PUREFUNC(VALUE rb_obj_frozen_p(VALUE));
|
PUREFUNC(VALUE rb_obj_frozen_p(VALUE));
|
||||||
VALUE rb_obj_id(VALUE);
|
VALUE rb_obj_id(VALUE);
|
||||||
|
VALUE rb_memory_id(VALUE);
|
||||||
VALUE rb_obj_class(VALUE);
|
VALUE rb_obj_class(VALUE);
|
||||||
PUREFUNC(VALUE rb_class_real(VALUE));
|
PUREFUNC(VALUE rb_class_real(VALUE));
|
||||||
PUREFUNC(VALUE rb_class_inherited_p(VALUE, VALUE));
|
PUREFUNC(VALUE rb_class_inherited_p(VALUE, VALUE));
|
||||||
|
|
|
@ -512,6 +512,7 @@ enum ruby_value_type {
|
||||||
RUBY_T_NODE = 0x1b,
|
RUBY_T_NODE = 0x1b,
|
||||||
RUBY_T_ICLASS = 0x1c,
|
RUBY_T_ICLASS = 0x1c,
|
||||||
RUBY_T_ZOMBIE = 0x1d,
|
RUBY_T_ZOMBIE = 0x1d,
|
||||||
|
RUBY_T_MOVED = 0x1e,
|
||||||
|
|
||||||
RUBY_T_MASK = 0x1f
|
RUBY_T_MASK = 0x1f
|
||||||
};
|
};
|
||||||
|
@ -542,6 +543,7 @@ enum ruby_value_type {
|
||||||
#define T_UNDEF RUBY_T_UNDEF
|
#define T_UNDEF RUBY_T_UNDEF
|
||||||
#define T_NODE RUBY_T_NODE
|
#define T_NODE RUBY_T_NODE
|
||||||
#define T_ZOMBIE RUBY_T_ZOMBIE
|
#define T_ZOMBIE RUBY_T_ZOMBIE
|
||||||
|
#define T_MOVED RUBY_T_MOVED
|
||||||
#define T_MASK RUBY_T_MASK
|
#define T_MASK RUBY_T_MASK
|
||||||
|
|
||||||
#define RB_BUILTIN_TYPE(x) (int)(((struct RBasic*)(x))->flags & RUBY_T_MASK)
|
#define RB_BUILTIN_TYPE(x) (int)(((struct RBasic*)(x))->flags & RUBY_T_MASK)
|
||||||
|
@ -845,6 +847,7 @@ enum ruby_fl_type {
|
||||||
RUBY_FL_FINALIZE = (1<<7),
|
RUBY_FL_FINALIZE = (1<<7),
|
||||||
RUBY_FL_TAINT = (1<<8),
|
RUBY_FL_TAINT = (1<<8),
|
||||||
RUBY_FL_UNTRUSTED = RUBY_FL_TAINT,
|
RUBY_FL_UNTRUSTED = RUBY_FL_TAINT,
|
||||||
|
RUBY_FL_SEEN_OBJ_ID = (1<<9),
|
||||||
RUBY_FL_EXIVAR = (1<<10),
|
RUBY_FL_EXIVAR = (1<<10),
|
||||||
RUBY_FL_FREEZE = (1<<11),
|
RUBY_FL_FREEZE = (1<<11),
|
||||||
|
|
||||||
|
@ -883,7 +886,7 @@ enum ruby_fl_type {
|
||||||
|
|
||||||
struct RUBY_ALIGNAS(SIZEOF_VALUE) RBasic {
|
struct RUBY_ALIGNAS(SIZEOF_VALUE) RBasic {
|
||||||
VALUE flags;
|
VALUE flags;
|
||||||
const VALUE klass;
|
VALUE klass;
|
||||||
};
|
};
|
||||||
|
|
||||||
VALUE rb_obj_hide(VALUE obj);
|
VALUE rb_obj_hide(VALUE obj);
|
||||||
|
@ -1105,7 +1108,7 @@ struct RArray {
|
||||||
struct RRegexp {
|
struct RRegexp {
|
||||||
struct RBasic basic;
|
struct RBasic basic;
|
||||||
struct re_pattern_buffer *ptr;
|
struct re_pattern_buffer *ptr;
|
||||||
const VALUE src;
|
VALUE src;
|
||||||
unsigned long usecnt;
|
unsigned long usecnt;
|
||||||
};
|
};
|
||||||
#define RREGEXP_PTR(r) (RREGEXP(r)->ptr)
|
#define RREGEXP_PTR(r) (RREGEXP(r)->ptr)
|
||||||
|
@ -1144,7 +1147,8 @@ struct rb_data_type_struct {
|
||||||
void (*dmark)(void*);
|
void (*dmark)(void*);
|
||||||
void (*dfree)(void*);
|
void (*dfree)(void*);
|
||||||
size_t (*dsize)(const void *);
|
size_t (*dsize)(const void *);
|
||||||
void *reserved[2]; /* For future extension.
|
void (*dcompact)(void*);
|
||||||
|
void *reserved[1]; /* For future extension.
|
||||||
This array *must* be filled with ZERO. */
|
This array *must* be filled with ZERO. */
|
||||||
} function;
|
} function;
|
||||||
const rb_data_type_t *parent;
|
const rb_data_type_t *parent;
|
||||||
|
@ -1255,6 +1259,7 @@ int rb_big_sign(VALUE);
|
||||||
#define RBIGNUM_NEGATIVE_P(b) (RBIGNUM_SIGN(b)==0)
|
#define RBIGNUM_NEGATIVE_P(b) (RBIGNUM_SIGN(b)==0)
|
||||||
|
|
||||||
#define R_CAST(st) (struct st*)
|
#define R_CAST(st) (struct st*)
|
||||||
|
#define RMOVED(obj) (R_CAST(RMoved)(obj))
|
||||||
#define RBASIC(obj) (R_CAST(RBasic)(obj))
|
#define RBASIC(obj) (R_CAST(RBasic)(obj))
|
||||||
#define ROBJECT(obj) (R_CAST(RObject)(obj))
|
#define ROBJECT(obj) (R_CAST(RObject)(obj))
|
||||||
#define RCLASS(obj) (R_CAST(RClass)(obj))
|
#define RCLASS(obj) (R_CAST(RClass)(obj))
|
||||||
|
@ -1273,6 +1278,7 @@ int rb_big_sign(VALUE);
|
||||||
#define FL_FINALIZE ((VALUE)RUBY_FL_FINALIZE)
|
#define FL_FINALIZE ((VALUE)RUBY_FL_FINALIZE)
|
||||||
#define FL_TAINT ((VALUE)RUBY_FL_TAINT)
|
#define FL_TAINT ((VALUE)RUBY_FL_TAINT)
|
||||||
#define FL_UNTRUSTED ((VALUE)RUBY_FL_UNTRUSTED)
|
#define FL_UNTRUSTED ((VALUE)RUBY_FL_UNTRUSTED)
|
||||||
|
#define FL_SEEN_OBJ_ID ((VALUE)RUBY_FL_SEEN_OBJ_ID)
|
||||||
#define FL_EXIVAR ((VALUE)RUBY_FL_EXIVAR)
|
#define FL_EXIVAR ((VALUE)RUBY_FL_EXIVAR)
|
||||||
#define FL_FREEZE ((VALUE)RUBY_FL_FREEZE)
|
#define FL_FREEZE ((VALUE)RUBY_FL_FREEZE)
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ struct st_table {
|
||||||
|
|
||||||
#define st_is_member(table,key) st_lookup((table),(key),(st_data_t *)0)
|
#define st_is_member(table,key) st_lookup((table),(key),(st_data_t *)0)
|
||||||
|
|
||||||
enum st_retval {ST_CONTINUE, ST_STOP, ST_DELETE, ST_CHECK};
|
enum st_retval {ST_CONTINUE, ST_STOP, ST_DELETE, ST_CHECK, ST_REPLACE};
|
||||||
|
|
||||||
st_table *st_init_table(const struct st_hash_type *);
|
st_table *st_init_table(const struct st_hash_type *);
|
||||||
st_table *st_init_table_with_size(const struct st_hash_type *, st_index_t);
|
st_table *st_init_table_with_size(const struct st_hash_type *, st_index_t);
|
||||||
|
@ -118,6 +118,7 @@ typedef int st_update_callback_func(st_data_t *key, st_data_t *value, st_data_t
|
||||||
* results of hash() are same and compare() returns 0, otherwise the
|
* results of hash() are same and compare() returns 0, otherwise the
|
||||||
* behavior is undefined */
|
* behavior is undefined */
|
||||||
int st_update(st_table *table, st_data_t key, st_update_callback_func *func, st_data_t arg);
|
int st_update(st_table *table, st_data_t key, st_update_callback_func *func, st_data_t arg);
|
||||||
|
int st_foreach_with_replace(st_table *tab, int (*func)(ANYARGS), st_update_callback_func *replace, st_data_t arg);
|
||||||
int st_foreach(st_table *, int (*)(ANYARGS), st_data_t);
|
int st_foreach(st_table *, int (*)(ANYARGS), st_data_t);
|
||||||
int st_foreach_check(st_table *, int (*)(ANYARGS), st_data_t, st_data_t);
|
int st_foreach_check(st_table *, int (*)(ANYARGS), st_data_t, st_data_t);
|
||||||
st_index_t st_keys(st_table *table, st_data_t *keys, st_index_t size);
|
st_index_t st_keys(st_table *table, st_data_t *keys, st_index_t size);
|
||||||
|
|
42
internal.h
42
internal.h
|
@ -731,8 +731,8 @@ struct RBignum {
|
||||||
|
|
||||||
struct RRational {
|
struct RRational {
|
||||||
struct RBasic basic;
|
struct RBasic basic;
|
||||||
const VALUE num;
|
VALUE num;
|
||||||
const VALUE den;
|
VALUE den;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RRATIONAL(obj) (R_CAST(RRational)(obj))
|
#define RRATIONAL(obj) (R_CAST(RRational)(obj))
|
||||||
|
@ -748,8 +748,8 @@ struct RFloat {
|
||||||
|
|
||||||
struct RComplex {
|
struct RComplex {
|
||||||
struct RBasic basic;
|
struct RBasic basic;
|
||||||
const VALUE real;
|
VALUE real;
|
||||||
const VALUE imag;
|
VALUE imag;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RCOMPLEX(obj) (R_CAST(RComplex)(obj))
|
#define RCOMPLEX(obj) (R_CAST(RComplex)(obj))
|
||||||
|
@ -816,8 +816,8 @@ struct RHash {
|
||||||
st_table *st;
|
st_table *st;
|
||||||
struct ar_table_struct *ar; /* possibly 0 */
|
struct ar_table_struct *ar; /* possibly 0 */
|
||||||
} as;
|
} as;
|
||||||
const int iter_lev;
|
int iter_lev;
|
||||||
const VALUE ifnone;
|
VALUE ifnone;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef RHASH_ITER_LEV
|
#ifdef RHASH_ITER_LEV
|
||||||
|
@ -830,6 +830,11 @@ struct RHash {
|
||||||
# define RHASH_SIZE(h) (RHASH_AR_TABLE_P(h) ? RHASH_AR_TABLE_SIZE_RAW(h) : RHASH_ST_SIZE(h))
|
# define RHASH_SIZE(h) (RHASH_AR_TABLE_P(h) ? RHASH_AR_TABLE_SIZE_RAW(h) : RHASH_ST_SIZE(h))
|
||||||
#endif /* #ifdef RHASH_ITER_LEV */
|
#endif /* #ifdef RHASH_ITER_LEV */
|
||||||
|
|
||||||
|
struct RMoved {
|
||||||
|
VALUE flags;
|
||||||
|
VALUE destination;
|
||||||
|
};
|
||||||
|
|
||||||
/* missing/setproctitle.c */
|
/* missing/setproctitle.c */
|
||||||
#ifndef HAVE_SETPROCTITLE
|
#ifndef HAVE_SETPROCTITLE
|
||||||
extern void ruby_init_setproctitle(int argc, char *argv[]);
|
extern void ruby_init_setproctitle(int argc, char *argv[]);
|
||||||
|
@ -947,7 +952,7 @@ struct rb_classext_struct {
|
||||||
*/
|
*/
|
||||||
rb_subclass_entry_t **module_subclasses;
|
rb_subclass_entry_t **module_subclasses;
|
||||||
rb_serial_t class_serial;
|
rb_serial_t class_serial;
|
||||||
const VALUE origin_;
|
VALUE origin_;
|
||||||
VALUE refined_class;
|
VALUE refined_class;
|
||||||
rb_alloc_func_t allocator;
|
rb_alloc_func_t allocator;
|
||||||
};
|
};
|
||||||
|
@ -1065,10 +1070,10 @@ imemo_type_p(VALUE imemo, enum imemo_type imemo_type)
|
||||||
/*! SVAR (Special VARiable) */
|
/*! SVAR (Special VARiable) */
|
||||||
struct vm_svar {
|
struct vm_svar {
|
||||||
VALUE flags;
|
VALUE flags;
|
||||||
const VALUE cref_or_me; /*!< class reference or rb_method_entry_t */
|
VALUE cref_or_me; /*!< class reference or rb_method_entry_t */
|
||||||
const VALUE lastline;
|
VALUE lastline;
|
||||||
const VALUE backref;
|
VALUE backref;
|
||||||
const VALUE others;
|
VALUE others;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1078,7 +1083,7 @@ struct vm_svar {
|
||||||
struct vm_throw_data {
|
struct vm_throw_data {
|
||||||
VALUE flags;
|
VALUE flags;
|
||||||
VALUE reserved;
|
VALUE reserved;
|
||||||
const VALUE throw_obj;
|
VALUE throw_obj;
|
||||||
const struct rb_control_frame_struct *catch_frame;
|
const struct rb_control_frame_struct *catch_frame;
|
||||||
VALUE throw_state;
|
VALUE throw_state;
|
||||||
};
|
};
|
||||||
|
@ -1101,7 +1106,7 @@ struct vm_ifunc {
|
||||||
VALUE flags;
|
VALUE flags;
|
||||||
VALUE reserved;
|
VALUE reserved;
|
||||||
VALUE (*func)(ANYARGS);
|
VALUE (*func)(ANYARGS);
|
||||||
const void *data;
|
void *data;
|
||||||
struct vm_ifunc_argc argc;
|
struct vm_ifunc_argc argc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1158,12 +1163,12 @@ void rb_strterm_mark(VALUE obj);
|
||||||
struct MEMO {
|
struct MEMO {
|
||||||
VALUE flags;
|
VALUE flags;
|
||||||
VALUE reserved;
|
VALUE reserved;
|
||||||
const VALUE v1;
|
VALUE v1;
|
||||||
const VALUE v2;
|
VALUE v2;
|
||||||
union {
|
union {
|
||||||
long cnt;
|
long cnt;
|
||||||
long state;
|
long state;
|
||||||
const VALUE value;
|
VALUE value;
|
||||||
VALUE (*func)(ANYARGS);
|
VALUE (*func)(ANYARGS);
|
||||||
} u3;
|
} u3;
|
||||||
};
|
};
|
||||||
|
@ -1567,6 +1572,7 @@ void rb_hash_bulk_insert(long, const VALUE *, VALUE);
|
||||||
int rb_hash_stlike_lookup(VALUE hash, st_data_t key, st_data_t *pval);
|
int rb_hash_stlike_lookup(VALUE hash, st_data_t key, st_data_t *pval);
|
||||||
int rb_hash_stlike_delete(VALUE hash, st_data_t *pkey, st_data_t *pval);
|
int rb_hash_stlike_delete(VALUE hash, st_data_t *pkey, st_data_t *pval);
|
||||||
int rb_hash_stlike_foreach(VALUE hash, int (*func)(ANYARGS), st_data_t arg);
|
int rb_hash_stlike_foreach(VALUE hash, int (*func)(ANYARGS), st_data_t arg);
|
||||||
|
int rb_hash_stlike_foreach_with_replace(VALUE hash, int (*func)(ANYARGS), st_update_callback_func *replace, st_data_t arg);
|
||||||
int rb_hash_stlike_update(VALUE hash, st_data_t key, st_update_callback_func func, st_data_t arg);
|
int rb_hash_stlike_update(VALUE hash, st_data_t key, st_update_callback_func func, st_data_t arg);
|
||||||
|
|
||||||
/* inits.c */
|
/* inits.c */
|
||||||
|
@ -2331,6 +2337,7 @@ extern unsigned long ruby_scan_digits(const char *str, ssize_t len, int base, si
|
||||||
|
|
||||||
/* variable.c (export) */
|
/* variable.c (export) */
|
||||||
void rb_mark_generic_ivar(VALUE);
|
void rb_mark_generic_ivar(VALUE);
|
||||||
|
void rb_mv_generic_ivar(VALUE src, VALUE dst);
|
||||||
VALUE rb_const_missing(VALUE klass, VALUE name);
|
VALUE rb_const_missing(VALUE klass, VALUE name);
|
||||||
int rb_class_ivar_set(VALUE klass, ID vid, VALUE value);
|
int rb_class_ivar_set(VALUE klass, ID vid, VALUE value);
|
||||||
st_table *rb_st_copy(VALUE obj, struct st_table *orig_tbl);
|
st_table *rb_st_copy(VALUE obj, struct st_table *orig_tbl);
|
||||||
|
@ -2342,9 +2349,10 @@ VALUE rb_wb_unprotected_newobj_of(VALUE, VALUE);
|
||||||
size_t rb_obj_memsize_of(VALUE);
|
size_t rb_obj_memsize_of(VALUE);
|
||||||
void rb_gc_verify_internal_consistency(void);
|
void rb_gc_verify_internal_consistency(void);
|
||||||
|
|
||||||
#define RB_OBJ_GC_FLAGS_MAX 5
|
#define RB_OBJ_GC_FLAGS_MAX 6
|
||||||
size_t rb_obj_gc_flags(VALUE, ID[], size_t);
|
size_t rb_obj_gc_flags(VALUE, ID[], size_t);
|
||||||
void rb_gc_mark_values(long n, const VALUE *values);
|
void rb_gc_mark_values(long n, const VALUE *values);
|
||||||
|
void rb_gc_mark_stack_values(long n, const VALUE *values);
|
||||||
|
|
||||||
#if IMEMO_DEBUG
|
#if IMEMO_DEBUG
|
||||||
VALUE rb_imemo_new_debug(enum imemo_type type, VALUE v1, VALUE v2, VALUE v3, VALUE v0, const char *file, int line);
|
VALUE rb_imemo_new_debug(enum imemo_type type, VALUE v1, VALUE v2, VALUE v3, VALUE v0, const char *file, int line);
|
||||||
|
|
100
iseq.c
100
iseq.c
|
@ -137,11 +137,11 @@ rb_vm_insn_null_translator(const void *addr)
|
||||||
return (VALUE)addr;
|
return (VALUE)addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void iseq_value_itr_t(void *ctx, VALUE obj);
|
typedef VALUE iseq_value_itr_t(void *ctx, VALUE obj);
|
||||||
typedef VALUE rb_vm_insns_translator_t(const void *addr);
|
typedef VALUE rb_vm_insns_translator_t(const void *addr);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
iseq_extract_values(const VALUE *code, size_t pos, iseq_value_itr_t * func, void *data, rb_vm_insns_translator_t * translator)
|
iseq_extract_values(VALUE *code, size_t pos, iseq_value_itr_t * func, void *data, rb_vm_insns_translator_t * translator)
|
||||||
{
|
{
|
||||||
VALUE insn = translator((void *)code[pos]);
|
VALUE insn = translator((void *)code[pos]);
|
||||||
int len = insn_len(insn);
|
int len = insn_len(insn);
|
||||||
|
@ -157,7 +157,10 @@ iseq_extract_values(const VALUE *code, size_t pos, iseq_value_itr_t * func, void
|
||||||
{
|
{
|
||||||
VALUE op = code[pos + op_no + 1];
|
VALUE op = code[pos + op_no + 1];
|
||||||
if (!SPECIAL_CONST_P(op)) {
|
if (!SPECIAL_CONST_P(op)) {
|
||||||
func(data, op);
|
VALUE newop = func(data, op);
|
||||||
|
if (newop != op) {
|
||||||
|
code[pos + op_no + 1] = newop;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -165,7 +168,10 @@ iseq_extract_values(const VALUE *code, size_t pos, iseq_value_itr_t * func, void
|
||||||
{
|
{
|
||||||
union iseq_inline_storage_entry *const is = (union iseq_inline_storage_entry *)code[pos + op_no + 1];
|
union iseq_inline_storage_entry *const is = (union iseq_inline_storage_entry *)code[pos + op_no + 1];
|
||||||
if (is->once.value) {
|
if (is->once.value) {
|
||||||
func(data, is->once.value);
|
VALUE nv = func(data, is->once.value);
|
||||||
|
if (is->once.value != nv) {
|
||||||
|
is->once.value = nv;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -181,7 +187,7 @@ static void
|
||||||
rb_iseq_each_value(const rb_iseq_t *iseq, iseq_value_itr_t * func, void *data)
|
rb_iseq_each_value(const rb_iseq_t *iseq, iseq_value_itr_t * func, void *data)
|
||||||
{
|
{
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
const VALUE *code;
|
VALUE *code;
|
||||||
size_t n;
|
size_t n;
|
||||||
rb_vm_insns_translator_t * translator;
|
rb_vm_insns_translator_t * translator;
|
||||||
const struct rb_iseq_constant_body *const body = iseq->body;
|
const struct rb_iseq_constant_body *const body = iseq->body;
|
||||||
|
@ -205,10 +211,65 @@ rb_iseq_each_value(const rb_iseq_t *iseq, iseq_value_itr_t * func, void *data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static VALUE
|
||||||
|
update_each_insn_value(void *ctx, VALUE obj)
|
||||||
|
{
|
||||||
|
return rb_gc_new_location(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_iseq_update_references(rb_iseq_t *iseq)
|
||||||
|
{
|
||||||
|
if (iseq->body) {
|
||||||
|
struct rb_iseq_constant_body *body = iseq->body;
|
||||||
|
|
||||||
|
body->variable.coverage = rb_gc_new_location(body->variable.coverage);
|
||||||
|
body->variable.pc2branchindex = rb_gc_new_location(body->variable.pc2branchindex);
|
||||||
|
body->location.label = rb_gc_new_location(body->location.label);
|
||||||
|
body->location.base_label = rb_gc_new_location(body->location.base_label);
|
||||||
|
body->location.pathobj = rb_gc_new_location(body->location.pathobj);
|
||||||
|
if (body->local_iseq) {
|
||||||
|
body->local_iseq = (struct rb_iseq_struct *)rb_gc_new_location((VALUE)body->local_iseq);
|
||||||
|
}
|
||||||
|
if (body->parent_iseq) {
|
||||||
|
body->parent_iseq = (struct rb_iseq_struct *)rb_gc_new_location((VALUE)body->parent_iseq);
|
||||||
|
}
|
||||||
|
if (FL_TEST(iseq, ISEQ_MARKABLE_ISEQ)) {
|
||||||
|
rb_iseq_each_value(iseq, update_each_insn_value, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body->param.flags.has_kw && ISEQ_COMPILE_DATA(iseq) == NULL) {
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
i = body->param.keyword->required_num;
|
||||||
|
|
||||||
|
for (j = 0; i < body->param.keyword->num; i++, j++) {
|
||||||
|
VALUE obj = body->param.keyword->default_values[j];
|
||||||
|
if (obj != Qundef) {
|
||||||
|
body->param.keyword->default_values[j] = rb_gc_new_location(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body->catch_table) {
|
||||||
|
struct iseq_catch_table *table = body->catch_table;
|
||||||
|
unsigned int i;
|
||||||
|
for(i = 0; i < table->size; i++) {
|
||||||
|
struct iseq_catch_table_entry *entry;
|
||||||
|
entry = &table->entries[i];
|
||||||
|
if (entry->iseq) {
|
||||||
|
entry->iseq = (rb_iseq_t *)rb_gc_new_location((VALUE)entry->iseq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
each_insn_value(void *ctx, VALUE obj)
|
each_insn_value(void *ctx, VALUE obj)
|
||||||
{
|
{
|
||||||
rb_gc_mark(obj);
|
rb_gc_mark_no_pin(obj);
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -225,12 +286,12 @@ rb_iseq_mark(const rb_iseq_t *iseq)
|
||||||
rb_iseq_each_value(iseq, each_insn_value, NULL);
|
rb_iseq_each_value(iseq, each_insn_value, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
rb_gc_mark(body->variable.coverage);
|
rb_gc_mark_no_pin(body->variable.coverage);
|
||||||
rb_gc_mark(body->variable.pc2branchindex);
|
rb_gc_mark_no_pin(body->variable.pc2branchindex);
|
||||||
rb_gc_mark(body->location.label);
|
rb_gc_mark_no_pin(body->location.label);
|
||||||
rb_gc_mark(body->location.base_label);
|
rb_gc_mark_no_pin(body->location.base_label);
|
||||||
rb_gc_mark(body->location.pathobj);
|
rb_gc_mark_no_pin(body->location.pathobj);
|
||||||
RUBY_MARK_UNLESS_NULL((VALUE)body->parent_iseq);
|
RUBY_MARK_NO_PIN_UNLESS_NULL((VALUE)body->parent_iseq);
|
||||||
|
|
||||||
if (body->param.flags.has_kw && ISEQ_COMPILE_DATA(iseq) == NULL) {
|
if (body->param.flags.has_kw && ISEQ_COMPILE_DATA(iseq) == NULL) {
|
||||||
const struct rb_iseq_param_keyword *const keyword = body->param.keyword;
|
const struct rb_iseq_param_keyword *const keyword = body->param.keyword;
|
||||||
|
@ -253,7 +314,7 @@ rb_iseq_mark(const rb_iseq_t *iseq)
|
||||||
const struct iseq_catch_table_entry *entry;
|
const struct iseq_catch_table_entry *entry;
|
||||||
entry = &table->entries[i];
|
entry = &table->entries[i];
|
||||||
if (entry->iseq) {
|
if (entry->iseq) {
|
||||||
rb_gc_mark((VALUE)entry->iseq);
|
rb_gc_mark_no_pin((VALUE)entry->iseq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,11 +325,14 @@ rb_iseq_mark(const rb_iseq_t *iseq)
|
||||||
}
|
}
|
||||||
else if (FL_TEST_RAW(iseq, ISEQ_USE_COMPILE_DATA)) {
|
else if (FL_TEST_RAW(iseq, ISEQ_USE_COMPILE_DATA)) {
|
||||||
const struct iseq_compile_data *const compile_data = ISEQ_COMPILE_DATA(iseq);
|
const struct iseq_compile_data *const compile_data = ISEQ_COMPILE_DATA(iseq);
|
||||||
VM_ASSERT(compile_data != NULL);
|
if (RTEST(compile_data->mark_ary)) {
|
||||||
|
rb_gc_mark(compile_data->mark_ary);
|
||||||
RUBY_MARK_UNLESS_NULL(compile_data->mark_ary);
|
}
|
||||||
RUBY_MARK_UNLESS_NULL(compile_data->err_info);
|
RUBY_MARK_UNLESS_NULL(compile_data->err_info);
|
||||||
RUBY_MARK_UNLESS_NULL(compile_data->catch_table_ary);
|
if (RTEST(compile_data->catch_table_ary)) {
|
||||||
|
rb_gc_mark(compile_data->catch_table_ary);
|
||||||
|
}
|
||||||
|
VM_ASSERT(compile_data != NULL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* executable */
|
/* executable */
|
||||||
|
|
2
iseq.h
2
iseq.h
|
@ -236,7 +236,7 @@ struct iseq_catch_table_entry {
|
||||||
* CATCH_TYPE_REDO, CATCH_TYPE_NEXT:
|
* CATCH_TYPE_REDO, CATCH_TYPE_NEXT:
|
||||||
* NULL.
|
* NULL.
|
||||||
*/
|
*/
|
||||||
const rb_iseq_t *iseq;
|
rb_iseq_t *iseq;
|
||||||
|
|
||||||
unsigned int start;
|
unsigned int start;
|
||||||
unsigned int end;
|
unsigned int end;
|
||||||
|
|
24
method.h
24
method.h
|
@ -40,9 +40,9 @@ typedef struct rb_scope_visi_struct {
|
||||||
/*! CREF (Class REFerence) */
|
/*! CREF (Class REFerence) */
|
||||||
typedef struct rb_cref_struct {
|
typedef struct rb_cref_struct {
|
||||||
VALUE flags;
|
VALUE flags;
|
||||||
const VALUE refinements;
|
VALUE refinements;
|
||||||
const VALUE klass;
|
VALUE klass;
|
||||||
struct rb_cref_struct * const next;
|
struct rb_cref_struct * next;
|
||||||
const rb_scope_visibility_t scope_visi;
|
const rb_scope_visibility_t scope_visi;
|
||||||
} rb_cref_t;
|
} rb_cref_t;
|
||||||
|
|
||||||
|
@ -50,10 +50,10 @@ typedef struct rb_cref_struct {
|
||||||
|
|
||||||
typedef struct rb_method_entry_struct {
|
typedef struct rb_method_entry_struct {
|
||||||
VALUE flags;
|
VALUE flags;
|
||||||
const VALUE defined_class;
|
VALUE defined_class;
|
||||||
struct rb_method_definition_struct * const def;
|
struct rb_method_definition_struct * const def;
|
||||||
ID called_id;
|
ID called_id;
|
||||||
const VALUE owner;
|
VALUE owner;
|
||||||
} rb_method_entry_t;
|
} rb_method_entry_t;
|
||||||
|
|
||||||
typedef struct rb_callable_method_entry_struct { /* same fields with rb_method_entry_t */
|
typedef struct rb_callable_method_entry_struct { /* same fields with rb_method_entry_t */
|
||||||
|
@ -123,8 +123,8 @@ typedef struct rb_iseq_struct rb_iseq_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct rb_method_iseq_struct {
|
typedef struct rb_method_iseq_struct {
|
||||||
const rb_iseq_t * const iseqptr; /*!< iseq pointer, should be separated from iseqval */
|
rb_iseq_t * iseqptr; /*!< iseq pointer, should be separated from iseqval */
|
||||||
rb_cref_t * const cref; /*!< class reference, should be marked */
|
rb_cref_t * cref; /*!< class reference, should be marked */
|
||||||
} rb_method_iseq_t; /* check rb_add_method_iseq() when modify the fields */
|
} rb_method_iseq_t; /* check rb_add_method_iseq() when modify the fields */
|
||||||
|
|
||||||
typedef struct rb_method_cfunc_struct {
|
typedef struct rb_method_cfunc_struct {
|
||||||
|
@ -135,20 +135,20 @@ typedef struct rb_method_cfunc_struct {
|
||||||
|
|
||||||
typedef struct rb_method_attr_struct {
|
typedef struct rb_method_attr_struct {
|
||||||
ID id;
|
ID id;
|
||||||
const VALUE location; /* should be marked */
|
VALUE location; /* should be marked */
|
||||||
} rb_method_attr_t;
|
} rb_method_attr_t;
|
||||||
|
|
||||||
typedef struct rb_method_alias_struct {
|
typedef struct rb_method_alias_struct {
|
||||||
const struct rb_method_entry_struct * const original_me; /* original_me->klass is original owner */
|
struct rb_method_entry_struct * original_me; /* original_me->klass is original owner */
|
||||||
} rb_method_alias_t;
|
} rb_method_alias_t;
|
||||||
|
|
||||||
typedef struct rb_method_refined_struct {
|
typedef struct rb_method_refined_struct {
|
||||||
const struct rb_method_entry_struct * const orig_me;
|
struct rb_method_entry_struct * orig_me;
|
||||||
const VALUE owner;
|
VALUE owner;
|
||||||
} rb_method_refined_t;
|
} rb_method_refined_t;
|
||||||
|
|
||||||
typedef struct rb_method_bmethod_struct {
|
typedef struct rb_method_bmethod_struct {
|
||||||
const VALUE proc; /* should be marked */
|
VALUE proc; /* should be marked */
|
||||||
struct rb_hook_list_struct *hooks;
|
struct rb_hook_list_struct *hooks;
|
||||||
} rb_method_bmethod_t;
|
} rb_method_bmethod_t;
|
||||||
|
|
||||||
|
|
23
st.c
23
st.c
|
@ -1548,7 +1548,7 @@ st_update(st_table *tab, st_data_t key,
|
||||||
different for ST_CHECK and when the current element is removed
|
different for ST_CHECK and when the current element is removed
|
||||||
during traversing. */
|
during traversing. */
|
||||||
static inline int
|
static inline int
|
||||||
st_general_foreach(st_table *tab, int (*func)(ANYARGS), st_data_t arg,
|
st_general_foreach(st_table *tab, int (*func)(ANYARGS), st_update_callback_func *replace, st_data_t arg,
|
||||||
int check_p)
|
int check_p)
|
||||||
{
|
{
|
||||||
st_index_t bin;
|
st_index_t bin;
|
||||||
|
@ -1572,6 +1572,15 @@ st_general_foreach(st_table *tab, int (*func)(ANYARGS), st_data_t arg,
|
||||||
rebuilds_num = tab->rebuilds_num;
|
rebuilds_num = tab->rebuilds_num;
|
||||||
hash = curr_entry_ptr->hash;
|
hash = curr_entry_ptr->hash;
|
||||||
retval = (*func)(key, curr_entry_ptr->record, arg, 0);
|
retval = (*func)(key, curr_entry_ptr->record, arg, 0);
|
||||||
|
|
||||||
|
if (retval == ST_REPLACE && replace) {
|
||||||
|
st_data_t value;
|
||||||
|
value = curr_entry_ptr->record;
|
||||||
|
retval = (*replace)(&key, &value, arg, TRUE);
|
||||||
|
curr_entry_ptr->key = key;
|
||||||
|
curr_entry_ptr->record = value;
|
||||||
|
}
|
||||||
|
|
||||||
if (rebuilds_num != tab->rebuilds_num) {
|
if (rebuilds_num != tab->rebuilds_num) {
|
||||||
retry:
|
retry:
|
||||||
entries = tab->entries;
|
entries = tab->entries;
|
||||||
|
@ -1600,6 +1609,8 @@ st_general_foreach(st_table *tab, int (*func)(ANYARGS), st_data_t arg,
|
||||||
curr_entry_ptr = &entries[i];
|
curr_entry_ptr = &entries[i];
|
||||||
}
|
}
|
||||||
switch (retval) {
|
switch (retval) {
|
||||||
|
case ST_REPLACE:
|
||||||
|
break;
|
||||||
case ST_CONTINUE:
|
case ST_CONTINUE:
|
||||||
break;
|
break;
|
||||||
case ST_CHECK:
|
case ST_CHECK:
|
||||||
|
@ -1647,10 +1658,16 @@ st_general_foreach(st_table *tab, int (*func)(ANYARGS), st_data_t arg,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
st_foreach_with_replace(st_table *tab, int (*func)(ANYARGS), st_update_callback_func *replace, st_data_t arg)
|
||||||
|
{
|
||||||
|
return st_general_foreach(tab, func, replace, arg, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
st_foreach(st_table *tab, int (*func)(ANYARGS), st_data_t arg)
|
st_foreach(st_table *tab, int (*func)(ANYARGS), st_data_t arg)
|
||||||
{
|
{
|
||||||
return st_general_foreach(tab, func, arg, FALSE);
|
return st_general_foreach(tab, func, NULL, arg, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See comments for function st_delete_safe. */
|
/* See comments for function st_delete_safe. */
|
||||||
|
@ -1658,7 +1675,7 @@ int
|
||||||
st_foreach_check(st_table *tab, int (*func)(ANYARGS), st_data_t arg,
|
st_foreach_check(st_table *tab, int (*func)(ANYARGS), st_data_t arg,
|
||||||
st_data_t never ATTRIBUTE_UNUSED)
|
st_data_t never ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
return st_general_foreach(tab, func, arg, TRUE);
|
return st_general_foreach(tab, func, NULL, arg, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set up array KEYS by at most SIZE keys of head table TAB entries.
|
/* Set up array KEYS by at most SIZE keys of head table TAB entries.
|
||||||
|
|
7
symbol.c
7
symbol.c
|
@ -60,12 +60,7 @@ enum id_entry_type {
|
||||||
ID_ENTRY_SIZE
|
ID_ENTRY_SIZE
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct symbols {
|
rb_symbols_t global_symbols = {tNEXT_ID-1};
|
||||||
rb_id_serial_t last_id;
|
|
||||||
st_table *str_sym;
|
|
||||||
VALUE ids;
|
|
||||||
VALUE dsymbol_fstr_hash;
|
|
||||||
} global_symbols = {tNEXT_ID-1};
|
|
||||||
|
|
||||||
static const struct st_hash_type symhash = {
|
static const struct st_hash_type symhash = {
|
||||||
rb_str_hash_cmp,
|
rb_str_hash_cmp,
|
||||||
|
|
7
symbol.h
7
symbol.h
|
@ -54,6 +54,13 @@ id_type(ID id)
|
||||||
|
|
||||||
typedef uint32_t rb_id_serial_t;
|
typedef uint32_t rb_id_serial_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
rb_id_serial_t last_id;
|
||||||
|
st_table *str_sym;
|
||||||
|
VALUE ids;
|
||||||
|
VALUE dsymbol_fstr_hash;
|
||||||
|
} rb_symbols_t;
|
||||||
|
|
||||||
static inline rb_id_serial_t
|
static inline rb_id_serial_t
|
||||||
rb_id_to_serial(ID id)
|
rb_id_to_serial(ID id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -253,6 +253,7 @@ class TestGc < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_profiler_clear
|
def test_profiler_clear
|
||||||
|
skip "for now"
|
||||||
assert_separately %w[--disable-gem], __FILE__, __LINE__, <<-'eom', timeout: 30
|
assert_separately %w[--disable-gem], __FILE__, __LINE__, <<-'eom', timeout: 30
|
||||||
GC::Profiler.enable
|
GC::Profiler.enable
|
||||||
|
|
||||||
|
|
97
test/ruby/test_gc_compact.rb
Normal file
97
test/ruby/test_gc_compact.rb
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
require 'test/unit'
|
||||||
|
require 'fiddle'
|
||||||
|
|
||||||
|
class TestGCCompact < Test::Unit::TestCase
|
||||||
|
def memory_location(obj)
|
||||||
|
(Fiddle.dlwrap(obj) >> 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_object_ids(list)
|
||||||
|
same_count = list.find_all { |obj|
|
||||||
|
memory_location(obj) == obj.object_id
|
||||||
|
}.count
|
||||||
|
list.count - same_count
|
||||||
|
end
|
||||||
|
|
||||||
|
def big_list
|
||||||
|
1000.times.map {
|
||||||
|
# try to make some empty slots by allocating an object and discarding
|
||||||
|
Object.new
|
||||||
|
Object.new
|
||||||
|
} # likely next to each other
|
||||||
|
end
|
||||||
|
|
||||||
|
# Find an object that's allocated in a slot that had a previous
|
||||||
|
# tenant, and that tenant moved and is still alive
|
||||||
|
def find_object_in_recycled_slot(addresses)
|
||||||
|
new_object = nil
|
||||||
|
|
||||||
|
100_000.times do
|
||||||
|
new_object = Object.new
|
||||||
|
if addresses.include? memory_location(new_object)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
new_object
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_find_collided_object
|
||||||
|
list_of_objects = big_list
|
||||||
|
|
||||||
|
ids = list_of_objects.map(&:object_id) # store id in map
|
||||||
|
addresses = list_of_objects.map(&self.:memory_location)
|
||||||
|
|
||||||
|
assert_equal ids, addresses
|
||||||
|
|
||||||
|
# All object ids should be equal
|
||||||
|
assert_equal 0, assert_object_ids(list_of_objects) # should be 0
|
||||||
|
|
||||||
|
GC.verify_compaction_references
|
||||||
|
|
||||||
|
# Some should have moved
|
||||||
|
id_count = assert_object_ids(list_of_objects)
|
||||||
|
skip "couldn't get objects to move" if id_count == 0
|
||||||
|
assert_operator id_count, :>, 0
|
||||||
|
|
||||||
|
new_ids = list_of_objects.map(&:object_id)
|
||||||
|
|
||||||
|
# Object ids should not change after compaction
|
||||||
|
assert_equal ids, new_ids
|
||||||
|
|
||||||
|
new_tenant = find_object_in_recycled_slot(addresses)
|
||||||
|
assert new_tenant
|
||||||
|
|
||||||
|
# This is the object that used to be in new_object's position
|
||||||
|
previous_tenant = list_of_objects[addresses.index(memory_location(new_tenant))]
|
||||||
|
|
||||||
|
assert_not_equal previous_tenant.object_id, new_tenant.object_id
|
||||||
|
|
||||||
|
# Should be able to look up object by object_id
|
||||||
|
assert_equal new_tenant, ObjectSpace._id2ref(new_tenant.object_id)
|
||||||
|
|
||||||
|
# Should be able to look up object by object_id
|
||||||
|
assert_equal previous_tenant, ObjectSpace._id2ref(previous_tenant.object_id)
|
||||||
|
|
||||||
|
int = (new_tenant.object_id >> 1)
|
||||||
|
# These two should be the same! but they are not :(
|
||||||
|
assert_equal int, ObjectSpace._id2ref(int.object_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_many_collisions
|
||||||
|
list_of_objects = big_list
|
||||||
|
ids = list_of_objects.map(&:object_id)
|
||||||
|
addresses = list_of_objects.map(&self.:memory_location)
|
||||||
|
|
||||||
|
GC.verify_compaction_references
|
||||||
|
|
||||||
|
new_tenants = 10.times.map {
|
||||||
|
find_object_in_recycled_slot(addresses)
|
||||||
|
}
|
||||||
|
|
||||||
|
collisions = GC.stat(:object_id_collisions)
|
||||||
|
skip "couldn't get objects to collide" if collisions == 0
|
||||||
|
assert_operator collisions, :>, 0
|
||||||
|
end
|
||||||
|
end
|
6
thread.c
6
thread.c
|
@ -4957,7 +4957,7 @@ exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE pairid, VALUE
|
||||||
struct exec_recursive_params p;
|
struct exec_recursive_params p;
|
||||||
int outermost;
|
int outermost;
|
||||||
p.list = recursive_list_access(sym);
|
p.list = recursive_list_access(sym);
|
||||||
p.objid = rb_obj_id(obj);
|
p.objid = rb_memory_id(obj);
|
||||||
p.obj = obj;
|
p.obj = obj;
|
||||||
p.pairid = pairid;
|
p.pairid = pairid;
|
||||||
p.arg = arg;
|
p.arg = arg;
|
||||||
|
@ -5026,7 +5026,7 @@ rb_exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
|
||||||
VALUE
|
VALUE
|
||||||
rb_exec_recursive_paired(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE paired_obj, VALUE arg)
|
rb_exec_recursive_paired(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE paired_obj, VALUE arg)
|
||||||
{
|
{
|
||||||
return exec_recursive(func, obj, rb_obj_id(paired_obj), arg, 0);
|
return exec_recursive(func, obj, rb_memory_id(paired_obj), arg, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -5050,7 +5050,7 @@ rb_exec_recursive_outer(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
|
||||||
VALUE
|
VALUE
|
||||||
rb_exec_recursive_paired_outer(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE paired_obj, VALUE arg)
|
rb_exec_recursive_paired_outer(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE paired_obj, VALUE arg)
|
||||||
{
|
{
|
||||||
return exec_recursive(func, obj, rb_obj_id(paired_obj), arg, 1);
|
return exec_recursive(func, obj, rb_memory_id(paired_obj), arg, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -796,6 +796,56 @@ blocks_clear_marked_index(struct transient_heap_block* block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
transient_heap_block_update_refs(struct transient_heap* theap, struct transient_heap_block* block)
|
||||||
|
{
|
||||||
|
int i=0, n=0;
|
||||||
|
|
||||||
|
while (i<block->info.index) {
|
||||||
|
void *ptr = &block->buff[i];
|
||||||
|
struct transient_alloc_header *header = ptr;
|
||||||
|
|
||||||
|
unpoison_memory_region(header, sizeof *header, false);
|
||||||
|
|
||||||
|
void *poisoned = __asan_region_is_poisoned(header->obj, SIZEOF_VALUE);
|
||||||
|
unpoison_object(header->obj, false);
|
||||||
|
|
||||||
|
header->obj = rb_gc_new_location(header->obj);
|
||||||
|
|
||||||
|
if (poisoned) {
|
||||||
|
poison_object(header->obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
i += header->size;
|
||||||
|
poison_memory_region(header, sizeof *header);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
transient_heap_blocks_update_refs(struct transient_heap* theap, struct transient_heap_block *block, const char *type_str)
|
||||||
|
{
|
||||||
|
while (block) {
|
||||||
|
transient_heap_block_update_refs(theap, block);
|
||||||
|
block = block->info.next_block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_transient_heap_update_references(void)
|
||||||
|
{
|
||||||
|
struct transient_heap* theap = transient_heap_get();
|
||||||
|
int i;
|
||||||
|
|
||||||
|
transient_heap_blocks_update_refs(theap, theap->using_blocks, "using_blocks");
|
||||||
|
transient_heap_blocks_update_refs(theap, theap->marked_blocks, "marked_blocks");
|
||||||
|
|
||||||
|
for (i=0; i<theap->promoted_objects_index; i++) {
|
||||||
|
VALUE obj = theap->promoted_objects[i];
|
||||||
|
theap->promoted_objects[i] = rb_gc_new_location(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rb_transient_heap_start_marking(int full_marking)
|
rb_transient_heap_start_marking(int full_marking)
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,6 +30,7 @@ void rb_transient_heap_mark(VALUE obj, const void *ptr);
|
||||||
void rb_transient_heap_promote(VALUE obj);
|
void rb_transient_heap_promote(VALUE obj);
|
||||||
void rb_transient_heap_start_marking(int full_marking);
|
void rb_transient_heap_start_marking(int full_marking);
|
||||||
void rb_transient_heap_finish_marking(void);
|
void rb_transient_heap_finish_marking(void);
|
||||||
|
void rb_transient_heap_update_references(void);
|
||||||
|
|
||||||
/* for debug API */
|
/* for debug API */
|
||||||
void rb_transient_heap_dump(void);
|
void rb_transient_heap_dump(void);
|
||||||
|
@ -48,6 +49,7 @@ void rb_struct_transient_heap_evacuate(VALUE st, int promote);
|
||||||
#define rb_transient_heap_verify() ((void)0)
|
#define rb_transient_heap_verify() ((void)0)
|
||||||
#define rb_transient_heap_promote(obj) ((void)0)
|
#define rb_transient_heap_promote(obj) ((void)0)
|
||||||
#define rb_transient_heap_start_marking(full_marking) ((void)0)
|
#define rb_transient_heap_start_marking(full_marking) ((void)0)
|
||||||
|
#define rb_transient_heap_update_references() ((void)0)
|
||||||
#define rb_transient_heap_finish_marking() ((void)0)
|
#define rb_transient_heap_finish_marking() ((void)0)
|
||||||
#define rb_transient_heap_mark(obj, ptr) ((void)0)
|
#define rb_transient_heap_mark(obj, ptr) ((void)0)
|
||||||
|
|
||||||
|
|
32
variable.c
32
variable.c
|
@ -1200,6 +1200,16 @@ rb_mark_generic_ivar(VALUE obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_mv_generic_ivar(VALUE rsrc, VALUE dst)
|
||||||
|
{
|
||||||
|
st_data_t key = (st_data_t)rsrc;
|
||||||
|
struct gen_ivtbl *ivtbl;
|
||||||
|
|
||||||
|
if (st_delete(generic_iv_tbl, &key, (st_data_t *)&ivtbl))
|
||||||
|
st_insert(generic_iv_tbl, (st_data_t)dst, (st_data_t)ivtbl);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rb_free_generic_ivar(VALUE obj)
|
rb_free_generic_ivar(VALUE obj)
|
||||||
{
|
{
|
||||||
|
@ -1950,7 +1960,7 @@ rb_mod_const_missing(VALUE klass, VALUE name)
|
||||||
static void
|
static void
|
||||||
autoload_mark(void *ptr)
|
autoload_mark(void *ptr)
|
||||||
{
|
{
|
||||||
rb_mark_tbl((st_table *)ptr);
|
rb_mark_tbl_no_pin((st_table *)ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1966,9 +1976,15 @@ autoload_memsize(const void *ptr)
|
||||||
return st_memsize(tbl);
|
return st_memsize(tbl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
autoload_compact(void *ptr)
|
||||||
|
{
|
||||||
|
rb_gc_update_tbl_refs((st_table *)ptr);
|
||||||
|
}
|
||||||
|
|
||||||
static const rb_data_type_t autoload_data_type = {
|
static const rb_data_type_t autoload_data_type = {
|
||||||
"autoload",
|
"autoload",
|
||||||
{autoload_mark, autoload_free, autoload_memsize,},
|
{autoload_mark, autoload_free, autoload_memsize, autoload_compact,},
|
||||||
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2014,12 +2030,19 @@ struct autoload_data_i {
|
||||||
struct list_head constants; /* <=> autoload_const.cnode */
|
struct list_head constants; /* <=> autoload_const.cnode */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
autoload_i_compact(void *ptr)
|
||||||
|
{
|
||||||
|
struct autoload_data_i *p = ptr;
|
||||||
|
p->feature = rb_gc_new_location(p->feature);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
autoload_i_mark(void *ptr)
|
autoload_i_mark(void *ptr)
|
||||||
{
|
{
|
||||||
struct autoload_data_i *p = ptr;
|
struct autoload_data_i *p = ptr;
|
||||||
|
|
||||||
rb_gc_mark(p->feature);
|
rb_gc_mark_no_pin(p->feature);
|
||||||
|
|
||||||
/* allow GC to free us if no modules refer to this via autoload_const.ad */
|
/* allow GC to free us if no modules refer to this via autoload_const.ad */
|
||||||
if (list_empty(&p->constants)) {
|
if (list_empty(&p->constants)) {
|
||||||
|
@ -2046,7 +2069,7 @@ autoload_i_memsize(const void *ptr)
|
||||||
|
|
||||||
static const rb_data_type_t autoload_data_i_type = {
|
static const rb_data_type_t autoload_data_i_type = {
|
||||||
"autoload_i",
|
"autoload_i",
|
||||||
{autoload_i_mark, autoload_i_free, autoload_i_memsize,},
|
{autoload_i_mark, autoload_i_free, autoload_i_memsize, autoload_i_compact},
|
||||||
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2971,6 +2994,7 @@ rb_define_const(VALUE klass, const char *name, VALUE val)
|
||||||
if (!rb_is_const_id(id)) {
|
if (!rb_is_const_id(id)) {
|
||||||
rb_warn("rb_define_const: invalid name `%s' for constant", name);
|
rb_warn("rb_define_const: invalid name `%s' for constant", name);
|
||||||
}
|
}
|
||||||
|
rb_gc_register_mark_object(val);
|
||||||
rb_const_set(klass, id, val);
|
rb_const_set(klass, id, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
31
vm.c
31
vm.c
|
@ -2202,6 +2202,15 @@ rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg,
|
||||||
|
|
||||||
/* vm */
|
/* vm */
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_vm_update_references(void *ptr)
|
||||||
|
{
|
||||||
|
if (ptr) {
|
||||||
|
rb_vm_t *vm = ptr;
|
||||||
|
rb_update_st_references(vm->frozen_strings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rb_vm_mark(void *ptr)
|
rb_vm_mark(void *ptr)
|
||||||
{
|
{
|
||||||
|
@ -2210,12 +2219,30 @@ rb_vm_mark(void *ptr)
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
rb_vm_t *vm = ptr;
|
rb_vm_t *vm = ptr;
|
||||||
rb_thread_t *th = 0;
|
rb_thread_t *th = 0;
|
||||||
|
long i, len;
|
||||||
|
const VALUE *obj_ary;
|
||||||
|
|
||||||
list_for_each(&vm->living_threads, th, vmlt_node) {
|
list_for_each(&vm->living_threads, th, vmlt_node) {
|
||||||
rb_gc_mark(th->self);
|
rb_gc_mark(th->self);
|
||||||
}
|
}
|
||||||
rb_gc_mark(vm->thgroup_default);
|
rb_gc_mark(vm->thgroup_default);
|
||||||
rb_gc_mark(vm->mark_object_ary);
|
rb_gc_mark(vm->mark_object_ary);
|
||||||
|
|
||||||
|
len = RARRAY_LEN(vm->mark_object_ary);
|
||||||
|
obj_ary = RARRAY_CONST_PTR(vm->mark_object_ary);
|
||||||
|
for (i=0; i < len; i++) {
|
||||||
|
const VALUE *ptr;
|
||||||
|
long j, jlen;
|
||||||
|
|
||||||
|
rb_gc_mark(*obj_ary);
|
||||||
|
jlen = RARRAY_LEN(*obj_ary);
|
||||||
|
ptr = RARRAY_CONST_PTR(*obj_ary);
|
||||||
|
for (j=0; j < jlen; j++) {
|
||||||
|
rb_gc_mark(*ptr++);
|
||||||
|
}
|
||||||
|
obj_ary++;
|
||||||
|
}
|
||||||
|
|
||||||
rb_gc_mark(vm->load_path);
|
rb_gc_mark(vm->load_path);
|
||||||
rb_gc_mark(vm->load_path_snapshot);
|
rb_gc_mark(vm->load_path_snapshot);
|
||||||
RUBY_MARK_UNLESS_NULL(vm->load_path_check_cache);
|
RUBY_MARK_UNLESS_NULL(vm->load_path_check_cache);
|
||||||
|
@ -2225,6 +2252,8 @@ rb_vm_mark(void *ptr)
|
||||||
rb_gc_mark(vm->top_self);
|
rb_gc_mark(vm->top_self);
|
||||||
RUBY_MARK_UNLESS_NULL(vm->coverages);
|
RUBY_MARK_UNLESS_NULL(vm->coverages);
|
||||||
rb_gc_mark(vm->defined_module_hash);
|
rb_gc_mark(vm->defined_module_hash);
|
||||||
|
/* Prevent classes from moving */
|
||||||
|
rb_mark_tbl(rb_hash_tbl(vm->defined_module_hash, __FILE__, __LINE__));
|
||||||
|
|
||||||
if (vm->loading_table) {
|
if (vm->loading_table) {
|
||||||
rb_mark_tbl(vm->loading_table);
|
rb_mark_tbl(vm->loading_table);
|
||||||
|
@ -2463,7 +2492,7 @@ rb_execution_context_mark(const rb_execution_context_t *ec)
|
||||||
rb_control_frame_t *cfp = ec->cfp;
|
rb_control_frame_t *cfp = ec->cfp;
|
||||||
rb_control_frame_t *limit_cfp = (void *)(ec->vm_stack + ec->vm_stack_size);
|
rb_control_frame_t *limit_cfp = (void *)(ec->vm_stack + ec->vm_stack_size);
|
||||||
|
|
||||||
rb_gc_mark_values((long)(sp - p), p);
|
rb_gc_mark_stack_values((long)(sp - p), p);
|
||||||
|
|
||||||
while (cfp != limit_cfp) {
|
while (cfp != limit_cfp) {
|
||||||
const VALUE *ep = cfp->ep;
|
const VALUE *ep = cfp->ep;
|
||||||
|
|
|
@ -346,7 +346,7 @@ struct rb_iseq_constant_body {
|
||||||
} type; /* instruction sequence type */
|
} type; /* instruction sequence type */
|
||||||
|
|
||||||
unsigned int iseq_size;
|
unsigned int iseq_size;
|
||||||
const VALUE *iseq_encoded; /* encoded iseq (insn addr and operands) */
|
VALUE *iseq_encoded; /* encoded iseq (insn addr and operands) */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* parameter information
|
* parameter information
|
||||||
|
@ -414,7 +414,7 @@ struct rb_iseq_constant_body {
|
||||||
int bits_start;
|
int bits_start;
|
||||||
int rest_start;
|
int rest_start;
|
||||||
const ID *table;
|
const ID *table;
|
||||||
const VALUE *default_values;
|
VALUE *default_values;
|
||||||
} *keyword;
|
} *keyword;
|
||||||
} param;
|
} param;
|
||||||
|
|
||||||
|
@ -433,7 +433,7 @@ struct rb_iseq_constant_body {
|
||||||
const ID *local_table; /* must free */
|
const ID *local_table; /* must free */
|
||||||
|
|
||||||
/* catch table */
|
/* catch table */
|
||||||
const struct iseq_catch_table *catch_table;
|
struct iseq_catch_table *catch_table;
|
||||||
|
|
||||||
/* for child iseq */
|
/* for child iseq */
|
||||||
const struct rb_iseq_struct *parent_iseq;
|
const struct rb_iseq_struct *parent_iseq;
|
||||||
|
@ -1029,7 +1029,7 @@ typedef struct {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
VALUE flags; /* imemo header */
|
VALUE flags; /* imemo header */
|
||||||
const rb_iseq_t *iseq;
|
rb_iseq_t *iseq;
|
||||||
const VALUE *ep;
|
const VALUE *ep;
|
||||||
const VALUE *env;
|
const VALUE *env;
|
||||||
unsigned int env_size;
|
unsigned int env_size;
|
||||||
|
|
|
@ -484,6 +484,7 @@ rb_type_str(enum ruby_value_type type)
|
||||||
case type_case(T_NODE);
|
case type_case(T_NODE);
|
||||||
case type_case(T_ICLASS);
|
case type_case(T_ICLASS);
|
||||||
case type_case(T_ZOMBIE);
|
case type_case(T_ZOMBIE);
|
||||||
|
case type_case(T_MOVED);
|
||||||
case T_MASK: break;
|
case T_MASK: break;
|
||||||
}
|
}
|
||||||
#undef type_case
|
#undef type_case
|
||||||
|
|
Loading…
Add table
Reference in a new issue