summaryrefslogtreecommitdiff
path: root/vm_eval.c
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-07-28 11:02:30 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-07-28 11:02:30 +0000
commit9f60791a0412cae804f13ed3e746a634c7a0731b (patch)
tree49b3f9ff4924a622e13fbdfc9478d34717d19378 /vm_eval.c
parent683eafd973e4db60756f6ee12e1b066e316f026f (diff)
* 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.c185
1 files changed, 99 insertions, 86 deletions
diff --git a/vm_eval.c b/vm_eval.c
index 7e131b28e7..4ef4d6e582 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -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 = &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 {