summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compile.c59
-rw-r--r--iseq.c39
-rw-r--r--iseq.h1
-rw-r--r--proc.c9
-rw-r--r--template/prelude.c.tmpl2
-rw-r--r--test/ruby/test_proc.rb51
-rw-r--r--vm.c111
-rw-r--r--vm_core.h19
-rw-r--r--vm_eval.c25
9 files changed, 264 insertions, 52 deletions
diff --git a/compile.c b/compile.c
index 767e6c48e7..e0d4bc5455 100644
--- a/compile.c
+++ b/compile.c
@@ -1319,9 +1319,12 @@ new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
ast.line_count = -1;
debugs("[new_child_iseq]> ---------------------------------------\n");
+ int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
ret_iseq = rb_iseq_new_with_opt(&ast, name,
rb_iseq_path(iseq), rb_iseq_realpath(iseq),
- INT2FIX(line_no), parent, type, ISEQ_COMPILE_DATA(iseq)->option);
+ INT2FIX(line_no), parent,
+ isolated_depth ? isolated_depth + 1 : 0,
+ type, ISEQ_COMPILE_DATA(iseq)->option);
debugs("[new_child_iseq]< ---------------------------------------\n");
return ret_iseq;
}
@@ -1601,13 +1604,50 @@ iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
}
static void
-check_access_outer_variables(const rb_iseq_t *iseq, int level)
+access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
+{
+ int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
+
+ if (isolated_depth && level >= isolated_depth) {
+ if (id == rb_intern("yield")) {
+ COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc", rb_id2name(id));
+ }
+ else {
+ COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable `%s' from isolated Proc", rb_id2name(id));
+ }
+ }
+
+ for (int i=0; i<level; i++) {
+ VALUE val;
+ struct rb_id_table *ovs = iseq->body->outer_variables;
+
+ if (!ovs) {
+ ovs = iseq->body->outer_variables = rb_id_table_create(8);
+ }
+
+ if (rb_id_table_lookup(iseq->body->outer_variables, id, &val)) {
+ if (write && !val) {
+ rb_id_table_insert(iseq->body->outer_variables, id, Qtrue);
+ }
+ }
+ else {
+ rb_id_table_insert(iseq->body->outer_variables, id, write ? Qtrue : Qfalse);
+ }
+
+ iseq = iseq->body->parent_iseq;
+ }
+}
+
+static ID
+iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
{
- // set access_outer_variables
for (int i=0; i<level; i++) {
- iseq->body->access_outer_variables = TRUE;
iseq = iseq->body->parent_iseq;
}
+
+ ID id = iseq->body->local_table[iseq->body->local_table_size - idx];
+ // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
+ return id;
}
static void
@@ -1619,7 +1659,7 @@ iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, in
else {
ADD_INSN2(seq, line, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
}
- check_access_outer_variables(iseq, level);
+ if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
}
static void
@@ -1631,7 +1671,7 @@ iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, in
else {
ADD_INSN2(seq, line, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
}
- check_access_outer_variables(iseq, level);
+ if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
}
@@ -8215,7 +8255,12 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
ADD_INSN(ret, line, pop);
}
- iseq->body->access_outer_variables = TRUE;
+ int level = 0;
+ const rb_iseq_t *tmp_iseq = iseq;
+ for (; tmp_iseq != iseq->body->local_iseq; level++ ) {
+ tmp_iseq = tmp_iseq->body->parent_iseq;
+ }
+ if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
break;
}
case NODE_LVAR:{
diff --git a/iseq.c b/iseq.c
index 85ced1212c..449d3385cc 100644
--- a/iseq.c
+++ b/iseq.c
@@ -130,6 +130,7 @@ rb_iseq_free(const rb_iseq_t *iseq)
ruby_xfree((void *)body->param.keyword);
}
compile_data_free(ISEQ_COMPILE_DATA(iseq));
+ if (body->outer_variables) rb_id_table_free(body->outer_variables);
ruby_xfree(body);
}
@@ -575,8 +576,7 @@ new_arena(void)
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, const int node_id,
- const rb_iseq_t *parent, enum iseq_type type,
- const rb_compile_option_t *option)
+ const rb_iseq_t *parent, int isolated_depth, enum iseq_type type, const rb_compile_option_t *option)
{
VALUE coverage = Qfalse;
VALUE err_info = Qnil;
@@ -603,11 +603,11 @@ prepare_iseq_build(rb_iseq_t *iseq,
ISEQ_COMPILE_DATA(iseq)->node.storage_head = ISEQ_COMPILE_DATA(iseq)->node.storage_current = new_arena();
ISEQ_COMPILE_DATA(iseq)->insn.storage_head = ISEQ_COMPILE_DATA(iseq)->insn.storage_current = new_arena();
+ ISEQ_COMPILE_DATA(iseq)->isolated_depth = isolated_depth;
ISEQ_COMPILE_DATA(iseq)->option = option;
-
ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = NULL;
-
ISEQ_COMPILE_DATA(iseq)->builtin_function_table = GET_VM()->builtin_function_table;
+
if (option->coverage_enabled) {
VALUE coverages = rb_get_coverages();
@@ -794,8 +794,8 @@ rb_iseq_t *
rb_iseq_new(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath,
const rb_iseq_t *parent, enum iseq_type type)
{
- return rb_iseq_new_with_opt(ast, name, path, realpath, INT2FIX(0), parent, type,
- &COMPILE_OPTION_DEFAULT);
+ return rb_iseq_new_with_opt(ast, name, path, realpath, INT2FIX(0), parent,
+ 0, type, &COMPILE_OPTION_DEFAULT);
}
rb_iseq_t *
@@ -810,8 +810,8 @@ rb_iseq_new_top(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath
}
}
- return rb_iseq_new_with_opt(ast, name, path, realpath, INT2FIX(0), parent, ISEQ_TYPE_TOP,
- &COMPILE_OPTION_DEFAULT);
+ return rb_iseq_new_with_opt(ast, name, path, realpath, INT2FIX(0), parent, 0,
+ ISEQ_TYPE_TOP, &COMPILE_OPTION_DEFAULT);
}
rb_iseq_t *
@@ -819,7 +819,14 @@ rb_iseq_new_main(const rb_ast_body_t *ast, VALUE path, VALUE realpath, const rb_
{
return rb_iseq_new_with_opt(ast, rb_fstring_lit("<main>"),
path, realpath, INT2FIX(0),
- parent, ISEQ_TYPE_MAIN, &COMPILE_OPTION_DEFAULT);
+ parent, 0, ISEQ_TYPE_MAIN, &COMPILE_OPTION_DEFAULT);
+}
+
+rb_iseq_t *
+rb_iseq_new_eval(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_iseq_t *parent, int isolated_depth)
+{
+ return rb_iseq_new_with_opt(ast, name, path, realpath, first_lineno,
+ parent, isolated_depth, ISEQ_TYPE_EVAL, &COMPILE_OPTION_DEFAULT);
}
static inline rb_iseq_t *
@@ -838,8 +845,8 @@ iseq_translate(rb_iseq_t *iseq)
rb_iseq_t *
rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath,
- VALUE first_lineno, const rb_iseq_t *parent,
- enum iseq_type type, const rb_compile_option_t *option)
+ VALUE first_lineno, const rb_iseq_t *parent, int isolated_depth,
+ enum iseq_type type, const rb_compile_option_t *option)
{
const NODE *node = ast ? ast->root : 0;
/* TODO: argument check */
@@ -854,7 +861,7 @@ rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE rea
}
if (ast && ast->compile_option) rb_iseq_make_compile_option(&new_opt, ast->compile_option);
- prepare_iseq_build(iseq, name, path, realpath, first_lineno, node ? &node->nd_loc : NULL, node ? nd_node_id(node) : -1, parent, type, &new_opt);
+ prepare_iseq_build(iseq, name, path, realpath, first_lineno, node ? &node->nd_loc : NULL, node ? nd_node_id(node) : -1, parent, isolated_depth, type, &new_opt);
rb_iseq_compile_node(iseq, node);
finish_iseq_build(iseq);
@@ -873,7 +880,7 @@ rb_iseq_new_with_callback(
rb_iseq_t *iseq = iseq_alloc();
if (!option) option = &COMPILE_OPTION_DEFAULT;
- prepare_iseq_build(iseq, name, path, realpath, first_lineno, NULL, -1, parent, type, option);
+ prepare_iseq_build(iseq, name, path, realpath, first_lineno, NULL, -1, parent, 0, type, option);
rb_iseq_compile_callback(iseq, ifunc);
finish_iseq_build(iseq);
@@ -986,7 +993,7 @@ iseq_load(VALUE data, const rb_iseq_t *parent, VALUE opt)
make_compile_option(&option, opt);
option.peephole_optimization = FALSE; /* because peephole optimization can modify original iseq */
prepare_iseq_build(iseq, name, path, realpath, first_lineno, &tmp_loc, NUM2INT(node_id),
- parent, (enum iseq_type)iseq_type, &option);
+ parent, 0, (enum iseq_type)iseq_type, &option);
rb_iseq_build_from_ary(iseq, misc, locals, params, exception, body);
@@ -1054,7 +1061,7 @@ rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, V
else {
INITIALIZED VALUE label = rb_fstring_lit("<compiled>");
iseq = rb_iseq_new_with_opt(&ast->body, label, file, realpath, line,
- 0, ISEQ_TYPE_TOP, &option);
+ NULL, 0, ISEQ_TYPE_TOP, &option);
rb_ast_dispose(ast);
}
@@ -1310,7 +1317,7 @@ iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
ret = iseqw_new(rb_iseq_new_with_opt(&ast->body, rb_fstring_lit("<main>"),
file,
rb_realpath_internal(Qnil, file, 1),
- line, NULL, ISEQ_TYPE_TOP, &option));
+ line, NULL, 0, ISEQ_TYPE_TOP, &option));
rb_ast_dispose(ast);
return ret;
}
diff --git a/iseq.h b/iseq.h
index 4e427f557c..bae534c71d 100644
--- a/iseq.h
+++ b/iseq.h
@@ -105,6 +105,7 @@ struct iseq_compile_data {
int last_line;
int label_no;
int node_level;
+ int isolated_depth;
unsigned int ci_index;
const rb_compile_option_t *option;
struct rb_id_table *ivar_cache_table;
diff --git a/proc.c b/proc.c
index 061c6c34a6..5c78fc10ed 100644
--- a/proc.c
+++ b/proc.c
@@ -424,7 +424,11 @@ get_local_variable_ptr(const rb_env_t **envp, ID lid)
const rb_env_t *env = *envp;
do {
if (!VM_ENV_FLAGS(env->ep, VM_FRAME_FLAG_CFRAME)) {
- const rb_iseq_t *iseq = env->iseq;
+ if (VM_ENV_FLAGS(env->ep, VM_ENV_FLAG_ISOLATED)) {
+ return NULL;
+ }
+
+ const rb_iseq_t *iseq = env->iseq;
unsigned int i;
VM_ASSERT(rb_obj_is_iseq((VALUE)iseq));
@@ -3245,6 +3249,8 @@ proc_binding(VALUE self)
GetProcPtr(self, proc);
block = &proc->block;
+ if (proc->is_isolated) rb_raise(rb_eArgError, "Can't create Binding from isolated Proc");
+
again:
switch (vm_block_type(block)) {
case block_type_iseq:
@@ -4065,6 +4071,7 @@ Init_Proc(void)
rb_define_method(rb_cProc, "source_location", rb_proc_location, 0);
rb_define_method(rb_cProc, "parameters", rb_proc_parameters, 0);
rb_define_method(rb_cProc, "ruby2_keywords", proc_ruby2_keywords, 0);
+ // rb_define_method(rb_cProc, "isolate", rb_proc_isolate, 0); is not accepted.
/* Exceptions */
rb_eLocalJumpError = rb_define_class("LocalJumpError", rb_eStandardError);
diff --git a/template/prelude.c.tmpl b/template/prelude.c.tmpl
index 0ba6b0ba4b..eec8a32da9 100644
--- a/template/prelude.c.tmpl
+++ b/template/prelude.c.tmpl
@@ -202,7 +202,7 @@ prelude_eval(VALUE code, VALUE name, int line)
rb_ast_t *ast = prelude_ast(name, code, line);
rb_iseq_eval(rb_iseq_new_with_opt(&ast->body, name, name, Qnil, INT2FIX(line),
- NULL, ISEQ_TYPE_TOP, &optimization));
+ NULL, 0, ISEQ_TYPE_TOP, &optimization));
rb_ast_dispose(ast);
}
COMPILER_WARNING_POP
diff --git a/test/ruby/test_proc.rb b/test/ruby/test_proc.rb
index 0cc5d488c2..c1f17a003a 100644
--- a/test/ruby/test_proc.rb
+++ b/test/ruby/test_proc.rb
@@ -1538,6 +1538,57 @@ class TestProc < Test::Unit::TestCase
assert_equal(42, Module.new { extend self
def m1(&b) b end; def m2(); m1 { next 42 } end }.m2.call)
end
+
+ def test_isolate
+ assert_raise_with_message ArgumentError, /\(a\)/ do
+ a = :a
+ Proc.new{p a}.isolate.call
+ end
+
+ assert_raise_with_message ArgumentError, /\(a\)/ do
+ a = :a
+ 1.times{
+ Proc.new{p a}.isolate.call
+ }
+ end
+
+ assert_raise_with_message ArgumentError, /yield/ do
+ Proc.new{yield}.isolate.call
+ end
+
+ # binding
+
+ :a.tap{|a|
+ :b.tap{|b|
+ Proc.new{
+ :c.tap{|c|
+ assert_equal :c, eval('c')
+
+ assert_raise_with_message SyntaxError, /\`a\'/ do
+ eval('p a')
+ end
+
+ assert_raise_with_message SyntaxError, /\`b\'/ do
+ eval('p b')
+ end
+
+ assert_raise_with_message SyntaxError, /can not yield from isolated Proc/ do
+ eval('p yield')
+ end
+
+ assert_equal :c, binding.local_variable_get(:c)
+
+ assert_raise_with_message NameError, /local variable \`a\' is not defined/ do
+ binding.local_variable_get(:a)
+ end
+
+ assert_equal [:c], local_variables
+ assert_equal [:c], binding.local_variables
+ }
+ }.isolate.call
+ }
+ }
+ end if proc{}.respond_to? :isolate
end
class TestProcKeywords < Test::Unit::TestCase
diff --git a/vm.c b/vm.c
index 1f3d97b56d..27e39cf2ae 100644
--- a/vm.c
+++ b/vm.c
@@ -739,18 +739,17 @@ vm_make_env_each(const rb_execution_context_t * const ec, rb_control_frame_t *co
if (!VM_ENV_LOCAL_P(ep)) {
const VALUE *prev_ep = VM_ENV_PREV_EP(ep);
+ if (!VM_ENV_ESCAPED_P(prev_ep)) {
+ rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
- if (!VM_ENV_ESCAPED_P(prev_ep)) {
- rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
-
- while (prev_cfp->ep != prev_ep) {
- prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(prev_cfp);
- VM_ASSERT(prev_cfp->ep != NULL);
- }
+ while (prev_cfp->ep != prev_ep) {
+ prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(prev_cfp);
+ VM_ASSERT(prev_cfp->ep != NULL);
+ }
- vm_make_env_each(ec, prev_cfp);
- VM_FORCE_WRITE_SPECIAL_CONST(&ep[VM_ENV_DATA_INDEX_SPECVAL], VM_GUARDED_PREV_EP(prev_cfp->ep));
- }
+ vm_make_env_each(ec, prev_cfp);
+ VM_FORCE_WRITE_SPECIAL_CONST(&ep[VM_ENV_DATA_INDEX_SPECVAL], VM_GUARDED_PREV_EP(prev_cfp->ep));
+ }
}
else {
VALUE block_handler = VM_ENV_BLOCK_HANDLER(ep);
@@ -836,7 +835,8 @@ rb_vm_env_prev_env(const rb_env_t *env)
return NULL;
}
else {
- return VM_ENV_ENVVAL_PTR(VM_ENV_PREV_EP(ep));
+ const VALUE *prev_ep = VM_ENV_PREV_EP(ep);
+ return VM_ENV_ENVVAL_PTR(prev_ep);
}
}
@@ -855,6 +855,7 @@ static void
collect_local_variables_in_env(const rb_env_t *env, const struct local_var_list *vars)
{
do {
+ if (VM_ENV_FLAGS(env->ep, VM_ENV_FLAG_ISOLATED)) break;
collect_local_variables_in_iseq(env->iseq, vars);
} while ((env = rb_vm_env_prev_env(env)) != NULL);
}
@@ -963,17 +964,97 @@ rb_proc_dup(VALUE self)
return procval;
}
+struct collect_outer_variable_name_data {
+ VALUE ary;
+ bool yield;
+};
+
+static enum rb_id_table_iterator_result
+collect_outer_variable_names(ID id, VALUE val, void *ptr)
+{
+ struct collect_outer_variable_name_data *data = (struct collect_outer_variable_name_data *)ptr;
+
+ if (id == rb_intern("yield")) {
+ data->yield = true;
+ }
+ else {
+ if (data->ary == Qfalse) data->ary = rb_ary_new();
+ rb_ary_push(data->ary, rb_id2str(id));
+ }
+ return ID_TABLE_CONTINUE;
+}
+
+static const rb_env_t *
+env_copy(const VALUE *src_ep)
+{
+ const rb_env_t *src_env = (rb_env_t *)VM_ENV_ENVVAL(src_ep);
+ VALUE *env_body = ZALLOC_N(VALUE, src_env->env_size); // fill with Qfalse
+ VALUE *ep = &env_body[src_env->env_size - 2];
+
+ VM_ASSERT(src_env->ep == src_ep);
+
+ ep[VM_ENV_DATA_INDEX_ME_CREF] = src_ep[VM_ENV_DATA_INDEX_ME_CREF];
+ ep[VM_ENV_DATA_INDEX_FLAGS] = src_ep[VM_ENV_DATA_INDEX_FLAGS] | VM_ENV_FLAG_ISOLATED;
+
+ if (!VM_ENV_LOCAL_P(src_ep)) {
+ const VALUE *prev_ep = VM_ENV_PREV_EP(src_env->ep);
+ const rb_env_t *new_prev_env = env_copy(prev_ep);
+ ep[VM_ENV_DATA_INDEX_SPECVAL] = VM_GUARDED_PREV_EP(new_prev_env->ep);
+ }
+ else {
+ ep[VM_ENV_DATA_INDEX_SPECVAL] = VM_BLOCK_HANDLER_NONE;
+ }
+ return vm_env_new(ep, env_body, src_env->env_size, src_env->iseq);
+}
+
+static void
+proc_isolate_env(VALUE self, rb_proc_t *proc)
+{
+ const struct rb_captured_block *captured = &proc->block.as.captured;
+ const rb_env_t *env = env_copy(captured->ep);
+ *((const VALUE **)&proc->block.as.captured.ep) = env->ep;
+ RB_OBJ_WRITTEN(self, Qundef, env);
+}
+
VALUE
rb_proc_isolate_bang(VALUE self)
{
// check accesses
const rb_iseq_t *iseq = vm_proc_iseq(self);
- if (iseq && iseq->body->access_outer_variables) {
- rb_raise(rb_eArgError, "can not isolate a Proc because it can accesses outer variables.");
+
+ if (iseq) {
+ rb_proc_t *proc = (rb_proc_t *)RTYPEDDATA_DATA(self);
+ if (proc->block.type != block_type_iseq) rb_raise(rb_eRuntimeError, "not supported yet");
+
+ if (iseq->body->outer_variables) {
+ struct collect_outer_variable_name_data data = {
+ .ary = Qfalse,
+ .yield = false,
+ };
+
+ rb_id_table_foreach(iseq->body->outer_variables, collect_outer_variable_names, (void *)&data);
+
+ if (data.ary != Qfalse) {
+ VALUE str = rb_ary_join(data.ary, rb_str_new2(", "));
+ if (data.yield) {
+ rb_raise(rb_eArgError, "can not isolate a Proc because it accesses outer variables (%s) and uses `yield'.",
+ StringValueCStr(str));
+ }
+ else {
+ rb_raise(rb_eArgError, "can not isolate a Proc because it accesses outer variables (%s).",
+ StringValueCStr(str));
+ }
+ }
+ else {
+ VM_ASSERT(data.yield);
+ rb_raise(rb_eArgError, "can not isolate a Proc because it uses `yield'.");
+ }
+ }
+
+ proc_isolate_env(self, proc);
+ proc->is_isolated = TRUE;
}
- rb_proc_t *proc = (rb_proc_t *)RTYPEDDATA_DATA(self);
- proc->is_isolated = TRUE;
return self;
}
diff --git a/vm_core.h b/vm_core.h
index 02e777fb06..c4341b474c 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -418,7 +418,7 @@ struct rb_iseq_constant_body {
char catch_except_p; /* If a frame of this ISeq may catch exception, set TRUE */
bool builtin_inline_p; // This ISeq's builtin func is safe to be inlined by MJIT
- char access_outer_variables;
+ struct rb_id_table *outer_variables;
#if USE_MJIT
/* The following fields are MJIT related info. */
@@ -1017,11 +1017,13 @@ typedef enum {
RUBY_SYMBOL_EXPORT_BEGIN
/* node -> iseq */
-rb_iseq_t *rb_iseq_new (const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, enum iseq_type);
-rb_iseq_t *rb_iseq_new_top (const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent);
-rb_iseq_t *rb_iseq_new_main (const rb_ast_body_t *ast, VALUE path, VALUE realpath, const rb_iseq_t *parent);
-rb_iseq_t *rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno,
- const rb_iseq_t *parent, enum iseq_type, const rb_compile_option_t*);
+rb_iseq_t *rb_iseq_new (const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, enum iseq_type);
+rb_iseq_t *rb_iseq_new_top (const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent);
+rb_iseq_t *rb_iseq_new_main (const rb_ast_body_t *ast, VALUE path, VALUE realpath, const rb_iseq_t *parent);
+rb_iseq_t *rb_iseq_new_eval (const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_iseq_t *parent, int isolated_depth);
+rb_iseq_t *rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_iseq_t *parent, int isolated_depth,
+ enum iseq_type, const rb_compile_option_t*);
+
struct iseq_link_anchor;
struct rb_iseq_new_with_callback_callback_func {
VALUE flags;
@@ -1156,18 +1158,19 @@ enum {
VM_FRAME_MAGIC_MASK = 0x7fff0001,
/* frame flag */
- VM_FRAME_FLAG_PASSED = 0x0010,
VM_FRAME_FLAG_FINISH = 0x0020,
VM_FRAME_FLAG_BMETHOD = 0x0040,
VM_FRAME_FLAG_CFRAME = 0x0080,
VM_FRAME_FLAG_LAMBDA = 0x0100,
VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM = 0x0200,
VM_FRAME_FLAG_CFRAME_KW = 0x0400,
+ VM_FRAME_FLAG_PASSED = 0x0800,
/* env flag */
VM_ENV_FLAG_LOCAL = 0x0002,
VM_ENV_FLAG_ESCAPED = 0x0004,
- VM_ENV_FLAG_WB_REQUIRED = 0x0008
+ VM_ENV_FLAG_WB_REQUIRED = 0x0008,
+ VM_ENV_FLAG_ISOLATED = 0x0010,
};
#define VM_ENV_DATA_SIZE ( 3)
diff --git a/vm_eval.c b/vm_eval.c
index 3ada33e128..20117bb79d 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -1461,6 +1461,23 @@ eval_make_iseq(VALUE src, VALUE fname, int line, const rb_binding_t *bind,
VALUE realpath = Qnil;
rb_iseq_t *iseq = NULL;
rb_ast_t *ast;
+ int isolated_depth = 0;
+ {
+ int depth = 1;
+ const VALUE *ep = vm_block_ep(base_block);
+
+ while (1) {
+ if (VM_ENV_FLAGS(ep, VM_ENV_FLAG_ISOLATED)) {
+ isolated_depth = depth;
+ break;
+ }
+ else if (VM_ENV_LOCAL_P(ep)) {
+ break;
+ }
+ ep = VM_ENV_PREV_EP(ep);
+ depth++;
+ }
+ }
if (!fname) {
fname = rb_source_location(&line);
@@ -1477,10 +1494,10 @@ eval_make_iseq(VALUE src, VALUE fname, int line, const rb_binding_t *bind,
rb_parser_set_context(parser, parent, FALSE);
ast = rb_parser_compile_string_path(parser, fname, src, line);
if (ast->body.root) {
- iseq = rb_iseq_new_with_opt(&ast->body,
- parent->body->location.label,
- fname, realpath, INT2FIX(line),
- parent, ISEQ_TYPE_EVAL, NULL);
+ iseq = rb_iseq_new_eval(&ast->body,
+ parent->body->location.label,
+ fname, realpath, INT2FIX(line),
+ parent, isolated_depth);
}
rb_ast_dispose(ast);