Feature #14370 » direct_marking.diff
| compile.c | ||
|---|---|---|
|
#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
|
||
|
#endif
|
||
|
static int
|
||
|
iseq_add_mark_object(const rb_iseq_t *iseq, VALUE v)
|
||
|
{
|
||
|
if (!SPECIAL_CONST_P(v)) {
|
||
|
rb_iseq_add_mark_object(iseq, v);
|
||
|
}
|
||
|
return COMPILE_OK;
|
||
|
}
|
||
|
static int
|
||
|
iseq_add_mark_object_compile_time(const rb_iseq_t *iseq, VALUE v)
|
||
|
{
|
||
| ... | ... | |
|
encoded[i] = (VALUE)table[insn];
|
||
|
i += len;
|
||
|
}
|
||
|
FL_SET(iseq, ISEQ_TRANSLATED);
|
||
|
#endif
|
||
|
return COMPILE_OK;
|
||
|
}
|
||
| ... | ... | |
|
rb_iseq_path(iseq), rb_iseq_realpath(iseq),
|
||
|
INT2FIX(line_no), parent, type, ISEQ_COMPILE_DATA(iseq)->option);
|
||
|
debugs("[new_child_iseq]< ---------------------------------------\n");
|
||
|
iseq_add_mark_object(iseq, (VALUE)ret_iseq);
|
||
|
iseq_add_mark_object_compile_time(iseq, (VALUE)ret_iseq);
|
||
|
return ret_iseq;
|
||
|
}
|
||
| ... | ... | |
|
rb_iseq_path(iseq), rb_iseq_realpath(iseq),
|
||
|
INT2FIX(line_no), parent, type, ISEQ_COMPILE_DATA(iseq)->option);
|
||
|
debugs("[new_child_iseq_ifunc]< ---------------------------------------\n");
|
||
|
iseq_add_mark_object(iseq, (VALUE)ret_iseq);
|
||
|
iseq_add_mark_object_compile_time(iseq, (VALUE)ret_iseq);
|
||
|
return ret_iseq;
|
||
|
}
|
||
| ... | ... | |
|
switch (nd_type(val_node)) {
|
||
|
case NODE_LIT:
|
||
|
dv = val_node->nd_lit;
|
||
|
iseq_add_mark_object(iseq, dv);
|
||
|
break;
|
||
|
case NODE_NIL:
|
||
|
dv = Qnil;
|
||
| ... | ... | |
|
rb_hash_rehash(map);
|
||
|
freeze_hide_obj(map);
|
||
|
generated_iseq[code_index + 1 + j] = map;
|
||
|
FL_SET(iseq, ISEQ_MARKABLE_ISEQ);
|
||
|
break;
|
||
|
}
|
||
|
case TS_LINDEX:
|
||
| ... | ... | |
|
{
|
||
|
VALUE v = operands[j];
|
||
|
generated_iseq[code_index + 1 + j] = v;
|
||
|
if (!SPECIAL_CONST_P(v)) {
|
||
|
FL_SET(iseq, ISEQ_MARKABLE_ISEQ);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case TS_VALUE: /* VALUE */
|
||
| ... | ... | |
|
VALUE v = operands[j];
|
||
|
generated_iseq[code_index + 1 + j] = v;
|
||
|
/* to mark ruby object */
|
||
|
iseq_add_mark_object(iseq, v);
|
||
|
if (!SPECIAL_CONST_P(v)) {
|
||
|
FL_SET(iseq, ISEQ_MARKABLE_ISEQ);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case TS_IC: /* inline cache */
|
||
| ... | ... | |
|
generated_iseq[code_index + 1 + j] = (VALUE)ic;
|
||
|
break;
|
||
|
}
|
||
|
case TS_ISE: /* inline storage entry */
|
||
|
{
|
||
|
unsigned int ic_index = FIX2UINT(operands[j]);
|
||
|
IC ic = (IC)&iseq->body->is_entries[ic_index];
|
||
|
if (UNLIKELY(ic_index >= iseq->body->is_size)) {
|
||
|
rb_bug("iseq_set_sequence: ic_index overflow: index: %d, size: %d", ic_index, iseq->body->is_size);
|
||
|
}
|
||
|
generated_iseq[code_index + 1 + j] = (VALUE)ic;
|
||
|
FL_SET(iseq, ISEQ_MARKABLE_ISEQ);
|
||
|
break;
|
||
|
}
|
||
|
case TS_CALLINFO: /* call info */
|
||
|
{
|
||
|
struct rb_call_info *base_ci = (struct rb_call_info *)operands[j];
|
||
| ... | ... | |
|
entry->end = label_get_position((LABEL *)(ptr[2] & ~1));
|
||
|
entry->iseq = (rb_iseq_t *)ptr[3];
|
||
|
/* register iseq as mark object */
|
||
|
if (entry->iseq != 0) {
|
||
|
iseq_add_mark_object(iseq, (VALUE)entry->iseq);
|
||
|
}
|
||
|
/* stack depth */
|
||
|
if (ptr[4]) {
|
||
|
LABEL *lobj = (LABEL *)(ptr[4] & ~1);
|
||
| ... | ... | |
|
}
|
||
|
if (only_special_literals) {
|
||
|
iseq_add_mark_object(iseq, literals);
|
||
|
iseq_add_mark_object_compile_time(iseq, literals);
|
||
|
ADD_INSN(ret, nd_line(orig_node), dup);
|
||
|
ADD_INSN2(ret, nd_line(orig_node), opt_case_dispatch, literals, elselabel);
|
||
| ... | ... | |
|
break;
|
||
|
}
|
||
|
case TS_IC: /* inline cache */
|
||
|
case TS_ISE: /* inline storage entry */
|
||
|
rb_str_catf(str, "<ic:%d>", FIX2INT(OPERAND_AT(iobj, j)));
|
||
|
break;
|
||
|
case TS_CALLINFO: /* call info */
|
||
| ... | ... | |
|
}
|
||
|
loaded_iseq = rb_iseqw_to_iseq(iseqw);
|
||
|
iseq_add_mark_object(iseq, (VALUE)loaded_iseq);
|
||
|
return loaded_iseq;
|
||
|
}
|
||
| ... | ... | |
|
break;
|
||
|
case TS_VALUE:
|
||
|
argv[j] = op;
|
||
|
iseq_add_mark_object(iseq, op);
|
||
|
break;
|
||
|
case TS_ISEQ:
|
||
|
{
|
||
| ... | ... | |
|
argv[j] = (VALUE)rb_global_entry(SYM2ID(op));
|
||
|
break;
|
||
|
case TS_IC:
|
||
|
case TS_ISE:
|
||
|
argv[j] = op;
|
||
|
if (NUM2UINT(op) >= iseq->body->is_size) {
|
||
|
iseq->body->is_size = NUM2INT(op) + 1;
|
||
| ... | ... | |
|
}
|
||
|
RB_GC_GUARD(op);
|
||
|
argv[j] = map;
|
||
|
rb_iseq_add_mark_object(iseq, map);
|
||
|
}
|
||
|
break;
|
||
|
case TS_FUNCPTR:
|
||
| ... | ... | |
|
code[code_index] = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
|
||
|
break;
|
||
|
case TS_IC:
|
||
|
case TS_ISE:
|
||
|
{
|
||
|
unsigned int i;
|
||
|
for (i=0; i<iseq->body->is_size; i++) {
|
||
| ... | ... | |
|
code[code_index] = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
|
||
|
break;
|
||
|
case TS_IC:
|
||
|
case TS_ISE:
|
||
|
code[code_index] = (VALUE)&is_entries[(int)op];
|
||
|
break;
|
||
|
case TS_CALLINFO:
|
||
| ... | ... | |
|
dump_body.is_entries = NULL;
|
||
|
dump_body.ci_entries = ibf_dump_ci_entries(dump, iseq);
|
||
|
dump_body.cc_entries = NULL;
|
||
|
dump_body.mark_ary = ISEQ_FLIP_CNT(iseq);
|
||
|
dump_body.variable.coverage = Qnil;
|
||
|
dump_body.variable.original_iseq = Qnil;
|
||
|
return ibf_dump_write(dump, &dump_body, sizeof(dump_body));
|
||
|
}
|
||
| ... | ... | |
|
load_body->ci_kw_size = body->ci_kw_size;
|
||
|
load_body->insns_info.size = body->insns_info.size;
|
||
|
RB_OBJ_WRITE(iseq, &load_body->mark_ary, iseq_mark_ary_create((int)body->mark_ary));
|
||
|
iseq_mark_ary_create(iseq, (int)body->variable.flip_count);
|
||
|
{
|
||
|
VALUE realpath = Qnil, path = ibf_load_object(load, body->location.pathobj);
|
||
| ... | ... | |
|
rb_ary_store(load->obj_list, (long)object_index, obj);
|
||
|
}
|
||
|
iseq_add_mark_object(load->iseq, obj);
|
||
|
return obj;
|
||
|
}
|
||
|
}
|
||
| ... | ... | |
|
ibf_load_iseq_complete(iseq);
|
||
|
#endif /* !USE_LAZY_LOAD */
|
||
|
if (load->iseq) {
|
||
|
iseq_add_mark_object(load->iseq, (VALUE)iseq);
|
||
|
}
|
||
|
return iseq;
|
||
|
}
|
||
|
}
|
||
| insns.def | ||
|---|---|---|
|
/* run iseq only once */
|
||
|
DEFINE_INSN
|
||
|
once
|
||
|
(ISEQ iseq, IC ic)
|
||
|
(ISEQ iseq, ISE ise)
|
||
|
()
|
||
|
(VALUE val)
|
||
|
{
|
||
|
val = vm_once_dispatch(ec, iseq, ic);
|
||
|
val = vm_once_dispatch(ec, iseq, ise);
|
||
|
}
|
||
|
/* case dispatcher, jump by table if possible */
|
||
| iseq.c | ||
|---|---|---|
|
RUBY_FREE_LEAVE("iseq");
|
||
|
}
|
||
|
#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
|
||
|
static int
|
||
|
rb_vm_insn_addr2insn2(const void *addr)
|
||
|
{
|
||
|
int insn;
|
||
|
const void * const *table = rb_vm_get_insns_address_table();
|
||
|
for (insn = 0; insn < VM_INSTRUCTION_SIZE; insn++) {
|
||
|
if (table[insn] == addr) {
|
||
|
return insn;
|
||
|
}
|
||
|
}
|
||
|
rb_bug("rb_vm_insn_addr2insn: invalid insn address: %p", addr);
|
||
|
}
|
||
|
#endif
|
||
|
static int
|
||
|
rb_vm_insn_null_translator(const void *addr)
|
||
|
{
|
||
|
return (int)addr;
|
||
|
}
|
||
|
typedef void iseq_value_itr_t(void *ctx, VALUE obj);
|
||
|
typedef int rb_vm_insns_translator_t(const void *addr);
|
||
|
static int
|
||
|
iseq_extract_values(const VALUE *code, size_t pos, iseq_value_itr_t * func, void *data, rb_vm_insns_translator_t * translator)
|
||
|
{
|
||
|
VALUE insn = translator((void *)code[pos]);
|
||
|
int len = insn_len(insn);
|
||
|
int op_no;
|
||
|
const char *types = insn_op_types(insn);
|
||
|
for (op_no = 0; types[op_no]; op_no++) {
|
||
|
char type = types[op_no];
|
||
|
switch (type) {
|
||
|
case TS_CDHASH:
|
||
|
case TS_ISEQ:
|
||
|
case TS_VALUE:
|
||
|
{
|
||
|
VALUE op = code[pos + op_no + 1];
|
||
|
if (!SPECIAL_CONST_P(op)) {
|
||
|
func(data, op);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case TS_ISE:
|
||
|
{
|
||
|
union iseq_inline_storage_entry *const is = (union iseq_inline_storage_entry *)code[pos + op_no + 1];
|
||
|
if (is->once.value) {
|
||
|
func(data, is->once.value);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return len;
|
||
|
}
|
||
|
static void
|
||
|
rb_iseq_each_value(const rb_iseq_t *iseq, iseq_value_itr_t * func, void *data)
|
||
|
{
|
||
|
unsigned int size;
|
||
|
const VALUE *code;
|
||
|
size_t n;
|
||
|
rb_vm_insns_translator_t * translator;
|
||
|
size = iseq->body->iseq_size;
|
||
|
code = iseq->body->iseq_encoded;
|
||
|
#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
|
||
|
if (FL_TEST(iseq, ISEQ_TRANSLATED)) {
|
||
|
translator = rb_vm_insn_addr2insn2;
|
||
|
} else {
|
||
|
translator = rb_vm_insn_null_translator;
|
||
|
}
|
||
|
#else
|
||
|
translator = rb_vm_insn_null_translator;
|
||
|
#endif
|
||
|
for (n = 0; n < size;) {
|
||
|
n += iseq_extract_values(code, n, func, data, translator);
|
||
|
}
|
||
|
}
|
||
|
static void
|
||
|
each_insn_value(void *ctx, VALUE obj)
|
||
|
{
|
||
|
rb_gc_mark(obj);
|
||
|
}
|
||
|
void
|
||
|
rb_iseq_mark(const rb_iseq_t *iseq)
|
||
|
{
|
||
| ... | ... | |
|
if (iseq->body) {
|
||
|
const struct rb_iseq_constant_body *body = iseq->body;
|
||
|
RUBY_MARK_UNLESS_NULL(body->mark_ary);
|
||
|
if(FL_TEST(iseq, ISEQ_MARKABLE_ISEQ)) {
|
||
|
rb_iseq_each_value(iseq, each_insn_value, NULL);
|
||
|
}
|
||
|
rb_gc_mark(body->variable.coverage);
|
||
|
rb_gc_mark(body->variable.original_iseq);
|
||
|
rb_gc_mark(body->location.label);
|
||
|
rb_gc_mark(body->location.base_label);
|
||
|
rb_gc_mark(body->location.pathobj);
|
||
|
RUBY_MARK_UNLESS_NULL((VALUE)body->parent_iseq);
|
||
|
if (body->catch_table) {
|
||
|
const struct iseq_catch_table *table = body->catch_table;
|
||
|
unsigned int i;
|
||
|
for(i = 0; i < table->size; i++) {
|
||
|
const struct iseq_catch_table_entry *entry;
|
||
|
entry = &table->entries[i];
|
||
|
if (entry->iseq) {
|
||
|
rb_gc_mark((VALUE)entry->iseq);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (FL_TEST(iseq, ISEQ_NOT_LOADED_YET)) {
|
||
|
rb_gc_mark(iseq->aux.loader.obj);
|
||
|
}
|
||
| ... | ... | |
|
}
|
||
|
}
|
||
|
void
|
||
|
rb_iseq_add_mark_object(const rb_iseq_t *iseq, VALUE obj)
|
||
|
{
|
||
|
/* TODO: check dedup */
|
||
|
rb_ary_push(ISEQ_MARK_ARY(iseq), obj);
|
||
|
}
|
||
|
static VALUE
|
||
|
prepare_iseq_build(rb_iseq_t *iseq,
|
||
|
VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_code_location_t *code_location,
|
||
| ... | ... | |
|
if (iseq != iseq->body->local_iseq) {
|
||
|
RB_OBJ_WRITE(iseq, &iseq->body->location.base_label, iseq->body->local_iseq->body->location.label);
|
||
|
}
|
||
|
RB_OBJ_WRITE(iseq, &iseq->body->mark_ary, iseq_mark_ary_create(0));
|
||
|
iseq_mark_ary_create(iseq, 0);
|
||
|
ISEQ_COMPILE_DATA_ALLOC(iseq);
|
||
|
RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err_info);
|
||
| ... | ... | |
|
break;
|
||
|
case TS_IC:
|
||
|
case TS_ISE:
|
||
|
ret = rb_sprintf("<is:%"PRIdPTRDIFF">", (union iseq_inline_storage_entry *)op - iseq->body->is_entries);
|
||
|
break;
|
||
| ... | ... | |
|
}
|
||
|
break;
|
||
|
case TS_IC:
|
||
|
case TS_ISE:
|
||
|
{
|
||
|
union iseq_inline_storage_entry *is = (union iseq_inline_storage_entry *)*seq;
|
||
|
rb_ary_push(ary, INT2FIX(is - iseq->body->is_entries));
|
||
| iseq.h | ||
|---|---|---|
|
return sizeof(struct rb_call_info_kw_arg) + sizeof(VALUE) * (keyword_len - 1);
|
||
|
}
|
||
|
enum iseq_mark_ary_index {
|
||
|
ISEQ_MARK_ARY_COVERAGE,
|
||
|
ISEQ_MARK_ARY_FLIP_CNT,
|
||
|
ISEQ_MARK_ARY_ORIGINAL_ISEQ,
|
||
|
ISEQ_MARK_ARY_INITIAL_SIZE
|
||
|
};
|
||
|
static inline VALUE
|
||
|
iseq_mark_ary_create(int flip_cnt)
|
||
|
static inline void
|
||
|
iseq_mark_ary_create(rb_iseq_t *iseq, int flip_cnt)
|
||
|
{
|
||
|
VALUE ary = rb_ary_tmp_new(ISEQ_MARK_ARY_INITIAL_SIZE);
|
||
|
rb_ary_push(ary, Qnil); /* ISEQ_MARK_ARY_COVERAGE */
|
||
|
rb_ary_push(ary, INT2FIX(flip_cnt)); /* ISEQ_MARK_ARY_FLIP_CNT */
|
||
|
rb_ary_push(ary, Qnil); /* ISEQ_MARK_ARY_ORIGINAL_ISEQ */
|
||
|
return ary;
|
||
|
RB_OBJ_WRITE(iseq, &iseq->body->variable.coverage, Qnil);
|
||
|
RB_OBJ_WRITE(iseq, &iseq->body->variable.original_iseq, Qnil);
|
||
|
iseq->body->variable.flip_count = flip_cnt;
|
||
|
}
|
||
|
#define ISEQ_MARK_ARY(iseq) (iseq)->body->mark_ary
|
||
|
#define ISEQ_COVERAGE(iseq) RARRAY_AREF(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_COVERAGE)
|
||
|
#define ISEQ_COVERAGE_SET(iseq, cov) RARRAY_ASET(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_COVERAGE, cov)
|
||
|
#define ISEQ_COVERAGE(iseq) iseq->body->variable.coverage
|
||
|
#define ISEQ_COVERAGE_SET(iseq, cov) RB_OBJ_WRITE(iseq, &iseq->body->variable.coverage, cov)
|
||
|
#define ISEQ_LINE_COVERAGE(iseq) RARRAY_AREF(ISEQ_COVERAGE(iseq), COVERAGE_INDEX_LINES)
|
||
|
#define ISEQ_BRANCH_COVERAGE(iseq) RARRAY_AREF(ISEQ_COVERAGE(iseq), COVERAGE_INDEX_BRANCHES)
|
||
|
#define ISEQ_FLIP_CNT(iseq) FIX2INT(RARRAY_AREF(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_FLIP_CNT))
|
||
|
#define ISEQ_FLIP_CNT(iseq) (iseq)->body->variable.flip_count
|
||
|
static inline int
|
||
|
ISEQ_FLIP_CNT_INCREMENT(const rb_iseq_t *iseq)
|
||
|
{
|
||
|
int cnt = ISEQ_FLIP_CNT(iseq);
|
||
|
RARRAY_ASET(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_FLIP_CNT, INT2FIX(cnt+1));
|
||
|
int cnt = iseq->body->variable.flip_count;
|
||
|
iseq->body->variable.flip_count += 1;
|
||
|
return cnt;
|
||
|
}
|
||
|
static inline VALUE *
|
||
|
ISEQ_ORIGINAL_ISEQ(const rb_iseq_t *iseq)
|
||
|
{
|
||
|
VALUE str = RARRAY_AREF(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_ORIGINAL_ISEQ);
|
||
|
VALUE str = iseq->body->variable.original_iseq;
|
||
|
if (RTEST(str)) return (VALUE *)RSTRING_PTR(str);
|
||
|
return NULL;
|
||
|
}
|
||
| ... | ... | |
|
static inline void
|
||
|
ISEQ_ORIGINAL_ISEQ_CLEAR(const rb_iseq_t *iseq)
|
||
|
{
|
||
|
RARRAY_ASET(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_ORIGINAL_ISEQ, Qnil);
|
||
|
RB_OBJ_WRITE(iseq, &iseq->body->variable.original_iseq, Qnil);
|
||
|
}
|
||
|
static inline VALUE *
|
||
|
ISEQ_ORIGINAL_ISEQ_ALLOC(const rb_iseq_t *iseq, long size)
|
||
|
{
|
||
|
VALUE str = rb_str_tmp_new(size * sizeof(VALUE));
|
||
|
RARRAY_ASET(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_ORIGINAL_ISEQ, str);
|
||
|
RB_OBJ_WRITE(iseq, &iseq->body->variable.original_iseq, str);
|
||
|
return (VALUE *)RSTRING_PTR(str);
|
||
|
}
|
||
| ... | ... | |
|
#define ISEQ_NOT_LOADED_YET IMEMO_FL_USER1
|
||
|
#define ISEQ_USE_COMPILE_DATA IMEMO_FL_USER2
|
||
|
#define ISEQ_TRANSLATED IMEMO_FL_USER3
|
||
|
#define ISEQ_MARKABLE_ISEQ IMEMO_FL_USER4
|
||
|
struct iseq_compile_data {
|
||
|
/* GC is needed */
|
||
| ... | ... | |
|
VALUE exception, VALUE body);
|
||
|
/* iseq.c */
|
||
|
void rb_iseq_add_mark_object(const rb_iseq_t *iseq, VALUE obj);
|
||
|
VALUE rb_iseq_load(VALUE data, VALUE parent, VALUE opt);
|
||
|
VALUE rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc);
|
||
|
struct st_table *ruby_insn_make_insn_table(void);
|
||
| tool/ruby_vm/models/typemap.rb | ||
|---|---|---|
|
"GENTRY" => %w[G TS_GENTRY],
|
||
|
"IC" => %w[K TS_IC],
|
||
|
"ID" => %w[I TS_ID],
|
||
|
"ISE" => %w[T TS_ISE],
|
||
|
"ISEQ" => %w[S TS_ISEQ],
|
||
|
"OFFSET" => %w[O TS_OFFSET],
|
||
|
"VALUE" => %w[V TS_VALUE],
|
||
| vm_core.h | ||
|---|---|---|
|
*/
|
||
|
struct rb_call_cache *cc_entries; /* size is ci_size = ci_kw_size */
|
||
|
VALUE mark_ary; /* Array: includes operands which should be GC marked */
|
||
|
struct {
|
||
|
rb_num_t flip_count;
|
||
|
VALUE coverage;
|
||
|
VALUE original_iseq;
|
||
|
} variable;
|
||
|
unsigned int local_table_size;
|
||
|
unsigned int is_size;
|
||
| ... | ... | |
|
/* inline cache */
|
||
|
typedef struct iseq_inline_cache_entry *IC;
|
||
|
typedef union iseq_inline_storage_entry *ISE;
|
||
|
typedef struct rb_call_info *CALL_INFO;
|
||
|
typedef struct rb_call_cache *CALL_CACHE;
|
||
| vm_insnhelper.c | ||
|---|---|---|
|
}
|
||
|
static VALUE
|
||
|
vm_once_dispatch(rb_execution_context_t *ec, ISEQ iseq, IC ic)
|
||
|
vm_once_dispatch(rb_execution_context_t *ec, ISEQ iseq, ISE is)
|
||
|
{
|
||
|
rb_thread_t *th = rb_ec_thread_ptr(ec);
|
||
|
rb_thread_t *const RUNNING_THREAD_ONCE_DONE = (rb_thread_t *)(0x1);
|
||
|
union iseq_inline_storage_entry *const is = (union iseq_inline_storage_entry *)ic;
|
||
|
again:
|
||
|
if (is->once.running_thread == RUNNING_THREAD_ONCE_DONE) {
|
||
| ... | ... | |
|
else if (is->once.running_thread == NULL) {
|
||
|
VALUE val;
|
||
|
is->once.running_thread = th;
|
||
|
val = is->once.value = rb_ensure(vm_once_exec, (VALUE)iseq, vm_once_clear, (VALUE)is);
|
||
|
val = rb_ensure(vm_once_exec, (VALUE)iseq, vm_once_clear, (VALUE)is);
|
||
|
RB_OBJ_WRITE(ec->cfp->iseq, &is->once.value, val);
|
||
|
/* is->once.running_thread is cleared by vm_once_clear() */
|
||
|
is->once.running_thread = RUNNING_THREAD_ONCE_DONE; /* success */
|
||
|
rb_iseq_add_mark_object(ec->cfp->iseq, val);
|
||
|
return val;
|
||
|
}
|
||
|
else if (is->once.running_thread == th) {
|
||
- « Previous
- 1
- …
- 4
- 5
- 6
- Next »