2006-12-31 18:02:22 +03:00
|
|
|
/**********************************************************************
|
|
|
|
|
2020-03-09 20:22:11 +03:00
|
|
|
Vm.c -
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
$Author$
|
|
|
|
|
2007-02-05 15:21:01 +03:00
|
|
|
Copyright (C) 2004-2007 Koichi Sasada
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
**********************************************************************/
|
|
|
|
|
2018-07-24 15:12:59 +03:00
|
|
|
#define vm_exec rb_vm_exec
|
|
|
|
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "eval_intern.h"
|
|
|
|
#include "internal.h"
|
2023-02-15 12:42:52 +03:00
|
|
|
#include "internal/class.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "internal/compile.h"
|
|
|
|
#include "internal/cont.h"
|
|
|
|
#include "internal/error.h"
|
2023-10-12 21:15:53 +03:00
|
|
|
#include "internal/encoding.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "internal/eval.h"
|
2023-02-08 14:56:53 +03:00
|
|
|
#include "internal/gc.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "internal/inits.h"
|
2024-01-09 21:17:17 +03:00
|
|
|
#include "internal/missing.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "internal/object.h"
|
|
|
|
#include "internal/proc.h"
|
|
|
|
#include "internal/re.h"
|
2023-05-28 14:00:20 +03:00
|
|
|
#include "internal/ruby_parser.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "internal/symbol.h"
|
2021-07-16 06:43:57 +03:00
|
|
|
#include "internal/thread.h"
|
2023-10-12 21:15:53 +03:00
|
|
|
#include "internal/transcode.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "internal/vm.h"
|
2020-09-26 01:01:23 +03:00
|
|
|
#include "internal/sanitizers.h"
|
2022-10-03 18:14:32 +03:00
|
|
|
#include "internal/variable.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "iseq.h"
|
2023-03-07 10:17:25 +03:00
|
|
|
#include "rjit.h"
|
2021-09-08 19:01:39 +03:00
|
|
|
#include "yjit.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "ruby/st.h"
|
|
|
|
#include "ruby/vm.h"
|
* common.mk: clean up
- remove blockinlining.$(OBJEXT) to built
- make ENCODING_H_INCLDUES variable (include/ruby/encoding.h)
- make VM_CORE_H_INCLUDES variable (vm_core.h)
- simplify rules.
- make depends rule to output depend status using gcc -MM.
* include/ruby/mvm.h, include/ruby/vm.h: rename mvm.h to vm.h.
* include/ruby.h: ditto.
* load.c: add inclusion explicitly.
* enumerator.c, object.c, parse.y, thread.c, vm_dump.c:
remove useless inclusion.
* eval_intern.h: cleanup inclusion.
* vm_core.h: rb_thread_t should be defined in this file.
* vm_evalbody.c, vm_exec.c: rename vm_evalbody.c to vm_exec.c.
* vm.h, vm_exec.h: rename vm.h to vm_exec.h.
* insnhelper.h, vm_insnhelper.h: rename insnhelper.h to vm_insnhelper.h.
* vm.c, vm_insnhelper.c, vm_insnhelper.h:
- rename vm_eval() to vm_exec_core().
- rename vm_eval_body() to vm_exec().
- cleanup include order.
* vm_method.c: fix comment.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19466 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-09-23 04:20:28 +04:00
|
|
|
#include "vm_core.h"
|
VALUE size packed callinfo (ci).
Now, rb_call_info contains how to call the method with tuple of
(mid, orig_argc, flags, kwarg). Most of cases, kwarg == NULL and
mid+argc+flags only requires 64bits. So this patch packed
rb_call_info to VALUE (1 word) on such cases. If we can not
represent it in VALUE, then use imemo_callinfo which contains
conventional callinfo (rb_callinfo, renamed from rb_call_info).
iseq->body->ci_kw_size is removed because all of callinfo is VALUE
size (packed ci or a pointer to imemo_callinfo).
To access ci information, we need to use these functions:
vm_ci_mid(ci), _flag(ci), _argc(ci), _kwarg(ci).
struct rb_call_info_kw_arg is renamed to rb_callinfo_kwarg.
rb_funcallv_with_cc() and rb_method_basic_definition_p_with_cc()
is temporary removed because cd->ci should be marked.
2020-01-08 02:20:36 +03:00
|
|
|
#include "vm_callinfo.h"
|
2018-01-09 09:24:11 +03:00
|
|
|
#include "vm_debug.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "vm_exec.h"
|
|
|
|
#include "vm_insnhelper.h"
|
2020-11-17 10:40:47 +03:00
|
|
|
#include "ractor_core.h"
|
2020-03-09 20:22:11 +03:00
|
|
|
#include "vm_sync.h"
|
2023-02-17 16:32:51 +03:00
|
|
|
#include "shape.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
|
2019-11-07 10:58:00 +03:00
|
|
|
#include "builtin.h"
|
|
|
|
|
* probes.d: add DTrace probe declarations. [ruby-core:27448]
* array.c (empty_ary_alloc, ary_new): added array create DTrace probe.
* compile.c (rb_insns_name): allowing DTrace probes to access
instruction sequence name.
* Makefile.in: translate probes.d file to appropriate header file.
* common.mk: declare dependencies on the DTrace header.
* configure.in: add a test for existence of DTrace.
* eval.c (setup_exception): add a probe for when an exception is
raised.
* gc.c: Add DTrace probes for mark begin and end, and sweep begin and
end.
* hash.c (empty_hash_alloc): Add a probe for hash allocation.
* insns.def: Add probes for function entry and return.
* internal.h: function declaration for compile.c change.
* load.c (rb_f_load): add probes for `load` entry and exit, require
entry and exit, and wrapping search_required for load path search.
* object.c (rb_obj_alloc): added a probe for general object creation.
* parse.y (yycompile0): added a probe around parse and compile phase.
* string.c (empty_str_alloc, str_new): DTrace probes for string
allocation.
* test/dtrace/*: tests for DTrace probes.
* vm.c (vm_invoke_proc): add probes for function return on exception
raise, hash create, and instruction sequence execution.
* vm_core.h: add probe declarations for function entry and exit.
* vm_dump.c: add probes header file.
* vm_eval.c (vm_call0_cfunc, vm_call0_cfunc_with_frame): add probe on
function entry and return.
* vm_exec.c: expose instruction number to instruction name function.
* vm_insnshelper.c: add function entry and exit probes for cfunc
methods.
* vm_insnhelper.h: vm usage information is always collected, so
uncomment the functions.
12 19:14:50 2012 Akinori MUSHA <knu@iDaemons.org>
* configure.in (isinf, isnan): isinf() and isnan() are macros on
DragonFly which cannot be found by AC_REPLACE_FUNCS(). This
workaround enforces the fact that they exist on DragonFly.
12 15:59:38 2012 Shugo Maeda <shugo@ruby-lang.org>
* vm_core.h (rb_call_info_t::refinements), compile.c (new_callinfo),
vm_insnhelper.c (vm_search_method): revert r37616 because it's too
slow. [ruby-dev:46477]
* test/ruby/test_refinement.rb (test_inline_method_cache): skip
the test until the bug is fixed efficiently.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-11-13 01:52:12 +04:00
|
|
|
#include "probes.h"
|
2012-11-18 20:30:10 +04:00
|
|
|
#include "probes_helper.h"
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2022-05-16 15:50:02 +03:00
|
|
|
#ifdef RUBY_ASSERT_CRITICAL_SECTION
|
|
|
|
int ruby_assert_critical_section_entered = 0;
|
2022-05-15 07:07:12 +03:00
|
|
|
#endif
|
|
|
|
|
Pass down "stack start" variables from closer to the top of the stack
This commit changes how stack extents are calculated for both the main
thread and other threads. Ruby uses the address of a local variable as
part of the calculation for machine stack extents:
* pthreads uses it as a lower-bound on the start of the stack, because
glibc (and maybe other libcs) can store its own data on the stack
before calling into user code on thread creation.
* win32 uses it as an argument to VirtualQuery, which gets the extent of
the memory mapping which contains the variable
However, the local being used for this is actually too low (too close to
the leaf function call) in both the main thread case and the new thread
case.
In the main thread case, we have the `INIT_STACK` macro, which is used
for pthreads to set the `native_main_thread->stack_start` value. This
value is correctly captured at the very top level of the program (in
main.c). However, this is _not_ what's used to set the execution context
machine stack (`th->ec->machine_stack.stack_start`); that gets set as
part of a call to `ruby_thread_init_stack` in `Init_BareVM`, using the
address of a local variable allocated _inside_ `Init_BareVM`. This is
too low; we need to use a local allocated closer to the top of the
program.
In the new thread case, the lolcal is allocated inside
`native_thread_init_stack`, which is, again, too low.
In both cases, this means that we might have VALUEs lying outside the
bounds of `th->ec->machine.stack_{start,end}`, which won't be marked
correctly by the GC machinery.
To fix this,
* In the main thread case: We already have `INIT_STACK` at the right
level, so just pass that local var to `ruby_thread_init_stack`.
* In the new thread case: Allocate the local one level above the call to
`native_thread_init_stack` in `call_thread_start_func2`.
[Bug #20001]
fix
2023-11-12 05:24:55 +03:00
|
|
|
static void *native_main_thread_stack_top;
|
|
|
|
|
2016-04-05 11:15:22 +03:00
|
|
|
VALUE rb_str_concat_literals(size_t, const VALUE*);
|
2015-09-29 10:37:40 +03:00
|
|
|
|
2023-03-15 00:00:19 +03:00
|
|
|
VALUE vm_exec(rb_execution_context_t *);
|
2018-12-26 03:59:37 +03:00
|
|
|
|
2022-12-08 04:09:30 +03:00
|
|
|
extern const char *const rb_debug_counter_names[];
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
PUREFUNC(static inline const VALUE *VM_EP_LEP(const VALUE *));
|
|
|
|
static inline const VALUE *
|
|
|
|
VM_EP_LEP(const VALUE *ep)
|
2012-06-11 07:14:59 +04:00
|
|
|
{
|
2016-07-28 14:02:30 +03:00
|
|
|
while (!VM_ENV_LOCAL_P(ep)) {
|
|
|
|
ep = VM_ENV_PREV_EP(ep);
|
2012-06-11 07:14:59 +04:00
|
|
|
}
|
2013-04-29 12:44:16 +04:00
|
|
|
return ep;
|
2012-06-11 07:14:59 +04:00
|
|
|
}
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
static inline const rb_control_frame_t *
|
2017-10-26 13:49:33 +03:00
|
|
|
rb_vm_search_cf_from_ep(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, const VALUE * const ep)
|
2015-01-16 05:54:22 +03:00
|
|
|
{
|
|
|
|
if (!ep) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else {
|
2017-10-26 13:49:33 +03:00
|
|
|
const rb_control_frame_t * const eocfp = RUBY_VM_END_CONTROL_FRAME(ec); /* end of control frame pointer */
|
2015-01-16 05:54:22 +03:00
|
|
|
|
|
|
|
while (cfp < eocfp) {
|
|
|
|
if (cfp->ep == ep) {
|
|
|
|
return cfp;
|
|
|
|
}
|
|
|
|
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:01:40 +03:00
|
|
|
return NULL;
|
2015-01-16 05:54:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
const VALUE *
|
|
|
|
rb_vm_ep_local_ep(const VALUE *ep)
|
2012-06-11 07:14:59 +04:00
|
|
|
{
|
|
|
|
return VM_EP_LEP(ep);
|
|
|
|
}
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
PUREFUNC(static inline const VALUE *VM_CF_LEP(const rb_control_frame_t * const cfp));
|
|
|
|
static inline const VALUE *
|
2015-01-16 11:21:49 +03:00
|
|
|
VM_CF_LEP(const rb_control_frame_t * const cfp)
|
2012-06-11 07:14:59 +04:00
|
|
|
{
|
|
|
|
return VM_EP_LEP(cfp->ep);
|
|
|
|
}
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
static inline const VALUE *
|
2015-01-16 11:21:49 +03:00
|
|
|
VM_CF_PREV_EP(const rb_control_frame_t * const cfp)
|
2012-06-11 07:14:59 +04:00
|
|
|
{
|
2016-07-28 14:02:30 +03:00
|
|
|
return VM_ENV_PREV_EP(cfp->ep);
|
|
|
|
}
|
|
|
|
|
|
|
|
PUREFUNC(static inline VALUE VM_CF_BLOCK_HANDLER(const rb_control_frame_t * const cfp));
|
|
|
|
static inline VALUE
|
|
|
|
VM_CF_BLOCK_HANDLER(const rb_control_frame_t * const cfp)
|
|
|
|
{
|
|
|
|
const VALUE *ep = VM_CF_LEP(cfp);
|
|
|
|
return VM_ENV_BLOCK_HANDLER(ep);
|
|
|
|
}
|
|
|
|
|
2019-09-03 21:32:02 +03:00
|
|
|
int
|
|
|
|
rb_vm_cframe_keyword_p(const rb_control_frame_t *cfp)
|
|
|
|
{
|
|
|
|
return VM_FRAME_CFRAME_KW_P(cfp);
|
|
|
|
}
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
VALUE
|
|
|
|
rb_vm_frame_block_handler(const rb_control_frame_t *cfp)
|
|
|
|
{
|
|
|
|
return VM_CF_BLOCK_HANDLER(cfp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if VM_CHECK_MODE > 0
|
|
|
|
static int
|
2017-10-26 13:50:45 +03:00
|
|
|
VM_CFP_IN_HEAP_P(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
|
2016-07-28 14:02:30 +03:00
|
|
|
{
|
2017-10-26 13:50:45 +03:00
|
|
|
const VALUE *start = ec->vm_stack;
|
|
|
|
const VALUE *end = (VALUE *)ec->vm_stack + ec->vm_stack_size;
|
2017-08-03 00:48:51 +03:00
|
|
|
VM_ASSERT(start != NULL);
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
if (start <= (VALUE *)cfp && (VALUE *)cfp < end) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2017-09-06 06:39:26 +03:00
|
|
|
VM_EP_IN_HEAP_P(const rb_execution_context_t *ec, const VALUE *ep)
|
2016-07-28 14:02:30 +03:00
|
|
|
{
|
2017-09-06 06:39:26 +03:00
|
|
|
const VALUE *start = ec->vm_stack;
|
|
|
|
const VALUE *end = (VALUE *)ec->cfp;
|
2017-08-03 00:48:51 +03:00
|
|
|
VM_ASSERT(start != NULL);
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
if (start <= ep && ep < end) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-15 12:56:44 +03:00
|
|
|
static int
|
2017-09-06 06:39:26 +03:00
|
|
|
vm_ep_in_heap_p_(const rb_execution_context_t *ec, const VALUE *ep)
|
2016-07-28 14:02:30 +03:00
|
|
|
{
|
2017-09-06 06:39:26 +03:00
|
|
|
if (VM_EP_IN_HEAP_P(ec, ep)) {
|
2016-07-28 14:02:30 +03:00
|
|
|
VALUE envval = ep[VM_ENV_DATA_INDEX_ENV]; /* VM_ENV_ENVVAL(ep); */
|
|
|
|
|
2022-11-15 07:24:08 +03:00
|
|
|
if (!UNDEF_P(envval)) {
|
2016-07-28 22:13:26 +03:00
|
|
|
const rb_env_t *env = (const rb_env_t *)envval;
|
2016-07-28 14:02:30 +03:00
|
|
|
|
2016-07-28 22:13:26 +03:00
|
|
|
VM_ASSERT(vm_assert_env(envval));
|
2016-07-28 14:02:30 +03:00
|
|
|
VM_ASSERT(VM_ENV_FLAGS(ep, VM_ENV_FLAG_ESCAPED));
|
|
|
|
VM_ASSERT(env->ep == ep);
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rb_vm_ep_in_heap_p(const VALUE *ep)
|
|
|
|
{
|
2017-10-26 13:52:05 +03:00
|
|
|
const rb_execution_context_t *ec = GET_EC();
|
|
|
|
if (ec->vm_stack == NULL) return TRUE;
|
|
|
|
return vm_ep_in_heap_p_(ec, ep);
|
2012-06-11 07:14:59 +04:00
|
|
|
}
|
2016-07-28 14:02:30 +03:00
|
|
|
#endif
|
2012-06-11 07:14:59 +04:00
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
static struct rb_captured_block *
|
|
|
|
VM_CFP_TO_CAPTURED_BLOCK(const rb_control_frame_t *cfp)
|
2012-06-11 07:14:59 +04:00
|
|
|
{
|
2017-10-26 13:50:45 +03:00
|
|
|
VM_ASSERT(!VM_CFP_IN_HEAP_P(GET_EC(), cfp));
|
2016-07-28 14:02:30 +03:00
|
|
|
return (struct rb_captured_block *)&cfp->self;
|
2012-06-11 07:14:59 +04:00
|
|
|
}
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
static rb_control_frame_t *
|
|
|
|
VM_CAPTURED_BLOCK_TO_CFP(const struct rb_captured_block *captured)
|
2012-06-11 07:14:59 +04:00
|
|
|
{
|
2016-07-28 14:02:30 +03:00
|
|
|
rb_control_frame_t *cfp = ((rb_control_frame_t *)((VALUE *)(captured) - 3));
|
2017-10-26 13:50:45 +03:00
|
|
|
VM_ASSERT(!VM_CFP_IN_HEAP_P(GET_EC(), cfp));
|
2023-07-17 20:57:58 +03:00
|
|
|
VM_ASSERT(sizeof(rb_control_frame_t)/sizeof(VALUE) == 7 + VM_DEBUG_BP_CHECK ? 1 : 0);
|
2016-07-28 14:02:30 +03:00
|
|
|
return cfp;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
VM_BH_FROM_CFP_P(VALUE block_handler, const rb_control_frame_t *cfp)
|
|
|
|
{
|
|
|
|
const struct rb_captured_block *captured = VM_CFP_TO_CAPTURED_BLOCK(cfp);
|
|
|
|
return VM_TAGGED_PTR_REF(block_handler, 0x03) == captured;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2017-10-28 13:01:54 +03:00
|
|
|
vm_passed_block_handler(rb_execution_context_t *ec)
|
2016-07-28 14:02:30 +03:00
|
|
|
{
|
2017-10-28 13:01:54 +03:00
|
|
|
VALUE block_handler = ec->passed_block_handler;
|
|
|
|
ec->passed_block_handler = VM_BLOCK_HANDLER_NONE;
|
2017-06-08 08:22:49 +03:00
|
|
|
vm_block_handler_verify(block_handler);
|
2016-07-28 14:02:30 +03:00
|
|
|
return block_handler;
|
2012-06-11 07:14:59 +04:00
|
|
|
}
|
|
|
|
|
2015-03-09 00:22:43 +03:00
|
|
|
static rb_cref_t *
|
2021-12-03 02:53:39 +03:00
|
|
|
vm_cref_new0(VALUE klass, rb_method_visibility_t visi, int module_func, rb_cref_t *prev_cref, int pushed_by_eval, int use_prev_prev, int singleton)
|
* fix namespace issue on singleton class expressions. [Bug #10943]
* vm_core.h, method.h: remove rb_iseq_t::cref_stack. CREF is stored
to rb_method_definition_t::body.iseq_body.cref.
* vm_insnhelper.c: modify SVAR usage.
When calling ISEQ type method, push CREF information onto method
frame, SVAR located place. Before this fix, SVAR is simply nil.
After this patch, CREF (or NULL == Qfalse for not iseq methods)
is stored at the method invocation.
When SVAR is requierd, then put NODE_IF onto SVAR location,
and NDOE_IF::nd_reserved points CREF itself.
* vm.c (vm_cref_new, vm_cref_dump, vm_cref_new_toplevel): added.
* vm_insnhelper.c (vm_push_frame): accept CREF.
* method.h, vm_method.c (rb_add_method_iseq): added. This function
accepts iseq and CREF.
* class.c (clone_method): use rb_add_method_iseq().
* gc.c (mark_method_entry): mark method_entry::body.iseq_body.cref.
* iseq.c: remove CREF related codes.
* insns.def (getinlinecache/setinlinecache): CREF should be cache key
because a different CREF has a different namespace.
* node.c (rb_gc_mark_node): mark NODE_IF::nd_reserved for SVAR.
* proc.c: catch up changes.
* struct.c: ditto.
* insns.def: ditto.
* vm_args.c (raise_argument_error): ditto.
* vm_eval.c: ditto.
* test/ruby/test_class.rb: add a test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49874 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-03-06 15:24:58 +03:00
|
|
|
{
|
2015-11-13 23:02:19 +03:00
|
|
|
VALUE refinements = Qnil;
|
|
|
|
int omod_shared = FALSE;
|
|
|
|
|
|
|
|
/* scope */
|
2015-06-05 14:42:34 +03:00
|
|
|
union {
|
|
|
|
rb_scope_visibility_t visi;
|
|
|
|
VALUE value;
|
|
|
|
} scope_visi;
|
2015-11-13 23:02:19 +03:00
|
|
|
|
2015-06-05 14:42:34 +03:00
|
|
|
scope_visi.visi.method_visi = visi;
|
2015-11-13 23:02:19 +03:00
|
|
|
scope_visi.visi.module_func = module_func;
|
|
|
|
|
|
|
|
/* refinements */
|
|
|
|
if (prev_cref != NULL && prev_cref != (void *)1 /* TODO: why CREF_NEXT(cref) is 1? */) {
|
|
|
|
refinements = CREF_REFINEMENTS(prev_cref);
|
|
|
|
|
|
|
|
if (!NIL_P(refinements)) {
|
|
|
|
omod_shared = TRUE;
|
|
|
|
CREF_OMOD_SHARED_SET(prev_cref);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-03 02:53:39 +03:00
|
|
|
VM_ASSERT(singleton || klass);
|
|
|
|
|
2024-02-20 23:58:10 +03:00
|
|
|
rb_cref_t *cref = IMEMO_NEW(rb_cref_t, imemo_cref, refinements);
|
|
|
|
cref->klass_or_self = klass;
|
|
|
|
cref->next = use_prev_prev ? CREF_NEXT(prev_cref) : prev_cref;
|
|
|
|
*((rb_scope_visibility_t *)&cref->scope_visi) = scope_visi.visi;
|
2015-11-13 23:02:19 +03:00
|
|
|
|
|
|
|
if (pushed_by_eval) CREF_PUSHED_BY_EVAL_SET(cref);
|
|
|
|
if (omod_shared) CREF_OMOD_SHARED_SET(cref);
|
2021-12-03 02:53:39 +03:00
|
|
|
if (singleton) CREF_SINGLETON_SET(cref);
|
2015-11-13 23:02:19 +03:00
|
|
|
|
|
|
|
return cref;
|
|
|
|
}
|
|
|
|
|
|
|
|
static rb_cref_t *
|
2021-12-03 02:53:39 +03:00
|
|
|
vm_cref_new(VALUE klass, rb_method_visibility_t visi, int module_func, rb_cref_t *prev_cref, int pushed_by_eval, int singleton)
|
2015-11-13 23:02:19 +03:00
|
|
|
{
|
2021-12-03 02:53:39 +03:00
|
|
|
return vm_cref_new0(klass, visi, module_func, prev_cref, pushed_by_eval, FALSE, singleton);
|
2015-11-13 23:02:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static rb_cref_t *
|
|
|
|
vm_cref_new_use_prev(VALUE klass, rb_method_visibility_t visi, int module_func, rb_cref_t *prev_cref, int pushed_by_eval)
|
|
|
|
{
|
2021-12-03 02:53:39 +03:00
|
|
|
return vm_cref_new0(klass, visi, module_func, prev_cref, pushed_by_eval, TRUE, FALSE);
|
2015-11-13 23:02:19 +03:00
|
|
|
}
|
|
|
|
|
2018-12-18 16:59:46 +03:00
|
|
|
static int
|
|
|
|
ref_delete_symkey(VALUE key, VALUE value, VALUE unused)
|
|
|
|
{
|
|
|
|
return SYMBOL_P(key) ? ST_DELETE : ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2015-11-13 23:02:19 +03:00
|
|
|
static rb_cref_t *
|
|
|
|
vm_cref_dup(const rb_cref_t *cref)
|
|
|
|
{
|
|
|
|
const rb_scope_visibility_t *visi = CREF_SCOPE_VISI(cref);
|
2015-11-20 03:17:25 +03:00
|
|
|
rb_cref_t *next_cref = CREF_NEXT(cref), *new_cref;
|
2015-11-13 23:02:19 +03:00
|
|
|
int pushed_by_eval = CREF_PUSHED_BY_EVAL(cref);
|
2021-12-03 02:53:39 +03:00
|
|
|
int singleton = CREF_SINGLETON(cref);
|
2015-06-05 14:42:34 +03:00
|
|
|
|
2021-12-03 02:53:39 +03:00
|
|
|
new_cref = vm_cref_new(cref->klass_or_self, visi->method_visi, visi->module_func, next_cref, pushed_by_eval, singleton);
|
2015-11-20 03:17:25 +03:00
|
|
|
|
|
|
|
if (!NIL_P(CREF_REFINEMENTS(cref))) {
|
2018-12-18 16:59:46 +03:00
|
|
|
VALUE ref = rb_hash_dup(CREF_REFINEMENTS(cref));
|
|
|
|
rb_hash_foreach(ref, ref_delete_symkey, Qnil);
|
|
|
|
CREF_REFINEMENTS_SET(new_cref, ref);
|
2021-12-03 02:53:39 +03:00
|
|
|
CREF_OMOD_SHARED_UNSET(new_cref);
|
2015-11-20 03:17:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return new_cref;
|
* fix namespace issue on singleton class expressions. [Bug #10943]
* vm_core.h, method.h: remove rb_iseq_t::cref_stack. CREF is stored
to rb_method_definition_t::body.iseq_body.cref.
* vm_insnhelper.c: modify SVAR usage.
When calling ISEQ type method, push CREF information onto method
frame, SVAR located place. Before this fix, SVAR is simply nil.
After this patch, CREF (or NULL == Qfalse for not iseq methods)
is stored at the method invocation.
When SVAR is requierd, then put NODE_IF onto SVAR location,
and NDOE_IF::nd_reserved points CREF itself.
* vm.c (vm_cref_new, vm_cref_dump, vm_cref_new_toplevel): added.
* vm_insnhelper.c (vm_push_frame): accept CREF.
* method.h, vm_method.c (rb_add_method_iseq): added. This function
accepts iseq and CREF.
* class.c (clone_method): use rb_add_method_iseq().
* gc.c (mark_method_entry): mark method_entry::body.iseq_body.cref.
* iseq.c: remove CREF related codes.
* insns.def (getinlinecache/setinlinecache): CREF should be cache key
because a different CREF has a different namespace.
* node.c (rb_gc_mark_node): mark NODE_IF::nd_reserved for SVAR.
* proc.c: catch up changes.
* struct.c: ditto.
* insns.def: ditto.
* vm_args.c (raise_argument_error): ditto.
* vm_eval.c: ditto.
* test/ruby/test_class.rb: add a test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49874 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-03-06 15:24:58 +03:00
|
|
|
}
|
|
|
|
|
2021-10-21 10:21:08 +03:00
|
|
|
|
|
|
|
rb_cref_t *
|
|
|
|
rb_vm_cref_dup_without_refinements(const rb_cref_t *cref)
|
|
|
|
{
|
|
|
|
const rb_scope_visibility_t *visi = CREF_SCOPE_VISI(cref);
|
|
|
|
rb_cref_t *next_cref = CREF_NEXT(cref), *new_cref;
|
|
|
|
int pushed_by_eval = CREF_PUSHED_BY_EVAL(cref);
|
2021-12-03 02:53:39 +03:00
|
|
|
int singleton = CREF_SINGLETON(cref);
|
2021-10-21 10:21:08 +03:00
|
|
|
|
2021-12-03 02:53:39 +03:00
|
|
|
new_cref = vm_cref_new(cref->klass_or_self, visi->method_visi, visi->module_func, next_cref, pushed_by_eval, singleton);
|
2021-10-21 10:21:08 +03:00
|
|
|
|
|
|
|
if (!NIL_P(CREF_REFINEMENTS(cref))) {
|
|
|
|
CREF_REFINEMENTS_SET(new_cref, Qnil);
|
|
|
|
CREF_OMOD_SHARED_UNSET(new_cref);
|
|
|
|
}
|
|
|
|
|
|
|
|
return new_cref;
|
|
|
|
}
|
|
|
|
|
2015-03-09 00:22:43 +03:00
|
|
|
static rb_cref_t *
|
2017-10-28 13:23:58 +03:00
|
|
|
vm_cref_new_toplevel(rb_execution_context_t *ec)
|
* fix namespace issue on singleton class expressions. [Bug #10943]
* vm_core.h, method.h: remove rb_iseq_t::cref_stack. CREF is stored
to rb_method_definition_t::body.iseq_body.cref.
* vm_insnhelper.c: modify SVAR usage.
When calling ISEQ type method, push CREF information onto method
frame, SVAR located place. Before this fix, SVAR is simply nil.
After this patch, CREF (or NULL == Qfalse for not iseq methods)
is stored at the method invocation.
When SVAR is requierd, then put NODE_IF onto SVAR location,
and NDOE_IF::nd_reserved points CREF itself.
* vm.c (vm_cref_new, vm_cref_dump, vm_cref_new_toplevel): added.
* vm_insnhelper.c (vm_push_frame): accept CREF.
* method.h, vm_method.c (rb_add_method_iseq): added. This function
accepts iseq and CREF.
* class.c (clone_method): use rb_add_method_iseq().
* gc.c (mark_method_entry): mark method_entry::body.iseq_body.cref.
* iseq.c: remove CREF related codes.
* insns.def (getinlinecache/setinlinecache): CREF should be cache key
because a different CREF has a different namespace.
* node.c (rb_gc_mark_node): mark NODE_IF::nd_reserved for SVAR.
* proc.c: catch up changes.
* struct.c: ditto.
* insns.def: ditto.
* vm_args.c (raise_argument_error): ditto.
* vm_eval.c: ditto.
* test/ruby/test_class.rb: add a test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49874 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-03-06 15:24:58 +03:00
|
|
|
{
|
2021-12-03 02:53:39 +03:00
|
|
|
rb_cref_t *cref = vm_cref_new(rb_cObject, METHOD_VISI_PRIVATE /* toplevel visibility is private */, FALSE, NULL, FALSE, FALSE);
|
2017-10-28 13:23:58 +03:00
|
|
|
VALUE top_wrapper = rb_ec_thread_ptr(ec)->top_wrapper;
|
* fix namespace issue on singleton class expressions. [Bug #10943]
* vm_core.h, method.h: remove rb_iseq_t::cref_stack. CREF is stored
to rb_method_definition_t::body.iseq_body.cref.
* vm_insnhelper.c: modify SVAR usage.
When calling ISEQ type method, push CREF information onto method
frame, SVAR located place. Before this fix, SVAR is simply nil.
After this patch, CREF (or NULL == Qfalse for not iseq methods)
is stored at the method invocation.
When SVAR is requierd, then put NODE_IF onto SVAR location,
and NDOE_IF::nd_reserved points CREF itself.
* vm.c (vm_cref_new, vm_cref_dump, vm_cref_new_toplevel): added.
* vm_insnhelper.c (vm_push_frame): accept CREF.
* method.h, vm_method.c (rb_add_method_iseq): added. This function
accepts iseq and CREF.
* class.c (clone_method): use rb_add_method_iseq().
* gc.c (mark_method_entry): mark method_entry::body.iseq_body.cref.
* iseq.c: remove CREF related codes.
* insns.def (getinlinecache/setinlinecache): CREF should be cache key
because a different CREF has a different namespace.
* node.c (rb_gc_mark_node): mark NODE_IF::nd_reserved for SVAR.
* proc.c: catch up changes.
* struct.c: ditto.
* insns.def: ditto.
* vm_args.c (raise_argument_error): ditto.
* vm_eval.c: ditto.
* test/ruby/test_class.rb: add a test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49874 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-03-06 15:24:58 +03:00
|
|
|
|
2017-10-28 13:23:58 +03:00
|
|
|
if (top_wrapper) {
|
2021-12-03 02:53:39 +03:00
|
|
|
cref = vm_cref_new(top_wrapper, METHOD_VISI_PRIVATE, FALSE, cref, FALSE, FALSE);
|
* fix namespace issue on singleton class expressions. [Bug #10943]
* vm_core.h, method.h: remove rb_iseq_t::cref_stack. CREF is stored
to rb_method_definition_t::body.iseq_body.cref.
* vm_insnhelper.c: modify SVAR usage.
When calling ISEQ type method, push CREF information onto method
frame, SVAR located place. Before this fix, SVAR is simply nil.
After this patch, CREF (or NULL == Qfalse for not iseq methods)
is stored at the method invocation.
When SVAR is requierd, then put NODE_IF onto SVAR location,
and NDOE_IF::nd_reserved points CREF itself.
* vm.c (vm_cref_new, vm_cref_dump, vm_cref_new_toplevel): added.
* vm_insnhelper.c (vm_push_frame): accept CREF.
* method.h, vm_method.c (rb_add_method_iseq): added. This function
accepts iseq and CREF.
* class.c (clone_method): use rb_add_method_iseq().
* gc.c (mark_method_entry): mark method_entry::body.iseq_body.cref.
* iseq.c: remove CREF related codes.
* insns.def (getinlinecache/setinlinecache): CREF should be cache key
because a different CREF has a different namespace.
* node.c (rb_gc_mark_node): mark NODE_IF::nd_reserved for SVAR.
* proc.c: catch up changes.
* struct.c: ditto.
* insns.def: ditto.
* vm_args.c (raise_argument_error): ditto.
* vm_eval.c: ditto.
* test/ruby/test_class.rb: add a test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49874 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-03-06 15:24:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return cref;
|
|
|
|
}
|
|
|
|
|
2015-05-21 11:45:57 +03:00
|
|
|
rb_cref_t *
|
|
|
|
rb_vm_cref_new_toplevel(void)
|
|
|
|
{
|
2017-10-28 13:23:58 +03:00
|
|
|
return vm_cref_new_toplevel(GET_EC());
|
2015-05-21 11:45:57 +03:00
|
|
|
}
|
|
|
|
|
2019-10-03 06:26:41 +03:00
|
|
|
static void
|
|
|
|
vm_cref_dump(const char *mesg, const rb_cref_t *cref)
|
|
|
|
{
|
2021-09-09 17:21:06 +03:00
|
|
|
ruby_debug_printf("vm_cref_dump: %s (%p)\n", mesg, (void *)cref);
|
2019-10-03 06:26:41 +03:00
|
|
|
|
|
|
|
while (cref) {
|
2021-09-09 17:21:06 +03:00
|
|
|
ruby_debug_printf("= cref| klass: %s\n", RSTRING_PTR(rb_class_path(CREF_CLASS(cref))));
|
2019-10-03 06:26:41 +03:00
|
|
|
cref = CREF_NEXT(cref);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-01 18:12:14 +03:00
|
|
|
void
|
|
|
|
rb_vm_block_ep_update(VALUE obj, const struct rb_block *dst, const VALUE *ep)
|
|
|
|
{
|
|
|
|
*((const VALUE **)&dst->as.captured.ep) = ep;
|
|
|
|
RB_OBJ_WRITTEN(obj, Qundef, VM_ENV_ENVVAL(ep));
|
|
|
|
}
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
static void
|
2017-06-01 18:12:14 +03:00
|
|
|
vm_bind_update_env(VALUE bindval, rb_binding_t *bind, VALUE envval)
|
2016-07-28 14:02:30 +03:00
|
|
|
{
|
2016-07-28 22:13:26 +03:00
|
|
|
const rb_env_t *env = (rb_env_t *)envval;
|
2017-06-01 18:12:14 +03:00
|
|
|
RB_OBJ_WRITE(bindval, &bind->block.as.captured.code.iseq, env->iseq);
|
|
|
|
rb_vm_block_ep_update(bindval, &bind->block, env->ep);
|
2016-07-28 14:02:30 +03:00
|
|
|
}
|
|
|
|
|
2012-11-22 11:23:40 +04:00
|
|
|
#if VM_COLLECT_USAGE_DETAILS
|
2012-10-04 16:31:05 +04:00
|
|
|
static void vm_collect_usage_operand(int insn, int n, VALUE op);
|
|
|
|
static void vm_collect_usage_insn(int insn);
|
* probes.d: add DTrace probe declarations. [ruby-core:27448]
* array.c (empty_ary_alloc, ary_new): added array create DTrace probe.
* compile.c (rb_insns_name): allowing DTrace probes to access
instruction sequence name.
* Makefile.in: translate probes.d file to appropriate header file.
* common.mk: declare dependencies on the DTrace header.
* configure.in: add a test for existence of DTrace.
* eval.c (setup_exception): add a probe for when an exception is
raised.
* gc.c: Add DTrace probes for mark begin and end, and sweep begin and
end.
* hash.c (empty_hash_alloc): Add a probe for hash allocation.
* insns.def: Add probes for function entry and return.
* internal.h: function declaration for compile.c change.
* load.c (rb_f_load): add probes for `load` entry and exit, require
entry and exit, and wrapping search_required for load path search.
* object.c (rb_obj_alloc): added a probe for general object creation.
* parse.y (yycompile0): added a probe around parse and compile phase.
* string.c (empty_str_alloc, str_new): DTrace probes for string
allocation.
* test/dtrace/*: tests for DTrace probes.
* vm.c (vm_invoke_proc): add probes for function return on exception
raise, hash create, and instruction sequence execution.
* vm_core.h: add probe declarations for function entry and exit.
* vm_dump.c: add probes header file.
* vm_eval.c (vm_call0_cfunc, vm_call0_cfunc_with_frame): add probe on
function entry and return.
* vm_exec.c: expose instruction number to instruction name function.
* vm_insnshelper.c: add function entry and exit probes for cfunc
methods.
* vm_insnhelper.h: vm usage information is always collected, so
uncomment the functions.
12 19:14:50 2012 Akinori MUSHA <knu@iDaemons.org>
* configure.in (isinf, isnan): isinf() and isnan() are macros on
DragonFly which cannot be found by AC_REPLACE_FUNCS(). This
workaround enforces the fact that they exist on DragonFly.
12 15:59:38 2012 Shugo Maeda <shugo@ruby-lang.org>
* vm_core.h (rb_call_info_t::refinements), compile.c (new_callinfo),
vm_insnhelper.c (vm_search_method): revert r37616 because it's too
slow. [ruby-dev:46477]
* test/ruby/test_refinement.rb (test_inline_method_cache): skip
the test until the bug is fixed efficiently.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-11-13 01:52:12 +04:00
|
|
|
static void vm_collect_usage_register(int reg, int isset);
|
2012-10-04 16:31:05 +04:00
|
|
|
#endif
|
|
|
|
|
2017-10-26 11:41:34 +03:00
|
|
|
static VALUE vm_make_env_object(const rb_execution_context_t *ec, rb_control_frame_t *cfp);
|
2024-08-08 01:29:33 +03:00
|
|
|
static VALUE vm_invoke_bmethod(rb_execution_context_t *ec, rb_proc_t *proc, VALUE self,
|
2019-09-03 19:32:42 +03:00
|
|
|
int argc, const VALUE *argv, int kw_splat, VALUE block_handler,
|
2018-11-09 04:02:13 +03:00
|
|
|
const rb_callable_method_entry_t *me);
|
2019-09-03 19:32:42 +03:00
|
|
|
static VALUE vm_invoke_proc(rb_execution_context_t *ec, rb_proc_t *proc, VALUE self, int argc, const VALUE *argv, int kw_splat, VALUE block_handler);
|
2012-08-20 15:36:34 +04:00
|
|
|
|
2023-10-12 17:05:34 +03:00
|
|
|
#if USE_YJIT
|
|
|
|
// Counter to serve as a proxy for execution time, total number of calls
|
|
|
|
static uint64_t yjit_total_entry_hits = 0;
|
|
|
|
|
|
|
|
// Number of calls used to estimate how hot an ISEQ is
|
|
|
|
#define YJIT_CALL_COUNT_INTERV 20u
|
|
|
|
|
|
|
|
/// Test whether we are ready to compile an ISEQ or not
|
|
|
|
static inline bool
|
|
|
|
rb_yjit_threshold_hit(const rb_iseq_t *iseq, uint64_t entry_calls)
|
|
|
|
{
|
|
|
|
yjit_total_entry_hits += 1;
|
|
|
|
|
|
|
|
// Record the number of calls at the beginning of the interval
|
|
|
|
if (entry_calls + YJIT_CALL_COUNT_INTERV == rb_yjit_call_threshold) {
|
|
|
|
iseq->body->yjit_calls_at_interv = yjit_total_entry_hits;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to estimate the total time taken (total number of calls) to reach 20 calls to this ISEQ
|
|
|
|
// This give us a ratio of how hot/cold this ISEQ is
|
|
|
|
if (entry_calls == rb_yjit_call_threshold) {
|
|
|
|
// We expect threshold 1 to compile everything immediately
|
|
|
|
if (rb_yjit_call_threshold < YJIT_CALL_COUNT_INTERV) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t num_calls = yjit_total_entry_hits - iseq->body->yjit_calls_at_interv;
|
|
|
|
|
|
|
|
// Reject ISEQs that don't get called often enough
|
|
|
|
if (num_calls > rb_yjit_cold_threshold) {
|
|
|
|
rb_yjit_incr_counter("cold_iseq_entry");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define rb_yjit_threshold_hit(iseq, entry_calls) false
|
|
|
|
#endif
|
|
|
|
|
2023-03-07 10:15:30 +03:00
|
|
|
#if USE_RJIT || USE_YJIT
|
2023-08-09 02:06:22 +03:00
|
|
|
// Generate JIT code that supports the following kinds of ISEQ entries:
|
|
|
|
// * The first ISEQ on vm_exec (e.g. <main>, or Ruby methods/blocks
|
|
|
|
// called by a C method). The current frame has VM_FRAME_FLAG_FINISH.
|
|
|
|
// The current vm_exec stops if JIT code returns a non-Qundef value.
|
|
|
|
// * ISEQs called by the interpreter on vm_sendish (e.g. Ruby methods or
|
|
|
|
// blocks called by a Ruby frame that isn't compiled or side-exited).
|
|
|
|
// The current frame doesn't have VM_FRAME_FLAG_FINISH. The current
|
|
|
|
// vm_exec does NOT stop whether JIT code returns Qundef or not.
|
2023-03-16 20:41:12 +03:00
|
|
|
static inline rb_jit_func_t
|
2023-03-14 23:39:06 +03:00
|
|
|
jit_compile(rb_execution_context_t *ec)
|
2022-08-13 17:50:00 +03:00
|
|
|
{
|
|
|
|
const rb_iseq_t *iseq = ec->cfp->iseq;
|
|
|
|
struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
|
2023-10-20 03:51:01 +03:00
|
|
|
bool yjit_enabled = rb_yjit_enabled_p;
|
|
|
|
if (!(yjit_enabled || rb_rjit_call_p)) {
|
2023-08-09 02:06:22 +03:00
|
|
|
return NULL;
|
2023-07-17 17:41:18 +03:00
|
|
|
}
|
|
|
|
|
2023-08-22 08:46:03 +03:00
|
|
|
// Increment the ISEQ's call counter and trigger JIT compilation if not compiled
|
2023-08-09 02:06:22 +03:00
|
|
|
if (body->jit_entry == NULL) {
|
2023-08-22 08:46:03 +03:00
|
|
|
body->jit_entry_calls++;
|
2023-10-20 03:51:01 +03:00
|
|
|
if (yjit_enabled) {
|
2023-08-09 02:06:22 +03:00
|
|
|
if (rb_yjit_threshold_hit(iseq, body->jit_entry_calls)) {
|
|
|
|
rb_yjit_compile_iseq(iseq, ec, false);
|
|
|
|
}
|
2022-08-13 17:50:00 +03:00
|
|
|
}
|
2023-10-12 17:05:34 +03:00
|
|
|
else if (body->jit_entry_calls == rb_rjit_call_threshold()) {
|
|
|
|
rb_rjit_compile(iseq);
|
2022-12-11 10:55:33 +03:00
|
|
|
}
|
2022-08-13 17:50:00 +03:00
|
|
|
}
|
2023-08-09 02:06:22 +03:00
|
|
|
return body->jit_entry;
|
2022-08-13 17:50:00 +03:00
|
|
|
}
|
2023-03-14 23:39:06 +03:00
|
|
|
|
2023-08-09 02:06:22 +03:00
|
|
|
// Execute JIT code compiled by jit_compile()
|
2023-03-08 09:43:37 +03:00
|
|
|
static inline VALUE
|
|
|
|
jit_exec(rb_execution_context_t *ec)
|
|
|
|
{
|
2023-03-16 20:41:12 +03:00
|
|
|
rb_jit_func_t func = jit_compile(ec);
|
2023-03-14 23:39:06 +03:00
|
|
|
if (func) {
|
|
|
|
// Call the JIT code
|
|
|
|
return func(ec, ec->cfp);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return Qundef;
|
|
|
|
}
|
2023-03-08 09:43:37 +03:00
|
|
|
}
|
2023-03-14 23:39:06 +03:00
|
|
|
#else
|
2023-08-06 07:25:23 +03:00
|
|
|
# define jit_compile(ec) ((rb_jit_func_t)0)
|
|
|
|
# define jit_exec(ec) Qundef
|
2022-08-13 17:50:00 +03:00
|
|
|
#endif
|
|
|
|
|
2023-08-09 02:06:22 +03:00
|
|
|
#if USE_YJIT
|
|
|
|
// Generate JIT code that supports the following kind of ISEQ entry:
|
|
|
|
// * The first ISEQ pushed by vm_exec_handle_exception. The frame would
|
|
|
|
// point to a location specified by a catch table, and it doesn't have
|
|
|
|
// VM_FRAME_FLAG_FINISH. The current vm_exec stops if JIT code returns
|
|
|
|
// a non-Qundef value. So you should not return a non-Qundef value
|
|
|
|
// until ec->cfp is changed to a frame with VM_FRAME_FLAG_FINISH.
|
|
|
|
static inline rb_jit_func_t
|
|
|
|
jit_compile_exception(rb_execution_context_t *ec)
|
|
|
|
{
|
|
|
|
const rb_iseq_t *iseq = ec->cfp->iseq;
|
|
|
|
struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
|
2023-10-19 20:54:35 +03:00
|
|
|
if (!rb_yjit_enabled_p) {
|
2023-08-09 02:06:22 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2023-08-22 08:46:03 +03:00
|
|
|
// Increment the ISEQ's call counter and trigger JIT compilation if not compiled
|
|
|
|
if (body->jit_exception == NULL) {
|
|
|
|
body->jit_exception_calls++;
|
2023-10-12 17:05:34 +03:00
|
|
|
if (body->jit_exception_calls == rb_yjit_call_threshold) {
|
2023-08-22 08:46:03 +03:00
|
|
|
rb_yjit_compile_iseq(iseq, ec, true);
|
|
|
|
}
|
2023-08-09 02:06:22 +03:00
|
|
|
}
|
2023-10-04 00:45:46 +03:00
|
|
|
|
2023-08-09 02:06:22 +03:00
|
|
|
return body->jit_exception;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Execute JIT code compiled by jit_compile_exception()
|
|
|
|
static inline VALUE
|
|
|
|
jit_exec_exception(rb_execution_context_t *ec)
|
|
|
|
{
|
|
|
|
rb_jit_func_t func = jit_compile_exception(ec);
|
|
|
|
if (func) {
|
|
|
|
// Call the JIT code
|
|
|
|
return func(ec, ec->cfp);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return Qundef;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
# define jit_compile_exception(ec) ((rb_jit_func_t)0)
|
|
|
|
# define jit_exec_exception(ec) Qundef
|
|
|
|
#endif
|
|
|
|
|
2023-10-18 11:47:48 +03:00
|
|
|
static void add_opt_method_entry(const rb_method_entry_t *me);
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
#include "vm_insnhelper.c"
|
mjit_compile.c: merge initial JIT compiler
which has been developed by Takashi Kokubun <takashikkbn@gmail> as
YARV-MJIT. Many of its bugs are fixed by wanabe <s.wanabe@gmail.com>.
This JIT compiler is designed to be a safe migration path to introduce
JIT compiler to MRI. So this commit does not include any bytecode
changes or dynamic instruction modifications, which are done in original
MJIT.
This commit even strips off some aggressive optimizations from
YARV-MJIT, and thus it's slower than YARV-MJIT too. But it's still
fairly faster than Ruby 2.5 in some benchmarks (attached below).
Note that this JIT compiler passes `make test`, `make test-all`, `make
test-spec` without JIT, and even with JIT. Not only it's perfectly safe
with JIT disabled because it does not replace VM instructions unlike
MJIT, but also with JIT enabled it stably runs Ruby applications
including Rails applications.
I'm expecting this version as just "initial" JIT compiler. I have many
optimization ideas which are skipped for initial merging, and you may
easily replace this JIT compiler with a faster one by just replacing
mjit_compile.c. `mjit_compile` interface is designed for the purpose.
common.mk: update dependencies for mjit_compile.c.
internal.h: declare `rb_vm_insn_addr2insn` for MJIT.
vm.c: exclude some definitions if `-DMJIT_HEADER` is provided to
compiler. This avoids to include some functions which take a long time
to compile, e.g. vm_exec_core. Some of the purpose is achieved in
transform_mjit_header.rb (see `IGNORED_FUNCTIONS`) but others are
manually resolved for now. Load mjit_helper.h for MJIT header.
mjit_helper.h: New. This is a file used only by JIT-ed code. I'll
refactor `mjit_call_cfunc` later.
vm_eval.c: add some #ifdef switches to skip compiling some functions
like Init_vm_eval.
win32/mkexports.rb: export thread/ec functions, which are used by MJIT.
include/ruby/defines.h: add MJIT_FUNC_EXPORTED macro alis to clarify
that a function is exported only for MJIT.
array.c: export a function used by MJIT.
bignum.c: ditto.
class.c: ditto.
compile.c: ditto.
error.c: ditto.
gc.c: ditto.
hash.c: ditto.
iseq.c: ditto.
numeric.c: ditto.
object.c: ditto.
proc.c: ditto.
re.c: ditto.
st.c: ditto.
string.c: ditto.
thread.c: ditto.
variable.c: ditto.
vm_backtrace.c: ditto.
vm_insnhelper.c: ditto.
vm_method.c: ditto.
I would like to improve maintainability of function exports, but I
believe this way is acceptable as initial merging if we clarify the
new exports are for MJIT (so that we can use them as TODO list to fix)
and add unit tests to detect unresolved symbols.
I'll add unit tests of JIT compilations in succeeding commits.
Author: Takashi Kokubun <takashikkbn@gmail.com>
Contributor: wanabe <s.wanabe@gmail.com>
Part of [Feature #14235]
---
* Known issues
* Code generated by gcc is faster than clang. The benchmark may be worse
in macOS. Following benchmark result is provided by gcc w/ Linux.
* Performance is decreased when Google Chrome is running
* JIT can work on MinGW, but it doesn't improve performance at least
in short running benchmark.
* Currently it doesn't perform well with Rails. We'll try to fix this
before release.
---
* Benchmark reslts
Benchmarked with:
Intel 4.0GHz i7-4790K with 16GB memory under x86-64 Ubuntu 8 Cores
- 2.0.0-p0: Ruby 2.0.0-p0
- r62186: Ruby trunk (early 2.6.0), before MJIT changes
- JIT off: On this commit, but without `--jit` option
- JIT on: On this commit, and with `--jit` option
** Optcarrot fps
Benchmark: https://github.com/mame/optcarrot
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:--------|:--------|:--------|:--------|:--------|
|fps |37.32 |51.46 |51.31 |58.88 |
|vs 2.0.0 |1.00x |1.38x |1.37x |1.58x |
** MJIT benchmarks
Benchmark: https://github.com/benchmark-driver/mjit-benchmarks
(Original: https://github.com/vnmakarov/ruby/tree/rtl_mjit_branch/MJIT-benchmarks)
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:----------|:--------|:--------|:--------|:--------|
|aread |1.00 |1.09 |1.07 |2.19 |
|aref |1.00 |1.13 |1.11 |2.22 |
|aset |1.00 |1.50 |1.45 |2.64 |
|awrite |1.00 |1.17 |1.13 |2.20 |
|call |1.00 |1.29 |1.26 |2.02 |
|const2 |1.00 |1.10 |1.10 |2.19 |
|const |1.00 |1.11 |1.10 |2.19 |
|fannk |1.00 |1.04 |1.02 |1.00 |
|fib |1.00 |1.32 |1.31 |1.84 |
|ivread |1.00 |1.13 |1.12 |2.43 |
|ivwrite |1.00 |1.23 |1.21 |2.40 |
|mandelbrot |1.00 |1.13 |1.16 |1.28 |
|meteor |1.00 |2.97 |2.92 |3.17 |
|nbody |1.00 |1.17 |1.15 |1.49 |
|nest-ntimes|1.00 |1.22 |1.20 |1.39 |
|nest-while |1.00 |1.10 |1.10 |1.37 |
|norm |1.00 |1.18 |1.16 |1.24 |
|nsvb |1.00 |1.16 |1.16 |1.17 |
|red-black |1.00 |1.02 |0.99 |1.12 |
|sieve |1.00 |1.30 |1.28 |1.62 |
|trees |1.00 |1.14 |1.13 |1.19 |
|while |1.00 |1.12 |1.11 |2.41 |
** Discourse's script/bench.rb
Benchmark: https://github.com/discourse/discourse/blob/v1.8.7/script/bench.rb
NOTE: Rails performance was somehow a little degraded with JIT for now.
We should fix this.
(At least I know opt_aref is performing badly in JIT and I have an idea
to fix it. Please wait for the fix.)
*** JIT off
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 17
75: 18
90: 22
99: 29
home_admin:
50: 21
75: 21
90: 27
99: 40
topic_admin:
50: 17
75: 18
90: 22
99: 32
categories:
50: 35
75: 41
90: 43
99: 77
home:
50: 39
75: 46
90: 49
99: 95
topic:
50: 46
75: 52
90: 56
99: 101
*** JIT on
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 19
75: 21
90: 25
99: 33
home_admin:
50: 24
75: 26
90: 30
99: 35
topic_admin:
50: 19
75: 20
90: 25
99: 30
categories:
50: 40
75: 44
90: 48
99: 76
home:
50: 42
75: 48
90: 51
99: 89
topic:
50: 49
75: 55
90: 58
99: 99
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62197 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 14:22:28 +03:00
|
|
|
|
* common.mk: clean up
- remove blockinlining.$(OBJEXT) to built
- make ENCODING_H_INCLDUES variable (include/ruby/encoding.h)
- make VM_CORE_H_INCLUDES variable (vm_core.h)
- simplify rules.
- make depends rule to output depend status using gcc -MM.
* include/ruby/mvm.h, include/ruby/vm.h: rename mvm.h to vm.h.
* include/ruby.h: ditto.
* load.c: add inclusion explicitly.
* enumerator.c, object.c, parse.y, thread.c, vm_dump.c:
remove useless inclusion.
* eval_intern.h: cleanup inclusion.
* vm_core.h: rb_thread_t should be defined in this file.
* vm_evalbody.c, vm_exec.c: rename vm_evalbody.c to vm_exec.c.
* vm.h, vm_exec.h: rename vm.h to vm_exec.h.
* insnhelper.h, vm_insnhelper.h: rename insnhelper.h to vm_insnhelper.h.
* vm.c, vm_insnhelper.c, vm_insnhelper.h:
- rename vm_eval() to vm_exec_core().
- rename vm_eval_body() to vm_exec().
- cleanup include order.
* vm_method.c: fix comment.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19466 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-09-23 04:20:28 +04:00
|
|
|
#include "vm_exec.c"
|
|
|
|
|
|
|
|
#include "vm_method.c"
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
#include "vm_eval.c"
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2007-06-24 21:19:22 +04:00
|
|
|
#define PROCDEBUG 0
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2008-06-29 21:26:16 +04:00
|
|
|
VALUE rb_cRubyVM;
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
VALUE rb_cThread;
|
2008-07-01 07:05:58 +04:00
|
|
|
VALUE rb_mRubyVMFrozenCore;
|
2019-07-14 12:04:14 +03:00
|
|
|
VALUE rb_block_param_proxy;
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
|
2009-01-15 18:31:43 +03:00
|
|
|
VALUE ruby_vm_const_missing_count = 0;
|
2017-10-26 11:32:49 +03:00
|
|
|
rb_vm_t *ruby_current_vm_ptr = NULL;
|
2020-12-06 18:07:30 +03:00
|
|
|
rb_ractor_t *ruby_single_main_ractor;
|
2021-09-30 10:58:46 +03:00
|
|
|
bool ruby_vm_keep_script_lines;
|
2020-10-19 10:47:32 +03:00
|
|
|
|
|
|
|
#ifdef RB_THREAD_LOCAL_SPECIFIER
|
|
|
|
RB_THREAD_LOCAL_SPECIFIER rb_execution_context_t *ruby_current_ec;
|
2023-04-10 04:53:13 +03:00
|
|
|
|
2023-03-30 21:52:58 +03:00
|
|
|
#ifdef RUBY_NT_SERIAL
|
|
|
|
RB_THREAD_LOCAL_SPECIFIER rb_atomic_t ruby_nt_serial;
|
|
|
|
#endif
|
2020-10-19 10:47:32 +03:00
|
|
|
|
2023-04-10 04:53:13 +03:00
|
|
|
// no-inline decl on thread_pthread.h
|
2023-07-07 19:47:06 +03:00
|
|
|
rb_execution_context_t *
|
2023-04-10 04:53:13 +03:00
|
|
|
rb_current_ec_noinline(void)
|
2023-07-07 19:47:06 +03:00
|
|
|
{
|
|
|
|
return ruby_current_ec;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_current_ec_set(rb_execution_context_t *ec)
|
|
|
|
{
|
|
|
|
ruby_current_ec = ec;
|
|
|
|
}
|
2020-10-19 10:47:32 +03:00
|
|
|
|
2023-04-10 04:53:13 +03:00
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
rb_execution_context_t *
|
|
|
|
rb_current_ec(void)
|
|
|
|
{
|
|
|
|
return ruby_current_ec;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
2020-10-19 10:47:32 +03:00
|
|
|
#else
|
2020-03-09 20:22:11 +03:00
|
|
|
native_tls_key_t ruby_current_ec_key;
|
2020-10-19 10:47:32 +03:00
|
|
|
#endif
|
2018-11-26 21:16:39 +03:00
|
|
|
|
2012-08-16 15:41:24 +04:00
|
|
|
rb_event_flag_t ruby_vm_event_flags;
|
2018-11-26 21:16:39 +03:00
|
|
|
rb_event_flag_t ruby_vm_event_enabled_global_flags;
|
|
|
|
unsigned int ruby_vm_event_local_num;
|
|
|
|
|
2022-04-05 23:37:00 +03:00
|
|
|
rb_serial_t ruby_vm_constant_cache_invalidations = 0;
|
|
|
|
rb_serial_t ruby_vm_constant_cache_misses = 0;
|
2021-06-01 20:34:06 +03:00
|
|
|
rb_serial_t ruby_vm_global_cvar_state = 1;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2020-06-03 12:33:59 +03:00
|
|
|
static const struct rb_callcache vm_empty_cc = {
|
|
|
|
.flags = T_IMEMO | (imemo_callcache << FL_USHIFT) | VM_CALLCACHE_UNMARKABLE,
|
|
|
|
.klass = Qfalse,
|
|
|
|
.cme_ = NULL,
|
|
|
|
.call_ = vm_call_general,
|
|
|
|
.aux_ = {
|
|
|
|
.v = Qfalse,
|
|
|
|
}
|
|
|
|
};
|
2020-01-08 10:14:01 +03:00
|
|
|
|
2021-11-16 11:57:49 +03:00
|
|
|
static const struct rb_callcache vm_empty_cc_for_super = {
|
|
|
|
.flags = T_IMEMO | (imemo_callcache << FL_USHIFT) | VM_CALLCACHE_UNMARKABLE,
|
|
|
|
.klass = Qfalse,
|
|
|
|
.cme_ = NULL,
|
|
|
|
.call_ = vm_call_super_method,
|
|
|
|
.aux_ = {
|
|
|
|
.v = Qfalse,
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-09-18 11:29:17 +04:00
|
|
|
static void thread_free(void *ptr);
|
|
|
|
|
2009-01-15 18:31:43 +03:00
|
|
|
void
|
|
|
|
rb_vm_inc_const_missing_count(void)
|
|
|
|
{
|
|
|
|
ruby_vm_const_missing_count +=1;
|
|
|
|
}
|
|
|
|
|
2023-03-07 08:34:31 +03:00
|
|
|
int
|
2017-11-07 11:19:25 +03:00
|
|
|
rb_dtrace_setup(rb_execution_context_t *ec, VALUE klass, ID id,
|
|
|
|
struct ruby_dtrace_method_hook_args *args)
|
2015-10-29 08:32:19 +03:00
|
|
|
{
|
|
|
|
enum ruby_value_type type;
|
|
|
|
if (!klass) {
|
2017-11-07 11:19:25 +03:00
|
|
|
if (!ec) ec = GET_EC();
|
|
|
|
if (!rb_ec_frame_method_id_and_class(ec, &id, 0, &klass) || !klass)
|
2015-10-29 08:32:19 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (RB_TYPE_P(klass, T_ICLASS)) {
|
|
|
|
klass = RBASIC(klass)->klass;
|
|
|
|
}
|
2024-03-06 19:04:22 +03:00
|
|
|
else if (RCLASS_SINGLETON_P(klass)) {
|
2023-02-15 12:42:52 +03:00
|
|
|
klass = RCLASS_ATTACHED_OBJECT(klass);
|
2015-10-29 08:32:19 +03:00
|
|
|
if (NIL_P(klass)) return FALSE;
|
|
|
|
}
|
|
|
|
type = BUILTIN_TYPE(klass);
|
|
|
|
if (type == T_CLASS || type == T_ICLASS || type == T_MODULE) {
|
2019-04-12 06:46:28 +03:00
|
|
|
VALUE name = rb_class_path(klass);
|
2015-10-31 04:02:26 +03:00
|
|
|
const char *classname, *filename;
|
2015-10-29 08:32:19 +03:00
|
|
|
const char *methodname = rb_id2name(id);
|
2017-11-16 08:52:19 +03:00
|
|
|
if (methodname && (filename = rb_source_location_cstr(&args->line_no)) != 0) {
|
2015-10-29 08:32:19 +03:00
|
|
|
if (NIL_P(name) || !(classname = StringValuePtr(name)))
|
|
|
|
classname = "<unknown>";
|
|
|
|
args->classname = classname;
|
|
|
|
args->methodname = methodname;
|
|
|
|
args->filename = filename;
|
|
|
|
args->klass = klass;
|
|
|
|
args->name = name;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2023-02-08 04:46:42 +03:00
|
|
|
extern unsigned int redblack_buffer_size;
|
|
|
|
|
2013-12-08 08:05:59 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* RubyVM.stat -> Hash
|
|
|
|
* RubyVM.stat(hsh) -> hsh
|
|
|
|
* RubyVM.stat(Symbol) -> Numeric
|
|
|
|
*
|
|
|
|
* Returns a Hash containing implementation-dependent counters inside the VM.
|
|
|
|
*
|
2022-03-31 18:04:25 +03:00
|
|
|
* This hash includes information about method/constant caches:
|
2013-12-08 08:05:59 +04:00
|
|
|
*
|
|
|
|
* {
|
2022-04-05 23:37:00 +03:00
|
|
|
* :constant_cache_invalidations=>2,
|
|
|
|
* :constant_cache_misses=>14,
|
|
|
|
* :global_cvar_state=>27
|
2013-12-08 08:05:59 +04:00
|
|
|
* }
|
|
|
|
*
|
2022-12-08 04:09:30 +03:00
|
|
|
* If <tt>USE_DEBUG_COUNTER</tt> is enabled, debug counters will be included.
|
|
|
|
*
|
2013-12-08 08:05:59 +04:00
|
|
|
* The contents of the hash are implementation specific and may be changed in
|
|
|
|
* the future.
|
|
|
|
*
|
|
|
|
* This method is only expected to work on C Ruby.
|
|
|
|
*/
|
|
|
|
static VALUE
|
2013-12-09 13:12:23 +04:00
|
|
|
vm_stat(int argc, VALUE *argv, VALUE self)
|
2013-12-08 08:05:59 +04:00
|
|
|
{
|
2022-11-23 20:02:14 +03:00
|
|
|
static VALUE sym_constant_cache_invalidations, sym_constant_cache_misses, sym_global_cvar_state, sym_next_shape_id;
|
2023-02-08 04:46:42 +03:00
|
|
|
static VALUE sym_shape_cache_size;
|
2013-12-08 08:05:59 +04:00
|
|
|
VALUE arg = Qnil;
|
|
|
|
VALUE hash = Qnil, key = Qnil;
|
|
|
|
|
2018-12-06 10:49:24 +03:00
|
|
|
if (rb_check_arity(argc, 0, 1) == 1) {
|
|
|
|
arg = argv[0];
|
2013-12-08 08:05:59 +04:00
|
|
|
if (SYMBOL_P(arg))
|
|
|
|
key = arg;
|
|
|
|
else if (RB_TYPE_P(arg, T_HASH))
|
|
|
|
hash = arg;
|
|
|
|
else
|
|
|
|
rb_raise(rb_eTypeError, "non-hash or symbol given");
|
2014-02-27 11:10:14 +04:00
|
|
|
}
|
2016-08-30 10:29:59 +03:00
|
|
|
else {
|
2013-12-08 08:05:59 +04:00
|
|
|
hash = rb_hash_new();
|
|
|
|
}
|
|
|
|
|
|
|
|
#define S(s) sym_##s = ID2SYM(rb_intern_const(#s))
|
2022-04-05 23:37:00 +03:00
|
|
|
S(constant_cache_invalidations);
|
|
|
|
S(constant_cache_misses);
|
2021-06-01 20:34:06 +03:00
|
|
|
S(global_cvar_state);
|
2022-11-23 20:02:14 +03:00
|
|
|
S(next_shape_id);
|
2023-02-08 04:46:42 +03:00
|
|
|
S(shape_cache_size);
|
2013-12-08 08:05:59 +04:00
|
|
|
#undef S
|
|
|
|
|
|
|
|
#define SET(name, attr) \
|
|
|
|
if (key == sym_##name) \
|
2013-12-09 03:07:43 +04:00
|
|
|
return SERIALT2NUM(attr); \
|
2013-12-08 08:05:59 +04:00
|
|
|
else if (hash != Qnil) \
|
2013-12-09 03:07:43 +04:00
|
|
|
rb_hash_aset(hash, sym_##name, SERIALT2NUM(attr));
|
2013-12-08 08:05:59 +04:00
|
|
|
|
2022-04-05 23:37:00 +03:00
|
|
|
SET(constant_cache_invalidations, ruby_vm_constant_cache_invalidations);
|
|
|
|
SET(constant_cache_misses, ruby_vm_constant_cache_misses);
|
2021-06-01 20:34:06 +03:00
|
|
|
SET(global_cvar_state, ruby_vm_global_cvar_state);
|
2023-02-17 16:32:51 +03:00
|
|
|
SET(next_shape_id, (rb_serial_t)GET_SHAPE_TREE()->next_shape_id);
|
2023-02-08 04:46:42 +03:00
|
|
|
SET(shape_cache_size, (rb_serial_t)GET_SHAPE_TREE()->cache_size);
|
2013-12-08 08:05:59 +04:00
|
|
|
#undef SET
|
|
|
|
|
2022-12-08 04:09:30 +03:00
|
|
|
#if USE_DEBUG_COUNTER
|
|
|
|
ruby_debug_counter_show_at_exit(FALSE);
|
|
|
|
for (size_t i = 0; i < RB_DEBUG_COUNTER_MAX; i++) {
|
|
|
|
const VALUE name = rb_sym_intern_ascii_cstr(rb_debug_counter_names[i]);
|
|
|
|
const VALUE boxed_value = SIZET2NUM(rb_debug_counter[i]);
|
|
|
|
|
|
|
|
if (key == name) {
|
|
|
|
return boxed_value;
|
|
|
|
}
|
|
|
|
else if (hash != Qnil) {
|
|
|
|
rb_hash_aset(hash, name, boxed_value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-03-31 06:34:40 +04:00
|
|
|
if (!NIL_P(key)) { /* matched key should return above */
|
|
|
|
rb_raise(rb_eArgError, "unknown key: %"PRIsVALUE, rb_sym2str(key));
|
|
|
|
}
|
2013-12-08 08:05:59 +04:00
|
|
|
|
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
2007-06-24 21:19:22 +04:00
|
|
|
/* control stack frame */
|
2007-06-25 06:44:20 +04:00
|
|
|
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
static void
|
2017-10-28 13:23:58 +03:00
|
|
|
vm_set_top_stack(rb_execution_context_t *ec, const rb_iseq_t *iseq)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2022-03-23 22:19:48 +03:00
|
|
|
if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_TOP) {
|
2006-12-31 18:02:22 +03:00
|
|
|
rb_raise(rb_eTypeError, "Not a toplevel InstructionSequence");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* for return */
|
2017-10-28 13:23:58 +03:00
|
|
|
vm_push_frame(ec, iseq, VM_FRAME_MAGIC_TOP | VM_ENV_FLAG_LOCAL | VM_FRAME_FLAG_FINISH, rb_ec_thread_ptr(ec)->top_self,
|
2016-07-28 14:02:30 +03:00
|
|
|
VM_BLOCK_HANDLER_NONE,
|
2017-10-28 13:23:58 +03:00
|
|
|
(VALUE)vm_cref_new_toplevel(ec), /* cref or me */
|
2022-03-23 22:19:48 +03:00
|
|
|
ISEQ_BODY(iseq)->iseq_encoded, ec->cfp->sp,
|
|
|
|
ISEQ_BODY(iseq)->local_table_size, ISEQ_BODY(iseq)->stack_max);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
static void
|
2017-10-28 13:23:58 +03:00
|
|
|
vm_set_eval_stack(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_cref_t *cref, const struct rb_block *base_block)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2017-10-28 13:23:58 +03:00
|
|
|
vm_push_frame(ec, iseq, VM_FRAME_MAGIC_EVAL | VM_FRAME_FLAG_FINISH,
|
2016-07-28 14:02:30 +03:00
|
|
|
vm_block_self(base_block), VM_GUARDED_PREV_EP(vm_block_ep(base_block)),
|
2015-06-02 07:20:30 +03:00
|
|
|
(VALUE)cref, /* cref or me */
|
2022-03-23 22:19:48 +03:00
|
|
|
ISEQ_BODY(iseq)->iseq_encoded,
|
|
|
|
ec->cfp->sp, ISEQ_BODY(iseq)->local_table_size,
|
|
|
|
ISEQ_BODY(iseq)->stack_max);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2008-12-27 04:15:56 +03:00
|
|
|
static void
|
2017-10-28 13:23:58 +03:00
|
|
|
vm_set_main_stack(rb_execution_context_t *ec, const rb_iseq_t *iseq)
|
2008-12-27 04:15:56 +03:00
|
|
|
{
|
|
|
|
VALUE toplevel_binding = rb_const_get(rb_cObject, rb_intern("TOPLEVEL_BINDING"));
|
|
|
|
rb_binding_t *bind;
|
|
|
|
|
|
|
|
GetBindingPtr(toplevel_binding, bind);
|
2016-08-19 03:12:47 +03:00
|
|
|
RUBY_ASSERT_MESG(bind, "TOPLEVEL_BINDING is not built");
|
2015-07-22 01:52:59 +03:00
|
|
|
|
2017-10-28 13:23:58 +03:00
|
|
|
vm_set_eval_stack(ec, iseq, 0, &bind->block);
|
2008-12-27 04:15:56 +03:00
|
|
|
|
|
|
|
/* save binding */
|
2022-03-23 22:19:48 +03:00
|
|
|
if (ISEQ_BODY(iseq)->local_table_size > 0) {
|
2017-10-28 13:23:58 +03:00
|
|
|
vm_bind_update_env(toplevel_binding, bind, vm_make_env_object(ec, ec->cfp));
|
2008-12-27 04:15:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-05 10:04:59 +04:00
|
|
|
rb_control_frame_t *
|
2017-10-28 13:47:19 +03:00
|
|
|
rb_vm_get_binding_creatable_next_cfp(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
|
2013-02-05 10:04:59 +04:00
|
|
|
{
|
2017-10-28 13:47:19 +03:00
|
|
|
while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(ec, cfp)) {
|
2013-02-05 10:04:59 +04:00
|
|
|
if (cfp->iseq) {
|
|
|
|
return (rb_control_frame_t *)cfp;
|
|
|
|
}
|
|
|
|
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-03-07 08:34:31 +03:00
|
|
|
rb_control_frame_t *
|
2017-10-26 11:41:34 +03:00
|
|
|
rb_vm_get_ruby_level_next_cfp(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
|
* vm.c, eval_intern.h (PASS_PASSED_BLOCK):
set a VM_FRAME_FLAG_PASSED flag to skip this frame when
searching ruby-level-cfp.
* eval.c, eval_intern.h, proc.c: fix to check cfp. if there is
no valid ruby-level-cfp, cause RuntimeError exception.
[ruby-dev:34128]
* vm_core.h, vm_evalbody.c, vm.c, vm_dump.c, vm_insnhelper.c,
insns.def: rename FRAME_MAGIC_* to VM_FRAME_MAGIC_*.
* KNOWNBUGS.rb, bootstraptest/test*.rb: move solved bugs.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17084 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-06-11 01:46:43 +04:00
|
|
|
{
|
2017-10-26 11:41:34 +03:00
|
|
|
while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(ec, cfp)) {
|
2016-08-03 04:50:50 +03:00
|
|
|
if (VM_FRAME_RUBYFRAME_P(cfp)) {
|
2012-11-29 11:05:27 +04:00
|
|
|
return (rb_control_frame_t *)cfp;
|
* vm.c, eval_intern.h (PASS_PASSED_BLOCK):
set a VM_FRAME_FLAG_PASSED flag to skip this frame when
searching ruby-level-cfp.
* eval.c, eval_intern.h, proc.c: fix to check cfp. if there is
no valid ruby-level-cfp, cause RuntimeError exception.
[ruby-dev:34128]
* vm_core.h, vm_evalbody.c, vm.c, vm_dump.c, vm_insnhelper.c,
insns.def: rename FRAME_MAGIC_* to VM_FRAME_MAGIC_*.
* KNOWNBUGS.rb, bootstraptest/test*.rb: move solved bugs.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17084 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-06-11 01:46:43 +04:00
|
|
|
}
|
|
|
|
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-01-19 06:03:09 +03:00
|
|
|
static rb_control_frame_t *
|
2017-10-27 03:46:11 +03:00
|
|
|
vm_get_ruby_level_caller_cfp(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
|
2008-05-22 13:55:36 +04:00
|
|
|
{
|
2016-08-03 04:50:50 +03:00
|
|
|
if (VM_FRAME_RUBYFRAME_P(cfp)) {
|
2014-12-17 06:08:20 +03:00
|
|
|
return (rb_control_frame_t *)cfp;
|
* vm.c, eval_intern.h (PASS_PASSED_BLOCK):
set a VM_FRAME_FLAG_PASSED flag to skip this frame when
searching ruby-level-cfp.
* eval.c, eval_intern.h, proc.c: fix to check cfp. if there is
no valid ruby-level-cfp, cause RuntimeError exception.
[ruby-dev:34128]
* vm_core.h, vm_evalbody.c, vm.c, vm_dump.c, vm_insnhelper.c,
insns.def: rename FRAME_MAGIC_* to VM_FRAME_MAGIC_*.
* KNOWNBUGS.rb, bootstraptest/test*.rb: move solved bugs.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17084 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-06-11 01:46:43 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
|
|
|
|
2017-10-27 03:46:11 +03:00
|
|
|
while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(ec, cfp)) {
|
2016-08-03 04:50:50 +03:00
|
|
|
if (VM_FRAME_RUBYFRAME_P(cfp)) {
|
2014-12-17 06:08:20 +03:00
|
|
|
return (rb_control_frame_t *)cfp;
|
2008-05-22 13:55:36 +04:00
|
|
|
}
|
* vm.c, eval_intern.h (PASS_PASSED_BLOCK):
set a VM_FRAME_FLAG_PASSED flag to skip this frame when
searching ruby-level-cfp.
* eval.c, eval_intern.h, proc.c: fix to check cfp. if there is
no valid ruby-level-cfp, cause RuntimeError exception.
[ruby-dev:34128]
* vm_core.h, vm_evalbody.c, vm.c, vm_dump.c, vm_insnhelper.c,
insns.def: rename FRAME_MAGIC_* to VM_FRAME_MAGIC_*.
* KNOWNBUGS.rb, bootstraptest/test*.rb: move solved bugs.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17084 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-06-11 01:46:43 +04:00
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
if (VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_PASSED) == FALSE) {
|
* vm.c, eval_intern.h (PASS_PASSED_BLOCK):
set a VM_FRAME_FLAG_PASSED flag to skip this frame when
searching ruby-level-cfp.
* eval.c, eval_intern.h, proc.c: fix to check cfp. if there is
no valid ruby-level-cfp, cause RuntimeError exception.
[ruby-dev:34128]
* vm_core.h, vm_evalbody.c, vm.c, vm_dump.c, vm_insnhelper.c,
insns.def: rename FRAME_MAGIC_* to VM_FRAME_MAGIC_*.
* KNOWNBUGS.rb, bootstraptest/test*.rb: move solved bugs.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17084 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-06-11 01:46:43 +04:00
|
|
|
break;
|
|
|
|
}
|
2008-05-22 13:55:36 +04:00
|
|
|
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-03-07 09:02:03 +03:00
|
|
|
void
|
2014-01-09 14:12:59 +04:00
|
|
|
rb_vm_pop_cfunc_frame(void)
|
|
|
|
{
|
2017-10-29 16:19:14 +03:00
|
|
|
rb_execution_context_t *ec = GET_EC();
|
|
|
|
rb_control_frame_t *cfp = ec->cfp;
|
2016-07-26 13:28:21 +03:00
|
|
|
const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
|
2015-06-02 07:20:30 +03:00
|
|
|
|
2017-10-29 16:19:14 +03:00
|
|
|
EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_RETURN, cfp->self, me->def->original_id, me->called_id, me->owner, Qnil);
|
2017-11-07 11:19:25 +03:00
|
|
|
RUBY_DTRACE_CMETHOD_RETURN_HOOK(ec, me->owner, me->def->original_id);
|
2017-10-29 16:19:14 +03:00
|
|
|
vm_pop_frame(ec, cfp, cfp->ep);
|
2014-01-09 14:12:59 +04:00
|
|
|
}
|
|
|
|
|
2014-06-19 16:43:48 +04:00
|
|
|
void
|
2017-10-28 13:43:30 +03:00
|
|
|
rb_vm_rewind_cfp(rb_execution_context_t *ec, rb_control_frame_t *cfp)
|
2014-06-19 16:43:48 +04:00
|
|
|
{
|
|
|
|
/* check skipped frame */
|
2017-10-28 13:43:30 +03:00
|
|
|
while (ec->cfp != cfp) {
|
2014-06-19 16:43:48 +04:00
|
|
|
#if VMDEBUG
|
2017-10-28 13:43:30 +03:00
|
|
|
printf("skipped frame: %s\n", vm_frametype_name(ec->cfp));
|
2014-06-19 16:43:48 +04:00
|
|
|
#endif
|
2017-10-28 13:43:30 +03:00
|
|
|
if (VM_FRAME_TYPE(ec->cfp) != VM_FRAME_MAGIC_CFUNC) {
|
|
|
|
rb_vm_pop_frame(ec);
|
2014-06-19 16:43:48 +04:00
|
|
|
}
|
|
|
|
else { /* unlikely path */
|
|
|
|
rb_vm_pop_cfunc_frame();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-02 14:06:32 +03:00
|
|
|
/* at exit */
|
|
|
|
|
|
|
|
void
|
|
|
|
ruby_vm_at_exit(void (*func)(rb_vm_t *))
|
|
|
|
{
|
2016-04-04 17:37:07 +03:00
|
|
|
rb_vm_t *vm = GET_VM();
|
|
|
|
rb_at_exit_list *nl = ALLOC(rb_at_exit_list);
|
|
|
|
nl->func = func;
|
|
|
|
nl->next = vm->at_exit;
|
|
|
|
vm->at_exit = nl;
|
2010-12-02 14:06:32 +03:00
|
|
|
}
|
|
|
|
|
2011-02-24 16:51:59 +03:00
|
|
|
static void
|
|
|
|
ruby_vm_run_at_exit_hooks(rb_vm_t *vm)
|
|
|
|
{
|
2016-04-04 17:37:07 +03:00
|
|
|
rb_at_exit_list *l = vm->at_exit;
|
2011-02-24 16:51:59 +03:00
|
|
|
|
2016-04-04 17:37:07 +03:00
|
|
|
while (l) {
|
|
|
|
rb_at_exit_list* t = l->next;
|
|
|
|
rb_vm_at_exit_func *func = l->func;
|
2017-05-12 09:19:00 +03:00
|
|
|
ruby_xfree(l);
|
2016-04-04 17:37:07 +03:00
|
|
|
l = t;
|
2011-02-24 16:51:59 +03:00
|
|
|
(*func)(vm);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
* blockinlining.c, compile.c, compile.h, error.c, eval.c,
eval_intern.h, eval_jump.h, eval_load.c, eval_method.h,
eval_safe.h, gc.c, insnhelper.h, insns.def, iseq.c, proc.c,
process.c, signal.c, thread.c, thread_pthread.ci, thread_win32.ci,
vm.c, vm.h, vm_dump.c, vm_evalbody.ci, vm_macro.def,
yarv.h, yarvcore.h, yarvcore.c: change type and macro names:
* yarv_*_t -> rb_*_t
* yarv_*_struct -> rb_*_struct
* yarv_tag -> rb_vm_tag
* YARV_* -> RUBY_VM_*
* proc.c, vm.c: move functions about env object creation
from proc.c to vm.c.
* proc.c, yarvcore.c: fix rb_cVM initialization place.
* inits.c: change Init_ISeq() order (after Init_VM).
* ruby.h, proc.c: change declaration place of rb_cEnv
from proc.c to ruby.c.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11651 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-02-06 22:00:03 +03:00
|
|
|
/* Env */
|
|
|
|
|
2016-07-28 22:13:26 +03:00
|
|
|
static VALUE check_env_value(const rb_env_t *env);
|
2007-06-25 06:44:20 +04:00
|
|
|
|
|
|
|
static int
|
2016-07-28 22:13:26 +03:00
|
|
|
check_env(const rb_env_t *env)
|
2007-06-25 06:44:20 +04:00
|
|
|
{
|
2021-09-09 17:21:06 +03:00
|
|
|
fputs("---\n", stderr);
|
|
|
|
ruby_debug_printf("envptr: %p\n", (void *)&env->ep[0]);
|
|
|
|
ruby_debug_printf("envval: %10p ", (void *)env->ep[1]);
|
2016-07-28 14:02:30 +03:00
|
|
|
dp(env->ep[1]);
|
2021-09-09 17:21:06 +03:00
|
|
|
ruby_debug_printf("ep: %10p\n", (void *)env->ep);
|
2016-07-28 22:13:26 +03:00
|
|
|
if (rb_vm_env_prev_env(env)) {
|
2021-09-09 17:21:06 +03:00
|
|
|
fputs(">>\n", stderr);
|
2016-07-28 22:13:26 +03:00
|
|
|
check_env_value(rb_vm_env_prev_env(env));
|
2021-09-09 17:21:06 +03:00
|
|
|
fputs("<<\n", stderr);
|
2007-06-25 06:44:20 +04:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2016-07-28 22:13:26 +03:00
|
|
|
check_env_value(const rb_env_t *env)
|
2007-06-25 06:44:20 +04:00
|
|
|
{
|
|
|
|
if (check_env(env)) {
|
2016-07-28 22:13:26 +03:00
|
|
|
return (VALUE)env;
|
2007-06-25 06:44:20 +04:00
|
|
|
}
|
2007-08-20 18:17:16 +04:00
|
|
|
rb_bug("invalid env");
|
2007-06-25 06:44:20 +04:00
|
|
|
return Qnil; /* unreachable */
|
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2018-05-23 09:56:08 +03:00
|
|
|
static VALUE
|
|
|
|
vm_block_handler_escape(const rb_execution_context_t *ec, VALUE block_handler)
|
2015-07-14 19:23:17 +03:00
|
|
|
{
|
2016-07-28 14:02:30 +03:00
|
|
|
switch (vm_block_handler_type(block_handler)) {
|
|
|
|
case block_handler_type_ifunc:
|
|
|
|
case block_handler_type_iseq:
|
2023-11-15 13:05:10 +03:00
|
|
|
return rb_vm_make_proc(ec, VM_BH_TO_CAPT_BLOCK(block_handler), rb_cProc);
|
2016-07-28 14:02:30 +03:00
|
|
|
|
|
|
|
case block_handler_type_symbol:
|
|
|
|
case block_handler_type_proc:
|
2018-05-23 09:56:08 +03:00
|
|
|
return block_handler;
|
2015-07-14 19:23:17 +03:00
|
|
|
}
|
2016-07-28 14:02:30 +03:00
|
|
|
VM_UNREACHABLE(vm_block_handler_escape);
|
2018-05-23 09:56:08 +03:00
|
|
|
return Qnil;
|
2015-07-14 19:23:17 +03:00
|
|
|
}
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
static VALUE
|
2017-10-26 11:41:34 +03:00
|
|
|
vm_make_env_each(const rb_execution_context_t * const ec, rb_control_frame_t *const cfp)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2016-07-28 14:02:30 +03:00
|
|
|
const VALUE * const ep = cfp->ep;
|
2016-07-28 22:13:26 +03:00
|
|
|
VALUE *env_body, *env_ep;
|
2015-07-15 08:43:07 +03:00
|
|
|
int local_size, env_size;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
if (VM_ENV_ESCAPED_P(ep)) {
|
|
|
|
return VM_ENV_ENVVAL(ep);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
if (!VM_ENV_LOCAL_P(ep)) {
|
|
|
|
const VALUE *prev_ep = VM_ENV_PREV_EP(ep);
|
2020-10-23 07:27:21 +03:00
|
|
|
if (!VM_ENV_ESCAPED_P(prev_ep)) {
|
|
|
|
rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2020-10-23 07:27:21 +03:00
|
|
|
while (prev_cfp->ep != prev_ep) {
|
|
|
|
prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(prev_cfp);
|
|
|
|
VM_ASSERT(prev_cfp->ep != NULL);
|
|
|
|
}
|
2015-07-14 19:23:17 +03:00
|
|
|
|
2020-10-23 07:27:21 +03:00
|
|
|
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));
|
|
|
|
}
|
2015-07-14 19:23:17 +03:00
|
|
|
}
|
|
|
|
else {
|
2016-07-28 14:02:30 +03:00
|
|
|
VALUE block_handler = VM_ENV_BLOCK_HANDLER(ep);
|
2015-07-14 19:23:17 +03:00
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
if (block_handler != VM_BLOCK_HANDLER_NONE) {
|
2018-05-23 09:56:08 +03:00
|
|
|
VALUE blockprocval = vm_block_handler_escape(ec, block_handler);
|
2016-07-28 14:02:30 +03:00
|
|
|
VM_STACK_ENV_WRITE(ep, VM_ENV_DATA_INDEX_SPECVAL, blockprocval);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
}
|
2007-01-17 11:48:52 +03:00
|
|
|
|
2016-08-03 04:50:50 +03:00
|
|
|
if (!VM_FRAME_RUBYFRAME_P(cfp)) {
|
2016-07-28 14:02:30 +03:00
|
|
|
local_size = VM_ENV_DATA_SIZE;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
else {
|
Optimized forwarding callers and callees
This patch optimizes forwarding callers and callees. It only optimizes methods that only take `...` as their parameter, and then pass `...` to other calls.
Calls it optimizes look like this:
```ruby
def bar(a) = a
def foo(...) = bar(...) # optimized
foo(123)
```
```ruby
def bar(a) = a
def foo(...) = bar(1, 2, ...) # optimized
foo(123)
```
```ruby
def bar(*a) = a
def foo(...)
list = [1, 2]
bar(*list, ...) # optimized
end
foo(123)
```
All variants of the above but using `super` are also optimized, including a bare super like this:
```ruby
def foo(...)
super
end
```
This patch eliminates intermediate allocations made when calling methods that accept `...`.
We can observe allocation elimination like this:
```ruby
def m
x = GC.stat(:total_allocated_objects)
yield
GC.stat(:total_allocated_objects) - x
end
def bar(a) = a
def foo(...) = bar(...)
def test
m { foo(123) }
end
test
p test # allocates 1 object on master, but 0 objects with this patch
```
```ruby
def bar(a, b:) = a + b
def foo(...) = bar(...)
def test
m { foo(1, b: 2) }
end
test
p test # allocates 2 objects on master, but 0 objects with this patch
```
How does it work?
-----------------
This patch works by using a dynamic stack size when passing forwarded parameters to callees.
The caller's info object (known as the "CI") contains the stack size of the
parameters, so we pass the CI object itself as a parameter to the callee.
When forwarding parameters, the forwarding ISeq uses the caller's CI to determine how much stack to copy, then copies the caller's stack before calling the callee.
The CI at the forwarded call site is adjusted using information from the caller's CI.
I think this description is kind of confusing, so let's walk through an example with code.
```ruby
def delegatee(a, b) = a + b
def delegator(...)
delegatee(...) # CI2 (FORWARDING)
end
def caller
delegator(1, 2) # CI1 (argc: 2)
end
```
Before we call the delegator method, the stack looks like this:
```
Executing Line | Code | Stack
---------------+---------------------------------------+--------
1| def delegatee(a, b) = a + b | self
2| | 1
3| def delegator(...) | 2
4| # |
5| delegatee(...) # CI2 (FORWARDING) |
6| end |
7| |
8| def caller |
-> 9| delegator(1, 2) # CI1 (argc: 2) |
10| end |
```
The ISeq for `delegator` is tagged as "forwardable", so when `caller` calls in
to `delegator`, it writes `CI1` on to the stack as a local variable for the
`delegator` method. The `delegator` method has a special local called `...`
that holds the caller's CI object.
Here is the ISeq disasm fo `delegator`:
```
== disasm: #<ISeq:delegator@-e:1 (1,0)-(1,39)>
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 1] "..."@0
0000 putself ( 1)[LiCa]
0001 getlocal_WC_0 "..."@0
0003 send <calldata!mid:delegatee, argc:0, FCALL|FORWARDING>, nil
0006 leave [Re]
```
The local called `...` will contain the caller's CI: CI1.
Here is the stack when we enter `delegator`:
```
Executing Line | Code | Stack
---------------+---------------------------------------+--------
1| def delegatee(a, b) = a + b | self
2| | 1
3| def delegator(...) | 2
-> 4| # | CI1 (argc: 2)
5| delegatee(...) # CI2 (FORWARDING) | cref_or_me
6| end | specval
7| | type
8| def caller |
9| delegator(1, 2) # CI1 (argc: 2) |
10| end |
```
The CI at `delegatee` on line 5 is tagged as "FORWARDING", so it knows to
memcopy the caller's stack before calling `delegatee`. In this case, it will
memcopy self, 1, and 2 to the stack before calling `delegatee`. It knows how much
memory to copy from the caller because `CI1` contains stack size information
(argc: 2).
Before executing the `send` instruction, we push `...` on the stack. The
`send` instruction pops `...`, and because it is tagged with `FORWARDING`, it
knows to memcopy (using the information in the CI it just popped):
```
== disasm: #<ISeq:delegator@-e:1 (1,0)-(1,39)>
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 1] "..."@0
0000 putself ( 1)[LiCa]
0001 getlocal_WC_0 "..."@0
0003 send <calldata!mid:delegatee, argc:0, FCALL|FORWARDING>, nil
0006 leave [Re]
```
Instruction 001 puts the caller's CI on the stack. `send` is tagged with
FORWARDING, so it reads the CI and _copies_ the callers stack to this stack:
```
Executing Line | Code | Stack
---------------+---------------------------------------+--------
1| def delegatee(a, b) = a + b | self
2| | 1
3| def delegator(...) | 2
4| # | CI1 (argc: 2)
-> 5| delegatee(...) # CI2 (FORWARDING) | cref_or_me
6| end | specval
7| | type
8| def caller | self
9| delegator(1, 2) # CI1 (argc: 2) | 1
10| end | 2
```
The "FORWARDING" call site combines information from CI1 with CI2 in order
to support passing other values in addition to the `...` value, as well as
perfectly forward splat args, kwargs, etc.
Since we're able to copy the stack from `caller` in to `delegator`'s stack, we
can avoid allocating objects.
I want to do this to eliminate object allocations for delegate methods.
My long term goal is to implement `Class#new` in Ruby and it uses `...`.
I was able to implement `Class#new` in Ruby
[here](https://github.com/ruby/ruby/pull/9289).
If we adopt the technique in this patch, then we can optimize allocating
objects that take keyword parameters for `initialize`.
For example, this code will allocate 2 objects: one for `SomeObject`, and one
for the kwargs:
```ruby
SomeObject.new(foo: 1)
```
If we combine this technique, plus implement `Class#new` in Ruby, then we can
reduce allocations for this common operation.
Co-Authored-By: John Hawthorn <john@hawthorn.email>
Co-Authored-By: Alan Wu <XrXr@users.noreply.github.com>
2024-04-15 20:48:53 +03:00
|
|
|
local_size = ISEQ_BODY(cfp->iseq)->local_table_size;
|
|
|
|
if (ISEQ_BODY(cfp->iseq)->param.flags.forwardable && VM_ENV_LOCAL_P(cfp->ep)) {
|
|
|
|
int ci_offset = local_size - ISEQ_BODY(cfp->iseq)->param.size + VM_ENV_DATA_SIZE;
|
|
|
|
|
|
|
|
CALL_INFO ci = (CALL_INFO)VM_CF_LEP(cfp)[-ci_offset];
|
|
|
|
local_size += vm_ci_argc(ci);
|
|
|
|
}
|
|
|
|
local_size += VM_ENV_DATA_SIZE;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 08:43:07 +03:00
|
|
|
/*
|
|
|
|
* # local variables on a stack frame (N == local_size)
|
|
|
|
* [lvar1, lvar2, ..., lvarN, SPECVAL]
|
|
|
|
* ^
|
|
|
|
* ep[0]
|
|
|
|
*
|
|
|
|
* # moved local variables
|
|
|
|
* [lvar1, lvar2, ..., lvarN, SPECVAL, Envval, BlockProcval (if needed)]
|
|
|
|
* ^ ^
|
|
|
|
* env->env[0] ep[0]
|
|
|
|
*/
|
|
|
|
|
2015-07-14 19:23:17 +03:00
|
|
|
env_size = local_size +
|
2018-05-23 09:56:08 +03:00
|
|
|
1 /* envval */;
|
2023-11-30 02:10:13 +03:00
|
|
|
|
|
|
|
// Careful with order in the following sequence. Each allocation can move objects.
|
2016-07-28 22:13:26 +03:00
|
|
|
env_body = ALLOC_N(VALUE, env_size);
|
2024-02-20 23:58:10 +03:00
|
|
|
rb_env_t *env = IMEMO_NEW(rb_env_t, imemo_env, 0);
|
2023-11-30 02:10:13 +03:00
|
|
|
|
|
|
|
// Set up env without WB since it's brand new (similar to newobj_init(), newobj_fill())
|
2016-07-28 22:13:26 +03:00
|
|
|
MEMCPY(env_body, ep - (local_size - 1 /* specval */), VALUE, local_size);
|
2015-07-15 08:43:07 +03:00
|
|
|
|
2023-11-30 02:10:13 +03:00
|
|
|
env_ep = &env_body[local_size - 1 /* specval */];
|
|
|
|
env_ep[VM_ENV_DATA_INDEX_ENV] = (VALUE)env;
|
|
|
|
|
|
|
|
env->iseq = (rb_iseq_t *)(VM_FRAME_RUBYFRAME_P(cfp) ? cfp->iseq : NULL);
|
|
|
|
env->ep = env_ep;
|
|
|
|
env->env = env_body;
|
|
|
|
env->env_size = env_size;
|
|
|
|
|
|
|
|
cfp->ep = env_ep;
|
|
|
|
VM_ENV_FLAGS_SET(env_ep, VM_ENV_FLAG_ESCAPED | VM_ENV_FLAG_WB_REQUIRED);
|
|
|
|
VM_STACK_ENV_WRITE(ep, 0, (VALUE)env); /* GC mark */
|
|
|
|
|
2007-08-16 11:46:11 +04:00
|
|
|
#if 0
|
2015-07-15 08:43:07 +03:00
|
|
|
for (i = 0; i < local_size; i++) {
|
2016-08-03 04:50:50 +03:00
|
|
|
if (VM_FRAME_RUBYFRAME_P(cfp)) {
|
2006-12-31 18:02:22 +03:00
|
|
|
/* clear value stack for GC */
|
2015-07-14 19:23:17 +03:00
|
|
|
ep[-local_size + i] = 0;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
}
|
2015-03-29 05:47:24 +03:00
|
|
|
#endif
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2024-04-25 17:04:53 +03:00
|
|
|
// Invalidate JIT code that assumes cfp->ep == vm_base_ptr(cfp).
|
|
|
|
if (env->iseq) {
|
|
|
|
rb_yjit_invalidate_ep_is_bp(env->iseq);
|
|
|
|
}
|
|
|
|
|
2016-07-28 22:13:26 +03:00
|
|
|
return (VALUE)env;
|
2015-07-14 19:23:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2017-10-26 11:41:34 +03:00
|
|
|
vm_make_env_object(const rb_execution_context_t *ec, rb_control_frame_t *cfp)
|
2015-07-14 19:23:17 +03:00
|
|
|
{
|
2017-10-26 11:41:34 +03:00
|
|
|
VALUE envval = vm_make_env_each(ec, cfp);
|
2015-07-14 19:23:17 +03:00
|
|
|
|
|
|
|
if (PROCDEBUG) {
|
2016-07-28 22:13:26 +03:00
|
|
|
check_env_value((const rb_env_t *)envval);
|
2015-07-14 19:23:17 +03:00
|
|
|
}
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
return envval;
|
|
|
|
}
|
|
|
|
|
2015-07-14 19:23:17 +03:00
|
|
|
void
|
2017-10-28 13:47:19 +03:00
|
|
|
rb_vm_stack_to_heap(rb_execution_context_t *ec)
|
2015-07-14 19:23:17 +03:00
|
|
|
{
|
2017-10-28 13:47:19 +03:00
|
|
|
rb_control_frame_t *cfp = ec->cfp;
|
|
|
|
while ((cfp = rb_vm_get_binding_creatable_next_cfp(ec, cfp)) != 0) {
|
|
|
|
vm_make_env_object(ec, cfp);
|
2015-07-14 19:23:17 +03:00
|
|
|
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-28 22:13:26 +03:00
|
|
|
const rb_env_t *
|
|
|
|
rb_vm_env_prev_env(const rb_env_t *env)
|
2015-07-14 20:36:36 +03:00
|
|
|
{
|
2016-07-28 14:02:30 +03:00
|
|
|
const VALUE *ep = env->ep;
|
2015-07-14 20:36:36 +03:00
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
if (VM_ENV_LOCAL_P(ep)) {
|
2016-07-28 22:13:26 +03:00
|
|
|
return NULL;
|
2015-07-14 20:36:36 +03:00
|
|
|
}
|
|
|
|
else {
|
2020-10-23 07:27:21 +03:00
|
|
|
const VALUE *prev_ep = VM_ENV_PREV_EP(ep);
|
|
|
|
return VM_ENV_ENVVAL_PTR(prev_ep);
|
2015-07-14 20:36:36 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
static int
|
2014-07-01 21:55:44 +04:00
|
|
|
collect_local_variables_in_iseq(const rb_iseq_t *iseq, const struct local_var_list *vars)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2015-07-25 00:44:14 +03:00
|
|
|
unsigned int i;
|
2009-09-21 12:12:12 +04:00
|
|
|
if (!iseq) return 0;
|
2022-03-23 22:19:48 +03:00
|
|
|
for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
|
|
|
|
local_var_list_add(vars, ISEQ_BODY(iseq)->local_table[i]);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2009-09-21 12:12:12 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-07-01 21:55:44 +04:00
|
|
|
static void
|
|
|
|
collect_local_variables_in_env(const rb_env_t *env, const struct local_var_list *vars)
|
2009-09-21 12:12:12 +04:00
|
|
|
{
|
2016-07-28 22:13:26 +03:00
|
|
|
do {
|
2020-10-23 07:27:21 +03:00
|
|
|
if (VM_ENV_FLAGS(env->ep, VM_ENV_FLAG_ISOLATED)) break;
|
2016-07-28 22:13:26 +03:00
|
|
|
collect_local_variables_in_iseq(env->iseq, vars);
|
|
|
|
} while ((env = rb_vm_env_prev_env(env)) != NULL);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2009-01-19 03:13:44 +03:00
|
|
|
static int
|
2017-10-27 03:46:11 +03:00
|
|
|
vm_collect_local_variables_in_heap(const VALUE *ep, const struct local_var_list *vars)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2016-07-28 14:02:30 +03:00
|
|
|
if (VM_ENV_ESCAPED_P(ep)) {
|
2016-07-28 22:13:26 +03:00
|
|
|
collect_local_variables_in_env(VM_ENV_ENVVAL_PTR(ep), vars);
|
2006-12-31 18:02:22 +03:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-01 21:57:37 +04:00
|
|
|
VALUE
|
2015-07-14 20:36:36 +03:00
|
|
|
rb_vm_env_local_variables(const rb_env_t *env)
|
2014-07-01 21:57:37 +04:00
|
|
|
{
|
|
|
|
struct local_var_list vars;
|
|
|
|
local_var_list_init(&vars);
|
|
|
|
collect_local_variables_in_env(env, &vars);
|
|
|
|
return local_var_list_finish(&vars);
|
|
|
|
}
|
|
|
|
|
2015-12-08 08:27:10 +03:00
|
|
|
VALUE
|
|
|
|
rb_iseq_local_variables(const rb_iseq_t *iseq)
|
|
|
|
{
|
|
|
|
struct local_var_list vars;
|
|
|
|
local_var_list_init(&vars);
|
|
|
|
while (collect_local_variables_in_iseq(iseq, &vars)) {
|
2022-03-23 22:19:48 +03:00
|
|
|
iseq = ISEQ_BODY(iseq)->parent_iseq;
|
2015-12-08 08:27:10 +03:00
|
|
|
}
|
|
|
|
return local_var_list_finish(&vars);
|
|
|
|
}
|
|
|
|
|
2007-06-25 06:44:20 +04:00
|
|
|
/* Proc */
|
|
|
|
|
2017-11-16 10:43:27 +03:00
|
|
|
static VALUE
|
|
|
|
vm_proc_create_from_captured(VALUE klass,
|
2016-07-28 14:02:30 +03:00
|
|
|
const struct rb_captured_block *captured,
|
|
|
|
enum rb_block_type block_type,
|
2017-12-28 23:09:24 +03:00
|
|
|
int8_t is_from_method, int8_t is_lambda)
|
2014-09-13 00:57:45 +04:00
|
|
|
{
|
2015-05-16 15:21:25 +03:00
|
|
|
VALUE procval = rb_proc_alloc(klass);
|
|
|
|
rb_proc_t *proc = RTYPEDDATA_DATA(procval);
|
2014-09-13 00:57:45 +04:00
|
|
|
|
2017-10-26 17:44:09 +03:00
|
|
|
VM_ASSERT(VM_EP_IN_HEAP_P(GET_EC(), captured->ep));
|
2016-07-28 14:02:30 +03:00
|
|
|
|
|
|
|
/* copy block */
|
|
|
|
RB_OBJ_WRITE(procval, &proc->block.as.captured.code.val, captured->code.val);
|
2020-12-04 08:59:12 +03:00
|
|
|
RB_OBJ_WRITE(procval, &proc->block.as.captured.self, captured->self);
|
2017-06-01 18:12:14 +03:00
|
|
|
rb_vm_block_ep_update(procval, &proc->block, captured->ep);
|
2016-07-28 14:02:30 +03:00
|
|
|
|
|
|
|
vm_block_type_set(&proc->block, block_type);
|
2014-09-13 00:57:45 +04:00
|
|
|
proc->is_from_method = is_from_method;
|
|
|
|
proc->is_lambda = is_lambda;
|
|
|
|
|
|
|
|
return procval;
|
|
|
|
}
|
|
|
|
|
2017-06-01 18:12:14 +03:00
|
|
|
void
|
|
|
|
rb_vm_block_copy(VALUE obj, const struct rb_block *dst, const struct rb_block *src)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2016-07-28 14:02:30 +03:00
|
|
|
/* copy block */
|
2017-06-01 18:12:14 +03:00
|
|
|
switch (vm_block_type(src)) {
|
2016-07-28 14:02:30 +03:00
|
|
|
case block_type_iseq:
|
|
|
|
case block_type_ifunc:
|
2017-06-01 18:12:14 +03:00
|
|
|
RB_OBJ_WRITE(obj, &dst->as.captured.self, src->as.captured.self);
|
|
|
|
RB_OBJ_WRITE(obj, &dst->as.captured.code.val, src->as.captured.code.val);
|
|
|
|
rb_vm_block_ep_update(obj, dst, src->as.captured.ep);
|
2016-07-28 14:02:30 +03:00
|
|
|
break;
|
|
|
|
case block_type_symbol:
|
2017-06-01 18:12:14 +03:00
|
|
|
RB_OBJ_WRITE(obj, &dst->as.symbol, src->as.symbol);
|
2016-07-28 14:02:30 +03:00
|
|
|
break;
|
|
|
|
case block_type_proc:
|
2017-06-01 18:12:14 +03:00
|
|
|
RB_OBJ_WRITE(obj, &dst->as.proc, src->as.proc);
|
2016-07-28 14:02:30 +03:00
|
|
|
break;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2017-06-01 18:12:14 +03:00
|
|
|
}
|
|
|
|
|
2017-12-28 23:09:24 +03:00
|
|
|
static VALUE
|
|
|
|
proc_create(VALUE klass, const struct rb_block *block, int8_t is_from_method, int8_t is_lambda)
|
2017-06-01 18:12:14 +03:00
|
|
|
{
|
|
|
|
VALUE procval = rb_proc_alloc(klass);
|
|
|
|
rb_proc_t *proc = RTYPEDDATA_DATA(procval);
|
|
|
|
|
2017-10-26 17:44:09 +03:00
|
|
|
VM_ASSERT(VM_EP_IN_HEAP_P(GET_EC(), vm_block_ep(block)));
|
2017-06-01 18:12:14 +03:00
|
|
|
rb_vm_block_copy(procval, &proc->block, block);
|
2016-07-28 14:02:30 +03:00
|
|
|
vm_block_type_set(&proc->block, block->type);
|
|
|
|
proc->is_from_method = is_from_method;
|
|
|
|
proc->is_lambda = is_lambda;
|
2007-06-17 21:50:56 +04:00
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
return procval;
|
|
|
|
}
|
|
|
|
|
2017-12-28 23:09:24 +03:00
|
|
|
VALUE
|
|
|
|
rb_proc_dup(VALUE self)
|
|
|
|
{
|
|
|
|
VALUE procval;
|
|
|
|
rb_proc_t *src;
|
|
|
|
|
|
|
|
GetProcPtr(self, src);
|
2021-02-18 11:10:39 +03:00
|
|
|
procval = proc_create(rb_obj_class(self), &src->block, src->is_from_method, src->is_lambda);
|
2020-10-29 18:32:53 +03:00
|
|
|
if (RB_OBJ_SHAREABLE_P(self)) FL_SET_RAW(procval, RUBY_FL_SHAREABLE);
|
2017-12-28 23:09:24 +03:00
|
|
|
RB_GC_GUARD(self); /* for: body = rb_proc_dup(body) */
|
|
|
|
return procval;
|
|
|
|
}
|
|
|
|
|
2020-10-23 07:27:21 +03:00
|
|
|
struct collect_outer_variable_name_data {
|
|
|
|
VALUE ary;
|
2020-10-29 18:32:53 +03:00
|
|
|
VALUE read_only;
|
2020-10-23 07:27:21 +03:00
|
|
|
bool yield;
|
2020-10-29 18:32:53 +03:00
|
|
|
bool isolate;
|
2020-10-23 07:27:21 +03:00
|
|
|
};
|
|
|
|
|
2021-11-07 19:43:06 +03:00
|
|
|
static VALUE
|
|
|
|
ID2NUM(ID id)
|
|
|
|
{
|
|
|
|
if (SIZEOF_VOIDP > SIZEOF_LONG)
|
|
|
|
return ULL2NUM(id);
|
|
|
|
else
|
|
|
|
return ULONG2NUM(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ID
|
|
|
|
NUM2ID(VALUE num)
|
|
|
|
{
|
|
|
|
if (SIZEOF_VOIDP > SIZEOF_LONG)
|
|
|
|
return (ID)NUM2ULL(num);
|
|
|
|
else
|
|
|
|
return (ID)NUM2ULONG(num);
|
|
|
|
}
|
|
|
|
|
2020-10-23 07:27:21 +03:00
|
|
|
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 {
|
2021-10-13 07:00:57 +03:00
|
|
|
VALUE *store;
|
2020-10-29 18:32:53 +03:00
|
|
|
if (data->isolate ||
|
|
|
|
val == Qtrue /* write */) {
|
2021-10-13 07:00:57 +03:00
|
|
|
store = &data->ary;
|
2020-10-29 18:32:53 +03:00
|
|
|
}
|
|
|
|
else {
|
2021-10-13 07:00:57 +03:00
|
|
|
store = &data->read_only;
|
2020-10-29 18:32:53 +03:00
|
|
|
}
|
2021-10-13 07:00:57 +03:00
|
|
|
if (*store == Qfalse) *store = rb_ary_new();
|
2021-11-07 19:43:06 +03:00
|
|
|
rb_ary_push(*store, ID2NUM(id));
|
2020-10-23 07:27:21 +03:00
|
|
|
}
|
|
|
|
return ID_TABLE_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const rb_env_t *
|
2020-10-29 18:32:53 +03:00
|
|
|
env_copy(const VALUE *src_ep, VALUE read_only_variables)
|
2020-10-23 07:27:21 +03:00
|
|
|
{
|
|
|
|
const rb_env_t *src_env = (rb_env_t *)VM_ENV_ENVVAL(src_ep);
|
2020-10-29 18:32:53 +03:00
|
|
|
VM_ASSERT(src_env->ep == src_ep);
|
|
|
|
|
2020-10-23 07:27:21 +03:00
|
|
|
VALUE *env_body = ZALLOC_N(VALUE, src_env->env_size); // fill with Qfalse
|
|
|
|
VALUE *ep = &env_body[src_env->env_size - 2];
|
2023-12-07 05:00:37 +03:00
|
|
|
const rb_env_t *copied_env = vm_env_new(ep, env_body, src_env->env_size, src_env->iseq);
|
|
|
|
|
|
|
|
// Copy after allocations above, since they can move objects in src_ep.
|
|
|
|
RB_OBJ_WRITE(copied_env, &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;
|
2023-12-04 22:02:56 +03:00
|
|
|
if (!VM_ENV_LOCAL_P(src_ep)) {
|
|
|
|
VM_ENV_FLAGS_SET(ep, VM_ENV_FLAG_LOCAL);
|
|
|
|
}
|
|
|
|
|
2020-10-29 18:32:53 +03:00
|
|
|
if (read_only_variables) {
|
2021-10-06 22:38:33 +03:00
|
|
|
for (int i=RARRAY_LENINT(read_only_variables)-1; i>=0; i--) {
|
2021-11-07 19:43:06 +03:00
|
|
|
ID id = NUM2ID(RARRAY_AREF(read_only_variables, i));
|
2020-10-29 18:32:53 +03:00
|
|
|
|
2022-03-23 22:19:48 +03:00
|
|
|
for (unsigned int j=0; j<ISEQ_BODY(src_env->iseq)->local_table_size; j++) {
|
2023-11-15 13:05:10 +03:00
|
|
|
if (id == ISEQ_BODY(src_env->iseq)->local_table[j]) {
|
2020-10-29 18:32:53 +03:00
|
|
|
VALUE v = src_env->env[j];
|
|
|
|
if (!rb_ractor_shareable_p(v)) {
|
2021-10-13 10:48:35 +03:00
|
|
|
VALUE name = rb_id2str(id);
|
|
|
|
VALUE msg = rb_sprintf("can not make shareable Proc because it can refer"
|
|
|
|
" unshareable object %+" PRIsVALUE " from ", v);
|
|
|
|
if (name)
|
2024-01-19 10:03:38 +03:00
|
|
|
rb_str_catf(msg, "variable '%" PRIsVALUE "'", name);
|
2021-10-13 10:48:35 +03:00
|
|
|
else
|
|
|
|
rb_str_cat_cstr(msg, "a hidden variable");
|
|
|
|
rb_exc_raise(rb_exc_new_str(rb_eRactorIsolationError, msg));
|
2020-10-29 18:32:53 +03:00
|
|
|
}
|
2023-12-04 22:02:56 +03:00
|
|
|
RB_OBJ_WRITE((VALUE)copied_env, &env_body[j], v);
|
2020-10-29 18:32:53 +03:00
|
|
|
rb_ary_delete_at(read_only_variables, i);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-10-23 07:27:21 +03:00
|
|
|
|
|
|
|
if (!VM_ENV_LOCAL_P(src_ep)) {
|
|
|
|
const VALUE *prev_ep = VM_ENV_PREV_EP(src_env->ep);
|
2020-10-29 18:32:53 +03:00
|
|
|
const rb_env_t *new_prev_env = env_copy(prev_ep, read_only_variables);
|
2020-10-23 07:27:21 +03:00
|
|
|
ep[VM_ENV_DATA_INDEX_SPECVAL] = VM_GUARDED_PREV_EP(new_prev_env->ep);
|
2023-12-07 04:35:40 +03:00
|
|
|
RB_OBJ_WRITTEN(copied_env, Qundef, new_prev_env);
|
2023-12-04 22:02:56 +03:00
|
|
|
VM_ENV_FLAGS_UNSET(ep, VM_ENV_FLAG_LOCAL);
|
2020-10-23 07:27:21 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
ep[VM_ENV_DATA_INDEX_SPECVAL] = VM_BLOCK_HANDLER_NONE;
|
|
|
|
}
|
2020-10-29 18:32:53 +03:00
|
|
|
|
2020-12-03 00:49:52 +03:00
|
|
|
return copied_env;
|
2020-10-23 07:27:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-10-29 18:32:53 +03:00
|
|
|
proc_isolate_env(VALUE self, rb_proc_t *proc, VALUE read_only_variables)
|
2020-10-23 07:27:21 +03:00
|
|
|
{
|
|
|
|
const struct rb_captured_block *captured = &proc->block.as.captured;
|
2020-10-29 18:32:53 +03:00
|
|
|
const rb_env_t *env = env_copy(captured->ep, read_only_variables);
|
2020-10-23 07:27:21 +03:00
|
|
|
*((const VALUE **)&proc->block.as.captured.ep) = env->ep;
|
|
|
|
RB_OBJ_WRITTEN(self, Qundef, env);
|
|
|
|
}
|
|
|
|
|
2021-10-29 11:34:09 +03:00
|
|
|
static VALUE
|
|
|
|
proc_shared_outer_variables(struct rb_id_table *outer_variables, bool isolate, const char *message)
|
|
|
|
{
|
|
|
|
struct collect_outer_variable_name_data data = {
|
|
|
|
.isolate = isolate,
|
|
|
|
.ary = Qfalse,
|
|
|
|
.read_only = Qfalse,
|
|
|
|
.yield = false,
|
|
|
|
};
|
|
|
|
rb_id_table_foreach(outer_variables, collect_outer_variable_names, (void *)&data);
|
|
|
|
|
|
|
|
if (data.ary != Qfalse) {
|
2021-11-07 19:43:06 +03:00
|
|
|
VALUE str = rb_sprintf("can not %s because it accesses outer variables", message);
|
|
|
|
VALUE ary = data.ary;
|
|
|
|
const char *sep = " (";
|
|
|
|
for (long i = 0; i < RARRAY_LEN(ary); i++) {
|
|
|
|
VALUE name = rb_id2str(NUM2ID(RARRAY_AREF(ary, i)));
|
|
|
|
if (!name) continue;
|
|
|
|
rb_str_cat_cstr(str, sep);
|
|
|
|
sep = ", ";
|
|
|
|
rb_str_append(str, name);
|
|
|
|
}
|
|
|
|
if (*sep == ',') rb_str_cat_cstr(str, ")");
|
2024-01-19 10:03:38 +03:00
|
|
|
rb_str_cat_cstr(str, data.yield ? " and uses 'yield'." : ".");
|
2021-10-29 11:34:09 +03:00
|
|
|
rb_exc_raise(rb_exc_new_str(rb_eArgError, str));
|
|
|
|
}
|
|
|
|
else if (data.yield) {
|
2024-01-19 10:03:38 +03:00
|
|
|
rb_raise(rb_eArgError, "can not %s because it uses 'yield'.", message);
|
2021-10-29 11:34:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return data.read_only;
|
|
|
|
}
|
|
|
|
|
2020-03-09 20:22:11 +03:00
|
|
|
VALUE
|
|
|
|
rb_proc_isolate_bang(VALUE self)
|
|
|
|
{
|
|
|
|
const rb_iseq_t *iseq = vm_proc_iseq(self);
|
2020-10-23 07:27:21 +03:00
|
|
|
|
|
|
|
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");
|
|
|
|
|
2022-03-23 22:19:48 +03:00
|
|
|
if (ISEQ_BODY(iseq)->outer_variables) {
|
|
|
|
proc_shared_outer_variables(ISEQ_BODY(iseq)->outer_variables, true, "isolate a Proc");
|
2020-10-23 07:27:21 +03:00
|
|
|
}
|
|
|
|
|
2020-10-29 18:32:53 +03:00
|
|
|
proc_isolate_env(self, proc, Qfalse);
|
2020-10-23 07:27:21 +03:00
|
|
|
proc->is_isolated = TRUE;
|
2020-03-09 20:22:11 +03:00
|
|
|
}
|
|
|
|
|
2020-10-29 18:32:53 +03:00
|
|
|
FL_SET_RAW(self, RUBY_FL_SHAREABLE);
|
2020-03-09 20:22:11 +03:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_proc_isolate(VALUE self)
|
|
|
|
{
|
|
|
|
VALUE dst = rb_proc_dup(self);
|
|
|
|
rb_proc_isolate_bang(dst);
|
|
|
|
return dst;
|
|
|
|
}
|
2017-12-28 23:09:24 +03:00
|
|
|
|
2020-10-29 18:32:53 +03:00
|
|
|
VALUE
|
|
|
|
rb_proc_ractor_make_shareable(VALUE self)
|
|
|
|
{
|
|
|
|
const rb_iseq_t *iseq = vm_proc_iseq(self);
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
2021-12-08 21:58:44 +03:00
|
|
|
if (!rb_ractor_shareable_p(vm_block_self(&proc->block))) {
|
2021-12-22 02:59:04 +03:00
|
|
|
rb_raise(rb_eRactorIsolationError,
|
|
|
|
"Proc's self is not shareable: %" PRIsVALUE,
|
|
|
|
self);
|
2021-12-08 21:58:44 +03:00
|
|
|
}
|
|
|
|
|
2020-10-29 18:32:53 +03:00
|
|
|
VALUE read_only_variables = Qfalse;
|
|
|
|
|
2022-03-23 22:19:48 +03:00
|
|
|
if (ISEQ_BODY(iseq)->outer_variables) {
|
2021-10-29 11:34:09 +03:00
|
|
|
read_only_variables =
|
2022-03-23 22:19:48 +03:00
|
|
|
proc_shared_outer_variables(ISEQ_BODY(iseq)->outer_variables, false, "make a Proc shareable");
|
2020-10-29 18:32:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
proc_isolate_env(self, proc, read_only_variables);
|
|
|
|
proc->is_isolated = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
FL_SET_RAW(self, RUBY_FL_SHAREABLE);
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2023-03-07 08:34:31 +03:00
|
|
|
VALUE
|
2017-10-26 11:41:34 +03:00
|
|
|
rb_vm_make_proc_lambda(const rb_execution_context_t *ec, const struct rb_captured_block *captured, VALUE klass, int8_t is_lambda)
|
2016-07-28 14:02:30 +03:00
|
|
|
{
|
|
|
|
VALUE procval;
|
2023-02-10 10:02:20 +03:00
|
|
|
enum imemo_type code_type = imemo_type(captured->code.val);
|
2016-07-28 14:02:30 +03:00
|
|
|
|
2016-07-28 22:27:52 +03:00
|
|
|
if (!VM_ENV_ESCAPED_P(captured->ep)) {
|
2016-07-28 14:02:30 +03:00
|
|
|
rb_control_frame_t *cfp = VM_CAPTURED_BLOCK_TO_CFP(captured);
|
2017-10-26 11:41:34 +03:00
|
|
|
vm_make_env_object(ec, cfp);
|
2016-07-28 14:02:30 +03:00
|
|
|
}
|
2023-02-10 10:02:20 +03:00
|
|
|
|
2017-10-26 11:41:34 +03:00
|
|
|
VM_ASSERT(VM_EP_IN_HEAP_P(ec, captured->ep));
|
2023-02-10 10:02:20 +03:00
|
|
|
VM_ASSERT(code_type == imemo_iseq || code_type == imemo_ifunc);
|
2016-07-28 14:02:30 +03:00
|
|
|
|
2017-11-16 10:43:27 +03:00
|
|
|
procval = vm_proc_create_from_captured(klass, captured,
|
2023-02-10 10:02:20 +03:00
|
|
|
code_type == imemo_iseq ? block_type_iseq : block_type_ifunc,
|
|
|
|
FALSE, is_lambda);
|
|
|
|
|
2023-11-15 13:05:10 +03:00
|
|
|
if (code_type == imemo_ifunc) {
|
2023-02-10 10:02:20 +03:00
|
|
|
struct vm_ifunc *ifunc = (struct vm_ifunc *)captured->code.val;
|
|
|
|
if (ifunc->svar_lep) {
|
|
|
|
VALUE ep0 = ifunc->svar_lep[0];
|
|
|
|
if (RB_TYPE_P(ep0, T_IMEMO) && imemo_type_p(ep0, imemo_env)) {
|
|
|
|
// `ep0 == imemo_env` means this ep is escaped to heap (in env object).
|
|
|
|
const rb_env_t *env = (const rb_env_t *)ep0;
|
|
|
|
ifunc->svar_lep = (VALUE *)env->ep;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
VM_ASSERT(FIXNUM_P(ep0));
|
|
|
|
if (ep0 & VM_ENV_FLAG_ESCAPED) {
|
|
|
|
// ok. do nothing
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ifunc->svar_lep = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
return procval;
|
|
|
|
}
|
2015-07-14 20:59:03 +03:00
|
|
|
|
2014-10-18 15:46:31 +04:00
|
|
|
/* Binding */
|
|
|
|
|
|
|
|
VALUE
|
2017-10-28 14:15:56 +03:00
|
|
|
rb_vm_make_binding(const rb_execution_context_t *ec, const rb_control_frame_t *src_cfp)
|
2014-10-18 15:46:31 +04:00
|
|
|
{
|
2017-10-28 14:15:56 +03:00
|
|
|
rb_control_frame_t *cfp = rb_vm_get_binding_creatable_next_cfp(ec, src_cfp);
|
|
|
|
rb_control_frame_t *ruby_level_cfp = rb_vm_get_ruby_level_next_cfp(ec, src_cfp);
|
2014-10-18 15:46:31 +04:00
|
|
|
VALUE bindval, envval;
|
|
|
|
rb_binding_t *bind;
|
|
|
|
|
|
|
|
if (cfp == 0 || ruby_level_cfp == 0) {
|
|
|
|
rb_raise(rb_eRuntimeError, "Can't create Binding Object on top of Fiber.");
|
|
|
|
}
|
2022-04-07 05:14:03 +03:00
|
|
|
if (!VM_FRAME_RUBYFRAME_P(src_cfp) &&
|
|
|
|
!VM_FRAME_RUBYFRAME_P(RUBY_VM_PREVIOUS_CONTROL_FRAME(src_cfp))) {
|
|
|
|
rb_raise(rb_eRuntimeError, "Cannot create Binding object for non-Ruby caller");
|
2014-10-18 15:46:31 +04:00
|
|
|
}
|
|
|
|
|
2022-04-07 05:14:03 +03:00
|
|
|
envval = vm_make_env_object(ec, cfp);
|
2014-10-18 15:46:31 +04:00
|
|
|
bindval = rb_binding_alloc(rb_cBinding);
|
|
|
|
GetBindingPtr(bindval, bind);
|
2017-06-01 18:12:14 +03:00
|
|
|
vm_bind_update_env(bindval, bind, envval);
|
|
|
|
RB_OBJ_WRITE(bindval, &bind->block.as.captured.self, cfp->self);
|
|
|
|
RB_OBJ_WRITE(bindval, &bind->block.as.captured.code.iseq, cfp->iseq);
|
2022-03-23 22:19:48 +03:00
|
|
|
RB_OBJ_WRITE(bindval, &bind->pathobj, ISEQ_BODY(ruby_level_cfp->iseq)->location.pathobj);
|
2014-10-18 15:46:31 +04:00
|
|
|
bind->first_lineno = rb_vm_get_sourceline(ruby_level_cfp);
|
|
|
|
|
|
|
|
return bindval;
|
|
|
|
}
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
const VALUE *
|
2017-06-01 18:12:14 +03:00
|
|
|
rb_binding_add_dynavars(VALUE bindval, rb_binding_t *bind, int dyncount, const ID *dynvars)
|
2013-08-09 13:51:00 +04:00
|
|
|
{
|
2017-06-01 03:05:33 +03:00
|
|
|
VALUE envval, pathobj = bind->pathobj;
|
|
|
|
VALUE path = pathobj_path(pathobj);
|
|
|
|
VALUE realpath = pathobj_realpath(pathobj);
|
2016-07-28 14:02:30 +03:00
|
|
|
const struct rb_block *base_block;
|
2016-07-28 22:13:26 +03:00
|
|
|
const rb_env_t *env;
|
2017-10-28 13:23:58 +03:00
|
|
|
rb_execution_context_t *ec = GET_EC();
|
2015-07-22 01:52:59 +03:00
|
|
|
const rb_iseq_t *base_iseq, *iseq;
|
2023-08-22 04:26:38 +03:00
|
|
|
rb_node_scope_t tmp_node;
|
2013-08-09 13:51:00 +04:00
|
|
|
|
|
|
|
if (dyncount < 0) return 0;
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
base_block = &bind->block;
|
|
|
|
base_iseq = vm_block_iseq(base_block);
|
2013-08-09 13:51:00 +04:00
|
|
|
|
2021-11-17 21:40:49 +03:00
|
|
|
VALUE idtmp = 0;
|
|
|
|
rb_ast_id_table_t *dyns = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + dyncount * sizeof(ID));
|
|
|
|
dyns->size = dyncount;
|
|
|
|
MEMCPY(dyns->ids, dynvars, ID, dyncount);
|
2013-08-09 13:51:00 +04:00
|
|
|
|
2023-08-22 04:26:38 +03:00
|
|
|
rb_node_init(RNODE(&tmp_node), NODE_SCOPE);
|
|
|
|
tmp_node.nd_tbl = dyns;
|
|
|
|
tmp_node.nd_body = 0;
|
|
|
|
tmp_node.nd_args = 0;
|
|
|
|
|
2024-05-03 02:57:55 +03:00
|
|
|
VALUE ast_value = rb_ruby_ast_new(RNODE(&tmp_node));
|
2013-08-09 13:51:00 +04:00
|
|
|
|
2015-05-21 11:45:57 +03:00
|
|
|
if (base_iseq) {
|
2024-05-03 02:57:55 +03:00
|
|
|
iseq = rb_iseq_new(ast_value, ISEQ_BODY(base_iseq)->location.label, path, realpath, base_iseq, ISEQ_TYPE_EVAL);
|
2015-05-21 11:45:57 +03:00
|
|
|
}
|
|
|
|
else {
|
2018-10-13 12:59:22 +03:00
|
|
|
VALUE tempstr = rb_fstring_lit("<temp>");
|
2024-05-03 02:57:55 +03:00
|
|
|
iseq = rb_iseq_new_top(ast_value, tempstr, tempstr, tempstr, NULL);
|
2015-05-21 11:45:57 +03:00
|
|
|
}
|
2018-01-05 11:59:22 +03:00
|
|
|
tmp_node.nd_tbl = 0; /* reset table */
|
2013-08-09 13:51:00 +04:00
|
|
|
ALLOCV_END(idtmp);
|
|
|
|
|
2017-10-28 13:23:58 +03:00
|
|
|
vm_set_eval_stack(ec, iseq, 0, base_block);
|
|
|
|
vm_bind_update_env(bindval, bind, envval = vm_make_env_object(ec, ec->cfp));
|
|
|
|
rb_vm_pop_frame(ec);
|
2013-08-09 13:51:00 +04:00
|
|
|
|
2016-07-28 22:13:26 +03:00
|
|
|
env = (const rb_env_t *)envval;
|
2013-08-09 13:51:00 +04:00
|
|
|
return env->env;
|
|
|
|
}
|
|
|
|
|
2007-06-25 06:44:20 +04:00
|
|
|
/* C -> Ruby: block */
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2024-08-03 03:53:13 +03:00
|
|
|
static inline void
|
2017-10-27 09:06:31 +03:00
|
|
|
invoke_block(rb_execution_context_t *ec, const rb_iseq_t *iseq, VALUE self, const struct rb_captured_block *captured, const rb_cref_t *cref, VALUE type, int opt_pc)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2022-03-23 22:19:48 +03:00
|
|
|
int arg_size = ISEQ_BODY(iseq)->param.size;
|
2015-10-10 23:32:07 +03:00
|
|
|
|
2017-10-27 09:06:31 +03:00
|
|
|
vm_push_frame(ec, iseq, type | VM_FRAME_FLAG_FINISH, self,
|
2016-07-28 14:02:30 +03:00
|
|
|
VM_GUARDED_PREV_EP(captured->ep),
|
2015-10-10 23:32:07 +03:00
|
|
|
(VALUE)cref, /* cref or method */
|
2022-03-23 22:19:48 +03:00
|
|
|
ISEQ_BODY(iseq)->iseq_encoded + opt_pc,
|
2017-10-27 09:06:31 +03:00
|
|
|
ec->cfp->sp + arg_size,
|
2022-03-23 22:19:48 +03:00
|
|
|
ISEQ_BODY(iseq)->local_table_size - arg_size,
|
|
|
|
ISEQ_BODY(iseq)->stack_max);
|
2015-10-10 23:32:07 +03:00
|
|
|
}
|
|
|
|
|
2024-08-03 03:53:13 +03:00
|
|
|
static inline void
|
2017-10-27 09:06:31 +03:00
|
|
|
invoke_bmethod(rb_execution_context_t *ec, const rb_iseq_t *iseq, VALUE self, const struct rb_captured_block *captured, const rb_callable_method_entry_t *me, VALUE type, int opt_pc)
|
2015-10-10 23:32:07 +03:00
|
|
|
{
|
2023-07-17 20:57:58 +03:00
|
|
|
/* bmethod call from outside the VM */
|
2022-03-23 22:19:48 +03:00
|
|
|
int arg_size = ISEQ_BODY(iseq)->param.size;
|
2018-11-26 21:16:39 +03:00
|
|
|
|
|
|
|
VM_ASSERT(me->def->type == VM_METHOD_TYPE_BMETHOD);
|
2015-10-10 23:32:07 +03:00
|
|
|
|
2017-10-27 09:06:31 +03:00
|
|
|
vm_push_frame(ec, iseq, type | VM_FRAME_FLAG_BMETHOD, self,
|
2016-07-28 14:02:30 +03:00
|
|
|
VM_GUARDED_PREV_EP(captured->ep),
|
|
|
|
(VALUE)me,
|
2022-03-23 22:19:48 +03:00
|
|
|
ISEQ_BODY(iseq)->iseq_encoded + opt_pc,
|
2023-07-17 20:57:58 +03:00
|
|
|
ec->cfp->sp + 1 /* self */ + arg_size,
|
2022-03-23 22:19:48 +03:00
|
|
|
ISEQ_BODY(iseq)->local_table_size - arg_size,
|
|
|
|
ISEQ_BODY(iseq)->stack_max);
|
2015-10-10 23:32:07 +03:00
|
|
|
|
2017-10-27 09:06:31 +03:00
|
|
|
VM_ENV_FLAGS_SET(ec->cfp->ep, VM_FRAME_FLAG_FINISH);
|
2015-10-10 23:32:07 +03:00
|
|
|
}
|
|
|
|
|
2018-11-27 04:25:16 +03:00
|
|
|
ALWAYS_INLINE(static VALUE
|
2018-11-09 04:02:13 +03:00
|
|
|
invoke_iseq_block_from_c(rb_execution_context_t *ec, const struct rb_captured_block *captured,
|
2019-09-03 19:32:42 +03:00
|
|
|
VALUE self, int argc, const VALUE *argv, int kw_splat, VALUE passed_block_handler,
|
2018-11-09 04:02:13 +03:00
|
|
|
const rb_cref_t *cref, int is_lambda, const rb_callable_method_entry_t *me));
|
|
|
|
|
2015-10-10 23:32:07 +03:00
|
|
|
static inline VALUE
|
2017-10-27 09:06:31 +03:00
|
|
|
invoke_iseq_block_from_c(rb_execution_context_t *ec, const struct rb_captured_block *captured,
|
2019-09-03 19:32:42 +03:00
|
|
|
VALUE self, int argc, const VALUE *argv, int kw_splat, VALUE passed_block_handler,
|
2018-11-09 04:02:20 +03:00
|
|
|
const rb_cref_t *cref, int is_lambda, const rb_callable_method_entry_t *me)
|
2015-10-10 23:32:07 +03:00
|
|
|
{
|
2016-07-28 14:02:30 +03:00
|
|
|
const rb_iseq_t *iseq = rb_iseq_check(captured->code.iseq);
|
2023-07-17 20:57:58 +03:00
|
|
|
int opt_pc;
|
2017-06-06 10:10:19 +03:00
|
|
|
VALUE type = VM_FRAME_MAGIC_BLOCK | (is_lambda ? VM_FRAME_FLAG_LAMBDA : 0);
|
2017-10-27 09:06:31 +03:00
|
|
|
rb_control_frame_t *cfp = ec->cfp;
|
2017-03-17 13:08:02 +03:00
|
|
|
VALUE *sp = cfp->sp;
|
Generalize cfunc large array splat fix to fix many additional cases raising SystemStackError
Originally, when 2e7bceb34ea858649e1f975a934ce1894d1f06a6 fixed cfuncs to no
longer use the VM stack for large array splats, it was thought to have fully
fixed Bug #4040, since the issue was fixed for methods defined in Ruby (iseqs)
back in Ruby 2.2.
After additional research, I determined that same issue affects almost all
types of method calls, not just iseq and cfunc calls. There were two main
types of remaining issues, important cases (where large array splat should
work) and pedantic cases (where large array splat raised SystemStackError
instead of ArgumentError).
Important cases:
```ruby
define_method(:a){|*a|}
a(*1380888.times)
def b(*a); end
send(:b, *1380888.times)
:b.to_proc.call(self, *1380888.times)
def d; yield(*1380888.times) end
d(&method(:b))
def self.method_missing(*a); end
not_a_method(*1380888.times)
```
Pedantic cases:
```ruby
def a; end
a(*1380888.times)
def b(_); end
b(*1380888.times)
def c(_=nil); end
c(*1380888.times)
c = Class.new do
attr_accessor :a
alias b a=
end.new
c.a(*1380888.times)
c.b(*1380888.times)
c = Struct.new(:a) do
alias b a=
end.new
c.a(*1380888.times)
c.b(*1380888.times)
```
This patch fixes all usage of CALLER_SETUP_ARG with splatting a large
number of arguments, and required similar fixes to use a temporary
hidden array in three other cases where the VM would use the VM stack
for handling a large number of arguments. However, it is possible
there may be additional cases where splatting a large number
of arguments still causes a SystemStackError.
This has a measurable performance impact, as it requires additional
checks for a large number of arguments in many additional cases.
This change is fairly invasive, as there were many different VM
functions that needed to be modified to support this. To avoid
too much API change, I modified struct rb_calling_info to add a
heap_argv member for storing the array, so I would not have to
thread it through many functions. This struct is always stack
allocated, which helps ensure sure GC doesn't collect it early.
Because of how invasive the changes are, and how rarely large
arrays are actually splatted in Ruby code, the existing test/spec
suites are not great at testing for correct behavior. To try to
find and fix all issues, I tested this in CI with
VM_ARGC_STACK_MAX to -1, ensuring that a temporary array is used
for all array splat method calls. This was very helpful in
finding breaking cases, especially ones involving flagged keyword
hashes.
Fixes [Bug #4040]
Co-authored-by: Jimmy Miller <jimmy.miller@shopify.com>
2023-03-07 02:58:58 +03:00
|
|
|
int flags = (kw_splat ? VM_CALL_KW_SPLAT : 0);
|
|
|
|
VALUE *use_argv = (VALUE *)argv;
|
|
|
|
VALUE av[2];
|
2018-11-09 04:02:13 +03:00
|
|
|
|
2017-10-28 15:23:51 +03:00
|
|
|
stack_check(ec);
|
2007-06-05 21:26:00 +04:00
|
|
|
|
2023-07-24 18:01:52 +03:00
|
|
|
if (UNLIKELY(argc > VM_ARGC_STACK_MAX) &&
|
|
|
|
(VM_ARGC_STACK_MAX >= 1 ||
|
|
|
|
/* Skip ruby array for potential autosplat case */
|
|
|
|
(argc != 1 || is_lambda))) {
|
Generalize cfunc large array splat fix to fix many additional cases raising SystemStackError
Originally, when 2e7bceb34ea858649e1f975a934ce1894d1f06a6 fixed cfuncs to no
longer use the VM stack for large array splats, it was thought to have fully
fixed Bug #4040, since the issue was fixed for methods defined in Ruby (iseqs)
back in Ruby 2.2.
After additional research, I determined that same issue affects almost all
types of method calls, not just iseq and cfunc calls. There were two main
types of remaining issues, important cases (where large array splat should
work) and pedantic cases (where large array splat raised SystemStackError
instead of ArgumentError).
Important cases:
```ruby
define_method(:a){|*a|}
a(*1380888.times)
def b(*a); end
send(:b, *1380888.times)
:b.to_proc.call(self, *1380888.times)
def d; yield(*1380888.times) end
d(&method(:b))
def self.method_missing(*a); end
not_a_method(*1380888.times)
```
Pedantic cases:
```ruby
def a; end
a(*1380888.times)
def b(_); end
b(*1380888.times)
def c(_=nil); end
c(*1380888.times)
c = Class.new do
attr_accessor :a
alias b a=
end.new
c.a(*1380888.times)
c.b(*1380888.times)
c = Struct.new(:a) do
alias b a=
end.new
c.a(*1380888.times)
c.b(*1380888.times)
```
This patch fixes all usage of CALLER_SETUP_ARG with splatting a large
number of arguments, and required similar fixes to use a temporary
hidden array in three other cases where the VM would use the VM stack
for handling a large number of arguments. However, it is possible
there may be additional cases where splatting a large number
of arguments still causes a SystemStackError.
This has a measurable performance impact, as it requires additional
checks for a large number of arguments in many additional cases.
This change is fairly invasive, as there were many different VM
functions that needed to be modified to support this. To avoid
too much API change, I modified struct rb_calling_info to add a
heap_argv member for storing the array, so I would not have to
thread it through many functions. This struct is always stack
allocated, which helps ensure sure GC doesn't collect it early.
Because of how invasive the changes are, and how rarely large
arrays are actually splatted in Ruby code, the existing test/spec
suites are not great at testing for correct behavior. To try to
find and fix all issues, I tested this in CI with
VM_ARGC_STACK_MAX to -1, ensuring that a temporary array is used
for all array splat method calls. This was very helpful in
finding breaking cases, especially ones involving flagged keyword
hashes.
Fixes [Bug #4040]
Co-authored-by: Jimmy Miller <jimmy.miller@shopify.com>
2023-03-07 02:58:58 +03:00
|
|
|
use_argv = vm_argv_ruby_array(av, argv, &flags, &argc, kw_splat);
|
|
|
|
}
|
|
|
|
|
2023-07-17 20:57:58 +03:00
|
|
|
CHECK_VM_STACK_OVERFLOW(cfp, argc + 1);
|
2019-02-01 10:26:39 +03:00
|
|
|
vm_check_canary(ec, sp);
|
2023-07-17 20:57:58 +03:00
|
|
|
|
|
|
|
VALUE *stack_argv = sp;
|
|
|
|
if (me) {
|
|
|
|
*sp = self; // bemthods need `self` on the VM stack
|
|
|
|
stack_argv++;
|
2016-07-28 14:02:30 +03:00
|
|
|
}
|
2023-07-17 20:57:58 +03:00
|
|
|
cfp->sp = stack_argv + argc;
|
|
|
|
MEMCPY(stack_argv, use_argv, VALUE, argc); // restrict: new stack space
|
2007-01-16 06:06:01 +03:00
|
|
|
|
2023-07-17 20:57:58 +03:00
|
|
|
opt_pc = vm_yield_setup_args(ec, iseq, argc, stack_argv, flags, passed_block_handler,
|
2017-06-06 10:10:19 +03:00
|
|
|
(is_lambda ? arg_setup_method : arg_setup_block));
|
2017-03-18 14:29:35 +03:00
|
|
|
cfp->sp = sp;
|
2014-06-19 14:49:46 +04:00
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
if (me == NULL) {
|
2024-08-03 03:53:13 +03:00
|
|
|
invoke_block(ec, iseq, self, captured, cref, type, opt_pc);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
else {
|
2024-08-03 03:53:13 +03:00
|
|
|
invoke_bmethod(ec, iseq, self, captured, me, type, opt_pc);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2024-08-03 03:53:13 +03:00
|
|
|
|
|
|
|
return vm_exec(ec);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2024-08-03 03:53:13 +03:00
|
|
|
static VALUE
|
2017-10-27 09:06:31 +03:00
|
|
|
invoke_block_from_c_bh(rb_execution_context_t *ec, VALUE block_handler,
|
2017-06-05 09:15:28 +03:00
|
|
|
int argc, const VALUE *argv,
|
2019-09-03 19:32:42 +03:00
|
|
|
int kw_splat, VALUE passed_block_handler, const rb_cref_t *cref,
|
2017-08-16 00:39:38 +03:00
|
|
|
int is_lambda, int force_blockarg)
|
2016-07-28 14:02:30 +03:00
|
|
|
{
|
|
|
|
again:
|
|
|
|
switch (vm_block_handler_type(block_handler)) {
|
|
|
|
case block_handler_type_iseq:
|
|
|
|
{
|
|
|
|
const struct rb_captured_block *captured = VM_BH_TO_ISEQ_BLOCK(block_handler);
|
2017-10-27 09:06:31 +03:00
|
|
|
return invoke_iseq_block_from_c(ec, captured, captured->self,
|
2019-09-03 19:32:42 +03:00
|
|
|
argc, argv, kw_splat, passed_block_handler,
|
2018-11-09 04:02:20 +03:00
|
|
|
cref, is_lambda, NULL);
|
2016-07-28 14:02:30 +03:00
|
|
|
}
|
|
|
|
case block_handler_type_ifunc:
|
2017-10-27 09:06:31 +03:00
|
|
|
return vm_yield_with_cfunc(ec, VM_BH_TO_IFUNC_BLOCK(block_handler),
|
2017-06-05 09:15:28 +03:00
|
|
|
VM_BH_TO_IFUNC_BLOCK(block_handler)->self,
|
2019-09-03 19:32:42 +03:00
|
|
|
argc, argv, kw_splat, passed_block_handler, NULL);
|
2016-07-28 14:02:30 +03:00
|
|
|
case block_handler_type_symbol:
|
2017-10-27 09:06:31 +03:00
|
|
|
return vm_yield_with_symbol(ec, VM_BH_TO_SYMBOL(block_handler),
|
2019-09-03 19:32:42 +03:00
|
|
|
argc, argv, kw_splat, passed_block_handler);
|
2016-07-28 14:02:30 +03:00
|
|
|
case block_handler_type_proc:
|
2017-06-06 10:10:19 +03:00
|
|
|
if (force_blockarg == FALSE) {
|
|
|
|
is_lambda = block_proc_is_lambda(VM_BH_TO_PROC(block_handler));
|
2017-06-05 09:15:28 +03:00
|
|
|
}
|
2016-07-28 14:02:30 +03:00
|
|
|
block_handler = vm_proc_to_block_handler(VM_BH_TO_PROC(block_handler));
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
VM_UNREACHABLE(invoke_block_from_c_splattable);
|
|
|
|
return Qundef;
|
2015-10-10 23:32:07 +03:00
|
|
|
}
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
static inline VALUE
|
2017-10-27 09:06:31 +03:00
|
|
|
check_block_handler(rb_execution_context_t *ec)
|
2007-01-16 06:06:01 +03:00
|
|
|
{
|
2017-10-27 09:06:31 +03:00
|
|
|
VALUE block_handler = VM_CF_BLOCK_HANDLER(ec->cfp);
|
2017-06-08 08:22:49 +03:00
|
|
|
vm_block_handler_verify(block_handler);
|
2016-07-28 14:02:30 +03:00
|
|
|
if (UNLIKELY(block_handler == VM_BLOCK_HANDLER_NONE)) {
|
* vm.c: add a prefix "rb_" to exposed functions
vm_get_ruby_level_next_cfp(), rb_vm_make_env_object(),
vm_stack_to_heap(), vm_make_proc(), vm_invoke_proc(),
vm_get_sourceline(), vm_cref(), vm_localjump_error(),
vm_make_jump_tag_but_local_jump(), vm_jump_tag_but_local_jump().
This changes may affect only core because most of renamed functions
require a pointer of not-exposed struct such as rb_thread_t or NODE.
In short, they are core functions.
* cont.c, eval.c, eval_intern.h, load.c, proc.c, thread.c,
vm_core.h, vm_dump.c, vm_eval.c, vm_exec.c, vm_insnhelper.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@21659 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2009-01-19 05:38:11 +03:00
|
|
|
rb_vm_localjump_error("no block given", Qnil, 0);
|
2007-01-16 06:06:01 +03:00
|
|
|
}
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
return block_handler;
|
2008-05-19 18:36:13 +04:00
|
|
|
}
|
|
|
|
|
2015-10-10 23:32:07 +03:00
|
|
|
static VALUE
|
2019-09-27 03:25:54 +03:00
|
|
|
vm_yield_with_cref(rb_execution_context_t *ec, int argc, const VALUE *argv, int kw_splat, const rb_cref_t *cref, int is_lambda)
|
2008-05-19 18:36:13 +04:00
|
|
|
{
|
2017-10-27 09:06:31 +03:00
|
|
|
return invoke_block_from_c_bh(ec, check_block_handler(ec),
|
2019-09-27 03:25:54 +03:00
|
|
|
argc, argv, kw_splat, VM_BLOCK_HANDLER_NONE,
|
2017-06-05 10:03:27 +03:00
|
|
|
cref, is_lambda, FALSE);
|
* vm.c, insns.def, eval.c, vm_insnhelper.c: fix CREF handling.
VM value stack frame of block contains cref information.
(dfp[-1] points CREF)
* compile.c, eval_intern.h, eval_method.c, load.c, proc.c,
vm_dump.h, vm_core.h: ditto.
* include/ruby/ruby.h, gc.c: remove T_VALUES because of above
changes.
* bootstraptest/test_eval.rb, test_knownbug.rb: move solved test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-19 07:08:50 +04:00
|
|
|
}
|
|
|
|
|
2015-10-10 23:32:07 +03:00
|
|
|
static VALUE
|
2019-09-27 03:25:54 +03:00
|
|
|
vm_yield(rb_execution_context_t *ec, int argc, const VALUE *argv, int kw_splat)
|
* vm.c, insns.def, eval.c, vm_insnhelper.c: fix CREF handling.
VM value stack frame of block contains cref information.
(dfp[-1] points CREF)
* compile.c, eval_intern.h, eval_method.c, load.c, proc.c,
vm_dump.h, vm_core.h: ditto.
* include/ruby/ruby.h, gc.c: remove T_VALUES because of above
changes.
* bootstraptest/test_eval.rb, test_knownbug.rb: move solved test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-19 07:08:50 +04:00
|
|
|
{
|
2021-09-14 03:19:30 +03:00
|
|
|
return vm_yield_with_cref(ec, argc, argv, kw_splat, NULL, FALSE);
|
2007-01-16 06:06:01 +03:00
|
|
|
}
|
|
|
|
|
2015-10-10 23:32:07 +03:00
|
|
|
static VALUE
|
2019-09-27 03:25:54 +03:00
|
|
|
vm_yield_with_block(rb_execution_context_t *ec, int argc, const VALUE *argv, VALUE block_handler, int kw_splat)
|
2016-07-28 14:02:30 +03:00
|
|
|
{
|
2017-10-27 09:06:31 +03:00
|
|
|
return invoke_block_from_c_bh(ec, check_block_handler(ec),
|
2019-09-27 03:25:54 +03:00
|
|
|
argc, argv, kw_splat, block_handler,
|
2017-06-05 09:15:28 +03:00
|
|
|
NULL, FALSE, FALSE);
|
2017-03-19 04:11:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2017-10-27 09:06:31 +03:00
|
|
|
vm_yield_force_blockarg(rb_execution_context_t *ec, VALUE args)
|
2017-03-19 04:11:12 +03:00
|
|
|
{
|
2017-10-27 09:06:31 +03:00
|
|
|
return invoke_block_from_c_bh(ec, check_block_handler(ec), 1, &args,
|
2019-09-30 02:41:00 +03:00
|
|
|
RB_NO_KEYWORDS, VM_BLOCK_HANDLER_NONE, NULL, FALSE, TRUE);
|
2016-07-28 14:02:30 +03:00
|
|
|
}
|
|
|
|
|
2018-11-27 04:25:16 +03:00
|
|
|
ALWAYS_INLINE(static VALUE
|
2018-11-09 04:02:13 +03:00
|
|
|
invoke_block_from_c_proc(rb_execution_context_t *ec, const rb_proc_t *proc,
|
|
|
|
VALUE self, int argc, const VALUE *argv,
|
2019-09-03 19:32:42 +03:00
|
|
|
int kw_splat, VALUE passed_block_handler, int is_lambda,
|
2018-11-09 04:02:13 +03:00
|
|
|
const rb_callable_method_entry_t *me));
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
static inline VALUE
|
2017-10-27 09:06:31 +03:00
|
|
|
invoke_block_from_c_proc(rb_execution_context_t *ec, const rb_proc_t *proc,
|
2017-06-05 09:15:28 +03:00
|
|
|
VALUE self, int argc, const VALUE *argv,
|
2019-09-03 19:32:42 +03:00
|
|
|
int kw_splat, VALUE passed_block_handler, int is_lambda,
|
2018-11-09 04:02:13 +03:00
|
|
|
const rb_callable_method_entry_t *me)
|
2013-11-29 12:06:19 +04:00
|
|
|
{
|
2017-06-05 09:15:28 +03:00
|
|
|
const struct rb_block *block = &proc->block;
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
again:
|
|
|
|
switch (vm_block_type(block)) {
|
|
|
|
case block_type_iseq:
|
2019-09-03 19:32:42 +03:00
|
|
|
return invoke_iseq_block_from_c(ec, &block->as.captured, self, argc, argv, kw_splat, passed_block_handler, NULL, is_lambda, me);
|
2016-07-28 14:02:30 +03:00
|
|
|
case block_type_ifunc:
|
Reduce allocations for keyword argument hashes
Previously, passing a keyword splat to a method always allocated
a hash on the caller side, and accepting arbitrary keywords in
a method allocated a separate hash on the callee side. Passing
explicit keywords to a method that accepted a keyword splat
did not allocate a hash on the caller side, but resulted in two
hashes allocated on the callee side.
This commit makes passing a single keyword splat to a method not
allocate a hash on the caller side. Passing multiple keyword
splats or a mix of explicit keywords and a keyword splat still
generates a hash on the caller side. On the callee side,
if arbitrary keywords are not accepted, it does not allocate a
hash. If arbitrary keywords are accepted, it will allocate a
hash, but this commit uses a callinfo flag to indicate whether
the caller already allocated a hash, and if so, the callee can
use the passed hash without duplicating it. So this commit
should make it so that a maximum of a single hash is allocated
during method calls.
To set the callinfo flag appropriately, method call argument
compilation checks if only a single keyword splat is given.
If only one keyword splat is given, the VM_CALL_KW_SPLAT_MUT
callinfo flag is not set, since in that case the keyword
splat is passed directly and not mutable. If more than one
splat is used, a new hash needs to be generated on the caller
side, and in that case the callinfo flag is set, indicating
the keyword splat is mutable by the callee.
In compile_hash, used for both hash and keyword argument
compilation, if compiling keyword arguments and only a
single keyword splat is used, pass the argument directly.
On the caller side, in vm_args.c, the callinfo flag needs to
be recognized and handled. Because the keyword splat
argument may not be a hash, it needs to be converted to a
hash first if not. Then, unless the callinfo flag is set,
the hash needs to be duplicated. The temporary copy of the
callinfo flag, kw_flag, is updated if a hash was duplicated,
to prevent the need to duplicate it again. If we are
converting to a hash or duplicating a hash, we need to update
the argument array, which can including duplicating the
positional splat array if one was passed. CALLER_SETUP_ARG
and a couple other places needs to be modified to handle
similar issues for other types of calls.
This includes fairly comprehensive tests for different ways
keywords are handled internally, checking that you get equal
results but that keyword splats on the caller side result in
distinct objects for keyword rest parameters.
Included are benchmarks for keyword argument calls.
Brief results when compiled without optimization:
def kw(a: 1) a end
def kws(**kw) kw end
h = {a: 1}
kw(a: 1) # about same
kw(**h) # 2.37x faster
kws(a: 1) # 1.30x faster
kws(**h) # 2.19x faster
kw(a: 1, **h) # 1.03x slower
kw(**h, **h) # about same
kws(a: 1, **h) # 1.16x faster
kws(**h, **h) # 1.14x faster
2020-02-24 23:05:07 +03:00
|
|
|
if (kw_splat == 1) {
|
|
|
|
VALUE keyword_hash = argv[argc-1];
|
|
|
|
if (!RB_TYPE_P(keyword_hash, T_HASH)) {
|
|
|
|
keyword_hash = rb_to_hash_type(keyword_hash);
|
|
|
|
}
|
|
|
|
if (RHASH_EMPTY_P(keyword_hash)) {
|
|
|
|
argc--;
|
2021-06-16 16:07:05 +03:00
|
|
|
}
|
|
|
|
else {
|
Reduce allocations for keyword argument hashes
Previously, passing a keyword splat to a method always allocated
a hash on the caller side, and accepting arbitrary keywords in
a method allocated a separate hash on the callee side. Passing
explicit keywords to a method that accepted a keyword splat
did not allocate a hash on the caller side, but resulted in two
hashes allocated on the callee side.
This commit makes passing a single keyword splat to a method not
allocate a hash on the caller side. Passing multiple keyword
splats or a mix of explicit keywords and a keyword splat still
generates a hash on the caller side. On the callee side,
if arbitrary keywords are not accepted, it does not allocate a
hash. If arbitrary keywords are accepted, it will allocate a
hash, but this commit uses a callinfo flag to indicate whether
the caller already allocated a hash, and if so, the callee can
use the passed hash without duplicating it. So this commit
should make it so that a maximum of a single hash is allocated
during method calls.
To set the callinfo flag appropriately, method call argument
compilation checks if only a single keyword splat is given.
If only one keyword splat is given, the VM_CALL_KW_SPLAT_MUT
callinfo flag is not set, since in that case the keyword
splat is passed directly and not mutable. If more than one
splat is used, a new hash needs to be generated on the caller
side, and in that case the callinfo flag is set, indicating
the keyword splat is mutable by the callee.
In compile_hash, used for both hash and keyword argument
compilation, if compiling keyword arguments and only a
single keyword splat is used, pass the argument directly.
On the caller side, in vm_args.c, the callinfo flag needs to
be recognized and handled. Because the keyword splat
argument may not be a hash, it needs to be converted to a
hash first if not. Then, unless the callinfo flag is set,
the hash needs to be duplicated. The temporary copy of the
callinfo flag, kw_flag, is updated if a hash was duplicated,
to prevent the need to duplicate it again. If we are
converting to a hash or duplicating a hash, we need to update
the argument array, which can including duplicating the
positional splat array if one was passed. CALLER_SETUP_ARG
and a couple other places needs to be modified to handle
similar issues for other types of calls.
This includes fairly comprehensive tests for different ways
keywords are handled internally, checking that you get equal
results but that keyword splats on the caller side result in
distinct objects for keyword rest parameters.
Included are benchmarks for keyword argument calls.
Brief results when compiled without optimization:
def kw(a: 1) a end
def kws(**kw) kw end
h = {a: 1}
kw(a: 1) # about same
kw(**h) # 2.37x faster
kws(a: 1) # 1.30x faster
kws(**h) # 2.19x faster
kw(a: 1, **h) # 1.03x slower
kw(**h, **h) # about same
kws(a: 1, **h) # 1.16x faster
kws(**h, **h) # 1.14x faster
2020-02-24 23:05:07 +03:00
|
|
|
((VALUE *)argv)[argc-1] = rb_hash_dup(keyword_hash);
|
|
|
|
}
|
2019-09-27 03:25:54 +03:00
|
|
|
}
|
2019-09-03 19:32:42 +03:00
|
|
|
return vm_yield_with_cfunc(ec, &block->as.captured, self, argc, argv, kw_splat, passed_block_handler, me);
|
2016-07-28 14:02:30 +03:00
|
|
|
case block_type_symbol:
|
2019-09-03 19:32:42 +03:00
|
|
|
return vm_yield_with_symbol(ec, block->as.symbol, argc, argv, kw_splat, passed_block_handler);
|
2016-07-28 14:02:30 +03:00
|
|
|
case block_type_proc:
|
2017-06-06 10:10:19 +03:00
|
|
|
is_lambda = block_proc_is_lambda(block->as.proc);
|
2016-07-28 14:02:30 +03:00
|
|
|
block = vm_proc_block(block->as.proc);
|
|
|
|
goto again;
|
|
|
|
}
|
2017-06-05 09:15:28 +03:00
|
|
|
VM_UNREACHABLE(invoke_block_from_c_proc);
|
2016-07-28 14:02:30 +03:00
|
|
|
return Qundef;
|
2013-11-29 12:06:19 +04:00
|
|
|
}
|
|
|
|
|
2012-08-20 15:36:34 +04:00
|
|
|
static VALUE
|
2017-10-27 09:06:31 +03:00
|
|
|
vm_invoke_proc(rb_execution_context_t *ec, rb_proc_t *proc, VALUE self,
|
2019-09-03 19:32:42 +03:00
|
|
|
int argc, const VALUE *argv, int kw_splat, VALUE passed_block_handler)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2019-09-03 19:32:42 +03:00
|
|
|
return invoke_block_from_c_proc(ec, proc, self, argc, argv, kw_splat, passed_block_handler, proc->is_lambda, NULL);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2024-08-08 01:29:33 +03:00
|
|
|
static VALUE
|
|
|
|
vm_invoke_bmethod(rb_execution_context_t *ec, rb_proc_t *proc, VALUE self,
|
2019-09-03 19:32:42 +03:00
|
|
|
int argc, const VALUE *argv, int kw_splat, VALUE block_handler, const rb_callable_method_entry_t *me)
|
2015-05-21 01:03:06 +03:00
|
|
|
{
|
2019-09-03 19:32:42 +03:00
|
|
|
return invoke_block_from_c_proc(ec, proc, self, argc, argv, kw_splat, block_handler, TRUE, me);
|
2015-05-21 01:03:06 +03:00
|
|
|
}
|
|
|
|
|
2023-03-07 08:34:31 +03:00
|
|
|
VALUE
|
2017-10-27 09:06:31 +03:00
|
|
|
rb_vm_invoke_proc(rb_execution_context_t *ec, rb_proc_t *proc,
|
2019-09-03 19:32:42 +03:00
|
|
|
int argc, const VALUE *argv, int kw_splat, VALUE passed_block_handler)
|
2012-08-20 15:36:34 +04:00
|
|
|
{
|
2016-07-28 14:02:30 +03:00
|
|
|
VALUE self = vm_block_self(&proc->block);
|
2017-06-08 08:22:49 +03:00
|
|
|
vm_block_handler_verify(passed_block_handler);
|
2016-07-28 14:02:30 +03:00
|
|
|
|
2015-05-21 01:03:06 +03:00
|
|
|
if (proc->is_from_method) {
|
2024-08-08 01:29:33 +03:00
|
|
|
return vm_invoke_bmethod(ec, proc, self, argc, argv, kw_splat, passed_block_handler, NULL);
|
2015-05-21 01:03:06 +03:00
|
|
|
}
|
|
|
|
else {
|
2019-09-03 19:32:42 +03:00
|
|
|
return vm_invoke_proc(ec, proc, self, argc, argv, kw_splat, passed_block_handler);
|
2015-05-21 01:03:06 +03:00
|
|
|
}
|
2012-08-20 15:36:34 +04:00
|
|
|
}
|
|
|
|
|
2020-03-09 20:22:11 +03:00
|
|
|
VALUE
|
|
|
|
rb_vm_invoke_proc_with_self(rb_execution_context_t *ec, rb_proc_t *proc, VALUE self,
|
|
|
|
int argc, const VALUE *argv, int kw_splat, VALUE passed_block_handler)
|
|
|
|
{
|
|
|
|
vm_block_handler_verify(passed_block_handler);
|
|
|
|
|
|
|
|
if (proc->is_from_method) {
|
2024-08-08 01:29:33 +03:00
|
|
|
return vm_invoke_bmethod(ec, proc, self, argc, argv, kw_splat, passed_block_handler, NULL);
|
2020-03-09 20:22:11 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
return vm_invoke_proc(ec, proc, self, argc, argv, kw_splat, passed_block_handler);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-25 06:44:20 +04:00
|
|
|
/* special variable */
|
|
|
|
|
2023-02-10 10:02:20 +03:00
|
|
|
VALUE *
|
|
|
|
rb_vm_svar_lep(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2023-03-30 00:57:52 +03:00
|
|
|
while (cfp->pc == 0 || cfp->iseq == 0) {
|
2023-11-15 13:05:10 +03:00
|
|
|
if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_IFUNC) {
|
2023-02-02 03:13:19 +03:00
|
|
|
struct vm_ifunc *ifunc = (struct vm_ifunc *)cfp->iseq;
|
2023-02-10 10:02:20 +03:00
|
|
|
return ifunc->svar_lep;
|
2023-02-02 03:13:19 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
|
|
|
}
|
|
|
|
|
2017-10-28 13:55:35 +03:00
|
|
|
if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(ec, cfp)) {
|
2023-02-02 03:13:19 +03:00
|
|
|
return NULL;
|
* vm.c, eval_intern.h (PASS_PASSED_BLOCK):
set a VM_FRAME_FLAG_PASSED flag to skip this frame when
searching ruby-level-cfp.
* eval.c, eval_intern.h, proc.c: fix to check cfp. if there is
no valid ruby-level-cfp, cause RuntimeError exception.
[ruby-dev:34128]
* vm_core.h, vm_evalbody.c, vm.c, vm_dump.c, vm_insnhelper.c,
insns.def: rename FRAME_MAGIC_* to VM_FRAME_MAGIC_*.
* KNOWNBUGS.rb, bootstraptest/test*.rb: move solved bugs.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17084 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-06-11 01:46:43 +04:00
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2023-02-10 10:02:20 +03:00
|
|
|
|
2023-11-14 16:07:15 +03:00
|
|
|
return (VALUE *)VM_CF_LEP(cfp);
|
* vm.c, eval_intern.h (PASS_PASSED_BLOCK):
set a VM_FRAME_FLAG_PASSED flag to skip this frame when
searching ruby-level-cfp.
* eval.c, eval_intern.h, proc.c: fix to check cfp. if there is
no valid ruby-level-cfp, cause RuntimeError exception.
[ruby-dev:34128]
* vm_core.h, vm_evalbody.c, vm.c, vm_dump.c, vm_insnhelper.c,
insns.def: rename FRAME_MAGIC_* to VM_FRAME_MAGIC_*.
* KNOWNBUGS.rb, bootstraptest/test*.rb: move solved bugs.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17084 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-06-11 01:46:43 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2017-10-28 13:55:35 +03:00
|
|
|
vm_cfp_svar_get(const rb_execution_context_t *ec, rb_control_frame_t *cfp, VALUE key)
|
* vm.c, eval_intern.h (PASS_PASSED_BLOCK):
set a VM_FRAME_FLAG_PASSED flag to skip this frame when
searching ruby-level-cfp.
* eval.c, eval_intern.h, proc.c: fix to check cfp. if there is
no valid ruby-level-cfp, cause RuntimeError exception.
[ruby-dev:34128]
* vm_core.h, vm_evalbody.c, vm.c, vm_dump.c, vm_insnhelper.c,
insns.def: rename FRAME_MAGIC_* to VM_FRAME_MAGIC_*.
* KNOWNBUGS.rb, bootstraptest/test*.rb: move solved bugs.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17084 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-06-11 01:46:43 +04:00
|
|
|
{
|
2023-02-10 10:02:20 +03:00
|
|
|
return lep_svar_get(ec, rb_vm_svar_lep(ec, cfp), key);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
static void
|
2017-10-28 13:55:35 +03:00
|
|
|
vm_cfp_svar_set(const rb_execution_context_t *ec, rb_control_frame_t *cfp, VALUE key, const VALUE val)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2023-02-10 10:02:20 +03:00
|
|
|
lep_svar_set(ec, rb_vm_svar_lep(ec, cfp), key, val);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2007-07-10 12:04:52 +04:00
|
|
|
static VALUE
|
2017-11-16 08:14:18 +03:00
|
|
|
vm_svar_get(const rb_execution_context_t *ec, VALUE key)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2017-10-28 13:55:35 +03:00
|
|
|
return vm_cfp_svar_get(ec, ec->cfp, key);
|
2007-07-10 12:04:52 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-11-16 08:14:18 +03:00
|
|
|
vm_svar_set(const rb_execution_context_t *ec, VALUE key, VALUE val)
|
2007-07-10 12:04:52 +04:00
|
|
|
{
|
2017-10-28 13:55:35 +03:00
|
|
|
vm_cfp_svar_set(ec, ec->cfp, key, val);
|
* this commit is a result of refactoring. only renaming functions,
moving definitions place, add/remove prototypes, deleting
unused variables and removing yarv.h.
This commit doesn't change any behavior of ruby/vm.
* yarv.h, common.mk: remove yarv.h (contents are moved to yarvcore.h).
* error.c, eval_intern.h: include yarvcore.h instead yarv.h
* rename some functions:
* debug.[ch]: debug_*() -> ruby_debug_*()
* iseq.c: iseq_*() -> rb_iseq_*(), ruby_iseq_disasm()
* iseq.c: node_name() -> ruby_node_name()
* vm.c: yarv_check_redefinition_opt_method() ->
rb_vm_check_redefinition_opt_method()
* some refactoring with checking -Wall.
* array.c: remove rb_ary_ptr() (unused) and remove unused
local variables.
* object.c: add a prototype of rb_mod_module_exec().
* eval_intern.h (ruby_cref): set it inline.
* eval_load.c (rb_load), yarvcore.c: yarv_load() -> rb_load_internal().
* parse.y: add a prototype of rb_parse_in_eval() (in eval.c).
* process.c: add a prototype of rb_thread_stop_timer_thread() (in thread.c).
* thread.c: remove raw_gets() function (unused) and fix some format
mismatch (format mismatchs have remained yet. this is todo).
* thread.c (rb_thread_wait_fd_rw): fix typo on label name.
* thread_pthread.ci: comment out codes with USE_THREAD_CACHE.
* vm.c (rb_svar, rb_backref_get, rb_backref_get,
rb_lastline_get, rb_lastline_set) : moved from yarvcore.c.
* vm.c (yarv_init_redefined_flag): add a prototype and rename
yarv_opt_method_table to vm_opt_method_table.
* vm.c (rb_thread_eval): moved from yarvcore.c.
* yarvcore.c: remove unused global variables and fix to use nsdr().
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11652 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-02-07 04:25:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_backref_get(void)
|
|
|
|
{
|
2017-11-16 08:14:18 +03:00
|
|
|
return vm_svar_get(GET_EC(), VM_SVAR_BACKREF);
|
* this commit is a result of refactoring. only renaming functions,
moving definitions place, add/remove prototypes, deleting
unused variables and removing yarv.h.
This commit doesn't change any behavior of ruby/vm.
* yarv.h, common.mk: remove yarv.h (contents are moved to yarvcore.h).
* error.c, eval_intern.h: include yarvcore.h instead yarv.h
* rename some functions:
* debug.[ch]: debug_*() -> ruby_debug_*()
* iseq.c: iseq_*() -> rb_iseq_*(), ruby_iseq_disasm()
* iseq.c: node_name() -> ruby_node_name()
* vm.c: yarv_check_redefinition_opt_method() ->
rb_vm_check_redefinition_opt_method()
* some refactoring with checking -Wall.
* array.c: remove rb_ary_ptr() (unused) and remove unused
local variables.
* object.c: add a prototype of rb_mod_module_exec().
* eval_intern.h (ruby_cref): set it inline.
* eval_load.c (rb_load), yarvcore.c: yarv_load() -> rb_load_internal().
* parse.y: add a prototype of rb_parse_in_eval() (in eval.c).
* process.c: add a prototype of rb_thread_stop_timer_thread() (in thread.c).
* thread.c: remove raw_gets() function (unused) and fix some format
mismatch (format mismatchs have remained yet. this is todo).
* thread.c (rb_thread_wait_fd_rw): fix typo on label name.
* thread_pthread.ci: comment out codes with USE_THREAD_CACHE.
* vm.c (rb_svar, rb_backref_get, rb_backref_get,
rb_lastline_get, rb_lastline_set) : moved from yarvcore.c.
* vm.c (yarv_init_redefined_flag): add a prototype and rename
yarv_opt_method_table to vm_opt_method_table.
* vm.c (rb_thread_eval): moved from yarvcore.c.
* yarvcore.c: remove unused global variables and fix to use nsdr().
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11652 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-02-07 04:25:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-05-22 20:19:14 +04:00
|
|
|
rb_backref_set(VALUE val)
|
* this commit is a result of refactoring. only renaming functions,
moving definitions place, add/remove prototypes, deleting
unused variables and removing yarv.h.
This commit doesn't change any behavior of ruby/vm.
* yarv.h, common.mk: remove yarv.h (contents are moved to yarvcore.h).
* error.c, eval_intern.h: include yarvcore.h instead yarv.h
* rename some functions:
* debug.[ch]: debug_*() -> ruby_debug_*()
* iseq.c: iseq_*() -> rb_iseq_*(), ruby_iseq_disasm()
* iseq.c: node_name() -> ruby_node_name()
* vm.c: yarv_check_redefinition_opt_method() ->
rb_vm_check_redefinition_opt_method()
* some refactoring with checking -Wall.
* array.c: remove rb_ary_ptr() (unused) and remove unused
local variables.
* object.c: add a prototype of rb_mod_module_exec().
* eval_intern.h (ruby_cref): set it inline.
* eval_load.c (rb_load), yarvcore.c: yarv_load() -> rb_load_internal().
* parse.y: add a prototype of rb_parse_in_eval() (in eval.c).
* process.c: add a prototype of rb_thread_stop_timer_thread() (in thread.c).
* thread.c: remove raw_gets() function (unused) and fix some format
mismatch (format mismatchs have remained yet. this is todo).
* thread.c (rb_thread_wait_fd_rw): fix typo on label name.
* thread_pthread.ci: comment out codes with USE_THREAD_CACHE.
* vm.c (rb_svar, rb_backref_get, rb_backref_get,
rb_lastline_get, rb_lastline_set) : moved from yarvcore.c.
* vm.c (yarv_init_redefined_flag): add a prototype and rename
yarv_opt_method_table to vm_opt_method_table.
* vm.c (rb_thread_eval): moved from yarvcore.c.
* yarvcore.c: remove unused global variables and fix to use nsdr().
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11652 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-02-07 04:25:05 +03:00
|
|
|
{
|
2017-11-16 08:14:18 +03:00
|
|
|
vm_svar_set(GET_EC(), VM_SVAR_BACKREF, val);
|
* this commit is a result of refactoring. only renaming functions,
moving definitions place, add/remove prototypes, deleting
unused variables and removing yarv.h.
This commit doesn't change any behavior of ruby/vm.
* yarv.h, common.mk: remove yarv.h (contents are moved to yarvcore.h).
* error.c, eval_intern.h: include yarvcore.h instead yarv.h
* rename some functions:
* debug.[ch]: debug_*() -> ruby_debug_*()
* iseq.c: iseq_*() -> rb_iseq_*(), ruby_iseq_disasm()
* iseq.c: node_name() -> ruby_node_name()
* vm.c: yarv_check_redefinition_opt_method() ->
rb_vm_check_redefinition_opt_method()
* some refactoring with checking -Wall.
* array.c: remove rb_ary_ptr() (unused) and remove unused
local variables.
* object.c: add a prototype of rb_mod_module_exec().
* eval_intern.h (ruby_cref): set it inline.
* eval_load.c (rb_load), yarvcore.c: yarv_load() -> rb_load_internal().
* parse.y: add a prototype of rb_parse_in_eval() (in eval.c).
* process.c: add a prototype of rb_thread_stop_timer_thread() (in thread.c).
* thread.c: remove raw_gets() function (unused) and fix some format
mismatch (format mismatchs have remained yet. this is todo).
* thread.c (rb_thread_wait_fd_rw): fix typo on label name.
* thread_pthread.ci: comment out codes with USE_THREAD_CACHE.
* vm.c (rb_svar, rb_backref_get, rb_backref_get,
rb_lastline_get, rb_lastline_set) : moved from yarvcore.c.
* vm.c (yarv_init_redefined_flag): add a prototype and rename
yarv_opt_method_table to vm_opt_method_table.
* vm.c (rb_thread_eval): moved from yarvcore.c.
* yarvcore.c: remove unused global variables and fix to use nsdr().
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11652 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-02-07 04:25:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_lastline_get(void)
|
|
|
|
{
|
2017-11-16 08:14:18 +03:00
|
|
|
return vm_svar_get(GET_EC(), VM_SVAR_LASTLINE);
|
* this commit is a result of refactoring. only renaming functions,
moving definitions place, add/remove prototypes, deleting
unused variables and removing yarv.h.
This commit doesn't change any behavior of ruby/vm.
* yarv.h, common.mk: remove yarv.h (contents are moved to yarvcore.h).
* error.c, eval_intern.h: include yarvcore.h instead yarv.h
* rename some functions:
* debug.[ch]: debug_*() -> ruby_debug_*()
* iseq.c: iseq_*() -> rb_iseq_*(), ruby_iseq_disasm()
* iseq.c: node_name() -> ruby_node_name()
* vm.c: yarv_check_redefinition_opt_method() ->
rb_vm_check_redefinition_opt_method()
* some refactoring with checking -Wall.
* array.c: remove rb_ary_ptr() (unused) and remove unused
local variables.
* object.c: add a prototype of rb_mod_module_exec().
* eval_intern.h (ruby_cref): set it inline.
* eval_load.c (rb_load), yarvcore.c: yarv_load() -> rb_load_internal().
* parse.y: add a prototype of rb_parse_in_eval() (in eval.c).
* process.c: add a prototype of rb_thread_stop_timer_thread() (in thread.c).
* thread.c: remove raw_gets() function (unused) and fix some format
mismatch (format mismatchs have remained yet. this is todo).
* thread.c (rb_thread_wait_fd_rw): fix typo on label name.
* thread_pthread.ci: comment out codes with USE_THREAD_CACHE.
* vm.c (rb_svar, rb_backref_get, rb_backref_get,
rb_lastline_get, rb_lastline_set) : moved from yarvcore.c.
* vm.c (yarv_init_redefined_flag): add a prototype and rename
yarv_opt_method_table to vm_opt_method_table.
* vm.c (rb_thread_eval): moved from yarvcore.c.
* yarvcore.c: remove unused global variables and fix to use nsdr().
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11652 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-02-07 04:25:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-05-22 20:19:14 +04:00
|
|
|
rb_lastline_set(VALUE val)
|
* this commit is a result of refactoring. only renaming functions,
moving definitions place, add/remove prototypes, deleting
unused variables and removing yarv.h.
This commit doesn't change any behavior of ruby/vm.
* yarv.h, common.mk: remove yarv.h (contents are moved to yarvcore.h).
* error.c, eval_intern.h: include yarvcore.h instead yarv.h
* rename some functions:
* debug.[ch]: debug_*() -> ruby_debug_*()
* iseq.c: iseq_*() -> rb_iseq_*(), ruby_iseq_disasm()
* iseq.c: node_name() -> ruby_node_name()
* vm.c: yarv_check_redefinition_opt_method() ->
rb_vm_check_redefinition_opt_method()
* some refactoring with checking -Wall.
* array.c: remove rb_ary_ptr() (unused) and remove unused
local variables.
* object.c: add a prototype of rb_mod_module_exec().
* eval_intern.h (ruby_cref): set it inline.
* eval_load.c (rb_load), yarvcore.c: yarv_load() -> rb_load_internal().
* parse.y: add a prototype of rb_parse_in_eval() (in eval.c).
* process.c: add a prototype of rb_thread_stop_timer_thread() (in thread.c).
* thread.c: remove raw_gets() function (unused) and fix some format
mismatch (format mismatchs have remained yet. this is todo).
* thread.c (rb_thread_wait_fd_rw): fix typo on label name.
* thread_pthread.ci: comment out codes with USE_THREAD_CACHE.
* vm.c (rb_svar, rb_backref_get, rb_backref_get,
rb_lastline_get, rb_lastline_set) : moved from yarvcore.c.
* vm.c (yarv_init_redefined_flag): add a prototype and rename
yarv_opt_method_table to vm_opt_method_table.
* vm.c (rb_thread_eval): moved from yarvcore.c.
* yarvcore.c: remove unused global variables and fix to use nsdr().
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11652 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-02-07 04:25:05 +03:00
|
|
|
{
|
2017-11-16 08:14:18 +03:00
|
|
|
vm_svar_set(GET_EC(), VM_SVAR_LASTLINE, val);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2023-09-19 00:44:51 +03:00
|
|
|
void
|
|
|
|
rb_lastline_set_up(VALUE val, unsigned int up)
|
|
|
|
{
|
|
|
|
rb_control_frame_t * cfp = GET_EC()->cfp;
|
|
|
|
|
|
|
|
for(unsigned int i = 0; i < up; i++) {
|
|
|
|
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
|
|
|
}
|
|
|
|
vm_cfp_svar_set(GET_EC(), cfp, VM_SVAR_LASTLINE, val);
|
|
|
|
}
|
|
|
|
|
2012-05-25 08:50:10 +04:00
|
|
|
/* misc */
|
|
|
|
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
const char *
|
|
|
|
rb_sourcefile(void)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2017-10-26 11:41:34 +03:00
|
|
|
const rb_execution_context_t *ec = GET_EC();
|
|
|
|
const rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
|
|
|
|
if (cfp) {
|
2017-06-01 03:05:33 +03:00
|
|
|
return RSTRING_PTR(rb_iseq_path(cfp->iseq));
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rb_sourceline(void)
|
|
|
|
{
|
2017-10-26 11:41:34 +03:00
|
|
|
const rb_execution_context_t *ec = GET_EC();
|
|
|
|
const rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
|
|
|
|
if (cfp) {
|
* vm.c: add a prefix "rb_" to exposed functions
vm_get_ruby_level_next_cfp(), rb_vm_make_env_object(),
vm_stack_to_heap(), vm_make_proc(), vm_invoke_proc(),
vm_get_sourceline(), vm_cref(), vm_localjump_error(),
vm_make_jump_tag_but_local_jump(), vm_jump_tag_but_local_jump().
This changes may affect only core because most of renamed functions
require a pointer of not-exposed struct such as rb_thread_t or NODE.
In short, they are core functions.
* cont.c, eval.c, eval_intern.h, load.c, proc.c, thread.c,
vm_core.h, vm_dump.c, vm_eval.c, vm_exec.c, vm_insnhelper.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@21659 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2009-01-19 05:38:11 +03:00
|
|
|
return rb_vm_get_sourceline(cfp);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
return 0;
|
2007-06-25 06:44:20 +04:00
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2015-10-29 08:32:57 +03:00
|
|
|
VALUE
|
|
|
|
rb_source_location(int *pline)
|
|
|
|
{
|
2017-10-26 11:41:34 +03:00
|
|
|
const rb_execution_context_t *ec = GET_EC();
|
|
|
|
const rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
|
2015-10-29 08:32:57 +03:00
|
|
|
|
2019-07-31 17:15:56 +03:00
|
|
|
if (cfp && VM_FRAME_RUBYFRAME_P(cfp)) {
|
2015-10-29 08:32:57 +03:00
|
|
|
if (pline) *pline = rb_vm_get_sourceline(cfp);
|
2017-06-01 03:05:33 +03:00
|
|
|
return rb_iseq_path(cfp->iseq);
|
2015-10-29 08:32:57 +03:00
|
|
|
}
|
|
|
|
else {
|
2015-10-31 03:17:41 +03:00
|
|
|
if (pline) *pline = 0;
|
2017-11-16 08:35:58 +03:00
|
|
|
return Qnil;
|
2015-10-29 08:32:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-07 08:34:31 +03:00
|
|
|
const char *
|
2017-11-16 08:52:19 +03:00
|
|
|
rb_source_location_cstr(int *pline)
|
2015-10-29 08:32:57 +03:00
|
|
|
{
|
|
|
|
VALUE path = rb_source_location(pline);
|
2017-11-16 08:45:44 +03:00
|
|
|
if (NIL_P(path)) return NULL;
|
2015-10-29 08:32:57 +03:00
|
|
|
return RSTRING_PTR(path);
|
|
|
|
}
|
|
|
|
|
2015-03-09 00:22:43 +03:00
|
|
|
rb_cref_t *
|
* vm.c: add a prefix "rb_" to exposed functions
vm_get_ruby_level_next_cfp(), rb_vm_make_env_object(),
vm_stack_to_heap(), vm_make_proc(), vm_invoke_proc(),
vm_get_sourceline(), vm_cref(), vm_localjump_error(),
vm_make_jump_tag_but_local_jump(), vm_jump_tag_but_local_jump().
This changes may affect only core because most of renamed functions
require a pointer of not-exposed struct such as rb_thread_t or NODE.
In short, they are core functions.
* cont.c, eval.c, eval_intern.h, load.c, proc.c, thread.c,
vm_core.h, vm_dump.c, vm_eval.c, vm_exec.c, vm_insnhelper.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@21659 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2009-01-19 05:38:11 +03:00
|
|
|
rb_vm_cref(void)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2017-10-26 11:41:34 +03:00
|
|
|
const rb_execution_context_t *ec = GET_EC();
|
2019-04-05 11:15:11 +03:00
|
|
|
return vm_ec_cref(ec);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2015-11-20 03:17:25 +03:00
|
|
|
rb_cref_t *
|
|
|
|
rb_vm_cref_replace_with_duplicated_cref(void)
|
|
|
|
{
|
2017-10-26 11:41:34 +03:00
|
|
|
const rb_execution_context_t *ec = GET_EC();
|
|
|
|
const rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
|
2015-11-20 03:17:25 +03:00
|
|
|
rb_cref_t *cref = vm_cref_replace_with_duplicated_cref(cfp->ep);
|
2017-10-25 12:32:44 +03:00
|
|
|
ASSUME(cref);
|
2015-11-20 03:17:25 +03:00
|
|
|
return cref;
|
|
|
|
}
|
|
|
|
|
2015-03-09 00:22:43 +03:00
|
|
|
const rb_cref_t *
|
2013-12-24 18:04:31 +04:00
|
|
|
rb_vm_cref_in_context(VALUE self, VALUE cbase)
|
2013-12-24 11:28:11 +04:00
|
|
|
{
|
2017-10-26 11:41:34 +03:00
|
|
|
const rb_execution_context_t *ec = GET_EC();
|
|
|
|
const rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
|
2015-03-09 00:22:43 +03:00
|
|
|
const rb_cref_t *cref;
|
2019-08-01 03:03:11 +03:00
|
|
|
if (!cfp || cfp->self != self) return NULL;
|
2015-12-09 10:15:48 +03:00
|
|
|
if (!vm_env_cref_by_cref(cfp->ep)) return NULL;
|
2019-04-05 11:15:11 +03:00
|
|
|
cref = vm_get_cref(cfp->ep);
|
2015-03-08 22:50:37 +03:00
|
|
|
if (CREF_CLASS(cref) != cbase) return NULL;
|
2013-12-24 18:04:31 +04:00
|
|
|
return cref;
|
2013-12-24 11:28:11 +04:00
|
|
|
}
|
|
|
|
|
2007-06-24 21:19:22 +04:00
|
|
|
#if 0
|
2006-12-31 18:02:22 +03:00
|
|
|
void
|
2015-03-09 00:22:43 +03:00
|
|
|
debug_cref(rb_cref_t *cref)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
|
|
|
while (cref) {
|
2015-03-08 22:50:37 +03:00
|
|
|
dp(CREF_CLASS(cref));
|
|
|
|
printf("%ld\n", CREF_VISI(cref));
|
|
|
|
cref = CREF_NEXT(cref);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
}
|
2007-06-24 21:19:22 +04:00
|
|
|
#endif
|
2006-12-31 18:02:22 +03:00
|
|
|
|
* vm.c, insns.def, eval.c, vm_insnhelper.c: fix CREF handling.
VM value stack frame of block contains cref information.
(dfp[-1] points CREF)
* compile.c, eval_intern.h, eval_method.c, load.c, proc.c,
vm_dump.h, vm_core.h: ditto.
* include/ruby/ruby.h, gc.c: remove T_VALUES because of above
changes.
* bootstraptest/test_eval.rb, test_knownbug.rb: move solved test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-19 07:08:50 +04:00
|
|
|
VALUE
|
|
|
|
rb_vm_cbase(void)
|
|
|
|
{
|
2017-10-26 11:41:34 +03:00
|
|
|
const rb_execution_context_t *ec = GET_EC();
|
|
|
|
const rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
|
* vm.c, eval_intern.h (PASS_PASSED_BLOCK):
set a VM_FRAME_FLAG_PASSED flag to skip this frame when
searching ruby-level-cfp.
* eval.c, eval_intern.h, proc.c: fix to check cfp. if there is
no valid ruby-level-cfp, cause RuntimeError exception.
[ruby-dev:34128]
* vm_core.h, vm_evalbody.c, vm.c, vm_dump.c, vm_insnhelper.c,
insns.def: rename FRAME_MAGIC_* to VM_FRAME_MAGIC_*.
* KNOWNBUGS.rb, bootstraptest/test*.rb: move solved bugs.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17084 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-06-11 01:46:43 +04:00
|
|
|
|
2011-07-31 06:32:48 +04:00
|
|
|
if (cfp == 0) {
|
|
|
|
rb_raise(rb_eRuntimeError, "Can't call on top of Fiber or Thread");
|
|
|
|
}
|
* fix namespace issue on singleton class expressions. [Bug #10943]
* vm_core.h, method.h: remove rb_iseq_t::cref_stack. CREF is stored
to rb_method_definition_t::body.iseq_body.cref.
* vm_insnhelper.c: modify SVAR usage.
When calling ISEQ type method, push CREF information onto method
frame, SVAR located place. Before this fix, SVAR is simply nil.
After this patch, CREF (or NULL == Qfalse for not iseq methods)
is stored at the method invocation.
When SVAR is requierd, then put NODE_IF onto SVAR location,
and NDOE_IF::nd_reserved points CREF itself.
* vm.c (vm_cref_new, vm_cref_dump, vm_cref_new_toplevel): added.
* vm_insnhelper.c (vm_push_frame): accept CREF.
* method.h, vm_method.c (rb_add_method_iseq): added. This function
accepts iseq and CREF.
* class.c (clone_method): use rb_add_method_iseq().
* gc.c (mark_method_entry): mark method_entry::body.iseq_body.cref.
* iseq.c: remove CREF related codes.
* insns.def (getinlinecache/setinlinecache): CREF should be cache key
because a different CREF has a different namespace.
* node.c (rb_gc_mark_node): mark NODE_IF::nd_reserved for SVAR.
* proc.c: catch up changes.
* struct.c: ditto.
* insns.def: ditto.
* vm_args.c (raise_argument_error): ditto.
* vm_eval.c: ditto.
* test/ruby/test_class.rb: add a test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49874 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-03-06 15:24:58 +03:00
|
|
|
return vm_get_cbase(cfp->ep);
|
* vm.c, insns.def, eval.c, vm_insnhelper.c: fix CREF handling.
VM value stack frame of block contains cref information.
(dfp[-1] points CREF)
* compile.c, eval_intern.h, eval_method.c, load.c, proc.c,
vm_dump.h, vm_core.h: ditto.
* include/ruby/ruby.h, gc.c: remove T_VALUES because of above
changes.
* bootstraptest/test_eval.rb, test_knownbug.rb: move solved test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-19 07:08:50 +04:00
|
|
|
}
|
|
|
|
|
2007-06-25 06:44:20 +04:00
|
|
|
/* jump */
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
static VALUE
|
2008-05-22 20:19:14 +04:00
|
|
|
make_localjump_error(const char *mesg, VALUE value, int reason)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2007-07-05 14:04:56 +04:00
|
|
|
extern VALUE rb_eLocalJumpError;
|
|
|
|
VALUE exc = rb_exc_new2(rb_eLocalJumpError, mesg);
|
2006-12-31 18:02:22 +03:00
|
|
|
ID id;
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
switch (reason) {
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
case TAG_BREAK:
|
2008-06-09 13:25:32 +04:00
|
|
|
CONST_ID(id, "break");
|
2006-12-31 18:02:22 +03:00
|
|
|
break;
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
case TAG_REDO:
|
2008-06-09 13:25:32 +04:00
|
|
|
CONST_ID(id, "redo");
|
2006-12-31 18:02:22 +03:00
|
|
|
break;
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
case TAG_RETRY:
|
2008-06-09 13:25:32 +04:00
|
|
|
CONST_ID(id, "retry");
|
2006-12-31 18:02:22 +03:00
|
|
|
break;
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
case TAG_NEXT:
|
2008-06-09 13:25:32 +04:00
|
|
|
CONST_ID(id, "next");
|
2006-12-31 18:02:22 +03:00
|
|
|
break;
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
case TAG_RETURN:
|
2008-06-09 13:25:32 +04:00
|
|
|
CONST_ID(id, "return");
|
2006-12-31 18:02:22 +03:00
|
|
|
break;
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
default:
|
2008-06-09 13:25:32 +04:00
|
|
|
CONST_ID(id, "noreason");
|
2006-12-31 18:02:22 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
rb_iv_set(exc, "@exit_value", value);
|
|
|
|
rb_iv_set(exc, "@reason", ID2SYM(id));
|
|
|
|
return exc;
|
|
|
|
}
|
|
|
|
|
2023-03-07 08:34:31 +03:00
|
|
|
void
|
* vm.c: add a prefix "rb_" to exposed functions
vm_get_ruby_level_next_cfp(), rb_vm_make_env_object(),
vm_stack_to_heap(), vm_make_proc(), vm_invoke_proc(),
vm_get_sourceline(), vm_cref(), vm_localjump_error(),
vm_make_jump_tag_but_local_jump(), vm_jump_tag_but_local_jump().
This changes may affect only core because most of renamed functions
require a pointer of not-exposed struct such as rb_thread_t or NODE.
In short, they are core functions.
* cont.c, eval.c, eval_intern.h, load.c, proc.c, thread.c,
vm_core.h, vm_dump.c, vm_eval.c, vm_exec.c, vm_insnhelper.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@21659 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2009-01-19 05:38:11 +03:00
|
|
|
rb_vm_localjump_error(const char *mesg, VALUE value, int reason)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
|
|
|
VALUE exc = make_localjump_error(mesg, value, reason);
|
|
|
|
rb_exc_raise(exc);
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
2023-08-07 18:32:45 +03:00
|
|
|
rb_vm_make_jump_tag_but_local_jump(enum ruby_tag_type state, VALUE val)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2017-09-26 00:51:56 +03:00
|
|
|
const char *mesg;
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
switch (state) {
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
case TAG_RETURN:
|
2017-09-26 00:51:56 +03:00
|
|
|
mesg = "unexpected return";
|
2006-12-31 18:02:22 +03:00
|
|
|
break;
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
case TAG_BREAK:
|
2017-09-26 00:51:56 +03:00
|
|
|
mesg = "unexpected break";
|
2006-12-31 18:02:22 +03:00
|
|
|
break;
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
case TAG_NEXT:
|
2017-09-26 00:51:56 +03:00
|
|
|
mesg = "unexpected next";
|
2006-12-31 18:02:22 +03:00
|
|
|
break;
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
case TAG_REDO:
|
2017-09-26 00:51:56 +03:00
|
|
|
mesg = "unexpected redo";
|
|
|
|
val = Qnil;
|
2006-12-31 18:02:22 +03:00
|
|
|
break;
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
case TAG_RETRY:
|
2017-09-26 00:51:56 +03:00
|
|
|
mesg = "retry outside of rescue clause";
|
|
|
|
val = Qnil;
|
2006-12-31 18:02:22 +03:00
|
|
|
break;
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
default:
|
2017-09-26 00:51:56 +03:00
|
|
|
return Qnil;
|
|
|
|
}
|
2022-11-15 07:24:08 +03:00
|
|
|
if (UNDEF_P(val)) {
|
2017-10-26 17:44:09 +03:00
|
|
|
val = GET_EC()->tag->retval;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2017-09-26 00:51:56 +03:00
|
|
|
return make_localjump_error(mesg, val, state);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2023-08-07 18:32:45 +03:00
|
|
|
rb_vm_jump_tag_but_local_jump(enum ruby_tag_type state)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2012-12-18 21:04:05 +04:00
|
|
|
VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef);
|
|
|
|
if (!NIL_P(exc)) rb_exc_raise(exc);
|
2017-12-06 06:16:08 +03:00
|
|
|
EC_JUMP_TAG(GET_EC(), state);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
static rb_control_frame_t *
|
|
|
|
next_not_local_frame(rb_control_frame_t *cfp)
|
|
|
|
{
|
|
|
|
while (VM_ENV_LOCAL_P(cfp->ep)) {
|
|
|
|
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
|
|
|
}
|
|
|
|
return cfp;
|
|
|
|
}
|
|
|
|
|
2017-10-28 13:59:37 +03:00
|
|
|
NORETURN(static void vm_iter_break(rb_execution_context_t *ec, VALUE val));
|
|
|
|
|
2007-06-25 06:44:20 +04:00
|
|
|
static void
|
2017-10-28 13:59:37 +03:00
|
|
|
vm_iter_break(rb_execution_context_t *ec, VALUE val)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2017-10-28 13:59:37 +03:00
|
|
|
rb_control_frame_t *cfp = next_not_local_frame(ec->cfp);
|
2016-07-28 14:02:30 +03:00
|
|
|
const VALUE *ep = VM_CF_PREV_EP(cfp);
|
2017-10-28 13:59:37 +03:00
|
|
|
const rb_control_frame_t *target_cfp = rb_vm_search_cf_from_ep(ec, cfp, ep);
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2015-06-12 16:01:40 +03:00
|
|
|
if (!target_cfp) {
|
|
|
|
rb_vm_localjump_error("unexpected break", val, TAG_BREAK);
|
|
|
|
}
|
|
|
|
|
2017-10-28 13:59:37 +03:00
|
|
|
ec->errinfo = (VALUE)THROW_DATA_NEW(val, target_cfp, TAG_BREAK);
|
|
|
|
EC_JUMP_TAG(ec, TAG_BREAK);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2007-06-25 06:44:20 +04:00
|
|
|
void
|
2008-05-22 08:28:13 +04:00
|
|
|
rb_iter_break(void)
|
2007-06-25 06:44:20 +04:00
|
|
|
{
|
2017-10-28 13:59:37 +03:00
|
|
|
vm_iter_break(GET_EC(), Qnil);
|
2012-01-24 09:20:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_iter_break_value(VALUE val)
|
|
|
|
{
|
2017-10-28 13:59:37 +03:00
|
|
|
vm_iter_break(GET_EC(), val);
|
2007-06-25 06:44:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* optimization: redefine management */
|
|
|
|
|
2022-12-01 04:28:14 +03:00
|
|
|
short ruby_vm_redefined_flag[BOP_LAST_];
|
2021-05-12 21:10:18 +03:00
|
|
|
static st_table *vm_opt_method_def_table = 0;
|
2019-12-13 02:47:59 +03:00
|
|
|
static st_table *vm_opt_mid_table = 0;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2023-10-12 21:15:53 +03:00
|
|
|
void
|
|
|
|
rb_free_vm_opt_tables(void)
|
|
|
|
{
|
|
|
|
st_free_table(vm_opt_method_def_table);
|
|
|
|
st_free_table(vm_opt_mid_table);
|
|
|
|
}
|
|
|
|
|
2013-03-05 16:36:45 +04:00
|
|
|
static int
|
|
|
|
vm_redefinition_check_flag(VALUE klass)
|
|
|
|
{
|
2016-05-17 09:53:48 +03:00
|
|
|
if (klass == rb_cInteger) return INTEGER_REDEFINED_OP_FLAG;
|
2013-03-05 16:36:45 +04:00
|
|
|
if (klass == rb_cFloat) return FLOAT_REDEFINED_OP_FLAG;
|
|
|
|
if (klass == rb_cString) return STRING_REDEFINED_OP_FLAG;
|
|
|
|
if (klass == rb_cArray) return ARRAY_REDEFINED_OP_FLAG;
|
|
|
|
if (klass == rb_cHash) return HASH_REDEFINED_OP_FLAG;
|
|
|
|
if (klass == rb_cSymbol) return SYMBOL_REDEFINED_OP_FLAG;
|
2020-12-02 09:50:01 +03:00
|
|
|
#if 0
|
2013-03-05 16:36:45 +04:00
|
|
|
if (klass == rb_cTime) return TIME_REDEFINED_OP_FLAG;
|
2020-12-02 09:50:01 +03:00
|
|
|
#endif
|
2013-09-26 11:39:48 +04:00
|
|
|
if (klass == rb_cRegexp) return REGEXP_REDEFINED_OP_FLAG;
|
2015-12-08 04:46:45 +03:00
|
|
|
if (klass == rb_cNilClass) return NIL_REDEFINED_OP_FLAG;
|
|
|
|
if (klass == rb_cTrueClass) return TRUE_REDEFINED_OP_FLAG;
|
|
|
|
if (klass == rb_cFalseClass) return FALSE_REDEFINED_OP_FLAG;
|
2018-01-07 22:18:49 +03:00
|
|
|
if (klass == rb_cProc) return PROC_REDEFINED_OP_FLAG;
|
2013-03-05 16:36:45 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-12-13 02:47:59 +03:00
|
|
|
int
|
|
|
|
rb_vm_check_optimizable_mid(VALUE mid)
|
|
|
|
{
|
|
|
|
if (!vm_opt_mid_table) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return st_lookup(vm_opt_mid_table, mid, NULL);
|
|
|
|
}
|
|
|
|
|
2018-01-08 12:04:07 +03:00
|
|
|
static int
|
2021-12-15 00:20:45 +03:00
|
|
|
vm_redefinition_check_method_type(const rb_method_entry_t *me)
|
2018-01-08 12:04:07 +03:00
|
|
|
{
|
2021-12-15 00:20:45 +03:00
|
|
|
if (me->called_id != me->def->original_id) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2023-10-18 11:47:48 +03:00
|
|
|
if (METHOD_ENTRY_BASIC(me)) return TRUE;
|
|
|
|
|
2021-12-15 00:20:45 +03:00
|
|
|
const rb_method_definition_t *def = me->def;
|
2018-01-08 12:04:07 +03:00
|
|
|
switch (def->type) {
|
|
|
|
case VM_METHOD_TYPE_CFUNC:
|
|
|
|
case VM_METHOD_TYPE_OPTIMIZED:
|
|
|
|
return TRUE;
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
static void
|
2011-08-25 02:02:03 +04:00
|
|
|
rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me, VALUE klass)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
* compile.c (iseq_build_body), error.c (set_syserr, get_syserr),
(syserr_initialize), gc.c (define_final, rb_gc_copy_finalizer),
(run_final), hash.c (rb_hash_aref, rb_hash_lookup2),
(rb_hash_fetch_m, rb_hash_clear, rb_hash_aset, eql_i),
iseq.c (iseq_load, iseq_data_to_ary), marshal.c (r_symlink),
thread.c (rb_thread_local_aref),
variable.c (generic_ivar_remove, ivar_get, rb_const_get_0),
(rb_cvar_get), vm.c (rb_vm_check_redefinition_opt_method),
vm_insnhelper.c (vm_get_ev_const), vm_method.c (remove_method),
ext/iconv/iconv.c (map_charset): use st_data_t.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@29462 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2010-10-12 18:47:23 +04:00
|
|
|
st_data_t bop;
|
2020-04-05 22:10:42 +03:00
|
|
|
if (RB_TYPE_P(klass, T_ICLASS) && FL_TEST(klass, RICLASS_IS_ORIGIN) &&
|
|
|
|
RB_TYPE_P(RBASIC_CLASS(klass), T_CLASS)) {
|
2015-12-18 01:43:35 +03:00
|
|
|
klass = RBASIC_CLASS(klass);
|
|
|
|
}
|
2021-12-15 00:20:45 +03:00
|
|
|
if (vm_redefinition_check_method_type(me)) {
|
2021-10-01 14:17:09 +03:00
|
|
|
if (st_lookup(vm_opt_method_def_table, (st_data_t)me->def, &bop)) {
|
2021-05-12 21:10:18 +03:00
|
|
|
int flag = vm_redefinition_check_flag(klass);
|
2021-12-11 04:08:05 +03:00
|
|
|
if (flag != 0) {
|
2024-04-15 14:03:26 +03:00
|
|
|
rb_category_warn(
|
|
|
|
RB_WARN_CATEGORY_PERFORMANCE,
|
|
|
|
"Redefining '%s#%s' disables interpreter and JIT optimizations",
|
|
|
|
rb_class2name(me->owner),
|
|
|
|
rb_id2name(me->called_id)
|
|
|
|
);
|
Rust YJIT
In December 2021, we opened an [issue] to solicit feedback regarding the
porting of the YJIT codebase from C99 to Rust. There were some
reservations, but this project was given the go ahead by Ruby core
developers and Matz. Since then, we have successfully completed the port
of YJIT to Rust.
The new Rust version of YJIT has reached parity with the C version, in
that it passes all the CRuby tests, is able to run all of the YJIT
benchmarks, and performs similarly to the C version (because it works
the same way and largely generates the same machine code). We've even
incorporated some design improvements, such as a more fine-grained
constant invalidation mechanism which we expect will make a big
difference in Ruby on Rails applications.
Because we want to be careful, YJIT is guarded behind a configure
option:
```shell
./configure --enable-yjit # Build YJIT in release mode
./configure --enable-yjit=dev # Build YJIT in dev/debug mode
```
By default, YJIT does not get compiled and cargo/rustc is not required.
If YJIT is built in dev mode, then `cargo` is used to fetch development
dependencies, but when building in release, `cargo` is not required,
only `rustc`. At the moment YJIT requires Rust 1.60.0 or newer.
The YJIT command-line options remain mostly unchanged, and more details
about the build process are documented in `doc/yjit/yjit.md`.
The CI tests have been updated and do not take any more resources than
before.
The development history of the Rust port is available at the following
commit for interested parties:
https://github.com/Shopify/ruby/commit/1fd9573d8b4b65219f1c2407f30a0a60e537f8be
Our hope is that Rust YJIT will be compiled and included as a part of
system packages and compiled binaries of the Ruby 3.2 release. We do not
anticipate any major problems as Rust is well supported on every
platform which YJIT supports, but to make sure that this process works
smoothly, we would like to reach out to those who take care of building
systems packages before the 3.2 release is shipped and resolve any
issues that may come up.
[issue]: https://bugs.ruby-lang.org/issues/18481
Co-authored-by: Maxime Chevalier-Boisvert <maximechevalierb@gmail.com>
Co-authored-by: Noah Gibbs <the.codefolio.guy@gmail.com>
Co-authored-by: Kevin Newton <kddnewton@gmail.com>
2022-04-19 21:40:21 +03:00
|
|
|
rb_yjit_bop_redefined(flag, (enum ruby_basic_operators)bop);
|
2023-03-07 10:17:25 +03:00
|
|
|
rb_rjit_bop_redefined(flag, (enum ruby_basic_operators)bop);
|
2021-12-11 04:08:05 +03:00
|
|
|
ruby_vm_redefined_flag[bop] |= flag;
|
|
|
|
}
|
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-12 11:43:55 +03:00
|
|
|
static enum rb_id_table_iterator_result
|
|
|
|
check_redefined_method(ID mid, VALUE value, void *data)
|
2013-03-05 16:36:45 +04:00
|
|
|
{
|
|
|
|
VALUE klass = (VALUE)data;
|
2019-10-03 06:26:41 +03:00
|
|
|
const rb_method_entry_t *me = (rb_method_entry_t *)value;
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
const rb_method_entry_t *newme = rb_method_entry(klass, mid);
|
|
|
|
|
|
|
|
if (newme != me) rb_vm_check_redefinition_opt_method(me, me->owner);
|
2013-03-05 16:36:45 +04:00
|
|
|
|
2015-08-12 11:59:27 +03:00
|
|
|
return ID_TABLE_CONTINUE;
|
2013-03-05 16:36:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_vm_check_redefinition_by_prepend(VALUE klass)
|
|
|
|
{
|
|
|
|
if (!vm_redefinition_check_flag(klass)) return;
|
2015-08-12 11:43:55 +03:00
|
|
|
rb_id_table_foreach(RCLASS_M_TBL(RCLASS_ORIGIN(klass)), check_redefined_method, (void *)klass);
|
2013-03-05 16:36:45 +04:00
|
|
|
}
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
static void
|
2023-10-18 11:47:48 +03:00
|
|
|
add_opt_method_entry_bop(const rb_method_entry_t *me, ID mid, enum ruby_basic_operators bop)
|
|
|
|
{
|
|
|
|
st_insert(vm_opt_method_def_table, (st_data_t)me->def, (st_data_t)bop);
|
|
|
|
st_insert(vm_opt_mid_table, (st_data_t)mid, (st_data_t)Qtrue);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
add_opt_method(VALUE klass, ID mid, enum ruby_basic_operators bop)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
const rb_method_entry_t *me = rb_method_entry_at(klass, mid);
|
2014-03-08 12:56:50 +04:00
|
|
|
|
2021-12-15 00:20:45 +03:00
|
|
|
if (me && vm_redefinition_check_method_type(me)) {
|
2023-10-18 11:47:48 +03:00
|
|
|
add_opt_method_entry_bop(me, mid, bop);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
else {
|
* this commit is a result of refactoring. only renaming functions,
moving definitions place, add/remove prototypes, deleting
unused variables and removing yarv.h.
This commit doesn't change any behavior of ruby/vm.
* yarv.h, common.mk: remove yarv.h (contents are moved to yarvcore.h).
* error.c, eval_intern.h: include yarvcore.h instead yarv.h
* rename some functions:
* debug.[ch]: debug_*() -> ruby_debug_*()
* iseq.c: iseq_*() -> rb_iseq_*(), ruby_iseq_disasm()
* iseq.c: node_name() -> ruby_node_name()
* vm.c: yarv_check_redefinition_opt_method() ->
rb_vm_check_redefinition_opt_method()
* some refactoring with checking -Wall.
* array.c: remove rb_ary_ptr() (unused) and remove unused
local variables.
* object.c: add a prototype of rb_mod_module_exec().
* eval_intern.h (ruby_cref): set it inline.
* eval_load.c (rb_load), yarvcore.c: yarv_load() -> rb_load_internal().
* parse.y: add a prototype of rb_parse_in_eval() (in eval.c).
* process.c: add a prototype of rb_thread_stop_timer_thread() (in thread.c).
* thread.c: remove raw_gets() function (unused) and fix some format
mismatch (format mismatchs have remained yet. this is todo).
* thread.c (rb_thread_wait_fd_rw): fix typo on label name.
* thread_pthread.ci: comment out codes with USE_THREAD_CACHE.
* vm.c (rb_svar, rb_backref_get, rb_backref_get,
rb_lastline_get, rb_lastline_set) : moved from yarvcore.c.
* vm.c (yarv_init_redefined_flag): add a prototype and rename
yarv_opt_method_table to vm_opt_method_table.
* vm.c (rb_thread_eval): moved from yarvcore.c.
* yarvcore.c: remove unused global variables and fix to use nsdr().
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11652 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-02-07 04:25:05 +03:00
|
|
|
rb_bug("undefined optimized method: %s", rb_id2name(mid));
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-18 11:47:48 +03:00
|
|
|
static enum ruby_basic_operators vm_redefinition_bop_for_id(ID mid);
|
|
|
|
|
|
|
|
static void
|
|
|
|
add_opt_method_entry(const rb_method_entry_t *me)
|
|
|
|
{
|
|
|
|
if (me && vm_redefinition_check_method_type(me)) {
|
|
|
|
ID mid = me->called_id;
|
|
|
|
enum ruby_basic_operators bop = vm_redefinition_bop_for_id(mid);
|
|
|
|
if ((int)bop >= 0) {
|
|
|
|
add_opt_method_entry_bop(me, mid, bop);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
static void
|
|
|
|
vm_init_redefined_flag(void)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2007-07-20 11:11:35 +04:00
|
|
|
ID mid;
|
2023-10-18 11:47:48 +03:00
|
|
|
enum ruby_basic_operators bop;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2008-10-12 07:28:49 +04:00
|
|
|
#define OP(mid_, bop_) (mid = id##mid_, bop = BOP_##bop_, ruby_vm_redefined_flag[bop] = 0)
|
2007-07-20 11:11:35 +04:00
|
|
|
#define C(k) add_opt_method(rb_c##k, mid, bop)
|
2016-05-17 09:53:48 +03:00
|
|
|
OP(PLUS, PLUS), (C(Integer), C(Float), C(String), C(Array));
|
|
|
|
OP(MINUS, MINUS), (C(Integer), C(Float));
|
|
|
|
OP(MULT, MULT), (C(Integer), C(Float));
|
|
|
|
OP(DIV, DIV), (C(Integer), C(Float));
|
|
|
|
OP(MOD, MOD), (C(Integer), C(Float));
|
2017-07-02 13:38:38 +03:00
|
|
|
OP(Eq, EQ), (C(Integer), C(Float), C(String), C(Symbol));
|
2016-05-17 09:53:48 +03:00
|
|
|
OP(Eqq, EQQ), (C(Integer), C(Float), C(Symbol), C(String),
|
2015-12-08 04:46:45 +03:00
|
|
|
C(NilClass), C(TrueClass), C(FalseClass));
|
2016-05-17 09:53:48 +03:00
|
|
|
OP(LT, LT), (C(Integer), C(Float));
|
|
|
|
OP(LE, LE), (C(Integer), C(Float));
|
|
|
|
OP(GT, GT), (C(Integer), C(Float));
|
|
|
|
OP(GE, GE), (C(Integer), C(Float));
|
2007-07-20 11:11:35 +04:00
|
|
|
OP(LTLT, LTLT), (C(String), C(Array));
|
2019-06-01 07:15:43 +03:00
|
|
|
OP(AREF, AREF), (C(Array), C(Hash), C(Integer));
|
2007-07-20 11:11:35 +04:00
|
|
|
OP(ASET, ASET), (C(Array), C(Hash));
|
|
|
|
OP(Length, LENGTH), (C(Array), C(String), C(Hash));
|
2009-09-06 12:39:57 +04:00
|
|
|
OP(Size, SIZE), (C(Array), C(String), C(Hash));
|
2012-09-26 13:34:46 +04:00
|
|
|
OP(EmptyP, EMPTY_P), (C(Array), C(String), C(Hash));
|
2020-12-02 09:50:01 +03:00
|
|
|
OP(Succ, SUCC), (C(Integer), C(String));
|
2013-09-26 11:58:28 +04:00
|
|
|
OP(EqTilde, MATCH), (C(Regexp), C(String));
|
2024-08-05 13:31:24 +03:00
|
|
|
OP(Freeze, FREEZE), (C(String), C(Array), C(Hash));
|
2017-03-27 09:12:37 +03:00
|
|
|
OP(UMinus, UMINUS), (C(String));
|
2016-03-17 15:47:31 +03:00
|
|
|
OP(Max, MAX), (C(Array));
|
|
|
|
OP(Min, MIN), (C(Array));
|
Emit special instruction for array literal + .(hash|min|max)
This commit introduces a new instruction `opt_newarray_send` which is
used when there is an array literal followed by either the `hash`,
`min`, or `max` method.
```
[a, b, c].hash
```
Will emit an `opt_newarray_send` instruction. This instruction falls
back to a method call if the "interested" method has been monkey
patched.
Here are some examples of the instructions generated:
```
$ ./miniruby --dump=insns -e '[@a, @b].max'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,12)> (catch: FALSE)
0000 getinstancevariable :@a, <is:0> ( 1)[Li]
0003 getinstancevariable :@b, <is:1>
0006 opt_newarray_send 2, :max
0009 leave
$ ./miniruby --dump=insns -e '[@a, @b].min'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,12)> (catch: FALSE)
0000 getinstancevariable :@a, <is:0> ( 1)[Li]
0003 getinstancevariable :@b, <is:1>
0006 opt_newarray_send 2, :min
0009 leave
$ ./miniruby --dump=insns -e '[@a, @b].hash'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,13)> (catch: FALSE)
0000 getinstancevariable :@a, <is:0> ( 1)[Li]
0003 getinstancevariable :@b, <is:1>
0006 opt_newarray_send 2, :hash
0009 leave
```
[Feature #18897] [ruby-core:109147]
Co-authored-by: John Hawthorn <jhawthorn@github.com>
2022-06-07 03:27:56 +03:00
|
|
|
OP(Hash, HASH), (C(Array));
|
2018-01-08 12:04:07 +03:00
|
|
|
OP(Call, CALL), (C(Proc));
|
2018-09-26 05:38:45 +03:00
|
|
|
OP(And, AND), (C(Integer));
|
|
|
|
OP(Or, OR), (C(Integer));
|
2019-08-02 17:25:38 +03:00
|
|
|
OP(NilP, NIL_P), (C(NilClass));
|
2022-11-23 05:16:11 +03:00
|
|
|
OP(Cmp, CMP), (C(Integer), C(Float), C(String));
|
2022-12-15 21:46:24 +03:00
|
|
|
OP(Default, DEFAULT), (C(Hash));
|
2007-07-20 11:11:35 +04:00
|
|
|
#undef C
|
|
|
|
#undef OP
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2023-10-18 11:47:48 +03:00
|
|
|
static enum ruby_basic_operators
|
|
|
|
vm_redefinition_bop_for_id(ID mid)
|
|
|
|
{
|
|
|
|
switch (mid) {
|
|
|
|
#define OP(mid_, bop_) case id##mid_: return BOP_##bop_
|
|
|
|
OP(PLUS, PLUS);
|
|
|
|
OP(MINUS, MINUS);
|
|
|
|
OP(MULT, MULT);
|
|
|
|
OP(DIV, DIV);
|
|
|
|
OP(MOD, MOD);
|
|
|
|
OP(Eq, EQ);
|
|
|
|
OP(Eqq, EQQ);
|
|
|
|
OP(LT, LT);
|
|
|
|
OP(LE, LE);
|
|
|
|
OP(GT, GT);
|
|
|
|
OP(GE, GE);
|
|
|
|
OP(LTLT, LTLT);
|
|
|
|
OP(AREF, AREF);
|
|
|
|
OP(ASET, ASET);
|
|
|
|
OP(Length, LENGTH);
|
|
|
|
OP(Size, SIZE);
|
|
|
|
OP(EmptyP, EMPTY_P);
|
|
|
|
OP(Succ, SUCC);
|
|
|
|
OP(EqTilde, MATCH);
|
|
|
|
OP(Freeze, FREEZE);
|
|
|
|
OP(UMinus, UMINUS);
|
|
|
|
OP(Max, MAX);
|
|
|
|
OP(Min, MIN);
|
|
|
|
OP(Hash, HASH);
|
|
|
|
OP(Call, CALL);
|
|
|
|
OP(And, AND);
|
|
|
|
OP(Or, OR);
|
|
|
|
OP(NilP, NIL_P);
|
|
|
|
OP(Cmp, CMP);
|
|
|
|
OP(Default, DEFAULT);
|
Introduce a specialize instruction for Array#pack
Instructions for this code:
```ruby
# frozen_string_literal: true
[a].pack("C")
```
Before this commit:
```
== disasm: #<ISeq:<main>@test.rb:1 (1,0)-(3,13)>
0000 putself ( 3)[Li]
0001 opt_send_without_block <calldata!mid:a, argc:0, FCALL|VCALL|ARGS_SIMPLE>
0003 newarray 1
0005 putobject "C"
0007 opt_send_without_block <calldata!mid:pack, argc:1, ARGS_SIMPLE>
0009 leave
```
After this commit:
```
== disasm: #<ISeq:<main>@test.rb:1 (1,0)-(3,13)>
0000 putself ( 3)[Li]
0001 opt_send_without_block <calldata!mid:a, argc:0, FCALL|VCALL|ARGS_SIMPLE>
0003 putobject "C"
0005 opt_newarray_send 2, :pack
0008 leave
```
Co-authored-by: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@shopify.com>
Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
2024-05-23 21:23:26 +03:00
|
|
|
OP(Pack, PACK);
|
2023-10-18 11:47:48 +03:00
|
|
|
#undef OP
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-01-24 16:52:32 +03:00
|
|
|
/* for vm development */
|
|
|
|
|
2010-02-17 11:05:42 +03:00
|
|
|
#if VMDEBUG
|
2010-01-24 16:52:32 +03:00
|
|
|
static const char *
|
|
|
|
vm_frametype_name(const rb_control_frame_t *cfp)
|
|
|
|
{
|
|
|
|
switch (VM_FRAME_TYPE(cfp)) {
|
|
|
|
case VM_FRAME_MAGIC_METHOD: return "method";
|
|
|
|
case VM_FRAME_MAGIC_BLOCK: return "block";
|
|
|
|
case VM_FRAME_MAGIC_CLASS: return "class";
|
|
|
|
case VM_FRAME_MAGIC_TOP: return "top";
|
|
|
|
case VM_FRAME_MAGIC_CFUNC: return "cfunc";
|
|
|
|
case VM_FRAME_MAGIC_IFUNC: return "ifunc";
|
|
|
|
case VM_FRAME_MAGIC_EVAL: return "eval";
|
2014-06-19 13:17:21 +04:00
|
|
|
case VM_FRAME_MAGIC_RESCUE: return "rescue";
|
2010-01-24 16:52:32 +03:00
|
|
|
default:
|
|
|
|
rb_bug("unknown frame");
|
|
|
|
}
|
|
|
|
}
|
2010-02-17 11:05:42 +03:00
|
|
|
#endif
|
2010-01-24 16:52:32 +03:00
|
|
|
|
2017-04-06 05:56:23 +03:00
|
|
|
static VALUE
|
|
|
|
frame_return_value(const struct vm_throw_data *err)
|
|
|
|
{
|
|
|
|
if (THROW_DATA_P(err) &&
|
|
|
|
THROW_DATA_STATE(err) == TAG_BREAK &&
|
|
|
|
THROW_DATA_CONSUMED_P(err) == FALSE) {
|
|
|
|
return THROW_DATA_VAL(err);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
/* for debug */
|
|
|
|
static const char *
|
|
|
|
frame_name(const rb_control_frame_t *cfp)
|
|
|
|
{
|
|
|
|
unsigned long type = VM_FRAME_TYPE(cfp);
|
|
|
|
#define C(t) if (type == VM_FRAME_MAGIC_##t) return #t
|
|
|
|
C(METHOD);
|
|
|
|
C(BLOCK);
|
|
|
|
C(CLASS);
|
|
|
|
C(TOP);
|
|
|
|
C(CFUNC);
|
|
|
|
C(PROC);
|
|
|
|
C(IFUNC);
|
|
|
|
C(EVAL);
|
|
|
|
C(LAMBDA);
|
|
|
|
C(RESCUE);
|
|
|
|
C(DUMMY);
|
|
|
|
#undef C
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-07-14 02:01:09 +03:00
|
|
|
// cfp_returning_with_value:
|
|
|
|
// Whether cfp is the last frame in the unwinding process for a non-local return.
|
2015-04-10 11:29:30 +03:00
|
|
|
static void
|
2023-08-25 00:32:45 +03:00
|
|
|
hook_before_rewind(rb_execution_context_t *ec, bool cfp_returning_with_value, int state, struct vm_throw_data *err)
|
2015-04-10 11:29:30 +03:00
|
|
|
{
|
2020-04-08 07:28:13 +03:00
|
|
|
if (state == TAG_RAISE && RBASIC(err)->klass == rb_eSysStackError) {
|
2017-04-14 10:46:11 +03:00
|
|
|
return;
|
|
|
|
}
|
2018-11-26 21:16:39 +03:00
|
|
|
else {
|
2023-08-25 00:32:45 +03:00
|
|
|
const rb_iseq_t *iseq = ec->cfp->iseq;
|
2018-12-06 13:52:27 +03:00
|
|
|
rb_hook_list_t *local_hooks = iseq->aux.exec.local_hooks;
|
2018-11-26 21:16:39 +03:00
|
|
|
|
|
|
|
switch (VM_FRAME_TYPE(ec->cfp)) {
|
|
|
|
case VM_FRAME_MAGIC_METHOD:
|
|
|
|
RUBY_DTRACE_METHOD_RETURN_HOOK(ec, 0, 0);
|
|
|
|
EXEC_EVENT_HOOK_AND_POP_FRAME(ec, RUBY_EVENT_RETURN, ec->cfp->self, 0, 0, 0, frame_return_value(err));
|
|
|
|
|
|
|
|
if (UNLIKELY(local_hooks && local_hooks->events & RUBY_EVENT_RETURN)) {
|
|
|
|
rb_exec_event_hook_orig(ec, local_hooks, RUBY_EVENT_RETURN,
|
|
|
|
ec->cfp->self, 0, 0, 0, frame_return_value(err), TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
THROW_DATA_CONSUMED_SET(err);
|
|
|
|
break;
|
|
|
|
case VM_FRAME_MAGIC_BLOCK:
|
|
|
|
if (VM_FRAME_BMETHOD_P(ec->cfp)) {
|
2021-07-14 02:01:09 +03:00
|
|
|
VALUE bmethod_return_value = frame_return_value(err);
|
|
|
|
if (cfp_returning_with_value) {
|
|
|
|
// Non-local return terminating at a BMETHOD control frame.
|
|
|
|
bmethod_return_value = THROW_DATA_VAL(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-07-09 01:23:39 +03:00
|
|
|
EXEC_EVENT_HOOK_AND_POP_FRAME(ec, RUBY_EVENT_B_RETURN, ec->cfp->self, 0, 0, 0, bmethod_return_value);
|
2018-11-26 21:16:39 +03:00
|
|
|
if (UNLIKELY(local_hooks && local_hooks->events & RUBY_EVENT_B_RETURN)) {
|
|
|
|
rb_exec_event_hook_orig(ec, local_hooks, RUBY_EVENT_B_RETURN,
|
2021-07-09 01:23:39 +03:00
|
|
|
ec->cfp->self, 0, 0, 0, bmethod_return_value, TRUE);
|
2018-11-26 21:16:39 +03:00
|
|
|
}
|
|
|
|
|
2021-07-14 02:01:09 +03:00
|
|
|
const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(ec->cfp);
|
|
|
|
|
|
|
|
EXEC_EVENT_HOOK_AND_POP_FRAME(ec, RUBY_EVENT_RETURN, ec->cfp->self,
|
|
|
|
rb_vm_frame_method_entry(ec->cfp)->def->original_id,
|
|
|
|
rb_vm_frame_method_entry(ec->cfp)->called_id,
|
|
|
|
rb_vm_frame_method_entry(ec->cfp)->owner,
|
|
|
|
bmethod_return_value);
|
|
|
|
|
|
|
|
VM_ASSERT(me->def->type == VM_METHOD_TYPE_BMETHOD);
|
|
|
|
local_hooks = me->def->body.bmethod.hooks;
|
|
|
|
|
|
|
|
if (UNLIKELY(local_hooks && local_hooks->events & RUBY_EVENT_RETURN)) {
|
|
|
|
rb_exec_event_hook_orig(ec, local_hooks, RUBY_EVENT_RETURN, ec->cfp->self,
|
|
|
|
rb_vm_frame_method_entry(ec->cfp)->def->original_id,
|
|
|
|
rb_vm_frame_method_entry(ec->cfp)->called_id,
|
|
|
|
rb_vm_frame_method_entry(ec->cfp)->owner,
|
|
|
|
bmethod_return_value, TRUE);
|
2018-11-26 21:16:39 +03:00
|
|
|
}
|
|
|
|
THROW_DATA_CONSUMED_SET(err);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
EXEC_EVENT_HOOK_AND_POP_FRAME(ec, RUBY_EVENT_B_RETURN, ec->cfp->self, 0, 0, 0, frame_return_value(err));
|
|
|
|
if (UNLIKELY(local_hooks && local_hooks->events & RUBY_EVENT_B_RETURN)) {
|
|
|
|
rb_exec_event_hook_orig(ec, local_hooks, RUBY_EVENT_B_RETURN,
|
|
|
|
ec->cfp->self, 0, 0, 0, frame_return_value(err), TRUE);
|
|
|
|
}
|
|
|
|
THROW_DATA_CONSUMED_SET(err);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VM_FRAME_MAGIC_CLASS:
|
|
|
|
EXEC_EVENT_HOOK_AND_POP_FRAME(ec, RUBY_EVENT_END, ec->cfp->self, 0, 0, 0, Qnil);
|
|
|
|
break;
|
|
|
|
}
|
2015-04-10 11:29:30 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-25 06:44:20 +04:00
|
|
|
/* evaluator body */
|
2007-04-19 14:37:08 +04:00
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
/* finish
|
|
|
|
VMe (h1) finish
|
|
|
|
VM finish F1 F2
|
2007-11-23 11:34:34 +03:00
|
|
|
cfunc finish F1 F2 C1
|
2006-12-31 18:02:22 +03:00
|
|
|
rb_funcall finish F1 F2 C1
|
|
|
|
VMe finish F1 F2 C1
|
|
|
|
VM finish F1 F2 C1 F3
|
|
|
|
|
|
|
|
F1 - F3 : pushed by VM
|
|
|
|
C1 : pushed by send insn (CFUNC)
|
|
|
|
|
|
|
|
struct CONTROL_FRAME {
|
* vm.c, insns.def, eval.c, vm_insnhelper.c: fix CREF handling.
VM value stack frame of block contains cref information.
(dfp[-1] points CREF)
* compile.c, eval_intern.h, eval_method.c, load.c, proc.c,
vm_dump.h, vm_core.h: ditto.
* include/ruby/ruby.h, gc.c: remove T_VALUES because of above
changes.
* bootstraptest/test_eval.rb, test_knownbug.rb: move solved test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-19 07:08:50 +04:00
|
|
|
VALUE *pc; // cfp[0], program counter
|
|
|
|
VALUE *sp; // cfp[1], stack pointer
|
2016-07-28 14:02:30 +03:00
|
|
|
rb_iseq_t *iseq; // cfp[2], iseq
|
|
|
|
VALUE self; // cfp[3], self
|
|
|
|
const VALUE *ep; // cfp[4], env pointer
|
2018-02-24 04:02:58 +03:00
|
|
|
const void *block_code; // cfp[5], block code
|
2006-12-31 18:02:22 +03:00
|
|
|
};
|
|
|
|
|
2018-02-24 04:02:58 +03:00
|
|
|
struct rb_captured_block {
|
2006-12-31 18:02:22 +03:00
|
|
|
VALUE self;
|
2012-06-11 07:14:59 +04:00
|
|
|
VALUE *ep;
|
2016-07-28 14:02:30 +03:00
|
|
|
union code;
|
2006-12-31 18:02:22 +03:00
|
|
|
};
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
struct METHOD_ENV {
|
2006-12-31 18:02:22 +03:00
|
|
|
VALUE param0;
|
|
|
|
...
|
|
|
|
VALUE paramN;
|
2016-07-28 14:02:30 +03:00
|
|
|
VALUE lvar1;
|
|
|
|
...
|
|
|
|
VALUE lvarM;
|
|
|
|
VALUE cref; // ep[-2]
|
|
|
|
VALUE special; // ep[-1]
|
|
|
|
VALUE flags; // ep[ 0] == lep[0]
|
2006-12-31 18:02:22 +03:00
|
|
|
};
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
struct BLOCK_ENV {
|
|
|
|
VALUE block_param0;
|
2006-12-31 18:02:22 +03:00
|
|
|
...
|
2016-07-28 14:02:30 +03:00
|
|
|
VALUE block_paramN;
|
|
|
|
VALUE block_lvar1;
|
2006-12-31 18:02:22 +03:00
|
|
|
...
|
2016-07-28 14:02:30 +03:00
|
|
|
VALUE block_lvarM;
|
|
|
|
VALUE cref; // ep[-2]
|
|
|
|
VALUE special; // ep[-1]
|
|
|
|
VALUE flags; // ep[ 0]
|
2006-12-31 18:02:22 +03:00
|
|
|
};
|
|
|
|
|
2016-07-28 14:02:30 +03:00
|
|
|
struct CLASS_ENV {
|
|
|
|
VALUE class_lvar0;
|
2006-12-31 18:02:22 +03:00
|
|
|
...
|
2016-07-28 14:02:30 +03:00
|
|
|
VALUE class_lvarN;
|
* vm.c, insns.def, eval.c, vm_insnhelper.c: fix CREF handling.
VM value stack frame of block contains cref information.
(dfp[-1] points CREF)
* compile.c, eval_intern.h, eval_method.c, load.c, proc.c,
vm_dump.h, vm_core.h: ditto.
* include/ruby/ruby.h, gc.c: remove T_VALUES because of above
changes.
* bootstraptest/test_eval.rb, test_knownbug.rb: move solved test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-19 07:08:50 +04:00
|
|
|
VALUE cref;
|
2012-06-11 07:14:59 +04:00
|
|
|
VALUE prev_ep; // for frame jump
|
2016-07-28 14:02:30 +03:00
|
|
|
VALUE flags;
|
2006-12-31 18:02:22 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
struct C_METHOD_CONTROL_FRAME {
|
|
|
|
VALUE *pc; // 0
|
|
|
|
VALUE *sp; // stack pointer
|
2012-06-11 07:14:59 +04:00
|
|
|
rb_iseq_t *iseq; // cmi
|
2006-12-31 18:02:22 +03:00
|
|
|
VALUE self; // ?
|
2012-06-11 07:14:59 +04:00
|
|
|
VALUE *ep; // ep == lep
|
2016-07-28 14:02:30 +03:00
|
|
|
void *code; //
|
2006-12-31 18:02:22 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
struct C_BLOCK_CONTROL_FRAME {
|
|
|
|
VALUE *pc; // point only "finish" insn
|
|
|
|
VALUE *sp; // sp
|
2012-06-11 07:14:59 +04:00
|
|
|
rb_iseq_t *iseq; // ?
|
2016-07-28 14:02:30 +03:00
|
|
|
VALUE self; //
|
2012-06-11 07:14:59 +04:00
|
|
|
VALUE *ep; // ep
|
2016-07-28 14:02:32 +03:00
|
|
|
void *code; //
|
2006-12-31 18:02:22 +03:00
|
|
|
};
|
|
|
|
*/
|
|
|
|
|
2018-03-04 05:37:22 +03:00
|
|
|
static inline VALUE
|
2023-07-28 03:31:12 +03:00
|
|
|
vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, VALUE errinfo);
|
2023-08-06 17:34:27 +03:00
|
|
|
static inline VALUE
|
|
|
|
vm_exec_loop(rb_execution_context_t *ec, enum ruby_tag_type state, struct rb_vm_tag *tag, VALUE result);
|
2018-03-04 05:37:22 +03:00
|
|
|
|
2022-01-27 15:33:39 +03:00
|
|
|
// for non-Emscripten Wasm build, use vm_exec with optimized setjmp for runtime performance
|
|
|
|
#if defined(__wasm__) && !defined(__EMSCRIPTEN__)
|
|
|
|
|
|
|
|
struct rb_vm_exec_context {
|
2023-08-06 17:34:27 +03:00
|
|
|
rb_execution_context_t *const ec;
|
|
|
|
struct rb_vm_tag *const tag;
|
|
|
|
|
2022-01-27 15:33:39 +03:00
|
|
|
VALUE result;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
vm_exec_bottom_main(void *context)
|
|
|
|
{
|
2023-08-06 17:34:27 +03:00
|
|
|
struct rb_vm_exec_context *ctx = context;
|
|
|
|
rb_execution_context_t *ec = ctx->ec;
|
2022-01-27 15:33:39 +03:00
|
|
|
|
2023-08-06 17:34:27 +03:00
|
|
|
ctx->result = vm_exec_loop(ec, TAG_NONE, ctx->tag, vm_exec_core(ec));
|
2022-01-27 15:33:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vm_exec_bottom_rescue(void *context)
|
|
|
|
{
|
2023-08-06 17:34:27 +03:00
|
|
|
struct rb_vm_exec_context *ctx = context;
|
|
|
|
rb_execution_context_t *ec = ctx->ec;
|
|
|
|
|
|
|
|
ctx->result = vm_exec_loop(ec, rb_ec_tag_state(ec), ctx->tag, ec->errinfo);
|
2022-01-27 15:33:39 +03:00
|
|
|
}
|
2023-08-06 17:34:27 +03:00
|
|
|
#endif
|
2022-01-27 15:33:39 +03:00
|
|
|
|
|
|
|
VALUE
|
2023-03-15 00:00:19 +03:00
|
|
|
vm_exec(rb_execution_context_t *ec)
|
2022-01-27 15:33:39 +03:00
|
|
|
{
|
2023-08-06 17:34:27 +03:00
|
|
|
VALUE result = Qundef;
|
2022-01-27 15:33:39 +03:00
|
|
|
|
|
|
|
EC_PUSH_TAG(ec);
|
|
|
|
|
|
|
|
_tag.retval = Qnil;
|
2023-08-06 17:34:27 +03:00
|
|
|
|
|
|
|
#if defined(__wasm__) && !defined(__EMSCRIPTEN__)
|
|
|
|
struct rb_vm_exec_context ctx = {
|
|
|
|
.ec = ec,
|
|
|
|
.tag = &_tag,
|
|
|
|
};
|
|
|
|
struct rb_wasm_try_catch try_catch;
|
2022-01-27 15:33:39 +03:00
|
|
|
|
|
|
|
EC_REPUSH_TAG();
|
|
|
|
|
|
|
|
rb_wasm_try_catch_init(&try_catch, vm_exec_bottom_main, vm_exec_bottom_rescue, &ctx);
|
|
|
|
|
2023-11-12 01:18:01 +03:00
|
|
|
rb_wasm_try_catch_loop_run(&try_catch, &RB_VM_TAG_JMPBUF_GET(_tag.buf));
|
2022-01-27 15:33:39 +03:00
|
|
|
|
2023-08-06 17:34:27 +03:00
|
|
|
result = ctx.result;
|
2022-01-27 15:33:39 +03:00
|
|
|
#else
|
2017-06-23 10:25:52 +03:00
|
|
|
enum ruby_tag_type state;
|
2017-12-06 06:16:08 +03:00
|
|
|
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
|
2023-03-15 00:00:19 +03:00
|
|
|
if (UNDEF_P(result = jit_exec(ec))) {
|
2023-07-28 03:31:12 +03:00
|
|
|
result = vm_exec_core(ec);
|
2018-03-05 04:17:08 +03:00
|
|
|
}
|
2023-08-06 17:34:27 +03:00
|
|
|
/* fallback to the VM */
|
|
|
|
result = vm_exec_loop(ec, TAG_NONE, &_tag, result);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
else {
|
2023-08-06 17:34:27 +03:00
|
|
|
result = vm_exec_loop(ec, state, &_tag, ec->errinfo);
|
2018-03-04 05:37:22 +03:00
|
|
|
}
|
2023-08-06 17:34:27 +03:00
|
|
|
#endif
|
|
|
|
|
2018-03-04 05:37:22 +03:00
|
|
|
EC_POP_TAG();
|
|
|
|
return result;
|
|
|
|
}
|
2023-08-06 17:34:27 +03:00
|
|
|
|
|
|
|
static inline VALUE
|
|
|
|
vm_exec_loop(rb_execution_context_t *ec, enum ruby_tag_type state,
|
|
|
|
struct rb_vm_tag *tag, VALUE result)
|
|
|
|
{
|
|
|
|
if (state == TAG_NONE) { /* no jumps, result is discarded */
|
|
|
|
goto vm_loop_start;
|
|
|
|
}
|
|
|
|
|
|
|
|
rb_ec_raised_reset(ec, RAISED_STACKOVERFLOW | RAISED_NOMEMORY);
|
|
|
|
while (UNDEF_P(result = vm_exec_handle_exception(ec, state, result))) {
|
2023-08-09 02:06:22 +03:00
|
|
|
// caught a jump, exec the handler. JIT code in jit_exec_exception()
|
|
|
|
// may return Qundef to run remaining frames with vm_exec_core().
|
|
|
|
if (UNDEF_P(result = jit_exec_exception(ec))) {
|
|
|
|
result = vm_exec_core(ec);
|
|
|
|
}
|
2023-08-06 17:34:27 +03:00
|
|
|
vm_loop_start:
|
|
|
|
VM_ASSERT(ec->tag == tag);
|
|
|
|
/* when caught `throw`, `tag.state` is set. */
|
|
|
|
if ((state = tag->state) == TAG_NONE) break;
|
|
|
|
tag->state = TAG_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2018-03-04 05:37:22 +03:00
|
|
|
|
|
|
|
static inline VALUE
|
2023-07-28 03:31:12 +03:00
|
|
|
vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, VALUE errinfo)
|
2018-03-04 05:37:22 +03:00
|
|
|
{
|
|
|
|
struct vm_throw_data *err = (struct vm_throw_data *)errinfo;
|
|
|
|
|
|
|
|
for (;;) {
|
2015-07-25 00:44:14 +03:00
|
|
|
unsigned int i;
|
2015-07-24 22:49:16 +03:00
|
|
|
const struct iseq_catch_table_entry *entry;
|
|
|
|
const struct iseq_catch_table *ct;
|
2006-12-31 18:02:22 +03:00
|
|
|
unsigned long epc, cont_pc, cont_sp;
|
2015-07-22 01:52:59 +03:00
|
|
|
const rb_iseq_t *catch_iseq;
|
2006-12-31 18:02:22 +03:00
|
|
|
VALUE type;
|
2015-03-10 21:39:46 +03:00
|
|
|
const rb_control_frame_t *escape_cfp;
|
2022-07-21 19:23:58 +03:00
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
cont_pc = cont_sp = 0;
|
|
|
|
catch_iseq = NULL;
|
2022-07-21 19:23:58 +03:00
|
|
|
|
2017-10-28 13:35:55 +03:00
|
|
|
while (ec->cfp->pc == 0 || ec->cfp->iseq == 0) {
|
|
|
|
if (UNLIKELY(VM_FRAME_TYPE(ec->cfp) == VM_FRAME_MAGIC_CFUNC)) {
|
2018-06-23 07:52:58 +03:00
|
|
|
EXEC_EVENT_HOOK_AND_POP_FRAME(ec, RUBY_EVENT_C_RETURN, ec->cfp->self,
|
|
|
|
rb_vm_frame_method_entry(ec->cfp)->def->original_id,
|
|
|
|
rb_vm_frame_method_entry(ec->cfp)->called_id,
|
|
|
|
rb_vm_frame_method_entry(ec->cfp)->owner, Qnil);
|
2017-11-07 11:19:25 +03:00
|
|
|
RUBY_DTRACE_CMETHOD_RETURN_HOOK(ec,
|
2017-10-28 13:35:55 +03:00
|
|
|
rb_vm_frame_method_entry(ec->cfp)->owner,
|
|
|
|
rb_vm_frame_method_entry(ec->cfp)->def->original_id);
|
2010-01-24 16:52:32 +03:00
|
|
|
}
|
2017-10-28 13:35:55 +03:00
|
|
|
rb_vm_pop_frame(ec);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2022-07-21 19:23:58 +03:00
|
|
|
|
2023-08-24 21:40:52 +03:00
|
|
|
rb_control_frame_t *const cfp = ec->cfp;
|
2022-03-23 22:19:48 +03:00
|
|
|
epc = cfp->pc - ISEQ_BODY(cfp->iseq)->iseq_encoded;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2015-01-16 05:54:22 +03:00
|
|
|
escape_cfp = NULL;
|
2006-12-31 18:02:22 +03:00
|
|
|
if (state == TAG_BREAK || state == TAG_RETURN) {
|
2015-03-10 21:39:46 +03:00
|
|
|
escape_cfp = THROW_DATA_CATCH_FRAME(err);
|
2022-07-21 19:23:58 +03:00
|
|
|
|
2015-01-16 05:54:22 +03:00
|
|
|
if (cfp == escape_cfp) {
|
2006-12-31 18:02:22 +03:00
|
|
|
if (state == TAG_RETURN) {
|
2016-08-03 03:28:12 +03:00
|
|
|
if (!VM_FRAME_FINISHED_P(cfp)) {
|
2015-03-10 21:39:46 +03:00
|
|
|
THROW_DATA_CATCH_FRAME_SET(err, cfp + 1);
|
|
|
|
THROW_DATA_STATE_SET(err, state = TAG_BREAK);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
else {
|
2022-03-23 22:19:48 +03:00
|
|
|
ct = ISEQ_BODY(cfp->iseq)->catch_table;
|
2014-07-14 11:06:26 +04:00
|
|
|
if (ct) for (i = 0; i < ct->size; i++) {
|
2019-05-31 09:58:50 +03:00
|
|
|
entry = UNALIGNED_MEMBER_PTR(ct, entries[i]);
|
2009-08-13 16:06:14 +04:00
|
|
|
if (entry->start < epc && entry->end >= epc) {
|
|
|
|
if (entry->type == CATCH_TYPE_ENSURE) {
|
2015-07-22 01:52:59 +03:00
|
|
|
catch_iseq = entry->iseq;
|
2009-08-13 16:06:14 +04:00
|
|
|
cont_pc = entry->cont;
|
|
|
|
cont_sp = entry->sp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-04-06 05:56:23 +03:00
|
|
|
if (catch_iseq == NULL) {
|
2017-10-28 13:35:55 +03:00
|
|
|
ec->errinfo = Qnil;
|
2017-04-06 05:56:23 +03:00
|
|
|
THROW_DATA_CATCH_FRAME_SET(err, cfp + 1);
|
2021-07-14 02:01:09 +03:00
|
|
|
// cfp == escape_cfp here so calling with cfp_returning_with_value = true
|
2023-08-25 00:32:45 +03:00
|
|
|
hook_before_rewind(ec, true, state, err);
|
2017-10-28 13:35:55 +03:00
|
|
|
rb_vm_pop_frame(ec);
|
2018-03-04 05:37:22 +03:00
|
|
|
return THROW_DATA_VAL(err);
|
2009-08-13 16:06:14 +04:00
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
/* through */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* TAG_BREAK */
|
2023-08-24 21:40:52 +03:00
|
|
|
*cfp->sp++ = THROW_DATA_VAL(err);
|
2017-10-28 13:35:55 +03:00
|
|
|
ec->errinfo = Qnil;
|
2018-03-04 05:37:22 +03:00
|
|
|
return Qundef;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state == TAG_RAISE) {
|
2022-03-23 22:19:48 +03:00
|
|
|
ct = ISEQ_BODY(cfp->iseq)->catch_table;
|
2014-07-14 11:06:26 +04:00
|
|
|
if (ct) for (i = 0; i < ct->size; i++) {
|
2019-05-31 09:58:50 +03:00
|
|
|
entry = UNALIGNED_MEMBER_PTR(ct, entries[i]);
|
2006-12-31 18:02:22 +03:00
|
|
|
if (entry->start < epc && entry->end >= epc) {
|
2022-07-21 19:23:58 +03:00
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
if (entry->type == CATCH_TYPE_RESCUE ||
|
|
|
|
entry->type == CATCH_TYPE_ENSURE) {
|
2015-07-22 01:52:59 +03:00
|
|
|
catch_iseq = entry->iseq;
|
2006-12-31 18:02:22 +03:00
|
|
|
cont_pc = entry->cont;
|
|
|
|
cont_sp = entry->sp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (state == TAG_RETRY) {
|
2022-03-23 22:19:48 +03:00
|
|
|
ct = ISEQ_BODY(cfp->iseq)->catch_table;
|
2014-07-14 11:06:26 +04:00
|
|
|
if (ct) for (i = 0; i < ct->size; i++) {
|
2019-05-31 09:58:50 +03:00
|
|
|
entry = UNALIGNED_MEMBER_PTR(ct, entries[i]);
|
2006-12-31 18:02:22 +03:00
|
|
|
if (entry->start < epc && entry->end >= epc) {
|
2022-07-21 19:23:58 +03:00
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
if (entry->type == CATCH_TYPE_ENSURE) {
|
2015-07-22 01:52:59 +03:00
|
|
|
catch_iseq = entry->iseq;
|
2006-12-31 18:02:22 +03:00
|
|
|
cont_pc = entry->cont;
|
|
|
|
cont_sp = entry->sp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (entry->type == CATCH_TYPE_RETRY) {
|
2015-03-10 21:39:46 +03:00
|
|
|
const rb_control_frame_t *escape_cfp;
|
|
|
|
escape_cfp = THROW_DATA_CATCH_FRAME(err);
|
2015-01-16 05:54:22 +03:00
|
|
|
if (cfp == escape_cfp) {
|
2022-03-23 22:19:48 +03:00
|
|
|
cfp->pc = ISEQ_BODY(cfp->iseq)->iseq_encoded + entry->cont;
|
2017-10-28 13:35:55 +03:00
|
|
|
ec->errinfo = Qnil;
|
2018-03-04 05:37:22 +03:00
|
|
|
return Qundef;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-06-22 04:57:01 +03:00
|
|
|
else if ((state == TAG_BREAK && !escape_cfp) ||
|
|
|
|
(state == TAG_REDO) ||
|
|
|
|
(state == TAG_NEXT)) {
|
2022-07-22 10:57:25 +03:00
|
|
|
type = (const enum rb_catch_type[TAG_MASK]) {
|
2020-06-22 04:57:01 +03:00
|
|
|
[TAG_BREAK] = CATCH_TYPE_BREAK,
|
|
|
|
[TAG_NEXT] = CATCH_TYPE_NEXT,
|
|
|
|
[TAG_REDO] = CATCH_TYPE_REDO,
|
|
|
|
/* otherwise = dontcare */
|
|
|
|
}[state];
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2022-03-23 22:19:48 +03:00
|
|
|
ct = ISEQ_BODY(cfp->iseq)->catch_table;
|
2014-07-14 11:06:26 +04:00
|
|
|
if (ct) for (i = 0; i < ct->size; i++) {
|
2019-05-31 09:58:50 +03:00
|
|
|
entry = UNALIGNED_MEMBER_PTR(ct, entries[i]);
|
2022-07-21 19:23:58 +03:00
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
if (entry->start < epc && entry->end >= epc) {
|
|
|
|
if (entry->type == CATCH_TYPE_ENSURE) {
|
2015-07-22 01:52:59 +03:00
|
|
|
catch_iseq = entry->iseq;
|
2006-12-31 18:02:22 +03:00
|
|
|
cont_pc = entry->cont;
|
|
|
|
cont_sp = entry->sp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (entry->type == type) {
|
2022-03-23 22:19:48 +03:00
|
|
|
cfp->pc = ISEQ_BODY(cfp->iseq)->iseq_encoded + entry->cont;
|
2012-09-28 08:05:36 +04:00
|
|
|
cfp->sp = vm_base_ptr(cfp) + entry->sp;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2008-05-24 10:29:48 +04:00
|
|
|
if (state != TAG_REDO) {
|
2023-08-24 21:40:52 +03:00
|
|
|
*cfp->sp++ = THROW_DATA_VAL(err);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2017-10-28 13:35:55 +03:00
|
|
|
ec->errinfo = Qnil;
|
|
|
|
VM_ASSERT(ec->tag->state == TAG_NONE);
|
2018-03-04 05:37:22 +03:00
|
|
|
return Qundef;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2022-03-23 22:19:48 +03:00
|
|
|
ct = ISEQ_BODY(cfp->iseq)->catch_table;
|
2014-07-14 11:06:26 +04:00
|
|
|
if (ct) for (i = 0; i < ct->size; i++) {
|
2019-05-31 09:58:50 +03:00
|
|
|
entry = UNALIGNED_MEMBER_PTR(ct, entries[i]);
|
2006-12-31 18:02:22 +03:00
|
|
|
if (entry->start < epc && entry->end >= epc) {
|
2022-07-21 19:23:58 +03:00
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
if (entry->type == CATCH_TYPE_ENSURE) {
|
2015-07-22 01:52:59 +03:00
|
|
|
catch_iseq = entry->iseq;
|
2006-12-31 18:02:22 +03:00
|
|
|
cont_pc = entry->cont;
|
|
|
|
cont_sp = entry->sp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-07-21 19:23:58 +03:00
|
|
|
|
2015-09-19 20:59:58 +03:00
|
|
|
if (catch_iseq != NULL) { /* found catch table */
|
2006-12-31 18:02:22 +03:00
|
|
|
/* enter catch scope */
|
2016-07-28 14:02:30 +03:00
|
|
|
const int arg_size = 1;
|
2022-07-21 19:23:58 +03:00
|
|
|
|
2015-12-08 16:58:50 +03:00
|
|
|
rb_iseq_check(catch_iseq);
|
2012-09-28 08:05:36 +04:00
|
|
|
cfp->sp = vm_base_ptr(cfp) + cont_sp;
|
2022-03-23 22:19:48 +03:00
|
|
|
cfp->pc = ISEQ_BODY(cfp->iseq)->iseq_encoded + cont_pc;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
/* push block frame */
|
2015-03-10 21:39:46 +03:00
|
|
|
cfp->sp[0] = (VALUE)err;
|
2017-10-28 13:35:55 +03:00
|
|
|
vm_push_frame(ec, catch_iseq, VM_FRAME_MAGIC_RESCUE,
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
cfp->self,
|
2016-07-28 14:02:30 +03:00
|
|
|
VM_GUARDED_PREV_EP(cfp->ep),
|
2015-06-02 07:20:30 +03:00
|
|
|
0, /* cref or me */
|
2022-03-23 22:19:48 +03:00
|
|
|
ISEQ_BODY(catch_iseq)->iseq_encoded,
|
2016-07-28 14:02:30 +03:00
|
|
|
cfp->sp + arg_size /* push value */,
|
2022-03-23 22:19:48 +03:00
|
|
|
ISEQ_BODY(catch_iseq)->local_table_size - arg_size,
|
|
|
|
ISEQ_BODY(catch_iseq)->stack_max);
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2010-02-10 19:46:39 +03:00
|
|
|
state = 0;
|
2017-10-28 13:35:55 +03:00
|
|
|
ec->tag->state = TAG_NONE;
|
|
|
|
ec->errinfo = Qnil;
|
mjit_compile.c: merge initial JIT compiler
which has been developed by Takashi Kokubun <takashikkbn@gmail> as
YARV-MJIT. Many of its bugs are fixed by wanabe <s.wanabe@gmail.com>.
This JIT compiler is designed to be a safe migration path to introduce
JIT compiler to MRI. So this commit does not include any bytecode
changes or dynamic instruction modifications, which are done in original
MJIT.
This commit even strips off some aggressive optimizations from
YARV-MJIT, and thus it's slower than YARV-MJIT too. But it's still
fairly faster than Ruby 2.5 in some benchmarks (attached below).
Note that this JIT compiler passes `make test`, `make test-all`, `make
test-spec` without JIT, and even with JIT. Not only it's perfectly safe
with JIT disabled because it does not replace VM instructions unlike
MJIT, but also with JIT enabled it stably runs Ruby applications
including Rails applications.
I'm expecting this version as just "initial" JIT compiler. I have many
optimization ideas which are skipped for initial merging, and you may
easily replace this JIT compiler with a faster one by just replacing
mjit_compile.c. `mjit_compile` interface is designed for the purpose.
common.mk: update dependencies for mjit_compile.c.
internal.h: declare `rb_vm_insn_addr2insn` for MJIT.
vm.c: exclude some definitions if `-DMJIT_HEADER` is provided to
compiler. This avoids to include some functions which take a long time
to compile, e.g. vm_exec_core. Some of the purpose is achieved in
transform_mjit_header.rb (see `IGNORED_FUNCTIONS`) but others are
manually resolved for now. Load mjit_helper.h for MJIT header.
mjit_helper.h: New. This is a file used only by JIT-ed code. I'll
refactor `mjit_call_cfunc` later.
vm_eval.c: add some #ifdef switches to skip compiling some functions
like Init_vm_eval.
win32/mkexports.rb: export thread/ec functions, which are used by MJIT.
include/ruby/defines.h: add MJIT_FUNC_EXPORTED macro alis to clarify
that a function is exported only for MJIT.
array.c: export a function used by MJIT.
bignum.c: ditto.
class.c: ditto.
compile.c: ditto.
error.c: ditto.
gc.c: ditto.
hash.c: ditto.
iseq.c: ditto.
numeric.c: ditto.
object.c: ditto.
proc.c: ditto.
re.c: ditto.
st.c: ditto.
string.c: ditto.
thread.c: ditto.
variable.c: ditto.
vm_backtrace.c: ditto.
vm_insnhelper.c: ditto.
vm_method.c: ditto.
I would like to improve maintainability of function exports, but I
believe this way is acceptable as initial merging if we clarify the
new exports are for MJIT (so that we can use them as TODO list to fix)
and add unit tests to detect unresolved symbols.
I'll add unit tests of JIT compilations in succeeding commits.
Author: Takashi Kokubun <takashikkbn@gmail.com>
Contributor: wanabe <s.wanabe@gmail.com>
Part of [Feature #14235]
---
* Known issues
* Code generated by gcc is faster than clang. The benchmark may be worse
in macOS. Following benchmark result is provided by gcc w/ Linux.
* Performance is decreased when Google Chrome is running
* JIT can work on MinGW, but it doesn't improve performance at least
in short running benchmark.
* Currently it doesn't perform well with Rails. We'll try to fix this
before release.
---
* Benchmark reslts
Benchmarked with:
Intel 4.0GHz i7-4790K with 16GB memory under x86-64 Ubuntu 8 Cores
- 2.0.0-p0: Ruby 2.0.0-p0
- r62186: Ruby trunk (early 2.6.0), before MJIT changes
- JIT off: On this commit, but without `--jit` option
- JIT on: On this commit, and with `--jit` option
** Optcarrot fps
Benchmark: https://github.com/mame/optcarrot
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:--------|:--------|:--------|:--------|:--------|
|fps |37.32 |51.46 |51.31 |58.88 |
|vs 2.0.0 |1.00x |1.38x |1.37x |1.58x |
** MJIT benchmarks
Benchmark: https://github.com/benchmark-driver/mjit-benchmarks
(Original: https://github.com/vnmakarov/ruby/tree/rtl_mjit_branch/MJIT-benchmarks)
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:----------|:--------|:--------|:--------|:--------|
|aread |1.00 |1.09 |1.07 |2.19 |
|aref |1.00 |1.13 |1.11 |2.22 |
|aset |1.00 |1.50 |1.45 |2.64 |
|awrite |1.00 |1.17 |1.13 |2.20 |
|call |1.00 |1.29 |1.26 |2.02 |
|const2 |1.00 |1.10 |1.10 |2.19 |
|const |1.00 |1.11 |1.10 |2.19 |
|fannk |1.00 |1.04 |1.02 |1.00 |
|fib |1.00 |1.32 |1.31 |1.84 |
|ivread |1.00 |1.13 |1.12 |2.43 |
|ivwrite |1.00 |1.23 |1.21 |2.40 |
|mandelbrot |1.00 |1.13 |1.16 |1.28 |
|meteor |1.00 |2.97 |2.92 |3.17 |
|nbody |1.00 |1.17 |1.15 |1.49 |
|nest-ntimes|1.00 |1.22 |1.20 |1.39 |
|nest-while |1.00 |1.10 |1.10 |1.37 |
|norm |1.00 |1.18 |1.16 |1.24 |
|nsvb |1.00 |1.16 |1.16 |1.17 |
|red-black |1.00 |1.02 |0.99 |1.12 |
|sieve |1.00 |1.30 |1.28 |1.62 |
|trees |1.00 |1.14 |1.13 |1.19 |
|while |1.00 |1.12 |1.11 |2.41 |
** Discourse's script/bench.rb
Benchmark: https://github.com/discourse/discourse/blob/v1.8.7/script/bench.rb
NOTE: Rails performance was somehow a little degraded with JIT for now.
We should fix this.
(At least I know opt_aref is performing badly in JIT and I have an idea
to fix it. Please wait for the fix.)
*** JIT off
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 17
75: 18
90: 22
99: 29
home_admin:
50: 21
75: 21
90: 27
99: 40
topic_admin:
50: 17
75: 18
90: 22
99: 32
categories:
50: 35
75: 41
90: 43
99: 77
home:
50: 39
75: 46
90: 49
99: 95
topic:
50: 46
75: 52
90: 56
99: 101
*** JIT on
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 19
75: 21
90: 25
99: 33
home_admin:
50: 24
75: 26
90: 30
99: 35
topic_admin:
50: 19
75: 20
90: 25
99: 30
categories:
50: 40
75: 44
90: 48
99: 76
home:
50: 42
75: 48
90: 51
99: 89
topic:
50: 49
75: 55
90: 58
99: 99
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62197 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 14:22:28 +03:00
|
|
|
|
2018-03-04 05:37:22 +03:00
|
|
|
return Qundef;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
else {
|
2023-08-25 00:32:45 +03:00
|
|
|
hook_before_rewind(ec, (cfp == escape_cfp), state, err);
|
2010-01-24 16:52:32 +03:00
|
|
|
|
2017-10-28 13:35:55 +03:00
|
|
|
if (VM_FRAME_FINISHED_P(ec->cfp)) {
|
|
|
|
rb_vm_pop_frame(ec);
|
|
|
|
ec->errinfo = (VALUE)err;
|
2018-03-04 05:37:22 +03:00
|
|
|
ec->tag = ec->tag->prev;
|
2017-10-28 13:35:55 +03:00
|
|
|
EC_JUMP_TAG(ec, state);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
* vm_core.h: remove VM_FRAME_MAGIC_FINISH (finish frame type).
Before this commit:
`finish frame' was place holder which indicates that VM loop
needs to return function.
If a C method calls a Ruby methods (a method written by Ruby),
then VM loop will be (re-)invoked. When the Ruby method returns,
then also VM loop should be escaped. `finish frame' has only
one instruction `finish', which returns VM loop function.
VM loop function executes `finish' instruction, then VM loop
function returns itself.
With such mechanism, `leave' instruction (which returns one
frame from current scope) doesn't need to check that this `leave'
should also return from VM loop function.
Strictly, one branch can be removed from `leave' instructon.
Consideration:
However, pushing the `finish frame' needs costs because
it needs several memory accesses. The number of pushing
`finish frame' is greater than I had assumed. Of course,
pushing `finish frame' consumes additional control frame.
Moreover, recent processors has good branch prediction,
with which we can ignore such trivial checking.
After this commit:
Finally, I decide to remove `finish frame' and `finish'
instruction. Some parts of VM depend on `finish frame',
so the new frame flag VM_FRAME_FLAG_FINISH is introduced.
If this frame should escape from VM function loop, then
the result of VM_FRAME_TYPE_FINISH_P(cfp) is true.
`leave' instruction checks this flag every time.
I measured performance on it. However on my environments,
it improves some benchmarks and slows some benchmarks down.
Maybe it is because of C compiler optimization parameters.
I'll re-visit here if this cause problems.
* insns.def (leave, finish): remove finish instruction.
* vm.c, vm_eval.c, vm_exec.c, vm_backtrace.c, vm_dump.c:
apply above changes.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36099 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-06-15 14:22:34 +04:00
|
|
|
else {
|
2017-10-28 13:35:55 +03:00
|
|
|
rb_vm_pop_frame(ec);
|
* vm_core.h: remove VM_FRAME_MAGIC_FINISH (finish frame type).
Before this commit:
`finish frame' was place holder which indicates that VM loop
needs to return function.
If a C method calls a Ruby methods (a method written by Ruby),
then VM loop will be (re-)invoked. When the Ruby method returns,
then also VM loop should be escaped. `finish frame' has only
one instruction `finish', which returns VM loop function.
VM loop function executes `finish' instruction, then VM loop
function returns itself.
With such mechanism, `leave' instruction (which returns one
frame from current scope) doesn't need to check that this `leave'
should also return from VM loop function.
Strictly, one branch can be removed from `leave' instructon.
Consideration:
However, pushing the `finish frame' needs costs because
it needs several memory accesses. The number of pushing
`finish frame' is greater than I had assumed. Of course,
pushing `finish frame' consumes additional control frame.
Moreover, recent processors has good branch prediction,
with which we can ignore such trivial checking.
After this commit:
Finally, I decide to remove `finish frame' and `finish'
instruction. Some parts of VM depend on `finish frame',
so the new frame flag VM_FRAME_FLAG_FINISH is introduced.
If this frame should escape from VM function loop, then
the result of VM_FRAME_TYPE_FINISH_P(cfp) is true.
`leave' instruction checks this flag every time.
I measured performance on it. However on my environments,
it improves some benchmarks and slows some benchmarks down.
Maybe it is because of C compiler optimization parameters.
I'll re-visit here if this cause problems.
* insns.def (leave, finish): remove finish instruction.
* vm.c, vm_eval.c, vm_exec.c, vm_backtrace.c, vm_dump.c:
apply above changes.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36099 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-06-15 14:22:34 +04:00
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
* this commit is a result of refactoring. only renaming functions,
moving definitions place, add/remove prototypes, deleting
unused variables and removing yarv.h.
This commit doesn't change any behavior of ruby/vm.
* yarv.h, common.mk: remove yarv.h (contents are moved to yarvcore.h).
* error.c, eval_intern.h: include yarvcore.h instead yarv.h
* rename some functions:
* debug.[ch]: debug_*() -> ruby_debug_*()
* iseq.c: iseq_*() -> rb_iseq_*(), ruby_iseq_disasm()
* iseq.c: node_name() -> ruby_node_name()
* vm.c: yarv_check_redefinition_opt_method() ->
rb_vm_check_redefinition_opt_method()
* some refactoring with checking -Wall.
* array.c: remove rb_ary_ptr() (unused) and remove unused
local variables.
* object.c: add a prototype of rb_mod_module_exec().
* eval_intern.h (ruby_cref): set it inline.
* eval_load.c (rb_load), yarvcore.c: yarv_load() -> rb_load_internal().
* parse.y: add a prototype of rb_parse_in_eval() (in eval.c).
* process.c: add a prototype of rb_thread_stop_timer_thread() (in thread.c).
* thread.c: remove raw_gets() function (unused) and fix some format
mismatch (format mismatchs have remained yet. this is todo).
* thread.c (rb_thread_wait_fd_rw): fix typo on label name.
* thread_pthread.ci: comment out codes with USE_THREAD_CACHE.
* vm.c (rb_svar, rb_backref_get, rb_backref_get,
rb_lastline_get, rb_lastline_set) : moved from yarvcore.c.
* vm.c (yarv_init_redefined_flag): add a prototype and rename
yarv_opt_method_table to vm_opt_method_table.
* vm.c (rb_thread_eval): moved from yarvcore.c.
* yarvcore.c: remove unused global variables and fix to use nsdr().
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11652 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-02-07 04:25:05 +03:00
|
|
|
|
2007-06-25 06:44:20 +04:00
|
|
|
/* misc */
|
|
|
|
|
* this commit is a result of refactoring. only renaming functions,
moving definitions place, add/remove prototypes, deleting
unused variables and removing yarv.h.
This commit doesn't change any behavior of ruby/vm.
* yarv.h, common.mk: remove yarv.h (contents are moved to yarvcore.h).
* error.c, eval_intern.h: include yarvcore.h instead yarv.h
* rename some functions:
* debug.[ch]: debug_*() -> ruby_debug_*()
* iseq.c: iseq_*() -> rb_iseq_*(), ruby_iseq_disasm()
* iseq.c: node_name() -> ruby_node_name()
* vm.c: yarv_check_redefinition_opt_method() ->
rb_vm_check_redefinition_opt_method()
* some refactoring with checking -Wall.
* array.c: remove rb_ary_ptr() (unused) and remove unused
local variables.
* object.c: add a prototype of rb_mod_module_exec().
* eval_intern.h (ruby_cref): set it inline.
* eval_load.c (rb_load), yarvcore.c: yarv_load() -> rb_load_internal().
* parse.y: add a prototype of rb_parse_in_eval() (in eval.c).
* process.c: add a prototype of rb_thread_stop_timer_thread() (in thread.c).
* thread.c: remove raw_gets() function (unused) and fix some format
mismatch (format mismatchs have remained yet. this is todo).
* thread.c (rb_thread_wait_fd_rw): fix typo on label name.
* thread_pthread.ci: comment out codes with USE_THREAD_CACHE.
* vm.c (rb_svar, rb_backref_get, rb_backref_get,
rb_lastline_get, rb_lastline_set) : moved from yarvcore.c.
* vm.c (yarv_init_redefined_flag): add a prototype and rename
yarv_opt_method_table to vm_opt_method_table.
* vm.c (rb_thread_eval): moved from yarvcore.c.
* yarvcore.c: remove unused global variables and fix to use nsdr().
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11652 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-02-07 04:25:05 +03:00
|
|
|
VALUE
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_iseq_eval(const rb_iseq_t *iseq)
|
* this commit is a result of refactoring. only renaming functions,
moving definitions place, add/remove prototypes, deleting
unused variables and removing yarv.h.
This commit doesn't change any behavior of ruby/vm.
* yarv.h, common.mk: remove yarv.h (contents are moved to yarvcore.h).
* error.c, eval_intern.h: include yarvcore.h instead yarv.h
* rename some functions:
* debug.[ch]: debug_*() -> ruby_debug_*()
* iseq.c: iseq_*() -> rb_iseq_*(), ruby_iseq_disasm()
* iseq.c: node_name() -> ruby_node_name()
* vm.c: yarv_check_redefinition_opt_method() ->
rb_vm_check_redefinition_opt_method()
* some refactoring with checking -Wall.
* array.c: remove rb_ary_ptr() (unused) and remove unused
local variables.
* object.c: add a prototype of rb_mod_module_exec().
* eval_intern.h (ruby_cref): set it inline.
* eval_load.c (rb_load), yarvcore.c: yarv_load() -> rb_load_internal().
* parse.y: add a prototype of rb_parse_in_eval() (in eval.c).
* process.c: add a prototype of rb_thread_stop_timer_thread() (in thread.c).
* thread.c: remove raw_gets() function (unused) and fix some format
mismatch (format mismatchs have remained yet. this is todo).
* thread.c (rb_thread_wait_fd_rw): fix typo on label name.
* thread_pthread.ci: comment out codes with USE_THREAD_CACHE.
* vm.c (rb_svar, rb_backref_get, rb_backref_get,
rb_lastline_get, rb_lastline_set) : moved from yarvcore.c.
* vm.c (yarv_init_redefined_flag): add a prototype and rename
yarv_opt_method_table to vm_opt_method_table.
* vm.c (rb_thread_eval): moved from yarvcore.c.
* yarvcore.c: remove unused global variables and fix to use nsdr().
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11652 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-02-07 04:25:05 +03:00
|
|
|
{
|
2017-10-28 13:35:55 +03:00
|
|
|
rb_execution_context_t *ec = GET_EC();
|
* this commit is a result of refactoring. only renaming functions,
moving definitions place, add/remove prototypes, deleting
unused variables and removing yarv.h.
This commit doesn't change any behavior of ruby/vm.
* yarv.h, common.mk: remove yarv.h (contents are moved to yarvcore.h).
* error.c, eval_intern.h: include yarvcore.h instead yarv.h
* rename some functions:
* debug.[ch]: debug_*() -> ruby_debug_*()
* iseq.c: iseq_*() -> rb_iseq_*(), ruby_iseq_disasm()
* iseq.c: node_name() -> ruby_node_name()
* vm.c: yarv_check_redefinition_opt_method() ->
rb_vm_check_redefinition_opt_method()
* some refactoring with checking -Wall.
* array.c: remove rb_ary_ptr() (unused) and remove unused
local variables.
* object.c: add a prototype of rb_mod_module_exec().
* eval_intern.h (ruby_cref): set it inline.
* eval_load.c (rb_load), yarvcore.c: yarv_load() -> rb_load_internal().
* parse.y: add a prototype of rb_parse_in_eval() (in eval.c).
* process.c: add a prototype of rb_thread_stop_timer_thread() (in thread.c).
* thread.c: remove raw_gets() function (unused) and fix some format
mismatch (format mismatchs have remained yet. this is todo).
* thread.c (rb_thread_wait_fd_rw): fix typo on label name.
* thread_pthread.ci: comment out codes with USE_THREAD_CACHE.
* vm.c (rb_svar, rb_backref_get, rb_backref_get,
rb_lastline_get, rb_lastline_set) : moved from yarvcore.c.
* vm.c (yarv_init_redefined_flag): add a prototype and rename
yarv_opt_method_table to vm_opt_method_table.
* vm.c (rb_thread_eval): moved from yarvcore.c.
* yarvcore.c: remove unused global variables and fix to use nsdr().
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11652 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-02-07 04:25:05 +03:00
|
|
|
VALUE val;
|
2017-10-28 13:35:55 +03:00
|
|
|
vm_set_top_stack(ec, iseq);
|
2023-03-15 00:00:19 +03:00
|
|
|
val = vm_exec(ec);
|
2008-12-27 04:15:56 +03:00
|
|
|
return val;
|
2009-01-05 12:54:47 +03:00
|
|
|
}
|
2008-12-27 04:15:56 +03:00
|
|
|
|
|
|
|
VALUE
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_iseq_eval_main(const rb_iseq_t *iseq)
|
2008-12-27 04:15:56 +03:00
|
|
|
{
|
2017-10-28 13:35:55 +03:00
|
|
|
rb_execution_context_t *ec = GET_EC();
|
2008-12-27 04:15:56 +03:00
|
|
|
VALUE val;
|
|
|
|
|
2017-10-28 13:35:55 +03:00
|
|
|
vm_set_main_stack(ec, iseq);
|
2023-03-15 00:00:19 +03:00
|
|
|
val = vm_exec(ec);
|
* this commit is a result of refactoring. only renaming functions,
moving definitions place, add/remove prototypes, deleting
unused variables and removing yarv.h.
This commit doesn't change any behavior of ruby/vm.
* yarv.h, common.mk: remove yarv.h (contents are moved to yarvcore.h).
* error.c, eval_intern.h: include yarvcore.h instead yarv.h
* rename some functions:
* debug.[ch]: debug_*() -> ruby_debug_*()
* iseq.c: iseq_*() -> rb_iseq_*(), ruby_iseq_disasm()
* iseq.c: node_name() -> ruby_node_name()
* vm.c: yarv_check_redefinition_opt_method() ->
rb_vm_check_redefinition_opt_method()
* some refactoring with checking -Wall.
* array.c: remove rb_ary_ptr() (unused) and remove unused
local variables.
* object.c: add a prototype of rb_mod_module_exec().
* eval_intern.h (ruby_cref): set it inline.
* eval_load.c (rb_load), yarvcore.c: yarv_load() -> rb_load_internal().
* parse.y: add a prototype of rb_parse_in_eval() (in eval.c).
* process.c: add a prototype of rb_thread_stop_timer_thread() (in thread.c).
* thread.c: remove raw_gets() function (unused) and fix some format
mismatch (format mismatchs have remained yet. this is todo).
* thread.c (rb_thread_wait_fd_rw): fix typo on label name.
* thread_pthread.ci: comment out codes with USE_THREAD_CACHE.
* vm.c (rb_svar, rb_backref_get, rb_backref_get,
rb_lastline_get, rb_lastline_set) : moved from yarvcore.c.
* vm.c (yarv_init_redefined_flag): add a prototype and rename
yarv_opt_method_table to vm_opt_method_table.
* vm.c (rb_thread_eval): moved from yarvcore.c.
* yarvcore.c: remove unused global variables and fix to use nsdr().
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11652 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-02-07 04:25:05 +03:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2007-04-25 07:50:00 +04:00
|
|
|
int
|
* vm_trace.c (tracepoint_attr_callee_id, rb_tracearg_callee_id):
add TracePoint#callee_id. [ruby-core:77241] [Feature #12747]
* cont.c, eval.c, gc.c, include/ruby/intern.h, insns.def, thread.c,
vm.c, vm_backtrace.c, vm_core.h, vm_eval.c, vm_insnhelper.c, vm_trace.c: ditto.
* test/ruby/test_settracefunc.rb: tests for above.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56593 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-11-05 16:15:27 +03:00
|
|
|
rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, ID *called_idp, VALUE *klassp)
|
2007-04-25 07:50:00 +04:00
|
|
|
{
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
|
2015-06-02 07:20:30 +03:00
|
|
|
|
2015-06-18 12:01:00 +03:00
|
|
|
if (me) {
|
2015-06-02 07:20:30 +03:00
|
|
|
if (idp) *idp = me->def->original_id;
|
* vm_trace.c (tracepoint_attr_callee_id, rb_tracearg_callee_id):
add TracePoint#callee_id. [ruby-core:77241] [Feature #12747]
* cont.c, eval.c, gc.c, include/ruby/intern.h, insns.def, thread.c,
vm.c, vm_backtrace.c, vm_core.h, vm_eval.c, vm_insnhelper.c, vm_trace.c: ditto.
* test/ruby/test_settracefunc.rb: tests for above.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56593 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-11-05 16:15:27 +03:00
|
|
|
if (called_idp) *called_idp = me->called_id;
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
if (klassp) *klassp = me->owner;
|
2015-06-18 12:01:00 +03:00
|
|
|
return TRUE;
|
2007-04-25 07:50:00 +04:00
|
|
|
}
|
2015-06-18 12:01:00 +03:00
|
|
|
else {
|
|
|
|
return FALSE;
|
2007-11-11 11:42:13 +03:00
|
|
|
}
|
2007-04-25 07:50:00 +04:00
|
|
|
}
|
|
|
|
|
2012-08-22 09:12:31 +04:00
|
|
|
int
|
2017-10-28 14:11:17 +03:00
|
|
|
rb_ec_frame_method_id_and_class(const rb_execution_context_t *ec, ID *idp, ID *called_idp, VALUE *klassp)
|
2012-08-22 09:12:31 +04:00
|
|
|
{
|
2017-10-28 14:11:17 +03:00
|
|
|
return rb_vm_control_frame_id_and_class(ec->cfp, idp, called_idp, klassp);
|
2012-08-22 09:12:31 +04:00
|
|
|
}
|
|
|
|
|
2018-12-24 05:02:47 +03:00
|
|
|
int
|
2017-12-01 15:26:40 +03:00
|
|
|
rb_frame_method_id_and_class(ID *idp, VALUE *klassp)
|
|
|
|
{
|
|
|
|
return rb_ec_frame_method_id_and_class(GET_EC(), idp, 0, klassp);
|
|
|
|
}
|
|
|
|
|
2007-06-18 12:02:30 +04:00
|
|
|
VALUE
|
2008-05-22 20:19:14 +04:00
|
|
|
rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg,
|
2016-07-28 14:02:30 +03:00
|
|
|
VALUE block_handler, VALUE filename)
|
2007-06-18 12:02:30 +04:00
|
|
|
{
|
2017-10-28 13:23:58 +03:00
|
|
|
rb_execution_context_t *ec = GET_EC();
|
|
|
|
const rb_control_frame_t *reg_cfp = ec->cfp;
|
[Universal parser] Decouple IMEMO from rb_ast_t
This patch removes the `VALUE flags` member from the `rb_ast_t` structure making `rb_ast_t` no longer an IMEMO object.
## Background
We are trying to make the Ruby parser generated from parse.y a universal parser that can be used by other implementations such as mruby.
To achieve this, it is necessary to exclude VALUE and IMEMO from parse.y, AST, and NODE.
## Summary (file by file)
- `rubyparser.h`
- Remove the `VALUE flags` member from `rb_ast_t`
- `ruby_parser.c` and `internal/ruby_parser.h`
- Use TypedData_Make_Struct VALUE which wraps `rb_ast_t` `in ast_alloc()` so that GC can manage it
- You can retrieve `rb_ast_t` from the VALUE by `rb_ruby_ast_data_get()`
- Change the return type of `rb_parser_compile_XXXX()` functions from `rb_ast_t *` to `VALUE`
- rb_ruby_ast_new() which internally `calls ast_alloc()` is to create VALUE vast outside ruby_parser.c
- `iseq.c` and `vm_core.h`
- Amend the first parameter of `rb_iseq_new_XXXX()` functions from `rb_ast_body_t *` to `VALUE`
- This keeps the VALUE of AST on the machine stack to prevent being removed by GC
- `ast.c`
- Almost all change is replacement `rb_ast_t *ast` with `VALUE vast` (sorry for the big diff)
- Fix `node_memsize()`
- Now it includes `rb_ast_local_table_link`, `tokens` and script_lines
- `compile.c`, `load.c`, `node.c`, `parse.y`, `proc.c`, `ruby.c`, `template/prelude.c.tmpl`, `vm.c` and `vm_eval.c`
- Follow-up due to the above changes
- `imemo.{c|h}`
- If an object with `imemo_ast` appears, considers it a bug
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2024-04-16 12:42:42 +03:00
|
|
|
const rb_iseq_t *iseq = rb_iseq_new(Qnil, filename, filename, Qnil, 0, ISEQ_TYPE_TOP);
|
2007-06-18 12:02:30 +04:00
|
|
|
VALUE val;
|
|
|
|
|
2017-10-28 13:23:58 +03:00
|
|
|
vm_push_frame(ec, iseq, VM_FRAME_MAGIC_TOP | VM_ENV_FLAG_LOCAL | VM_FRAME_FLAG_FINISH,
|
2016-07-28 14:02:30 +03:00
|
|
|
recv, block_handler,
|
2017-10-28 13:23:58 +03:00
|
|
|
(VALUE)vm_cref_new_toplevel(ec), /* cref or me */
|
2016-07-28 14:02:30 +03:00
|
|
|
0, reg_cfp->sp, 0, 0);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
|
2007-06-18 12:02:30 +04:00
|
|
|
val = (*func)(arg);
|
2007-06-25 00:33:04 +04:00
|
|
|
|
2017-10-28 13:23:58 +03:00
|
|
|
rb_vm_pop_frame(ec);
|
2007-06-18 12:02:30 +04:00
|
|
|
return val;
|
|
|
|
}
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
|
|
|
|
/* vm */
|
|
|
|
|
2019-04-20 04:19:47 +03:00
|
|
|
void
|
|
|
|
rb_vm_update_references(void *ptr)
|
|
|
|
{
|
|
|
|
if (ptr) {
|
|
|
|
rb_vm_t *vm = ptr;
|
2020-05-21 20:48:02 +03:00
|
|
|
|
2024-02-12 08:43:38 +03:00
|
|
|
rb_gc_update_tbl_refs(vm->ci_table);
|
2019-11-07 03:29:09 +03:00
|
|
|
rb_gc_update_tbl_refs(vm->frozen_strings);
|
2020-05-21 20:48:02 +03:00
|
|
|
vm->mark_object_ary = rb_gc_location(vm->mark_object_ary);
|
|
|
|
vm->load_path = rb_gc_location(vm->load_path);
|
|
|
|
vm->load_path_snapshot = rb_gc_location(vm->load_path_snapshot);
|
|
|
|
|
|
|
|
if (vm->load_path_check_cache) {
|
|
|
|
vm->load_path_check_cache = rb_gc_location(vm->load_path_check_cache);
|
|
|
|
}
|
|
|
|
|
|
|
|
vm->expanded_load_path = rb_gc_location(vm->expanded_load_path);
|
|
|
|
vm->loaded_features = rb_gc_location(vm->loaded_features);
|
|
|
|
vm->loaded_features_snapshot = rb_gc_location(vm->loaded_features_snapshot);
|
Do not load file with same realpath twice when requiring
This fixes issues with paths being loaded twice in certain cases
when symlinks are used.
It took me multiple attempts to get this working. My original
attempt tried to convert paths to realpaths before adding them
to $LOADED_FEATURES. Unfortunately, this doesn't work well
with the loaded feature index, which is based off load paths
and not realpaths. While I was able to get require working, I'm
fairly sure the loaded feature index was not being used as
expected, which would have significant performance implications.
Additionally, I was never able to get that approach working with
autoload when autoloading a non-realpath file. It also broke
some specs.
This takes a more conservative approach. Directly before loading the
file, if the file with the same realpath has been required, the
loading of the file is skipped. The realpaths are stored as
fstrings in a hidden hash.
When rebuilding the loaded feature index, the hash of realpaths
is also rebuilt. I'm guessing this makes rebuilding process
slower, but I don think that is a hot path. In general, modifying
loaded features is only done when reloading, and that tends to be
in non-production environments.
Change test_require_with_loaded_features_pop test to use 30 threads
and 300 iterations, instead of 4 threads and 1000 iterations.
I saw only sporadic failures with 4/1000, but consistent failures
30/300 threads. These failures were due to the fact that the
concurrent deletions from $LOADED_FEATURES in other threads can
result in rb_ary_entry returning nil when rebuilding the loaded
features index.
To avoid concurrency issues when rebuilding the loaded features
index, the building of the index itself is left alone, and
afterwards, a separate loop is done on a copy of the loaded feature
snapshot in order to rebuild the realpaths hash.
Fixes [Bug #17885]
2021-06-30 23:50:19 +03:00
|
|
|
vm->loaded_features_realpaths = rb_gc_location(vm->loaded_features_realpaths);
|
2023-04-12 22:33:16 +03:00
|
|
|
vm->loaded_features_realpath_map = rb_gc_location(vm->loaded_features_realpath_map);
|
2020-05-21 20:48:02 +03:00
|
|
|
vm->top_self = rb_gc_location(vm->top_self);
|
|
|
|
vm->orig_progname = rb_gc_location(vm->orig_progname);
|
|
|
|
|
2021-12-21 08:06:02 +03:00
|
|
|
rb_gc_update_tbl_refs(vm->overloaded_cme_table);
|
|
|
|
|
2023-08-31 17:35:56 +03:00
|
|
|
rb_gc_update_values(RUBY_NSIG, vm->trap_list.cmd);
|
|
|
|
|
2020-05-21 20:48:02 +03:00
|
|
|
if (vm->coverages) {
|
|
|
|
vm->coverages = rb_gc_location(vm->coverages);
|
2021-10-25 14:00:51 +03:00
|
|
|
vm->me2counter = rb_gc_location(vm->me2counter);
|
2020-05-21 20:48:02 +03:00
|
|
|
}
|
2019-04-20 04:19:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-03 01:40:29 +03:00
|
|
|
void
|
|
|
|
rb_vm_each_stack_value(void *ptr, void (*cb)(VALUE, void*), void *ctx)
|
|
|
|
{
|
|
|
|
if (ptr) {
|
|
|
|
rb_vm_t *vm = ptr;
|
|
|
|
rb_ractor_t *r = 0;
|
2022-03-30 10:36:31 +03:00
|
|
|
ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
|
2020-11-03 01:40:29 +03:00
|
|
|
VM_ASSERT(rb_ractor_status_p(r, ractor_blocking) ||
|
|
|
|
rb_ractor_status_p(r, ractor_running));
|
|
|
|
if (r->threads.cnt > 0) {
|
|
|
|
rb_thread_t *th = 0;
|
2022-03-30 10:36:31 +03:00
|
|
|
ccan_list_for_each(&r->threads.set, th, lt_node) {
|
2020-11-03 01:40:29 +03:00
|
|
|
VM_ASSERT(th != NULL);
|
|
|
|
rb_execution_context_t * ec = th->ec;
|
|
|
|
if (ec->vm_stack) {
|
|
|
|
VALUE *p = ec->vm_stack;
|
|
|
|
VALUE *sp = ec->cfp->sp;
|
2023-01-06 22:19:00 +03:00
|
|
|
while (p < sp) {
|
2024-02-27 23:09:18 +03:00
|
|
|
if (!RB_SPECIAL_CONST_P(*p)) {
|
2020-11-03 01:40:29 +03:00
|
|
|
cb(*p, ctx);
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-12 23:55:18 +03:00
|
|
|
static enum rb_id_table_iterator_result
|
|
|
|
vm_mark_negative_cme(VALUE val, void *dmy)
|
|
|
|
{
|
|
|
|
rb_gc_mark(val);
|
|
|
|
return ID_TABLE_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2023-04-10 04:53:13 +03:00
|
|
|
void rb_thread_sched_mark_zombies(rb_vm_t *vm);
|
|
|
|
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
void
|
2008-05-22 20:19:14 +04:00
|
|
|
rb_vm_mark(void *ptr)
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
{
|
|
|
|
RUBY_MARK_ENTER("vm");
|
|
|
|
RUBY_GC_INFO("-------------------------------------------------\n");
|
|
|
|
if (ptr) {
|
|
|
|
rb_vm_t *vm = ptr;
|
2020-09-04 05:46:50 +03:00
|
|
|
rb_ractor_t *r = 0;
|
2024-03-03 12:46:46 +03:00
|
|
|
long i;
|
2014-05-28 05:48:11 +04:00
|
|
|
|
2022-03-30 10:36:31 +03:00
|
|
|
ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
|
2020-03-09 20:22:11 +03:00
|
|
|
// ractor.set only contains blocking or running ractors
|
|
|
|
VM_ASSERT(rb_ractor_status_p(r, ractor_blocking) ||
|
|
|
|
rb_ractor_status_p(r, ractor_running));
|
|
|
|
rb_gc_mark(rb_ractor_self(r));
|
|
|
|
}
|
|
|
|
|
2024-03-14 20:52:20 +03:00
|
|
|
for (struct global_object_list *list = vm->global_object_list; list; list = list->next) {
|
2024-03-13 20:58:03 +03:00
|
|
|
rb_gc_mark_maybe(*list->varptr);
|
|
|
|
}
|
|
|
|
|
2020-05-21 20:48:02 +03:00
|
|
|
rb_gc_mark_movable(vm->mark_object_ary);
|
|
|
|
rb_gc_mark_movable(vm->load_path);
|
|
|
|
rb_gc_mark_movable(vm->load_path_snapshot);
|
2024-03-07 00:43:00 +03:00
|
|
|
rb_gc_mark_movable(vm->load_path_check_cache);
|
2020-05-21 20:48:02 +03:00
|
|
|
rb_gc_mark_movable(vm->expanded_load_path);
|
|
|
|
rb_gc_mark_movable(vm->loaded_features);
|
|
|
|
rb_gc_mark_movable(vm->loaded_features_snapshot);
|
Do not load file with same realpath twice when requiring
This fixes issues with paths being loaded twice in certain cases
when symlinks are used.
It took me multiple attempts to get this working. My original
attempt tried to convert paths to realpaths before adding them
to $LOADED_FEATURES. Unfortunately, this doesn't work well
with the loaded feature index, which is based off load paths
and not realpaths. While I was able to get require working, I'm
fairly sure the loaded feature index was not being used as
expected, which would have significant performance implications.
Additionally, I was never able to get that approach working with
autoload when autoloading a non-realpath file. It also broke
some specs.
This takes a more conservative approach. Directly before loading the
file, if the file with the same realpath has been required, the
loading of the file is skipped. The realpaths are stored as
fstrings in a hidden hash.
When rebuilding the loaded feature index, the hash of realpaths
is also rebuilt. I'm guessing this makes rebuilding process
slower, but I don think that is a hot path. In general, modifying
loaded features is only done when reloading, and that tends to be
in non-production environments.
Change test_require_with_loaded_features_pop test to use 30 threads
and 300 iterations, instead of 4 threads and 1000 iterations.
I saw only sporadic failures with 4/1000, but consistent failures
30/300 threads. These failures were due to the fact that the
concurrent deletions from $LOADED_FEATURES in other threads can
result in rb_ary_entry returning nil when rebuilding the loaded
features index.
To avoid concurrency issues when rebuilding the loaded features
index, the building of the index itself is left alone, and
afterwards, a separate loop is done on a copy of the loaded feature
snapshot in order to rebuild the realpaths hash.
Fixes [Bug #17885]
2021-06-30 23:50:19 +03:00
|
|
|
rb_gc_mark_movable(vm->loaded_features_realpaths);
|
2023-04-12 22:33:16 +03:00
|
|
|
rb_gc_mark_movable(vm->loaded_features_realpath_map);
|
2020-05-21 20:48:02 +03:00
|
|
|
rb_gc_mark_movable(vm->top_self);
|
|
|
|
rb_gc_mark_movable(vm->orig_progname);
|
2024-03-07 00:43:00 +03:00
|
|
|
rb_gc_mark_movable(vm->coverages);
|
|
|
|
rb_gc_mark_movable(vm->me2counter);
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
|
|
|
|
if (vm->loading_table) {
|
|
|
|
rb_mark_tbl(vm->loading_table);
|
|
|
|
}
|
|
|
|
|
2021-12-21 08:06:02 +03:00
|
|
|
rb_gc_mark_values(RUBY_NSIG, vm->trap_list.cmd);
|
mjit.c: merge MJIT infrastructure
that allows to JIT-compile Ruby methods by generating C code and
using C compiler. See the first comment of mjit.c to know what this
file does.
mjit.c is authored by Vladimir Makarov <vmakarov@redhat.com>.
After he invented great method JIT infrastructure for MRI as MJIT,
Lars Kanis <lars@greiz-reinsdorf.de> sent the patch to support MinGW
in MJIT. In addition to merging it, I ported pthread to Windows native
threads. Now this MJIT infrastructure can be compiled on Visual Studio.
This commit simplifies mjit.c to decrease code at initial merge. For
example, this commit does not provide multiple JIT threads support.
We can resurrect them later if we really want them, but I wanted to minimize
diff to make it easier to review this patch.
`/tmp/_mjitXXX` file is renamed to `/tmp/_ruby_mjitXXX` because non-Ruby
developers may not know the name "mjit" and the file name should make
sure it's from Ruby and not from some harmful programs. TODO: it may be
better to store this to some temporary directory which Ruby is already using
by Tempfile, if it's not bad for performance.
mjit.h: New. It has `mjit_exec` interface similar to `vm_exec`, which is
for triggering MJIT. This drops interface for AOT compared to the original
MJIT.
Makefile.in: define macros to let MJIT know the path of MJIT header.
Probably we can refactor this to reduce the number of macros (TODO).
win32/Makefile.sub: ditto.
common.mk: compile mjit.o and mjit_compile.o. Unlike original MJIT, this
commit separates MJIT infrastructure and JIT compiler code as independent
object files. As initial patch is NOT going to have ultra-fast JIT compiler,
it's likely to replace JIT compiler, e.g. original MJIT's compiler or some
future JIT impelementations which are not public now.
inits.c: define MJIT module. This is added because `MJIT.enabled?` was
necessary for testing.
test/lib/zombie_hunter.rb: skip if `MJIT.enabled?`. Obviously this
wouldn't work with current code when JIT is enabled.
test/ruby/test_io.rb: skip this too. This would make no sense with MJIT.
ruby.c: define MJIT CLI options. As major difference from original MJIT,
"-j:l"/"--jit:llvm" are renamed to "--jit-cc" because I want to support
not only gcc/clang but also cl.exe (Visual Studio) in the future. But it
takes only "--jit-cc=gcc", "--jit-cc=clang" for now. And only long "--jit"
options are allowed since some Ruby committers preferred it at Ruby
developers Meeting on January, and some of options are renamed.
This file also triggers to initialize MJIT thread and variables.
eval.c: finalize MJIT worker thread and variables.
test/ruby/test_rubyoptions.rb: fix number of CLI options for --jit.
thread_pthread.c: change for pthread abstraction in MJIT. Prefix rb_ for
functions which are used by other files.
thread_win32.c: ditto, for Windows. Those pthread porting is one of major
works that YARV-MJIT created, which is my fork of MJIT, in Feature 14235.
thread.c: follow rb_ prefix changes
vm.c: trigger MJIT call on VM invocation. Also trigger `mjit_mark` to avoid
SEGV by race between JIT and GC of ISeq. The improvement was provided by
wanabe <s.wanabe@gmail.com>.
In JIT compiler I created and am going to add in my next commit, I found
that having `mjit_exec` after `vm_loop_start:` is harmful because the
JIT-ed function doesn't proceed other ISeqs on RESTORE_REGS of leave insn.
Executing non-FINISH frame is unexpected for my JIT compiler and
`exception_handler` triggers executions of such ISeqs. So `mjit_exec`
here should be executed only when it directly comes from `vm_exec` call.
`RubyVM::MJIT` module and `.enabled?` method is added so that we can skip
some tests which don't expect JIT threads or compiler file descriptors.
vm_insnhelper.h: trigger MJIT on method calls during VM execution.
vm_core.h: add fields required for mjit.c. `bp` must be `cfp[6]` because
rb_control_frame_struct is likely to be casted to another struct. The
last position is the safest place to add the new field.
vm_insnhelper.c: save initial value of cfp->ep as cfp->bp. This is an
optimization which are done in both MJIT and YARV-MJIT. So this change
is added in this commit. Calculating bp from ep is a little heavy work,
so bp is kind of cache for it.
iseq.c: notify ISeq GC to MJIT. We should know which iseq in MJIT queue
is GCed to avoid SEGV. TODO: unload some GCed units in some safe way.
gc.c: add hooks so that MJIT can wait GC, and vice versa. Simultaneous
JIT and GC executions may cause SEGV and so we should synchronize them.
cont.c: save continuation information in MJIT worker. As MJIT shouldn't
unload JIT-ed code which is being used, MJIT wants to know full list of
saved execution contexts for continuation and detect ISeqs in use.
mjit_compile.c: added empty JIT compiler so that you can reuse this commit
to build your own JIT compiler. This commit tries to compile ISeqs but
all of them are considered as not supported in this commit. So you can't
use JIT compiler in this commit yet while we added --jit option now.
Patch author: Vladimir Makarov <vmakarov@redhat.com>.
Contributors:
Takashi Kokubun <takashikkbn@gmail.com>.
wanabe <s.wanabe@gmail.com>.
Lars Kanis <lars@greiz-reinsdorf.de>.
Part of Feature 12589 and 14235.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62189 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 09:58:09 +03:00
|
|
|
|
2020-12-12 23:55:18 +03:00
|
|
|
rb_id_table_foreach_values(vm->negative_cme_table, vm_mark_negative_cme, NULL);
|
2021-12-21 08:06:02 +03:00
|
|
|
rb_mark_tbl_no_pin(vm->overloaded_cme_table);
|
2021-01-20 21:33:59 +03:00
|
|
|
for (i=0; i<VM_GLOBAL_CC_CACHE_TABLE_SIZE; i++) {
|
|
|
|
const struct rb_callcache *cc = vm->global_cc_cache_table[i];
|
|
|
|
|
|
|
|
if (cc != NULL) {
|
|
|
|
if (!vm_cc_invalidated_p(cc)) {
|
|
|
|
rb_gc_mark((VALUE)cc);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
vm->global_cc_cache_table[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-12-21 09:41:52 +03:00
|
|
|
|
2023-04-10 04:53:13 +03:00
|
|
|
rb_thread_sched_mark_zombies(vm);
|
2023-03-09 10:14:33 +03:00
|
|
|
rb_rjit_mark();
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
RUBY_MARK_LEAVE("vm");
|
|
|
|
}
|
|
|
|
|
2017-04-09 07:01:07 +03:00
|
|
|
#undef rb_vm_register_special_exception
|
2014-09-11 14:53:48 +04:00
|
|
|
void
|
2017-04-09 07:01:07 +03:00
|
|
|
rb_vm_register_special_exception_str(enum ruby_special_exceptions sp, VALUE cls, VALUE mesg)
|
2014-09-11 14:53:48 +04:00
|
|
|
{
|
|
|
|
rb_vm_t *vm = GET_VM();
|
2017-04-09 07:01:07 +03:00
|
|
|
VALUE exc = rb_exc_new3(cls, rb_obj_freeze(mesg));
|
2014-09-11 14:53:48 +04:00
|
|
|
OBJ_FREEZE(exc);
|
|
|
|
((VALUE *)vm->special_exceptions)[sp] = exc;
|
2024-03-03 12:46:46 +03:00
|
|
|
rb_vm_register_global_object(exc);
|
2013-10-11 22:27:18 +04:00
|
|
|
}
|
|
|
|
|
2015-12-12 12:00:27 +03:00
|
|
|
static int
|
|
|
|
free_loading_table_entry(st_data_t key, st_data_t value, st_data_t arg)
|
|
|
|
{
|
|
|
|
xfree((char *)key);
|
|
|
|
return ST_DELETE;
|
|
|
|
}
|
|
|
|
|
2023-10-12 21:15:53 +03:00
|
|
|
void rb_free_loaded_features_index(rb_vm_t *vm);
|
|
|
|
void rb_objspace_free_objects(void *objspace);
|
|
|
|
|
2009-09-18 11:29:17 +04:00
|
|
|
int
|
2010-10-13 14:28:25 +04:00
|
|
|
ruby_vm_destruct(rb_vm_t *vm)
|
2009-06-17 02:23:53 +04:00
|
|
|
{
|
|
|
|
RUBY_FREE_ENTER("vm");
|
2014-06-02 12:17:55 +04:00
|
|
|
|
2010-10-13 14:28:25 +04:00
|
|
|
if (vm) {
|
2020-03-09 20:22:11 +03:00
|
|
|
rb_thread_t *th = vm->ractor.main_thread;
|
2023-10-12 21:15:53 +03:00
|
|
|
VALUE *stack = th->ec->vm_stack;
|
2023-12-20 08:12:18 +03:00
|
|
|
if (rb_free_at_exit) {
|
2023-10-12 21:15:53 +03:00
|
|
|
rb_free_encoded_insn_data();
|
|
|
|
rb_free_global_enc_table();
|
|
|
|
rb_free_loaded_builtin_table();
|
|
|
|
|
|
|
|
rb_free_shared_fiber_pool();
|
|
|
|
rb_free_static_symid_str();
|
|
|
|
rb_free_transcoder_table();
|
|
|
|
rb_free_vm_opt_tables();
|
|
|
|
rb_free_warning();
|
|
|
|
rb_free_rb_global_tbl();
|
|
|
|
rb_free_loaded_features_index(vm);
|
|
|
|
|
|
|
|
rb_id_table_free(vm->negative_cme_table);
|
|
|
|
st_free_table(vm->overloaded_cme_table);
|
|
|
|
|
|
|
|
rb_id_table_free(RCLASS(rb_mRubyVMFrozenCore)->m_tbl);
|
|
|
|
|
|
|
|
rb_shape_t *cursor = rb_shape_get_root_shape();
|
|
|
|
rb_shape_t *end = rb_shape_get_shape_by_id(GET_SHAPE_TREE()->next_shape_id);
|
|
|
|
while (cursor < end) {
|
|
|
|
// 0x1 == SINGLE_CHILD_P
|
|
|
|
if (cursor->edges && !(((uintptr_t)cursor->edges) & 0x1))
|
|
|
|
rb_id_table_free(cursor->edges);
|
|
|
|
cursor += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
xfree(GET_SHAPE_TREE());
|
|
|
|
|
|
|
|
st_free_table(vm->static_ext_inits);
|
|
|
|
|
Change the semantics of rb_postponed_job_register
Our current implementation of rb_postponed_job_register suffers from
some safety issues that can lead to interpreter crashes (see bug #1991).
Essentially, the issue is that jobs can be called with the wrong
arguments.
We made two attempts to fix this whilst keeping the promised semantics,
but:
* The first one involved masking/unmasking when flushing jobs, which
was believed to be too expensive
* The second one involved a lock-free, multi-producer, single-consumer
ringbuffer, which was too complex
The critical insight behind this third solution is that essentially the
only user of these APIs are a) internal, or b) profiling gems.
For a), none of the usages actually require variable data; they will
work just fine with the preregistration interface.
For b), generally profiling gems only call a single callback with a
single piece of data (which is actually usually just zero) for the life
of the program. The ringbuffer is complex because it needs to support
multi-word inserts of job & data (which can't be atomic); but nobody
actually even needs that functionality, really.
So, this comit:
* Introduces a pre-registration API for jobs, with a GVL-requiring
rb_postponed_job_prereigster, which returns a handle which can be
used with an async-signal-safe rb_postponed_job_trigger.
* Deprecates rb_postponed_job_register (and re-implements it on top of
the preregister function for compatability)
* Moves all the internal usages of postponed job register
pre-registration
2023-11-19 14:54:57 +03:00
|
|
|
rb_vm_postponed_job_free();
|
2020-03-09 20:22:11 +03:00
|
|
|
|
2023-10-12 21:15:53 +03:00
|
|
|
rb_id_table_free(vm->constant_cache);
|
2024-04-30 00:42:00 +03:00
|
|
|
st_free_table(vm->unused_block_warning_table);
|
2024-01-03 17:53:55 +03:00
|
|
|
|
|
|
|
if (th) {
|
|
|
|
xfree(th->nt);
|
|
|
|
th->nt = NULL;
|
|
|
|
}
|
2024-01-09 21:17:17 +03:00
|
|
|
|
|
|
|
#ifndef HAVE_SETPROCTITLE
|
|
|
|
ruby_free_proctitle();
|
|
|
|
#endif
|
2009-09-18 11:29:17 +04:00
|
|
|
}
|
2023-10-12 21:15:53 +03:00
|
|
|
else {
|
|
|
|
if (th) {
|
|
|
|
rb_fiber_reset_root_local_storage(th);
|
|
|
|
thread_free(th);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-30 20:05:24 +03:00
|
|
|
struct rb_objspace *objspace = vm->gc.objspace;
|
2023-10-12 21:15:53 +03:00
|
|
|
|
vm*: doubly-linked list from ccan to manage vm->living_threads
A doubly-linked list for tracking living threads guarantees
constant-time insert/delete performance with no corner cases of a
hash table. I chose this ccan implementation of doubly-linked
lists over the BSD sys/queue.h implementation since:
1) insertion and removal are both branchless
2) locality is improved if a struct may be a member of multiple lists
(0002 patch in Feature 9632 will introduce a secondary list
for waiting FDs)
This also increases cache locality during iteration: improving
performance in a new IO#close benchmark with many sleeping threads
while still scanning the same number of threads.
vm_thread_close 1.762
* vm_core.h (rb_vm_t): list_head and counter for living_threads
(rb_thread_t): vmlt_node for living_threads linkage
(rb_vm_living_threads_init): new function wrapper
(rb_vm_living_threads_insert): ditto
(rb_vm_living_threads_remove): ditto
* vm.c (rb_vm_living_threads_foreach): new function wrapper
* thread.c (terminate_i, thread_start_func_2, thread_create_core,
thread_fd_close_i, thread_fd_close): update to use new APIs
* vm.c (vm_mark_each_thread_func, rb_vm_mark, ruby_vm_destruct,
vm_memsize, vm_init2, Init_VM): ditto
* vm_trace.c (clear_trace_func_i, rb_clear_trace_func): ditto
* benchmark/bm_vm_thread_close.rb: added to show improvement
* ccan/build_assert/build_assert.h: added as a dependency of list.h
* ccan/check_type/check_type.h: ditto
* ccan/container_of/container_of.h: ditto
* ccan/licenses/BSD-MIT: ditto
* ccan/licenses/CC0: ditto
* ccan/str/str.h: ditto (stripped of unused macros)
* ccan/list/list.h: ditto
* common.mk: add CCAN_LIST_INCLUDES
[ruby-core:61871][Feature 9632 (part 1)]
Apologies for the size of this commit, but I think a good
doubly-linked list will be useful for future features, too.
This may be used to add ordering to a container_of-based hash
table to preserve compatibility if required (e.g. feature 9614).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@45913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2014-05-11 03:48:51 +04:00
|
|
|
rb_vm_living_threads_init(vm);
|
2013-11-22 05:38:08 +04:00
|
|
|
ruby_vm_run_at_exit_hooks(vm);
|
2015-12-12 12:00:27 +03:00
|
|
|
if (vm->loading_table) {
|
|
|
|
st_foreach(vm->loading_table, free_loading_table_entry, 0);
|
|
|
|
st_free_table(vm->loading_table);
|
|
|
|
vm->loading_table = 0;
|
|
|
|
}
|
2024-02-12 08:43:38 +03:00
|
|
|
if (vm->ci_table) {
|
|
|
|
st_free_table(vm->ci_table);
|
|
|
|
vm->ci_table = NULL;
|
|
|
|
}
|
2015-12-12 12:00:27 +03:00
|
|
|
if (vm->frozen_strings) {
|
|
|
|
st_free_table(vm->frozen_strings);
|
|
|
|
vm->frozen_strings = 0;
|
|
|
|
}
|
2018-04-21 00:38:27 +03:00
|
|
|
RB_ALTSTACK_FREE(vm->main_altstack);
|
2024-03-13 20:58:03 +03:00
|
|
|
|
|
|
|
struct global_object_list *next;
|
2024-03-14 20:52:20 +03:00
|
|
|
for (struct global_object_list *list = vm->global_object_list; list; list = next) {
|
2024-03-13 20:58:03 +03:00
|
|
|
next = list->next;
|
|
|
|
xfree(list);
|
|
|
|
}
|
|
|
|
|
2009-09-18 11:29:17 +04:00
|
|
|
if (objspace) {
|
2023-12-20 08:12:18 +03:00
|
|
|
if (rb_free_at_exit) {
|
2023-10-12 21:15:53 +03:00
|
|
|
rb_objspace_free_objects(objspace);
|
|
|
|
rb_free_generic_iv_tbl_();
|
2023-12-22 23:15:07 +03:00
|
|
|
rb_free_default_rand_key();
|
2023-12-22 23:15:22 +03:00
|
|
|
if (th && vm->fork_gen == 0) {
|
|
|
|
/* If we have forked, main_thread may not be the initial thread */
|
2023-10-12 21:15:53 +03:00
|
|
|
xfree(stack);
|
|
|
|
ruby_mimfree(th);
|
|
|
|
}
|
|
|
|
}
|
2009-09-18 11:29:17 +04:00
|
|
|
rb_objspace_free(objspace);
|
|
|
|
}
|
2021-02-19 05:40:37 +03:00
|
|
|
rb_native_mutex_destroy(&vm->workqueue_lock);
|
2013-11-22 05:38:08 +04:00
|
|
|
/* after freeing objspace, you *can't* use ruby_xfree() */
|
|
|
|
ruby_mimfree(vm);
|
2017-10-26 11:32:49 +03:00
|
|
|
ruby_current_vm_ptr = NULL;
|
2009-06-17 02:23:53 +04:00
|
|
|
}
|
|
|
|
RUBY_FREE_LEAVE("vm");
|
2009-09-18 11:29:17 +04:00
|
|
|
return 0;
|
2009-06-17 02:23:53 +04:00
|
|
|
}
|
|
|
|
|
2022-03-30 10:36:31 +03:00
|
|
|
size_t rb_vm_memsize_waiting_fds(struct ccan_list_head *waiting_fds); // thread.c
|
|
|
|
size_t rb_vm_memsize_workqueue(struct ccan_list_head *workqueue); // vm_trace.c
|
2022-01-11 20:47:22 +03:00
|
|
|
|
|
|
|
// Used for VM memsize reporting. Returns the size of the at_exit list by
|
|
|
|
// looping through the linked list and adding up the size of the structs.
|
2022-03-31 18:04:25 +03:00
|
|
|
static enum rb_id_table_iterator_result
|
|
|
|
vm_memsize_constant_cache_i(ID id, VALUE ics, void *size)
|
|
|
|
{
|
|
|
|
*((size_t *) size) += rb_st_memsize((st_table *) ics);
|
|
|
|
return ID_TABLE_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a size_t representing the memory footprint of the VM's constant
|
|
|
|
// cache, which is the memsize of the table as well as the memsize of all of the
|
|
|
|
// nested tables.
|
|
|
|
static size_t
|
|
|
|
vm_memsize_constant_cache(void)
|
|
|
|
{
|
|
|
|
rb_vm_t *vm = GET_VM();
|
|
|
|
size_t size = rb_id_table_memsize(vm->constant_cache);
|
|
|
|
|
|
|
|
rb_id_table_foreach(vm->constant_cache, vm_memsize_constant_cache_i, &size);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2009-06-17 02:23:53 +04:00
|
|
|
static size_t
|
2022-01-11 20:47:22 +03:00
|
|
|
vm_memsize_at_exit_list(rb_at_exit_list *at_exit)
|
2009-06-17 02:23:53 +04:00
|
|
|
{
|
2022-01-11 20:47:22 +03:00
|
|
|
size_t size = 0;
|
vm*: doubly-linked list from ccan to manage vm->living_threads
A doubly-linked list for tracking living threads guarantees
constant-time insert/delete performance with no corner cases of a
hash table. I chose this ccan implementation of doubly-linked
lists over the BSD sys/queue.h implementation since:
1) insertion and removal are both branchless
2) locality is improved if a struct may be a member of multiple lists
(0002 patch in Feature 9632 will introduce a secondary list
for waiting FDs)
This also increases cache locality during iteration: improving
performance in a new IO#close benchmark with many sleeping threads
while still scanning the same number of threads.
vm_thread_close 1.762
* vm_core.h (rb_vm_t): list_head and counter for living_threads
(rb_thread_t): vmlt_node for living_threads linkage
(rb_vm_living_threads_init): new function wrapper
(rb_vm_living_threads_insert): ditto
(rb_vm_living_threads_remove): ditto
* vm.c (rb_vm_living_threads_foreach): new function wrapper
* thread.c (terminate_i, thread_start_func_2, thread_create_core,
thread_fd_close_i, thread_fd_close): update to use new APIs
* vm.c (vm_mark_each_thread_func, rb_vm_mark, ruby_vm_destruct,
vm_memsize, vm_init2, Init_VM): ditto
* vm_trace.c (clear_trace_func_i, rb_clear_trace_func): ditto
* benchmark/bm_vm_thread_close.rb: added to show improvement
* ccan/build_assert/build_assert.h: added as a dependency of list.h
* ccan/check_type/check_type.h: ditto
* ccan/container_of/container_of.h: ditto
* ccan/licenses/BSD-MIT: ditto
* ccan/licenses/CC0: ditto
* ccan/str/str.h: ditto (stripped of unused macros)
* ccan/list/list.h: ditto
* common.mk: add CCAN_LIST_INCLUDES
[ruby-core:61871][Feature 9632 (part 1)]
Apologies for the size of this commit, but I think a good
doubly-linked list will be useful for future features, too.
This may be used to add ordering to a container_of-based hash
table to preserve compatibility if required (e.g. feature 9614).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@45913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2014-05-11 03:48:51 +04:00
|
|
|
|
2022-01-11 20:47:22 +03:00
|
|
|
while (at_exit) {
|
|
|
|
size += sizeof(rb_at_exit_list);
|
|
|
|
at_exit = at_exit->next;
|
|
|
|
}
|
vm*: doubly-linked list from ccan to manage vm->living_threads
A doubly-linked list for tracking living threads guarantees
constant-time insert/delete performance with no corner cases of a
hash table. I chose this ccan implementation of doubly-linked
lists over the BSD sys/queue.h implementation since:
1) insertion and removal are both branchless
2) locality is improved if a struct may be a member of multiple lists
(0002 patch in Feature 9632 will introduce a secondary list
for waiting FDs)
This also increases cache locality during iteration: improving
performance in a new IO#close benchmark with many sleeping threads
while still scanning the same number of threads.
vm_thread_close 1.762
* vm_core.h (rb_vm_t): list_head and counter for living_threads
(rb_thread_t): vmlt_node for living_threads linkage
(rb_vm_living_threads_init): new function wrapper
(rb_vm_living_threads_insert): ditto
(rb_vm_living_threads_remove): ditto
* vm.c (rb_vm_living_threads_foreach): new function wrapper
* thread.c (terminate_i, thread_start_func_2, thread_create_core,
thread_fd_close_i, thread_fd_close): update to use new APIs
* vm.c (vm_mark_each_thread_func, rb_vm_mark, ruby_vm_destruct,
vm_memsize, vm_init2, Init_VM): ditto
* vm_trace.c (clear_trace_func_i, rb_clear_trace_func): ditto
* benchmark/bm_vm_thread_close.rb: added to show improvement
* ccan/build_assert/build_assert.h: added as a dependency of list.h
* ccan/check_type/check_type.h: ditto
* ccan/container_of/container_of.h: ditto
* ccan/licenses/BSD-MIT: ditto
* ccan/licenses/CC0: ditto
* ccan/str/str.h: ditto (stripped of unused macros)
* ccan/list/list.h: ditto
* common.mk: add CCAN_LIST_INCLUDES
[ruby-core:61871][Feature 9632 (part 1)]
Apologies for the size of this commit, but I think a good
doubly-linked list will be useful for future features, too.
This may be used to add ordering to a container_of-based hash
table to preserve compatibility if required (e.g. feature 9614).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@45913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2014-05-11 03:48:51 +04:00
|
|
|
|
2015-12-09 03:38:32 +03:00
|
|
|
return size;
|
2009-06-17 02:23:53 +04:00
|
|
|
}
|
|
|
|
|
2022-01-11 20:47:22 +03:00
|
|
|
// Used for VM memsize reporting. Returns the size of the builtin function
|
|
|
|
// table if it has been defined.
|
|
|
|
static size_t
|
|
|
|
vm_memsize_builtin_function_table(const struct rb_builtin_function *builtin_function_table)
|
|
|
|
{
|
|
|
|
return builtin_function_table == NULL ? 0 : sizeof(struct rb_builtin_function);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reports the memsize of the VM struct object and the structs that are
|
|
|
|
// associated with it.
|
|
|
|
static size_t
|
|
|
|
vm_memsize(const void *ptr)
|
|
|
|
{
|
|
|
|
rb_vm_t *vm = GET_VM();
|
|
|
|
|
|
|
|
return (
|
|
|
|
sizeof(rb_vm_t) +
|
|
|
|
rb_vm_memsize_waiting_fds(&vm->waiting_fds) +
|
|
|
|
rb_st_memsize(vm->loaded_features_index) +
|
|
|
|
rb_st_memsize(vm->loading_table) +
|
Change the semantics of rb_postponed_job_register
Our current implementation of rb_postponed_job_register suffers from
some safety issues that can lead to interpreter crashes (see bug #1991).
Essentially, the issue is that jobs can be called with the wrong
arguments.
We made two attempts to fix this whilst keeping the promised semantics,
but:
* The first one involved masking/unmasking when flushing jobs, which
was believed to be too expensive
* The second one involved a lock-free, multi-producer, single-consumer
ringbuffer, which was too complex
The critical insight behind this third solution is that essentially the
only user of these APIs are a) internal, or b) profiling gems.
For a), none of the usages actually require variable data; they will
work just fine with the preregistration interface.
For b), generally profiling gems only call a single callback with a
single piece of data (which is actually usually just zero) for the life
of the program. The ringbuffer is complex because it needs to support
multi-word inserts of job & data (which can't be atomic); but nobody
actually even needs that functionality, really.
So, this comit:
* Introduces a pre-registration API for jobs, with a GVL-requiring
rb_postponed_job_prereigster, which returns a handle which can be
used with an async-signal-safe rb_postponed_job_trigger.
* Deprecates rb_postponed_job_register (and re-implements it on top of
the preregister function for compatability)
* Moves all the internal usages of postponed job register
pre-registration
2023-11-19 14:54:57 +03:00
|
|
|
rb_vm_memsize_postponed_job_queue() +
|
2022-01-11 20:47:22 +03:00
|
|
|
rb_vm_memsize_workqueue(&vm->workqueue) +
|
|
|
|
vm_memsize_at_exit_list(vm->at_exit) +
|
2024-02-12 08:43:38 +03:00
|
|
|
rb_st_memsize(vm->ci_table) +
|
2022-01-11 20:47:22 +03:00
|
|
|
rb_st_memsize(vm->frozen_strings) +
|
|
|
|
vm_memsize_builtin_function_table(vm->builtin_function_table) +
|
|
|
|
rb_id_table_memsize(vm->negative_cme_table) +
|
2022-03-31 18:04:25 +03:00
|
|
|
rb_st_memsize(vm->overloaded_cme_table) +
|
2023-02-08 04:46:42 +03:00
|
|
|
vm_memsize_constant_cache() +
|
|
|
|
GET_SHAPE_TREE()->cache_size * sizeof(redblack_node_t)
|
2022-01-11 20:47:22 +03:00
|
|
|
);
|
|
|
|
|
|
|
|
// TODO
|
2022-03-30 10:36:31 +03:00
|
|
|
// struct { struct ccan_list_head set; } ractor;
|
2022-01-11 20:47:22 +03:00
|
|
|
// void *main_altstack; #ifdef USE_SIGALTSTACK
|
|
|
|
// struct rb_objspace *objspace;
|
|
|
|
}
|
|
|
|
|
2009-07-07 10:23:39 +04:00
|
|
|
static const rb_data_type_t vm_data_type = {
|
2009-06-17 02:23:53 +04:00
|
|
|
"VM",
|
2020-02-07 08:14:05 +03:00
|
|
|
{0, 0, vm_memsize,},
|
2014-12-01 09:38:04 +03:00
|
|
|
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
2009-06-17 02:23:53 +04:00
|
|
|
};
|
|
|
|
|
2012-12-20 02:29:18 +04:00
|
|
|
|
|
|
|
static VALUE
|
|
|
|
vm_default_params(void)
|
|
|
|
{
|
|
|
|
rb_vm_t *vm = GET_VM();
|
2019-10-22 01:49:54 +03:00
|
|
|
VALUE result = rb_hash_new_with_size(4);
|
2012-12-20 02:29:18 +04:00
|
|
|
#define SET(name) rb_hash_aset(result, ID2SYM(rb_intern(#name)), SIZET2NUM(vm->default_params.name));
|
|
|
|
SET(thread_vm_stack_size);
|
|
|
|
SET(thread_machine_stack_size);
|
|
|
|
SET(fiber_vm_stack_size);
|
|
|
|
SET(fiber_machine_stack_size);
|
|
|
|
#undef SET
|
|
|
|
rb_obj_freeze(result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t
|
|
|
|
get_param(const char *name, size_t default_value, size_t min_value)
|
|
|
|
{
|
|
|
|
const char *envval;
|
|
|
|
size_t result = default_value;
|
|
|
|
if ((envval = getenv(name)) != 0) {
|
|
|
|
long val = atol(envval);
|
|
|
|
if (val < (long)min_value) {
|
|
|
|
val = (long)min_value;
|
|
|
|
}
|
|
|
|
result = (size_t)(((val -1 + RUBY_VM_SIZE_ALIGN) / RUBY_VM_SIZE_ALIGN) * RUBY_VM_SIZE_ALIGN);
|
|
|
|
}
|
2021-09-09 17:21:06 +03:00
|
|
|
if (0) ruby_debug_printf("%s: %"PRIuSIZE"\n", name, result); /* debug print */
|
2012-12-20 02:29:18 +04:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
check_machine_stack_size(size_t *sizep)
|
|
|
|
{
|
2012-12-28 07:03:19 +04:00
|
|
|
#ifdef PTHREAD_STACK_MIN
|
2012-12-20 02:29:18 +04:00
|
|
|
size_t size = *sizep;
|
2012-12-28 07:03:19 +04:00
|
|
|
#endif
|
|
|
|
|
2012-12-20 02:29:18 +04:00
|
|
|
#ifdef PTHREAD_STACK_MIN
|
2021-10-22 19:43:00 +03:00
|
|
|
if (size < (size_t)PTHREAD_STACK_MIN) {
|
|
|
|
*sizep = (size_t)PTHREAD_STACK_MIN * 2;
|
2012-12-20 02:29:18 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vm_default_params_setup(rb_vm_t *vm)
|
|
|
|
{
|
|
|
|
vm->default_params.thread_vm_stack_size =
|
|
|
|
get_param("RUBY_THREAD_VM_STACK_SIZE",
|
|
|
|
RUBY_VM_THREAD_VM_STACK_SIZE,
|
|
|
|
RUBY_VM_THREAD_VM_STACK_SIZE_MIN);
|
|
|
|
|
|
|
|
vm->default_params.thread_machine_stack_size =
|
|
|
|
get_param("RUBY_THREAD_MACHINE_STACK_SIZE",
|
|
|
|
RUBY_VM_THREAD_MACHINE_STACK_SIZE,
|
|
|
|
RUBY_VM_THREAD_MACHINE_STACK_SIZE_MIN);
|
|
|
|
|
|
|
|
vm->default_params.fiber_vm_stack_size =
|
|
|
|
get_param("RUBY_FIBER_VM_STACK_SIZE",
|
|
|
|
RUBY_VM_FIBER_VM_STACK_SIZE,
|
|
|
|
RUBY_VM_FIBER_VM_STACK_SIZE_MIN);
|
|
|
|
|
|
|
|
vm->default_params.fiber_machine_stack_size =
|
|
|
|
get_param("RUBY_FIBER_MACHINE_STACK_SIZE",
|
|
|
|
RUBY_VM_FIBER_MACHINE_STACK_SIZE,
|
|
|
|
RUBY_VM_FIBER_MACHINE_STACK_SIZE_MIN);
|
|
|
|
|
|
|
|
/* environment dependent check */
|
|
|
|
check_machine_stack_size(&vm->default_params.thread_machine_stack_size);
|
|
|
|
check_machine_stack_size(&vm->default_params.fiber_machine_stack_size);
|
|
|
|
}
|
|
|
|
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
static void
|
2008-05-22 20:19:14 +04:00
|
|
|
vm_init2(rb_vm_t *vm)
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
{
|
vm*: doubly-linked list from ccan to manage vm->living_threads
A doubly-linked list for tracking living threads guarantees
constant-time insert/delete performance with no corner cases of a
hash table. I chose this ccan implementation of doubly-linked
lists over the BSD sys/queue.h implementation since:
1) insertion and removal are both branchless
2) locality is improved if a struct may be a member of multiple lists
(0002 patch in Feature 9632 will introduce a secondary list
for waiting FDs)
This also increases cache locality during iteration: improving
performance in a new IO#close benchmark with many sleeping threads
while still scanning the same number of threads.
vm_thread_close 1.762
* vm_core.h (rb_vm_t): list_head and counter for living_threads
(rb_thread_t): vmlt_node for living_threads linkage
(rb_vm_living_threads_init): new function wrapper
(rb_vm_living_threads_insert): ditto
(rb_vm_living_threads_remove): ditto
* vm.c (rb_vm_living_threads_foreach): new function wrapper
* thread.c (terminate_i, thread_start_func_2, thread_create_core,
thread_fd_close_i, thread_fd_close): update to use new APIs
* vm.c (vm_mark_each_thread_func, rb_vm_mark, ruby_vm_destruct,
vm_memsize, vm_init2, Init_VM): ditto
* vm_trace.c (clear_trace_func_i, rb_clear_trace_func): ditto
* benchmark/bm_vm_thread_close.rb: added to show improvement
* ccan/build_assert/build_assert.h: added as a dependency of list.h
* ccan/check_type/check_type.h: ditto
* ccan/container_of/container_of.h: ditto
* ccan/licenses/BSD-MIT: ditto
* ccan/licenses/CC0: ditto
* ccan/str/str.h: ditto (stripped of unused macros)
* ccan/list/list.h: ditto
* common.mk: add CCAN_LIST_INCLUDES
[ruby-core:61871][Feature 9632 (part 1)]
Apologies for the size of this commit, but I think a good
doubly-linked list will be useful for future features, too.
This may be used to add ordering to a container_of-based hash
table to preserve compatibility if required (e.g. feature 9614).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@45913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2014-05-11 03:48:51 +04:00
|
|
|
rb_vm_living_threads_init(vm);
|
2017-12-12 21:43:42 +03:00
|
|
|
vm->thread_report_on_exception = 1;
|
2008-06-09 08:20:07 +04:00
|
|
|
vm->src_encoding_index = -1;
|
2012-12-20 02:29:18 +04:00
|
|
|
|
|
|
|
vm_default_params_setup(vm);
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
}
|
|
|
|
|
2019-05-31 23:25:24 +03:00
|
|
|
void
|
2022-12-01 13:00:33 +03:00
|
|
|
rb_execution_context_update(rb_execution_context_t *ec)
|
2019-05-31 23:25:24 +03:00
|
|
|
{
|
|
|
|
/* update VM stack */
|
|
|
|
if (ec->vm_stack) {
|
2020-05-12 22:00:35 +03:00
|
|
|
long i;
|
2019-07-19 05:54:31 +03:00
|
|
|
VM_ASSERT(ec->cfp);
|
2020-05-12 22:00:35 +03:00
|
|
|
VALUE *p = ec->vm_stack;
|
|
|
|
VALUE *sp = ec->cfp->sp;
|
2019-06-11 19:16:45 +03:00
|
|
|
rb_control_frame_t *cfp = ec->cfp;
|
|
|
|
rb_control_frame_t *limit_cfp = (void *)(ec->vm_stack + ec->vm_stack_size);
|
2019-05-31 23:25:24 +03:00
|
|
|
|
2020-05-12 22:00:35 +03:00
|
|
|
for (i = 0; i < (long)(sp - p); i++) {
|
|
|
|
VALUE ref = p[i];
|
|
|
|
VALUE update = rb_gc_location(ref);
|
|
|
|
if (ref != update) {
|
|
|
|
p[i] = update;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-11 19:16:45 +03:00
|
|
|
while (cfp != limit_cfp) {
|
|
|
|
const VALUE *ep = cfp->ep;
|
2019-05-31 23:25:24 +03:00
|
|
|
cfp->self = rb_gc_location(cfp->self);
|
|
|
|
cfp->iseq = (rb_iseq_t *)rb_gc_location((VALUE)cfp->iseq);
|
|
|
|
cfp->block_code = (void *)rb_gc_location((VALUE)cfp->block_code);
|
|
|
|
|
2020-12-01 00:28:24 +03:00
|
|
|
if (!VM_ENV_LOCAL_P(ep)) {
|
2021-02-11 23:32:19 +03:00
|
|
|
const VALUE *prev_ep = VM_ENV_PREV_EP(ep);
|
|
|
|
if (VM_ENV_FLAGS(prev_ep, VM_ENV_FLAG_ESCAPED)) {
|
|
|
|
VM_FORCE_WRITE(&prev_ep[VM_ENV_DATA_INDEX_ENV], rb_gc_location(prev_ep[VM_ENV_DATA_INDEX_ENV]));
|
|
|
|
}
|
|
|
|
|
2020-05-21 20:48:02 +03:00
|
|
|
if (VM_ENV_FLAGS(ep, VM_ENV_FLAG_ESCAPED)) {
|
|
|
|
VM_FORCE_WRITE(&ep[VM_ENV_DATA_INDEX_ENV], rb_gc_location(ep[VM_ENV_DATA_INDEX_ENV]));
|
|
|
|
VM_FORCE_WRITE(&ep[VM_ENV_DATA_INDEX_ME_CREF], rb_gc_location(ep[VM_ENV_DATA_INDEX_ME_CREF]));
|
2019-06-11 19:16:45 +03:00
|
|
|
}
|
|
|
|
}
|
2019-05-31 23:25:24 +03:00
|
|
|
|
2019-06-11 19:16:45 +03:00
|
|
|
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
|
|
|
}
|
2019-05-31 23:25:24 +03:00
|
|
|
}
|
2022-12-01 13:00:33 +03:00
|
|
|
|
|
|
|
ec->storage = rb_gc_location(ec->storage);
|
2019-05-31 23:25:24 +03:00
|
|
|
}
|
|
|
|
|
2020-01-04 03:45:58 +03:00
|
|
|
static enum rb_id_table_iterator_result
|
|
|
|
mark_local_storage_i(VALUE local, void *data)
|
|
|
|
{
|
|
|
|
rb_gc_mark(local);
|
|
|
|
return ID_TABLE_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2017-09-10 22:00:08 +03:00
|
|
|
void
|
2017-09-06 05:46:59 +03:00
|
|
|
rb_execution_context_mark(const rb_execution_context_t *ec)
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
{
|
2017-06-12 10:58:23 +03:00
|
|
|
/* mark VM stack */
|
2019-06-20 04:41:18 +03:00
|
|
|
if (ec->vm_stack) {
|
2019-07-19 05:54:31 +03:00
|
|
|
VM_ASSERT(ec->cfp);
|
2017-09-06 05:46:59 +03:00
|
|
|
VALUE *p = ec->vm_stack;
|
|
|
|
VALUE *sp = ec->cfp->sp;
|
|
|
|
rb_control_frame_t *cfp = ec->cfp;
|
|
|
|
rb_control_frame_t *limit_cfp = (void *)(ec->vm_stack + ec->vm_stack_size);
|
2015-07-15 11:29:22 +03:00
|
|
|
|
2020-03-09 20:22:11 +03:00
|
|
|
VM_ASSERT(sp == ec->cfp->sp);
|
2019-05-14 18:18:43 +03:00
|
|
|
rb_gc_mark_vm_stack_values((long)(sp - p), p);
|
2015-07-15 11:29:22 +03:00
|
|
|
|
|
|
|
while (cfp != limit_cfp) {
|
2016-07-28 14:02:30 +03:00
|
|
|
const VALUE *ep = cfp->ep;
|
2017-09-06 06:39:26 +03:00
|
|
|
VM_ASSERT(!!VM_ENV_FLAGS(ep, VM_ENV_FLAG_ESCAPED) == vm_ep_in_heap_p_(ec, ep));
|
2016-07-28 14:02:30 +03:00
|
|
|
|
2022-10-17 11:50:42 +03:00
|
|
|
if (VM_FRAME_TYPE(cfp) != VM_FRAME_MAGIC_DUMMY) {
|
|
|
|
rb_gc_mark_movable(cfp->self);
|
|
|
|
rb_gc_mark_movable((VALUE)cfp->iseq);
|
|
|
|
rb_gc_mark_movable((VALUE)cfp->block_code);
|
2021-02-11 23:32:19 +03:00
|
|
|
|
2022-10-17 11:50:42 +03:00
|
|
|
if (!VM_ENV_LOCAL_P(ep)) {
|
|
|
|
const VALUE *prev_ep = VM_ENV_PREV_EP(ep);
|
|
|
|
if (VM_ENV_FLAGS(prev_ep, VM_ENV_FLAG_ESCAPED)) {
|
|
|
|
rb_gc_mark_movable(prev_ep[VM_ENV_DATA_INDEX_ENV]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VM_ENV_FLAGS(ep, VM_ENV_FLAG_ESCAPED)) {
|
|
|
|
rb_gc_mark_movable(ep[VM_ENV_DATA_INDEX_ENV]);
|
|
|
|
rb_gc_mark(ep[VM_ENV_DATA_INDEX_ME_CREF]);
|
|
|
|
}
|
2018-01-08 18:27:56 +03:00
|
|
|
}
|
2020-05-21 20:48:02 +03:00
|
|
|
}
|
2018-01-08 18:27:56 +03:00
|
|
|
|
2015-07-15 11:29:22 +03:00
|
|
|
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
}
|
2015-07-15 11:29:22 +03:00
|
|
|
}
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
|
2017-09-10 18:49:45 +03:00
|
|
|
/* mark machine stack */
|
2017-10-28 08:36:48 +03:00
|
|
|
if (ec->machine.stack_start && ec->machine.stack_end &&
|
|
|
|
ec != GET_EC() /* marked for current ec at the first stage of marking */
|
|
|
|
) {
|
2024-02-24 11:32:17 +03:00
|
|
|
rb_gc_mark_machine_context(ec);
|
2017-09-10 18:49:45 +03:00
|
|
|
}
|
|
|
|
|
2024-03-07 00:43:00 +03:00
|
|
|
rb_gc_mark(ec->errinfo);
|
|
|
|
rb_gc_mark(ec->root_svar);
|
2020-01-04 03:45:58 +03:00
|
|
|
if (ec->local_storage) {
|
|
|
|
rb_id_table_foreach_values(ec->local_storage, mark_local_storage_i, NULL);
|
|
|
|
}
|
2024-03-07 00:43:00 +03:00
|
|
|
rb_gc_mark(ec->local_storage_recursive_hash);
|
|
|
|
rb_gc_mark(ec->local_storage_recursive_hash_for_trace);
|
|
|
|
rb_gc_mark(ec->private_const_reference);
|
2022-12-01 13:00:33 +03:00
|
|
|
|
2024-03-07 00:43:00 +03:00
|
|
|
rb_gc_mark_movable(ec->storage);
|
2017-09-06 05:46:59 +03:00
|
|
|
}
|
|
|
|
|
2017-10-26 11:32:49 +03:00
|
|
|
void rb_fiber_mark_self(rb_fiber_t *fib);
|
2019-05-31 23:25:24 +03:00
|
|
|
void rb_fiber_update_self(rb_fiber_t *fib);
|
2018-04-04 11:19:28 +03:00
|
|
|
void rb_threadptr_root_fiber_setup(rb_thread_t *th);
|
2017-10-26 17:21:31 +03:00
|
|
|
void rb_threadptr_root_fiber_release(rb_thread_t *th);
|
2017-10-26 11:32:49 +03:00
|
|
|
|
2019-05-31 23:25:24 +03:00
|
|
|
static void
|
|
|
|
thread_compact(void *ptr)
|
|
|
|
{
|
|
|
|
rb_thread_t *th = ptr;
|
|
|
|
|
2020-10-02 04:13:26 +03:00
|
|
|
th->self = rb_gc_location(th->self);
|
|
|
|
|
2020-09-25 19:18:12 +03:00
|
|
|
if (!th->root_fiber) {
|
|
|
|
rb_execution_context_update(th->ec);
|
|
|
|
}
|
2019-05-31 23:25:24 +03:00
|
|
|
}
|
|
|
|
|
2017-11-16 10:28:16 +03:00
|
|
|
static void
|
|
|
|
thread_mark(void *ptr)
|
2017-09-06 05:46:59 +03:00
|
|
|
{
|
|
|
|
rb_thread_t *th = ptr;
|
|
|
|
RUBY_MARK_ENTER("thread");
|
2017-11-06 08:41:48 +03:00
|
|
|
rb_fiber_mark_self(th->ec->fiber_ptr);
|
2017-09-06 05:46:59 +03:00
|
|
|
|
2015-07-15 11:29:22 +03:00
|
|
|
/* mark ruby objects */
|
2018-11-08 08:01:23 +03:00
|
|
|
switch (th->invoke_type) {
|
|
|
|
case thread_invoke_type_proc:
|
2020-03-09 20:22:11 +03:00
|
|
|
case thread_invoke_type_ractor_proc:
|
2024-03-07 00:43:00 +03:00
|
|
|
rb_gc_mark(th->invoke_arg.proc.proc);
|
|
|
|
rb_gc_mark(th->invoke_arg.proc.args);
|
2018-11-08 08:01:23 +03:00
|
|
|
break;
|
|
|
|
case thread_invoke_type_func:
|
|
|
|
rb_gc_mark_maybe((VALUE)th->invoke_arg.func.arg);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2015-07-15 11:29:22 +03:00
|
|
|
|
2020-03-09 20:22:11 +03:00
|
|
|
rb_gc_mark(rb_ractor_self(th->ractor));
|
2024-03-07 00:43:00 +03:00
|
|
|
rb_gc_mark(th->thgroup);
|
|
|
|
rb_gc_mark(th->value);
|
|
|
|
rb_gc_mark(th->pending_interrupt_queue);
|
|
|
|
rb_gc_mark(th->pending_interrupt_mask_stack);
|
|
|
|
rb_gc_mark(th->top_self);
|
|
|
|
rb_gc_mark(th->top_wrapper);
|
2017-10-26 17:21:31 +03:00
|
|
|
if (th->root_fiber) rb_fiber_mark_self(th->root_fiber);
|
2019-04-23 03:14:36 +03:00
|
|
|
|
2022-07-13 02:42:14 +03:00
|
|
|
RUBY_ASSERT(th->ec == rb_fiberptr_get_ec(th->ec->fiber_ptr));
|
2024-03-07 00:43:00 +03:00
|
|
|
rb_gc_mark(th->stat_insn_usage);
|
|
|
|
rb_gc_mark(th->last_status);
|
|
|
|
rb_gc_mark(th->locking_mutex);
|
|
|
|
rb_gc_mark(th->name);
|
2015-07-15 11:29:22 +03:00
|
|
|
|
2024-03-07 00:43:00 +03:00
|
|
|
rb_gc_mark(th->scheduler);
|
2020-05-14 13:10:55 +03:00
|
|
|
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
RUBY_MARK_LEAVE("thread");
|
|
|
|
}
|
|
|
|
|
2023-04-10 04:53:13 +03:00
|
|
|
void rb_threadptr_sched_free(rb_thread_t *th); // thread_*.c
|
|
|
|
|
2009-06-17 02:23:53 +04:00
|
|
|
static void
|
|
|
|
thread_free(void *ptr)
|
|
|
|
{
|
2017-03-17 22:59:56 +03:00
|
|
|
rb_thread_t *th = ptr;
|
2009-06-17 02:23:53 +04:00
|
|
|
RUBY_FREE_ENTER("thread");
|
|
|
|
|
2023-04-10 04:53:13 +03:00
|
|
|
rb_threadptr_sched_free(th);
|
|
|
|
|
2017-03-17 22:59:56 +03:00
|
|
|
if (th->locking_mutex != Qfalse) {
|
|
|
|
rb_bug("thread_free: locking_mutex must be NULL (%p:%p)", (void *)th, (void *)th->locking_mutex);
|
|
|
|
}
|
|
|
|
if (th->keeping_mutexes != NULL) {
|
|
|
|
rb_bug("thread_free: keeping_mutexes must be NULL (%p:%p)", (void *)th, (void *)th->keeping_mutexes);
|
|
|
|
}
|
2009-06-17 02:23:53 +04:00
|
|
|
|
2024-01-17 23:55:08 +03:00
|
|
|
ruby_xfree(th->specific_storage);
|
2023-11-16 20:29:11 +03:00
|
|
|
|
2019-06-05 09:23:04 +03:00
|
|
|
rb_threadptr_root_fiber_release(th);
|
2017-10-26 11:32:49 +03:00
|
|
|
|
2020-03-09 20:22:11 +03:00
|
|
|
if (th->vm && th->vm->ractor.main_thread == th) {
|
|
|
|
RUBY_GC_INFO("MRI main thread\n");
|
2017-03-17 22:59:56 +03:00
|
|
|
}
|
|
|
|
else {
|
2023-04-10 04:53:13 +03:00
|
|
|
// ruby_xfree(th->nt);
|
|
|
|
// TODO: MN system collect nt, but without MN system it should be freed here.
|
2022-04-22 15:19:03 +03:00
|
|
|
ruby_xfree(th);
|
2009-06-17 02:23:53 +04:00
|
|
|
}
|
2017-03-17 22:59:56 +03:00
|
|
|
|
2009-06-17 02:23:53 +04:00
|
|
|
RUBY_FREE_LEAVE("thread");
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t
|
2009-09-09 06:11:35 +04:00
|
|
|
thread_memsize(const void *ptr)
|
2009-06-17 02:23:53 +04:00
|
|
|
{
|
2015-12-09 03:38:32 +03:00
|
|
|
const rb_thread_t *th = ptr;
|
|
|
|
size_t size = sizeof(rb_thread_t);
|
2009-06-17 02:23:53 +04:00
|
|
|
|
2015-12-09 03:38:32 +03:00
|
|
|
if (!th->root_fiber) {
|
2017-10-26 11:32:49 +03:00
|
|
|
size += th->ec->vm_stack_size * sizeof(VALUE);
|
2009-06-17 02:23:53 +04:00
|
|
|
}
|
2017-10-26 11:32:49 +03:00
|
|
|
if (th->ec->local_storage) {
|
2020-01-04 03:45:58 +03:00
|
|
|
size += rb_id_table_memsize(th->ec->local_storage);
|
2009-06-17 02:23:53 +04:00
|
|
|
}
|
2015-12-09 03:38:32 +03:00
|
|
|
return size;
|
2009-06-17 02:23:53 +04:00
|
|
|
}
|
|
|
|
|
2011-08-16 13:56:56 +04:00
|
|
|
#define thread_data_type ruby_threadptr_data_type
|
|
|
|
const rb_data_type_t ruby_threadptr_data_type = {
|
2009-06-17 02:23:53 +04:00
|
|
|
"VM/thread",
|
2010-07-18 11:31:54 +04:00
|
|
|
{
|
2017-11-16 10:28:16 +03:00
|
|
|
thread_mark,
|
2010-07-18 11:31:54 +04:00
|
|
|
thread_free,
|
|
|
|
thread_memsize,
|
2019-06-11 19:16:45 +03:00
|
|
|
thread_compact,
|
2010-07-18 11:31:54 +04:00
|
|
|
},
|
2014-12-01 09:38:04 +03:00
|
|
|
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
2009-06-17 02:23:53 +04:00
|
|
|
};
|
|
|
|
|
2011-06-09 18:45:56 +04:00
|
|
|
VALUE
|
|
|
|
rb_obj_is_thread(VALUE obj)
|
|
|
|
{
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL(rb_typeddata_is_kind_of(obj, &thread_data_type));
|
2011-06-09 18:45:56 +04:00
|
|
|
}
|
|
|
|
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
static VALUE
|
2008-05-22 20:19:14 +04:00
|
|
|
thread_alloc(VALUE klass)
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
{
|
|
|
|
rb_thread_t *th;
|
2022-04-22 15:19:03 +03:00
|
|
|
return TypedData_Make_Struct(klass, rb_thread_t, &thread_data_type, th);
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
}
|
|
|
|
|
2019-06-20 02:31:22 +03:00
|
|
|
inline void
|
|
|
|
rb_ec_set_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t size)
|
|
|
|
{
|
|
|
|
ec->vm_stack = stack;
|
|
|
|
ec->vm_stack_size = size;
|
|
|
|
}
|
|
|
|
|
2019-06-19 09:47:15 +03:00
|
|
|
void
|
|
|
|
rb_ec_initialize_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t size)
|
|
|
|
{
|
2019-06-20 02:31:22 +03:00
|
|
|
rb_ec_set_vm_stack(ec, stack, size);
|
|
|
|
|
2024-03-16 00:00:24 +03:00
|
|
|
#if VM_CHECK_MODE > 0
|
|
|
|
MEMZERO(stack, VALUE, size); // malloc memory could have the VM canary in it
|
|
|
|
#endif
|
|
|
|
|
2019-06-20 02:31:22 +03:00
|
|
|
ec->cfp = (void *)(ec->vm_stack + ec->vm_stack_size);
|
2019-06-19 09:47:15 +03:00
|
|
|
|
2019-07-19 02:00:58 +03:00
|
|
|
vm_push_frame(ec,
|
2019-06-20 02:31:22 +03:00
|
|
|
NULL /* dummy iseq */,
|
|
|
|
VM_FRAME_MAGIC_DUMMY | VM_ENV_FLAG_LOCAL | VM_FRAME_FLAG_FINISH | VM_FRAME_FLAG_CFRAME /* dummy frame */,
|
|
|
|
Qnil /* dummy self */, VM_BLOCK_HANDLER_NONE /* dummy block ptr */,
|
|
|
|
0 /* dummy cref/me */,
|
|
|
|
0 /* dummy pc */, ec->vm_stack, 0, 0
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_ec_clear_vm_stack(rb_execution_context_t *ec)
|
|
|
|
{
|
|
|
|
rb_ec_set_vm_stack(ec, NULL, 0);
|
2019-06-19 09:47:15 +03:00
|
|
|
|
2019-06-20 02:31:22 +03:00
|
|
|
// Avoid dangling pointers:
|
2019-07-19 06:45:44 +03:00
|
|
|
ec->cfp = NULL;
|
2019-06-19 09:47:15 +03:00
|
|
|
}
|
|
|
|
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
static void
|
2022-05-20 10:04:10 +03:00
|
|
|
th_init(rb_thread_t *th, VALUE self, rb_vm_t *vm)
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
{
|
2008-06-14 06:59:19 +04:00
|
|
|
th->self = self;
|
2022-04-22 16:58:15 +03:00
|
|
|
|
2018-04-04 11:19:28 +03:00
|
|
|
rb_threadptr_root_fiber_setup(th);
|
2008-06-14 06:59:19 +04:00
|
|
|
|
2020-05-14 13:10:55 +03:00
|
|
|
/* All threads are blocking until a non-blocking fiber is scheduled */
|
|
|
|
th->blocking = 1;
|
|
|
|
th->scheduler = Qnil;
|
|
|
|
|
2019-06-05 02:18:50 +03:00
|
|
|
if (self == 0) {
|
2022-04-22 16:58:15 +03:00
|
|
|
size_t size = vm->default_params.thread_vm_stack_size / sizeof(VALUE);
|
2019-06-19 09:47:15 +03:00
|
|
|
rb_ec_initialize_vm_stack(th->ec, ALLOC_N(VALUE, size), size);
|
2019-06-19 14:40:49 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
VM_ASSERT(th->ec->cfp == NULL);
|
|
|
|
VM_ASSERT(th->ec->vm_stack == NULL);
|
|
|
|
VM_ASSERT(th->ec->vm_stack_size == 0);
|
2017-10-26 11:32:49 +03:00
|
|
|
}
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
|
|
|
|
th->status = THREAD_RUNNABLE;
|
2008-07-10 07:10:00 +04:00
|
|
|
th->last_status = Qnil;
|
2022-04-22 16:58:15 +03:00
|
|
|
th->top_wrapper = 0;
|
|
|
|
th->top_self = vm->top_self; // 0 while self == 0
|
|
|
|
th->value = Qundef;
|
|
|
|
|
|
|
|
th->ec->errinfo = Qnil;
|
|
|
|
th->ec->root_svar = Qfalse;
|
|
|
|
th->ec->local_storage_recursive_hash = Qnil;
|
|
|
|
th->ec->local_storage_recursive_hash_for_trace = Qnil;
|
2021-07-28 10:55:55 +03:00
|
|
|
|
2022-12-01 13:00:33 +03:00
|
|
|
th->ec->storage = Qnil;
|
|
|
|
|
2012-08-07 15:13:57 +04:00
|
|
|
#if OPT_CALL_THREADED_CODE
|
|
|
|
th->retval = Qundef;
|
|
|
|
#endif
|
2015-06-13 11:39:30 +03:00
|
|
|
th->name = Qnil;
|
2022-04-22 16:58:15 +03:00
|
|
|
th->report_on_exception = vm->thread_report_on_exception;
|
2020-11-30 10:18:43 +03:00
|
|
|
th->ext_config.ractor_safe = true;
|
2022-05-20 09:47:20 +03:00
|
|
|
|
|
|
|
#if USE_RUBY_DEBUG_LOG
|
2023-04-10 04:53:13 +03:00
|
|
|
static rb_atomic_t thread_serial = 1;
|
2022-05-20 09:47:20 +03:00
|
|
|
th->serial = RUBY_ATOMIC_FETCH_ADD(thread_serial, 1);
|
2023-04-10 04:53:13 +03:00
|
|
|
|
|
|
|
RUBY_DEBUG_LOG("th:%u", th->serial);
|
2022-05-20 09:47:20 +03:00
|
|
|
#endif
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
2008-05-22 20:19:14 +04:00
|
|
|
rb_thread_alloc(VALUE klass)
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
{
|
|
|
|
VALUE self = thread_alloc(klass);
|
2022-04-22 16:58:15 +03:00
|
|
|
rb_thread_t *target_th = rb_thread_ptr(self);
|
2022-05-20 10:04:10 +03:00
|
|
|
target_th->ractor = GET_RACTOR();
|
|
|
|
th_init(target_th, self, target_th->vm = GET_VM());
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2008-08-13 08:49:37 +04:00
|
|
|
#define REWIND_CFP(expr) do { \
|
2017-10-28 14:02:16 +03:00
|
|
|
rb_execution_context_t *ec__ = GET_EC(); \
|
|
|
|
VALUE *const curr_sp = (ec__->cfp++)->sp; \
|
|
|
|
VALUE *const saved_sp = ec__->cfp->sp; \
|
|
|
|
ec__->cfp->sp = curr_sp; \
|
2015-07-16 08:34:27 +03:00
|
|
|
expr; \
|
2017-10-28 14:02:16 +03:00
|
|
|
(ec__->cfp--)->sp = saved_sp; \
|
2008-08-13 08:49:37 +04:00
|
|
|
} while (0)
|
|
|
|
|
2008-07-01 16:19:00 +04:00
|
|
|
static VALUE
|
2008-08-13 08:49:37 +04:00
|
|
|
m_core_set_method_alias(VALUE self, VALUE cbase, VALUE sym1, VALUE sym2)
|
2008-07-01 16:19:00 +04:00
|
|
|
{
|
2008-08-13 08:49:37 +04:00
|
|
|
REWIND_CFP({
|
|
|
|
rb_alias(cbase, SYM2ID(sym1), SYM2ID(sym2));
|
|
|
|
});
|
|
|
|
return Qnil;
|
|
|
|
}
|
2008-07-01 16:19:00 +04:00
|
|
|
|
2008-08-13 08:49:37 +04:00
|
|
|
static VALUE
|
|
|
|
m_core_set_variable_alias(VALUE self, VALUE sym1, VALUE sym2)
|
|
|
|
{
|
|
|
|
REWIND_CFP({
|
|
|
|
rb_alias_variable(SYM2ID(sym1), SYM2ID(sym2));
|
|
|
|
});
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
m_core_undef_method(VALUE self, VALUE cbase, VALUE sym)
|
|
|
|
{
|
|
|
|
REWIND_CFP({
|
2020-01-08 10:14:01 +03:00
|
|
|
ID mid = SYM2ID(sym);
|
|
|
|
rb_undef(cbase, mid);
|
|
|
|
rb_clear_method_cache(self, mid);
|
2008-08-13 08:49:37 +04:00
|
|
|
});
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2013-08-22 10:50:42 +04:00
|
|
|
m_core_set_postexe(VALUE self)
|
2008-08-13 08:49:37 +04:00
|
|
|
{
|
2013-08-22 10:50:42 +04:00
|
|
|
rb_set_end_proc(rb_call_end_proc, rb_block_proc());
|
2008-07-01 16:19:00 +04:00
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2018-07-04 02:56:11 +03:00
|
|
|
static VALUE core_hash_merge_kwd(VALUE hash, VALUE kw);
|
2014-03-24 19:28:30 +04:00
|
|
|
|
2014-03-24 19:28:31 +04:00
|
|
|
static VALUE
|
|
|
|
core_hash_merge(VALUE hash, long argc, const VALUE *argv)
|
|
|
|
{
|
2016-12-08 09:19:06 +03:00
|
|
|
Check_Type(hash, T_HASH);
|
2017-04-24 04:40:51 +03:00
|
|
|
VM_ASSERT(argc % 2 == 0);
|
2017-04-27 07:21:04 +03:00
|
|
|
rb_hash_bulk_insert(argc, argv, hash);
|
2014-03-24 19:28:31 +04:00
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
2012-04-12 05:33:34 +04:00
|
|
|
static VALUE
|
|
|
|
m_core_hash_merge_ptr(int argc, VALUE *argv, VALUE recv)
|
|
|
|
{
|
|
|
|
VALUE hash = argv[0];
|
2015-07-16 08:34:27 +03:00
|
|
|
|
2019-03-18 08:25:47 +03:00
|
|
|
REWIND_CFP(hash = core_hash_merge(hash, argc-1, argv+1));
|
2012-04-12 05:33:34 +04:00
|
|
|
|
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
2012-04-29 01:12:05 +04:00
|
|
|
static int
|
|
|
|
kwmerge_i(VALUE key, VALUE value, VALUE hash)
|
|
|
|
{
|
2014-10-11 08:46:56 +04:00
|
|
|
rb_hash_aset(hash, key, value);
|
2012-04-29 01:12:05 +04:00
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2018-07-04 02:56:11 +03:00
|
|
|
m_core_hash_merge_kwd(VALUE recv, VALUE hash, VALUE kw)
|
2014-05-21 10:11:25 +04:00
|
|
|
{
|
2024-01-14 22:41:02 +03:00
|
|
|
if (!NIL_P(kw)) {
|
|
|
|
REWIND_CFP(hash = core_hash_merge_kwd(hash, kw));
|
|
|
|
}
|
2014-05-21 10:11:25 +04:00
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
2020-10-20 11:28:12 +03:00
|
|
|
static VALUE
|
|
|
|
m_core_make_shareable(VALUE recv, VALUE obj)
|
|
|
|
{
|
2020-10-21 08:11:18 +03:00
|
|
|
return rb_ractor_make_shareable(obj);
|
2020-10-20 11:28:12 +03:00
|
|
|
}
|
|
|
|
|
2020-12-24 04:59:27 +03:00
|
|
|
static VALUE
|
|
|
|
m_core_make_shareable_copy(VALUE recv, VALUE obj)
|
|
|
|
{
|
|
|
|
return rb_ractor_make_shareable_copy(obj);
|
|
|
|
}
|
|
|
|
|
2020-12-19 14:42:58 +03:00
|
|
|
static VALUE
|
|
|
|
m_core_ensure_shareable(VALUE recv, VALUE obj, VALUE name)
|
|
|
|
{
|
|
|
|
return rb_ractor_ensure_shareable(obj, name);
|
|
|
|
}
|
|
|
|
|
2014-05-21 10:11:25 +04:00
|
|
|
static VALUE
|
2018-07-04 02:56:11 +03:00
|
|
|
core_hash_merge_kwd(VALUE hash, VALUE kw)
|
|
|
|
{
|
|
|
|
rb_hash_foreach(rb_to_hash_type(kw), kwmerge_i, hash);
|
2012-04-29 01:12:05 +04:00
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
extern VALUE *rb_gc_stack_start;
|
2007-12-15 07:09:24 +03:00
|
|
|
extern size_t rb_gc_stack_maxsize;
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
|
2008-05-22 08:28:13 +04:00
|
|
|
/* debug functions */
|
|
|
|
|
2009-09-08 02:32:31 +04:00
|
|
|
/* :nodoc: */
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
static VALUE
|
2019-12-05 08:38:46 +03:00
|
|
|
sdr(VALUE self)
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
{
|
2023-07-31 21:04:42 +03:00
|
|
|
rb_vm_bugreport(NULL, stderr);
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2009-09-08 02:32:31 +04:00
|
|
|
/* :nodoc: */
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
static VALUE
|
2019-12-05 08:38:46 +03:00
|
|
|
nsdr(VALUE self)
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
{
|
|
|
|
VALUE ary = rb_ary_new();
|
2021-04-29 15:31:05 +03:00
|
|
|
#ifdef HAVE_BACKTRACE
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
#include <execinfo.h>
|
|
|
|
#define MAX_NATIVE_TRACE 1024
|
|
|
|
static void *trace[MAX_NATIVE_TRACE];
|
2014-01-15 01:49:45 +04:00
|
|
|
int n = (int)backtrace(trace, MAX_NATIVE_TRACE);
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
char **syms = backtrace_symbols(trace, n);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (syms == 0) {
|
|
|
|
rb_memerror();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<n; i++) {
|
|
|
|
rb_ary_push(ary, rb_str_new2(syms[i]));
|
|
|
|
}
|
* array.c, bignum.c, cont.c, dir.c, dln.c, encoding.c, enumerator.c,
enumerator.c (enumerator_allocate), eval_jump.c, file.c, hash.c,
io.c, load.c, pack.c, proc.c, random.c, re.c, ruby.c, st.c,
string.c, thread.c, thread_pthread.c, time.c, util.c, variable.c,
vm.c, gc.c:
allocated memory objects by xmalloc (ruby_xmalloc) should be
freed by xfree (ruby_xfree).
* ext/curses/curses.c, ext/dbm/dbm.c, ext/digest/digest.c,
ext/gdbm/gdbm.c, ext/json/ext/parser/parser.c,
ext/json/ext/parser/unicode.c, ext/openssl/ossl_cipher.c,
ext/openssl/ossl_hmac.c, ext/openssl/ossl_pkey_ec.c,
ext/sdbm/init.c, ext/strscan/strscan.c, ext/zlib/zlib.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17017 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-06-08 14:01:40 +04:00
|
|
|
free(syms); /* OK */
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
#endif
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2012-10-04 16:31:05 +04:00
|
|
|
#if VM_COLLECT_USAGE_DETAILS
|
2019-03-11 22:07:52 +03:00
|
|
|
static VALUE usage_analysis_insn_start(VALUE self);
|
|
|
|
static VALUE usage_analysis_operand_start(VALUE self);
|
|
|
|
static VALUE usage_analysis_register_start(VALUE self);
|
2012-10-04 16:31:05 +04:00
|
|
|
static VALUE usage_analysis_insn_stop(VALUE self);
|
|
|
|
static VALUE usage_analysis_operand_stop(VALUE self);
|
|
|
|
static VALUE usage_analysis_register_stop(VALUE self);
|
2019-03-11 22:07:52 +03:00
|
|
|
static VALUE usage_analysis_insn_running(VALUE self);
|
|
|
|
static VALUE usage_analysis_operand_running(VALUE self);
|
|
|
|
static VALUE usage_analysis_register_running(VALUE self);
|
2019-08-07 01:38:55 +03:00
|
|
|
static VALUE usage_analysis_insn_clear(VALUE self);
|
|
|
|
static VALUE usage_analysis_operand_clear(VALUE self);
|
|
|
|
static VALUE usage_analysis_register_clear(VALUE self);
|
2012-10-04 16:31:05 +04:00
|
|
|
#endif
|
|
|
|
|
2019-08-29 04:40:40 +03:00
|
|
|
static VALUE
|
|
|
|
f_raise(int c, VALUE *v, VALUE _)
|
|
|
|
{
|
|
|
|
return rb_f_raise(c, v);
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
f_proc(VALUE _)
|
|
|
|
{
|
|
|
|
return rb_block_proc();
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
f_lambda(VALUE _)
|
|
|
|
{
|
|
|
|
return rb_block_lambda();
|
|
|
|
}
|
|
|
|
|
2021-08-15 03:38:24 +03:00
|
|
|
static VALUE
|
|
|
|
f_sprintf(int c, const VALUE *v, VALUE _)
|
|
|
|
{
|
|
|
|
return rb_f_sprintf(c, v);
|
|
|
|
}
|
|
|
|
|
2023-12-18 13:57:45 +03:00
|
|
|
/* :nodoc: */
|
2020-01-08 10:14:01 +03:00
|
|
|
static VALUE
|
|
|
|
vm_mtbl(VALUE self, VALUE obj, VALUE sym)
|
|
|
|
{
|
2020-03-10 18:23:56 +03:00
|
|
|
vm_mtbl_dump(CLASS_OF(obj), RTEST(sym) ? SYM2ID(sym) : 0);
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2023-12-18 13:57:45 +03:00
|
|
|
/* :nodoc: */
|
2020-03-10 18:23:56 +03:00
|
|
|
static VALUE
|
|
|
|
vm_mtbl2(VALUE self, VALUE obj, VALUE sym)
|
|
|
|
{
|
|
|
|
vm_mtbl_dump(obj, RTEST(sym) ? SYM2ID(sym) : 0);
|
2020-01-08 10:14:01 +03:00
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2021-09-30 10:58:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* RubyVM.keep_script_lines -> true or false
|
|
|
|
*
|
|
|
|
* Return current +keep_script_lines+ status. Now it only returns
|
|
|
|
* +true+ of +false+, but it can return other objects in future.
|
|
|
|
*
|
|
|
|
* Note that this is an API for ruby internal use, debugging,
|
|
|
|
* and research. Do not use this for any other purpose.
|
|
|
|
* The compatibility is not guaranteed.
|
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
vm_keep_script_lines(VALUE self)
|
|
|
|
{
|
|
|
|
return RBOOL(ruby_vm_keep_script_lines);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* RubyVM.keep_script_lines = true / false
|
|
|
|
*
|
|
|
|
* It set +keep_script_lines+ flag. If the flag is set, all
|
|
|
|
* loaded scripts are recorded in a interpreter process.
|
|
|
|
*
|
|
|
|
* Note that this is an API for ruby internal use, debugging,
|
|
|
|
* and research. Do not use this for any other purpose.
|
|
|
|
* The compatibility is not guaranteed.
|
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
vm_keep_script_lines_set(VALUE self, VALUE flags)
|
|
|
|
{
|
|
|
|
ruby_vm_keep_script_lines = RTEST(flags);
|
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
void
|
|
|
|
Init_VM(void)
|
|
|
|
{
|
|
|
|
VALUE opts;
|
2008-08-14 09:14:01 +04:00
|
|
|
VALUE klass;
|
2023-09-19 07:56:06 +03:00
|
|
|
VALUE fcore;
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
|
2018-08-17 06:36:01 +03:00
|
|
|
/*
|
|
|
|
* Document-class: RubyVM
|
|
|
|
*
|
2019-08-19 08:51:00 +03:00
|
|
|
* The RubyVM module only exists on MRI. +RubyVM+ is not defined in
|
|
|
|
* other Ruby implementations such as JRuby and TruffleRuby.
|
|
|
|
*
|
|
|
|
* The RubyVM module provides some access to MRI internals.
|
2018-10-12 23:00:13 +03:00
|
|
|
* This module is for very limited purposes, such as debugging,
|
2018-08-17 06:36:01 +03:00
|
|
|
* prototyping, and research. Normal users must not use it.
|
2019-08-19 08:51:00 +03:00
|
|
|
* This module is not portable between Ruby implementations.
|
2018-08-17 06:36:01 +03:00
|
|
|
*/
|
2008-06-29 21:26:16 +04:00
|
|
|
rb_cRubyVM = rb_define_class("RubyVM", rb_cObject);
|
|
|
|
rb_undef_alloc_func(rb_cRubyVM);
|
2009-12-21 13:12:21 +03:00
|
|
|
rb_undef_method(CLASS_OF(rb_cRubyVM), "new");
|
2013-12-09 13:12:23 +04:00
|
|
|
rb_define_singleton_method(rb_cRubyVM, "stat", vm_stat, -1);
|
2021-09-30 10:58:46 +03:00
|
|
|
rb_define_singleton_method(rb_cRubyVM, "keep_script_lines", vm_keep_script_lines, 0);
|
|
|
|
rb_define_singleton_method(rb_cRubyVM, "keep_script_lines=", vm_keep_script_lines_set, 1);
|
|
|
|
|
2019-04-14 09:57:21 +03:00
|
|
|
#if USE_DEBUG_COUNTER
|
|
|
|
rb_define_singleton_method(rb_cRubyVM, "reset_debug_counters", rb_debug_counter_reset, 0);
|
2019-08-06 22:23:30 +03:00
|
|
|
rb_define_singleton_method(rb_cRubyVM, "show_debug_counters", rb_debug_counter_show, 0);
|
2019-04-14 09:57:21 +03:00
|
|
|
#endif
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
|
2012-01-02 12:28:05 +04:00
|
|
|
/* FrozenCore (hidden) */
|
2023-09-19 07:56:06 +03:00
|
|
|
fcore = rb_class_new(rb_cBasicObject);
|
2020-10-20 13:32:10 +03:00
|
|
|
rb_set_class_path(fcore, rb_cRubyVM, "FrozenCore");
|
2024-03-26 18:35:44 +03:00
|
|
|
rb_vm_register_global_object(rb_class_path_cached(fcore));
|
2023-09-19 07:56:06 +03:00
|
|
|
RBASIC(fcore)->flags = T_ICLASS;
|
2008-08-14 09:14:01 +04:00
|
|
|
klass = rb_singleton_class(fcore);
|
|
|
|
rb_define_method_id(klass, id_core_set_method_alias, m_core_set_method_alias, 3);
|
|
|
|
rb_define_method_id(klass, id_core_set_variable_alias, m_core_set_variable_alias, 2);
|
|
|
|
rb_define_method_id(klass, id_core_undef_method, m_core_undef_method, 2);
|
2013-08-22 10:50:42 +04:00
|
|
|
rb_define_method_id(klass, id_core_set_postexe, m_core_set_postexe, 0);
|
2012-04-12 05:33:34 +04:00
|
|
|
rb_define_method_id(klass, id_core_hash_merge_ptr, m_core_hash_merge_ptr, -1);
|
2018-07-04 02:56:11 +03:00
|
|
|
rb_define_method_id(klass, id_core_hash_merge_kwd, m_core_hash_merge_kwd, 2);
|
2019-08-29 04:40:40 +03:00
|
|
|
rb_define_method_id(klass, id_core_raise, f_raise, -1);
|
2021-08-15 03:38:24 +03:00
|
|
|
rb_define_method_id(klass, id_core_sprintf, f_sprintf, -1);
|
2019-08-29 04:40:40 +03:00
|
|
|
rb_define_method_id(klass, idProc, f_proc, 0);
|
|
|
|
rb_define_method_id(klass, idLambda, f_lambda, 0);
|
2020-10-20 11:28:12 +03:00
|
|
|
rb_define_method(klass, "make_shareable", m_core_make_shareable, 1);
|
2020-12-24 04:59:27 +03:00
|
|
|
rb_define_method(klass, "make_shareable_copy", m_core_make_shareable_copy, 1);
|
2020-12-19 14:42:58 +03:00
|
|
|
rb_define_method(klass, "ensure_shareable", m_core_ensure_shareable, 2);
|
2008-08-14 09:14:01 +04:00
|
|
|
rb_obj_freeze(fcore);
|
2013-10-10 06:11:37 +04:00
|
|
|
RBASIC_CLEAR_CLASS(klass);
|
|
|
|
rb_obj_freeze(klass);
|
2024-03-03 12:46:46 +03:00
|
|
|
rb_vm_register_global_object(fcore);
|
2023-09-19 07:56:06 +03:00
|
|
|
rb_mRubyVMFrozenCore = fcore;
|
2008-07-01 07:05:58 +04:00
|
|
|
|
2013-02-27 08:02:06 +04:00
|
|
|
/*
|
|
|
|
* Document-class: Thread
|
|
|
|
*
|
|
|
|
* Threads are the Ruby implementation for a concurrent programming model.
|
|
|
|
*
|
|
|
|
* Programs that require multiple threads of execution are a perfect
|
|
|
|
* candidate for Ruby's Thread class.
|
|
|
|
*
|
|
|
|
* For example, we can create a new thread separate from the main thread's
|
|
|
|
* execution using ::new.
|
|
|
|
*
|
2019-12-20 03:19:39 +03:00
|
|
|
* thr = Thread.new { puts "What's the big deal" }
|
2013-02-27 08:02:06 +04:00
|
|
|
*
|
|
|
|
* Then we are able to pause the execution of the main thread and allow
|
|
|
|
* our new thread to finish, using #join:
|
|
|
|
*
|
2019-12-20 03:19:39 +03:00
|
|
|
* thr.join #=> "What's the big deal"
|
2013-02-27 08:02:06 +04:00
|
|
|
*
|
|
|
|
* If we don't call +thr.join+ before the main thread terminates, then all
|
|
|
|
* other threads including +thr+ will be killed.
|
|
|
|
*
|
|
|
|
* Alternatively, you can use an array for handling multiple threads at
|
|
|
|
* once, like in the following example:
|
|
|
|
*
|
|
|
|
* threads = []
|
2019-12-20 03:19:39 +03:00
|
|
|
* threads << Thread.new { puts "What's the big deal" }
|
2013-02-27 08:02:06 +04:00
|
|
|
* threads << Thread.new { 3.times { puts "Threads are fun!" } }
|
|
|
|
*
|
|
|
|
* After creating a few threads we wait for them all to finish
|
|
|
|
* consecutively.
|
|
|
|
*
|
|
|
|
* threads.each { |thr| thr.join }
|
|
|
|
*
|
2019-07-24 21:54:07 +03:00
|
|
|
* To retrieve the last value of a thread, use #value
|
|
|
|
*
|
|
|
|
* thr = Thread.new { sleep 1; "Useful value" }
|
|
|
|
* thr.value #=> "Useful value"
|
|
|
|
*
|
2013-02-27 08:02:06 +04:00
|
|
|
* === Thread initialization
|
|
|
|
*
|
|
|
|
* In order to create new threads, Ruby provides ::new, ::start, and
|
|
|
|
* ::fork. A block must be provided with each of these methods, otherwise
|
|
|
|
* a ThreadError will be raised.
|
|
|
|
*
|
|
|
|
* When subclassing the Thread class, the +initialize+ method of your
|
|
|
|
* subclass will be ignored by ::start and ::fork. Otherwise, be sure to
|
|
|
|
* call super in your +initialize+ method.
|
|
|
|
*
|
|
|
|
* === Thread termination
|
|
|
|
*
|
|
|
|
* For terminating threads, Ruby provides a variety of ways to do this.
|
|
|
|
*
|
|
|
|
* The class method ::kill, is meant to exit a given thread:
|
|
|
|
*
|
2019-12-24 00:41:58 +03:00
|
|
|
* thr = Thread.new { sleep }
|
2013-02-27 08:02:06 +04:00
|
|
|
* Thread.kill(thr) # sends exit() to thr
|
|
|
|
*
|
2013-02-27 14:54:11 +04:00
|
|
|
* Alternatively, you can use the instance method #exit, or any of its
|
2013-02-27 08:02:06 +04:00
|
|
|
* aliases #kill or #terminate.
|
|
|
|
*
|
|
|
|
* thr.exit
|
|
|
|
*
|
|
|
|
* === Thread status
|
|
|
|
*
|
|
|
|
* Ruby provides a few instance methods for querying the state of a given
|
2013-02-27 14:54:11 +04:00
|
|
|
* thread. To get a string with the current thread's state use #status
|
2013-02-27 08:02:06 +04:00
|
|
|
*
|
|
|
|
* thr = Thread.new { sleep }
|
|
|
|
* thr.status # => "sleep"
|
|
|
|
* thr.exit
|
2013-02-27 21:43:25 +04:00
|
|
|
* thr.status # => false
|
2013-02-27 08:02:06 +04:00
|
|
|
*
|
|
|
|
* You can also use #alive? to tell if the thread is running or sleeping,
|
|
|
|
* and #stop? if the thread is dead or sleeping.
|
|
|
|
*
|
|
|
|
* === Thread variables and scope
|
|
|
|
*
|
|
|
|
* Since threads are created with blocks, the same rules apply to other
|
|
|
|
* Ruby blocks for variable scope. Any local variables created within this
|
|
|
|
* block are accessible to only this thread.
|
|
|
|
*
|
|
|
|
* ==== Fiber-local vs. Thread-local
|
|
|
|
*
|
2013-02-27 14:54:11 +04:00
|
|
|
* Each fiber has its own bucket for Thread#[] storage. When you set a
|
2013-02-27 08:02:06 +04:00
|
|
|
* new fiber-local it is only accessible within this Fiber. To illustrate:
|
|
|
|
*
|
|
|
|
* Thread.new {
|
|
|
|
* Thread.current[:foo] = "bar"
|
|
|
|
* Fiber.new {
|
|
|
|
* p Thread.current[:foo] # => nil
|
|
|
|
* }.resume
|
|
|
|
* }.join
|
|
|
|
*
|
2013-02-27 08:22:08 +04:00
|
|
|
* This example uses #[] for getting and #[]= for setting fiber-locals,
|
2013-02-27 08:02:06 +04:00
|
|
|
* you can also use #keys to list the fiber-locals for a given
|
|
|
|
* thread and #key? to check if a fiber-local exists.
|
|
|
|
*
|
|
|
|
* When it comes to thread-locals, they are accessible within the entire
|
|
|
|
* scope of the thread. Given the following example:
|
|
|
|
*
|
|
|
|
* Thread.new{
|
|
|
|
* Thread.current.thread_variable_set(:foo, 1)
|
|
|
|
* p Thread.current.thread_variable_get(:foo) # => 1
|
|
|
|
* Fiber.new{
|
|
|
|
* Thread.current.thread_variable_set(:foo, 2)
|
|
|
|
* p Thread.current.thread_variable_get(:foo) # => 2
|
|
|
|
* }.resume
|
|
|
|
* p Thread.current.thread_variable_get(:foo) # => 2
|
|
|
|
* }.join
|
|
|
|
*
|
|
|
|
* You can see that the thread-local +:foo+ carried over into the fiber
|
|
|
|
* and was changed to +2+ by the end of the thread.
|
|
|
|
*
|
|
|
|
* This example makes use of #thread_variable_set to create new
|
|
|
|
* thread-locals, and #thread_variable_get to reference them.
|
|
|
|
*
|
|
|
|
* There is also #thread_variables to list all thread-locals, and
|
|
|
|
* #thread_variable? to check if a given thread-local exists.
|
|
|
|
*
|
|
|
|
* === Exception handling
|
|
|
|
*
|
2019-07-24 21:54:07 +03:00
|
|
|
* When an unhandled exception is raised inside a thread, it will
|
|
|
|
* terminate. By default, this exception will not propagate to other
|
|
|
|
* threads. The exception is stored and when another thread calls #value
|
|
|
|
* or #join, the exception will be re-raised in that thread.
|
|
|
|
*
|
|
|
|
* t = Thread.new{ raise 'something went wrong' }
|
|
|
|
* t.value #=> RuntimeError: something went wrong
|
|
|
|
*
|
|
|
|
* An exception can be raised from outside the thread using the
|
|
|
|
* Thread#raise instance method, which takes the same parameters as
|
|
|
|
* Kernel#raise.
|
2013-02-27 08:02:06 +04:00
|
|
|
*
|
2019-07-24 21:54:07 +03:00
|
|
|
* Setting Thread.abort_on_exception = true, Thread#abort_on_exception =
|
|
|
|
* true, or $DEBUG = true will cause a subsequent unhandled exception
|
|
|
|
* raised in a thread to be automatically re-raised in the main thread.
|
2013-02-27 08:02:06 +04:00
|
|
|
*
|
|
|
|
* With the addition of the class method ::handle_interrupt, you can now
|
|
|
|
* handle exceptions asynchronously with threads.
|
|
|
|
*
|
|
|
|
* === Scheduling
|
|
|
|
*
|
|
|
|
* Ruby provides a few ways to support scheduling threads in your program.
|
|
|
|
*
|
|
|
|
* The first way is by using the class method ::stop, to put the current
|
|
|
|
* running thread to sleep and schedule the execution of another thread.
|
|
|
|
*
|
|
|
|
* Once a thread is asleep, you can use the instance method #wakeup to
|
|
|
|
* mark your thread as eligible for scheduling.
|
|
|
|
*
|
|
|
|
* You can also try ::pass, which attempts to pass execution to another
|
|
|
|
* thread but is dependent on the OS whether a running thread will switch
|
2013-02-27 14:54:11 +04:00
|
|
|
* or not. The same goes for #priority, which lets you hint to the thread
|
2013-02-27 08:02:06 +04:00
|
|
|
* scheduler which threads you want to take precedence when passing
|
|
|
|
* execution. This method is also dependent on the OS and may be ignored
|
|
|
|
* on some platforms.
|
|
|
|
*
|
|
|
|
*/
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
rb_cThread = rb_define_class("Thread", rb_cObject);
|
|
|
|
rb_undef_alloc_func(rb_cThread);
|
|
|
|
|
2012-10-04 16:31:05 +04:00
|
|
|
#if VM_COLLECT_USAGE_DETAILS
|
2012-01-02 12:28:05 +04:00
|
|
|
/* ::RubyVM::USAGE_ANALYSIS_* */
|
2013-06-02 07:12:04 +04:00
|
|
|
#define define_usage_analysis_hash(name) /* shut up rdoc -C */ \
|
2016-04-04 10:42:51 +03:00
|
|
|
rb_define_const(rb_cRubyVM, "USAGE_ANALYSIS_" #name, rb_hash_new())
|
|
|
|
define_usage_analysis_hash(INSN);
|
|
|
|
define_usage_analysis_hash(REGS);
|
|
|
|
define_usage_analysis_hash(INSN_BIGRAM);
|
2012-10-04 16:31:05 +04:00
|
|
|
|
2019-03-11 22:07:52 +03:00
|
|
|
rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_INSN_START", usage_analysis_insn_start, 0);
|
|
|
|
rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_OPERAND_START", usage_analysis_operand_start, 0);
|
|
|
|
rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_REGISTER_START", usage_analysis_register_start, 0);
|
2012-10-04 16:31:05 +04:00
|
|
|
rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_INSN_STOP", usage_analysis_insn_stop, 0);
|
|
|
|
rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_OPERAND_STOP", usage_analysis_operand_stop, 0);
|
|
|
|
rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_REGISTER_STOP", usage_analysis_register_stop, 0);
|
2019-03-11 22:07:52 +03:00
|
|
|
rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_INSN_RUNNING", usage_analysis_insn_running, 0);
|
|
|
|
rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_OPERAND_RUNNING", usage_analysis_operand_running, 0);
|
|
|
|
rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_REGISTER_RUNNING", usage_analysis_register_running, 0);
|
2019-08-07 01:38:55 +03:00
|
|
|
rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_INSN_CLEAR", usage_analysis_insn_clear, 0);
|
|
|
|
rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_OPERAND_CLEAR", usage_analysis_operand_clear, 0);
|
|
|
|
rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_REGISTER_CLEAR", usage_analysis_register_clear, 0);
|
2012-10-04 16:31:05 +04:00
|
|
|
#endif
|
|
|
|
|
2019-08-19 08:51:00 +03:00
|
|
|
/* ::RubyVM::OPTS
|
|
|
|
* An Array of VM build options.
|
|
|
|
* This constant is MRI specific.
|
|
|
|
*/
|
2008-06-29 21:26:16 +04:00
|
|
|
rb_define_const(rb_cRubyVM, "OPTS", opts = rb_ary_new());
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
|
|
|
|
#if OPT_DIRECT_THREADED_CODE
|
|
|
|
rb_ary_push(opts, rb_str_new2("direct threaded code"));
|
|
|
|
#elif OPT_TOKEN_THREADED_CODE
|
|
|
|
rb_ary_push(opts, rb_str_new2("token threaded code"));
|
|
|
|
#elif OPT_CALL_THREADED_CODE
|
|
|
|
rb_ary_push(opts, rb_str_new2("call threaded code"));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if OPT_OPERANDS_UNIFICATION
|
2014-01-04 12:22:46 +04:00
|
|
|
rb_ary_push(opts, rb_str_new2("operands unification"));
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
#endif
|
|
|
|
#if OPT_INSTRUCTIONS_UNIFICATION
|
|
|
|
rb_ary_push(opts, rb_str_new2("instructions unification"));
|
|
|
|
#endif
|
|
|
|
#if OPT_INLINE_METHOD_CACHE
|
|
|
|
rb_ary_push(opts, rb_str_new2("inline method cache"));
|
|
|
|
#endif
|
|
|
|
|
2019-08-19 08:51:00 +03:00
|
|
|
/* ::RubyVM::INSTRUCTION_NAMES
|
|
|
|
* A list of bytecode instruction names in MRI.
|
|
|
|
* This constant is MRI specific.
|
|
|
|
*/
|
2009-01-19 04:06:56 +03:00
|
|
|
rb_define_const(rb_cRubyVM, "INSTRUCTION_NAMES", rb_insns_name_array());
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
|
2012-12-20 02:29:18 +04:00
|
|
|
/* ::RubyVM::DEFAULT_PARAMS
|
2019-08-19 08:51:00 +03:00
|
|
|
* This constant exposes the VM's default parameters.
|
2013-05-19 07:10:21 +04:00
|
|
|
* Note that changing these values does not affect VM execution.
|
2012-12-20 02:29:18 +04:00
|
|
|
* Specification is not stable and you should not depend on this value.
|
|
|
|
* Of course, this constant is MRI specific.
|
|
|
|
*/
|
|
|
|
rb_define_const(rb_cRubyVM, "DEFAULT_PARAMS", vm_default_params());
|
|
|
|
|
2012-01-02 12:28:05 +04:00
|
|
|
/* debug functions ::RubyVM::SDR(), ::RubyVM::NSDR() */
|
2008-05-22 14:01:32 +04:00
|
|
|
#if VMDEBUG
|
2008-06-29 21:26:16 +04:00
|
|
|
rb_define_singleton_method(rb_cRubyVM, "SDR", sdr, 0);
|
|
|
|
rb_define_singleton_method(rb_cRubyVM, "NSDR", nsdr, 0);
|
2020-01-08 10:14:01 +03:00
|
|
|
rb_define_singleton_method(rb_cRubyVM, "mtbl", vm_mtbl, 2);
|
2020-03-10 18:23:56 +03:00
|
|
|
rb_define_singleton_method(rb_cRubyVM, "mtbl2", vm_mtbl2, 2);
|
2008-06-01 23:55:25 +04:00
|
|
|
#else
|
|
|
|
(void)sdr;
|
|
|
|
(void)nsdr;
|
2020-01-08 10:14:01 +03:00
|
|
|
(void)vm_mtbl;
|
2020-03-10 18:23:56 +03:00
|
|
|
(void)vm_mtbl2;
|
2008-05-22 14:01:32 +04:00
|
|
|
#endif
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
|
|
|
|
/* VM bootstrap: phase 2 */
|
|
|
|
{
|
2017-10-26 11:32:49 +03:00
|
|
|
rb_vm_t *vm = ruby_current_vm_ptr;
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
rb_thread_t *th = GET_THREAD();
|
2018-10-13 12:59:22 +03:00
|
|
|
VALUE filename = rb_fstring_lit("<main>");
|
[Universal parser] Decouple IMEMO from rb_ast_t
This patch removes the `VALUE flags` member from the `rb_ast_t` structure making `rb_ast_t` no longer an IMEMO object.
## Background
We are trying to make the Ruby parser generated from parse.y a universal parser that can be used by other implementations such as mruby.
To achieve this, it is necessary to exclude VALUE and IMEMO from parse.y, AST, and NODE.
## Summary (file by file)
- `rubyparser.h`
- Remove the `VALUE flags` member from `rb_ast_t`
- `ruby_parser.c` and `internal/ruby_parser.h`
- Use TypedData_Make_Struct VALUE which wraps `rb_ast_t` `in ast_alloc()` so that GC can manage it
- You can retrieve `rb_ast_t` from the VALUE by `rb_ruby_ast_data_get()`
- Change the return type of `rb_parser_compile_XXXX()` functions from `rb_ast_t *` to `VALUE`
- rb_ruby_ast_new() which internally `calls ast_alloc()` is to create VALUE vast outside ruby_parser.c
- `iseq.c` and `vm_core.h`
- Amend the first parameter of `rb_iseq_new_XXXX()` functions from `rb_ast_body_t *` to `VALUE`
- This keeps the VALUE of AST on the machine stack to prevent being removed by GC
- `ast.c`
- Almost all change is replacement `rb_ast_t *ast` with `VALUE vast` (sorry for the big diff)
- Fix `node_memsize()`
- Now it includes `rb_ast_local_table_link`, `tokens` and script_lines
- `compile.c`, `load.c`, `node.c`, `parse.y`, `proc.c`, `ruby.c`, `template/prelude.c.tmpl`, `vm.c` and `vm_eval.c`
- Follow-up due to the above changes
- `imemo.{c|h}`
- If an object with `imemo_ast` appears, considers it a bug
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2024-04-16 12:42:42 +03:00
|
|
|
const rb_iseq_t *iseq = rb_iseq_new(Qnil, filename, filename, Qnil, 0, ISEQ_TYPE_TOP);
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
|
2020-03-09 20:22:11 +03:00
|
|
|
// Ractor setup
|
|
|
|
rb_ractor_main_setup(vm, th->ractor, th);
|
|
|
|
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
/* create vm object */
|
2009-07-08 00:28:27 +04:00
|
|
|
vm->self = TypedData_Wrap_Struct(rb_cRubyVM, &vm_data_type, vm);
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
|
|
|
|
/* create main thread */
|
2020-03-09 20:22:11 +03:00
|
|
|
th->self = TypedData_Wrap_Struct(rb_cThread, &thread_data_type, th);
|
|
|
|
vm->ractor.main_thread = th;
|
|
|
|
vm->ractor.main_ractor = th->ractor;
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
th->vm = vm;
|
|
|
|
th->top_wrapper = 0;
|
|
|
|
th->top_self = rb_vm_top_self();
|
2020-05-14 13:10:55 +03:00
|
|
|
|
2024-03-03 12:46:46 +03:00
|
|
|
rb_vm_register_global_object((VALUE)iseq);
|
2017-10-26 11:32:49 +03:00
|
|
|
th->ec->cfp->iseq = iseq;
|
2022-03-23 22:19:48 +03:00
|
|
|
th->ec->cfp->pc = ISEQ_BODY(iseq)->iseq_encoded;
|
2017-10-26 11:32:49 +03:00
|
|
|
th->ec->cfp->self = th->top_self;
|
2008-12-27 04:15:56 +03:00
|
|
|
|
2017-10-26 11:32:49 +03:00
|
|
|
VM_ENV_FLAGS_UNSET(th->ec->cfp->ep, VM_FRAME_FLAG_CFRAME);
|
2021-12-03 02:53:39 +03:00
|
|
|
VM_STACK_ENV_WRITE(th->ec->cfp->ep, VM_ENV_DATA_INDEX_ME_CREF, (VALUE)vm_cref_new(rb_cObject, METHOD_VISI_PRIVATE, FALSE, NULL, FALSE, FALSE));
|
* fix namespace issue on singleton class expressions. [Bug #10943]
* vm_core.h, method.h: remove rb_iseq_t::cref_stack. CREF is stored
to rb_method_definition_t::body.iseq_body.cref.
* vm_insnhelper.c: modify SVAR usage.
When calling ISEQ type method, push CREF information onto method
frame, SVAR located place. Before this fix, SVAR is simply nil.
After this patch, CREF (or NULL == Qfalse for not iseq methods)
is stored at the method invocation.
When SVAR is requierd, then put NODE_IF onto SVAR location,
and NDOE_IF::nd_reserved points CREF itself.
* vm.c (vm_cref_new, vm_cref_dump, vm_cref_new_toplevel): added.
* vm_insnhelper.c (vm_push_frame): accept CREF.
* method.h, vm_method.c (rb_add_method_iseq): added. This function
accepts iseq and CREF.
* class.c (clone_method): use rb_add_method_iseq().
* gc.c (mark_method_entry): mark method_entry::body.iseq_body.cref.
* iseq.c: remove CREF related codes.
* insns.def (getinlinecache/setinlinecache): CREF should be cache key
because a different CREF has a different namespace.
* node.c (rb_gc_mark_node): mark NODE_IF::nd_reserved for SVAR.
* proc.c: catch up changes.
* struct.c: ditto.
* insns.def: ditto.
* vm_args.c (raise_argument_error): ditto.
* vm_eval.c: ditto.
* test/ruby/test_class.rb: add a test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49874 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-03-06 15:24:58 +03:00
|
|
|
|
2011-06-29 07:09:34 +04:00
|
|
|
/*
|
|
|
|
* The Binding of the top level scope
|
|
|
|
*/
|
2008-12-27 04:15:56 +03:00
|
|
|
rb_define_global_const("TOPLEVEL_BINDING", rb_binding_new());
|
2021-03-09 10:29:50 +03:00
|
|
|
|
2024-03-26 21:25:41 +03:00
|
|
|
#ifdef _WIN32
|
2024-08-30 20:05:24 +03:00
|
|
|
rb_objspace_gc_enable(vm->gc.objspace);
|
2024-03-26 21:25:41 +03:00
|
|
|
#endif
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
}
|
|
|
|
vm_init_redefined_flag();
|
2012-06-02 19:23:37 +04:00
|
|
|
|
2018-01-07 22:18:49 +03:00
|
|
|
rb_block_param_proxy = rb_obj_alloc(rb_cObject);
|
2021-11-17 18:43:40 +03:00
|
|
|
rb_add_method_optimized(rb_singleton_class(rb_block_param_proxy), idCall,
|
|
|
|
OPTIMIZED_METHOD_TYPE_BLOCK_CALL, 0, METHOD_VISI_PUBLIC);
|
2018-01-07 22:18:49 +03:00
|
|
|
rb_obj_freeze(rb_block_param_proxy);
|
2024-03-03 12:46:46 +03:00
|
|
|
rb_vm_register_global_object(rb_block_param_proxy);
|
2018-01-07 22:18:49 +03:00
|
|
|
|
2012-06-15 16:01:41 +04:00
|
|
|
/* vm_backtrace.c */
|
2012-06-02 19:23:37 +04:00
|
|
|
Init_vm_backtrace();
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
}
|
|
|
|
|
2009-05-17 09:02:58 +04:00
|
|
|
void
|
|
|
|
rb_vm_set_progname(VALUE filename)
|
|
|
|
{
|
2020-03-09 20:22:11 +03:00
|
|
|
rb_thread_t *th = GET_VM()->ractor.main_thread;
|
2017-10-26 11:32:49 +03:00
|
|
|
rb_control_frame_t *cfp = (void *)(th->ec->vm_stack + th->ec->vm_stack_size);
|
2009-05-17 09:02:58 +04:00
|
|
|
--cfp;
|
2017-06-01 03:05:33 +03:00
|
|
|
|
2023-04-13 15:45:56 +03:00
|
|
|
filename = rb_str_new_frozen(filename);
|
|
|
|
rb_iseq_pathobj_set(cfp->iseq, filename, rb_iseq_realpath(cfp->iseq));
|
2009-05-17 09:02:58 +04:00
|
|
|
}
|
|
|
|
|
2015-08-09 08:15:57 +03:00
|
|
|
extern const struct st_hash_type rb_fstring_hash_type;
|
|
|
|
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
void
|
2024-01-12 09:32:16 +03:00
|
|
|
Init_BareVM(void)
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
{
|
|
|
|
/* VM bootstrap: phase 1 */
|
2024-04-23 23:32:45 +03:00
|
|
|
rb_vm_t *vm = ruby_mimcalloc(1, sizeof(*vm));
|
|
|
|
rb_thread_t *th = ruby_mimcalloc(1, sizeof(*th));
|
2008-08-01 16:30:25 +04:00
|
|
|
if (!vm || !th) {
|
2021-09-09 17:21:06 +03:00
|
|
|
fputs("[FATAL] failed to allocate memory\n", stderr);
|
2008-08-01 16:30:25 +04:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2022-04-22 16:58:15 +03:00
|
|
|
|
|
|
|
// setup the VM
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
vm_init2(vm);
|
2017-10-26 11:32:49 +03:00
|
|
|
|
Change the semantics of rb_postponed_job_register
Our current implementation of rb_postponed_job_register suffers from
some safety issues that can lead to interpreter crashes (see bug #1991).
Essentially, the issue is that jobs can be called with the wrong
arguments.
We made two attempts to fix this whilst keeping the promised semantics,
but:
* The first one involved masking/unmasking when flushing jobs, which
was believed to be too expensive
* The second one involved a lock-free, multi-producer, single-consumer
ringbuffer, which was too complex
The critical insight behind this third solution is that essentially the
only user of these APIs are a) internal, or b) profiling gems.
For a), none of the usages actually require variable data; they will
work just fine with the preregistration interface.
For b), generally profiling gems only call a single callback with a
single piece of data (which is actually usually just zero) for the life
of the program. The ringbuffer is complex because it needs to support
multi-word inserts of job & data (which can't be atomic); but nobody
actually even needs that functionality, really.
So, this comit:
* Introduces a pre-registration API for jobs, with a GVL-requiring
rb_postponed_job_prereigster, which returns a handle which can be
used with an async-signal-safe rb_postponed_job_trigger.
* Deprecates rb_postponed_job_register (and re-implements it on top of
the preregister function for compatability)
* Moves all the internal usages of postponed job register
pre-registration
2023-11-19 14:54:57 +03:00
|
|
|
rb_vm_postponed_job_queue_init(vm);
|
2017-10-26 11:32:49 +03:00
|
|
|
ruby_current_vm_ptr = vm;
|
2024-04-03 22:46:30 +03:00
|
|
|
rb_objspace_alloc();
|
2020-12-12 23:55:18 +03:00
|
|
|
vm->negative_cme_table = rb_id_table_create(16);
|
2021-12-21 08:06:02 +03:00
|
|
|
vm->overloaded_cme_table = st_init_numtable();
|
2022-03-31 18:04:25 +03:00
|
|
|
vm->constant_cache = rb_id_table_create(0);
|
2024-04-17 13:46:48 +03:00
|
|
|
vm->unused_block_warning_table = st_init_numtable();
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
|
2024-04-19 07:21:55 +03:00
|
|
|
// TODO: remove before Ruby 3.4.0 release
|
|
|
|
const char *s = getenv("RUBY_TRY_UNUSED_BLOCK_WARNING_STRICT");
|
|
|
|
if (s && strcmp(s, "1") == 0) {
|
|
|
|
vm->unused_block_warning_strict = true;
|
|
|
|
}
|
|
|
|
|
2022-04-22 16:58:15 +03:00
|
|
|
// setup main thread
|
2022-04-22 15:19:03 +03:00
|
|
|
th->nt = ZALLOC(struct rb_native_thread);
|
2022-05-20 10:04:10 +03:00
|
|
|
th->vm = vm;
|
|
|
|
th->ractor = vm->ractor.main_ractor = rb_ractor_main_alloc();
|
2017-10-26 11:32:49 +03:00
|
|
|
Init_native_thread(th);
|
2023-10-20 03:12:08 +03:00
|
|
|
rb_jit_cont_init();
|
2022-05-20 10:04:10 +03:00
|
|
|
th_init(th, 0, vm);
|
2022-04-22 16:58:15 +03:00
|
|
|
|
2020-03-09 20:22:11 +03:00
|
|
|
rb_ractor_set_current_ec(th->ractor, th->ec);
|
Pass down "stack start" variables from closer to the top of the stack
This commit changes how stack extents are calculated for both the main
thread and other threads. Ruby uses the address of a local variable as
part of the calculation for machine stack extents:
* pthreads uses it as a lower-bound on the start of the stack, because
glibc (and maybe other libcs) can store its own data on the stack
before calling into user code on thread creation.
* win32 uses it as an argument to VirtualQuery, which gets the extent of
the memory mapping which contains the variable
However, the local being used for this is actually too low (too close to
the leaf function call) in both the main thread case and the new thread
case.
In the main thread case, we have the `INIT_STACK` macro, which is used
for pthreads to set the `native_main_thread->stack_start` value. This
value is correctly captured at the very top level of the program (in
main.c). However, this is _not_ what's used to set the execution context
machine stack (`th->ec->machine_stack.stack_start`); that gets set as
part of a call to `ruby_thread_init_stack` in `Init_BareVM`, using the
address of a local variable allocated _inside_ `Init_BareVM`. This is
too low; we need to use a local allocated closer to the top of the
program.
In the new thread case, the lolcal is allocated inside
`native_thread_init_stack`, which is, again, too low.
In both cases, this means that we might have VALUEs lying outside the
bounds of `th->ec->machine.stack_{start,end}`, which won't be marked
correctly by the GC machinery.
To fix this,
* In the main thread case: We already have `INIT_STACK` at the right
level, so just pass that local var to `ruby_thread_init_stack`.
* In the new thread case: Allocate the local one level above the call to
`native_thread_init_stack` in `call_thread_start_func2`.
[Bug #20001]
fix
2023-11-12 05:24:55 +03:00
|
|
|
/* n.b. native_main_thread_stack_top is set by the INIT_STACK macro */
|
|
|
|
ruby_thread_init_stack(th, native_main_thread_stack_top);
|
2020-03-09 20:22:11 +03:00
|
|
|
|
2022-04-22 16:58:15 +03:00
|
|
|
// setup ractor system
|
2020-03-09 20:22:11 +03:00
|
|
|
rb_native_mutex_initialize(&vm->ractor.sync.lock);
|
|
|
|
rb_native_cond_initialize(&vm->ractor.sync.terminate_cond);
|
2023-04-10 04:53:13 +03:00
|
|
|
|
2023-10-18 11:47:48 +03:00
|
|
|
vm_opt_method_def_table = st_init_numtable();
|
|
|
|
vm_opt_mid_table = st_init_numtable();
|
|
|
|
|
2023-04-10 04:53:13 +03:00
|
|
|
#ifdef RUBY_THREAD_WIN32_H
|
|
|
|
rb_native_cond_initialize(&vm->ractor.sync.barrier_cond);
|
|
|
|
#endif
|
2014-05-04 17:04:37 +04:00
|
|
|
}
|
|
|
|
|
Pass down "stack start" variables from closer to the top of the stack
This commit changes how stack extents are calculated for both the main
thread and other threads. Ruby uses the address of a local variable as
part of the calculation for machine stack extents:
* pthreads uses it as a lower-bound on the start of the stack, because
glibc (and maybe other libcs) can store its own data on the stack
before calling into user code on thread creation.
* win32 uses it as an argument to VirtualQuery, which gets the extent of
the memory mapping which contains the variable
However, the local being used for this is actually too low (too close to
the leaf function call) in both the main thread case and the new thread
case.
In the main thread case, we have the `INIT_STACK` macro, which is used
for pthreads to set the `native_main_thread->stack_start` value. This
value is correctly captured at the very top level of the program (in
main.c). However, this is _not_ what's used to set the execution context
machine stack (`th->ec->machine_stack.stack_start`); that gets set as
part of a call to `ruby_thread_init_stack` in `Init_BareVM`, using the
address of a local variable allocated _inside_ `Init_BareVM`. This is
too low; we need to use a local allocated closer to the top of the
program.
In the new thread case, the lolcal is allocated inside
`native_thread_init_stack`, which is, again, too low.
In both cases, this means that we might have VALUEs lying outside the
bounds of `th->ec->machine.stack_{start,end}`, which won't be marked
correctly by the GC machinery.
To fix this,
* In the main thread case: We already have `INIT_STACK` at the right
level, so just pass that local var to `ruby_thread_init_stack`.
* In the new thread case: Allocate the local one level above the call to
`native_thread_init_stack` in `call_thread_start_func2`.
[Bug #20001]
fix
2023-11-12 05:24:55 +03:00
|
|
|
void
|
|
|
|
ruby_init_stack(void *addr)
|
|
|
|
{
|
|
|
|
native_main_thread_stack_top = addr;
|
|
|
|
}
|
|
|
|
|
2022-10-03 18:14:32 +03:00
|
|
|
#ifndef _WIN32
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#endif
|
|
|
|
|
2024-03-03 12:46:46 +03:00
|
|
|
|
|
|
|
#ifndef MARK_OBJECT_ARY_BUCKET_SIZE
|
|
|
|
#define MARK_OBJECT_ARY_BUCKET_SIZE 1024
|
|
|
|
#endif
|
|
|
|
|
|
|
|
struct pin_array_list {
|
|
|
|
VALUE next;
|
|
|
|
long len;
|
|
|
|
VALUE *array;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
pin_array_list_mark(void *data)
|
|
|
|
{
|
|
|
|
struct pin_array_list *array = (struct pin_array_list *)data;
|
|
|
|
rb_gc_mark_movable(array->next);
|
|
|
|
|
|
|
|
rb_gc_mark_vm_stack_values(array->len, array->array);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
pin_array_list_free(void *data)
|
|
|
|
{
|
|
|
|
struct pin_array_list *array = (struct pin_array_list *)data;
|
|
|
|
xfree(array->array);
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t
|
|
|
|
pin_array_list_memsize(const void *data)
|
|
|
|
{
|
|
|
|
return sizeof(struct pin_array_list) + (MARK_OBJECT_ARY_BUCKET_SIZE * sizeof(VALUE));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
pin_array_list_update_references(void *data)
|
|
|
|
{
|
|
|
|
struct pin_array_list *array = (struct pin_array_list *)data;
|
|
|
|
array->next = rb_gc_location(array->next);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const rb_data_type_t pin_array_list_type = {
|
|
|
|
.wrap_struct_name = "VM/pin_array_list",
|
|
|
|
.function = {
|
|
|
|
.dmark = pin_array_list_mark,
|
|
|
|
.dfree = pin_array_list_free,
|
|
|
|
.dsize = pin_array_list_memsize,
|
|
|
|
.dcompact = pin_array_list_update_references,
|
|
|
|
},
|
|
|
|
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
|
|
|
|
};
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
pin_array_list_new(VALUE next)
|
|
|
|
{
|
|
|
|
struct pin_array_list *array_list;
|
|
|
|
VALUE obj = TypedData_Make_Struct(0, struct pin_array_list, &pin_array_list_type, array_list);
|
|
|
|
RB_OBJ_WRITE(obj, &array_list->next, next);
|
|
|
|
array_list->array = ALLOC_N(VALUE, MARK_OBJECT_ARY_BUCKET_SIZE);
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
pin_array_list_append(VALUE obj, VALUE item)
|
|
|
|
{
|
|
|
|
struct pin_array_list *array_list;
|
|
|
|
TypedData_Get_Struct(obj, struct pin_array_list, &pin_array_list_type, array_list);
|
|
|
|
|
|
|
|
if (array_list->len >= MARK_OBJECT_ARY_BUCKET_SIZE) {
|
|
|
|
obj = pin_array_list_new(obj);
|
|
|
|
TypedData_Get_Struct(obj, struct pin_array_list, &pin_array_list_type, array_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
RB_OBJ_WRITE(obj, &array_list->array[array_list->len], item);
|
|
|
|
array_list->len++;
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_vm_register_global_object(VALUE obj)
|
|
|
|
{
|
|
|
|
RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj));
|
|
|
|
if (RB_SPECIAL_CONST_P(obj)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (RB_BUILTIN_TYPE(obj)) {
|
|
|
|
case T_CLASS:
|
|
|
|
case T_MODULE:
|
|
|
|
if (FL_TEST(obj, RCLASS_IS_ROOT)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
FL_SET(obj, RCLASS_IS_ROOT);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
RB_VM_LOCK_ENTER();
|
|
|
|
{
|
|
|
|
VALUE list = GET_VM()->mark_object_ary;
|
|
|
|
VALUE head = pin_array_list_append(list, obj);
|
|
|
|
if (head != list) {
|
|
|
|
GET_VM()->mark_object_ary = head;
|
|
|
|
}
|
|
|
|
RB_GC_GUARD(obj);
|
|
|
|
}
|
|
|
|
RB_VM_LOCK_LEAVE();
|
|
|
|
}
|
|
|
|
|
2014-05-04 17:04:37 +04:00
|
|
|
void
|
|
|
|
Init_vm_objects(void)
|
|
|
|
{
|
|
|
|
rb_vm_t *vm = GET_VM();
|
|
|
|
|
|
|
|
/* initialize mark object array, hash */
|
2024-03-03 12:46:46 +03:00
|
|
|
vm->mark_object_ary = pin_array_list_new(Qnil);
|
2015-06-03 10:21:37 +03:00
|
|
|
vm->loading_table = st_init_strtable();
|
2024-02-12 08:43:38 +03:00
|
|
|
vm->ci_table = st_init_table(&vm_ci_hashtype);
|
2020-01-15 16:40:01 +03:00
|
|
|
vm->frozen_strings = st_init_table_with_size(&rb_fstring_hash_type, 10000);
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
}
|
|
|
|
|
Rust YJIT
In December 2021, we opened an [issue] to solicit feedback regarding the
porting of the YJIT codebase from C99 to Rust. There were some
reservations, but this project was given the go ahead by Ruby core
developers and Matz. Since then, we have successfully completed the port
of YJIT to Rust.
The new Rust version of YJIT has reached parity with the C version, in
that it passes all the CRuby tests, is able to run all of the YJIT
benchmarks, and performs similarly to the C version (because it works
the same way and largely generates the same machine code). We've even
incorporated some design improvements, such as a more fine-grained
constant invalidation mechanism which we expect will make a big
difference in Ruby on Rails applications.
Because we want to be careful, YJIT is guarded behind a configure
option:
```shell
./configure --enable-yjit # Build YJIT in release mode
./configure --enable-yjit=dev # Build YJIT in dev/debug mode
```
By default, YJIT does not get compiled and cargo/rustc is not required.
If YJIT is built in dev mode, then `cargo` is used to fetch development
dependencies, but when building in release, `cargo` is not required,
only `rustc`. At the moment YJIT requires Rust 1.60.0 or newer.
The YJIT command-line options remain mostly unchanged, and more details
about the build process are documented in `doc/yjit/yjit.md`.
The CI tests have been updated and do not take any more resources than
before.
The development history of the Rust port is available at the following
commit for interested parties:
https://github.com/Shopify/ruby/commit/1fd9573d8b4b65219f1c2407f30a0a60e537f8be
Our hope is that Rust YJIT will be compiled and included as a part of
system packages and compiled binaries of the Ruby 3.2 release. We do not
anticipate any major problems as Rust is well supported on every
platform which YJIT supports, but to make sure that this process works
smoothly, we would like to reach out to those who take care of building
systems packages before the 3.2 release is shipped and resolve any
issues that may come up.
[issue]: https://bugs.ruby-lang.org/issues/18481
Co-authored-by: Maxime Chevalier-Boisvert <maximechevalierb@gmail.com>
Co-authored-by: Noah Gibbs <the.codefolio.guy@gmail.com>
Co-authored-by: Kevin Newton <kddnewton@gmail.com>
2022-04-19 21:40:21 +03:00
|
|
|
/* Stub for builtin function when not building YJIT units*/
|
2022-08-15 20:05:12 +03:00
|
|
|
#if !USE_YJIT
|
Rust YJIT
In December 2021, we opened an [issue] to solicit feedback regarding the
porting of the YJIT codebase from C99 to Rust. There were some
reservations, but this project was given the go ahead by Ruby core
developers and Matz. Since then, we have successfully completed the port
of YJIT to Rust.
The new Rust version of YJIT has reached parity with the C version, in
that it passes all the CRuby tests, is able to run all of the YJIT
benchmarks, and performs similarly to the C version (because it works
the same way and largely generates the same machine code). We've even
incorporated some design improvements, such as a more fine-grained
constant invalidation mechanism which we expect will make a big
difference in Ruby on Rails applications.
Because we want to be careful, YJIT is guarded behind a configure
option:
```shell
./configure --enable-yjit # Build YJIT in release mode
./configure --enable-yjit=dev # Build YJIT in dev/debug mode
```
By default, YJIT does not get compiled and cargo/rustc is not required.
If YJIT is built in dev mode, then `cargo` is used to fetch development
dependencies, but when building in release, `cargo` is not required,
only `rustc`. At the moment YJIT requires Rust 1.60.0 or newer.
The YJIT command-line options remain mostly unchanged, and more details
about the build process are documented in `doc/yjit/yjit.md`.
The CI tests have been updated and do not take any more resources than
before.
The development history of the Rust port is available at the following
commit for interested parties:
https://github.com/Shopify/ruby/commit/1fd9573d8b4b65219f1c2407f30a0a60e537f8be
Our hope is that Rust YJIT will be compiled and included as a part of
system packages and compiled binaries of the Ruby 3.2 release. We do not
anticipate any major problems as Rust is well supported on every
platform which YJIT supports, but to make sure that this process works
smoothly, we would like to reach out to those who take care of building
systems packages before the 3.2 release is shipped and resolve any
issues that may come up.
[issue]: https://bugs.ruby-lang.org/issues/18481
Co-authored-by: Maxime Chevalier-Boisvert <maximechevalierb@gmail.com>
Co-authored-by: Noah Gibbs <the.codefolio.guy@gmail.com>
Co-authored-by: Kevin Newton <kddnewton@gmail.com>
2022-04-19 21:40:21 +03:00
|
|
|
void Init_builtin_yjit(void) {}
|
|
|
|
#endif
|
|
|
|
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
/* top self */
|
|
|
|
|
|
|
|
static VALUE
|
2008-05-22 20:19:14 +04:00
|
|
|
main_to_s(VALUE obj)
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
{
|
|
|
|
return rb_str_new2("main");
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
2008-05-22 08:28:13 +04:00
|
|
|
rb_vm_top_self(void)
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
{
|
|
|
|
return GET_VM()->top_self;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-05-22 08:28:13 +04:00
|
|
|
Init_top_self(void)
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
{
|
|
|
|
rb_vm_t *vm = GET_VM();
|
|
|
|
|
|
|
|
vm->top_self = rb_obj_alloc(rb_cObject);
|
|
|
|
rb_define_singleton_method(rb_vm_top_self(), "to_s", main_to_s, 0);
|
2012-08-15 15:50:01 +04:00
|
|
|
rb_define_alias(rb_singleton_class(rb_vm_top_self()), "inspect", "to_s");
|
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 08:25:46 +04:00
|
|
|
}
|
2008-06-09 09:18:03 +04:00
|
|
|
|
|
|
|
VALUE *
|
|
|
|
rb_ruby_verbose_ptr(void)
|
|
|
|
{
|
Some global variables can be accessed from ractors
Some global variables should be used from non-main Ractors.
[Bug #17268]
```ruby
# ractor-local (derived from created ractor): debug
'$DEBUG' => $DEBUG,
'$-d' => $-d,
# ractor-local (derived from created ractor): verbose
'$VERBOSE' => $VERBOSE,
'$-w' => $-w,
'$-W' => $-W,
'$-v' => $-v,
# process-local (readonly): other commandline parameters
'$-p' => $-p,
'$-l' => $-l,
'$-a' => $-a,
# process-local (readonly): getpid
'$$' => $$,
# thread local: process result
'$?' => $?,
# scope local: match
'$~' => $~.inspect,
'$&' => $&,
'$`' => $`,
'$\'' => $',
'$+' => $+,
'$1' => $1,
# scope local: last line
'$_' => $_,
# scope local: last backtrace
'$@' => $@,
'$!' => $!,
# ractor local: stdin, out, err
'$stdin' => $stdin.inspect,
'$stdout' => $stdout.inspect,
'$stderr' => $stderr.inspect,
```
2020-10-20 04:46:43 +03:00
|
|
|
rb_ractor_t *cr = GET_RACTOR();
|
|
|
|
return &cr->verbose;
|
2008-06-09 09:18:03 +04:00
|
|
|
}
|
|
|
|
|
2008-06-14 06:59:19 +04:00
|
|
|
VALUE *
|
|
|
|
rb_ruby_debug_ptr(void)
|
2008-06-09 09:18:03 +04:00
|
|
|
{
|
Some global variables can be accessed from ractors
Some global variables should be used from non-main Ractors.
[Bug #17268]
```ruby
# ractor-local (derived from created ractor): debug
'$DEBUG' => $DEBUG,
'$-d' => $-d,
# ractor-local (derived from created ractor): verbose
'$VERBOSE' => $VERBOSE,
'$-w' => $-w,
'$-W' => $-W,
'$-v' => $-v,
# process-local (readonly): other commandline parameters
'$-p' => $-p,
'$-l' => $-l,
'$-a' => $-a,
# process-local (readonly): getpid
'$$' => $$,
# thread local: process result
'$?' => $?,
# scope local: match
'$~' => $~.inspect,
'$&' => $&,
'$`' => $`,
'$\'' => $',
'$+' => $+,
'$1' => $1,
# scope local: last line
'$_' => $_,
# scope local: last backtrace
'$@' => $@,
'$!' => $!,
# ractor local: stdin, out, err
'$stdin' => $stdin.inspect,
'$stdout' => $stdout.inspect,
'$stderr' => $stderr.inspect,
```
2020-10-20 04:46:43 +03:00
|
|
|
rb_ractor_t *cr = GET_RACTOR();
|
|
|
|
return &cr->debug;
|
2008-06-09 09:18:03 +04:00
|
|
|
}
|
2012-10-04 16:31:05 +04:00
|
|
|
|
2023-12-20 08:12:18 +03:00
|
|
|
bool rb_free_at_exit = false;
|
2023-10-12 21:15:53 +03:00
|
|
|
|
2024-02-26 23:07:28 +03:00
|
|
|
bool
|
|
|
|
ruby_free_at_exit_p(void)
|
|
|
|
{
|
|
|
|
return rb_free_at_exit;
|
|
|
|
}
|
|
|
|
|
* probes.d: add DTrace probe declarations. [ruby-core:27448]
* array.c (empty_ary_alloc, ary_new): added array create DTrace probe.
* compile.c (rb_insns_name): allowing DTrace probes to access
instruction sequence name.
* Makefile.in: translate probes.d file to appropriate header file.
* common.mk: declare dependencies on the DTrace header.
* configure.in: add a test for existence of DTrace.
* eval.c (setup_exception): add a probe for when an exception is
raised.
* gc.c: Add DTrace probes for mark begin and end, and sweep begin and
end.
* hash.c (empty_hash_alloc): Add a probe for hash allocation.
* insns.def: Add probes for function entry and return.
* internal.h: function declaration for compile.c change.
* load.c (rb_f_load): add probes for `load` entry and exit, require
entry and exit, and wrapping search_required for load path search.
* object.c (rb_obj_alloc): added a probe for general object creation.
* parse.y (yycompile0): added a probe around parse and compile phase.
* string.c (empty_str_alloc, str_new): DTrace probes for string
allocation.
* test/dtrace/*: tests for DTrace probes.
* vm.c (vm_invoke_proc): add probes for function return on exception
raise, hash create, and instruction sequence execution.
* vm_core.h: add probe declarations for function entry and exit.
* vm_dump.c: add probes header file.
* vm_eval.c (vm_call0_cfunc, vm_call0_cfunc_with_frame): add probe on
function entry and return.
* vm_exec.c: expose instruction number to instruction name function.
* vm_insnshelper.c: add function entry and exit probes for cfunc
methods.
* vm_insnhelper.h: vm usage information is always collected, so
uncomment the functions.
12 19:14:50 2012 Akinori MUSHA <knu@iDaemons.org>
* configure.in (isinf, isnan): isinf() and isnan() are macros on
DragonFly which cannot be found by AC_REPLACE_FUNCS(). This
workaround enforces the fact that they exist on DragonFly.
12 15:59:38 2012 Shugo Maeda <shugo@ruby-lang.org>
* vm_core.h (rb_call_info_t::refinements), compile.c (new_callinfo),
vm_insnhelper.c (vm_search_method): revert r37616 because it's too
slow. [ruby-dev:46477]
* test/ruby/test_refinement.rb (test_inline_method_cache): skip
the test until the bug is fixed efficiently.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-11-13 01:52:12 +04:00
|
|
|
/* iseq.c */
|
2015-07-22 01:52:59 +03:00
|
|
|
VALUE rb_insn_operand_intern(const rb_iseq_t *iseq,
|
2013-03-06 10:30:03 +04:00
|
|
|
VALUE insn, int op_no, VALUE op,
|
|
|
|
int len, size_t pos, VALUE *pnop, VALUE child);
|
* probes.d: add DTrace probe declarations. [ruby-core:27448]
* array.c (empty_ary_alloc, ary_new): added array create DTrace probe.
* compile.c (rb_insns_name): allowing DTrace probes to access
instruction sequence name.
* Makefile.in: translate probes.d file to appropriate header file.
* common.mk: declare dependencies on the DTrace header.
* configure.in: add a test for existence of DTrace.
* eval.c (setup_exception): add a probe for when an exception is
raised.
* gc.c: Add DTrace probes for mark begin and end, and sweep begin and
end.
* hash.c (empty_hash_alloc): Add a probe for hash allocation.
* insns.def: Add probes for function entry and return.
* internal.h: function declaration for compile.c change.
* load.c (rb_f_load): add probes for `load` entry and exit, require
entry and exit, and wrapping search_required for load path search.
* object.c (rb_obj_alloc): added a probe for general object creation.
* parse.y (yycompile0): added a probe around parse and compile phase.
* string.c (empty_str_alloc, str_new): DTrace probes for string
allocation.
* test/dtrace/*: tests for DTrace probes.
* vm.c (vm_invoke_proc): add probes for function return on exception
raise, hash create, and instruction sequence execution.
* vm_core.h: add probe declarations for function entry and exit.
* vm_dump.c: add probes header file.
* vm_eval.c (vm_call0_cfunc, vm_call0_cfunc_with_frame): add probe on
function entry and return.
* vm_exec.c: expose instruction number to instruction name function.
* vm_insnshelper.c: add function entry and exit probes for cfunc
methods.
* vm_insnhelper.h: vm usage information is always collected, so
uncomment the functions.
12 19:14:50 2012 Akinori MUSHA <knu@iDaemons.org>
* configure.in (isinf, isnan): isinf() and isnan() are macros on
DragonFly which cannot be found by AC_REPLACE_FUNCS(). This
workaround enforces the fact that they exist on DragonFly.
12 15:59:38 2012 Shugo Maeda <shugo@ruby-lang.org>
* vm_core.h (rb_call_info_t::refinements), compile.c (new_callinfo),
vm_insnhelper.c (vm_search_method): revert r37616 because it's too
slow. [ruby-dev:46477]
* test/ruby/test_refinement.rb (test_inline_method_cache): skip
the test until the bug is fixed efficiently.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-11-13 01:52:12 +04:00
|
|
|
|
2015-08-09 08:15:57 +03:00
|
|
|
st_table *
|
|
|
|
rb_vm_fstring_table(void)
|
|
|
|
{
|
|
|
|
return GET_VM()->frozen_strings;
|
|
|
|
}
|
|
|
|
|
2012-10-04 16:31:05 +04:00
|
|
|
#if VM_COLLECT_USAGE_DETAILS
|
|
|
|
|
2013-12-08 04:41:01 +04:00
|
|
|
#define HASH_ASET(h, k, v) rb_hash_aset((h), (st_data_t)(k), (st_data_t)(v))
|
2012-10-04 16:48:35 +04:00
|
|
|
|
2012-10-04 16:31:05 +04:00
|
|
|
/* uh = {
|
|
|
|
* insn(Fixnum) => ihash(Hash)
|
|
|
|
* }
|
|
|
|
* ihash = {
|
|
|
|
* -1(Fixnum) => count, # insn usage
|
|
|
|
* 0(Fixnum) => ophash, # operand usage
|
|
|
|
* }
|
|
|
|
* ophash = {
|
|
|
|
* val(interned string) => count(Fixnum)
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
vm_analysis_insn(int insn)
|
|
|
|
{
|
|
|
|
ID usage_hash;
|
|
|
|
ID bigram_hash;
|
|
|
|
static int prev_insn = -1;
|
|
|
|
|
|
|
|
VALUE uh;
|
|
|
|
VALUE ihash;
|
|
|
|
VALUE cv;
|
|
|
|
|
|
|
|
CONST_ID(usage_hash, "USAGE_ANALYSIS_INSN");
|
|
|
|
CONST_ID(bigram_hash, "USAGE_ANALYSIS_INSN_BIGRAM");
|
|
|
|
uh = rb_const_get(rb_cRubyVM, usage_hash);
|
2021-10-03 16:34:45 +03:00
|
|
|
if (NIL_P(ihash = rb_hash_aref(uh, INT2FIX(insn)))) {
|
2012-10-04 16:31:05 +04:00
|
|
|
ihash = rb_hash_new();
|
2012-10-04 16:48:35 +04:00
|
|
|
HASH_ASET(uh, INT2FIX(insn), ihash);
|
2012-10-04 16:31:05 +04:00
|
|
|
}
|
2021-10-03 16:34:45 +03:00
|
|
|
if (NIL_P(cv = rb_hash_aref(ihash, INT2FIX(-1)))) {
|
2012-10-04 16:31:05 +04:00
|
|
|
cv = INT2FIX(0);
|
|
|
|
}
|
2012-10-04 16:48:35 +04:00
|
|
|
HASH_ASET(ihash, INT2FIX(-1), INT2FIX(FIX2INT(cv) + 1));
|
2012-10-04 16:31:05 +04:00
|
|
|
|
|
|
|
/* calc bigram */
|
|
|
|
if (prev_insn != -1) {
|
|
|
|
VALUE bi;
|
|
|
|
VALUE ary[2];
|
|
|
|
VALUE cv;
|
|
|
|
|
|
|
|
ary[0] = INT2FIX(prev_insn);
|
|
|
|
ary[1] = INT2FIX(insn);
|
|
|
|
bi = rb_ary_new4(2, &ary[0]);
|
|
|
|
|
|
|
|
uh = rb_const_get(rb_cRubyVM, bigram_hash);
|
2021-10-03 16:34:45 +03:00
|
|
|
if (NIL_P(cv = rb_hash_aref(uh, bi))) {
|
2012-10-04 16:31:05 +04:00
|
|
|
cv = INT2FIX(0);
|
|
|
|
}
|
2012-10-04 16:48:35 +04:00
|
|
|
HASH_ASET(uh, bi, INT2FIX(FIX2INT(cv) + 1));
|
2012-10-04 16:31:05 +04:00
|
|
|
}
|
|
|
|
prev_insn = insn;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vm_analysis_operand(int insn, int n, VALUE op)
|
|
|
|
{
|
|
|
|
ID usage_hash;
|
|
|
|
|
|
|
|
VALUE uh;
|
|
|
|
VALUE ihash;
|
|
|
|
VALUE ophash;
|
|
|
|
VALUE valstr;
|
|
|
|
VALUE cv;
|
|
|
|
|
|
|
|
CONST_ID(usage_hash, "USAGE_ANALYSIS_INSN");
|
|
|
|
|
|
|
|
uh = rb_const_get(rb_cRubyVM, usage_hash);
|
2021-10-03 16:34:45 +03:00
|
|
|
if (NIL_P(ihash = rb_hash_aref(uh, INT2FIX(insn)))) {
|
2012-10-04 16:31:05 +04:00
|
|
|
ihash = rb_hash_new();
|
2012-10-04 16:48:35 +04:00
|
|
|
HASH_ASET(uh, INT2FIX(insn), ihash);
|
2012-10-04 16:31:05 +04:00
|
|
|
}
|
2021-10-03 16:34:45 +03:00
|
|
|
if (NIL_P(ophash = rb_hash_aref(ihash, INT2FIX(n)))) {
|
2012-10-04 16:31:05 +04:00
|
|
|
ophash = rb_hash_new();
|
2012-10-04 16:48:35 +04:00
|
|
|
HASH_ASET(ihash, INT2FIX(n), ophash);
|
2012-10-04 16:31:05 +04:00
|
|
|
}
|
|
|
|
/* intern */
|
2017-10-26 17:44:09 +03:00
|
|
|
valstr = rb_insn_operand_intern(GET_EC()->cfp->iseq, insn, n, op, 0, 0, 0, 0);
|
2012-10-04 16:31:05 +04:00
|
|
|
|
|
|
|
/* set count */
|
2021-10-03 16:34:45 +03:00
|
|
|
if (NIL_P(cv = rb_hash_aref(ophash, valstr))) {
|
2012-10-04 16:31:05 +04:00
|
|
|
cv = INT2FIX(0);
|
|
|
|
}
|
2012-10-04 16:48:35 +04:00
|
|
|
HASH_ASET(ophash, valstr, INT2FIX(FIX2INT(cv) + 1));
|
2012-10-04 16:31:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vm_analysis_register(int reg, int isset)
|
|
|
|
{
|
|
|
|
ID usage_hash;
|
|
|
|
VALUE uh;
|
|
|
|
VALUE valstr;
|
|
|
|
static const char regstrs[][5] = {
|
|
|
|
"pc", /* 0 */
|
|
|
|
"sp", /* 1 */
|
|
|
|
"ep", /* 2 */
|
|
|
|
"cfp", /* 3 */
|
|
|
|
"self", /* 4 */
|
|
|
|
"iseq", /* 5 */
|
|
|
|
};
|
|
|
|
static const char getsetstr[][4] = {
|
|
|
|
"get",
|
|
|
|
"set",
|
|
|
|
};
|
|
|
|
static VALUE syms[sizeof(regstrs) / sizeof(regstrs[0])][2];
|
|
|
|
|
|
|
|
VALUE cv;
|
|
|
|
|
|
|
|
CONST_ID(usage_hash, "USAGE_ANALYSIS_REGS");
|
|
|
|
if (syms[0] == 0) {
|
|
|
|
char buff[0x10];
|
|
|
|
int i;
|
2022-07-21 19:23:58 +03:00
|
|
|
|
2012-10-04 16:31:05 +04:00
|
|
|
for (i = 0; i < (int)(sizeof(regstrs) / sizeof(regstrs[0])); i++) {
|
|
|
|
int j;
|
|
|
|
for (j = 0; j < 2; j++) {
|
|
|
|
snprintf(buff, 0x10, "%d %s %-4s", i, getsetstr[j], regstrs[i]);
|
|
|
|
syms[i][j] = ID2SYM(rb_intern(buff));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
valstr = syms[reg][isset];
|
|
|
|
|
|
|
|
uh = rb_const_get(rb_cRubyVM, usage_hash);
|
2021-10-03 16:34:45 +03:00
|
|
|
if (NIL_P(cv = rb_hash_aref(uh, valstr))) {
|
2012-10-04 16:31:05 +04:00
|
|
|
cv = INT2FIX(0);
|
|
|
|
}
|
2012-10-04 16:48:35 +04:00
|
|
|
HASH_ASET(uh, valstr, INT2FIX(FIX2INT(cv) + 1));
|
2012-10-04 16:31:05 +04:00
|
|
|
}
|
|
|
|
|
2012-10-04 16:48:35 +04:00
|
|
|
#undef HASH_ASET
|
|
|
|
|
2019-03-11 22:07:52 +03:00
|
|
|
static void (*ruby_vm_collect_usage_func_insn)(int insn) = NULL;
|
|
|
|
static void (*ruby_vm_collect_usage_func_operand)(int insn, int n, VALUE op) = NULL;
|
|
|
|
static void (*ruby_vm_collect_usage_func_register)(int reg, int isset) = NULL;
|
|
|
|
|
|
|
|
/* :nodoc: */
|
|
|
|
static VALUE
|
|
|
|
usage_analysis_insn_start(VALUE self)
|
|
|
|
{
|
|
|
|
ruby_vm_collect_usage_func_insn = vm_analysis_insn;
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* :nodoc: */
|
|
|
|
static VALUE
|
|
|
|
usage_analysis_operand_start(VALUE self)
|
|
|
|
{
|
|
|
|
ruby_vm_collect_usage_func_operand = vm_analysis_operand;
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* :nodoc: */
|
|
|
|
static VALUE
|
|
|
|
usage_analysis_register_start(VALUE self)
|
|
|
|
{
|
|
|
|
ruby_vm_collect_usage_func_register = vm_analysis_register;
|
|
|
|
return Qnil;
|
|
|
|
}
|
2012-10-04 16:31:05 +04:00
|
|
|
|
|
|
|
/* :nodoc: */
|
|
|
|
static VALUE
|
|
|
|
usage_analysis_insn_stop(VALUE self)
|
|
|
|
{
|
|
|
|
ruby_vm_collect_usage_func_insn = 0;
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* :nodoc: */
|
|
|
|
static VALUE
|
|
|
|
usage_analysis_operand_stop(VALUE self)
|
|
|
|
{
|
|
|
|
ruby_vm_collect_usage_func_operand = 0;
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* :nodoc: */
|
|
|
|
static VALUE
|
|
|
|
usage_analysis_register_stop(VALUE self)
|
|
|
|
{
|
|
|
|
ruby_vm_collect_usage_func_register = 0;
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2019-03-11 22:07:52 +03:00
|
|
|
/* :nodoc: */
|
|
|
|
static VALUE
|
|
|
|
usage_analysis_insn_running(VALUE self)
|
|
|
|
{
|
2023-11-15 13:05:10 +03:00
|
|
|
return RBOOL(ruby_vm_collect_usage_func_insn != 0);
|
2019-03-11 22:07:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* :nodoc: */
|
|
|
|
static VALUE
|
|
|
|
usage_analysis_operand_running(VALUE self)
|
|
|
|
{
|
2023-11-15 13:05:10 +03:00
|
|
|
return RBOOL(ruby_vm_collect_usage_func_operand != 0);
|
2019-03-11 22:07:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* :nodoc: */
|
|
|
|
static VALUE
|
|
|
|
usage_analysis_register_running(VALUE self)
|
|
|
|
{
|
2023-11-15 13:05:10 +03:00
|
|
|
return RBOOL(ruby_vm_collect_usage_func_register != 0);
|
2019-03-11 22:07:52 +03:00
|
|
|
}
|
|
|
|
|
2022-08-29 08:42:19 +03:00
|
|
|
static VALUE
|
|
|
|
usage_analysis_clear(VALUE self, ID usage_hash)
|
|
|
|
{
|
|
|
|
VALUE uh;
|
|
|
|
uh = rb_const_get(self, usage_hash);
|
|
|
|
rb_hash_clear(uh);
|
|
|
|
|
|
|
|
return Qtrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-08-07 01:38:55 +03:00
|
|
|
/* :nodoc: */
|
|
|
|
static VALUE
|
|
|
|
usage_analysis_insn_clear(VALUE self)
|
|
|
|
{
|
2022-08-29 08:42:19 +03:00
|
|
|
ID usage_hash;
|
|
|
|
ID bigram_hash;
|
2019-08-07 01:38:55 +03:00
|
|
|
|
2022-08-29 08:42:19 +03:00
|
|
|
CONST_ID(usage_hash, "USAGE_ANALYSIS_INSN");
|
|
|
|
CONST_ID(bigram_hash, "USAGE_ANALYSIS_INSN_BIGRAM");
|
|
|
|
usage_analysis_clear(rb_cRubyVM, usage_hash);
|
|
|
|
return usage_analysis_clear(rb_cRubyVM, bigram_hash);
|
2019-08-07 01:38:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* :nodoc: */
|
|
|
|
static VALUE
|
|
|
|
usage_analysis_operand_clear(VALUE self)
|
|
|
|
{
|
2022-08-29 08:42:19 +03:00
|
|
|
ID usage_hash;
|
2019-08-07 01:38:55 +03:00
|
|
|
|
2022-08-29 08:42:19 +03:00
|
|
|
CONST_ID(usage_hash, "USAGE_ANALYSIS_INSN");
|
|
|
|
return usage_analysis_clear(self, usage_hash);
|
2019-08-07 01:38:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* :nodoc: */
|
|
|
|
static VALUE
|
|
|
|
usage_analysis_register_clear(VALUE self)
|
|
|
|
{
|
2022-08-29 08:42:19 +03:00
|
|
|
ID usage_hash;
|
2019-08-07 01:38:55 +03:00
|
|
|
|
2022-08-29 08:42:19 +03:00
|
|
|
CONST_ID(usage_hash, "USAGE_ANALYSIS_REGS");
|
|
|
|
return usage_analysis_clear(self, usage_hash);
|
2019-08-07 01:38:55 +03:00
|
|
|
}
|
|
|
|
|
* probes.d: add DTrace probe declarations. [ruby-core:27448]
* array.c (empty_ary_alloc, ary_new): added array create DTrace probe.
* compile.c (rb_insns_name): allowing DTrace probes to access
instruction sequence name.
* Makefile.in: translate probes.d file to appropriate header file.
* common.mk: declare dependencies on the DTrace header.
* configure.in: add a test for existence of DTrace.
* eval.c (setup_exception): add a probe for when an exception is
raised.
* gc.c: Add DTrace probes for mark begin and end, and sweep begin and
end.
* hash.c (empty_hash_alloc): Add a probe for hash allocation.
* insns.def: Add probes for function entry and return.
* internal.h: function declaration for compile.c change.
* load.c (rb_f_load): add probes for `load` entry and exit, require
entry and exit, and wrapping search_required for load path search.
* object.c (rb_obj_alloc): added a probe for general object creation.
* parse.y (yycompile0): added a probe around parse and compile phase.
* string.c (empty_str_alloc, str_new): DTrace probes for string
allocation.
* test/dtrace/*: tests for DTrace probes.
* vm.c (vm_invoke_proc): add probes for function return on exception
raise, hash create, and instruction sequence execution.
* vm_core.h: add probe declarations for function entry and exit.
* vm_dump.c: add probes header file.
* vm_eval.c (vm_call0_cfunc, vm_call0_cfunc_with_frame): add probe on
function entry and return.
* vm_exec.c: expose instruction number to instruction name function.
* vm_insnshelper.c: add function entry and exit probes for cfunc
methods.
* vm_insnhelper.h: vm usage information is always collected, so
uncomment the functions.
12 19:14:50 2012 Akinori MUSHA <knu@iDaemons.org>
* configure.in (isinf, isnan): isinf() and isnan() are macros on
DragonFly which cannot be found by AC_REPLACE_FUNCS(). This
workaround enforces the fact that they exist on DragonFly.
12 15:59:38 2012 Shugo Maeda <shugo@ruby-lang.org>
* vm_core.h (rb_call_info_t::refinements), compile.c (new_callinfo),
vm_insnhelper.c (vm_search_method): revert r37616 because it's too
slow. [ruby-dev:46477]
* test/ruby/test_refinement.rb (test_inline_method_cache): skip
the test until the bug is fixed efficiently.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-11-13 01:52:12 +04:00
|
|
|
#else
|
|
|
|
|
2020-02-07 08:14:05 +03:00
|
|
|
MAYBE_UNUSED(static void (*ruby_vm_collect_usage_func_insn)(int insn)) = 0;
|
|
|
|
MAYBE_UNUSED(static void (*ruby_vm_collect_usage_func_operand)(int insn, int n, VALUE op)) = 0;
|
|
|
|
MAYBE_UNUSED(static void (*ruby_vm_collect_usage_func_register)(int reg, int isset)) = 0;
|
* probes.d: add DTrace probe declarations. [ruby-core:27448]
* array.c (empty_ary_alloc, ary_new): added array create DTrace probe.
* compile.c (rb_insns_name): allowing DTrace probes to access
instruction sequence name.
* Makefile.in: translate probes.d file to appropriate header file.
* common.mk: declare dependencies on the DTrace header.
* configure.in: add a test for existence of DTrace.
* eval.c (setup_exception): add a probe for when an exception is
raised.
* gc.c: Add DTrace probes for mark begin and end, and sweep begin and
end.
* hash.c (empty_hash_alloc): Add a probe for hash allocation.
* insns.def: Add probes for function entry and return.
* internal.h: function declaration for compile.c change.
* load.c (rb_f_load): add probes for `load` entry and exit, require
entry and exit, and wrapping search_required for load path search.
* object.c (rb_obj_alloc): added a probe for general object creation.
* parse.y (yycompile0): added a probe around parse and compile phase.
* string.c (empty_str_alloc, str_new): DTrace probes for string
allocation.
* test/dtrace/*: tests for DTrace probes.
* vm.c (vm_invoke_proc): add probes for function return on exception
raise, hash create, and instruction sequence execution.
* vm_core.h: add probe declarations for function entry and exit.
* vm_dump.c: add probes header file.
* vm_eval.c (vm_call0_cfunc, vm_call0_cfunc_with_frame): add probe on
function entry and return.
* vm_exec.c: expose instruction number to instruction name function.
* vm_insnshelper.c: add function entry and exit probes for cfunc
methods.
* vm_insnhelper.h: vm usage information is always collected, so
uncomment the functions.
12 19:14:50 2012 Akinori MUSHA <knu@iDaemons.org>
* configure.in (isinf, isnan): isinf() and isnan() are macros on
DragonFly which cannot be found by AC_REPLACE_FUNCS(). This
workaround enforces the fact that they exist on DragonFly.
12 15:59:38 2012 Shugo Maeda <shugo@ruby-lang.org>
* vm_core.h (rb_call_info_t::refinements), compile.c (new_callinfo),
vm_insnhelper.c (vm_search_method): revert r37616 because it's too
slow. [ruby-dev:46477]
* test/ruby/test_refinement.rb (test_inline_method_cache): skip
the test until the bug is fixed efficiently.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-11-13 01:52:12 +04:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2012-11-22 11:23:40 +04:00
|
|
|
#if VM_COLLECT_USAGE_DETAILS
|
2012-10-04 16:31:05 +04:00
|
|
|
/* @param insn instruction number */
|
|
|
|
static void
|
|
|
|
vm_collect_usage_insn(int insn)
|
|
|
|
{
|
* probes.d: add DTrace probe declarations. [ruby-core:27448]
* array.c (empty_ary_alloc, ary_new): added array create DTrace probe.
* compile.c (rb_insns_name): allowing DTrace probes to access
instruction sequence name.
* Makefile.in: translate probes.d file to appropriate header file.
* common.mk: declare dependencies on the DTrace header.
* configure.in: add a test for existence of DTrace.
* eval.c (setup_exception): add a probe for when an exception is
raised.
* gc.c: Add DTrace probes for mark begin and end, and sweep begin and
end.
* hash.c (empty_hash_alloc): Add a probe for hash allocation.
* insns.def: Add probes for function entry and return.
* internal.h: function declaration for compile.c change.
* load.c (rb_f_load): add probes for `load` entry and exit, require
entry and exit, and wrapping search_required for load path search.
* object.c (rb_obj_alloc): added a probe for general object creation.
* parse.y (yycompile0): added a probe around parse and compile phase.
* string.c (empty_str_alloc, str_new): DTrace probes for string
allocation.
* test/dtrace/*: tests for DTrace probes.
* vm.c (vm_invoke_proc): add probes for function return on exception
raise, hash create, and instruction sequence execution.
* vm_core.h: add probe declarations for function entry and exit.
* vm_dump.c: add probes header file.
* vm_eval.c (vm_call0_cfunc, vm_call0_cfunc_with_frame): add probe on
function entry and return.
* vm_exec.c: expose instruction number to instruction name function.
* vm_insnshelper.c: add function entry and exit probes for cfunc
methods.
* vm_insnhelper.h: vm usage information is always collected, so
uncomment the functions.
12 19:14:50 2012 Akinori MUSHA <knu@iDaemons.org>
* configure.in (isinf, isnan): isinf() and isnan() are macros on
DragonFly which cannot be found by AC_REPLACE_FUNCS(). This
workaround enforces the fact that they exist on DragonFly.
12 15:59:38 2012 Shugo Maeda <shugo@ruby-lang.org>
* vm_core.h (rb_call_info_t::refinements), compile.c (new_callinfo),
vm_insnhelper.c (vm_search_method): revert r37616 because it's too
slow. [ruby-dev:46477]
* test/ruby/test_refinement.rb (test_inline_method_cache): skip
the test until the bug is fixed efficiently.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-11-13 01:52:12 +04:00
|
|
|
if (RUBY_DTRACE_INSN_ENABLED()) {
|
|
|
|
RUBY_DTRACE_INSN(rb_insns_name(insn));
|
|
|
|
}
|
2012-10-04 16:31:05 +04:00
|
|
|
if (ruby_vm_collect_usage_func_insn)
|
2012-11-16 21:02:35 +04:00
|
|
|
(*ruby_vm_collect_usage_func_insn)(insn);
|
2012-10-04 16:31:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* @param insn instruction number
|
|
|
|
* @param n n-th operand
|
|
|
|
* @param op operand value
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
vm_collect_usage_operand(int insn, int n, VALUE op)
|
|
|
|
{
|
* probes.d: add DTrace probe declarations. [ruby-core:27448]
* array.c (empty_ary_alloc, ary_new): added array create DTrace probe.
* compile.c (rb_insns_name): allowing DTrace probes to access
instruction sequence name.
* Makefile.in: translate probes.d file to appropriate header file.
* common.mk: declare dependencies on the DTrace header.
* configure.in: add a test for existence of DTrace.
* eval.c (setup_exception): add a probe for when an exception is
raised.
* gc.c: Add DTrace probes for mark begin and end, and sweep begin and
end.
* hash.c (empty_hash_alloc): Add a probe for hash allocation.
* insns.def: Add probes for function entry and return.
* internal.h: function declaration for compile.c change.
* load.c (rb_f_load): add probes for `load` entry and exit, require
entry and exit, and wrapping search_required for load path search.
* object.c (rb_obj_alloc): added a probe for general object creation.
* parse.y (yycompile0): added a probe around parse and compile phase.
* string.c (empty_str_alloc, str_new): DTrace probes for string
allocation.
* test/dtrace/*: tests for DTrace probes.
* vm.c (vm_invoke_proc): add probes for function return on exception
raise, hash create, and instruction sequence execution.
* vm_core.h: add probe declarations for function entry and exit.
* vm_dump.c: add probes header file.
* vm_eval.c (vm_call0_cfunc, vm_call0_cfunc_with_frame): add probe on
function entry and return.
* vm_exec.c: expose instruction number to instruction name function.
* vm_insnshelper.c: add function entry and exit probes for cfunc
methods.
* vm_insnhelper.h: vm usage information is always collected, so
uncomment the functions.
12 19:14:50 2012 Akinori MUSHA <knu@iDaemons.org>
* configure.in (isinf, isnan): isinf() and isnan() are macros on
DragonFly which cannot be found by AC_REPLACE_FUNCS(). This
workaround enforces the fact that they exist on DragonFly.
12 15:59:38 2012 Shugo Maeda <shugo@ruby-lang.org>
* vm_core.h (rb_call_info_t::refinements), compile.c (new_callinfo),
vm_insnhelper.c (vm_search_method): revert r37616 because it's too
slow. [ruby-dev:46477]
* test/ruby/test_refinement.rb (test_inline_method_cache): skip
the test until the bug is fixed efficiently.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-11-13 01:52:12 +04:00
|
|
|
if (RUBY_DTRACE_INSN_OPERAND_ENABLED()) {
|
|
|
|
VALUE valstr;
|
|
|
|
|
2017-10-26 17:44:09 +03:00
|
|
|
valstr = rb_insn_operand_intern(GET_EC()->cfp->iseq, insn, n, op, 0, 0, 0, 0);
|
* probes.d: add DTrace probe declarations. [ruby-core:27448]
* array.c (empty_ary_alloc, ary_new): added array create DTrace probe.
* compile.c (rb_insns_name): allowing DTrace probes to access
instruction sequence name.
* Makefile.in: translate probes.d file to appropriate header file.
* common.mk: declare dependencies on the DTrace header.
* configure.in: add a test for existence of DTrace.
* eval.c (setup_exception): add a probe for when an exception is
raised.
* gc.c: Add DTrace probes for mark begin and end, and sweep begin and
end.
* hash.c (empty_hash_alloc): Add a probe for hash allocation.
* insns.def: Add probes for function entry and return.
* internal.h: function declaration for compile.c change.
* load.c (rb_f_load): add probes for `load` entry and exit, require
entry and exit, and wrapping search_required for load path search.
* object.c (rb_obj_alloc): added a probe for general object creation.
* parse.y (yycompile0): added a probe around parse and compile phase.
* string.c (empty_str_alloc, str_new): DTrace probes for string
allocation.
* test/dtrace/*: tests for DTrace probes.
* vm.c (vm_invoke_proc): add probes for function return on exception
raise, hash create, and instruction sequence execution.
* vm_core.h: add probe declarations for function entry and exit.
* vm_dump.c: add probes header file.
* vm_eval.c (vm_call0_cfunc, vm_call0_cfunc_with_frame): add probe on
function entry and return.
* vm_exec.c: expose instruction number to instruction name function.
* vm_insnshelper.c: add function entry and exit probes for cfunc
methods.
* vm_insnhelper.h: vm usage information is always collected, so
uncomment the functions.
12 19:14:50 2012 Akinori MUSHA <knu@iDaemons.org>
* configure.in (isinf, isnan): isinf() and isnan() are macros on
DragonFly which cannot be found by AC_REPLACE_FUNCS(). This
workaround enforces the fact that they exist on DragonFly.
12 15:59:38 2012 Shugo Maeda <shugo@ruby-lang.org>
* vm_core.h (rb_call_info_t::refinements), compile.c (new_callinfo),
vm_insnhelper.c (vm_search_method): revert r37616 because it's too
slow. [ruby-dev:46477]
* test/ruby/test_refinement.rb (test_inline_method_cache): skip
the test until the bug is fixed efficiently.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-11-13 01:52:12 +04:00
|
|
|
|
|
|
|
RUBY_DTRACE_INSN_OPERAND(RSTRING_PTR(valstr), rb_insns_name(insn));
|
2012-11-16 21:02:37 +04:00
|
|
|
RB_GC_GUARD(valstr);
|
* probes.d: add DTrace probe declarations. [ruby-core:27448]
* array.c (empty_ary_alloc, ary_new): added array create DTrace probe.
* compile.c (rb_insns_name): allowing DTrace probes to access
instruction sequence name.
* Makefile.in: translate probes.d file to appropriate header file.
* common.mk: declare dependencies on the DTrace header.
* configure.in: add a test for existence of DTrace.
* eval.c (setup_exception): add a probe for when an exception is
raised.
* gc.c: Add DTrace probes for mark begin and end, and sweep begin and
end.
* hash.c (empty_hash_alloc): Add a probe for hash allocation.
* insns.def: Add probes for function entry and return.
* internal.h: function declaration for compile.c change.
* load.c (rb_f_load): add probes for `load` entry and exit, require
entry and exit, and wrapping search_required for load path search.
* object.c (rb_obj_alloc): added a probe for general object creation.
* parse.y (yycompile0): added a probe around parse and compile phase.
* string.c (empty_str_alloc, str_new): DTrace probes for string
allocation.
* test/dtrace/*: tests for DTrace probes.
* vm.c (vm_invoke_proc): add probes for function return on exception
raise, hash create, and instruction sequence execution.
* vm_core.h: add probe declarations for function entry and exit.
* vm_dump.c: add probes header file.
* vm_eval.c (vm_call0_cfunc, vm_call0_cfunc_with_frame): add probe on
function entry and return.
* vm_exec.c: expose instruction number to instruction name function.
* vm_insnshelper.c: add function entry and exit probes for cfunc
methods.
* vm_insnhelper.h: vm usage information is always collected, so
uncomment the functions.
12 19:14:50 2012 Akinori MUSHA <knu@iDaemons.org>
* configure.in (isinf, isnan): isinf() and isnan() are macros on
DragonFly which cannot be found by AC_REPLACE_FUNCS(). This
workaround enforces the fact that they exist on DragonFly.
12 15:59:38 2012 Shugo Maeda <shugo@ruby-lang.org>
* vm_core.h (rb_call_info_t::refinements), compile.c (new_callinfo),
vm_insnhelper.c (vm_search_method): revert r37616 because it's too
slow. [ruby-dev:46477]
* test/ruby/test_refinement.rb (test_inline_method_cache): skip
the test until the bug is fixed efficiently.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-11-13 01:52:12 +04:00
|
|
|
}
|
2012-10-04 16:31:05 +04:00
|
|
|
if (ruby_vm_collect_usage_func_operand)
|
2012-11-16 21:02:35 +04:00
|
|
|
(*ruby_vm_collect_usage_func_operand)(insn, n, op);
|
2012-10-04 16:31:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* @param reg register id. see code of vm_analysis_register() */
|
2014-10-12 05:39:53 +04:00
|
|
|
/* @param isset 0: read, 1: write */
|
2012-10-04 16:31:05 +04:00
|
|
|
static void
|
|
|
|
vm_collect_usage_register(int reg, int isset)
|
|
|
|
{
|
|
|
|
if (ruby_vm_collect_usage_func_register)
|
2012-11-16 21:02:35 +04:00
|
|
|
(*ruby_vm_collect_usage_func_register)(reg, isset);
|
2012-10-04 16:31:05 +04:00
|
|
|
}
|
|
|
|
#endif
|
2015-10-23 20:53:35 +03:00
|
|
|
|
2023-03-07 08:34:31 +03:00
|
|
|
const struct rb_callcache *
|
2020-01-08 10:14:01 +03:00
|
|
|
rb_vm_empty_cc(void)
|
|
|
|
{
|
2020-05-29 10:04:53 +03:00
|
|
|
return &vm_empty_cc;
|
2020-01-08 10:14:01 +03:00
|
|
|
}
|
|
|
|
|
2023-03-07 08:34:31 +03:00
|
|
|
const struct rb_callcache *
|
2021-11-16 11:57:49 +03:00
|
|
|
rb_vm_empty_cc_for_super(void)
|
|
|
|
{
|
|
|
|
return &vm_empty_cc_for_super;
|
|
|
|
}
|
|
|
|
|
2015-10-23 20:53:35 +03:00
|
|
|
#include "vm_call_iseq_optimized.inc" /* required from vm_insnhelper.c */
|