summaryrefslogtreecommitdiff
path: root/vm_eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'vm_eval.c')
-rw-r--r--vm_eval.c153
1 files changed, 103 insertions, 50 deletions
diff --git a/vm_eval.c b/vm_eval.c
index b8694284d4..652fc4d85f 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -1,6 +1,6 @@
/**********************************************************************
- vm_eval.c -
+ vm_eval.c - Included into vm.c.
$Author$
created at: Sat May 24 16:02:32 JST 2008
@@ -57,7 +57,7 @@ static inline VALUE vm_call0_cc(rb_execution_context_t *ec, VALUE recv, ID id, i
VALUE
rb_vm_call0(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE *argv, const rb_callable_method_entry_t *cme, int kw_splat)
{
- const struct rb_callcache cc = VM_CC_ON_STACK(Qfalse, vm_call_general, {{ 0 }}, cme);
+ const struct rb_callcache cc = VM_CC_ON_STACK(Qundef, vm_call_general, {{ 0 }}, cme);
return vm_call0_cc(ec, recv, id, argc, argv, &cc, kw_splat);
}
@@ -104,7 +104,7 @@ vm_call0_cc(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE
static VALUE
vm_call0_cme(rb_execution_context_t *ec, struct rb_calling_info *calling, const VALUE *argv, const rb_callable_method_entry_t *cme)
{
- calling->cc = &VM_CC_ON_STACK(Qfalse, vm_call_general, {{ 0 }}, cme);
+ calling->cc = &VM_CC_ON_STACK(Qundef, vm_call_general, {{ 0 }}, cme);
return vm_call0_body(ec, calling, argv);
}
@@ -400,9 +400,9 @@ static inline const rb_callable_method_entry_t *rb_search_method_entry(VALUE rec
static inline enum method_missing_reason rb_method_call_status(rb_execution_context_t *ec, const rb_callable_method_entry_t *me, call_type scope, VALUE self);
static VALUE
-gccct_hash(VALUE klass, ID mid)
+gccct_hash(VALUE klass, VALUE box_value, ID mid)
{
- return (klass >> 3) ^ (VALUE)mid;
+ return ((klass ^ box_value) >> 3) ^ (VALUE)mid;
}
NOINLINE(static const struct rb_callcache *gccct_method_search_slowpath(rb_vm_t *vm, VALUE klass, unsigned int index, const struct rb_callinfo * ci));
@@ -447,7 +447,8 @@ scope_to_ci(call_type scope, ID mid, int argc, struct rb_callinfo *ci)
static inline const struct rb_callcache *
gccct_method_search(rb_execution_context_t *ec, VALUE recv, ID mid, const struct rb_callinfo *ci)
{
- VALUE klass;
+ VALUE klass, box_value;
+ const rb_box_t *box = rb_current_box();
if (!SPECIAL_CONST_P(recv)) {
klass = RBASIC_CLASS(recv);
@@ -457,8 +458,14 @@ gccct_method_search(rb_execution_context_t *ec, VALUE recv, ID mid, const struct
klass = CLASS_OF(recv);
}
+ if (BOX_USER_P(box)) {
+ box_value = box->box_object;
+ }
+ else {
+ box_value = 0;
+ }
// search global method cache
- unsigned int index = (unsigned int)(gccct_hash(klass, mid) % VM_GLOBAL_CC_CACHE_TABLE_SIZE);
+ unsigned int index = (unsigned int)(gccct_hash(klass, box_value, mid) % VM_GLOBAL_CC_CACHE_TABLE_SIZE);
rb_vm_t *vm = rb_ec_vm_ptr(ec);
const struct rb_callcache *cc = vm->global_cc_cache_table[index];
@@ -483,6 +490,17 @@ gccct_method_search(rb_execution_context_t *ec, VALUE recv, ID mid, const struct
return gccct_method_search_slowpath(vm, klass, index, ci);
}
+VALUE
+rb_gccct_clear_table(VALUE _self)
+{
+ int i;
+ rb_vm_t *vm = GET_VM();
+ for (i=0; i<VM_GLOBAL_CC_CACHE_TABLE_SIZE; i++) {
+ vm->global_cc_cache_table[i] = NULL;
+ }
+ return Qnil;
+}
+
/**
* @internal
* calls the specified method.
@@ -1361,6 +1379,17 @@ rb_yield(VALUE val)
}
}
+VALUE
+rb_ec_yield(rb_execution_context_t *ec, VALUE val)
+{
+ if (UNDEF_P(val)) {
+ return vm_yield(ec, 0, NULL, RB_NO_KEYWORDS);
+ }
+ else {
+ return vm_yield(ec, 1, &val, RB_NO_KEYWORDS);
+ }
+}
+
#undef rb_yield_values
VALUE
rb_yield_values(int n, ...)
@@ -1504,13 +1533,6 @@ rb_iterate_internal(VALUE (* it_proc)(VALUE), VALUE data1,
GET_EC());
}
-VALUE
-rb_iterate(VALUE (* it_proc)(VALUE), VALUE data1,
- rb_block_call_func_t bl_proc, VALUE data2)
-{
- return rb_iterate_internal(it_proc, data1, bl_proc, data2);
-}
-
struct iter_method_arg {
VALUE obj;
ID mid;
@@ -1651,6 +1673,24 @@ get_eval_default_path(void)
return eval_default_path;
}
+static inline int
+compute_isolated_depth_from_ep(const VALUE *ep)
+{
+ int depth = 1;
+ while (1) {
+ if (VM_ENV_FLAGS(ep, VM_ENV_FLAG_ISOLATED)) return depth;
+ if (VM_ENV_LOCAL_P(ep)) return 0;
+ ep = VM_ENV_PREV_EP(ep);
+ depth++;
+ }
+}
+
+static inline int
+compute_isolated_depth_from_block(const struct rb_block *blk)
+{
+ return compute_isolated_depth_from_ep(vm_block_ep(blk));
+}
+
static const rb_iseq_t *
pm_eval_make_iseq(VALUE src, VALUE fname, int line,
const struct rb_block *base_block)
@@ -1659,8 +1699,8 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
const rb_iseq_t *iseq = parent;
VALUE name = rb_fstring_lit("<compiled>");
- // Conditionally enable coverage depending on the current mode:
int coverage_enabled = ((rb_get_coverage_mode() & COVERAGE_TARGET_EVAL) != 0) ? 1 : 0;
+ int isolated_depth = compute_isolated_depth_from_block(base_block);
if (!fname) {
fname = rb_source_location(&line);
@@ -1854,7 +1894,7 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
#undef FORWARDING_ALL_STR
int error_state;
- iseq = pm_iseq_new_eval(&result.node, name, fname, Qnil, line, parent, 0, &error_state);
+ iseq = pm_iseq_new_eval(&result.node, name, fname, Qnil, line, parent, isolated_depth, &error_state);
pm_scope_node_t *prev = result.node.previous;
while (prev) {
@@ -1890,27 +1930,9 @@ eval_make_iseq(VALUE src, VALUE fname, int line,
rb_iseq_t *iseq = NULL;
VALUE ast_value;
rb_ast_t *ast;
- int isolated_depth = 0;
- // Conditionally enable coverage depending on the current mode:
int coverage_enabled = (rb_get_coverage_mode() & COVERAGE_TARGET_EVAL) != 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++;
- }
- }
+ int isolated_depth = compute_isolated_depth_from_block(base_block);
if (!fname) {
fname = rb_source_location(&line);
@@ -1967,6 +1989,10 @@ eval_string_with_cref(VALUE self, VALUE src, rb_cref_t *cref, VALUE file, int li
block.as.captured.code.iseq = cfp->iseq;
block.type = block_type_iseq;
+ // EP is not escaped to the heap here, but captured and reused by another frame.
+ // ZJIT's locals are incompatible with it unlike YJIT's, so invalidate the ISEQ for ZJIT.
+ rb_zjit_invalidate_no_ep_escape(cfp->iseq);
+
iseq = eval_make_iseq(src, file, line, &block);
if (!iseq) {
rb_exc_raise(ec->errinfo);
@@ -2005,21 +2031,38 @@ eval_string_with_scope(VALUE scope, VALUE src, VALUE file, int line)
}
/*
- * call-seq:
- * eval(string [, binding [, filename [,lineno]]]) -> obj
+ * call-seq:
+ * eval(string, binding = nil, filename = default_filename, lineno = 1) -> obj
*
- * Evaluates the Ruby expression(s) in <em>string</em>. If
- * <em>binding</em> is given, which must be a Binding object, the
- * evaluation is performed in its context. If the optional
- * <em>filename</em> and <em>lineno</em> parameters are present, they
- * will be used when reporting syntax errors.
+ * Evaluates the Ruby expression(s) in +string+. Returns the result of the last
+ * expression.
*
- * def get_binding(str)
- * return binding
- * end
- * str = "hello"
- * eval "str + ' Fred'" #=> "hello Fred"
- * eval "str + ' Fred'", get_binding("bye") #=> "bye Fred"
+ * str = "Hello"
+ * eval("str + ' World'") # => "Hello World"
+ *
+ * If +binding+ is given, which must be a Binding object, the
+ * evaluation is performed in its context. Otherwise, the
+ * evaluation is performed in the context of the caller.
+ *
+ * def get_binding(str) = binding
+ * str = "Hello"
+ * eval("str + ' World'", get_binding("Bye")) # => "Bye World"
+ *
+ * If the optional +filename+ is given, it will be used as the
+ * filename of the evaluation (for <tt>__FILE__</tt> and errors).
+ * Otherwise, it will default to <tt>(eval at __FILE__:__LINE__)</tt>
+ * where <tt>__FILE__</tt> and <tt>__LINE__</tt> are the filename and
+ * line number of the caller, respectively.
+ *
+ * eval("puts __FILE__") # => "(eval at test.rb:1)"
+ * eval("puts __FILE__", nil, "foobar.rb") # => "foobar.rb"
+ *
+ * If the optional +lineno+ is given, it will be used as the
+ * line number of the evaluation (for <tt>__LINE__</tt> and errors).
+ * Otherwise, it will default to 1.
+ *
+ * eval("puts __LINE__") # => 1
+ * eval("puts __LINE__", nil, "foobar.rb", 10) # => 10
*/
VALUE
@@ -2126,6 +2169,17 @@ rb_eval_string_wrap(const char *str, int *pstate)
VALUE
rb_eval_cmd_kw(VALUE cmd, VALUE arg, int kw_splat)
{
+ Check_Type(arg, T_ARRAY);
+ int argc = RARRAY_LENINT(arg);
+ const VALUE *argv = RARRAY_CONST_PTR(arg);
+ VALUE val = rb_eval_cmd_call_kw(cmd, argc, argv, kw_splat);
+ RB_GC_GUARD(arg);
+ return val;
+}
+
+VALUE
+rb_eval_cmd_call_kw(VALUE cmd, int argc, const VALUE *argv, int kw_splat)
+{
enum ruby_tag_type state;
volatile VALUE val = Qnil; /* OK */
rb_execution_context_t * volatile ec = GET_EC();
@@ -2133,8 +2187,7 @@ rb_eval_cmd_kw(VALUE cmd, VALUE arg, int kw_splat)
EC_PUSH_TAG(ec);
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
if (!RB_TYPE_P(cmd, T_STRING)) {
- val = rb_funcallv_kw(cmd, idCall, RARRAY_LENINT(arg),
- RARRAY_CONST_PTR(arg), kw_splat);
+ val = rb_funcallv_kw(cmd, idCall, argc, argv, kw_splat);
}
else {
val = eval_string_with_cref(rb_vm_top_self(), cmd, NULL, 0, 0);