diff options
author | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2016-07-28 11:02:30 +0000 |
---|---|---|
committer | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2016-07-28 11:02:30 +0000 |
commit | 9f60791a0412cae804f13ed3e746a634c7a0731b (patch) | |
tree | 49b3f9ff4924a622e13fbdfc9478d34717d19378 /vm_eval.c | |
parent | 683eafd973e4db60756f6ee12e1b066e316f026f (diff) | |
download | ruby-9f60791a0412cae804f13ed3e746a634c7a0731b.tar.gz |
* vm_core.h: revisit the structure of frame, block and env.
[Bug #12628]
This patch introduce many changes.
* Introduce concept of "Block Handler (BH)" to represent
passed blocks.
* move rb_control_frame_t::flag to ep[0] (as a special local
variable). This flags represents not only frame type, but also
env flags such as escaped.
* rename `rb_block_t` to `struct rb_block`.
* Make Proc, Binding and RubyVM::Env objects wb-protected.
Check [Bug #12628] for more details.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55766 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'vm_eval.c')
-rw-r--r-- | vm_eval.c | 185 |
1 files changed, 99 insertions, 86 deletions
@@ -18,9 +18,9 @@ struct local_var_list { static inline VALUE method_missing(VALUE obj, ID id, int argc, const VALUE *argv, enum method_missing_reason call_status); static inline VALUE vm_yield_with_cref(rb_thread_t *th, int argc, const VALUE *argv, const rb_cref_t *cref); static inline VALUE vm_yield(rb_thread_t *th, int argc, const VALUE *argv); -static inline VALUE vm_yield_with_block(rb_thread_t *th, int argc, const VALUE *argv, const rb_block_t *blockargptr); +static inline VALUE vm_yield_with_block(rb_thread_t *th, int argc, const VALUE *argv, VALUE block_handler); static VALUE vm_exec(rb_thread_t *th); -static void vm_set_eval_stack(rb_thread_t * th, const rb_iseq_t *iseq, const rb_cref_t *cref, rb_block_t *base_block); +static void vm_set_eval_stack(rb_thread_t * th, const rb_iseq_t *iseq, const rb_cref_t *cref, const struct rb_block *base_block); static int vm_collect_local_variables_in_heap(rb_thread_t *th, const VALUE *dfp, const struct local_var_list *vars); static VALUE rb_eUncaughtThrow; @@ -114,16 +114,16 @@ vm_call0_cfunc_with_frame(rb_thread_t* th, struct rb_calling_info *calling, cons VALUE recv = calling->recv; int argc = calling->argc; ID mid = ci->mid; - rb_block_t *blockptr = calling->blockptr; + VALUE block_handler = calling->block_handler; RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->owner, mid); EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, mid, me->owner, Qnil); { rb_control_frame_t *reg_cfp = th->cfp; - vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, - VM_ENVVAL_BLOCK_PTR(blockptr), (VALUE)me, - 0, reg_cfp->sp, 1, 0); + vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC | VM_ENV_FLAG_LOCAL, recv, + block_handler, (VALUE)me, + 0, reg_cfp->sp, 0, 0); if (len >= 0) rb_check_arity(argc, len, len); @@ -155,13 +155,7 @@ vm_call0_body(rb_thread_t* th, struct rb_calling_info *calling, const struct rb_ { VALUE ret; - if (th->passed_block) { - calling->blockptr = (rb_block_t *)th->passed_block; - th->passed_block = 0; - } - else { - calling->blockptr = 0; - } + calling->block_handler = vm_passed_block_handler(th); again: switch (cc->me->def->type) { @@ -178,7 +172,7 @@ vm_call0_body(rb_thread_t* th, struct rb_calling_info *calling, const struct rb_ } vm_call_iseq_setup(th, reg_cfp, calling, ci, cc); - th->cfp->flag |= VM_FRAME_FLAG_FINISH; + VM_ENV_FLAGS_SET(th->cfp->ep, VM_FRAME_FLAG_FINISH); return vm_exec(th); /* CHECK_INTS in this function */ } case VM_METHOD_TYPE_NOTIMPLEMENTED: @@ -222,7 +216,7 @@ vm_call0_body(rb_thread_t* th, struct rb_calling_info *calling, const struct rb_ goto again; case VM_METHOD_TYPE_MISSING: { - th->passed_block = calling->blockptr; + vm_passed_block_handler_set(th, calling->block_handler); return method_missing(calling->recv, ci->mid, calling->argc, argv, MISSING_NOENTRY); } @@ -235,7 +229,7 @@ vm_call0_body(rb_thread_t* th, struct rb_calling_info *calling, const struct rb_ { rb_proc_t *proc; GetProcPtr(calling->recv, proc); - ret = rb_vm_invoke_proc(th, proc, calling->argc, argv, calling->blockptr); + ret = rb_vm_invoke_proc(th, proc, calling->argc, argv, calling->block_handler); goto success; } default: @@ -288,8 +282,9 @@ vm_call_super(rb_thread_t *th, int argc, const VALUE *argv) VALUE rb_call_super(int argc, const VALUE *argv) { - PASS_PASSED_BLOCK(); - return vm_call_super(GET_THREAD(), argc, argv); + rb_thread_t *th = GET_THREAD(); + PASS_PASSED_BLOCK_HANDLER_TH(th); + return vm_call_super(th, argc, argv); } VALUE @@ -747,11 +742,10 @@ method_missing(VALUE obj, ID id, int argc, const VALUE *argv, enum method_missin { VALUE *nargv, result, work, klass; rb_thread_t *th = GET_THREAD(); - const rb_block_t *blockptr = th->passed_block; + VALUE block_handler = vm_passed_block_handler(th); const rb_callable_method_entry_t *me; th->method_missing_reason = call_status; - th->passed_block = 0; if (id == idMethodMissing) { missing: @@ -768,7 +762,7 @@ method_missing(VALUE obj, ID id, int argc, const VALUE *argv, enum method_missin if (!klass) goto missing; me = rb_callable_method_entry(klass, idMethodMissing); if (!me || METHOD_ENTRY_BASIC(me)) goto missing; - th->passed_block = blockptr; + vm_passed_block_handler_set(th, block_handler); result = vm_call0(th, obj, idMethodMissing, argc, argv, me); if (work) ALLOCV_END(work); return result; @@ -778,7 +772,7 @@ void rb_raise_method_missing(rb_thread_t *th, int argc, const VALUE *argv, VALUE obj, int call_status) { - th->passed_block = 0; + vm_passed_block_handler_set(th, VM_BLOCK_HANDLER_NONE); raise_method_missing(th, argc, argv, obj, call_status | MISSING_MISSING); } @@ -874,23 +868,16 @@ rb_funcallv_public(VALUE recv, ID mid, int argc, const VALUE *argv) VALUE rb_funcall_passing_block(VALUE recv, ID mid, int argc, const VALUE *argv) { - PASS_PASSED_BLOCK(); - + PASS_PASSED_BLOCK_HANDLER(); return rb_call(recv, mid, argc, argv, CALL_PUBLIC); } VALUE -rb_funcall_with_block(VALUE recv, ID mid, int argc, const VALUE *argv, VALUE pass_procval) +rb_funcall_with_block(VALUE recv, ID mid, int argc, const VALUE *argv, VALUE passed_procval) { - if (!NIL_P(pass_procval)) { + if (!NIL_P(passed_procval)) { rb_thread_t *th = GET_THREAD(); - rb_block_t *block = 0; - - rb_proc_t *pass_proc; - GetProcPtr(pass_procval, pass_proc); - block = &pass_proc->block; - - th->passed_block = block; + vm_passed_block_handler_set(th, passed_procval); } return rb_call(recv, mid, argc, argv, CALL_PUBLIC); @@ -957,7 +944,7 @@ send_internal(int argc, const VALUE *argv, VALUE recv, call_type scope) else { argv++; argc--; } - PASS_PASSED_BLOCK_TH(th); + PASS_PASSED_BLOCK_HANDLER_TH(th); ret = rb_call0(recv, id, argc, argv, scope, self); ALLOCV_END(vargv); return ret; @@ -1080,13 +1067,8 @@ rb_yield_splat(VALUE values) VALUE rb_yield_block(VALUE val, VALUE arg, int argc, const VALUE *argv, VALUE blockarg) { - const rb_block_t *blockptr = NULL; - if (!NIL_P(blockarg)) { - rb_proc_t *blockproc; - GetProcPtr(blockarg, blockproc); - blockptr = &blockproc->block; - } - return vm_yield_with_block(GET_THREAD(), argc, argv, blockptr); + return vm_yield_with_block(GET_THREAD(), argc, argv, + NIL_P(blockarg) ? VM_BLOCK_HANDLER_NONE : blockarg); } static VALUE @@ -1166,16 +1148,17 @@ rb_iterate0(VALUE (* it_proc) (VALUE), VALUE data1, if (state == 0) { iter_retry: { - rb_block_t *blockptr; + VALUE block_handler; + if (ifunc) { - blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp); - blockptr->iseq = (void *)ifunc; - blockptr->proc = 0; + struct rb_captured_block *captured = VM_CFP_TO_CAPTURED_BLOCK(cfp); + captured->code.ifunc = ifunc; + block_handler = VM_BH_FROM_IFUNC_BLOCK(captured); } else { - blockptr = VM_CF_BLOCK_PTR(cfp); + block_handler = VM_CF_BLOCK_HANDLER(cfp); } - th->passed_block = blockptr; + vm_passed_block_handler_set(th, block_handler); } retval = (*it_proc) (data1); } @@ -1294,12 +1277,14 @@ eval_string_with_cref(VALUE self, VALUE src, VALUE scope, rb_cref_t *const cref_ { int state; VALUE result = Qundef; - VALUE envval; rb_thread_t *th = GET_THREAD(); - rb_env_t *env = NULL; - rb_block_t block, *base_block; - VALUE file = filename ? filename : rb_source_location(&lineno); - int line = lineno; + struct rb_block block; + const struct rb_block *base_block; + volatile VALUE file; + volatile int line; + + file = filename ? filename : rb_source_location(&lineno); + line = lineno; { rb_cref_t *cref = cref_arg; @@ -1314,25 +1299,23 @@ eval_string_with_cref(VALUE self, VALUE src, VALUE scope, rb_cref_t *const cref_ if (!NIL_P(scope)) { bind = Check_TypedStruct(scope, &ruby_binding_data_type); - { - envval = bind->env; - if (NIL_P(absolute_path) && !NIL_P(bind->path)) { - file = bind->path; - line = bind->first_lineno; - absolute_path = rb_current_realfilepath(); - } + + if (NIL_P(absolute_path) && !NIL_P(bind->path)) { + file = bind->path; + line = bind->first_lineno; + absolute_path = rb_current_realfilepath(); } - GetEnvPtr(envval, env); - base_block = &env->block; + base_block = &bind->block; } else { rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp); if (cfp != 0) { - block = *RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp); + block.as.captured = *VM_CFP_TO_CAPTURED_BLOCK(cfp); + block.as.captured.self = self; + block.as.captured.code.iseq = cfp->iseq; + block.type = block_type_iseq; base_block = █ - base_block->self = self; - base_block->iseq = cfp->iseq; /* TODO */ } else { rb_raise(rb_eRuntimeError, "Can't eval on top of Fiber or Thread"); @@ -1355,9 +1338,10 @@ eval_string_with_cref(VALUE self, VALUE src, VALUE scope, rb_cref_t *const cref_ rb_exc_raise(adjust_backtrace_in_eval(th, th->errinfo)); } - if (!cref && base_block->iseq) { + /* TODO: what the code checking? */ + if (!cref && base_block->as.captured.code.val) { if (NIL_P(scope)) { - rb_cref_t *orig_cref = rb_vm_get_cref(base_block->ep); + rb_cref_t *orig_cref = rb_vm_get_cref(vm_block_ep(base_block)); cref = vm_cref_dup(orig_cref); } else { @@ -1373,7 +1357,7 @@ eval_string_with_cref(VALUE self, VALUE src, VALUE scope, rb_cref_t *const cref_ /* save new env */ if (bind && iseq->body->local_table_size > 0) { - bind->env = vm_make_env_object(th, th->cfp); + vm_bind_update_env(bind, vm_make_env_object(th, th->cfp)); } } @@ -1579,16 +1563,41 @@ static VALUE yield_under(VALUE under, VALUE self, int argc, const VALUE *argv) { rb_thread_t *th = GET_THREAD(); - rb_block_t block, *blockptr; + rb_control_frame_t *cfp = th->cfp; + VALUE block_handler = VM_CF_BLOCK_HANDLER(cfp); + VALUE new_block_handler = 0; + const struct rb_captured_block *captured = NULL; + struct rb_captured_block new_captured; + const VALUE *ep = NULL; rb_cref_t *cref; - if ((blockptr = VM_CF_BLOCK_PTR(th->cfp)) != 0) { - block = *blockptr; - block.self = self; - VM_CF_LEP(th->cfp)[0] = VM_ENVVAL_BLOCK_PTR(&block); + if (block_handler != VM_BLOCK_HANDLER_NONE) { + again: + switch (vm_block_handler_type(block_handler)) { + case block_handler_type_iseq: + captured = VM_BH_TO_CAPT_BLOCK(block_handler); + new_captured = *captured; + new_block_handler = VM_BH_FROM_ISEQ_BLOCK(&new_captured); + break; + case block_handler_type_ifunc: + captured = VM_BH_TO_CAPT_BLOCK(block_handler); + new_captured = *captured; + new_block_handler = VM_BH_FROM_IFUNC_BLOCK(&new_captured); + break; + case block_handler_type_proc: + block_handler = vm_proc_to_block_handler(VM_BH_TO_PROC(block_handler)); + goto again; + case block_handler_type_symbol: + return rb_sym_proc_call(SYM2ID(VM_BH_TO_SYMBOL(block_handler)), 1, &self, VM_BLOCK_HANDLER_NONE); + } + + new_captured.self = self; + ep = captured->ep; + + VM_FORCE_WRITE_SPECIAL_CONST(&VM_CF_LEP(th->cfp)[VM_ENV_DATA_INDEX_SPECVAL], new_block_handler); } - cref = vm_cref_push(th, under, blockptr, TRUE); + cref = vm_cref_push(th, under, ep, TRUE); return vm_yield_with_cref(th, argc, argv, cref); } @@ -1596,18 +1605,22 @@ VALUE rb_yield_refine_block(VALUE refinement, VALUE refinements) { rb_thread_t *th = GET_THREAD(); - rb_block_t block, *blockptr; - rb_cref_t *cref; + VALUE block_handler = VM_CF_BLOCK_HANDLER(th->cfp); - if ((blockptr = VM_CF_BLOCK_PTR(th->cfp)) != 0) { - block = *blockptr; - block.self = refinement; - VM_CF_LEP(th->cfp)[0] = VM_ENVVAL_BLOCK_PTR(&block); + if (vm_block_handler_type(block_handler) != block_handler_type_iseq) { + rb_bug("rb_yield_refine_block: an iseq block is required"); + } + else { + const struct rb_captured_block *captured = VM_BH_TO_ISEQ_BLOCK(block_handler); + struct rb_captured_block new_captured = *captured; + VALUE new_block_handler = VM_BH_FROM_ISEQ_BLOCK(&new_captured); + const VALUE *ep = captured->ep; + rb_cref_t *cref = vm_cref_push(th, refinement, ep, TRUE); + CREF_REFINEMENTS_SET(cref, refinements); + VM_FORCE_WRITE_SPECIAL_CONST(&VM_CF_LEP(th->cfp)[VM_ENV_DATA_INDEX_SPECVAL], new_block_handler); + new_captured.self = refinement; + return vm_yield_with_cref(th, 0, NULL, cref); } - cref = vm_cref_push(th, refinement, blockptr, TRUE); - CREF_REFINEMENTS_SET(cref, refinements); - - return vm_yield_with_cref(th, 0, NULL, cref); } /* string eval under the class/module context */ @@ -2093,9 +2106,9 @@ rb_f_local_variables(void) local_var_list_add(&vars, cfp->iseq->body->local_table[i]); } } - if (!VM_EP_LEP_P(cfp->ep)) { + if (!VM_ENV_LOCAL_P(cfp->ep)) { /* block */ - VALUE *ep = VM_CF_PREV_EP(cfp); + const VALUE *ep = VM_CF_PREV_EP(cfp); if (vm_collect_local_variables_in_heap(th, ep, &vars)) { break; @@ -2142,7 +2155,7 @@ rb_f_block_given_p(void) rb_control_frame_t *cfp = th->cfp; cfp = vm_get_ruby_level_caller_cfp(th, RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)); - if (cfp != 0 && VM_CF_BLOCK_PTR(cfp)) { + if (cfp != NULL && VM_CF_BLOCK_HANDLER(cfp) != VM_BLOCK_HANDLER_NONE) { return Qtrue; } else { |